This is the mail archive of the gdb-patches@sources.redhat.com 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]

[offbyone RFC] Merge i386newframe


Hi Andrew,
this patch is a merge of Mark's i386newframe-branch to your offbyone-branch. It works quite well, unwinds through signal frames and frameless functions, but still has some strange regressions that aren't present in i386newframe branch.


For example this program:
int var;
void foo ()
{
  var = 0x1234;
}
int main ()
{
  foo ();
  return 0;
}

Running it in the GDB:
(gdb) b main
Breakpoint 1 at 0x804832c: file tst.c, line 8.
(gdb) r
Starting program: tst

Breakpoint 1, main () at tst.c:8
8         foo ();
(gdb) n

Program exited normally.
(gdb)

Why it didn't stop on "return 0" but exitted immediately instead? Did you observe this behaviour in offbyone branch too, or is it caused by this patch? It seems to have something to do with symbols, linetables, ... but I can't see how it could be related to this patch. It doesn't matter if I compile the program with stabs or dwarf2 debug info. Ideas?

Anyway comments on the code are welcome. As soon as i386newframe is merged to offbyone I'll start porting x86-64 on top of it as well.

Michal Ludvig
--
* SuSE CR, s.r.o     * mludvig at suse dot cz
* (+420) 296.545.373 * http://www.suse.cz
2003-03-12  Michal Ludvig  <mludvig at suse dot cz>

	* frame.c (get_prev_frame): Link prev_frame to this_frame 
	as soon as possible.
	* i386-tdep.c (i386_frameless_signal_p, i386_frame_chain)
	(i386_sigtramp_saved_pc, i386_sigtramp_saved_sp)
	(i386_frame_saved_pc, i386_frame_init_saved_regs): Removed.
	(i386_frame_cache): New structure.
	(i386_unwind_pc): New method.
	(i386_frame_cache, i386_frame_pc_unwind, i386_frame_unwind)
	(i386_frame_id_unwind, i386_frame_register_unwind): New 
	stuff for unwinding normal frames.
	(i386_sigtramp_cache, i386_sigtramp_pc_unwind)
	(i386_sigtramp_id_unwind, i386_sigtramp_register_unwind)
	(i386_sigtramp_unwind): New stuff for unwinding sigtramp 
	frames.
	(i386_frame_p): New.
	(i386_unwind_dummy_id, i386_save_dummy_frame_tos): New.
	(i386_pc_in_sigtramp): Doesn't need name anymore.
	(i386_gdbarch_init): Updated to use new unwinding methods.

