+2005-12-22 Daniel Jacobowitz <dan@codesourcery.com>
+
+ * arm-linux-tdep.c (ARM_SET_R7_SIGRETURN, ARM_SET_R7_RT_SIGRETURN)
+ (ARM_EABI_SYSCALL, arm_linux_sigtramp_cache, arm_linux_sigreturn_init)
+ (arm_linux_rt_sigreturn_init, arm_linux_sigreturn_tramp_frame)
+ (arm_linux_rt_sigreturn_tramp_frame)
+ (arm_eabi_linux_sigreturn_tramp_frame)
+ (arm_eabi_linux_rt_sigreturn_tramp_frame): New.
+ (arm_linux_init_abi): Register the new signal unwinders.
+ (arm_linux_in_sigtramp, arm_linux_sigcontext_register_address):
+ Delete.
+ * arm-tdep.c (SIGCONTEXT_REGISTER_ADDRESS_P)
+ (SIGCONTEXT_REGISTER_ADDRESS, arm_make_sigtramp_cache)
+ (arm_sigtramp_this_id, arm_sigtramp_prev_register)
+ (arm_sigtramp_unwind, arm_sigtramp_unwind_sniffer): Delete.
+ (arm_gdbarch_init): Don't register a signal unwinder.
+ * config/arm/tm-linux.h (arm_linux_in_sigtramp)
+ (arm_linux_sigcontext_register_address): Delete prototypes.
+ (DEPRECATED_IN_SIGTRAMP, SIGCONTEXT_REGISTER_ADDRESS): Delete.
+ * Makefile.in (arm-linux-tdep.o): Update.
+
2005-12-22 Daniel Jacobowitz <dan@codesourcery.com>
* amd64obsd-tdep.c (amd64obsd_trapframe_sniffer): Spelling fix.
arm-linux-tdep.o: arm-linux-tdep.c $(defs_h) $(target_h) $(value_h) \
$(gdbtypes_h) $(floatformat_h) $(gdbcore_h) $(frame_h) $(regcache_h) \
$(doublest_h) $(solib_svr4_h) $(osabi_h) $(arm_tdep_h) \
- $(glibc_tdep_h)
+ $(glibc_tdep_h) $(trad_frame_h) $(tramp_frame_h) $(gdb_string_h)
armnbsd-nat.o: armnbsd-nat.c $(defs_h) $(gdbcore_h) $(inferior_h) \
$(regcache_h) $(target_h) $(gdb_string_h) $(arm_tdep_h) $(inf_ptrace_h)
armnbsd-tdep.o: armnbsd-tdep.c $(defs_h) $(osabi_h) $(gdb_string_h) \
/* GNU/Linux on ARM target support.
- Copyright (C) 1999, 2000, 2001, 2002, 2003, 2005 Free Software
- Foundation, Inc.
+ Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005
+ Free Software Foundation, Inc.
This file is part of GDB.
#include "doublest.h"
#include "solib-svr4.h"
#include "osabi.h"
+#include "trad-frame.h"
+#include "tramp-frame.h"
#include "arm-tdep.h"
#include "glibc-tdep.h"
+#include "gdb_string.h"
+
/* Under ARM GNU/Linux the traditional way of performing a breakpoint
is to execute a particular software interrupt, rather than use a
particular undefined instruction to provoke a trap. Upon exection
#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. */
+/* For ARM EABI, recognize the pattern that glibc uses... alternatively,
+ we could arrange to do this by function name, but they are not always
+ exported. */
+#define ARM_SET_R7_SIGRETURN 0xe3a07077
+#define ARM_SET_R7_RT_SIGRETURN 0xe3a070ad
+#define ARM_EABI_SYSCALL 0xef000000
-int
-arm_linux_in_sigtramp (CORE_ADDR pc, char *func_name)
+static void
+arm_linux_sigtramp_cache (struct frame_info *next_frame,
+ struct trad_frame_cache *this_cache,
+ CORE_ADDR func, int regs_offset)
{
- unsigned long inst;
+ CORE_ADDR sp = frame_unwind_register_unsigned (next_frame, ARM_SP_REGNUM);
+ CORE_ADDR base = sp + regs_offset;
+ int i;
- inst = read_memory_integer (pc, 4);
+ for (i = 0; i < 16; i++)
+ trad_frame_set_reg_addr (this_cache, i, base + i * 4);
- return (inst == ARM_LINUX_SIGRETURN_INSTR
- || inst == ARM_LINUX_RT_SIGRETURN_INSTR);
+ trad_frame_set_reg_addr (this_cache, ARM_PS_REGNUM, base + 16 * 4);
-}
+ /* The VFP or iWMMXt registers may be saved on the stack, but there's
+ no reliable way to restore them (yet). */
-/* 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. */
+ /* Save a frame ID. */
+ trad_frame_set_id (this_cache, frame_id_build (sp, func));
+}
-CORE_ADDR
-arm_linux_sigcontext_register_address (CORE_ADDR sp, CORE_ADDR pc, int regno)
+static void
+arm_linux_sigreturn_init (const struct tramp_frame *self,
+ struct frame_info *next_frame,
+ struct trad_frame_cache *this_cache,
+ CORE_ADDR func)
{
- 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 <= ARM_PC_REGNUM)
- reg_addr = sigcontext_addr + 12 + (4 * regno);
- else if (regno == ARM_PS_REGNUM)
- reg_addr = sigcontext_addr + 19 * 4;
- }
+ arm_linux_sigtramp_cache (next_frame, this_cache, func,
+ 0x0c /* Offset to registers. */);
+}
- return reg_addr;
+static void
+arm_linux_rt_sigreturn_init (const struct tramp_frame *self,
+ struct frame_info *next_frame,
+ struct trad_frame_cache *this_cache,
+ CORE_ADDR func)
+{
+ arm_linux_sigtramp_cache (next_frame, this_cache, func,
+ 0x88 /* Offset to ucontext_t. */
+ + 0x14 /* Offset to sigcontext. */
+ + 0x0c /* Offset to registers. */);
}
+static struct tramp_frame arm_linux_sigreturn_tramp_frame = {
+ SIGTRAMP_FRAME,
+ 4,
+ {
+ { ARM_LINUX_SIGRETURN_INSTR, -1 },
+ { TRAMP_SENTINEL_INSN }
+ },
+ arm_linux_sigreturn_init
+};
+
+static struct tramp_frame arm_linux_rt_sigreturn_tramp_frame = {
+ SIGTRAMP_FRAME,
+ 4,
+ {
+ { ARM_LINUX_RT_SIGRETURN_INSTR, -1 },
+ { TRAMP_SENTINEL_INSN }
+ },
+ arm_linux_rt_sigreturn_init
+};
+
+static struct tramp_frame arm_eabi_linux_sigreturn_tramp_frame = {
+ SIGTRAMP_FRAME,
+ 4,
+ {
+ { ARM_SET_R7_SIGRETURN, -1 },
+ { ARM_EABI_SYSCALL, -1 },
+ { TRAMP_SENTINEL_INSN }
+ },
+ arm_linux_sigreturn_init
+};
+
+static struct tramp_frame arm_eabi_linux_rt_sigreturn_tramp_frame = {
+ SIGTRAMP_FRAME,
+ 4,
+ {
+ { ARM_SET_R7_RT_SIGRETURN, -1 },
+ { ARM_EABI_SYSCALL, -1 },
+ { TRAMP_SENTINEL_INSN }
+ },
+ arm_linux_rt_sigreturn_init
+};
+
static void
arm_linux_init_abi (struct gdbarch_info info,
struct gdbarch *gdbarch)
/* Enable TLS support. */
set_gdbarch_fetch_tls_load_module_address (gdbarch,
svr4_fetch_objfile_link_map);
+
+ tramp_frame_prepend_unwinder (gdbarch,
+ &arm_linux_sigreturn_tramp_frame);
+ tramp_frame_prepend_unwinder (gdbarch,
+ &arm_linux_rt_sigreturn_tramp_frame);
+ tramp_frame_prepend_unwinder (gdbarch,
+ &arm_eabi_linux_sigreturn_tramp_frame);
+ tramp_frame_prepend_unwinder (gdbarch,
+ &arm_eabi_linux_rt_sigreturn_tramp_frame);
}
void
static int arm_debug;
-/* Each OS has a different mechanism for accessing the various
- registers stored in the sigcontext structure.
-
- SIGCONTEXT_REGISTER_ADDRESS should be defined to the name (or
- function pointer) which may be used to determine the addresses
- of the various saved registers in the sigcontext structure.
-
- For the ARM target, there are three parameters to this function.
- The first is the pc value of the frame under consideration, the
- second the stack pointer of this frame, and the last is the
- register number to fetch.
-
- If the tm.h file does not define this macro, then it's assumed that
- no mechanism is needed and we define SIGCONTEXT_REGISTER_ADDRESS to
- be 0.
-
- When it comes time to multi-arching this code, see the identically
- named machinery in ia64-tdep.c for an example of how it could be
- done. It should not be necessary to modify the code below where
- this macro is used. */
-
-#ifdef SIGCONTEXT_REGISTER_ADDRESS
-#ifndef SIGCONTEXT_REGISTER_ADDRESS_P
-#define SIGCONTEXT_REGISTER_ADDRESS_P() 1
-#endif
-#else
-#define SIGCONTEXT_REGISTER_ADDRESS(SP,PC,REG) 0
-#define SIGCONTEXT_REGISTER_ADDRESS_P() 0
-#endif
-
/* Macros for setting and testing a bit in a minimal symbol that marks
it as Thumb function. The MSB of the minimal symbol's "info" field
is used for this purpose.
arm_normal_frame_base
};
-static struct arm_prologue_cache *
-arm_make_sigtramp_cache (struct frame_info *next_frame)
-{
- struct arm_prologue_cache *cache;
- int reg;
-
- cache = frame_obstack_zalloc (sizeof (struct arm_prologue_cache));
-
- cache->prev_sp = frame_unwind_register_unsigned (next_frame, ARM_SP_REGNUM);
-
- cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
-
- for (reg = 0; reg < NUM_REGS; reg++)
- cache->saved_regs[reg].addr
- = SIGCONTEXT_REGISTER_ADDRESS (cache->prev_sp,
- frame_pc_unwind (next_frame), reg);
-
- /* FIXME: What about thumb mode? */
- cache->framereg = ARM_SP_REGNUM;
- cache->prev_sp
- = read_memory_integer (cache->saved_regs[cache->framereg].addr,
- register_size (current_gdbarch, cache->framereg));
-
- return cache;
-}
-
-static void
-arm_sigtramp_this_id (struct frame_info *next_frame,
- void **this_cache,
- struct frame_id *this_id)
-{
- struct arm_prologue_cache *cache;
-
- if (*this_cache == NULL)
- *this_cache = arm_make_sigtramp_cache (next_frame);
- cache = *this_cache;
-
- /* FIXME drow/2003-07-07: This isn't right if we single-step within
- the sigtramp frame; the PC should be the beginning of the trampoline. */
- *this_id = frame_id_build (cache->prev_sp, frame_pc_unwind (next_frame));
-}
-
-static void
-arm_sigtramp_prev_register (struct frame_info *next_frame,
- void **this_cache,
- int prev_regnum,
- int *optimized,
- enum lval_type *lvalp,
- CORE_ADDR *addrp,
- int *realnump,
- gdb_byte *valuep)
-{
- struct arm_prologue_cache *cache;
-
- if (*this_cache == NULL)
- *this_cache = arm_make_sigtramp_cache (next_frame);
- cache = *this_cache;
-
- trad_frame_get_prev_register (next_frame, cache->saved_regs, prev_regnum,
- optimized, lvalp, addrp, realnump, valuep);
-}
-
-struct frame_unwind arm_sigtramp_unwind = {
- SIGTRAMP_FRAME,
- arm_sigtramp_this_id,
- arm_sigtramp_prev_register
-};
-
-static const struct frame_unwind *
-arm_sigtramp_unwind_sniffer (struct frame_info *next_frame)
-{
- if (SIGCONTEXT_REGISTER_ADDRESS_P ()
- && legacy_pc_in_sigtramp (frame_pc_unwind (next_frame), (char *) 0))
- return &arm_sigtramp_unwind;
-
- return NULL;
-}
-
/* Assuming NEXT_FRAME->prev is a dummy, return the frame ID of that
dummy frame. The frame ID's base needs to match the TOS value
saved by save_dummy_frame_tos() and returned from
/* Add some default predicates. */
frame_unwind_append_sniffer (gdbarch, arm_stub_unwind_sniffer);
- frame_unwind_append_sniffer (gdbarch, arm_sigtramp_unwind_sniffer);
frame_unwind_append_sniffer (gdbarch, dwarf2_frame_sniffer);
frame_unwind_append_sniffer (gdbarch, arm_prologue_unwind_sniffer);
/* Target definitions for GNU/Linux on ARM, for GDB.
- Copyright 1999, 2000 Free Software Foundation, Inc.
+ Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005
+ Free Software Foundation, Inc.
This file is part of GDB.
#define IN_SOLIB_DYNSYM_RESOLVE_CODE in_svr4_dynsym_resolve_code */
#endif
-/* When the ARM Linux kernel invokes a signal handler, the return
- address points at a special instruction which'll trap back into
- the kernel. These definitions are used to identify this bit of
- code as a signal trampoline in order to support backtracing
- through calls to signal handlers. */
-
-int arm_linux_in_sigtramp (CORE_ADDR pc, char *name);
-#define DEPRECATED_IN_SIGTRAMP(pc, name) arm_linux_in_sigtramp (pc, name)
-
-/* Each OS has different mechanisms for accessing the various
- registers stored in the sigcontext structure. These definitions
- provide a mechanism by which the generic code in arm-tdep.c can
- find the addresses at which various registers are saved at in the
- sigcontext structure. If SIGCONTEXT_REGISTER_ADDRESS is not
- defined, arm-tdep.c will define it to be 0. (See ia64-tdep.c and
- ia64-linux-tdep.c to see what a similar mechanism looks like when
- multi-arched.) */
-
-extern CORE_ADDR arm_linux_sigcontext_register_address (CORE_ADDR, CORE_ADDR,
- int);
-#define SIGCONTEXT_REGISTER_ADDRESS arm_linux_sigcontext_register_address
-
#endif /* TM_ARMLINUX_H */