trace.c revision ba6aca21bd9e0e66dac17b1828cf6b6e7377b983
1#include "config.h" 2 3#include <string.h> 4#include <sys/types.h> 5#include <sys/wait.h> 6#include <signal.h> 7#include <sys/ptrace.h> 8#include <asm/ptrace.h> 9 10#include "common.h" 11#include "output.h" 12#include "ptrace.h" 13 14#if (!defined(PTRACE_PEEKUSER) && defined(PTRACE_PEEKUSR)) 15# define PTRACE_PEEKUSER PTRACE_PEEKUSR 16#endif 17 18#if (!defined(PTRACE_POKEUSER) && defined(PTRACE_POKEUSR)) 19# define PTRACE_POKEUSER PTRACE_POKEUSR 20#endif 21 22#define off_r0 0 23#define off_r7 28 24#define off_ip 48 25#define off_pc 60 26 27void 28get_arch_dep(Process *proc) { 29 proc_archdep *a; 30 31 if (!proc->arch_ptr) 32 proc->arch_ptr = (void *)malloc(sizeof(proc_archdep)); 33 a = (proc_archdep *) (proc->arch_ptr); 34 a->valid = (ptrace(PTRACE_GETREGS, proc->pid, 0, &a->regs) >= 0); 35} 36 37/* Returns 0 if not a syscall, 38 * 1 if syscall entry, 2 if syscall exit, 39 * 3 if arch-specific syscall entry, 4 if arch-specific syscall exit, 40 * -1 on error. 41 */ 42int 43syscall_p(Process *proc, int status, int *sysnum) { 44 if (WIFSTOPPED(status) 45 && WSTOPSIG(status) == (SIGTRAP | proc->tracesysgood)) { 46 /* get the user's pc (plus 8) */ 47 int pc = ptrace(PTRACE_PEEKUSER, proc->pid, off_pc, 0); 48 /* fetch the SWI instruction */ 49 unsigned insn = ptrace(PTRACE_PEEKTEXT, proc->pid, pc - 4, 0); 50 int ip = ptrace(PTRACE_PEEKUSER, proc->pid, off_ip, 0); 51 52 if (insn == 0xef000000 || insn == 0x0f000000 53 || (insn & 0xffff0000) == 0xdf000000) { 54 /* EABI syscall */ 55 *sysnum = ptrace(PTRACE_PEEKUSER, proc->pid, off_r7, 0); 56 } else if ((insn & 0xfff00000) == 0xef900000) { 57 /* old ABI syscall */ 58 *sysnum = insn & 0xfffff; 59 } else { 60 /* TODO: handle swi<cond> variations */ 61 /* one possible reason for getting in here is that we 62 * are coming from a signal handler, so the current 63 * PC does not point to the instruction just after the 64 * "swi" one. */ 65 output_line(proc, "unexpected instruction 0x%x at %p", insn, pc - 4); 66 return 0; 67 } 68 if ((*sysnum & 0xf0000) == 0xf0000) { 69 /* arch-specific syscall */ 70 *sysnum &= ~0xf0000; 71 return ip ? 4 : 3; 72 } 73 /* ARM syscall convention: on syscall entry, ip is zero; 74 * on syscall exit, ip is non-zero */ 75 return ip ? 2 : 1; 76 } 77 return 0; 78} 79 80long 81gimme_arg(enum tof type, Process *proc, int arg_num, arg_type_info *info) { 82 proc_archdep *a = (proc_archdep *) proc->arch_ptr; 83 84 if (arg_num == -1) { /* return value */ 85 return ptrace(PTRACE_PEEKUSER, proc->pid, off_r0, 0); 86 } 87 88 /* deal with the ARM calling conventions */ 89 if (type == LT_TOF_FUNCTION || type == LT_TOF_FUNCTIONR) { 90 if (arg_num < 4) { 91 if (a->valid && type == LT_TOF_FUNCTION) 92 return a->regs.uregs[arg_num]; 93 if (a->valid && type == LT_TOF_FUNCTIONR) 94 return a->func_arg[arg_num]; 95 return ptrace(PTRACE_PEEKUSER, proc->pid, 4 * arg_num, 96 0); 97 } else { 98 return ptrace(PTRACE_PEEKDATA, proc->pid, 99 proc->stack_pointer + 4 * (arg_num - 4), 100 0); 101 } 102 } else if (type == LT_TOF_SYSCALL || type == LT_TOF_SYSCALLR) { 103 if (arg_num < 5) { 104 if (a->valid && type == LT_TOF_SYSCALL) 105 return a->regs.uregs[arg_num]; 106 if (a->valid && type == LT_TOF_SYSCALLR) 107 return a->sysc_arg[arg_num]; 108 return ptrace(PTRACE_PEEKUSER, proc->pid, 4 * arg_num, 109 0); 110 } else { 111 return ptrace(PTRACE_PEEKDATA, proc->pid, 112 proc->stack_pointer + 4 * (arg_num - 5), 113 0); 114 } 115 } else { 116 fprintf(stderr, "gimme_arg called with wrong arguments\n"); 117 exit(1); 118 } 119 120 return 0; 121} 122 123void 124save_register_args(enum tof type, Process *proc) { 125 proc_archdep *a = (proc_archdep *) proc->arch_ptr; 126 if (a->valid) { 127 if (type == LT_TOF_FUNCTION) 128 memcpy(a->func_arg, a->regs.uregs, sizeof(a->func_arg)); 129 else 130 memcpy(a->sysc_arg, a->regs.uregs, sizeof(a->sysc_arg)); 131 } 132} 133