From c12260ac385cffb6c60330b62a789a4fad9f52a1 Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Tue, 6 Nov 2001 11:02:12 +0000 Subject: [PATCH] * arch-utils.c (generic_in_function_epilogue_p): New function. * arch-utils.h (generic_in_function_epilogue_p): Declare extern. * breakpoint.c (watchpoint_check): Add test whether the pc is currently in the epilogue of a function. * gdbarch.c: Autogenerated from gdbarch.sh. * gdbarch.h: Ditto. * gdbarch.sh (function_list): Add `in_function_epilogue_p' definition. --- gdb/ChangeLog | 10 ++++++++++ gdb/arch-utils.c | 6 ++++++ gdb/arch-utils.h | 2 ++ gdb/breakpoint.c | 8 ++++++++ gdb/gdbarch.c | 26 ++++++++++++++++++++++++++ gdb/gdbarch.h | 14 ++++++++++++++ gdb/gdbarch.sh | 10 ++++++++++ 7 files changed, 76 insertions(+) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index e5e5715a8f2..51d071a68c2 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,13 @@ +2001-11-06 Corinna Vinschen + + * arch-utils.c (generic_in_function_epilogue_p): New function. + * arch-utils.h (generic_in_function_epilogue_p): Declare extern. + * breakpoint.c (watchpoint_check): Add test whether the pc is + currently in the epilogue of a function. + * gdbarch.c: Autogenerated from gdbarch.sh. + * gdbarch.h: Ditto. + * gdbarch.sh (function_list): Add `in_function_epilogue_p' definition. + 2001-11-05 Jim Blandy * config/s390/s390.mh (NATDEPFILES): Don't split this across diff --git a/gdb/arch-utils.c b/gdb/arch-utils.c index 19e35ffe4e5..0dab00c9330 100644 --- a/gdb/arch-utils.c +++ b/gdb/arch-utils.c @@ -111,6 +111,12 @@ generic_in_solib_call_trampoline (CORE_ADDR pc, char *name) return 0; } +int +generic_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc) +{ + return 0; +} + char * legacy_register_name (int i) { diff --git a/gdb/arch-utils.h b/gdb/arch-utils.h index 92fee9c4650..5dec3c2bb78 100644 --- a/gdb/arch-utils.h +++ b/gdb/arch-utils.h @@ -134,4 +134,6 @@ extern CORE_ADDR generic_skip_trampoline_code (CORE_ADDR pc); extern int generic_in_solib_call_trampoline (CORE_ADDR pc, char *name); +extern int generic_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc); + #endif diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index 310d2d6f4f7..848a07fe0ae 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -2308,6 +2308,14 @@ watchpoint_check (PTR p) reinit_frame_cache (); fr = find_frame_addr_in_frame_chain (b->watchpoint_frame); within_current_scope = (fr != NULL); + /* in_function_epilogue_p() returns a non-zero value if we're still + in the function but the stack frame has already been invalidated. + Since we can't rely on the values of local variables after the + stack has been destroyed, we are treating the watchpoint in that + state as `not changed' without further checking. */ + if (within_current_scope && fr == get_current_frame () + && gdbarch_in_function_epilogue_p (current_gdbarch, read_pc ())) + return WP_VALUE_NOT_CHANGED; if (within_current_scope) /* If we end up stopping, the current frame will get selected in normal_stop. So this call to select_frame won't affect diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c index 9cbc87a3cb9..94cac0210db 100644 --- a/gdb/gdbarch.c +++ b/gdb/gdbarch.c @@ -254,6 +254,7 @@ struct gdbarch gdbarch_print_insn_ftype *print_insn; gdbarch_skip_trampoline_code_ftype *skip_trampoline_code; gdbarch_in_solib_call_trampoline_ftype *in_solib_call_trampoline; + gdbarch_in_function_epilogue_p_ftype *in_function_epilogue_p; }; @@ -392,6 +393,7 @@ struct gdbarch startup_gdbarch = 0, 0, 0, + 0, /* startup_gdbarch() */ }; @@ -500,6 +502,7 @@ gdbarch_alloc (const struct gdbarch_info *info, current_gdbarch->print_insn = legacy_print_insn; current_gdbarch->skip_trampoline_code = generic_skip_trampoline_code; current_gdbarch->in_solib_call_trampoline = generic_in_solib_call_trampoline; + current_gdbarch->in_function_epilogue_p = generic_in_function_epilogue_p; /* gdbarch_alloc() */ return current_gdbarch; @@ -754,6 +757,7 @@ verify_gdbarch (struct gdbarch *gdbarch) /* Skip verify of print_insn, invalid_p == 0 */ /* Skip verify of skip_trampoline_code, invalid_p == 0 */ /* Skip verify of in_solib_call_trampoline, invalid_p == 0 */ + /* Skip verify of in_function_epilogue_p, invalid_p == 0 */ buf = ui_file_xstrdup (log, &dummy); make_cleanup (xfree, buf); if (strlen (buf) > 0) @@ -778,6 +782,10 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file) fprintf_unfiltered (file, "gdbarch_dump: GDB_MULTI_ARCH = %d\n", GDB_MULTI_ARCH); + if (GDB_MULTI_ARCH) + fprintf_unfiltered (file, + "gdbarch_dump: in_function_epilogue_p = 0x%08lx\n", + (long) current_gdbarch->in_function_epilogue_p); if (GDB_MULTI_ARCH) fprintf_unfiltered (file, "gdbarch_dump: register_read = 0x%08lx\n", @@ -4241,6 +4249,24 @@ set_gdbarch_in_solib_call_trampoline (struct gdbarch *gdbarch, gdbarch->in_solib_call_trampoline = in_solib_call_trampoline; } +int +gdbarch_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR addr) +{ + if (gdbarch->in_function_epilogue_p == 0) + internal_error (__FILE__, __LINE__, + "gdbarch: gdbarch_in_function_epilogue_p invalid"); + if (gdbarch_debug >= 2) + fprintf_unfiltered (gdb_stdlog, "gdbarch_in_function_epilogue_p called\n"); + return gdbarch->in_function_epilogue_p (gdbarch, addr); +} + +void +set_gdbarch_in_function_epilogue_p (struct gdbarch *gdbarch, + gdbarch_in_function_epilogue_p_ftype in_function_epilogue_p) +{ + gdbarch->in_function_epilogue_p = in_function_epilogue_p; +} + /* Keep a registry of per-architecture data-pointers required by GDB modules. */ diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h index 19909693656..f41a35d6d2b 100644 --- a/gdb/gdbarch.h +++ b/gdb/gdbarch.h @@ -2069,6 +2069,20 @@ extern void set_gdbarch_in_solib_call_trampoline (struct gdbarch *gdbarch, gdbar #endif #endif +/* A target might have problems with watchpoints as soon as the stack + frame of the current function has been destroyed. This mostly happens + as the first action in a funtion's epilogue. in_function_epilogue_p() + is defined to return a non-zero value if either the given addr is one + instruction after the stack destroying instruction up to the trailing + return instruction or if we can figure out that the stack frame has + already been invalidated regardless of the value of addr. Targets + which don't suffer from that problem could just let this functionality + untouched. */ + +typedef int (gdbarch_in_function_epilogue_p_ftype) (struct gdbarch *gdbarch, CORE_ADDR addr); +extern int gdbarch_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR addr); +extern void set_gdbarch_in_function_epilogue_p (struct gdbarch *gdbarch, gdbarch_in_function_epilogue_p_ftype *in_function_epilogue_p); + extern struct gdbarch_tdep *gdbarch_tdep (struct gdbarch *gdbarch); diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh index 5e1f101dbf4..34be94e6b7d 100755 --- a/gdb/gdbarch.sh +++ b/gdb/gdbarch.sh @@ -546,6 +546,16 @@ f:2:SKIP_TRAMPOLINE_CODE:CORE_ADDR:skip_trampoline_code:CORE_ADDR pc:pc:::generi # trampoline code in the ".plt" section. IN_SOLIB_CALL_TRAMPOLINE evaluates # to nonzero if we are current stopped in one of these. f:2:IN_SOLIB_CALL_TRAMPOLINE:int:in_solib_call_trampoline:CORE_ADDR pc, char *name:pc, name:::generic_in_solib_call_trampoline::0 +# A target might have problems with watchpoints as soon as the stack +# frame of the current function has been destroyed. This mostly happens +# as the first action in a funtion's epilogue. in_function_epilogue_p() +# is defined to return a non-zero value if either the given addr is one +# instruction after the stack destroying instruction up to the trailing +# return instruction or if we can figure out that the stack frame has +# already been invalidated regardless of the value of addr. Targets +# which don't suffer from that problem could just let this functionality +# untouched. +m:::int:in_function_epilogue_p:CORE_ADDR addr:addr::0:generic_in_function_epilogue_p::0 EOF } -- 2.30.2