aboutsummaryrefslogtreecommitdiff
blob: 0110302e024b7e2b270bda1d067d53bcdb28f60b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
#ifdef SB_SCHIZO

static const struct syscall_entry syscall_table_32[] = {
#define S(s) { SB_SYS_x86_##s, SB_NR_##s, #s },
#include "trace_syscalls_x86.h"
#undef S
	{ SB_NR_UNDEF, SB_NR_UNDEF, NULL },
};
static const struct syscall_entry syscall_table_64[] = {
#define S(s) { SB_SYS_x86_64_##s, SB_NR_##s, #s },
#include "trace_syscalls_x86_64.h"
#undef S
	{ SB_NR_UNDEF, SB_NR_UNDEF, NULL },
};

static bool pers_is_32(void)
{
	switch (do_peekuser(8 * CS)) {
		case 0x23: return true;
		case 0x33: return false;
		default:   sb_abort();
	}
}

static const struct syscall_entry *trace_check_personality(void)
{
	return pers_is_32() ? syscall_table_32 : syscall_table_64;
}

#else

static bool pers_is_32(void)
{
	return false;
}

#endif

static int trace_sysnum(void)
{
	return do_peekuser(8 * ORIG_RAX);
}

static long trace_raw_ret(void *vregs)
{
	trace_regs *regs = vregs;
	return pers_is_32() ? (int)regs->rax : regs->rax;
}

static void trace_set_sysnum(void *vregs, long nr)
{
	do_pokeuser(8 * ORIG_RAX, nr);
}

static void trace_set_ret(void *vregs, int err)
{
	do_pokeuser(8 * RAX, -err);
}

static unsigned long trace_arg(void *vregs, int num)
{
	trace_regs *regs = vregs;
	if (pers_is_32())
		switch (num) {
			case 1: return regs->rbx;
			case 2: return regs->rcx;
			case 3: return regs->rdx;
			case 4: return regs->rsi;
			case 5: return regs->rdi;
			case 6: return regs->rbp;
			default: return -1;
		}
	else
		switch (num) {
			case 1: return regs->rdi;
			case 2: return regs->rsi;
			case 3: return regs->rdx;
			case 4: return regs->r10;
			case 5: return regs->r8;
			case 6: return regs->r9;
			default: return -1;
		}
}

#ifdef DEBUG
static void trace_dump_regs(void *vregs)
{
	trace_regs *regs = vregs;
	sb_printf("{ ");
#define D(r) sb_printf(#r":%lu ", regs->r)
	D(rax);
	D(rdi);
	D(rsi);
	D(rdx);
	D(r10);
	D(r8);
	D(r9);
#undef D
	sb_printf("}");
}
#endif