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