* arch-utils.c (generic_in_function_epilogue_p): New function.
authorCorinna Vinschen <corinna@vinschen.de>
Tue, 6 Nov 2001 11:02:12 +0000 (11:02 +0000)
committerCorinna Vinschen <corinna@vinschen.de>
Tue, 6 Nov 2001 11:02:12 +0000 (11:02 +0000)
* 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
gdb/arch-utils.c
gdb/arch-utils.h
gdb/breakpoint.c
gdb/gdbarch.c
gdb/gdbarch.h
gdb/gdbarch.sh

index e5e5715a8f25691665fc4fb778bf9975940c6614..51d071a68c275e6f276718fab9b232cc8932cce9 100644 (file)
@@ -1,3 +1,13 @@
+2001-11-06  Corinna Vinschen  <vinschen@redhat.com>
+
+       * 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  <jimb@redhat.com>
 
        * config/s390/s390.mh (NATDEPFILES): Don't split this across
index 19e35ffe4e522ae18148db04bb317a068f0faba8..0dab00c9330ec6ad5211b8d4740e5ae2be0e234e 100644 (file)
@@ -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)
 {
index 92fee9c4650e523985d23874be237d19ab119d43..5dec3c2bb784de0df5ca4ec5a10ec81d144c1e70 100644 (file)
@@ -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
index 310d2d6f4f77bb520770d5db6d210871727df397..848a07fe0aecc7f47ba72311fb20514fa7686716 100644 (file)
@@ -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
index 9cbc87a3cb93c67579b840a44dae44dac453ac01..94cac0210dbbb95a43faa6a902a05d94054e0b35 100644 (file)
@@ -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. */
index 19909693656e6e6bb3ef943acf9d1a8acac0b961..f41a35d6d2b8e33c44fb08d2d0b43b77d8f91b29 100644 (file)
@@ -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);
 
 
index 5e1f101dbf41bee3c917585e9dbaa084fb561609..34be94e6b7deb98057b6186b7ad3da7c0361d238 100755 (executable)
@@ -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
 }