aboutsummaryrefslogtreecommitdiff
path: root/gdb/arm-linux-tdep.c
diff options
context:
space:
mode:
authorKevin Buettner <kevinb@redhat.com>2000-09-06 00:39:11 +0000
committerKevin Buettner <kevinb@redhat.com>2000-09-06 00:39:11 +0000
commit2a451106e278d23b1ef4a208c270947b0451f7d0 (patch)
tree2f49aa6bf32cb71a628078ea8896205c7b5d5943 /gdb/arm-linux-tdep.c
parenta966dba9daedf21904c2be865c97aee21d6eca0d (diff)
downloadgdb-2a451106e278d23b1ef4a208c270947b0451f7d0.zip
gdb-2a451106e278d23b1ef4a208c270947b0451f7d0.tar.gz
gdb-2a451106e278d23b1ef4a208c270947b0451f7d0.tar.bz2
Add support for backtracing through signal handlers on Linux/ARM. Also,
make prologue scanning code somewhat less naive about optimized code on GNU/Linux/ARM.
Diffstat (limited to 'gdb/arm-linux-tdep.c')
-rw-r--r--gdb/arm-linux-tdep.c89
1 files changed, 88 insertions, 1 deletions
diff --git a/gdb/arm-linux-tdep.c b/gdb/arm-linux-tdep.c
index cbe8c18..0e4c370 100644
--- a/gdb/arm-linux-tdep.c
+++ b/gdb/arm-linux-tdep.c
@@ -23,12 +23,18 @@
#include "value.h"
#include "gdbtypes.h"
#include "floatformat.h"
+#include "gdbcore.h"
+#include "frame.h"
/* For arm_linux_skip_solib_resolver. */
#include "symtab.h"
#include "symfile.h"
#include "objfiles.h"
+/* FIXME: Put in common header file shared between arm-tdep.c and
+ arm-linux-tdep.c */
+int arm_pc_is_thumb (CORE_ADDR memaddr);
+
#ifdef GET_LONGJMP_TARGET
/* Figure out where the longjmp will land. We expect that we have
@@ -425,7 +431,7 @@ arm_linux_skip_solib_resolver (CORE_ADDR pc)
/* Plug in functions for other kinds of resolvers here. */
result = skip_hurd_resolver (pc);
- printf ("Result = 0x%08x\n");
+ printf ("Result = 0x%08lx\n", result);
if (result)
return result;
@@ -433,6 +439,87 @@ arm_linux_skip_solib_resolver (CORE_ADDR pc)
return 0;
}
+/* The constants below were determined by examining the following files
+ in the linux kernel sources:
+
+ arch/arm/kernel/signal.c
+ - see SWI_SYS_SIGRETURN and SWI_SYS_RT_SIGRETURN
+ include/asm-arm/unistd.h
+ - see __NR_sigreturn, __NR_rt_sigreturn, and __NR_SYSCALL_BASE */
+
+#define ARM_LINUX_SIGRETURN_INSTR 0xef900077
+#define ARM_LINUX_RT_SIGRETURN_INSTR 0xef9000ad
+
+/* arm_linux_in_sigtramp determines if PC points at one of the
+ instructions which cause control to return to the Linux kernel upon
+ return from a signal handler. FUNC_NAME is unused. */
+
+int
+arm_linux_in_sigtramp (CORE_ADDR pc, char *func_name)
+{
+ unsigned long inst;
+
+ inst = read_memory_integer (pc, 4);
+
+ return (inst == ARM_LINUX_SIGRETURN_INSTR
+ || inst == ARM_LINUX_RT_SIGRETURN_INSTR);
+
+}
+
+/* arm_linux_sigcontext_register_address returns the address in the
+ sigcontext of register REGNO given a stack pointer value SP and
+ program counter value PC. The value 0 is returned if PC is not
+ pointing at one of the signal return instructions or if REGNO is
+ not saved in the sigcontext struct. */
+
+CORE_ADDR
+arm_linux_sigcontext_register_address (CORE_ADDR sp, CORE_ADDR pc, int regno)
+{
+ unsigned long inst;
+ CORE_ADDR reg_addr = 0;
+
+ inst = read_memory_integer (pc, 4);
+
+ if (inst == ARM_LINUX_SIGRETURN_INSTR || inst == ARM_LINUX_RT_SIGRETURN_INSTR)
+ {
+ CORE_ADDR sigcontext_addr;
+
+ /* The sigcontext structure is at different places for the two
+ signal return instructions. For ARM_LINUX_SIGRETURN_INSTR,
+ it starts at the SP value. For ARM_LINUX_RT_SIGRETURN_INSTR,
+ it is at SP+8. For the latter instruction, it may also be
+ the case that the address of this structure may be determined
+ by reading the 4 bytes at SP, but I'm not convinced this is
+ reliable.
+
+ In any event, these magic constants (0 and 8) may be
+ determined by examining struct sigframe and struct
+ rt_sigframe in arch/arm/kernel/signal.c in the Linux kernel
+ sources. */
+
+ if (inst == ARM_LINUX_RT_SIGRETURN_INSTR)
+ sigcontext_addr = sp + 8;
+ else /* inst == ARM_LINUX_SIGRETURN_INSTR */
+ sigcontext_addr = sp + 0;
+
+ /* The layout of the sigcontext structure for ARM GNU/Linux is
+ in include/asm-arm/sigcontext.h in the Linux kernel sources.
+
+ There are three 4-byte fields which precede the saved r0
+ field. (This accounts for the 12 in the code below.) The
+ sixteen registers (4 bytes per field) follow in order. The
+ PSR value follows the sixteen registers which accounts for
+ the constant 19 below. */
+
+ if (0 <= regno && regno <= PC_REGNUM)
+ reg_addr = sigcontext_addr + 12 + (4 * regno);
+ else if (regno == PS_REGNUM)
+ reg_addr = sigcontext_addr + 19 * 4;
+ }
+
+ return reg_addr;
+}
+
void
_initialize_arm_linux_tdep (void)
{