Index: frame.c
===================================================================
RCS file: /cvs/src/src/gdb/frame.c,v
retrieving revision 1.71.2.7
diff -u -p -r1.71.2.7 frame.c
--- frame.c	11 Mar 2003 23:00:26 -0000	1.71.2.7
+++ frame.c	12 Mar 2003 16:28:15 -0000
@@ -1282,7 +1282,6 @@ get_prev_frame (struct frame_info *this_
   /* Only try to do the unwind once.  */
   if (this_frame->prev_p)
     return this_frame->prev;
-  this_frame->prev_p = 1;
 
   /* If we're inside the entry file, it isn't valid.  Don't apply this
      test to a dummy frame - dummy frame PC's typically land in the
@@ -1351,6 +1350,11 @@ get_prev_frame (struct frame_info *this_
   prev_frame = FRAME_OBSTACK_ZALLOC (struct frame_info);
   prev_frame->level = this_frame->level + 1;
 
+  /* Link it in.  */
+  this_frame->prev = prev_frame;
+  prev_frame->next = this_frame;
+  this_frame->prev_p = 1;
+
   /* Try to unwind the PC.  If that doesn't work, assume we've reached
      the oldest frame and simply return.  Is there a better sentinal
      value?  The unwound PC value is then used to initialize the new
@@ -1466,10 +1470,6 @@ get_prev_frame (struct frame_info *this_
      (HP/UX) still reply on EXTRA_FRAME_INFO and, hence, still poke at
      the "struct frame_info" object directly.  */
   prev_frame->frame = prev_frame->id.base;
-
-  /* Link it in.  */
-  this_frame->prev = prev_frame;
-  prev_frame->next = this_frame;
 
   /* FIXME: cagney/2002-01-19: This call will go away.  Instead of
      initializing extra info, all frames will use the frame_cache
Index: i386-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/i386-tdep.c,v
retrieving revision 1.116
diff -u -p -r1.116 i386-tdep.c
--- i386-tdep.c	3 Mar 2003 20:50:18 -0000	1.116
+++ i386-tdep.c	12 Mar 2003 16:28:15 -0000
@@ -469,64 +476,8 @@ i386_get_frame_setup (CORE_ADDR pc)
   return (-1);
 }
 
-/* Signal trampolines don't have a meaningful frame.  The frame
-   pointer value we use is actually the frame pointer of the calling
-   frame -- that is, the frame which was in progress when the signal
-   trampoline was entered.  GDB mostly treats this frame pointer value
-   as a magic cookie.  We detect the case of a signal trampoline by
-   testing for get_frame_type() == SIGTRAMP_FRAME, which is set based
-   on PC_IN_SIGTRAMP.
-
-   When a signal trampoline is invoked from a frameless function, we
-   essentially have two frameless functions in a row.  In this case,
-   we use the same magic cookie for three frames in a row.  We detect
-   this case by seeing whether the next frame is a SIGTRAMP_FRAME,
-   and, if it does, checking whether the current frame is actually
-   frameless.  In this case, we need to get the PC by looking at the
-   SP register value stored in the signal context.
-
-   This should work in most cases except in horrible situations where
-   a signal occurs just as we enter a function but before the frame
-   has been set up.  Incidentally, that's just what happens when we
-   call a function from GDB with a signal pending (there's a test in
-   the testsuite that makes this happen).  Therefore we pretend that
-   we have a frameless function if we're stopped at the start of a
-   function.  */
-
-/* Return non-zero if we're dealing with a frameless signal, that is,
-   a signal trampoline invoked from a frameless function.  */
-
-int
-i386_frameless_signal_p (struct frame_info *frame)
-{
-  return (get_next_frame (frame)
-	  && get_frame_type (get_next_frame (frame)) == SIGTRAMP_FRAME
-	  && (frameless_look_for_prologue (frame)
-	      || get_frame_pc (frame) == get_pc_function_start (get_frame_pc (frame))));
-}
-
-/* Return the chain-pointer for FRAME.  In the case of the i386, the
-   frame's nominal address is the address of a 4-byte word containing
-   the calling frame's address.  */
-
-static CORE_ADDR
-i386_frame_chain (struct frame_info *frame)
-{
-  if (pc_in_dummy_frame (get_frame_pc (frame)))
-    return get_frame_base (frame);
-
-  if (get_frame_type (frame) == SIGTRAMP_FRAME
-      || i386_frameless_signal_p (frame))
-    return get_frame_base (frame);
-
-  if (! inside_entry_file (get_frame_pc (frame)))
-    return read_memory_unsigned_integer (get_frame_base (frame), 4);
-
-  return 0;
-}
-
 /* Determine whether the function invocation represented by FRAME does
-   not have a from on the stack associated with it.  If it does not,
+   not have a frame on the stack associated with it.  If it does not,
    return non-zero, otherwise return zero.  */
 
 static int
@@ -538,66 +489,16 @@ i386_frameless_function_invocation (stru
   return frameless_look_for_prologue (frame);
 }
 
-/* Assuming FRAME is for a sigtramp routine, return the saved program
-   counter.  */
-
-static CORE_ADDR
-i386_sigtramp_saved_pc (struct frame_info *frame)
-{
-  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
-  CORE_ADDR addr;
-
-  addr = tdep->sigcontext_addr (frame);
-  return read_memory_unsigned_integer (addr + tdep->sc_pc_offset, 4);
-}
-
-/* Assuming FRAME is for a sigtramp routine, return the saved stack
-   pointer.  */
-
-static CORE_ADDR
-i386_sigtramp_saved_sp (struct frame_info *frame)
-{
-  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
-  CORE_ADDR addr;
-
-  addr = tdep->sigcontext_addr (frame);
-  return read_memory_unsigned_integer (addr + tdep->sc_sp_offset, 4);
-}
-
-/* Return the saved program counter for FRAME.  */
-
-static CORE_ADDR
-i386_frame_saved_pc (struct frame_info *frame)
-{
-  if (pc_in_dummy_frame (get_frame_pc (frame)))
-    {
-      ULONGEST pc;
-
-      frame_unwind_unsigned_register (frame, PC_REGNUM, &pc);
-      return pc;
-    }
-
-  if (get_frame_type (frame) == SIGTRAMP_FRAME)
-    return i386_sigtramp_saved_pc (frame);
-
-  if (i386_frameless_signal_p (frame))
-    {
-      CORE_ADDR sp = i386_sigtramp_saved_sp (get_next_frame (frame));
-      return read_memory_unsigned_integer (sp, 4);
-    }
-
-  return read_memory_unsigned_integer (get_frame_base (frame) + 4, 4);
-}
-
 /* Immediately after a function call, return the saved pc.  */
 
 static CORE_ADDR
 i386_saved_pc_after_call (struct frame_info *frame)
 {
-  if (get_frame_type (frame) == SIGTRAMP_FRAME)
-    return i386_sigtramp_saved_pc (frame);
+  char buf[4];
 
-  return read_memory_unsigned_integer (read_register (SP_REGNUM), 4);
+  /* Our frame unwinder handles this just fine.  */
+  frame_unwind_register (frame, PC_REGNUM, buf);
+  return extract_address (buf, 4);
 }
 
 /* Return number of args passed to a frame.
@@ -674,72 +575,6 @@ i386_frame_num_args (struct frame_info *
 #endif
 }
 
-/* Parse the first few instructions the function to see what registers
-   were stored.
-   
-   We handle these cases:
-
-   The startup sequence can be at the start of the function, or the
-   function can start with a branch to startup code at the end.
-
-   %ebp can be set up with either the 'enter' instruction, or "pushl
-   %ebp, movl %esp, %ebp" (`enter' is too slow to be useful, but was
-   once used in the System V compiler).
-
-   Local space is allocated just below the saved %ebp by either the
-   'enter' instruction, or by "subl $<size>, %esp".  'enter' has a 16
-   bit unsigned argument for space to allocate, and the 'addl'
-   instruction could have either a signed byte, or 32 bit immediate.
-
-   Next, the registers used by this function are pushed.  With the
-   System V compiler they will always be in the order: %edi, %esi,
-   %ebx (and sometimes a harmless bug causes it to also save but not
-   restore %eax); however, the code below is willing to see the pushes
-   in any order, and will handle up to 8 of them.
- 
-   If the setup sequence is at the end of the function, then the next
-   instruction will be a branch back to the start.  */
-
-static void
-i386_frame_init_saved_regs (struct frame_info *fip)
-{
-  long locals = -1;
-  unsigned char op;
-  CORE_ADDR addr;
-  CORE_ADDR pc;
-  int i;
-
-  if (get_frame_saved_regs (fip))
-    return;
-
-  frame_saved_regs_zalloc (fip);
-
-  pc = get_pc_function_start (get_frame_pc (fip));
-  if (pc != 0)
-    locals = i386_get_frame_setup (pc);
-
-  if (locals >= 0)
-    {
-      addr = get_frame_base (fip) - 4 - locals;
-      for (i = 0; i < 8; i++)
-	{
-	  op = codestream_get ();
-	  if (op < 0x50 || op > 0x57)
-	    break;
-#ifdef I386_REGNO_TO_SYMMETRY
-	  /* Dynix uses different internal numbering.  Ick.  */
-	  get_frame_saved_regs (fip)[I386_REGNO_TO_SYMMETRY (op - 0x50)] = addr;
-#else
-	  get_frame_saved_regs (fip)[op - 0x50] = addr;
-#endif
-	  addr -= 4;
-	}
-    }
-
-  get_frame_saved_regs (fip)[PC_REGNUM] = get_frame_base (fip) + 4;
-  get_frame_saved_regs (fip)[FP_REGNUM] = get_frame_base (fip);
-}
-
 /* Return PC of first real instruction.  */
 
 static CORE_ADDR
@@ -855,37 +690,423 @@ i386_push_return_address (CORE_ADDR pc, 
   write_memory (sp - 4, buf, 4);
   return sp - 4;
 }
+
+#include "frame-unwind.h"
+
+#define regcache_cooked_write_unsigned regcache_raw_write_unsigned
+
+#ifdef I386_REGNO_TO_SYMMETRY
+#error "The Sequent Symmetry is no longer supported."
+#endif
+
+/* According to the System V ABI, the registers %ebp, %ebx, %edi, %esi
+   and %esp "belong" to the calling function.  */
+
+/* The maximum number of saved registers.  This should include all
+   registers mentioned above, and %eip.  */
+#define I386_NUM_SAVED_REGISTERS	9
+
+struct i386_frame_cache
+{
+  CORE_ADDR saved_regs[I386_NUM_SAVED_REGISTERS];
+  CORE_ADDR saved_sp;
+  CORE_ADDR return_pc;
+  CORE_ADDR base;
+  int frameless;
+};
+
+/* Parse the first few instructions the function to see what registers
+   were stored.
+   
+   We handle these cases:
+
+   The startup sequence can be at the start of the function, or the
+   function can start with a branch to startup code at the end.
+
+   %ebp can be set up with either the 'enter' instruction, or "pushl
+   %ebp, movl %esp, %ebp" (`enter' is too slow to be useful, but was
+   once used in the System V compiler).
+
+   Local space is allocated just below the saved %ebp by either the
+   'enter' instruction, or by "subl $<size>, %esp".  'enter' has a 16
+   bit unsigned argument for space to allocate, and the 'addl'
+   instruction could have either a signed byte, or 32 bit immediate.
+
+   Next, the registers used by this function are pushed.  With the
+   System V compiler they will always be in the order: %edi, %esi,
+   %ebx (and sometimes a harmless bug causes it to also save but not
+   restore %eax); however, the code below is willing to see the pushes
+   in any order, and will handle up to 8 of them.
+ 
+   If the setup sequence is at the end of the function, then the next
+   instruction will be a branch back to the start.  */
+
+static struct i386_frame_cache *
+i386_frame_cache (struct frame_info *frame, void **cachep)
+{
+  struct i386_frame_cache *cache;
+  CORE_ADDR pc, start_pc;
+
+  if (*cachep)
+    return *cachep;
+
+  cache = FRAME_OBSTACK_ZALLOC (struct i386_frame_cache);
+
+  pc = frame_pc_unwind (frame);
+  start_pc = get_pc_function_start (pc);
+
+  long locals = -1;
+
+  if (start_pc != 0)
+    locals = i386_get_frame_setup (start_pc);
+
+  if (locals >= 0 && pc > start_pc)
+    {
+      ULONGEST fp;
+      CORE_ADDR addr;
+      unsigned char op;
+      int i;
+
+      frame_unwind_unsigned_register (frame, FP_REGNUM, &fp);
+      cache->base = fp;
+
+      addr = fp - 4 - locals;
+      for (i = 0; i < I386_NUM_SAVED_REGISTERS; i++)
+        {
+          op = codestream_get ();
+          if (op < 0x50 || op > 0x57)
+    	break;
+
+          cache->saved_regs[op - 0x50] = addr;
+          addr -= 4;
+        }
+
+      cache->saved_regs[PC_REGNUM] = fp + 4;
+      cache->saved_regs[FP_REGNUM] = fp;
+      cache->saved_sp = fp + 8;
+    }
+  else
+    {
+      ULONGEST sp;
+    
+      /* This function is either frameless or we're at the start
+         of the function and this function's frame hasn't been
+         setup yet.  In the latter case only %eip and %esp have
+         changed, and we can determine their previous values.  We
+         pretend we can do the same in the former case.  */
+      cache->frameless = 1;
+    
+      frame_unwind_unsigned_register (frame, SP_REGNUM, &sp);
+      cache->saved_regs[PC_REGNUM] = sp;
+      cache->saved_sp = cache->saved_regs[PC_REGNUM] + 4;
+      cache->base = sp;
+    }
+
+  *cachep = cache;
+  return cache;
+}
 
 static void
-i386_do_pop_frame (struct frame_info *frame)
+i386_frame_pop (struct frame_info *frame, void **cachep,
+		struct regcache *regcache)
 {
-  CORE_ADDR fp;
+  CORE_ADDR fp = get_frame_base (frame);
   int regnum;
-  char regbuf[I386_MAX_REGISTER_SIZE];
+  char buf[4];
+  ULONGEST val;
 
-  fp = get_frame_base (frame);
-  i386_frame_init_saved_regs (frame);
+  gdb_assert (get_frame_type (frame) != DUMMY_FRAME);
 
-  for (regnum = 0; regnum < NUM_REGS; regnum++)
+  for (regnum = 0; regnum < I386_NUM_SAVED_REGISTERS; regnum++)
     {
-      CORE_ADDR addr;
-      addr = get_frame_saved_regs (frame)[regnum];
-      if (addr)
+      frame_unwind_register (frame, regnum, buf);
+      regcache_cooked_write (regcache, regnum, buf);
+    }
+
+  /* Reset the direction flag.  */
+  regcache_cooked_read_unsigned (regcache, PS_REGNUM, &val);
+  val &= ~(1 << 10);
+  regcache_cooked_write_unsigned (regcache, PS_REGNUM, val);
+
+  /* The following sequence restores %ebp, %eip and %esp.  */
+  read_memory (fp, buf, 4);
+  regcache_cooked_write (regcache, FP_REGNUM, buf);
+  read_memory (fp + 4, buf, 4);
+  regcache_cooked_write (regcache, PC_REGNUM, buf);
+  regcache_cooked_write_unsigned (regcache, SP_REGNUM, fp + 8);
+
+  flush_cached_frames ();
+}
+
+static CORE_ADDR
+i386_frame_pc_unwind (struct frame_info *frame, void **cachep)
+{
+  struct i386_frame_cache *cache = i386_frame_cache (frame, cachep);
+
+  gdb_assert (get_frame_type (frame) != DUMMY_FRAME);
+
+  if (cache->return_pc == 0)
+    {
+      char buf[4];
+
+      frame_unwind_register (frame, PC_REGNUM, buf);
+      cache->return_pc = extract_address (buf, 4);
+    }
+
+  return cache->return_pc;
+}
+
+static CORE_ADDR
+i386_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+  ULONGEST pc;
+  frame_unwind_unsigned_register (next_frame, PC_REGNUM, &pc);
+  return (CORE_ADDR) pc;
+}
+
+static void
+i386_frame_id_unwind (struct frame_info *next_frame, void **cachep,
+		      struct frame_id *id)
+{
+  struct i386_frame_cache *cache = i386_frame_cache (next_frame, cachep);
+  
+  gdb_assert (cache);
+  gdb_assert (get_frame_type (next_frame) != DUMMY_FRAME);
+
+  /* Start with a NULL next_frame ID.  */
+  *id = null_frame_id;
+
+  /* Unwind PC first */
+  id->pc = frame_pc_unwind (next_frame);
+  cache->return_pc = id->pc;
+
+  /* The next_frame's base is the address of a 4-byte word containing the
+     calling next_frame's address.
+
+     Signal trampolines don't have a meaningful next_frame.  The frame
+     pointer value we use is actually the next_frame pointer of the calling
+     next_frame -- that is, the frame which was in progress when the signal
+     trampoline was entered.  GDB mostly treats this next_frame pointer
+     value as a magic cookie.  We detect the case of a signal
+     trampoline by testing for get_frame_type() == SIGTRAMP_FRAME,
+     which is set based on PC_IN_SIGTRAMP.  */
+
+  if (get_frame_type (next_frame) == SIGTRAMP_FRAME || cache->frameless)
+    id->base = get_frame_base (next_frame);
+  else
+    if (!inside_entry_file (get_frame_pc (next_frame)))
+      id->base = cache->base;
+}
+
+static void
+i386_frame_register_unwind (struct frame_info *frame, void **cachep,
+			    int regnum, int *optimizedp,
+			    enum lval_type *lvalp, CORE_ADDR *addrp,
+			    int *realnump, void *valuep)
+{
+  /* FIXME: kettenis/20030302: I don't understand why the cache isn't
+     already initialized.  */
+  struct i386_frame_cache *cache = i386_frame_cache (frame, cachep);
+
+  gdb_assert (cache);
+  gdb_assert (get_frame_type (frame) != DUMMY_FRAME);
+  gdb_assert (regnum >= 0);
+
+  if (regnum == SP_REGNUM && cache->saved_sp)
+    {
+      *optimizedp = 0;
+      *lvalp = not_lval;
+      *addrp = 0;
+      *realnump = -1;
+      if (valuep)
 	{
-	  read_memory (addr, regbuf, REGISTER_RAW_SIZE (regnum));
-	  deprecated_write_register_gen (regnum, regbuf);
+	  /* Store the value.  */
+	  store_address (valuep, 4, cache->saved_regs[SP_REGNUM]);
 	}
+      return;
     }
-  write_register (FP_REGNUM, read_memory_integer (fp, 4));
-  write_register (PC_REGNUM, read_memory_integer (fp + 4, 4));
-  write_register (SP_REGNUM, fp + 8);
-  flush_cached_frames ();
+
+  if (regnum == PC_REGNUM)
+    {
+      CORE_ADDR pc;
+      *optimizedp = 0;
+      *lvalp = not_lval;
+      *addrp = 0;
+      *realnump = -1;
+      pc = i386_frame_pc_unwind (frame, cachep);
+      if (valuep)
+        store_address (valuep, 4, pc);
+    }
+
+  if (regnum < I386_NUM_SAVED_REGISTERS && cache->saved_regs[regnum] != 0)
+    {
+      *optimizedp = 0;
+      *lvalp = lval_memory;
+      *addrp = cache->saved_regs[regnum];
+      *realnump = -1;
+      if (valuep)
+	{
+	  /* Read the value in from memory.  */
+	  read_memory (*addrp, valuep,
+		       register_size (current_gdbarch, regnum));
+	}
+      return;
+    }
+
+  frame_register (frame, regnum, optimizedp, lvalp, addrp, realnump, valuep);
+}
+
+static struct i386_frame_cache *
+i386_sigtramp_cache (struct frame_info *frame, void **cachep)
+{
+  struct i386_frame_cache *cache;
+  CORE_ADDR pc, start_pc, addr;
+  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+  int sc_offset, regnum;
+
+  if (*cachep)
+    return *cachep;
+
+  cache = FRAME_OBSTACK_ZALLOC (struct i386_frame_cache);
+
+  pc = frame_pc_unwind (frame);
+  start_pc = get_pc_function_start (pc);
+  addr = tdep->sigcontext_addr (frame->prev);
+
+  for (regnum=0; regnum<=PS_REGNUM; regnum++)
+  {
+    /* See <asm/sigcontext.h> for details on how registers are stored 
+       in the sigcontext.  */
+    if (regnum < PC_REGNUM)
+      sc_offset = (11 - regnum);
+    else if (regnum == PC_REGNUM)
+      sc_offset = 14;
+    else if (regnum == PS_REGNUM)
+      sc_offset = 16;
+    else
+      break;
+
+    sc_offset *= 4;
+
+    if (regnum < sizeof (cache->saved_regs))
+      cache->saved_regs[regnum] = addr + sc_offset;
+  }
+
+  cache->base = addr;
+
+  *cachep = cache;
+  return cache;
+}
+
+static void
+i386_sigtramp_register_unwind (struct frame_info *frame, void **cachep,
+			    int regnum, int *optimizedp,
+			    enum lval_type *lvalp, CORE_ADDR *addrp,
+			    int *realnump, void *valuep)
+{
+  printf_debug ("## %s(%p, %p, %s(%d))\n", __func__, (void*)frame->frame,
+		   (void*)frame->pc, i386_register_name(regnum), regnum);
+
+  struct i386_frame_cache *cache = i386_sigtramp_cache (frame, cachep);
+  char buf[4];
+  CORE_ADDR addr;
+
+  gdb_assert (cache);
+  gdb_assert (regnum >= 0);
+
+  if (regnum < I386_NUM_SAVED_REGISTERS && cache->saved_regs[regnum] != 0)
+  {
+    *optimizedp = 0;
+    *lvalp = lval_memory;
+    *addrp = cache->saved_regs[regnum];
+    *realnump = -1;
+    if (valuep)
+        read_memory (*addrp, valuep,
+		   register_size (current_gdbarch, regnum));
+    return;
+  }
+  
+  /* Fall back for non-saved registers.  */
+  frame_register (frame, regnum, optimizedp, lvalp, addrp, realnump, valuep);
 }
 
 static void
