From 9df628e0aa21fe96d386e6a634d0af30d9b2efb7 Mon Sep 17 00:00:00 2001 From: Richard Earnshaw Date: Mon, 18 Feb 2002 13:35:31 +0000 Subject: [PATCH] * 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. --- gdb/ChangeLog | 26 ++++++++++++++++++++++++++ gdb/arm-linux-tdep.c | 37 +++++-------------------------------- gdb/arm-tdep.c | 22 ++++++++++++++++++++++ gdb/arm-tdep.h | 14 ++++++++++---- gdb/armnbsd-nat.c | 6 ------ gdb/armnbsd-tdep.c | 7 +++++++ gdb/breakpoint.c | 20 ++++++++------------ gdb/config/arm/tm-linux.h | 8 -------- gdb/config/arm/tm-nbsd.h | 13 ------------- gdb/gdbarch.c | 38 ++++++++++++++++++++++++++++++++++++++ gdb/gdbarch.h | 39 +++++++++++++++++++++++++++++++++++++++ gdb/gdbarch.sh | 2 ++ gdb/infrun.c | 12 ++---------- 13 files changed, 159 insertions(+), 85 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index b0007fc1b7..a415c6bb70 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,29 @@ +2002-02-18 Richard Earnshaw + + * 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 From Peter Schauer : diff --git a/gdb/arm-linux-tdep.c b/gdb/arm-linux-tdep.c index 6049cf53a8..6faa4a277c 100644 --- a/gdb/arm-linux-tdep.c +++ b/gdb/arm-linux-tdep.c @@ -58,40 +58,10 @@ LONGEST arm_linux_call_dummy_words[] = 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. */ @@ -548,6 +518,9 @@ arm_linux_init_abi (struct gdbarch_info info, 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 diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c index a60f4978f0..7f2026708d 100644 --- a/gdb/arm-tdep.c +++ b/gdb/arm-tdep.c @@ -2272,6 +2272,23 @@ arm_store_struct_return (CORE_ADDR addr, CORE_ADDR sp) 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 @@ -2775,7 +2792,9 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) "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); @@ -2904,6 +2923,9 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) /* 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. */ diff --git a/gdb/arm-tdep.h b/gdb/arm-tdep.h index 85d9e4fb0c..29c8bc97db 100644 --- a/gdb/arm-tdep.h +++ b/gdb/arm-tdep.h @@ -123,10 +123,16 @@ struct gdbarch_tdep 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 diff --git a/gdb/armnbsd-nat.c b/gdb/armnbsd-nat.c index a270772b05..2d09bd3f62 100644 --- a/gdb/armnbsd-nat.c +++ b/gdb/armnbsd-nat.c @@ -97,9 +97,3 @@ fetch_core_registers (core_reg_sect, core_reg_size, which, ignore) #else #error Not FETCH_INFERIOR_REGISTERS #endif /* !FETCH_INFERIOR_REGISTERS */ - -int -get_longjmp_target (CORE_ADDR *addr) -{ - return 0; -} diff --git a/gdb/armnbsd-tdep.c b/gdb/armnbsd-tdep.c index 25c2f16424..291273b1fb 100644 --- a/gdb/armnbsd-tdep.c +++ b/gdb/armnbsd-tdep.c @@ -22,6 +22,10 @@ #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}; @@ -35,6 +39,9 @@ arm_netbsd_init_abi_common (struct gdbarch_info info, 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 diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index b22a2069b5..640505eab5 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -143,9 +143,7 @@ static int cover_target_enable_exception_callback (PTR); 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 *); @@ -3758,7 +3756,6 @@ create_internal_breakpoint (CORE_ADDR address, enum bptype type) return b; } -#ifdef GET_LONGJMP_TARGET static void create_longjmp_breakpoint (char *func_name) @@ -3782,8 +3779,6 @@ 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. */ @@ -6967,13 +6962,14 @@ breakpoint_re_set (void) 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"); } diff --git a/gdb/config/arm/tm-linux.h b/gdb/config/arm/tm-linux.h index aa3fa52cee..11de4fac7c 100644 --- a/gdb/config/arm/tm-linux.h +++ b/gdb/config/arm/tm-linux.h @@ -76,14 +76,6 @@ extern CORE_ADDR arm_linux_push_arguments (int, struct value **, CORE_ADDR, /* Offset to saved PC in sigcontext structure, from */ #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 diff --git a/gdb/config/arm/tm-nbsd.h b/gdb/config/arm/tm-nbsd.h index 4dfc32916e..5119879fe4 100644 --- a/gdb/config/arm/tm-nbsd.h +++ b/gdb/config/arm/tm-nbsd.h @@ -24,24 +24,11 @@ #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 diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c index f4000b52f2..8467d41423 100644 --- a/gdb/gdbarch.c +++ b/gdb/gdbarch.c @@ -182,6 +182,7 @@ struct gdbarch 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; @@ -346,6 +347,7 @@ struct gdbarch startup_gdbarch = 0, 0, 0, + 0, generic_get_saved_register, 0, 0, @@ -638,6 +640,7 @@ verify_gdbarch (struct gdbarch *gdbarch) /* 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"); @@ -1282,6 +1285,17 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file) "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 */ @@ -3029,6 +3043,30 @@ set_gdbarch_cannot_store_register (struct gdbarch *gdbarch, 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) { diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h index da5156cbf4..2dba00f3ee 100644 --- a/gdb/gdbarch.h +++ b/gdb/gdbarch.h @@ -883,6 +883,45 @@ extern void set_gdbarch_cannot_store_register (struct gdbarch *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 diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh index 29aca34637..996b87668d 100755 --- a/gdb/gdbarch.sh +++ b/gdb/gdbarch.sh @@ -466,6 +466,8 @@ f:2:REGISTER_SIM_REGNO:int:register_sim_regno:int reg_nr:reg_nr:::default_regist 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 diff --git a/gdb/infrun.c b/gdb/infrun.c index c935db86a7..1efe87b936 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -114,15 +114,6 @@ static ptid_t previous_inferior_ptid; 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 @@ -2306,7 +2297,8 @@ handle_inferior_event (struct execution_control_state *ecs) 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; -- 2.34.1