trace.c revision 87e1a5cc080cdab488a6c7076aa5c86dfe1c26f0
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 return ptrace (PTRACE_PEEKDATA, proc->pid, 92 proc->stack_pointer + sizeof (long) * 93 (arg_num - 8), 0); 94 95 return 0; 96} 97 98static long 99gimme_retval(Process *proc, int arg_num, arg_type_info *info, 100 gregset_t *regs, fpregset_t *fpregs) 101{ 102 union { long val; float fval; double dval; } cvt; 103 if (info->type == ARGTYPE_FLOAT || info->type == ARGTYPE_DOUBLE) { 104 double val = GET_FPREG(*fpregs, 1); 105 106 if (info->type == ARGTYPE_FLOAT) 107 cvt.fval = val; 108 else 109 cvt.dval = val; 110 111 return cvt.val; 112 } 113 else 114 return (*regs)[3]; 115} 116 117/* Grab functions arguments based on the PPC64 ABI. */ 118long 119gimme_arg(enum tof type, Process *proc, int arg_num, arg_type_info *info) 120{ 121 proc_archdep *arch = (proc_archdep *)proc->arch_ptr; 122 if (arch == NULL || !arch->valid) 123 return -1; 124 125 /* Check if we're entering a new function call to list parameters. If 126 so, initialize the register control variables to keep track of where 127 the parameters were stored. */ 128 if ((type == LT_TOF_FUNCTION || type == LT_TOF_FUNCTIONR) 129 && arg_num == 0) { 130 /* Initialize the set of registrers for parameter passing. */ 131 greg = 3; 132 freg = 1; 133 } 134 135 136 if (type == LT_TOF_FUNCTIONR) { 137 if (arg_num == -1) 138 return gimme_retval(proc, arg_num, info, 139 &arch->regs, &arch->fpregs); 140 else 141 return gimme_arg_regset(type, proc, arg_num, info, 142 &arch->regs_copy, 143 &arch->fpregs_copy); 144 } 145 else 146 return gimme_arg_regset(type, proc, arg_num, info, 147 &arch->regs, &arch->fpregs); 148} 149 150void 151save_register_args(enum tof type, Process *proc) { 152 proc_archdep *arch = (proc_archdep *)proc->arch_ptr; 153 if (arch == NULL || !arch->valid) 154 return; 155 156 memcpy(&arch->regs_copy, &arch->regs, sizeof(arch->regs)); 157 memcpy(&arch->fpregs_copy, &arch->fpregs, sizeof(arch->fpregs)); 158} 159 160/* Read a single long from the process's memory address 'addr'. */ 161int 162arch_umovelong (Process *proc, void *addr, long *result, arg_type_info *info) { 163 long pointed_to; 164 165 errno = 0; 166 167 pointed_to = ptrace (PTRACE_PEEKTEXT, proc->pid, addr, 0); 168 169 if (pointed_to == -1 && errno) 170 return -errno; 171 172 /* Since int's are 4-bytes (long is 8-bytes) in length for ppc64, we 173 need to shift the long values returned by ptrace to end up with 174 the correct value. */ 175 176 if (info) { 177 if (info->type == ARGTYPE_INT || (proc->mask_32bit && (info->type == ARGTYPE_POINTER 178 || info->type == ARGTYPE_STRING))) { 179 pointed_to = pointed_to >> 32; 180 181 /* Make sure we have nothing in the upper word so we can 182 do a explicit cast from long to int later in the code. */ 183 pointed_to &= 0x00000000ffffffff; 184 } 185 } 186 187 *result = pointed_to; 188 return 0; 189} 190