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(®); 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(®); 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(®); 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