[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 *)&regs) == -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 *)&regs) == -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, &regs) < 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