Package: ltrace
Version: 0.5-3
Severity: important
Tags: patch
User: [EMAIL PROTECTED]

Code compiled with thumb code (-mthumb option in gcc) currently
segfaults on ltrace. This patch fixes this issue.

Changelog:

2008-01-25  Anderson Lizardo  <[EMAIL PROTECTED]>

        * sysdeps/linux-gnu/arm/arch.h, sysdeps/linux-gnu/arm/regs.c,
        sysdeps/linux-gnu/arm/breakpoint.c, sysdeps/linux-gnu/arm/Makefile,
        debian/copyright: add ARM Thumb mode support.

-- 
Anderson Lizardo
Instituto Nokia de Tecnologia
Manaus - Brazil
Code compiled with thumb code (-mthumb option in gcc) currently segfaults on
ltrace. This patch fixes this issue.

Signed-off-by: Anderson Lizardo <[EMAIL PROTECTED]>
Signed-off-by: Bruna Moreira <[EMAIL PROTECTED]>

Index: ltrace-indt/sysdeps/linux-gnu/arm/arch.h
===================================================================
--- ltrace-indt.orig/sysdeps/linux-gnu/arm/arch.h	2007-12-18 21:10:24.000000000 -0400
+++ ltrace-indt/sysdeps/linux-gnu/arm/arch.h	2007-12-18 21:10:25.000000000 -0400
@@ -1,5 +1,10 @@
+#define ARCH_HAVE_ENABLE_BREAKPOINT 1
+#define ARCH_HAVE_DISABLE_BREAKPOINT 1
+
 #define BREAKPOINT_VALUE { 0xf0, 0x01, 0xf0, 0xe7 }
 #define BREAKPOINT_LENGTH 4
+#define THUMB_BREAKPOINT_VALUE { 0x01, 0xde }
+#define THUMB_BREAKPOINT_LENGTH 2
 #define DECR_PC_AFTER_BREAK 0
 
 #define LT_ELFCLASS	ELFCLASS32
Index: ltrace-indt/sysdeps/linux-gnu/arm/breakpoint.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ ltrace-indt/sysdeps/linux-gnu/arm/breakpoint.c	2007-12-18 21:10:25.000000000 -0400
@@ -0,0 +1,86 @@
+/*
+ * This file is part of ltrace.
+ *
+ * Copyright (C) 2007 by Instituto Nokia de Tecnologia (INdT)
+ *
+ * Author: Anderson Lizardo <[EMAIL PROTECTED]>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ * Modified from sysdeps/linux-gnu/breakpoint.c and added ARM Thumb support.
+*/
+
+#include <sys/ptrace.h>
+#include "config.h"
+#include "arch.h"
+#include "options.h"
+#include "output.h"
+#include "debug.h"
+
+void arch_enable_breakpoint(pid_t pid, struct breakpoint *sbp)
+{
+	unsigned int i, j;
+	const unsigned char break_insn[] = BREAKPOINT_VALUE;
+	const unsigned char thumb_break_insn[] = THUMB_BREAKPOINT_VALUE;
+
+	debug(1, "arch_enable_breakpoint(%d,%p)", pid, sbp->addr);
+
+	for (i = 0; i < 1 + ((BREAKPOINT_LENGTH - 1) / sizeof(long)); i++) {
+		long a =
+		    ptrace(PTRACE_PEEKTEXT, pid, sbp->addr + i * sizeof(long),
+			   0);
+		unsigned char *bytes = (unsigned char *)&a;
+
+		debug(2, "current = 0x%lx, orig_value = 0x%lx, thumb_mode = %d", a, *(long *)&sbp->orig_value, sbp->thumb_mode);
+		for (j = 0;
+		     j < sizeof(long)
+		     && i * sizeof(long) + j < BREAKPOINT_LENGTH; j++) {
+
+			sbp->orig_value[i * sizeof(long) + j] = bytes[j];
+			if (!sbp->thumb_mode) {
+				bytes[j] = break_insn[i * sizeof(long) + j];
+			}
+			else if (j < THUMB_BREAKPOINT_LENGTH) {
+				bytes[j] = thumb_break_insn[i * sizeof(long) + j];
+			}
+		}
+		ptrace(PTRACE_POKETEXT, pid, sbp->addr + i * sizeof(long), a);
+	}
+}
+
+void arch_disable_breakpoint(pid_t pid, const struct breakpoint *sbp)
+{
+	unsigned int i, j;
+	const unsigned char break_insn[] = BREAKPOINT_VALUE;
+	const unsigned char thumb_break_insn[] = THUMB_BREAKPOINT_VALUE;
+
+	debug(1, "arch_disable_breakpoint(%d,%p)", pid, sbp->addr);
+
+	for (i = 0; i < 1 + ((BREAKPOINT_LENGTH - 1) / sizeof(long)); i++) {
+		long a =
+		    ptrace(PTRACE_PEEKTEXT, pid, sbp->addr + i * sizeof(long),
+			   0);
+		unsigned char *bytes = (unsigned char *)&a;
+
+		debug(2, "current = 0x%lx, orig_value = 0x%lx, thumb_mode = %d", a, *(long *)&sbp->orig_value, sbp->thumb_mode);
+		for (j = 0;
+		     j < sizeof(long)
+		     && i * sizeof(long) + j < BREAKPOINT_LENGTH; j++) {
+
+			bytes[j] = sbp->orig_value[i * sizeof(long) + j];
+		}
+		ptrace(PTRACE_POKETEXT, pid, sbp->addr + i * sizeof(long), a);
+	}
+}
Index: ltrace-indt/sysdeps/linux-gnu/arm/Makefile
===================================================================
--- ltrace-indt.orig/sysdeps/linux-gnu/arm/Makefile	2007-12-18 21:10:24.000000000 -0400
+++ ltrace-indt/sysdeps/linux-gnu/arm/Makefile	2007-12-18 21:10:25.000000000 -0400
@@ -1,4 +1,4 @@
-OBJ	=	trace.o regs.o plt.o
+OBJ	=	trace.o regs.o plt.o breakpoint.o
 
 all:		arch.o
 
