This is the mail archive of the gdb@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Frame lost after 'leave' and before 'ret' instruction on i386?


Hello,

The patch is an attempt to solve the issue from the subject. It introduces a check for in_function_epilogue_p and introduces architecture level prev_register_from_epilogue.

The patch is a draft (works but is not complete).

Rationale: Dealing with epilogue in frame unwinders needs to be done only in sentinel frame (older frames will never be in epilogue).

Comments appreciated.


Thanks,


Aleksandar Ristovski
QNX Software Systems


ChangeLog (for reference only):


* gdbarch.c, gdbarch.h: Regenerated.
* gdbarch.sh: Introduce gdbarch_prev_frame_from_epilogue and provide
default_prev_frame_from_epilogue.
* i386-tdep.c (i386_in_function_epilogue_p, i386_prev_register_from_epilogue): New functions.
(struct frame_unwind_cache): Struct definition.
(i386_gdbarch_init): Register i386_prev_register_from_epilogue and
i386_in_function_epilogue_p.
* sentinel-frame.c (sentinel_frame_prev_register): Check if we are
in epilogue and if so, call gdbarch provided prev_frame_from_epilogue.
If this returns NULL do as before.
Index: gdb/gdbarch.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbarch.c,v
retrieving revision 1.427
diff -u -p -r1.427 gdbarch.c
--- gdb/gdbarch.c	16 May 2008 00:27:23 -0000	1.427
+++ gdb/gdbarch.c	23 May 2008 15:13:39 -0000
@@ -52,7 +52,12 @@
 /* Static function declarations */
 
 static void alloc_gdbarch_data (struct gdbarch *);
-
+static struct value *
+default_prev_register_from_epilogue (struct gdbarch *gdbarch,
+				     struct frame_info *this_frame, 
+				     void **this_prologue_cache, 
+				     int regnum,
+				     CORE_ADDR pc);
 /* Non-zero if we want to trace architecture code.  */
 
 #ifndef GDBARCH_DEBUG
@@ -237,6 +242,7 @@ struct gdbarch
   gdbarch_target_signal_from_host_ftype *target_signal_from_host;
   gdbarch_target_signal_to_host_ftype *target_signal_to_host;
   gdbarch_record_special_symbol_ftype *record_special_symbol;
+  gdbarch_prev_register_from_epilogue_ftype *prev_register_from_epilogue;
 };
 
 
@@ -366,6 +372,7 @@ struct gdbarch startup_gdbarch =
   default_target_signal_from_host,  /* target_signal_from_host */
   default_target_signal_to_host,  /* target_signal_to_host */
   0,  /* record_special_symbol */
+  default_prev_register_from_epilogue,  /* prev_register_from_epilogue */
   /* startup_gdbarch() */
 };
 
