aboutsummaryrefslogtreecommitdiff
path: root/sysdeps/linux-gnu/arm/trace.c
diff options
context:
space:
mode:
Diffstat (limited to 'sysdeps/linux-gnu/arm/trace.c')
-rw-r--r--sysdeps/linux-gnu/arm/trace.c64
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));
+ }
}