[rfc] Teach i386 prologue reader about _alloca and __main

Pedro Alves pedro_alves@portugalmail.pt
Sat Oct 13 20:26:00 GMT 2007


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
-------------- next part --------------
A non-text attachment was scrubbed...
Name: skip_main.diff
Type: text/x-diff
Size: 19401 bytes
Desc: not available
URL: <http://sourceware.org/pipermail/gdb-patches/attachments/20071013/cd486dcb/attachment.bin>


More information about the Gdb-patches mailing list