From 2a451106e278d23b1ef4a208c270947b0451f7d0 Mon Sep 17 00:00:00 2001 From: Kevin Buettner Date: Wed, 6 Sep 2000 00:39:11 +0000 Subject: 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. --- gdb/arm-linux-tdep.c | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 88 insertions(+), 1 deletion(-) (limited to 'gdb/arm-linux-tdep.c') 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) { -- cgit v1.1