trace.c revision 32e8e76f492a48ee3e6284e237f958b71d4d3e71
1#include "config.h"
2
3#include <string.h>
4#include <sys/types.h>
5#include <sys/wait.h>
6#include <signal.h>
7#include <sys/ptrace.h>
8#include <asm/ptrace.h>
9
10#include "common.h"
11#include "output.h"
12#include "ptrace.h"
13
14#if (!defined(PTRACE_PEEKUSER) && defined(PTRACE_PEEKUSR))
15# define PTRACE_PEEKUSER PTRACE_PEEKUSR
16#endif
17
18#if (!defined(PTRACE_POKEUSER) && defined(PTRACE_POKEUSR))
19# define PTRACE_POKEUSER PTRACE_POKEUSR
20#endif
21
22#define off_r0 0
23#define off_r7 28
24#define off_ip 48
25#define off_pc 60
26
27void
28get_arch_dep(Process *proc) {
29	proc_archdep *a;
30
31	if (!proc->arch_ptr)
32		proc->arch_ptr = (void *)malloc(sizeof(proc_archdep));
33	a = (proc_archdep *) (proc->arch_ptr);
34	a->valid = (ptrace(PTRACE_GETREGS, proc->pid, 0, &a->regs) >= 0);
35}
36
37/* Returns 0 if not a syscall,
38 *         1 if syscall entry, 2 if syscall exit,
39 *         3 if arch-specific syscall entry, 4 if arch-specific syscall exit,
40 *         -1 on error.
41 */
42int
43syscall_p(Process *proc, int status, int *sysnum) {
44	if (WIFSTOPPED(status)
45	    && WSTOPSIG(status) == (SIGTRAP | proc->tracesysgood)) {
46		/* get the user's pc (plus 8) */
47		int pc = ptrace(PTRACE_PEEKUSER, proc->pid, off_pc, 0);
48		/* fetch the SWI instruction */
49		int insn = ptrace(PTRACE_PEEKTEXT, proc->pid, pc - 4, 0);
50		int ip = ptrace(PTRACE_PEEKUSER, proc->pid, off_ip, 0);
51
52		if (insn == 0xef000000 || insn == 0x0f000000) {
53			/* EABI syscall */
54			*sysnum = ptrace(PTRACE_PEEKUSER, proc->pid, off_r7, 0);
55		} else if ((insn & 0xfff00000) == 0xef900000) {
56			/* old ABI syscall */
57			*sysnum = insn & 0xfffff;
58		} else {
59			/* TODO: handle swi<cond> variations */
60			/* one possible reason for getting in here is that we
61			 * are coming from a signal handler, so the current
62			 * PC does not point to the instruction just after the
63			 * "swi" one. */
64			output_line(proc, "unexpected instruction 0x%x at %p", insn, pc - 4);
65			return 0;
66		}
67		if ((*sysnum & 0xf0000) == 0xf0000) {
68			/* arch-specific syscall */
69			*sysnum &= ~0xf0000;
70			return ip ? 4 : 3;
71		}
72		/* ARM syscall convention: on syscall entry, ip is zero;
73		 * on syscall exit, ip is non-zero */
74		return ip ? 2 : 1;
75	}
76	return 0;
77}
78
79long
80gimme_arg(enum tof type, Process *proc, int arg_num, arg_type_info *info) {
81	proc_archdep *a = (proc_archdep *) proc->arch_ptr;
82
83	if (arg_num == -1) {	/* return value */
84		return ptrace(PTRACE_PEEKUSER, proc->pid, off_r0, 0);
85	}
86
87	/* deal with the ARM calling conventions */
88	if (type == LT_TOF_FUNCTION || type == LT_TOF_FUNCTIONR) {
89		if (arg_num < 4) {
90			if (a->valid && type == LT_TOF_FUNCTION)
91				return a->regs.uregs[arg_num];
92			if (a->valid && type == LT_TOF_FUNCTIONR)
93				return a->func_arg[arg_num];
94			return ptrace(PTRACE_PEEKUSER, proc->pid, 4 * arg_num,
95				      0);
96		} else {
97			return ptrace(PTRACE_PEEKDATA, proc->pid,
98				      proc->stack_pointer + 4 * (arg_num - 4),
99				      0);
100		}
101	} else if (type == LT_TOF_SYSCALL || type == LT_TOF_SYSCALLR) {
102		if (arg_num < 5) {
103			if (a->valid && type == LT_TOF_SYSCALL)
104				return a->regs.uregs[arg_num];
105			if (a->valid && type == LT_TOF_SYSCALLR)
106				return a->sysc_arg[arg_num];
107			return ptrace(PTRACE_PEEKUSER, proc->pid, 4 * arg_num,
108				      0);
109		} else {
110			return ptrace(PTRACE_PEEKDATA, proc->pid,
111				      proc->stack_pointer + 4 * (arg_num - 5),
112				      0);
113		}
114	} else {
115		fprintf(stderr, "gimme_arg called with wrong arguments\n");
116		exit(1);
117	}
118
119	return 0;
120}
121
122void
123save_register_args(enum tof type, Process *proc) {
124	proc_archdep *a = (proc_archdep *) proc->arch_ptr;
125	if (a->valid) {
126		if (type == LT_TOF_FUNCTION)
127			memcpy(a->func_arg, a->regs.uregs, sizeof(a->func_arg));
128		else
129			memcpy(a->sysc_arg, a->regs.uregs, sizeof(a->sysc_arg));
130	}
131}
132