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