trace.c revision a266acb9c3bbde884a32268f164de62d03aa04d0
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 "common.h" 13#include "ptrace.h" 14 15#if (!defined(PTRACE_PEEKUSER) && defined(PTRACE_PEEKUSR)) 16# define PTRACE_PEEKUSER PTRACE_PEEKUSR 17#endif 18 19#if (!defined(PTRACE_POKEUSER) && defined(PTRACE_POKEUSR)) 20# define PTRACE_POKEUSER PTRACE_POKEUSR 21#endif 22 23void 24get_arch_dep(Process *proc) { 25 if (proc->arch_ptr == NULL) { 26 proc->arch_ptr = malloc(sizeof(proc_archdep)); 27#ifdef __powerpc64__ 28 proc->mask_32bit = (proc->e_machine == EM_PPC); 29#endif 30 } 31 32 proc_archdep *a = (proc_archdep *) (proc->arch_ptr); 33 a->valid = (ptrace(PTRACE_GETREGS, proc->pid, 0, &a->regs) >= 0) 34 && (ptrace(PTRACE_GETFPREGS, proc->pid, 0, &a->fpregs) >= 0); 35} 36 37#define SYSCALL_INSN 0x44000002 38 39unsigned int greg = 3; 40unsigned int freg = 1; 41 42/* Returns 1 if syscall, 2 if sysret, 0 otherwise. */ 43int 44syscall_p(Process *proc, int status, int *sysnum) { 45 if (WIFSTOPPED(status) 46 && WSTOPSIG(status) == (SIGTRAP | proc->tracesysgood)) { 47 long pc = (long)get_instruction_pointer(proc); 48 int insn = 49 (int)ptrace(PTRACE_PEEKTEXT, proc->pid, pc - sizeof(long), 50 0); 51 52 if (insn == SYSCALL_INSN) { 53 *sysnum = 54 (int)ptrace(PTRACE_PEEKUSER, proc->pid, 55 sizeof(long) * PT_R0, 0); 56 if (proc->callstack_depth > 0 && 57 proc->callstack[proc->callstack_depth - 1].is_syscall && 58 proc->callstack[proc->callstack_depth - 1].c_un.syscall == *sysnum) { 59 return 2; 60 } 61 return 1; 62 } 63 } 64 return 0; 65} 66 67static long 68gimme_arg_regset(enum tof type, Process *proc, int arg_num, arg_type_info *info, 69 gregset_t *regs, fpregset_t *fpregs) 70{ 71 union { long val; float fval; double dval; } cvt; 72 73 if (info->type == ARGTYPE_FLOAT || info->type == ARGTYPE_DOUBLE) { 74 if (freg <= 13 || (proc->mask_32bit && freg <= 8)) { 75 double val = GET_FPREG(*fpregs, freg); 76 77 if (info->type == ARGTYPE_FLOAT) 78 cvt.fval = val; 79 else 80 cvt.dval = val; 81 82 freg++; 83 greg++; 84 85 return cvt.val; 86 } 87 } 88 else if (greg <= 10) 89 return (*regs)[greg++]; 90 else { 91#ifdef __powerpc64__ 92 if (proc->mask_32bit) 93 return ptrace (PTRACE_PEEKDATA, proc->pid, 94 proc->stack_pointer + 8 + 95 sizeof (int) * (arg_num - 8), 0) >> 32; 96 else 97 return ptrace (PTRACE_PEEKDATA, proc->pid, 98 proc->stack_pointer + 112 + 99 sizeof (long) * (arg_num - 8), 0); 100#else 101 return ptrace (PTRACE_PEEKDATA, proc->pid, 102 proc->stack_pointer + 8 + 103 sizeof (long) * (arg_num - 8), 0); 104#endif 105 } 106 107 return 0; 108} 109 110static long 111gimme_retval(Process *proc, int arg_num, arg_type_info *info, 112 gregset_t *regs, fpregset_t *fpregs) 113{ 114 union { long val; float fval; double dval; } cvt; 115 if (info->type == ARGTYPE_FLOAT || info->type == ARGTYPE_DOUBLE) { 116 double val = GET_FPREG(*fpregs, 1); 117 118 if (info->type == ARGTYPE_FLOAT) 119 cvt.fval = val; 120 else 121 cvt.dval = val; 122 123 return cvt.val; 124 } 125 else 126 return (*regs)[3]; 127} 128 129/* Grab functions arguments based on the PPC64 ABI. */ 130long 131gimme_arg(enum tof type, Process *proc, int arg_num, arg_type_info *info) 132{ 133 proc_archdep *arch = (proc_archdep *)proc->arch_ptr; 134 if (arch == NULL || !arch->valid) 135 return -1; 136 137 /* Check if we're entering a new function call to list parameters. If 138 so, initialize the register control variables to keep track of where 139 the parameters were stored. */ 140 if ((type == LT_TOF_FUNCTION || type == LT_TOF_FUNCTIONR) 141 && arg_num == 0) { 142 /* Initialize the set of registrers for parameter passing. */ 143 greg = 3; 144 freg = 1; 145 } 146 147 148 if (type == LT_TOF_FUNCTIONR) { 149 if (arg_num == -1) 150 return gimme_retval(proc, arg_num, info, 151 &arch->regs, &arch->fpregs); 152 else 153 return gimme_arg_regset(type, proc, arg_num, info, 154 &arch->regs_copy, 155 &arch->fpregs_copy); 156 } 157 else 158 return gimme_arg_regset(type, proc, arg_num, info, 159 &arch->regs, &arch->fpregs); 160} 161 162void 163save_register_args(enum tof type, Process *proc) { 164 proc_archdep *arch = (proc_archdep *)proc->arch_ptr; 165 if (arch == NULL || !arch->valid) 166 return; 167 168 memcpy(&arch->regs_copy, &arch->regs, sizeof(arch->regs)); 169 memcpy(&arch->fpregs_copy, &arch->fpregs, sizeof(arch->fpregs)); 170} 171 172/* Read a single long from the process's memory address 'addr'. */ 173int 174arch_umovelong (Process *proc, void *addr, long *result, arg_type_info *info) { 175 long pointed_to; 176 177 errno = 0; 178 179 pointed_to = ptrace (PTRACE_PEEKTEXT, proc->pid, addr, 0); 180 181 if (pointed_to == -1 && errno) 182 return -errno; 183 184#if SIZEOF_LONG == 8 185 /* Since int's are 4-bytes (long is 8-bytes) in length for ppc64, we 186 need to shift the long values returned by ptrace to end up with 187 the correct value. */ 188 189 if (info) { 190 if (info->type == ARGTYPE_INT || (proc->mask_32bit && (info->type == ARGTYPE_POINTER 191 || info->type == ARGTYPE_STRING))) { 192 pointed_to = (long) (((unsigned long) pointed_to) >> 32); 193 } 194 } 195#endif 196 197 *result = pointed_to; 198 return 0; 199} 200 201/* The atomic skip code is mostly taken from GDB. */ 202 203/* Instruction masks used during single-stepping of atomic 204 * sequences. This was lifted from GDB. */ 205#define LWARX_MASK 0xfc0007fe 206#define LWARX_INSTRUCTION 0x7c000028 207#define LDARX_INSTRUCTION 0x7c0000A8 208#define STWCX_MASK 0xfc0007ff 209#define STWCX_INSTRUCTION 0x7c00012d 210#define STDCX_INSTRUCTION 0x7c0001ad 211#define BC_MASK 0xfc000000 212#define BC_INSTRUCTION 0x40000000 213 214int 215arch_atomic_singlestep(struct Process *proc, Breakpoint *sbp, 216 int (*add_cb)(void *addr, void *data), 217 void *add_cb_data) 218{ 219 void *addr = sbp->addr; 220 debug(1, "pid=%d addr=%p", proc->pid, addr); 221 222 /* If the original instruction was lwarx/ldarx, we can't 223 * single-step over it, instead we have to execute the whole 224 * atomic block at once. */ 225 union { 226 uint32_t insn; 227 char buf[4]; 228 } u; 229 memcpy(u.buf, sbp->orig_value, BREAKPOINT_LENGTH); 230 231 if ((u.insn & LWARX_MASK) != LWARX_INSTRUCTION 232 && (u.insn & LWARX_MASK) != LDARX_INSTRUCTION) 233 return 1; 234 235 int insn_count; 236 for (insn_count = 0; ; ++insn_count) { 237 addr += 4; 238 unsigned long l = ptrace(PTRACE_PEEKTEXT, proc->pid, addr, 0); 239 if (l == (unsigned long)-1 && errno) 240 return -1; 241 uint32_t insn; 242#ifdef __powerpc64__ 243 insn = l >> 32; 244#else 245 insn = l; 246#endif 247 248 /* If we hit a branch instruction, give up. The 249 * computation could escape that way and we'd have to 250 * treat that case specially. */ 251 if ((insn & BC_MASK) == BC_INSTRUCTION) { 252 debug(1, "pid=%d, found branch at %p, giving up", 253 proc->pid, addr); 254 return -1; 255 } 256 257 if ((insn & STWCX_MASK) == STWCX_INSTRUCTION 258 || (insn & STWCX_MASK) == STDCX_INSTRUCTION) { 259 debug(1, "pid=%d, found end of atomic block at %p", 260 proc->pid, addr); 261 break; 262 } 263 264 /* Arbitrary cut-off. If we didn't find the 265 * terminating instruction by now, just give up. */ 266 if (insn_count > 16) { 267 debug(1, "pid=%d, couldn't find end of atomic block", 268 proc->pid); 269 return -1; 270 } 271 } 272 273 /* Put the breakpoint to the next instruction. */ 274 addr += 4; 275 if (add_cb(addr, add_cb_data) < 0) 276 return -1; 277 278 debug(1, "PTRACE_CONT"); 279 ptrace(PTRACE_CONT, proc->pid, 0, 0); 280 return 0; 281} 282