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

[rfc] Teach i386 prologue reader about _alloca and __main


Hi guys,

This is a new take on solving the issue described here:

http://www.sourceware.org/ml/gdb/2006-11/msg00140.html

On a nutshell, breaking on main is broken on Cygwin, and
all targets where gcc emits a call to __main in main,
right after the prologue.  __main is responsible for calling
the c++ constructors of global objects, and registering the
destructors of the same objects to run at exit.  This call
is inserted on targets that don't have an .init section.

http://sources.redhat.com/ml/gdb-patches/2006-12/msg00140.html

My first aproach tackled it by making i386 skip the prologue
using the debug info, and teaching gcc to put the line marker
that marks the end of the prologue after the __main call.

http://sources.redhat.com/ml/gdb-patches/2006-12/msg00140.html
http://gcc.gnu.org/ml/gcc-patches/2006-12/msg00633.html

Mark didn't like it, because:
"The last time I tried using sals on i386, I simply encountered too
many cases where the line number information couldn't be trusted and
putting a breakpoint on a function that was defenitely called never
hit."
http://sources.redhat.com/ml/gdb-patches/2006-12/msg00375.html

To which Daniel responded:
"Yeah.  That's definitely the biggest risk.
I think the first step, for Pedro's specific problem, should be
to recognize the call to __main as special and skippable.  We can
play with sals later."

The attached patch does that - make __main skippable.  This version
doesn't need any gcc changes.

There are a few complications, though.  On NT, the stack must be grown
page wise, by touching a guard page.  Because of that we often see calls
to _alloca AKA __chkstk (gcc/config/i386/cygwin.asm) in the prologue:

http://cygwin.com/ml/cygwin-developers/2001-10/msg00108.html
http://cygwin.com/ml/cygwin-developers/2001-10/msg00118.html

There is another problem with the prologue analysing, which is visible
on i386 targets using stabs debug info on gcc >= 4.1.0.

