diff options
Diffstat (limited to 'sysdeps/linux-gnu/arm/trace.c')
-rw-r--r-- | sysdeps/linux-gnu/arm/trace.c | 64 |
1 files changed, 54 insertions, 10 deletions
diff --git a/sysdeps/linux-gnu/arm/trace.c b/sysdeps/linux-gnu/arm/trace.c index b5c2122..b9be605 100644 --- a/sysdeps/linux-gnu/arm/trace.c +++ b/sysdeps/linux-gnu/arm/trace.c @@ -2,6 +2,7 @@ #include "config.h" #endif +#include <string.h> #include <sys/types.h> #include <sys/wait.h> #include <signal.h> @@ -9,6 +10,8 @@ #include <asm/ptrace.h> #include "ltrace.h" +#include "output.h" +#include "ptrace.h" #if (!defined(PTRACE_PEEKUSER) && defined(PTRACE_PEEKUSR)) # define PTRACE_PEEKUSER PTRACE_PEEKUSR @@ -18,19 +21,25 @@ # define PTRACE_POKEUSER PTRACE_POKEUSR #endif -/* syscall tracing protocol: ArmLinux - on the way in, ip is 0 - on the way out, ip is non-zero -*/ #define off_r0 0 +#define off_r7 28 #define off_ip 48 #define off_pc 60 void get_arch_dep(struct process *proc) { + proc_archdep *a; + + if (!proc->arch_ptr) + proc->arch_ptr = (void *)malloc(sizeof(proc_archdep)); + a = (proc_archdep *) (proc->arch_ptr); + a->valid = (ptrace(PTRACE_GETREGS, proc->pid, 0, &a->regs) >= 0); } -/* Returns 1 if syscall, 2 if sysret, 0 otherwise. +/* Returns 0 if not a syscall, + * 1 if syscall entry, 2 if syscall exit, + * 3 if arch-specific syscall entry, 4 if arch-specific syscall exit, + * -1 on error. */ int syscall_p(struct process *proc, int status, int *sysnum) { @@ -40,19 +49,39 @@ int syscall_p(struct process *proc, int status, int *sysnum) int pc = ptrace(PTRACE_PEEKUSER, proc->pid, off_pc, 0); /* fetch the SWI instruction */ int insn = ptrace(PTRACE_PEEKTEXT, proc->pid, pc - 4, 0); + int ip = ptrace(PTRACE_PEEKUSER, proc->pid, off_ip, 0); - *sysnum = insn & 0xFFFF; - /* if it is a syscall, return 1 or 2 */ - if ((insn & 0xFFFF0000) == 0xef900000) { - return ptrace(PTRACE_PEEKUSER, proc->pid, off_ip, - 0) ? 2 : 1; + if (insn == 0xef000000 || insn == 0x0f000000) { + /* EABI syscall */ + *sysnum = ptrace(PTRACE_PEEKUSER, proc->pid, off_r7, 0); + } else if ((insn & 0xfff00000) == 0xef900000) { + /* old ABI syscall */ + *sysnum = insn & 0xfffff; + } else { + /* TODO: handle swi<cond> variations */ + /* one possible reason for getting in here is that we + * are coming from a signal handler, so the current + * PC does not point to the instruction just after the + * "swi" one. */ + output_line(proc, "unexpected instruction 0x%x at %p", insn, pc - 4); + return -1; + } + if ((*sysnum & 0xf0000) == 0xf0000) { + /* arch-specific syscall */ + *sysnum &= ~0xf0000; + return ip ? 4 : 3; } + /* ARM syscall convention: on syscall entry, ip is zero; + * on syscall exit, ip is non-zero */ + return ip ? 2 : 1; } return 0; } long gimme_arg(enum tof type, struct process *proc, int arg_num, arg_type_info *info) { + proc_archdep *a = (proc_archdep *) proc->arch_ptr; + if (arg_num == -1) { /* return value */ return ptrace(PTRACE_PEEKUSER, proc->pid, off_r0, 0); } @@ -60,6 +89,10 @@ long gimme_arg(enum tof type, struct process *proc, int arg_num, arg_type_info * /* deal with the ARM calling conventions */ if (type == LT_TOF_FUNCTION || type == LT_TOF_FUNCTIONR) { if (arg_num < 4) { + if (a->valid && type == LT_TOF_FUNCTION) + return a->regs.uregs[arg_num]; + if (a->valid && type == LT_TOF_FUNCTIONR) + return a->func_arg[arg_num]; return ptrace(PTRACE_PEEKUSER, proc->pid, 4 * arg_num, 0); } else { @@ -69,6 +102,10 @@ long gimme_arg(enum tof type, struct process *proc, int arg_num, arg_type_info * } } else if (type == LT_TOF_SYSCALL || type == LT_TOF_SYSCALLR) { if (arg_num < 5) { + if (a->valid && type == LT_TOF_SYSCALL) + return a->regs.uregs[arg_num]; + if (a->valid && type == LT_TOF_SYSCALLR) + return a->sysc_arg[arg_num]; return ptrace(PTRACE_PEEKUSER, proc->pid, 4 * arg_num, 0); } else { @@ -86,4 +123,11 @@ long gimme_arg(enum tof type, struct process *proc, int arg_num, arg_type_info * void save_register_args(enum tof type, struct process *proc) { + proc_archdep *a = (proc_archdep *) proc->arch_ptr; + if (a->valid) { + if (type == LT_TOF_FUNCTION) + memcpy(a->func_arg, a->regs.uregs, sizeof(a->func_arg)); + else + memcpy(a->sysc_arg, a->regs.uregs, sizeof(a->sysc_arg)); + } } |