-i386_pop_frame (void)
+i386_sigtramp_id_unwind (struct frame_info *next_frame, void **cachep,
+		      struct frame_id *id)
+{
+  printf_debug ("## %s(%p, %p)\n", __func__, (void*)next_frame->frame,
+		   (void*)next_frame->pc);
+  struct i386_frame_cache *cache = i386_sigtramp_cache (next_frame, cachep);
+  
+  gdb_assert (cache);
+  gdb_assert (get_frame_type (next_frame) != DUMMY_FRAME);
+
+  /* Start with a NULL next_frame ID.  */
+  *id = null_frame_id;
+
+  /* Unwind PC first */
+  id->pc = frame_pc_unwind (next_frame);
+  cache->return_pc = id->pc;
+
+  /* The next_frame's base is the address of a 4-byte word containing the
+     calling next_frame's address.
+
+     Signal trampolines don't have a meaningful next_frame.  The frame
+     pointer value we use is actually the next_frame pointer of the calling
+     next_frame -- that is, the frame which was in progress when the signal
+     trampoline was entered.  GDB mostly treats this next_frame pointer
+     value as a magic cookie.  We detect the case of a signal
+     trampoline by testing for get_frame_type() == SIGTRAMP_FRAME,
+     which is set based on PC_IN_SIGTRAMP.  */
+
+  if (get_frame_type (next_frame) == SIGTRAMP_FRAME || cache->frameless)
+    id->base = get_frame_base (next_frame);
+  else
+    if (!inside_entry_file (get_frame_pc (next_frame)))
+      id->base = cache->base;
+}
+
+static struct frame_unwind i386_sigtramp_unwind = {
+  i386_sigtramp_id_unwind,
+  i386_sigtramp_register_unwind
+};
+
+static struct frame_unwind i386_frame_unwind = {
+  i386_frame_id_unwind,
+  i386_frame_register_unwind
+};
+
+const struct frame_unwind *
+i386_frame_p (CORE_ADDR pc)
 {
-  generic_pop_current_frame (i386_do_pop_frame);
+  if (gdbarch_pc_in_sigtramp (current_gdbarch, pc, NULL))
+    return &i386_sigtramp_unwind;
+  else
+    return &i386_frame_unwind;
+}
+
+static struct frame_id
+i386_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+  struct frame_id id;
+  ULONGEST base;
+
+  id.pc = frame_pc_unwind (next_frame);
+  frame_unwind_unsigned_register (next_frame, FP_REGNUM, &base);
+  id.base = base;
+  return id;
+}
+
+static void
+i386_save_dummy_frame_tos (CORE_ADDR sp)
+{
+  /* We can't use the saved top-of-stack to find the right dummy frame
+     when unwinding, since we can't reconstruct it properly if the
+     dummy frame is the innermost frame.  To circumvent this, we fake
+     a frame pointer here.  */
+
+  regcache_cooked_write_unsigned (current_regcache, FP_REGNUM, sp);
+  generic_save_dummy_frame_tos (sp);
 }
 
 
