trace.c revision 46a41f7c72828f2f43a640e0ce1fbb41d7a196e9
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/* The atomic skip code is mostly taken from GDB. */ 177 178/* Instruction masks used during single-stepping of atomic 179 * sequences. This was lifted from GDB. */ 180#define LWARX_MASK 0xfc0007fe 181#define LWARX_INSTRUCTION 0x7c000028 182#define LDARX_INSTRUCTION 0x7c0000A8 183#define STWCX_MASK 0xfc0007ff 184#define STWCX_INSTRUCTION 0x7c00012d 185#define STDCX_INSTRUCTION 0x7c0001ad 186#define BC_MASK 0xfc000000 187#define BC_INSN 0x40000000 188#define BRANCH_MASK 0xfc000000 189 190/* In plt.h. XXX make this official interface. */ 191int read_target_4(struct Process *proc, target_address_t addr, uint32_t *lp); 192 193int 194arch_atomic_singlestep(struct Process *proc, struct breakpoint *sbp, 195 int (*add_cb)(void *addr, void *data), 196 void *add_cb_data) 197{ 198 target_address_t ip = get_instruction_pointer(proc); 199 struct breakpoint *other = address2bpstruct(proc->leader, ip); 200 201 debug(1, "arch_atomic_singlestep pid=%d addr=%p %s(%p)", 202 proc->pid, ip, breakpoint_name(sbp), sbp->addr); 203 204 /* If the original instruction was lwarx/ldarx, we can't 205 * single-step over it, instead we have to execute the whole 206 * atomic block at once. */ 207 union { 208 uint32_t insn; 209 char buf[BREAKPOINT_LENGTH]; 210 } u; 211 if (other != NULL) { 212 memcpy(u.buf, sbp->orig_value, BREAKPOINT_LENGTH); 213 } else if (read_target_4(proc, ip, &u.insn) < 0) { 214 fprintf(stderr, "couldn't read instruction at IP %p\n", ip); 215 /* Do the normal singlestep. */ 216 return 1; 217 } 218 219 if ((u.insn & LWARX_MASK) != LWARX_INSTRUCTION 220 && (u.insn & LWARX_MASK) != LDARX_INSTRUCTION) 221 return 1; 222 223 debug(1, "singlestep over atomic block at %p", ip); 224 225 int insn_count; 226 target_address_t addr = ip; 227 for (insn_count = 0; ; ++insn_count) { 228 addr += 4; 229 unsigned long l = ptrace(PTRACE_PEEKTEXT, proc->pid, addr, 0); 230 if (l == (unsigned long)-1 && errno) 231 return -1; 232 uint32_t insn; 233#ifdef __powerpc64__ 234 insn = l >> 32; 235#else 236 insn = l; 237#endif 238 239 /* If a conditional branch is found, put a breakpoint 240 * in its destination address. */ 241 if ((insn & BRANCH_MASK) == BC_INSN) { 242 int immediate = ((insn & 0xfffc) ^ 0x8000) - 0x8000; 243 int absolute = insn & 2; 244 245 /* XXX drop the following casts. */ 246 target_address_t branch_addr; 247 if (absolute) 248 branch_addr = (void *)(uintptr_t)immediate; 249 else 250 branch_addr = addr + (uintptr_t)immediate; 251 252 debug(1, "pid=%d, branch in atomic block from %p to %p", 253 proc->pid, addr, branch_addr); 254 if (add_cb(branch_addr, add_cb_data) < 0) 255 return -1; 256 } 257 258 /* Assume that the atomic sequence ends with a 259 * stwcx/stdcx instruction. */ 260 if ((insn & STWCX_MASK) == STWCX_INSTRUCTION 261 || (insn & STWCX_MASK) == STDCX_INSTRUCTION) { 262 debug(1, "pid=%d, found end of atomic block %p at %p", 263 proc->pid, ip, addr); 264 break; 265 } 266 267 /* Arbitrary cut-off. If we didn't find the 268 * terminating instruction by now, just give up. */ 269 if (insn_count > 16) { 270 fprintf(stderr, "[%d] couldn't find end of atomic block" 271 " at %p\n", proc->pid, ip); 272 return -1; 273 } 274 } 275 276 /* Put the breakpoint to the next instruction. */ 277 addr += 4; 278 if (add_cb(addr, add_cb_data) < 0) 279 return -1; 280 281 debug(1, "PTRACE_CONT"); 282 ptrace(PTRACE_CONT, proc->pid, 0, 0); 283 return 0; 284} 285