eg:
int main (int argc, char **argv)
{

On stabs, the debugger only knows that argc is the first parameter to
the function and that its type is int.  It is up to the debugger
to know how to extract it from the frame.

Gcc >= 4.1 can put code in the prologue to realign the stack pointer.
In that case, the frame base will not be the same as the incoming args
address, so gdb prints garbage for the arguments:

main (argc=2280856, argv=0x61006198) at main.c:8

The prologue analyser already knows about a saved_sp, and that it
can be extracted from %ecx, but on cygwin, %ecx will be clobbered
by the __main call, before we get to user code:

int
main (int argc, char ** argv)
{
 401050:       8d 4c 24 04             lea    0x4(%esp),%ecx
  401054:       83 e4 f0                and    $0xfffffff0,%esp
  401057:       ff 71 fc                pushl  0xfffffffc(%ecx)
  40105a:       55                      push   %ebp
  40105b:       89 e5                   mov    %esp,%ebp
  40105d:       53                      push   %ebx
  40105e:       51                      push   %ecx
  40105f:       b8 20 40 00 00          mov    $0x4020,%eax
  401064:       e8 d7 00 00 00          call   401140 <___chkstk>
  401069:       89 cb                   mov    %ecx,%ebx
  40106b:       e8 60 01 00 00          call   4011d0 <___main>
  char asdf[0x4001];

  printf ("argc %d\n", argc);
  401070:       8b 03                   mov    (%ebx),%eax

Luckilly, %ecx is pushed on the stack, and we already know how to
get at it thanks to i386_analyze_register_saves.

Follows a listing of prologue patterns I see here on i386 Cygwin.

---

#include <stdio.h>

int
main (int argc, char ** argv)
{
  char asdf[0x4001];

  printf ("argc %d\n", argc);
...
}


gcc3.4.4 (cygming special) -O0


   _main:
   .stabn 68,0,8,LM1-_main
   LM1:
           pushl   %ebp               ;frame setup
           movl    %esp, %ebp         ;

           movl    $16440, %eax       ;local space
           call    __alloca           ;

andl $-16, %esp ;alignment

           movl    $0, %eax           ;local space
           addl    $15, %eax          ;
           addl    $15, %eax          ;
           shrl    $4, %eax           ;
           sall    $4, %eax           ;
           movl    %eax, -16412(%ebp) ;
           movl    -16412(%ebp), %eax ;
           call    __alloca           ;
   .stabn 68,0,8,LM2-_main
   LM2:
           call    ___main            ;__main call
   .stabn 68,0,11,LM3-_main
   LM3:

---
gcc3.4.4 (cygming special) -O1

   _main:
   .stabn 68,0,8,LM1-_main
   LM1:
           pushl   %ebp               ;frame setup
           movl    %esp, %ebp         ;

pushl %ebx

           movl    $16420, %eax       ;local space
           call    __alloca           ;

movl 8(%ebp), %ebx

andl $-16, %esp ;alignment

           movl    $16, %eax          ;local space
           call    __alloca
   .stabn 68,0,8,LM2-_main
   LM2:
           call    ___main            ;__main call
   .stabn 68,0,11,LM3-_main
   LM3:

---
gcc3.4.4 (cygming special) -O2

   _main:
   .stabn 68,0,8,LM1-_main
   LM1:
           pushl   %ebp               ;frame setup
           movl    $16420, %eax       ;parameter to __alloca migrated here.
           movl    %esp, %ebp         ;frame setup
           pushl   %ebx
           call    __alloca
   .stabn 68,0,8,LM2-_main
   LM2:
           movl    8(%ebp), %ebx
           andl    $-16, %esp
           movl    $16, %eax
           call    __alloca
           call    ___main
   .stabn 68,0,11,LM3-_main
   LM3:

---
gcc 4.3.0 20070824 -O0

   _main:
           .stabd  46,0,0
           .stabn  68,0,8,LM0-LFBB1
   LM0:
   LFBB1:
           leal    4(%esp), %ecx      ;stack alignment
           andl    $-16, %esp         ;
           pushl   -4(%ecx)           ;

           pushl   %ebp               ;frame setup
           movl    %esp, %ebp         ;

           pushl   %ebx               ;register saves
           pushl   %ecx               ;

           movl    $16416, %eax       ;local space
           call    __alloca           ;

           movl    %ecx, %ebx
           .stabn  68,0,8,LM1-LFBB1
   LM1:
           call    ___main            ;__main call
           .stabn  68,0,11,LM2-LFBB1
   LM2:

gcc 4.3.0 20070824 -O1

   _main:
           .stabd  46,0,0
           .stabn  68,0,8,LM0-LFBB1
   LM0:
   LFBB1:
           leal    4(%esp), %ecx      ;stack alignment
           andl    $-16, %esp         ;
           pushl   -4(%ecx)           ;

           pushl   %ebp               ;frame setup
           movl    %esp, %ebp         ;

           pushl   %esi               ;register saves
           pushl   %ebx               ;register saves
           pushl   %ecx               ;register saves

subl $12, %esp ;local space

           movl    (%ecx), %esi
           movl    4(%ecx), %ebx
           .stabn  68,0,8,LM1-LFBB1
   LM1:
           call    ___main            ;main call
           .stabn  68,0,11,LM2-LFBB1

gcc 4.3.0 20070824 -O2

   _main:
           .stabd  46,0,0
           .stabn  68,0,8,LM0-LFBB1
   LM0:
   LFBB1:
           leal    4(%esp), %ecx      ;stack alignment
           andl    $-16, %esp         ;
           pushl   -4(%ecx)           ;

           pushl   %ebp               ;frame setup
           movl    %esp, %ebp         ;

           pushl   %esi               ;register saves
           pushl   %ebx               ;register saves
           pushl   %ecx               ;register saves

subl $12, %esp ;local space

           .stabn  68,0,8,LM1-LFBB1
   LM1:
           movl    (%ecx), %esi
           movl    4(%ecx), %ebx
           call    ___main            ;main call
           .stabn  68,0,11,LM2-LFBB1
   LM2:


Note that the standard compiler on Cygwin is still gcc3 based, and it is unknown when it will switch to a newer one.

The patch teaches gdb about the -O0 level good behaved prologues,
and where easy makes it understand optimized ones.

The __main call is only expected on targets that gdb knows it should
be there.  A new gdbarch callback is introduced for it, and cygwin
registers it.
The patch intruduces a few minsyms lookups, which I'm not sure we
can do without.  It looks like the risk is high to get it wrong
otherwise.

If left a few things to clean up, as it would make the patch harder
to read.

With this patch, all the run_to_main related failures and
timeouts are gone, both with stock cygwin gcc, and with 4.3 trunk (*),
and we start to see the real failures that are masked currently.

(*) - In the mean time, cygming switched to dwarf debug info by default
in 4.3.  MinGW land has a gcc 4.2 based compiler in testing
with the prospect of becoming the officially supported compiler.

With nosignals on the board file, I get the FAIL rate down to
< 150, and no new problems.   Much better.

It will need a lot more testing and tweaking, but I'd like to get
comments before I spend more time in this.

If this looks too much, the gcc3 patterns support could be
dropped, as if the reader stops mid-line, the rest of the line is
skipped, and that at -O0 lands us in the __main call.  For gcc4, we
need to read the prologue, due to the need to know where the args
are on the stack - but gcc4 prologues are much more consistent.

So...

Comments?

Cheers,
Pedro Alves
2007-10-13  Pedro Alves  <pedro_alves@portugalmail.pt>

	* gdbarch.sh (gdbarch_skip___main_call): New.
	* gdbarch.h, gdbarch.c: Regenerate.

	* i386-tdep.h (i386_skip___main_call): Declare.
	* i386-tdep.c (i386_skip_alloca_call, i386_analyze_alloca2)
	(i386_analyze_alloca): New functions.
	(i386_analyze_frame_setup): Account for register saves before
	stack adjustment, for stack adjustment with _alloca and for stack
	adjustment with andl.  Relax the insns requence.
	(i386___main_skip_insns): New.
	(i386_skip___main_call): New.
	(i386_analyze_prologue): Call i386_analyze_alloca.
	(i386_skip_prologue): Skip calls to __main on targets where gcc
	emits that call.
	(i386_frame_cache): If needed, extract %ecx from the stack.
	(i386_frame_args_address): New.
	(i386_frame_base): Set i386_frame_args_address as args method.
	
	* i386-cygwin-tdep.c (i386_cygwin_init_abi): Register
	i386_skip___main_call as gdbarch_skip___main_call gdbarch
	callback.

---
 gdb/gdbarch.c          |   33 ++++
 gdb/gdbarch.h          |    6 
 gdb/gdbarch.sh         |    1 
 gdb/i386-cygwin-tdep.c |    2 
 gdb/i386-tdep.c        |  341 ++++++++++++++++++++++++++++++++++++++++++++++---
 gdb/i386-tdep.h        |    3 
 6 files changed, 368 insertions(+), 18 deletions(-)

Index: src/gdb/i386-tdep.c
===================================================================
--- src.orig/gdb/i386-tdep.c	2007-10-13 01:51:08.000000000 +0100
+++ src/gdb/i386-tdep.c	2007-10-13 20:32:54.000000000 +0100
@@ -579,6 +579,185 @@ i386_match_insn (CORE_ADDR pc, struct i3
   return NULL;
 }
 
+/* Check that the code pointed to by PC corresponds to a call to
+   __chkstk/_alloca and skip it if so.  Return PC otherwise.  */
+
+static CORE_ADDR
+i386_skip_alloca_call (CORE_ADDR pc, CORE_ADDR limit)
+{
+  gdb_byte op;
+
+  /* If we don't have enough code for a call, return now.  */
+  if (pc + 5 > limit)
+    return pc;
+
+  read_memory_nobpt (pc, &op, 1);
+  if (op == 0xe8)
+    {
+      gdb_byte buf[4];
+      if (target_read_memory (pc + 1, buf, sizeof buf) == 0)
+	{
+	  CORE_ADDR call_dest = pc + 5 + extract_unsigned_integer (buf, 4);
+
+	  struct minimal_symbol *s =
+	    lookup_minimal_symbol_by_pc (call_dest);
+	  if (s != NULL
+	      && SYMBOL_LINKAGE_NAME (s) != NULL
+	      && (strcmp (SYMBOL_LINKAGE_NAME (s), "__chkstk") == 0
+		  || strcmp (SYMBOL_LINKAGE_NAME (s), "_alloca") == 0))
+	    pc += 5;
+	}
+    }
+
+  return pc;
+}
+
+/* Check that the code pointed to by PC corresponds to a call to
+   __chkstk/_alloca and skip it if so.  Return PC otherwise.  */
+
+static CORE_ADDR
+i386_analyze_alloca2 (CORE_ADDR pc, CORE_ADDR limit,
+		      struct i386_frame_cache *cache)
+{
+  /* On gcc3 ,and at -O0, the usual sequence in main is given by
+     setting %eax, storing/retrieving it (this is unoptimized code),
+     and then an _alloca/__chkstk call, which takes it's parameter in
+     %eax:
+
+     eg:
+    mov    $0x0,%eax
+    add    $0xf,%eax
+    add    $0xf,%eax
+    shr    $0x4,%eax
+    shl    $0x4,%eax
+    mov %eax,xxx(%ebp)
+    mov xxx(%ebp),%eax
+    call __alloca
+
+    Also, if local variables take more than a page (4k), the stack
+    adjustment will be done using _alloca, because of the need to
+    touch the guard page on NT.  The sequence will be:
+
+    mov $xxx,%eax
+    call __alloca
+
+    That's valid for main, and for every other function.  At -O1,
+    long sequence above turns into the second sequence (mov,call).
+
+    On gcc3, at -O2 and above, the `mov $xxx,%eax' is often migrated
+    into the frame setup, but we don't support that currently.  Eg:
+
+    push   %ebp
+    mov    $0x10,%eax
+    mov    %esp,%ebp
+    sub    $0x8,%esp
+    and    $0xfffffff0,%esp
+    call   __alloca
+    call   ___main
+
+  */
+
+  gdb_byte op;
+
+  const gdb_byte insns[] = {
+    0xb8, 0x00, 0x00, 0x00, 0x00,    /* mov    $0x0,%eax */
+    0x83, 0xc0, 0x0f,                /* add    $0xf,%eax */
+    0x83, 0xc0, 0x0f,                /* add    $0xf,%eax */
+    0xc1, 0xe8, 0x04,                /* shr    $0x4,%eax */
+    0xc1, 0xe0, 0x04,                /* shl    $0x4,%eax */
+  };
+  gdb_byte buf[sizeof insns];
+
+  if (target_read_memory (pc, buf, sizeof buf) == 0
+      && memcmp (buf, insns, sizeof insns) == 0)
+    {
+      CORE_ADDR pc2 = pc + sizeof insns;
+      CORE_ADDR pos;
+
+      /* mov %eax,xxx(%ebp) */
+      read_memory_nobpt (pc2, &op, 1);
+      if (op == 0x89)
+	{
+	  read_memory_nobpt (pc2 + 1, &op, 1);
+	  switch (op)
+	    {
+	    case 0x45:
+	      pc2 += 3;
+	      break;
+	    case 0x85:
+	      pc2 += 6;
+	      break;
+	    default:
+	      goto other;
+	    }
+	}
+      else
+	goto other;
+
+      /* mov xxx(%ebp),%eax */
+      read_memory_nobpt (pc2, &op, 1);
+      if (op == 0x8b)
+	{
+	  read_memory_nobpt (pc2 + 1, &op, 1);
+	  switch (op)
+	    {
+	    case 0x45:
+	      pc2 += 3;
+	      break;
+	    case 0x85:
+	      pc2 += 6;
+	      break;
+	    default:
+	      goto other;
+	    }
+	}
+
+      pos = i386_skip_alloca_call (pc2, limit);
+      if (pos != pc2)
+	{
+	  cache->locals += 0x10;
+	  pc = pos;
+
+	  if (limit <= pc)
+	    return limit;
+	}
+    }
+
+ other:
+  /* mov $xxx,%eax */
+  read_memory_nobpt (pc, &op, 1);
+  if (op == 0xb8)
+    {
+      CORE_ADDR pos = i386_skip_alloca_call (pc + 5, limit);
+      if (pos != pc + 5)
+	{
+	  ULONGEST eax = read_memory_unsigned_integer (pc + 1, 4);
+	  cache->locals += eax;
+	  pc = pos;
+
+	  if (limit <= pc)
+	    return limit;
+	}
+    }
+
+  return pc;
+}
+
+/* Check that the code pointed to by PC corresponds to a call to
+   __chkstk/_alloca and skip it if so.  Return PC otherwise.  */
+
+static CORE_ADDR
+i386_analyze_alloca (CORE_ADDR pc, CORE_ADDR limit,
+		     struct i386_frame_cache *cache)
+{
+  CORE_ADDR next_pc;
+
+  while ((next_pc = i386_analyze_alloca2 (pc, limit, cache)) != pc)
+    pc = next_pc;
+
+  return pc;
+}
+
 /* Some special instructions that might be migrated by GCC into the
    part of the prologue that sets up the new stack frame.  Because the
    stack frame hasn't been setup yet, no registers have been saved
@@ -634,6 +813,10 @@ struct i386_insn i386_frame_setup_skip_i
   { 0 }
 };
 
+static CORE_ADDR
+i386_analyze_register_saves (CORE_ADDR pc, CORE_ADDR current_pc,
+			     struct i386_frame_cache *cache);
+
 /* Check whether PC points at a code that sets up a new stack frame.
    If so, it updates CACHE and returns the address of the first
    instruction after the sequence that sets up the frame or LIMIT,
@@ -713,7 +896,11 @@ i386_analyze_frame_setup (CORE_ADDR pc, 
       if (limit <= pc)
 	return limit;
 
-      /* Check for stack adjustment 
+      /* Check for registers saves seen before stack adjustment.  Seen
+       on targets that emit a call to __main.  */
+      pc = i386_analyze_register_saves (pc, limit, cache);
+
+      /* Check for stack adjustment
 
 	    subl $XXX, %esp
 
@@ -730,7 +917,7 @@ i386_analyze_frame_setup (CORE_ADDR pc, 
 	  /* `subl' with signed 8-bit immediate (though it wouldn't
 	     make sense to be negative).  */
 	  cache->locals = read_memory_integer (pc + 2, 1);
-	  return pc + 3;
+	  pc += 3;
 	}
       else if (op == 0x81)
 	{
@@ -741,13 +928,26 @@ i386_analyze_frame_setup (CORE_ADDR pc, 
 
 	  /* It is `subl' with a 32-bit immediate.  */
 	  cache->locals = read_memory_integer (pc + 2, 4);
-	  return pc + 6;
-	}
-      else
-	{
-	  /* Some instruction other than `subl'.  */
-	  return pc;
+	  pc += 6;
 	}
+
+      /* _alloca call */
+      pc = i386_analyze_alloca (pc, limit, cache);
+
+      /* and $-16,%esp */
+      {
+	const gdb_byte insns[] = {
+	  0x83, 0xe4, 0xf0                /* and    $0xfffffff0,%esp */
+	};
+	gdb_byte buf[sizeof insns];
+
+	if (target_read_memory (pc, buf, sizeof buf) == 0
+	    && memcmp (buf, insns, sizeof insns) == 0)
+	  {
+	    cache->locals &= -16L;
+	    return pc + 3;
+	  }
+      }
     }
   else if (op == 0xc8)		/* enter */
     {
@@ -758,6 +958,73 @@ i386_analyze_frame_setup (CORE_ADDR pc, 
   return pc;
 }
 
+/* Some instructions that might be migrated by GCC into after the
+   prologue and just before the __main call.  */
+
+struct i386_insn i386___main_skip_insns[] =
+{
+  /* `mov %ecx,%ebx' */
+  { 2, { 0x89, 0xcb }, { 0xff, 0xff } },
+
+  /* `mov (%ecx),%esi' */
+  { 2, { 0x8b, 0x31 }, { 0xff, 0xff } },
+
+  /* `mov  xxx(%ecx),%ebx' */
+  { 3, { 0x8b, 0x59 }, { 0xff, 0xff } },
+
+  { 0 }
+};
+
+
+/* Check that the code pointed to by PC corresponds to a call to
+   __main, skip it if so.  Return PC otherwise.  */
+
+CORE_ADDR
+i386_skip___main_call (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+  gdb_byte op;
+  int skip = 0;
+  CORE_ADDR limit = pc + 20;
+
+  /* Check for some instructions that might be migrated by
+     GCC into before the __main call and skip them.
+
+     Make sure we only skip these instructions if we later see the
+     `call ___main'.  */
+  while (pc + skip < limit)
+    {
+      struct i386_insn *insn;
+      insn = i386_match_insn (pc + skip, i386___main_skip_insns);
+      if (insn == NULL)
+	break;
+
+      skip += insn->len;
+    }
+
+  /* If that's all, return now.  */
+  if (limit <= pc)
+    return limit;
+
+  read_memory_nobpt (pc + skip, &op, 1);
+  if (op == 0xe8)
+    {
+      gdb_byte buf[4];
+      if (target_read_memory (pc + skip + 1, buf, sizeof buf) == 0)
+	{
+	  CORE_ADDR call_dest = pc + skip + 5 + extract_unsigned_integer (buf, 4);
+
+	  struct minimal_symbol *s =
+	    lookup_minimal_symbol_by_pc (call_dest);
+	  if (s != NULL
+	      && SYMBOL_LINKAGE_NAME (s) != NULL
+	      && strcmp (SYMBOL_LINKAGE_NAME (s), "__main") == 0)
+	    pc += skip + 5;
+	}
+    }
+
+  return pc;
+}
+
 /* Check whether PC points at code that saves registers on the stack.
    If so, it updates CACHE and returns the address of the first
    instruction after the register saves or CURRENT_PC, whichever is
@@ -802,16 +1069,18 @@ i386_analyze_register_saves (CORE_ADDR p
    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.
+   'enter' instruction, or by "subl $<size>, %esp", or by a call to
+   _alloca (libgcc/Cygwin).  'enter' has a 16-bit unsigned argument
+   for space to allocate; the 'addl' instruction could have either a
+   signed byte, or 32-bit immediate; the _alloca call is passed the
+   stack space to allocate in %eax.
 
    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.  */
 
@@ -824,7 +1093,10 @@ i386_analyze_prologue (CORE_ADDR pc, COR
   pc = i386_skip_probe (pc);
   pc = i386_analyze_stack_align (pc, current_pc, cache);
   pc = i386_analyze_frame_setup (pc, current_pc, cache);
-  return i386_analyze_register_saves (pc, current_pc, cache);
+  pc = i386_analyze_register_saves (pc, current_pc, cache);
+  pc = i386_analyze_alloca (pc, current_pc, cache);
+
+  return pc;
 }
 
 /* Return PC of first real instruction.  */
@@ -902,6 +1174,17 @@ i386_skip_prologue (CORE_ADDR start_pc)
   if (i386_follow_jump (start_pc) != start_pc)
     pc = i386_follow_jump (pc);
 
+  /* Skip __main calls in main.  */
+  if (gdbarch_skip___main_call_p (current_gdbarch))
+    {
+      struct minimal_symbol *mainf = lookup_minimal_symbol_by_pc (start_pc);
+
+      if (mainf != NULL
+	  && SYMBOL_LINKAGE_NAME (mainf)
+	  && strcmp (SYMBOL_LINKAGE_NAME (mainf), "main") == 0)
+	pc = gdbarch_skip___main_call (current_gdbarch, pc);
+    }
+
   return pc;
 }
 
@@ -956,8 +1239,19 @@ i386_frame_cache (struct frame_info *nex
   if (cache->stack_align)
     {
       /* Saved stack pointer has been saved in %ecx.  */
-      frame_unwind_register (next_frame, I386_ECX_REGNUM, buf);
-      cache->saved_sp = extract_unsigned_integer(buf, 4);
+
+      /* If we are analysing a `main', and this target emits __main
+	 calls, %ecx will be clobbered by __main, and possibly pushed
+	 on the stack.  */
+      if (cache->saved_regs[I386_ECX_REGNUM] != -1)
+	{
+	  CORE_ADDR ecx = cache->base + cache->saved_regs[I386_ECX_REGNUM];
+	  read_memory (ecx, buf, 4);
+	}
+      else
+	frame_unwind_register (next_frame, I386_ECX_REGNUM, buf);
+
+      cache->saved_sp = extract_unsigned_integer (buf, 4);
     }
 
   if (cache->locals < 0)
@@ -1233,12 +1527,23 @@ i386_frame_base_address (struct frame_in
   return cache->base;
 }
 
+static CORE_ADDR
+i386_frame_args_address (struct frame_info *next_frame, void **this_cache)
+{
+  struct i386_frame_cache *cache = i386_frame_cache (next_frame, this_cache);
+
+  if (cache->stack_align)
+    return cache->saved_sp;
+
+  return cache->base;
+}
+
 static const struct frame_base i386_frame_base =
 {
   &i386_frame_unwind,
-  i386_frame_base_address,
-  i386_frame_base_address,
-  i386_frame_base_address
+  i386_frame_base_address, /* base */
+  i386_frame_base_address, /* locals */
+  i386_frame_args_address  /* args */
 };
 
 static struct frame_id
Index: src/gdb/gdbarch.c
===================================================================
--- src.orig/gdb/gdbarch.c	2007-10-12 20:25:22.000000000 +0100
+++ src/gdb/gdbarch.c	2007-10-13 03:52:14.000000000 +0100
@@ -186,6 +186,7 @@ struct gdbarch
   gdbarch_store_return_value_ftype *store_return_value;
   gdbarch_deprecated_use_struct_convention_ftype *deprecated_use_struct_convention;
   gdbarch_skip_prologue_ftype *skip_prologue;
+  gdbarch_skip___main_call_ftype *skip___main_call;
   gdbarch_inner_than_ftype *inner_than;
   gdbarch_breakpoint_from_pc_ftype *breakpoint_from_pc;
   gdbarch_adjust_breakpoint_address_ftype *adjust_breakpoint_address;
@@ -308,6 +309,7 @@ struct gdbarch startup_gdbarch =
   0,  /* store_return_value */
   0,  /* deprecated_use_struct_convention */
   0,  /* skip_prologue */
+  0,  /* skip___main_call */
   0,  /* inner_than */
   0,  /* breakpoint_from_pc */
   0,  /* adjust_breakpoint_address */
@@ -553,6 +555,7 @@ verify_gdbarch (struct gdbarch *current_
   /* Skip verify of deprecated_use_struct_convention, invalid_p == 0 */
   if (current_gdbarch->skip_prologue == 0)
     fprintf_unfiltered (log, "\n\tskip_prologue");
+  /* Skip verify of skip___main_call, has predicate */
   if (current_gdbarch->inner_than == 0)
     fprintf_unfiltered (log, "\n\tinner_than");
   if (current_gdbarch->breakpoint_from_pc == 0)
@@ -966,6 +969,12 @@ gdbarch_dump (struct gdbarch *current_gd
                       "gdbarch_dump: single_step_through_delay = <0x%lx>\n",
                       (long) current_gdbarch->single_step_through_delay);
   fprintf_unfiltered (file,
+                      "gdbarch_dump: gdbarch_skip___main_call_p() = %d\n",
+                      gdbarch_skip___main_call_p (current_gdbarch));
+  fprintf_unfiltered (file,
+                      "gdbarch_dump: skip___main_call = <0x%lx>\n",
+                      (long) current_gdbarch->skip___main_call);
+  fprintf_unfiltered (file,
                       "gdbarch_dump: gdbarch_skip_permanent_breakpoint_p() = %d\n",
                       gdbarch_skip_permanent_breakpoint_p (current_gdbarch));
   fprintf_unfiltered (file,
@@ -2136,6 +2145,30 @@ set_gdbarch_skip_prologue (struct gdbarc
 }
 
 int
+gdbarch_skip___main_call_p (struct gdbarch *gdbarch)
+{
+  gdb_assert (gdbarch != NULL);
+  return gdbarch->skip___main_call != NULL;
+}
+
+CORE_ADDR
+gdbarch_skip___main_call (struct gdbarch *gdbarch, CORE_ADDR ip)
+{
+  gdb_assert (gdbarch != NULL);
+  gdb_assert (gdbarch->skip___main_call != NULL);
+  if (gdbarch_debug >= 2)
+    fprintf_unfiltered (gdb_stdlog, "gdbarch_skip___main_call called\n");
+  return gdbarch->skip___main_call (gdbarch, ip);
+}
+
+void
+set_gdbarch_skip___main_call (struct gdbarch *gdbarch,
+                              gdbarch_skip___main_call_ftype skip___main_call)
+{
+  gdbarch->skip___main_call = skip___main_call;
+}
+
+int
 gdbarch_inner_than (struct gdbarch *gdbarch, CORE_ADDR lhs, CORE_ADDR rhs)
 {
   gdb_assert (gdbarch != NULL);
Index: src/gdb/gdbarch.h
===================================================================
--- src.orig/gdb/gdbarch.h	2007-10-12 20:25:22.000000000 +0100
+++ src/gdb/gdbarch.h	2007-10-13 03:45:06.000000000 +0100
@@ -388,6 +388,12 @@ typedef CORE_ADDR (gdbarch_skip_prologue
 extern CORE_ADDR gdbarch_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR ip);
 extern void set_gdbarch_skip_prologue (struct gdbarch *gdbarch, gdbarch_skip_prologue_ftype *skip_prologue);
 
+extern int gdbarch_skip___main_call_p (struct gdbarch *gdbarch);
+
+typedef CORE_ADDR (gdbarch_skip___main_call_ftype) (struct gdbarch *gdbarch, CORE_ADDR ip);
+extern CORE_ADDR gdbarch_skip___main_call (struct gdbarch *gdbarch, CORE_ADDR ip);
+extern void set_gdbarch_skip___main_call (struct gdbarch *gdbarch, gdbarch_skip___main_call_ftype *skip___main_call);
+
 typedef int (gdbarch_inner_than_ftype) (CORE_ADDR lhs, CORE_ADDR rhs);
 extern int gdbarch_inner_than (struct gdbarch *gdbarch, CORE_ADDR lhs, CORE_ADDR rhs);
 extern void set_gdbarch_inner_than (struct gdbarch *gdbarch, gdbarch_inner_than_ftype *inner_than);
Index: src/gdb/gdbarch.sh
===================================================================
--- src.orig/gdb/gdbarch.sh	2007-10-12 20:25:22.000000000 +0100
+++ src/gdb/gdbarch.sh	2007-10-13 03:42:14.000000000 +0100
@@ -514,6 +514,7 @@ f::void:store_return_value:struct type *
 f::int:deprecated_use_struct_convention:int gcc_p, struct type *value_type:gcc_p, value_type::generic_use_struct_convention::0
 
 f::CORE_ADDR:skip_prologue:CORE_ADDR ip:ip:0:0
+M::CORE_ADDR:skip___main_call:CORE_ADDR ip:ip
 f::int:inner_than:CORE_ADDR lhs, CORE_ADDR rhs:lhs, rhs:0:0
 f::const gdb_byte *:breakpoint_from_pc:CORE_ADDR *pcptr, int *lenptr:pcptr, lenptr::0:
 M::CORE_ADDR:adjust_breakpoint_address:CORE_ADDR bpaddr:bpaddr
Index: src/gdb/i386-cygwin-tdep.c
===================================================================
--- src.orig/gdb/i386-cygwin-tdep.c	2007-09-22 17:08:46.000000000 +0100
+++ src/gdb/i386-cygwin-tdep.c	2007-10-13 03:22:58.000000000 +0100
@@ -225,6 +225,8 @@ i386_cygwin_init_abi (struct gdbarch_inf
 
   set_gdbarch_skip_trampoline_code (gdbarch, i386_cygwin_skip_trampoline_code);
 
+  set_gdbarch_skip___main_call (gdbarch, i386_skip___main_call);
+
   tdep->struct_return = reg_struct_return;
 
   tdep->gregset_reg_offset = i386_win32_gregset_reg_offset;
Index: src/gdb/i386-tdep.h
===================================================================
--- src.orig/gdb/i386-tdep.h	2007-09-22 17:08:46.000000000 +0100
+++ src/gdb/i386-tdep.h	2007-10-13 03:29:48.000000000 +0100
@@ -167,6 +167,9 @@ extern struct type *i386_sse_type (struc
 /* Functions exported from i386-tdep.c.  */
 extern CORE_ADDR i386_pe_skip_trampoline_code (CORE_ADDR pc, char *name);
 
+extern CORE_ADDR i386_skip___main_call (struct gdbarch *gdbarch, CORE_ADDR pc);
+
+
 /* Return the name of register REGNUM.  */
 extern char const *i386_register_name (int regnum);
 

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