[Ltrace-devel] [PATCH] [MIPS] Detect return from rt_sigreturn syscalls

Faraz Shahbazker faraz.shahbazker at imgtec.com
Tue Feb 17 23:36:33 UTC 2015


On MIPS, rt_sigreturn does not return control to the instruction after
the syscall instruction. Instead, it transfers control directly to
the point where the signal occurred. If this transfer is not correctly
marked as a SYSRET event, it gets mis-categorized as a breakpoint event
and generates "unexpected breakpoint" messages. The rt_sigreturn
frame remains on the callstack until the next rt_sigreturn, which is then
misinterpreted as as a return from the previous 'unfinished' syscall.

If the top of the callstack is a rt_sigreturn syscall, we must force
the current event to be treated as a SYSRET without checking for a
preceding SYSCALL instruction.

Verify by invoking:
$ ltrace [-S] openssl speed
---
 sysdeps/linux-gnu/mips/trace.c |   13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/sysdeps/linux-gnu/mips/trace.c b/sysdeps/linux-gnu/mips/trace.c
index 88e13ac..5651fa3 100644
--- a/sysdeps/linux-gnu/mips/trace.c
+++ b/sysdeps/linux-gnu/mips/trace.c
@@ -30,6 +30,7 @@
 #include <sys/ptrace.h>
 #include <asm/ptrace.h>
 #include <assert.h>
+#include <asm/unistd.h>
 
 #include "backend.h"
 #include "common.h"
@@ -103,7 +104,17 @@ syscall_p(struct process *proc, int status, int *sysnum)
 		   0000000c    syscall
 		 */
 		if(insn!=0x0000000c){
-			return 0;
+			/* rt_sigreturn returns control to the point
+			   where the signal was received; skip check 
+			   for preceeding syscall instruction */
+			int depth = proc->callstack_depth;
+			if (depth > 0 &&
+			    proc->callstack[depth - 1].is_syscall &&
+			    proc->callstack[depth - 1].c_un.syscall ==
+			    (__NR_rt_sigreturn - __NR_Linux))
+				return 2;
+			else
+				return 0;
 		}
 
 		*sysnum = (num & 0xFFFF) - 4000;
-- 
1.7.9.5




More information about the Ltrace-devel mailing list