* gdbarch.c gdbarch.h: Regenerate.
* breakpoint.c (create_longjmp_breakpoint): Always compile this
function.
(breakpoint_reset): Test GET_LONGJMP_TARGET_P().
* infrun.c (GET_LONGJMP_TARGET): Delete default definition.
(handle_inferior_event): Test GET_LONGJMP_TARGET_P().
* arm-tdep.h (struct gdbarch_tdep): Add jb_pc and jb_elt_size fields.
* arm-tdep.c (arm_get_longjmp_target): New function.
(arm_gdbarch_init): Initialize jb_pc to -1. If ABI handler changes
this to a positive value register arm_get_longjmp_target as the
longjmp handler.
* arm-linux-tdep.c (arm_get_longjmp_target): Delete.
(arm_linux_init_abi): Set up longjmp description in tdep.
* armnbsd-nat.c (get_longjmp_target): Delete.
* armnbsd-tdep.c (arm_netbsd_init_abi_common): Set up longjmp
description in tdep.
* config/arm/tm-nbsd.h (JB_ELEMENT_SIZE, JB_PC): Delete.
(get_longjmp_target): Delete declaration.
(GET_LONGJMP_TARGET): Delete.
* config/arm/tm-linux.h (arm_get_longjmp_target): Delete declaration.
(GET_LONGJMP_TARGET): Delete.
+2002-02-18 Richard Earnshaw <rearnsha@arm.com>
+
+ * gdbarch.sh (GET_LONGJMP_TARGET): Add rule.
+ * gdbarch.c gdbarch.h: Regenerate.
+ * breakpoint.c (create_longjmp_breakpoint): Always compile this
+ function.
+ (breakpoint_reset): Test GET_LONGJMP_TARGET_P().
+ * infrun.c (GET_LONGJMP_TARGET): Delete default definition.
+ (handle_inferior_event): Test GET_LONGJMP_TARGET_P().
+
+ * arm-tdep.h (struct gdbarch_tdep): Add jb_pc and jb_elt_size fields.
+ * arm-tdep.c (arm_get_longjmp_target): New function.
+ (arm_gdbarch_init): Initialize jb_pc to -1. If ABI handler changes
+ this to a positive value register arm_get_longjmp_target as the
+ longjmp handler.
+ * arm-linux-tdep.c (arm_get_longjmp_target): Delete.
+ (arm_linux_init_abi): Set up longjmp description in tdep.
+ * armnbsd-nat.c (get_longjmp_target): Delete.
+ * armnbsd-tdep.c (arm_netbsd_init_abi_common): Set up longjmp
+ description in tdep.
+ * config/arm/tm-nbsd.h (JB_ELEMENT_SIZE, JB_PC): Delete.
+ (get_longjmp_target): Delete declaration.
+ (GET_LONGJMP_TARGET): Delete.
+ * config/arm/tm-linux.h (arm_get_longjmp_target): Delete declaration.
+ (GET_LONGJMP_TARGET): Delete.
+
2002-02-17 Kevin Buettner <kevinb@redhat.com>
From Peter Schauer <pes@regent.e-technik.tu-muenchen.de>:
0xe1a0e00f, 0xe1a0f004, 0xef9f001
};
-#ifdef GET_LONGJMP_TARGET
-
-/* Figure out where the longjmp will land. We expect that we have
- just entered longjmp and haven't yet altered r0, r1, so the
- arguments are still in the registers. (ARM_A1_REGNUM) points at
- the jmp_buf structure from which we extract the pc (JB_PC) that we
- will land at. The pc is copied into ADDR. This routine returns
- true on success. */
-
-#define LONGJMP_TARGET_SIZE sizeof(int)
-#define JB_ELEMENT_SIZE sizeof(int)
-#define JB_SL 18
-#define JB_FP 19
-#define JB_SP 20
+/* Description of the longjmp buffer. */
+#define JB_ELEMENT_SIZE INT_REGISTER_RAW_SIZE
#define JB_PC 21
-int
-arm_get_longjmp_target (CORE_ADDR * pc)
-{
- CORE_ADDR jb_addr;
- char buf[LONGJMP_TARGET_SIZE];
-
- jb_addr = read_register (ARM_A1_REGNUM);
-
- if (target_read_memory (jb_addr + JB_PC * JB_ELEMENT_SIZE, buf,
- LONGJMP_TARGET_SIZE))
- return 0;
-
- *pc = extract_address (buf, LONGJMP_TARGET_SIZE);
- return 1;
-}
-
-#endif /* GET_LONGJMP_TARGET */
-
/* Extract from an array REGBUF containing the (raw) register state
a function return value of type TYPE, and copy that, in virtual format,
into VALBUF. */
tdep->lowest_pc = 0x8000;
tdep->arm_breakpoint = arm_linux_arm_le_breakpoint;
tdep->arm_breakpoint_size = sizeof (arm_linux_arm_le_breakpoint);
+
+ tdep->jb_pc = JB_PC;
+ tdep->jb_elt_size = JB_ELEMENT_SIZE;
}
void
write_register (ARM_A1_REGNUM, addr);
}
+static int
+arm_get_longjmp_target (CORE_ADDR *pc)
+{
+ CORE_ADDR jb_addr;
+ char buf[INT_REGISTER_RAW_SIZE];
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ jb_addr = read_register (ARM_A1_REGNUM);
+
+ if (target_read_memory (jb_addr + tdep->jb_pc * tdep->jb_elt_size, buf,
+ INT_REGISTER_RAW_SIZE))
+ return 0;
+
+ *pc = extract_address (buf, INT_REGISTER_RAW_SIZE);
+ return 1;
+}
+
/* Return non-zero if the PC is inside a thumb call thunk. */
int
"arm_gdbarch_init: bad byte order for float format");
}
+ /* This should be low enough for everything. */
tdep->lowest_pc = 0x20;
+ tdep->jb_pc = -1; /* Longjump support not enabled by default. */
set_gdbarch_use_generic_dummy_frames (gdbarch, 0);
/* Now we have tuned the configuration, set a few final things,
based on what the OS ABI has told us. */
+ if (tdep->jb_pc >= 0)
+ set_gdbarch_get_longjmp_target (gdbarch, arm_get_longjmp_target);
+
/* We can't use SIZEOF_FRAME_SAVED_REGS here, since that still
references the old architecture vector, not the one we are
building here. */
const char *abi_name; /* Name of the above. */
CORE_ADDR lowest_pc; /* Lowest address at which instructions
will appear. */
- const char *arm_breakpoint;
- int arm_breakpoint_size;
- const char *thumb_breakpoint;
- int thumb_breakpoint_size;
+
+ const char *arm_breakpoint; /* Breakpoint pattern for an ARM insn. */
+ int arm_breakpoint_size; /* And its size. */
+ const char *thumb_breakpoint; /* Breakpoint pattern for an ARM insn. */
+ int thumb_breakpoint_size; /* And its size. */
+
+ int jb_pc; /* Offset to PC value in jump buffer.
+ If this is negative, longjmp support
+ will be disabled. */
+ size_t jb_elt_size; /* And the size of each entry in the buf. */
};
#ifndef LOWEST_PC
#else
#error Not FETCH_INFERIOR_REGISTERS
#endif /* !FETCH_INFERIOR_REGISTERS */
-
-int
-get_longjmp_target (CORE_ADDR *addr)
-{
- return 0;
-}
#include "arm-tdep.h"
+/* Description of the longjmp buffer. */
+#define JB_PC 24
+#define JB_ELEMENT_SIZE INT_REGISTER_RAW_SIZE
+
/* For compatibility with previous implemenations of GDB on arm/NetBSD,
override the default little-endian breakpoint. */
static const char arm_nbsd_arm_le_breakpoint[] = {0x11, 0x00, 0x00, 0xe6};
tdep->lowest_pc = 0x8000;
tdep->arm_breakpoint = arm_nbsd_arm_le_breakpoint;
tdep->arm_breakpoint_size = sizeof (arm_nbsd_arm_le_breakpoint);
+
+ tdep->jb_pc = JB_PC;
+ tdep->jb_elt_size = JB_ELEMENT_SIZE;
}
static void
static void maintenance_info_breakpoints (char *, int);
-#ifdef GET_LONGJMP_TARGET
static void create_longjmp_breakpoint (char *);
-#endif
static void create_overlay_event_breakpoint (char *);
return b;
}
-#ifdef GET_LONGJMP_TARGET
static void
create_longjmp_breakpoint (char *func_name)
b->addr_string = xstrdup (func_name);
}
-#endif /* #ifdef GET_LONGJMP_TARGET */
-
/* Call this routine when stepping and nexting to enable a breakpoint
if we do a longjmp(). When we hit that breakpoint, call
set_longjmp_resume_breakpoint() to figure out where we are going. */
set_language (save_language);
input_radix = save_input_radix;
-#ifdef GET_LONGJMP_TARGET
- create_longjmp_breakpoint ("longjmp");
- create_longjmp_breakpoint ("_longjmp");
- create_longjmp_breakpoint ("siglongjmp");
- create_longjmp_breakpoint ("_siglongjmp");
- create_longjmp_breakpoint (NULL);
-#endif
+ if (GET_LONGJMP_TARGET_P ())
+ {
+ create_longjmp_breakpoint ("longjmp");
+ create_longjmp_breakpoint ("_longjmp");
+ create_longjmp_breakpoint ("siglongjmp");
+ create_longjmp_breakpoint ("_siglongjmp");
+ create_longjmp_breakpoint (NULL);
+ }
create_overlay_event_breakpoint ("_ovly_debug_event");
}
/* Offset to saved PC in sigcontext structure, from <asm/sigcontext.h> */
#define SIGCONTEXT_PC_OFFSET (sizeof(unsigned long) * 18)
-/* Figure out where the longjmp will land. The code expects that longjmp
- has just been entered and the code had not altered the registers, so
- the arguments are are still in r0-r1. r0 points at the jmp_buf structure
- from which the target pc (JB_PC) is extracted. This pc value is copied
- into ADDR. This routine returns true on success */
-extern int arm_get_longjmp_target (CORE_ADDR *);
-#define GET_LONGJMP_TARGET(addr) arm_get_longjmp_target (addr)
-
/* On ARM Linux, each call to a library routine goes through a small piece
of trampoline code in the ".plt" section. The wait_for_inferior()
routine uses this macro to detect when we have stepped into one of
#include "arm/tm-arm.h"
#include "tm-nbsd.h"
-#define JB_ELEMENT_SIZE sizeof(long) /* jmp_buf[_JBLEN] is array of ints */
-#define JB_PC 24 /* Setjmp()'s return PC saved here */
-
/* Return non-zero if inside a shared-library entry stub. */
#undef IN_SOLIB_CALL_TRAMPOLINE
#define IN_SOLIB_CALL_TRAMPOLINE(pc, name) \
STREQ ((name), "_PROCEDURE_LINKAGE_TABLE_")
-/* Figure out where the longjmp will land. Slurp the args out of the stack.
- We expect the first arg to be a pointer to the jmp_buf structure from which
- we extract the pc (JB_PC) that we will land at. The pc is copied into ADDR.
- This routine returns true on success */
-
-extern int
-get_longjmp_target (CORE_ADDR *);
-
-#define GET_LONGJMP_TARGET(ADDR) get_longjmp_target(ADDR)
-
/* By convention, NetBSD uses the "other" register names. */
#define DEFAULT_REGISTER_NAMES additional_register_names
gdbarch_register_bytes_ok_ftype *register_bytes_ok;
gdbarch_cannot_fetch_register_ftype *cannot_fetch_register;
gdbarch_cannot_store_register_ftype *cannot_store_register;
+ gdbarch_get_longjmp_target_ftype *get_longjmp_target;
int use_generic_dummy_frames;
int call_dummy_location;
gdbarch_call_dummy_address_ftype *call_dummy_address;
0,
0,
0,
+ 0,
generic_get_saved_register,
0,
0,
/* Skip verify of register_bytes_ok, has predicate */
/* Skip verify of cannot_fetch_register, invalid_p == 0 */
/* Skip verify of cannot_store_register, invalid_p == 0 */
+ /* Skip verify of get_longjmp_target, has predicate */
if ((GDB_MULTI_ARCH >= GDB_MULTI_ARCH_PARTIAL)
&& (gdbarch->use_generic_dummy_frames == -1))
fprintf_unfiltered (log, "\n\tuse_generic_dummy_frames");
"gdbarch_dump: FUNCTION_START_OFFSET = %ld\n",
(long) FUNCTION_START_OFFSET);
#endif
+#ifdef GET_LONGJMP_TARGET
+ fprintf_unfiltered (file,
+ "gdbarch_dump: %s # %s\n",
+ "GET_LONGJMP_TARGET(pc)",
+ XSTRING (GET_LONGJMP_TARGET (pc)));
+ if (GDB_MULTI_ARCH)
+ fprintf_unfiltered (file,
+ "gdbarch_dump: GET_LONGJMP_TARGET = 0x%08lx\n",
+ (long) current_gdbarch->get_longjmp_target
+ /*GET_LONGJMP_TARGET ()*/);
+#endif
#ifdef GET_SAVED_REGISTER
#if GDB_MULTI_ARCH
/* Macro might contain `[{}]' when not multi-arch */
gdbarch->cannot_store_register = cannot_store_register;
}
+int
+gdbarch_get_longjmp_target_p (struct gdbarch *gdbarch)
+{
+ return gdbarch->get_longjmp_target != 0;
+}
+
+int
+gdbarch_get_longjmp_target (struct gdbarch *gdbarch, CORE_ADDR *pc)
+{
+ if (gdbarch->get_longjmp_target == 0)
+ internal_error (__FILE__, __LINE__,
+ "gdbarch: gdbarch_get_longjmp_target invalid");
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_get_longjmp_target called\n");
+ return gdbarch->get_longjmp_target (pc);
+}
+
+void
+set_gdbarch_get_longjmp_target (struct gdbarch *gdbarch,
+ gdbarch_get_longjmp_target_ftype get_longjmp_target)
+{
+ gdbarch->get_longjmp_target = get_longjmp_target;
+}
+
int
gdbarch_use_generic_dummy_frames (struct gdbarch *gdbarch)
{
#endif
#endif
+/* setjmp/longjmp support. */
+
+#if defined (GET_LONGJMP_TARGET)
+/* Legacy for systems yet to multi-arch GET_LONGJMP_TARGET */
+#if !defined (GET_LONGJMP_TARGET_P)
+#define GET_LONGJMP_TARGET_P() (1)
+#endif
+#endif
+
+/* Default predicate for non- multi-arch targets. */
+#if (!GDB_MULTI_ARCH) && !defined (GET_LONGJMP_TARGET_P)
+#define GET_LONGJMP_TARGET_P() (0)
+#endif
+
+extern int gdbarch_get_longjmp_target_p (struct gdbarch *gdbarch);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (GET_LONGJMP_TARGET_P)
+#error "Non multi-arch definition of GET_LONGJMP_TARGET"
+#endif
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) || !defined (GET_LONGJMP_TARGET_P)
+#define GET_LONGJMP_TARGET_P() (gdbarch_get_longjmp_target_p (current_gdbarch))
+#endif
+
+/* Default (function) for non- multi-arch platforms. */
+#if (!GDB_MULTI_ARCH) && !defined (GET_LONGJMP_TARGET)
+#define GET_LONGJMP_TARGET(pc) (internal_error (__FILE__, __LINE__, "GET_LONGJMP_TARGET"), 0)
+#endif
+
+typedef int (gdbarch_get_longjmp_target_ftype) (CORE_ADDR *pc);
+extern int gdbarch_get_longjmp_target (struct gdbarch *gdbarch, CORE_ADDR *pc);
+extern void set_gdbarch_get_longjmp_target (struct gdbarch *gdbarch, gdbarch_get_longjmp_target_ftype *get_longjmp_target);
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (GET_LONGJMP_TARGET)
+#error "Non multi-arch definition of GET_LONGJMP_TARGET"
+#endif
+#if GDB_MULTI_ARCH
+#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) || !defined (GET_LONGJMP_TARGET)
+#define GET_LONGJMP_TARGET(pc) (gdbarch_get_longjmp_target (current_gdbarch, pc))
+#endif
+#endif
+
/* Non multi-arch DUMMY_FRAMES are a mess (multi-arch ones are not that
much better but at least they are vaguely consistent). The headers
and body contain convoluted #if/#else sequences for determine how
F:2:REGISTER_BYTES_OK:int:register_bytes_ok:long nr_bytes:nr_bytes::0:0
f:2:CANNOT_FETCH_REGISTER:int:cannot_fetch_register:int regnum:regnum:::cannot_register_not::0
f:2:CANNOT_STORE_REGISTER:int:cannot_store_register:int regnum:regnum:::cannot_register_not::0
+# setjmp/longjmp support.
+F:2:GET_LONGJMP_TARGET:int:get_longjmp_target:CORE_ADDR *pc:pc::0:0
#
# Non multi-arch DUMMY_FRAMES are a mess (multi-arch ones are not that
# much better but at least they are vaguely consistent). The headers
static int may_follow_exec = MAY_FOLLOW_EXEC;
-/* GET_LONGJMP_TARGET returns the PC at which longjmp() will resume the
- program. It needs to examine the jmp_buf argument and extract the PC
- from it. The return value is non-zero on success, zero otherwise. */
-
-#ifndef GET_LONGJMP_TARGET
-#define GET_LONGJMP_TARGET(PC_ADDR) 0
-#endif
-
-
/* Dynamic function trampolines are similar to solib trampolines in that they
are between the caller and the callee. The difference is that when you
enter a dynamic trampoline, you can't determine the callee's address. Some
disable_longjmp_breakpoint ();
remove_breakpoints ();
breakpoints_inserted = 0;
- if (!GET_LONGJMP_TARGET (&jmp_buf_pc))
+ if (!GET_LONGJMP_TARGET_P ()
+ || !GET_LONGJMP_TARGET (&jmp_buf_pc))
{
keep_going (ecs);
return;