trace.c revision f728123bd75a65a6a1536e198c3c30719e494e71
1#if HAVE_CONFIG_H
2#include "config.h"
3#endif
4
5#include <stdlib.h>
6#include <stddef.h>
7#include <sys/types.h>
8#include <sys/wait.h>
9#include <signal.h>
10#include <sys/ptrace.h>
11#include <string.h>
12#include <asm/ptrace_offsets.h>
13#include <asm/rse.h>
14
15#include "common.h"
16
17/* What we think of as a bundle, ptrace thinks of it as two unsigned
18 * longs */
19union bundle_t {
20	/* An IA64 instruction bundle has a 5 bit header describing the
21	 * type of bundle, then 3 41 bit instructions
22	 */
23	struct {
24		struct {
25			unsigned long template:5;
26			unsigned long slot0:41;
27			unsigned long bot_slot1:18;
28		} word0;
29		struct {
30			unsigned long top_slot1:23;
31			unsigned long slot2:41;
32		} word1;
33	} bitmap;
34	unsigned long code[2];
35};
36
37union cfm_t {
38	struct {
39		unsigned long sof:7;
40		unsigned long sol:7;
41		unsigned long sor:4;
42		unsigned long rrb_gr:7;
43		unsigned long rrb_fr:7;
44		unsigned long rrb_pr:6;
45	} cfm;
46	unsigned long value;
47};
48
49int
50syscall_p(Process *proc, int status, int *sysnum) {
51	if (WIFSTOPPED(status)
52	    && WSTOPSIG(status) == (SIGTRAP | proc->tracesysgood)) {
53		unsigned long slot =
54		    (ptrace(PTRACE_PEEKUSER, proc->pid, PT_CR_IPSR, 0) >> 41) &
55		    0x3;
56		unsigned long ip =
57		    ptrace(PTRACE_PEEKUSER, proc->pid, PT_CR_IIP, 0);
58
59		/* r15 holds the system call number */
60		unsigned long r15 =
61		    ptrace(PTRACE_PEEKUSER, proc->pid, PT_R15, 0);
62		unsigned long insn;
63
64		union bundle_t bundle;
65
66		/* On fault, the IP has moved forward to the next
67		 * slot.  If that is zero, then the actual place we
68		 * broke was in the previous bundle, so wind back the
69		 * IP.
70		 */
71		if (slot == 0)
72			ip = ip - 16;
73		bundle.code[0] = ptrace(PTRACE_PEEKTEXT, proc->pid, ip, 0);
74		bundle.code[1] = ptrace(PTRACE_PEEKTEXT, proc->pid, ip + 8, 0);
75
76		unsigned long bot = 0UL | bundle.bitmap.word0.bot_slot1;
77		unsigned long top = 0UL | bundle.bitmap.word1.top_slot1;
78
79		/* handle the rollback, slot 0 is actually slot 2 of
80		 * the previous instruction (see above) */
81		switch (slot) {
82		case 0:
83			insn = bundle.bitmap.word1.slot2;
84			break;
85		case 1:
86			insn = bundle.bitmap.word0.slot0;
87			break;
88		case 2:
89			/* make sure we're shifting about longs */
90			insn = 0UL | bot | (top << 18UL);
91			break;
92		default:
93			printf("Ummm, can't find instruction slot?\n");
94			exit(1);
95		}
96
97		/* We need to support both the older break instruction
98		 * type syscalls, and the new epc type ones.
99		 *
100		 * Bit 20 of the break constant is encoded in the "i"
101		 * bit (bit 36) of the instruction, hence you should
102		 * see 0x1000000000.
103		 *
104		 *  An EPC call is just 0x1ffffffffff
105		 */
106		if (insn == 0x1000000000 || insn == 0x1ffffffffff) {
107			*sysnum = r15;
108			if (proc->callstack_depth > 0 &&
109				proc->callstack[proc->callstack_depth - 1].is_syscall &&
110				proc->callstack[proc->callstack_depth - 1].c_un.syscall == *sysnum) {
111				return 2;
112			}
113			return 1;
114		}
115	}
116	return 0;
117}
118
119/* Stolen from David Mosberger's utrace tool, which he released under
120   the GPL
121   (http://www.gelato.unsw.edu.au/archives/linux-ia64/0104/1405.html) */
122static inline double
123fpreg_to_double (struct ia64_fpreg *fp) {
124  double result;
125
126  asm ("ldf.fill %0=%1" : "=f"(result) : "m"(*fp));
127  return result;
128}
129
130static long
131gimme_long_arg(enum tof type, Process *proc, int arg_num) {
132	union cfm_t cfm;
133	unsigned long bsp;
134
135	bsp = ptrace(PTRACE_PEEKUSER, proc->pid, PT_AR_BSP, 0);
136	cfm.value = ptrace(PTRACE_PEEKUSER, proc->pid, PT_CFM, 0);
137
138	if (arg_num == -1)	/* return value */
139		return ptrace(PTRACE_PEEKUSER, proc->pid, PT_R8, 0);
140
141	/* First 8 arguments are passed in registers on the register
142	 * stack, the following arguments are passed on the stack
143	 * after a 16 byte scratch area
144	 *
145	 * If the function has returned, the ia64 register window has
146	 * been reverted to the caller's configuration. So although in
147	 * the callee, the first parameter is in R32, in the caller
148	 * the first parameter comes in the registers after the local
149	 * registers (really, input parameters plus locals, but the
150	 * hardware doesn't track the distinction.) So we have to add
151	 * in the size of the local area (sol) to find the first
152	 * parameter passed to the callee. */
153	if (type == LT_TOF_FUNCTION || type == LT_TOF_FUNCTIONR) {
154		if (arg_num < 8) {
155                        if (type == LT_TOF_FUNCTIONR)
156				arg_num += cfm.cfm.sol;
157
158			return ptrace(PTRACE_PEEKDATA, proc->pid,
159				      (long)ia64_rse_skip_regs((unsigned long *)bsp,
160							       -cfm.cfm.sof + arg_num),
161				      0);
162		} else {
163			unsigned long sp =
164			    ptrace(PTRACE_PEEKUSER, proc->pid, PT_R12, 0) + 16;
165			return ptrace(PTRACE_PEEKDATA, proc->pid,
166				      sp + (8 * (arg_num - 8)));
167		}
168	}
169
170	if (type == LT_TOF_SYSCALL || LT_TOF_SYSCALLR)
171		return ptrace(PTRACE_PEEKDATA, proc->pid,
172			      (long)ia64_rse_skip_regs((unsigned long *)bsp, arg_num),
173			      0);
174
175	/* error if we get here */
176	fprintf(stderr, "gimme_arg called with wrong arguments\n");
177	exit(1);
178}
179
180static long float_regs[8] = { PT_F8, PT_F9, PT_F10, PT_F11,
181			      PT_F12, PT_F13, PT_F14, PT_F15 };
182static double
183gimme_float_arg(enum tof type, Process *proc, int arg_num) {
184	union cfm_t cfm;
185	unsigned long bsp;
186	struct ia64_fpreg reg;
187
188	if (arg_num == -1) {	/* return value */
189		reg.u.bits[0] = ptrace(PTRACE_PEEKUSER, proc->pid,
190				       PT_F8, 0);
191		reg.u.bits[1] = ptrace(PTRACE_PEEKUSER, proc->pid,
192				       PT_F8 + 0x8, 0);
193		return fpreg_to_double(&reg);
194	}
195
196	bsp = ptrace(PTRACE_PEEKUSER, proc->pid, PT_AR_BSP, 0);
197	cfm.value = ptrace(PTRACE_PEEKUSER, proc->pid, PT_CFM, 0);
198
199	/* The first 8 arguments are passed in regular registers
200	 * (counting from R32), unless they are floating point values
201	 * (the case in question here). In that case, up to the first
202	 * 8 regular registers are still "allocated" for each of the
203	 * first 8 parameters, but if a parameter is floating point,
204	 * then the register is left unset and the parameter is passed
205	 * in the first available floating-point register, counting
206	 * from F8.
207	 *
208	 * Take func(int a, float f, int b, double d), for example.
209	 *    a - passed in R32
210	 *    f - R33 left unset, value passed in F8
211	 *    b - passed in R34
212	 *    d - R35 left unset, value passed in F9
213	 *
214	 * ltrace handles this by counting floating point arguments
215	 * while parsing declarations. The "arg_num" in this routine
216	 * (which is only called for floating point values) really
217	 * means which floating point parameter we're looking for,
218	 * ignoring everything else.
219	 *
220	 * Following the first 8 arguments, the remaining arguments
221	 * are passed on the stack after a 16 byte scratch area
222	 */
223	if (type == LT_TOF_FUNCTION || type == LT_TOF_FUNCTIONR) {
224		if (arg_num < 8) {
225			reg.u.bits[0] = ptrace(PTRACE_PEEKUSER, proc->pid,
226					       float_regs[arg_num], 0);
227			reg.u.bits[1] = ptrace(PTRACE_PEEKUSER, proc->pid,
228					       float_regs[arg_num] + 0x8, 0);
229			return fpreg_to_double(&reg);
230		} else {
231			unsigned long sp =
232			    ptrace(PTRACE_PEEKUSER, proc->pid, PT_R12, 0) + 16;
233			reg.u.bits[0] = ptrace(PTRACE_PEEKDATA, proc->pid,
234					       sp + (8 * (arg_num - 8)));
235			reg.u.bits[0] = ptrace(PTRACE_PEEKDATA, proc->pid,
236					       sp + (8 * (arg_num - 8)) + 0x8);
237			return fpreg_to_double(&reg);
238		}
239	}
240
241	/* error if we get here */
242	fprintf(stderr, "gimme_arg called with wrong arguments\n");
243	exit(1);
244}
245
246long
247gimme_arg(enum tof type, Process *proc, int arg_num, arg_type_info *info) {
248	union {
249		long l;
250		float f;
251		double d;
252	} cvt;
253
254	if (info->type == ARGTYPE_FLOAT)
255		cvt.f = gimme_float_arg(type, proc, info->u.float_info.float_index);
256	else if (info->type == ARGTYPE_DOUBLE)
257		cvt.d = gimme_float_arg(type, proc, info->u.double_info.float_index);
258	else
259		cvt.l = gimme_long_arg(type, proc, arg_num);
260
261	return cvt.l;
262}
263
264void
265save_register_args(enum tof type, Process *proc) {
266}
267
268void
269get_arch_dep(Process *proc) {
270}
271