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