0

I am calling main() inside main(), recursively for 10 times. Now while debugging using gdb (bt/backtrace), I don't see multiple frames for main(). Why?

#include<stdio.h>

int main(){

     static int i;
     int num=100;

     if(i>10)
       return 0;
     else {
       i++;
       num++;
       main();
       printf("\n%d",num); 
     }
 }
ArjunShankar
  • 23,020
  • 5
  • 61
  • 83

3 Answers3

4

This is documented behaviour of gdb, and it is (supposed to be) configurable.

When I compile your code with gcc 4.7.2 (-O3), I get the following assembly:

_main:
LFB1:
        movl    _i.2134(%rip), %eax
        cmpl    $10, %eax
        jle     L6
        xorl    %eax, %eax
        ret
L6:
        addl    $1, %eax
        pushq   %rdx
LCFI0:
        movl    %eax, _i.2134(%rip)
        xorl    %eax, %eax
        call    _main                    ; <=== recursive call
        popq    %rcx
LCFI1:
        movl    $101, %esi
        xorl    %eax, %eax
        leaq    LC0(%rip), %rdi
        jmp     _printf
LFE1:

This refutes the hypothesis that the recursive call is optimized away.

Now, if I load the binary into gdb and set a breakpoint on main(), it gets hit repeatedly. When I examine the registers, %rsp is getting decremented with each call, so there are clearly stack frames associated with each main().

Nonetheless, bt only shows a single frame:

(gdb) bt
#0  0x0000000100000f50 in main ()

(In this case, I know there are three main() frames and not just one.)

I therefore conclude that this has something to do with gdb itself.

Upon further investigation, it turns out that this behaviour is documented:

Most programs have a standard user entry point—a place where system libraries and startup code transition into user code. For C this is main. When gdb finds the entry function in a backtrace it will terminate the backtrace, to avoid tracing into highly system-specific (and generally uninteresting) code.

When I set the following in gdb:

set backtrace past-main on
set backtrace past-entry on

it starts showing two main() frames. For some reason, it's still not going any deeper.

NPE
  • 486,780
  • 108
  • 951
  • 1,012
2

Your question has nothing to do with the fact that you use main for that.

A simple recursive program as you finally care to show us in a comment can easily be optimized by the compiler by not doing recursion at all. In your case it is even more simple that usual, since you have a predefined recursion depth of 10. This can easily be unrolled by the compiler to static code.

Jens Gustedt
  • 76,821
  • 6
  • 102
  • 177
  • I tried by disabling the optimization during compilation but again one frame only during debugging. – Arjun Prasad Dec 19 '12 at 10:13
  • 1
    hum .. gdb disass does show a `callq 0x40050c
    ` instruction. Could it be that gdb purposely hide function calls above `main()` ?
    – Ben Dec 19 '12 at 10:14
  • 1
    Have a look in the assembler, for gcc e.g this is option `-S` instead of `-c`. And first of all use another function name for recursion to see if it is coming from there. – Jens Gustedt Dec 19 '12 at 10:15
  • By default gdb hide the fun call before main but if we want we can make gdb to show those fun call as well. But here in this case i want to see multiple main() frame not fun who called main(). – Arjun Prasad Dec 19 '12 at 10:18
  • 1
    It's possible that gdb's stack unwinding code stops once it found the first frame within `main()`. Try moving your code into another function, disable optimization and see whether that fixes it. – Martin Baulig Dec 19 '12 at 10:20
  • @MartinBaulig's guess seems right. For me, backtrace always stops at `main`, even when that particular frame of `main` is called by a function *other than* `main`. – ArjunShankar Dec 19 '12 at 10:23
  • If i move my code to other function it will sure work. Why its not working in current case as per gdb manual(call stack) it should work. – Arjun Prasad Dec 19 '12 at 10:24
1
Here is the Answer for my own Question.
(gdb) set backtrace past-main on
(gdb) b main
Breakpoint 1 at 0x4004b0: file recursion.c, line 5.
(gdb) run
Starting program: /nobackup/arjprasa/C/gdb/a.out

Breakpoint 1, main () at recursion.c:5
5               int num=100;
(gdb) c
Continuing.

Breakpoint 1, main () at recursion.c:5
5               int num=100;
(gdb) bt
#0  main () at recursion.c:5
#1  0x00000000004004df in main () at recursion.c:12
#2  0x00000034d091c4cb in __libc_start_main () from /lib64/tls/libc.so.6
#3  0x000000000040041a in _start ()
(gdb) c
Continuing.

Breakpoint 1, main () at recursion.c:5
5               int num=100;
(gdb) bt
#0  main () at recursion.c:5
#1  0x00000000004004df in main () at recursion.c:12
#2  0x00000000004004df in main () at recursion.c:12
#3  0x00000034d091c4cb in __libc_start_main () from /lib64/tls/libc.so.6
#4  0x000000000040041a in _start ()
(gdb) c
Continuing.

Breakpoint 1, main () at recursion.c:5
5               int num=100;
(gdb) bt
#0  main () at recursion.c:5
#1  0x00000000004004df in main () at recursion.c:12
#2  0x00000000004004df in main () at recursion.c:12
#3  0x00000000004004df in main () at recursion.c:12
#4  0x00000034d091c4cb in __libc_start_main () from /lib64/tls/libc.so.6
#5  0x000000000040041a in _start ()
(gdb)