trace.c revision 9e1e969838d9cc520abb96038aa98520c08c80b9
1#include "config.h"
2
3#include <sys/types.h>
4#include <sys/wait.h>
5#include <signal.h>
6#include <sys/ptrace.h>
7#include <asm/ptrace.h>
8#include <elf.h>
9#include <errno.h>
10#include <string.h>
11
12#include "proc.h"
13#include "common.h"
14#include "ptrace.h"
15#include "breakpoint.h"
16
17#if (!defined(PTRACE_PEEKUSER) && defined(PTRACE_PEEKUSR))
18# define PTRACE_PEEKUSER PTRACE_PEEKUSR
19#endif
20
21#if (!defined(PTRACE_POKEUSER) && defined(PTRACE_POKEUSR))
22# define PTRACE_POKEUSER PTRACE_POKEUSR
23#endif
24
25void
26get_arch_dep(Process *proc) {
27	if (proc->arch_ptr == NULL) {
28		proc->arch_ptr = malloc(sizeof(proc_archdep));
29#ifdef __powerpc64__
30		proc->mask_32bit = (proc->e_machine == EM_PPC);
31#endif
32	}
33
34	proc_archdep *a = (proc_archdep *) (proc->arch_ptr);
35	a->valid = (ptrace(PTRACE_GETREGS, proc->pid, 0, &a->regs) >= 0)
36		&& (ptrace(PTRACE_GETFPREGS, proc->pid, 0, &a->fpregs) >= 0);
37}
38
39#define SYSCALL_INSN   0x44000002
40
41unsigned int greg = 3;
42unsigned int freg = 1;
43
44/* Returns 1 if syscall, 2 if sysret, 0 otherwise. */
45int
46syscall_p(Process *proc, int status, int *sysnum) {
47	if (WIFSTOPPED(status)
48	    && WSTOPSIG(status) == (SIGTRAP | proc->tracesysgood)) {
49		long pc = (long)get_instruction_pointer(proc);
50		int insn =
51		    (int)ptrace(PTRACE_PEEKTEXT, proc->pid, pc - sizeof(long),
52				0);
53
54		if (insn == SYSCALL_INSN) {
55			*sysnum =
56			    (int)ptrace(PTRACE_PEEKUSER, proc->pid,
57					sizeof(long) * PT_R0, 0);
58			if (proc->callstack_depth > 0 &&
59					proc->callstack[proc->callstack_depth - 1].is_syscall &&
60					proc->callstack[proc->callstack_depth - 1].c_un.syscall == *sysnum) {
61				return 2;
62			}
63			return 1;
64		}
65	}
66	return 0;
67}
68
69static long
70gimme_arg_regset(enum tof type, Process *proc, int arg_num, arg_type_info *info,
71		 gregset_t *regs, fpregset_t *fpregs)
72{
73	union { long val; float fval; double dval; } cvt;
74
75	if (info->type == ARGTYPE_FLOAT || info->type == ARGTYPE_DOUBLE) {
76		if (freg <= 13 || (proc->mask_32bit && freg <= 8)) {
77			double val = GET_FPREG(*fpregs, freg);
78
79			if (info->type == ARGTYPE_FLOAT)
80				cvt.fval = val;
81			else
82				cvt.dval = val;
83
84			freg++;
85			greg++;
86
87			return cvt.val;
88		}
89	}
90	else if (greg <= 10)
91		return (*regs)[greg++];
92	else {
93#ifdef __powerpc64__
94		if (proc->mask_32bit)
95			return ptrace (PTRACE_PEEKDATA, proc->pid,
96				       proc->stack_pointer + 8 +
97				       sizeof (int) * (arg_num - 8), 0) >> 32;
98		else
99			return ptrace (PTRACE_PEEKDATA, proc->pid,
100				       proc->stack_pointer + 112 +
101				       sizeof (long) * (arg_num - 8), 0);
102#else
103		return ptrace (PTRACE_PEEKDATA, proc->pid,
104			       proc->stack_pointer + 8 +
105			       sizeof (long) * (arg_num - 8), 0);
106#endif
107	}
108
109	return 0;
110}
111
112static long
113gimme_retval(Process *proc, int arg_num, arg_type_info *info,
114	     gregset_t *regs, fpregset_t *fpregs)
115{
116	union { long val; float fval; double dval; } cvt;
117	if (info->type == ARGTYPE_FLOAT || info->type == ARGTYPE_DOUBLE) {
118		double val = GET_FPREG(*fpregs, 1);
119
120		if (info->type == ARGTYPE_FLOAT)
121			cvt.fval = val;
122		else
123			cvt.dval = val;
124
125		return cvt.val;
126	}
127	else
128		return (*regs)[3];
129}
130
131/* Grab functions arguments based on the PPC64 ABI.  */
132long
133gimme_arg(enum tof type, Process *proc, int arg_num, arg_type_info *info)
134{
135	proc_archdep *arch = (proc_archdep *)proc->arch_ptr;
136	if (arch == NULL || !arch->valid)
137		return -1;
138
139	/* Check if we're entering a new function call to list parameters.  If
140	   so, initialize the register control variables to keep track of where
141	   the parameters were stored.  */
142	if ((type == LT_TOF_FUNCTION || type == LT_TOF_FUNCTIONR)
143	    && arg_num == 0) {
144		/* Initialize the set of registrers for parameter passing.  */
145		greg = 3;
146		freg = 1;
147	}
148
149
150	if (type == LT_TOF_FUNCTIONR) {
151		if (arg_num == -1)
152			return gimme_retval(proc, arg_num, info,
153					    &arch->regs, &arch->fpregs);
154		else
155			return gimme_arg_regset(type, proc, arg_num, info,
156						&arch->regs_copy,
157						&arch->fpregs_copy);
158	}
159	else
160		return gimme_arg_regset(type, proc, arg_num, info,
161					&arch->regs, &arch->fpregs);
162}
163
164void
165save_register_args(enum tof type, Process *proc) {
166	proc_archdep *arch = (proc_archdep *)proc->arch_ptr;
167	if (arch == NULL || !arch->valid)
168		return;
169
170	memcpy(&arch->regs_copy, &arch->regs, sizeof(arch->regs));
171	memcpy(&arch->fpregs_copy, &arch->fpregs, sizeof(arch->fpregs));
172}
173
174/* Read a single long from the process's memory address 'addr'.  */
175int
176arch_umovelong (Process *proc, void *addr, long *result, arg_type_info *info) {
177	long pointed_to;
178
179	errno = 0;
180
181	pointed_to = ptrace (PTRACE_PEEKTEXT, proc->pid, addr, 0);
182
183	if (pointed_to == -1 && errno)
184		return -errno;
185
186#if SIZEOF_LONG == 8
187	/* Since int's are 4-bytes (long is 8-bytes) in length for ppc64, we
188	   need to shift the long values returned by ptrace to end up with
189	   the correct value.  */
190
191	if (info) {
192		if (info->type == ARGTYPE_INT || (proc->mask_32bit && (info->type == ARGTYPE_POINTER
193		    || info->type == ARGTYPE_STRING))) {
194			pointed_to = (long) (((unsigned long) pointed_to) >> 32);
195		}
196	}
197#endif
198
199	*result = pointed_to;
200	return 0;
201}
202
203/* The atomic skip code is mostly taken from GDB.  */
204
205/* Instruction masks used during single-stepping of atomic
206 * sequences.  This was lifted from GDB.  */
207#define LWARX_MASK 0xfc0007fe
208#define LWARX_INSTRUCTION 0x7c000028
209#define LDARX_INSTRUCTION 0x7c0000A8
210#define STWCX_MASK 0xfc0007ff
211#define STWCX_INSTRUCTION 0x7c00012d
212#define STDCX_INSTRUCTION 0x7c0001ad
213#define BC_MASK 0xfc000000
214#define BC_INSTRUCTION 0x40000000
215
216int
217arch_atomic_singlestep(struct Process *proc, struct breakpoint *sbp,
218		       int (*add_cb)(void *addr, void *data),
219		       void *add_cb_data)
220{
221	void *addr = sbp->addr;
222	debug(1, "pid=%d addr=%p", proc->pid, addr);
223
224	/* If the original instruction was lwarx/ldarx, we can't
225	 * single-step over it, instead we have to execute the whole
226	 * atomic block at once.  */
227	union {
228		uint32_t insn;
229		char buf[4];
230	} u;
231	memcpy(u.buf, sbp->orig_value, BREAKPOINT_LENGTH);
232
233	if ((u.insn & LWARX_MASK) != LWARX_INSTRUCTION
234	    && (u.insn & LWARX_MASK) != LDARX_INSTRUCTION)
235		return 1;
236
237	int insn_count;
238	for (insn_count = 0; ; ++insn_count) {
239		addr += 4;
240		unsigned long l = ptrace(PTRACE_PEEKTEXT, proc->pid, addr, 0);
241		if (l == (unsigned long)-1 && errno)
242			return -1;
243		uint32_t insn;
244#ifdef __powerpc64__
245		insn = l >> 32;
246#else
247		insn = l;
248#endif
249
250		/* If we hit a branch instruction, give up.  The
251		 * computation could escape that way and we'd have to
252		 * treat that case specially.  */
253		if ((insn & BC_MASK) == BC_INSTRUCTION) {
254			debug(1, "pid=%d, found branch at %p, giving up",
255			      proc->pid, addr);
256			return -1;
257		}
258
259		if ((insn & STWCX_MASK) == STWCX_INSTRUCTION
260		    || (insn & STWCX_MASK) == STDCX_INSTRUCTION) {
261			debug(1, "pid=%d, found end of atomic block at %p",
262			      proc->pid, addr);
263			break;
264		}
265
266		/* Arbitrary cut-off.  If we didn't find the
267		 * terminating instruction by now, just give up.  */
268		if (insn_count > 16) {
269			debug(1, "pid=%d, couldn't find end of atomic block",
270			      proc->pid);
271			return -1;
272		}
273	}
274
275	/* Put the breakpoint to the next instruction.  */
276	addr += 4;
277	if (add_cb(addr, add_cb_data) < 0)
278		return -1;
279
280	debug(1, "PTRACE_CONT");
281	ptrace(PTRACE_CONT, proc->pid, 0, 0);
282	return 0;
283}
284