@@ -1312,7 +1533,13 @@ i386_pe_skip_trampoline_code (CORE_ADDR 
 static int
 i386_pc_in_sigtramp (CORE_ADDR pc, char *name)
 {
-  return (name && strcmp ("_sigtramp", name) == 0);
+  char *pname;
+  if (name)
+    pname = name;
+  else
+    find_pc_partial_function (pc, &pname, NULL, NULL);
+
+  return (name && strcmp ("_sigtramp", pname) == 0);
 }
 
 
@@ -1506,10 +1733,6 @@ i386_gdbarch_init (struct gdbarch_info i
   tdep = XMALLOC (struct gdbarch_tdep);
   gdbarch = gdbarch_alloc (&info, tdep);
 
-  /* NOTE: cagney/2002-12-06: This can be deleted when this arch is
-     ready to unwind the PC first (see frame.c:get_prev_frame()).  */
-  set_gdbarch_deprecated_init_frame_pc (gdbarch, init_frame_pc_default);
-
   /* The i386 default settings don't include the SSE registers.
      FIXME: kettenis/20020614: They do include the FPU registers for
      now, which probably is not quite right.  */
@@ -1591,14 +1814,12 @@ i386_gdbarch_init (struct gdbarch_info i
   set_gdbarch_extract_return_value (gdbarch, i386_extract_return_value);
   set_gdbarch_push_arguments (gdbarch, i386_push_arguments);
   set_gdbarch_push_return_address (gdbarch, i386_push_return_address);
-  set_gdbarch_pop_frame (gdbarch, i386_pop_frame);
   set_gdbarch_store_struct_return (gdbarch, i386_store_struct_return);
   set_gdbarch_store_return_value (gdbarch, i386_store_return_value);
   set_gdbarch_extract_struct_value_address (gdbarch,
 					    i386_extract_struct_value_address);
   set_gdbarch_use_struct_convention (gdbarch, i386_use_struct_convention);
 
-  set_gdbarch_deprecated_frame_init_saved_regs (gdbarch, i386_frame_init_saved_regs);
   set_gdbarch_skip_prologue (gdbarch, i386_skip_prologue);
 
   /* Stack grows downward.  */
@@ -1608,16 +1829,9 @@ i386_gdbarch_init (struct gdbarch_info i
   set_gdbarch_decr_pc_after_break (gdbarch, 1);
   set_gdbarch_function_start_offset (gdbarch, 0);
 
-  /* The following redefines make backtracing through sigtramp work.
-     They manufacture a fake sigtramp frame and obtain the saved pc in
-     sigtramp from the sigcontext structure which is pushed by the
-     kernel on the user stack, along with a pointer to it.  */
-
   set_gdbarch_frame_args_skip (gdbarch, 8);
   set_gdbarch_frameless_function_invocation (gdbarch,
                                            i386_frameless_function_invocation);
-  set_gdbarch_frame_chain (gdbarch, i386_frame_chain);
-  set_gdbarch_frame_saved_pc (gdbarch, i386_frame_saved_pc);
   set_gdbarch_saved_pc_after_call (gdbarch, i386_saved_pc_after_call);
   set_gdbarch_frame_num_args (gdbarch, i386_frame_num_args);
   set_gdbarch_pc_in_sigtramp (gdbarch, i386_pc_in_sigtramp);
@@ -1629,12 +1843,19 @@ i386_gdbarch_init (struct gdbarch_info i
 
   set_gdbarch_print_insn (gdbarch, i386_print_insn);
 
+  set_gdbarch_unwind_dummy_id (gdbarch, i386_unwind_dummy_id);
+  set_gdbarch_save_dummy_frame_tos (gdbarch, i386_save_dummy_frame_tos);
+
+  set_gdbarch_unwind_pc (gdbarch, i386_unwind_pc);
+
   /* Add the i386 register groups.  */
   i386_add_reggroups (gdbarch);
   set_gdbarch_register_reggroup_p (gdbarch, i386_register_reggroup_p);
 
   /* Hook in ABI-specific overrides, if they have been registered.  */
   gdbarch_init_osabi (info, gdbarch);
+
+  frame_unwind_append_predicate (gdbarch, i386_frame_p);
 
   return gdbarch;
 }

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