a backtracing problem with gdb

Kevin Nomura nomura@netapp.com
Tue Apr 30 03:18:00 GMT 2002


I hit a corner case where the gdb backtrace is inaccurate.  It seems
like a case that's hard for the debugger to detect, so I thought to
ask here first if a codegen workaround would make sense.

On x86, the epilogue's frame pointer restore (pop %ebp) can float up
past an instruction that might fault.  If this faults, the backtrace
gets confused because it starts with the parent's frame pointer.
The symptom is a missing stack frame above where the fault occurred
in gdb's backtrace.

gdb seems to work around this scenario by marking some procedures
FRAMELESS, I guess by disassembly inspection of the prologue and
isolating itself from the unpredictable value of %ebp by using %esp
instead.  Looks like this pattern match is defeated if the prologue
starts with "push %ebp / mov %esp, %ebp", gdb thinks the procedure
has a real frame.  Here is the fragment from my corner case using
gcc 3.0.4 (gcc 2.96 as shipped with redhat 7.1 does a similar thing):

[noname]$ cat ebp.c
typedef struct {
        int junk[2004];
        int i:3;
} mytype;


foo(mytype *p) {
        return ((  p->i  ) == 0 || (  p->i  ) == 1)  ? 1  : 0 ;
}

[noname]$ /usr/local/build/compilers/gcc-3.0.4/bin/gcc --no-inline -O2 ebp.c -march=i686 -S

[noname]$ cat ebp.s
        .file   "ebp.c"
        .text
        .align 16
.globl foo
        .type   foo,@function
foo:
        pushl   %ebp
        movl    %esp, %ebp
        movl    8(%ebp), %eax
        popl    %ebp              # early frame restore
        movzbl  8016(%eax), %eax  # this load faults, now ebp is wrong for backtrace
        andb    $7, %al
        cmpb    $1, %al
        setbe   %al
        movzbl  %al, %eax
        ret


The combination of a standard-looking prologue looks standard and
a hoisted epilogue loses the parent frame in gdb's backtrace.  I've
tried gdbs through the just-released 5.2 with the same result.

So here is the gcc question.  The motion of "mov %ebp" seems to happen
in very limited cases, so would it hurt performance to stop it from
moving, across faulting instructions at least?  Or maybe I'm just missing
a switch that would suppress this particular behavior.  

Otherwise if gdb needs to handle this, could someone suggest what added
pattern matches or debug info could make backtrace more robust?  Thanks
for any suggestions.

Kevin



More information about the Gcc-help mailing list