@@ -449,6 +456,7 @@ gdbarch_alloc (const struct gdbarch_info
   gdbarch->displaced_step_location = NULL;
   gdbarch->target_signal_from_host = default_target_signal_from_host;
   gdbarch->target_signal_to_host = default_target_signal_to_host;
+  gdbarch->prev_register_from_epilogue = default_prev_register_from_epilogue;
   /* gdbarch_alloc() */
 
   return gdbarch;
@@ -617,6 +625,7 @@ verify_gdbarch (struct gdbarch *gdbarch)
   /* Skip verify of target_signal_from_host, invalid_p == 0 */
   /* Skip verify of target_signal_to_host, invalid_p == 0 */
   /* Skip verify of record_special_symbol, has predicate */
+  /* Skip verify of prev_register_from_epilogue, invalid_p == 0 */
   buf = ui_file_xstrdup (log, &dummy);
   make_cleanup (xfree, buf);
   if (strlen (buf) > 0)
@@ -889,6 +898,9 @@ gdbarch_dump (struct gdbarch *gdbarch, s
                       "gdbarch_dump: pointer_to_address = <0x%lx>\n",
                       (long) gdbarch->pointer_to_address);
   fprintf_unfiltered (file,
+                      "gdbarch_dump: prev_register_from_epilogue = <0x%lx>\n",
+                      (long) gdbarch->prev_register_from_epilogue);
+  fprintf_unfiltered (file,
                       "gdbarch_dump: gdbarch_print_float_info_p() = %d\n",
                       gdbarch_print_float_info_p (gdbarch));
   fprintf_unfiltered (file,
@@ -3190,6 +3202,23 @@ set_gdbarch_record_special_symbol (struc
   gdbarch->record_special_symbol = record_special_symbol;
 }
 
+struct value *
+gdbarch_prev_register_from_epilogue (struct gdbarch *gdbarch, struct frame_info *this_frame, void **this_prologue_cache, int regnum, CORE_ADDR pc)
+{
+  gdb_assert (gdbarch != NULL);
+  gdb_assert (gdbarch->prev_register_from_epilogue != NULL);
+  if (gdbarch_debug >= 2)
+    fprintf_unfiltered (gdb_stdlog, "gdbarch_prev_register_from_epilogue called\n");
+  return gdbarch->prev_register_from_epilogue (gdbarch, this_frame, this_prologue_cache, regnum, pc);
+}
+
+void
+set_gdbarch_prev_register_from_epilogue (struct gdbarch *gdbarch,
+                                         gdbarch_prev_register_from_epilogue_ftype prev_register_from_epilogue)
+{
+  gdbarch->prev_register_from_epilogue = prev_register_from_epilogue;
+}
+
 
 /* Keep a registry of per-architecture data-pointers required by GDB
    modules. */
@@ -3600,6 +3629,16 @@ deprecated_current_gdbarch_select_hack (
   reinit_frame_cache ();
 }
 
+static struct value *
+default_prev_register_from_epilogue (struct gdbarch *gdbarch,
+				     struct frame_info *this_frame, 
+				     void **this_prologue_cache, 
+				     int regnum,
+				     CORE_ADDR pc)
+{
+  return NULL;
+}
+
 extern void _initialize_gdbarch (void);
 
 void
Index: gdb/gdbarch.h
===================================================================
RCS file: /cvs/src/src/gdb/gdbarch.h,v
retrieving revision 1.382
diff -u -p -r1.382 gdbarch.h
--- gdb/gdbarch.h	16 May 2008 00:27:23 -0000	1.382
+++ gdb/gdbarch.h	23 May 2008 15:13:39 -0000
@@ -798,6 +798,12 @@ typedef void (gdbarch_record_special_sym
 extern void gdbarch_record_special_symbol (struct gdbarch *gdbarch, struct objfile *objfile, asymbol *sym);
 extern void set_gdbarch_record_special_symbol (struct gdbarch *gdbarch, gdbarch_record_special_symbol_ftype *record_special_symbol);
 
+/* Create architecture dependent sentinel_frame. */
+
+typedef struct value * (gdbarch_prev_register_from_epilogue_ftype) (struct gdbarch *gdbarch, struct frame_info *this_frame, void **this_prologue_cache, int regnum, CORE_ADDR pc);
+extern struct value * gdbarch_prev_register_from_epilogue (struct gdbarch *gdbarch, struct frame_info *this_frame, void **this_prologue_cache, int regnum, CORE_ADDR pc);
+extern void set_gdbarch_prev_register_from_epilogue (struct gdbarch *gdbarch, gdbarch_prev_register_from_epilogue_ftype *prev_register_from_epilogue);
+
 extern struct gdbarch_tdep *gdbarch_tdep (struct gdbarch *gdbarch);
 
 
Index: gdb/gdbarch.sh
===================================================================
RCS file: /cvs/src/src/gdb/gdbarch.sh,v
retrieving revision 1.468
diff -u -p -r1.468 gdbarch.sh
--- gdb/gdbarch.sh	16 May 2008 00:27:23 -0000	1.468
+++ gdb/gdbarch.sh	23 May 2008 15:13:39 -0000
@@ -703,6 +703,10 @@ m:int:target_signal_to_host:enum target_
 
 # Record architecture-specific information from the symbol table.
 M:void:record_special_symbol:struct objfile *objfile, asymbol *sym:objfile, sym
+
+# Create architecture dependent sentinel_frame.
+m:struct value *:prev_register_from_epilogue:struct frame_info *this_frame, void **this_prologue_cache, int regnum, CORE_ADDR pc:this_frame, this_prologue_cache, regnum, pc::default_prev_register_from_epilogue::0
+
 EOF
 }
 
@@ -1133,7 +1137,12 @@ cat <<EOF
 /* Static function declarations */
 
 static void alloc_gdbarch_data (struct gdbarch *);
-
+static struct value *
+default_prev_register_from_epilogue (struct gdbarch *gdbarch,
+				     struct frame_info *this_frame, 
+				     void **this_prologue_cache, 
+				     int regnum,
+				     CORE_ADDR pc);
 /* Non-zero if we want to trace architecture code.  */
 
 #ifndef GDBARCH_DEBUG
@@ -2017,6 +2026,16 @@ deprecated_current_gdbarch_select_hack (
   reinit_frame_cache ();
 }
 
+static struct value *
+default_prev_register_from_epilogue (struct gdbarch *gdbarch,
+				     struct frame_info *this_frame, 
+				     void **this_prologue_cache, 
+				     int regnum,
+				     CORE_ADDR pc)
+{
+  return NULL;
+}
+
 extern void _initialize_gdbarch (void);
 
 void
Index: gdb/i386-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/i386-tdep.c,v
retrieving revision 1.258
diff -u -p -r1.258 i386-tdep.c
--- gdb/i386-tdep.c	16 May 2008 00:27:23 -0000	1.258
+++ gdb/i386-tdep.c	23 May 2008 15:13:40 -0000
@@ -2449,7 +2449,68 @@ i386_fetch_pointer_argument (struct fram
   CORE_ADDR sp = get_frame_register_unsigned  (frame, I386_ESP_REGNUM);
   return read_memory_unsigned_integer (sp + (4 * (argi + 1)), 4);
 }
+
+/* Determine if we are at one of RET instructions. If we are, then
+   chances are SP has been restored to the previous frame.  */
+
+static int
+i386_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+  gdb_byte insn_buf[4];
+  struct frame_info *current_frame = get_current_frame ();
+
+  if (!safe_frame_unwind_memory (current_frame, pc, insn_buf, 1))
+    return 0;
+
+  if (insn_buf[0] == 0xC3)
+    return 1;
+
+  return 0;
+}
+
+struct frame_unwind_cache
+{
+  struct regcache *regcache;
+};
 
+static struct value *
+i386_prev_register_from_epilogue (struct gdbarch *gdbarch, 
+				  struct frame_info *this_frame, 
+				  void **this_cache, 
+				  int regnum, 
+				  CORE_ADDR pc)
+{
+  struct value *value;
+  struct frame_unwind_cache *cache = *this_cache;
+  printf_unfiltered ("Register from epilogue\n");
+  /* Return the actual value.  */
+  value = allocate_value (register_type (gdbarch, regnum));
+  VALUE_LVAL (value) = lval_register;
+  VALUE_REGNUM (value) = regnum;
+  VALUE_FRAME_ID (value) = get_frame_id (this_frame);
+
+  if (regnum == I386_EBP_REGNUM)
+    {
+      CORE_ADDR esp;
+      /* This register has special meaning; it preserves ESP of the caller
+	 (set in prologue) but in epilogue it has already been restored to
+	 the value before the call.  To keep the rest of the stuff working,
+	 pretend we are still before the epilogue, i.e. return the ESP.  */
+      regcache_cooked_read (cache->regcache, I386_ESP_REGNUM, 
+			    value_contents_raw (value));
+      esp = value_as_address (value);
+      esp -= 4;
+      store_unsigned_integer (value_contents_raw (value), 4, esp);
+      return value;
+    }
+
+  /* Use the regcache_cooked_read() method so that it, on the fly,
+     constructs either a raw or pseudo register from the raw
+     register cache.  */
+  regcache_cooked_read (cache->regcache, regnum, value_contents_raw (value));
+
+  return value;
+}
 
 static struct gdbarch *
 i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
@@ -2587,6 +2648,7 @@ i386_gdbarch_init (struct gdbarch_info i
   set_gdbarch_return_value (gdbarch, i386_return_value);
 
   set_gdbarch_skip_prologue (gdbarch, i386_skip_prologue);
+  set_gdbarch_in_function_epilogue_p (gdbarch, i386_in_function_epilogue_p);
 
   /* Stack grows downward.  */
   set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
@@ -2625,6 +2687,8 @@ i386_gdbarch_init (struct gdbarch_info i
 
   frame_unwind_append_unwinder (gdbarch, &i386_sigtramp_frame_unwind);
   frame_unwind_append_unwinder (gdbarch, &i386_frame_unwind);
+  set_gdbarch_prev_register_from_epilogue (gdbarch, 
+					   i386_prev_register_from_epilogue);
 
   /* If we have a register mapping, enable the generic core file
      support, unless it has already been enabled.  */
Index: gdb/sentinel-frame.c
===================================================================
RCS file: /cvs/src/src/gdb/sentinel-frame.c,v
retrieving revision 1.18
diff -u -p -r1.18 sentinel-frame.c
--- gdb/sentinel-frame.c	30 Apr 2008 21:16:45 -0000	1.18
+++ gdb/sentinel-frame.c	23 May 2008 15:13:40 -0000
@@ -49,8 +49,25 @@ sentinel_frame_prev_register (struct fra
 {
   struct gdbarch *gdbarch = get_frame_arch (this_frame);
   struct frame_unwind_cache *cache = *this_prologue_cache;
-  struct value *value;
+  struct value *value = NULL;
 
+  if (regnum != gdbarch_pc_regnum (gdbarch))
+    {
+      struct value *value_pc;
+      CORE_ADDR pc;
+      value_pc = sentinel_frame_prev_register (this_frame, 
+					       this_prologue_cache, 
+					       gdbarch_pc_regnum (gdbarch));
+      pc = value_as_address (value_pc);
+      if (gdbarch_in_function_epilogue_p (gdbarch, pc))
+	value = gdbarch_prev_register_from_epilogue (gdbarch, 
+						     this_frame, 
+						     this_prologue_cache,
+						     regnum,
+						     pc);
+      if (value)
+	return value;
+    }
   /* Return the actual value.  */
   value = allocate_value (register_type (gdbarch, regnum));
   VALUE_LVAL (value) = lval_register;
@@ -84,3 +101,4 @@ const struct frame_unwind sentinel_frame
 };
 
 const struct frame_unwind *const sentinel_frame_unwind = &sentinel_frame_unwinder;
+

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]