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