trace.c revision ba6aca21bd9e0e66dac17b1828cf6b6e7377b983
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		unsigned 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		    || (insn & 0xffff0000) == 0xdf000000) {
54			/* EABI syscall */
55			*sysnum = ptrace(PTRACE_PEEKUSER, proc->pid, off_r7, 0);
56		} else if ((insn & 0xfff00000) == 0xef900000) {
57			/* old ABI syscall */
58			*sysnum = insn & 0xfffff;
59		} else {
60			/* TODO: handle swi<cond> variations */
61			/* one possible reason for getting in here is that we
62			 * are coming from a signal handler, so the current
63			 * PC does not point to the instruction just after the
64			 * "swi" one. */
65			output_line(proc, "unexpected instruction 0x%x at %p", insn, pc - 4);
66			return 0;
67		}
68		if ((*sysnum & 0xf0000) == 0xf0000) {
69			/* arch-specific syscall */
70			*sysnum &= ~0xf0000;
71			return ip ? 4 : 3;
72		}
73		/* ARM syscall convention: on syscall entry, ip is zero;
74		 * on syscall exit, ip is non-zero */
75		return ip ? 2 : 1;
76	}
77	return 0;
78}
79
80long
81gimme_arg(enum tof type, Process *proc, int arg_num, arg_type_info *info) {
82	proc_archdep *a = (proc_archdep *) proc->arch_ptr;
83
84	if (arg_num == -1) {	/* return value */
85		return ptrace(PTRACE_PEEKUSER, proc->pid, off_r0, 0);
86	}
87
88	/* deal with the ARM calling conventions */
89	if (type == LT_TOF_FUNCTION || type == LT_TOF_FUNCTIONR) {
90		if (arg_num < 4) {
91			if (a->valid && type == LT_TOF_FUNCTION)
92				return a->regs.uregs[arg_num];
93			if (a->valid && type == LT_TOF_FUNCTIONR)
94				return a->func_arg[arg_num];
95			return ptrace(PTRACE_PEEKUSER, proc->pid, 4 * arg_num,
96				      0);
97		} else {
98			return ptrace(PTRACE_PEEKDATA, proc->pid,
99				      proc->stack_pointer + 4 * (arg_num - 4),
100				      0);
101		}
102	} else if (type == LT_TOF_SYSCALL || type == LT_TOF_SYSCALLR) {
103		if (arg_num < 5) {
104			if (a->valid && type == LT_TOF_SYSCALL)
105				return a->regs.uregs[arg_num];
106			if (a->valid && type == LT_TOF_SYSCALLR)
107				return a->sysc_arg[arg_num];
108			return ptrace(PTRACE_PEEKUSER, proc->pid, 4 * arg_num,
109				      0);
110		} else {
111			return ptrace(PTRACE_PEEKDATA, proc->pid,
112				      proc->stack_pointer + 4 * (arg_num - 5),
113				      0);
114		}
115	} else {
116		fprintf(stderr, "gimme_arg called with wrong arguments\n");
117		exit(1);
118	}
119
120	return 0;
121}
122
123void
124save_register_args(enum tof type, Process *proc) {
125	proc_archdep *a = (proc_archdep *) proc->arch_ptr;
126	if (a->valid) {
127		if (type == LT_TOF_FUNCTION)
128			memcpy(a->func_arg, a->regs.uregs, sizeof(a->func_arg));
129		else
130			memcpy(a->sysc_arg, a->regs.uregs, sizeof(a->sysc_arg));
131	}
132}
133