[PATCH] Fix ARM strace support
Russell King
rmk at arm.linux.org.uk
Fri Apr 25 03:50:02 UTC 2003
Hi,
It seems that strace is fairly sub-optimal on ARM, and ignores the syscall
"entry/exit" flag which has been passed since the year dot.
Here's a patch against strace 4.4+ia64 support to fix up ARM support.
(I guess the two hunks in defs.h and process.c which are affected by
ia64 support will need to be applied by hand anyway.)
diff -ur strace-4.4-orig/defs.h strace-4.4/defs.h
--- strace-4.4-orig/defs.h Fri Jul 13 23:07:44 2001
+++ strace-4.4/defs.h Fri Apr 25 11:13:01 2003
@@ -284,7 +284,7 @@
#define TCB_FOLLOWFORK 00400 /* Process should have forks followed */
#define TCB_REPRINT 01000 /* We should reprint this syscall on exit */
#ifdef LINUX
-#if defined(ALPHA) || defined(SPARC) || defined(POWERPC) || defined(HPPA) || defined(IA64)
+#if defined(ALPHA) || defined(SPARC) || defined(POWERPC) || defined(HPPA) || defined(IA64) || defined(ARM)
/* When execve'ing an ELF binary, the kernel sends an extra SIGTRAP
which we need to ignore. */
#define TCB_WAITEXECVE 02000 /* ignore SIGTRAP after exceve */
diff -ur strace-4.4-orig/process.c strace-4.4/process.c
--- strace-4.4-orig/process.c Fri Aug 3 12:51:28 2001
+++ strace-4.4/process.c Fri Apr 25 11:12:38 2003
@@ -1198,9 +1198,9 @@
}
}
#ifdef LINUX
-#if defined(ALPHA) || defined(SPARC) || defined(POWERPC) || defined(HPPA) || defined(IA64)
+#if defined(ALPHA) || defined(SPARC) || defined(POWERPC) || defined(HPPA) || defined(IA64) || defined (ARM)
tcp->flags |= TCB_WAITEXECVE;
-#endif /* ALPHA || SPARC || POWERPC || HPPA || IA64 */
+#endif /* ALPHA || SPARC || POWERPC || HPPA || IA64 || ARM */
#endif /* LINUX */
return 0;
}
@@ -1732,6 +1732,12 @@
{ PTRACE_SINGLESTEP, "PTRACE_SINGLESTEP" },
{ PTRACE_ATTACH, "PTRACE_ATTACH" },
{ PTRACE_DETACH, "PTRACE_DETACH" },
+#ifdef ARM
+ { PTRACE_GETREGS, "PTRACE_GETREGS" },
+ { PTRACE_SETREGS, "PTRACE_SETREGS" },
+ { PTRACE_GETFPREGS, "PTRACE_GETFPREGS", },
+ { PTRACE_SETFPREGS, "PTRACE_SETFPREGS", },
+#endif
#ifdef SUNOS4
{ PTRACE_GETREGS, "PTRACE_GETREGS" },
{ PTRACE_SETREGS, "PTRACE_SETREGS" },
@@ -2067,6 +2073,24 @@
{ 4*EFL, "4*EFL" },
{ 4*UESP, "4*UESP" },
{ 4*SS, "4*SS" },
+#elif defined(ARM)
+ { uoff(regs.ARM_r0), "r0" },
+ { uoff(regs.ARM_r1), "r1" },
+ { uoff(regs.ARM_r2), "r2" },
+ { uoff(regs.ARM_r3), "r3" },
+ { uoff(regs.ARM_r4), "r4" },
+ { uoff(regs.ARM_r5), "r5" },
+ { uoff(regs.ARM_r6), "r6" },
+ { uoff(regs.ARM_r7), "r7" },
+ { uoff(regs.ARM_r8), "r8" },
+ { uoff(regs.ARM_r9), "r9" },
+ { uoff(regs.ARM_r10), "r10" },
+ { uoff(regs.ARM_fp), "fp" },
+ { uoff(regs.ARM_ip), "ip" },
+ { uoff(regs.ARM_sp), "sp" },
+ { uoff(regs.ARM_lr), "lr" },
+ { uoff(regs.ARM_pc), "pc" },
+ { uoff(regs.ARM_cpsr), "cpsr" },
#else /* !I386 */
#ifdef M68K
{ 4*PT_D1, "4*PT_D1" },
diff -ur strace-4.4-orig/signal.c strace-4.4/signal.c
--- strace-4.4-orig/signal.c Sun Aug 19 13:06:50 2001
+++ strace-4.4/signal.c Fri Apr 25 11:22:48 2003
@@ -769,7 +769,32 @@
sys_sigreturn(tcp)
struct tcb *tcp;
{
-#ifdef S390
+#ifdef ARM
+ struct pt_regs regs;
+ struct sigcontext_struct sc;
+
+ if (entering(tcp)) {
+ tcp->u_arg[0] = 0;
+
+ if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (void *)®s) == -1)
+ return 0;
+
+ if (umove(tcp, regs.ARM_sp, &sc) < 0)
+ return 0;
+
+ tcp->u_arg[0] = 1;
+ tcp->u_arg[1] = sc.oldmask;
+ } else {
+ sigset_t sigm;
+ long_to_sigset(tcp->u_arg[1], &sigm);
+ tcp->u_rval = tcp->u_error = 0;
+ if (tcp->u_arg[0] == 0)
+ return 0;
+ tcp->auxstr = sprintsigmask("mask now ", &sigm, 0);
+ return RVAL_NONE | RVAL_STR;
+ }
+ return 0;
+#elif defined(S390)
long usp;
struct sigcontext_struct sc;
diff -ur strace-4.4-orig/syscall.c strace-4.4/syscall.c
--- strace-4.4-orig/syscall.c Fri Jul 13 23:07:45 2001
+++ strace-4.4/syscall.c Fri Apr 25 11:28:56 2003
@@ -658,7 +658,7 @@
#elif defined (M68K)
static int d0;
#elif defined (ARM)
- static int r0;
+ static struct pt_regs regs; /* should be in tcb */
#elif defined (ALPHA)
static long r0;
static long a3;
@@ -729,11 +729,59 @@
return -1;
}
#elif defined (ARM)
- {
- long pc;
- upeek(pid, 4*15, &pc);
- umoven(tcp, pc-4, 4, (char *)&scno);
- scno &= 0x000fffff;
+ /*
+ * Read complete register set in one go.
+ */
+ if (ptrace(PTRACE_GETREGS, pid, NULL, (void *)®s) == -1)
+ return -1;
+
+ /*
+ * We only need to grab the syscall number on syscall entry.
+ */
+ if (regs.ARM_ip == 0) {
+ /*
+ * Note: we only deal with only 32-bit CPUs here.
+ */
+ if (regs.ARM_cpsr & 0x20) {
+ /*
+ * Get the Thumb-mode system call number
+ */
+ scno = regs.ARM_r7;
+ } else {
+ /*
+ * Get the ARM-mode system call number
+ */
+ errno = 0;
+ scno = ptrace(PTRACE_PEEKTEXT, pid, (void *)(regs.ARM_pc - 4), NULL);
+ if (errno)
+ return -1;
+
+ if (scno == 0 && (tcp->flags & TCB_WAITEXECVE)) {
+ tcp->flags &= ~TCB_WAITEXECVE;
+ return 0;
+ }
+
+ if ((scno & 0x0ff00000) != 0x0f900000) {
+ fprintf(stderr, "syscall: unknown syscall trap 0x%08lx\n",
+ scno);
+ return -1;
+ }
+
+ /*
+ * Fixup the syscall number
+ */
+ scno &= 0x000fffff;
+ }
+
+ if (tcp->flags & TCB_INSYSCALL) {
+ fprintf(stderr, "pid %d stray syscall entry\n", tcp->pid);
+ tcp->flags &= ~TCB_INSYSCALL;
+ }
+ } else {
+ if (!(tcp->flags & TCB_INSYSCALL)) {
+ fprintf(stderr, "pid %d stray syscall exit\n", tcp->pid);
+ tcp->flags |= TCB_INSYSCALL;
+ }
}
#elif defined (M68K)
if (upeek(pid, 4*PT_ORIG_D0, &scno) < 0)
@@ -993,13 +1041,9 @@
return 0;
}
#elif defined (ARM)
- if (upeek(pid, 4*0, (long *)&r0) < 0)
- return -1;
- if ( 0 && r0 != -ENOSYS && !(tcp->flags & TCB_INSYSCALL)) {
- if (debug)
- fprintf(stderr, "stray syscall exit: d0 = %ld\n", r0);
- return 0;
- }
+ /*
+ * Nothing required
+ */
#elif defined (HPPA)
if (upeek(pid, PT_GR28, &r28) < 0)
return -1;
@@ -1087,12 +1131,12 @@
}
#else /* !M68K */
#ifdef ARM
- if (r0 && (unsigned) -r0 < nerrnos) {
+ if (regs.ARM_r0 && (unsigned) -regs.ARM_r0 < nerrnos) {
tcp->u_rval = -1;
- u_error = -r0;
+ u_error = -regs.ARM_r0;
}
else {
- tcp->u_rval = r0;
+ tcp->u_rval = regs.ARM_r0;
u_error = 0;
}
#else /* !ARM */
@@ -1316,6 +1360,17 @@
if (upeek(pid, PT_GR26-4*i, &tcp->u_arg[i]) < 0)
return -1;
}
+ }
+#elif defined(ARM)
+ {
+ int i;
+
+ if (tcp->scno >= 0 && tcp->scno < nsyscalls && sysent[tcp->scno].nargs != -1)
+ tcp->u_nargs = sysent[tcp->scno].nargs;
+ else
+ tcp->u_nargs = MAX_ARGS;
+ for (i = 0; i < tcp->u_nargs; i++)
+ tcp->u_arg[i] = regs.uregs[i];
}
#else /* Other architecture (like i386) (32bits specific) */
{
diff -ur strace-4.4-orig/util.c strace-4.4/util.c
--- strace-4.4-orig/util.c Fri Jul 13 23:07:45 2001
+++ strace-4.4/util.c Fri Apr 25 01:05:14 2003
@@ -999,6 +999,14 @@
return;
}
tprintf("[%08lx] ", eip);
+#elif defined(ARM)
+ long pc;
+
+ if (upeek(tcp->pid, 4*15, &pc) < 0) {
+ tprintf("[????????] ");
+ return;
+ }
+ tprintf("[%08lx] ", pc);
#elif defined(IA62)
long ip;
@@ -1169,6 +1177,47 @@
}
tcp->flags |= TCB_BPTSET;
}
+#elif defined(ARM)
+ struct pt_regs regs;
+
+#define ARM_LOOP 0xeafffffe
+
+ if (tcp->flags & TCB_BPTSET) {
+ fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
+ return -1;
+ }
+
+ if (ptrace(PTRACE_GETREGS, tcp->pid, 0, ®s) < 0) {
+ perror("setbpt: ptrace(PTRACE_GETREGS, ...)");
+ return -1;
+ }
+
+ /*
+ * Again, we only support 32-bit CPUs
+ */
+ tcp->baddr = regs.ARM_pc;
+
+ if (debug)
+ fprintf(stderr, "[%d] setting bpt at %lx\n", tcp->pid, tcp->baddr);
+
+ if (regs.ARM_cpsr & 0x20) {
+ fprintf(stderr, "PANIC: can't handle thumb mode\n");
+ return -1;
+ } else {
+ errno = 0;
+ tcp->inst[0] = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)tcp->baddr, 0);
+ if (errno) {
+ perror("setbpt: ptrace(PTRACE_PEEKTEXT, ...)");
+ return -1;
+ }
+
+ ptrace(PTRACE_POKETEXT, tcp->pid, (char *)tcp->baddr, ARM_LOOP);
+ if (errno) {
+ perror("setbpt: ptrace(PTRACE_POKETEXT, ...)");
+ return -1;
+ }
+ tcp->flags |= TCB_BPTSET;
+ }
#else /* !IA64 */
#if defined (I386)
@@ -1179,8 +1228,6 @@
#define LOOP 0xc3ffffff
#elif defined (POWERPC)
#define LOOP 0x0000feeb
-#elif defined(ARM)
-#define LOOP 0xEAFFFFFE
#elif defined(MIPS)
#define LOOP 0x1000ffff
#elif defined(S390)
@@ -1203,8 +1250,6 @@
return -1;
#elif defined (ALPHA)
return -1;
-#elif defined (ARM)
- return -1;
#elif defined (MIPS)
return -1; /* FIXME: I do not know what i do - Flo */
#elif defined (POWERPC)
@@ -1310,6 +1355,22 @@
#ifdef SPARC
/* Again, we borrow the SunOS breakpoint code. */
+ if (!(tcp->flags & TCB_BPTSET)) {
+ fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
+ return -1;
+ }
+ errno = 0;
+ ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, tcp->inst[0]);
+ if(errno) {
+ perror("clearbtp: ptrace(PTRACE_POKETEXT, ...)");
+ return -1;
+ }
+ tcp->flags &= ~TCB_BPTSET;
+#elif defined(ARM)
+ /*
+ * Gratuitously copied from SPARC. Replace the breakpoint
+ * instruction with the original instruction we saved earlier.
+ */
if (!(tcp->flags & TCB_BPTSET)) {
fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
return -1;
--
Russell King (rmk at arm.linux.org.uk) The developer of ARM Linux
http://www.arm.linux.org.uk/personal/aboutme.html
More information about the Strace-devel
mailing list