trace.c revision e276cf41371cd5c5a722043658ccc15321aa15ac
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 /* Since int's are 4-bytes (long is 8-bytes) in length for ppc64, we 185 need to shift the long values returned by ptrace to end up with 186 the correct value. */ 187 188 if (info) { 189 if (info->type == ARGTYPE_INT || (proc->mask_32bit && (info->type == ARGTYPE_POINTER 190 || info->type == ARGTYPE_STRING))) { 191 pointed_to = pointed_to >> 32; 192 193 /* Make sure we have nothing in the upper word so we can 194 do a explicit cast from long to int later in the code. */ 195 pointed_to &= 0x00000000ffffffff; 196 } 197 } 198 199 *result = pointed_to; 200 return 0; 201} 202