trace.c revision a8909f71e1421949c960f287217be6c42c286c0f
1#if HAVE_CONFIG_H 2#include "config.h" 3#endif 4 5#include <sys/types.h> 6#include <sys/wait.h> 7#include <signal.h> 8#include <sys/ptrace.h> 9#include <asm/ptrace.h> 10#include <elf.h> 11#include <errno.h> 12 13#include "ltrace.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#ifdef __powerpc64__ 26 if (proc->arch_ptr) 27 return; 28 proc->mask_32bit = (proc->e_machine == EM_PPC); 29 proc->arch_ptr = (void *)1; 30#endif 31} 32 33/* Returns 1 if syscall, 2 if sysret, 0 otherwise. */ 34#define SYSCALL_INSN 0x44000002 35 36unsigned int greg = 3; 37unsigned int freg = 1; 38unsigned int vreg = 2; 39 40int 41syscall_p(Process *proc, int status, int *sysnum) { 42 if (WIFSTOPPED(status) 43 && WSTOPSIG(status) == (SIGTRAP | proc->tracesysgood)) { 44 long pc = (long)get_instruction_pointer(proc); 45 int insn = 46 (int)ptrace(PTRACE_PEEKTEXT, proc->pid, pc - sizeof(long), 47 0); 48 49 if (insn == SYSCALL_INSN) { 50 *sysnum = 51 (int)ptrace(PTRACE_PEEKUSER, proc->pid, 52 sizeof(long) * PT_R0, 0); 53 if (proc->callstack_depth > 0 54 && proc->callstack[proc->callstack_depth - 55 1].is_syscall) { 56 return 2; 57 } 58 return 1; 59 } 60 } 61 return 0; 62} 63 64/* Grab functions arguments based on the PPC64 ABI. */ 65long 66gimme_arg(enum tof type, Process *proc, int arg_num, arg_type_info *info) { 67 long data; 68 69 if (type == LT_TOF_FUNCTIONR) { 70 if (info->type == ARGTYPE_FLOAT || info->type == ARGTYPE_DOUBLE) 71 return ptrace (PTRACE_PEEKUSER, proc->pid, 72 sizeof (long) * (PT_FPR0 + 1), 0); 73 else 74 return ptrace (PTRACE_PEEKUSER, proc->pid, 75 sizeof (long) * PT_R3, 0); 76 } 77 78 /* Check if we're entering a new function call to list parameters. If 79 so, initialize the register control variables to keep track of where 80 the parameters were stored. */ 81 if (type == LT_TOF_FUNCTION && arg_num == 0) { 82 /* Initialize the set of registrers for parameter passing. */ 83 greg = 3; 84 freg = 1; 85 vreg = 2; 86 } 87 88 if (info->type == ARGTYPE_FLOAT || info->type == ARGTYPE_DOUBLE) { 89 if (freg <= 13 || (proc->mask_32bit && freg <= 8)) { 90 data = ptrace (PTRACE_PEEKUSER, proc->pid, 91 sizeof (long) * (PT_FPR0 + freg), 0); 92 93 if (info->type == ARGTYPE_FLOAT) { 94 /* float values passed in FP registers are automatically 95 promoted to double. We need to convert it back to float 96 before printing. */ 97 union { long val; float fval; double dval; } cvt; 98 cvt.val = data; 99 cvt.fval = (float) cvt.dval; 100 data = cvt.val; 101 } 102 103 freg++; 104 greg++; 105 106 return data; 107 } 108 } 109 else if (greg <= 10) { 110 data = ptrace (PTRACE_PEEKUSER, proc->pid, 111 sizeof (long) * greg, 0); 112 greg++; 113 114 return data; 115 } 116 else 117 return ptrace (PTRACE_PEEKDATA, proc->pid, 118 proc->stack_pointer + sizeof (long) * 119 (arg_num - 8), 0); 120 121 return 0; 122} 123 124void 125save_register_args(enum tof type, Process *proc) { 126} 127 128/* Read a single long from the process's memory address 'addr'. */ 129int 130arch_umovelong (Process *proc, void *addr, long *result, arg_type_info *info) { 131 long pointed_to; 132 133 errno = 0; 134 135 pointed_to = ptrace (PTRACE_PEEKTEXT, proc->pid, addr, 0); 136 137 if (pointed_to == -1 && errno) 138 return -errno; 139 140 /* Since int's are 4-bytes (long is 8-bytes) in length for ppc64, we 141 need to shift the long values returned by ptrace to end up with 142 the correct value. */ 143 144 if (info) { 145 if (info->type == ARGTYPE_INT || (proc->mask_32bit && (info->type == ARGTYPE_POINTER 146 || info->type == ARGTYPE_STRING))) { 147 pointed_to = pointed_to >> 32; 148 149 /* Make sure we have nothing in the upper word so we can 150 do a explicit cast from long to int later in the code. */ 151 pointed_to &= 0x00000000ffffffff; 152 } 153 } 154 155 *result = pointed_to; 156 return 0; 157} 158