[Ltrace-devel] FC5 ltrace sigsegvs traced process on ppc

Petr Machata pmachata at redhat.com
Wed Jul 12 21:42:12 UTC 2006


Petr Machata wrote:
> Basically what I did:
>  * secure PLT branch (now trunk) contains code to cope with secure PLTs,
> with few issues to fix
>  * call breakpoints_init only when the traced binary was started, you
> can't ptrace it earlier

This part of the fix breaks ltrace on fc4.  Didn't look at it yet.

>  * make sure you won't place breakpoint over another breakpoint,
> otherwise you end up with breakpoint insn in orig_value, and the binary
> will stuck on the first breakpoint, reinserting in endlessly.
> 
> Any advice on how to do this cleanly is welcome.
> 
> PM

Also the testsuite doesn't pass.

I've been looking at it today, and at least with some tests, the problem
is that ltrace isn't able to extract return address from PT_LNK register
in sysdeps/linux-gnu/ppc/regs.c.  It gets NULL, to be correct, the call
won't end with an error.  But because of that NULL, ltrace doesn't
notice when library call ends, displays <unfinished...> message, and
won't include the call in final statistics (in case of -c option).

Attaching the current patch.

PM
-------------- next part --------------
Index: elf.c
===================================================================
--- elf.c	(revision 45)
+++ elf.c	(working copy)
@@ -464,7 +464,7 @@
 			if (strcmp(xptr->name, PLTs_initialized_by_here) == 0) {
 				if (lte->ehdr.e_entry) {
 					add_library_symbol (
-						elf_plt2addr (lte, (void*)(long)
+						opd2addr (lte, (void*)(long)
 							lte->ehdr.e_entry),
 						PLTs_initialized_by_here,
 						lib_tail, 1, 0);
Index: sysdeps/linux-gnu/breakpoint.c
===================================================================
--- sysdeps/linux-gnu/breakpoint.c	(revision 45)
+++ sysdeps/linux-gnu/breakpoint.c	(working copy)
@@ -9,6 +9,8 @@
 #include "output.h"
 #include "debug.h"
 
+#include <errno.h>
+
 static unsigned char break_insn[] = BREAKPOINT_VALUE;
 
 #ifdef ARCH_HAVE_ENABLE_BREAKPOINT
@@ -24,20 +26,27 @@
 
 	debug(1, "enable_breakpoint(%d,%p)", pid, sbp->addr);
 
+	unsigned char orig[BREAKPOINT_LENGTH];
 	for (i = 0; i < 1 + ((BREAKPOINT_LENGTH - 1) / sizeof(long)); i++) {
 		long a =
 		    ptrace(PTRACE_PEEKTEXT, pid, sbp->addr + i * sizeof(long),
 			   0);
+		if (a == -1 && errno) {
+			perror ("ptrace");
+			return;
+		}
 		for (j = 0;
 		     j < sizeof(long)
 		     && i * sizeof(long) + j < BREAKPOINT_LENGTH; j++) {
 			unsigned char *bytes = (unsigned char *)&a;
 
-			sbp->orig_value[i * sizeof(long) + j] = bytes[j];
+			orig[i * sizeof(long) + j] = bytes[j];
 			bytes[j] = break_insn[i * sizeof(long) + j];
 		}
 		ptrace(PTRACE_POKETEXT, pid, sbp->addr + i * sizeof(long), a);
 	}
+	if (memcmp (orig, break_insn, BREAKPOINT_LENGTH) != 0)
+		memcpy (sbp->orig_value, orig, BREAKPOINT_LENGTH);
 }
 #endif				/* ARCH_HAVE_ENABLE_BREAKPOINT */
 
Index: sysdeps/linux-gnu/ppc/plt.c
===================================================================
--- sysdeps/linux-gnu/ppc/plt.c	(revision 45)
+++ sysdeps/linux-gnu/ppc/plt.c	(working copy)
@@ -1,4 +1,5 @@
 #include <gelf.h>
+#include <errno.h>
 #include "ltrace.h"
 #include "elf.h"
 #include "debug.h"
@@ -17,6 +18,7 @@
 
 	debug(3, 0);
 
+	debug(1, "sym2addr: sym=%s, pid=%d", sym->name, proc->pid);
 	if (sym->plt_type != LS_TOPLT_POINT) {
 		return addr;
 	}
@@ -46,6 +48,11 @@
 	// break-point right in the PLT.
 
 	pt_ret = ptrace(PTRACE_PEEKTEXT, proc->pid, addr, 0);
+	if (pt_ret == -1 && errno) {
+		debug(1, "ptrace: addr=%08x pt_ret=%08x", addr, pt_ret);
+		perror ("ptrace");
+		return 0;
+	}
 
 	if (proc->mask_32bit) {
 		// Assume big-endian.
Index: sysdeps/linux-gnu/ppc/arch.h
===================================================================
--- sysdeps/linux-gnu/ppc/arch.h	(revision 45)
+++ sysdeps/linux-gnu/ppc/arch.h	(working copy)
@@ -7,8 +7,11 @@
 #ifdef __powerpc64__ // Says 'ltrace' is 64 bits, says nothing about target.
 #define LT_ELFCLASS2	ELFCLASS64
 #define LT_ELF_MACHINE2	EM_PPC64
+#endif
 
+#ifdef __powerpc__
 #define PLT_REINITALISATION_BP    "_start"
+#endif
 
 #define PPC_NOP { 0x60, 0x00, 0x00, 0x00 }
 #define PPC_NOP_LENGTH 4
@@ -16,6 +19,3 @@
 #if (PPC_NOP_LENGTH != BREAKPOINT_LENGTH)
 #error "Length of the breakpoint value not equal to the length of a nop instruction"
 #endif
-
-
-#endif
Index: breakpoints.c
===================================================================
--- breakpoints.c	(revision 45)
+++ breakpoints.c	(working copy)
@@ -28,6 +28,7 @@
 		  struct library_symbol *libsym)
 {
 	struct breakpoint *sbp;
+	debug(1, "insert_breakpoint(symbol=%s, addr=%p)", libsym?libsym->name:"(nil)", addr);
 
 	if (!proc->breakpoints) {
 		proc->breakpoints =
@@ -165,11 +166,9 @@
 	} else {
 		proc->list_of_symbols = NULL;
 	}
-	sym = proc->list_of_symbols;
-	while (sym) {
+	for (sym = proc->list_of_symbols; sym; sym = sym->next) {
 		/* proc->pid==0 delays enabling. */
 		insert_breakpoint(proc, sym2addr(proc, sym), sym);
-		sym = sym->next;
 	}
 	proc->callstack_depth = 0;
 	proc->breakpoints_enabled = -1;
Index: wait_for_something.c
===================================================================
--- wait_for_something.c	(revision 45)
+++ wait_for_something.c	(working copy)
@@ -25,6 +25,7 @@
 	pid_t pid;
 	int status;
 	int tmp;
+	static int bp_initialized = 0;
 
 	if (!list_of_processes) {
 		debug(1, "No more children");
@@ -48,6 +49,12 @@
 		fprintf(stderr, "signal from wrong pid %u ?!?\n", pid);
 		exit(1);
 	}
+	if (!bp_initialized)
+	  {
+	    /* hack... */
+	    breakpoints_init (event.proc);
+	    bp_initialized = 1;
+	  }
 	get_arch_dep(event.proc);
 	event.proc->instruction_pointer = NULL;
 	debug(3, "signal from pid %u", pid);


More information about the Ltrace-devel mailing list