trace.c revision 32e8e76f492a48ee3e6284e237f958b71d4d3e71
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 int 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 /* EABI syscall */ 54 *sysnum = ptrace(PTRACE_PEEKUSER, proc->pid, off_r7, 0); 55 } else if ((insn & 0xfff00000) == 0xef900000) { 56 /* old ABI syscall */ 57 *sysnum = insn & 0xfffff; 58 } else { 59 /* TODO: handle swi<cond> variations */ 60 /* one possible reason for getting in here is that we 61 * are coming from a signal handler, so the current 62 * PC does not point to the instruction just after the 63 * "swi" one. */ 64 output_line(proc, "unexpected instruction 0x%x at %p", insn, pc - 4); 65 return 0; 66 } 67 if ((*sysnum & 0xf0000) == 0xf0000) { 68 /* arch-specific syscall */ 69 *sysnum &= ~0xf0000; 70 return ip ? 4 : 3; 71 } 72 /* ARM syscall convention: on syscall entry, ip is zero; 73 * on syscall exit, ip is non-zero */ 74 return ip ? 2 : 1; 75 } 76 return 0; 77} 78 79long 80gimme_arg(enum tof type, Process *proc, int arg_num, arg_type_info *info) { 81 proc_archdep *a = (proc_archdep *) proc->arch_ptr; 82 83 if (arg_num == -1) { /* return value */ 84 return ptrace(PTRACE_PEEKUSER, proc->pid, off_r0, 0); 85 } 86 87 /* deal with the ARM calling conventions */ 88 if (type == LT_TOF_FUNCTION || type == LT_TOF_FUNCTIONR) { 89 if (arg_num < 4) { 90 if (a->valid && type == LT_TOF_FUNCTION) 91 return a->regs.uregs[arg_num]; 92 if (a->valid && type == LT_TOF_FUNCTIONR) 93 return a->func_arg[arg_num]; 94 return ptrace(PTRACE_PEEKUSER, proc->pid, 4 * arg_num, 95 0); 96 } else { 97 return ptrace(PTRACE_PEEKDATA, proc->pid, 98 proc->stack_pointer + 4 * (arg_num - 4), 99 0); 100 } 101 } else if (type == LT_TOF_SYSCALL || type == LT_TOF_SYSCALLR) { 102 if (arg_num < 5) { 103 if (a->valid && type == LT_TOF_SYSCALL) 104 return a->regs.uregs[arg_num]; 105 if (a->valid && type == LT_TOF_SYSCALLR) 106 return a->sysc_arg[arg_num]; 107 return ptrace(PTRACE_PEEKUSER, proc->pid, 4 * arg_num, 108 0); 109 } else { 110 return ptrace(PTRACE_PEEKDATA, proc->pid, 111 proc->stack_pointer + 4 * (arg_num - 5), 112 0); 113 } 114 } else { 115 fprintf(stderr, "gimme_arg called with wrong arguments\n"); 116 exit(1); 117 } 118 119 return 0; 120} 121 122void 123save_register_args(enum tof type, Process *proc) { 124 proc_archdep *a = (proc_archdep *) proc->arch_ptr; 125 if (a->valid) { 126 if (type == LT_TOF_FUNCTION) 127 memcpy(a->func_arg, a->regs.uregs, sizeof(a->func_arg)); 128 else 129 memcpy(a->sysc_arg, a->regs.uregs, sizeof(a->sysc_arg)); 130 } 131} 132