Index: ltrace-indt/breakpoints.c
===================================================================
--- ltrace-indt.orig/breakpoints.c	2007-12-18 21:10:24.000000000 -0400
+++ ltrace-indt/breakpoints.c	2007-12-18 21:10:25.000000000 -0400
@@ -48,6 +48,10 @@ insert_breakpoint(struct process *proc, 
 		if (libsym)
 			libsym->brkpnt = sbp;
 	}
+#ifdef __arm__
+	sbp->thumb_mode = proc->thumb_mode;
+	proc->thumb_mode = 0;
+#endif
 	sbp->enabled++;
 	if (sbp->enabled == 1 && proc->pid)
 		enable_breakpoint(proc->pid, sbp);
Index: ltrace-indt/ltrace.h
===================================================================
--- ltrace-indt.orig/ltrace.h	2007-12-18 21:10:24.000000000 -0400
+++ ltrace-indt/ltrace.h	2007-12-18 21:10:25.000000000 -0400
@@ -26,6 +26,9 @@ struct breakpoint {
 	unsigned char orig_value[BREAKPOINT_LENGTH];
 	int enabled;
 	struct library_symbol *libsym;
+#ifdef __arm__
+	int thumb_mode;
+#endif
 };
 
 enum arg_type {
@@ -170,6 +173,9 @@ struct process {
 	void *arch_ptr;
 	short e_machine;
 	short need_to_reinitialize_breakpoints;
+#ifdef __arm__
+	int thumb_mode; /* ARM execution mode: 0: ARM mode, 1: Thumb mode */
+#endif
 
 	/* output: */
 	enum tof type_being_displayed;
Index: ltrace-indt/sysdeps/linux-gnu/arm/regs.c
===================================================================
--- ltrace-indt.orig/sysdeps/linux-gnu/arm/regs.c	2007-12-18 21:10:24.000000000 -0400
+++ ltrace-indt/sysdeps/linux-gnu/arm/regs.c	2007-12-18 21:10:25.000000000 -0400
@@ -39,5 +39,10 @@ void *get_stack_pointer(struct process *
  * a CISC architecture; in our case, we don't need that */
 void *get_return_addr(struct process *proc, void *stack_pointer)
 {
-	return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, off_lr, 0);
+	long addr = ptrace(PTRACE_PEEKUSER, proc->pid, off_lr, 0);
+
+	proc->thumb_mode = addr & 1;
+	if (proc->thumb_mode)
+		addr &= ~1;
+	return (void *)addr;
 }

Reply via email to