-2

I am trying to implement a recursive tree function and I am getting a segfault because the function calls itself over and I would like to see what state my program is at the end.

Employed Russian
  • 199,314
  • 34
  • 295
  • 362

1 Answers1

2

I would like to see what state my program is at the end.

Run the program under GDB, and it will stop (when your program exhausts its stack) and show you the state at the end.

Example:

void fn(int j)
{
  char buf[1024];  // consume some stack space.
  buf[0] = 'a';
  fn(j - buf[0]);  // bad recursion -- should have checked for j - 'a' > 0
}

int main()
{
  fn(10000);
  return 0;
}
gcc -g t.c && gdb -q ./a.out
(gdb) run
Starting program: /tmp/a.out 

Program received signal SIGSEGV, Segmentation fault.
0x0000555555555130 in fn (j=<error reading variable: Cannot access memory at address 0x7fffff7fef8c>) at t.c:2
2       {
(gdb) bt 10
#0  0x0000555555555130 in fn (j=<error reading variable: Cannot access memory at address 0x7fffff7fef8c>) at t.c:2
#1  0x0000555555555158 in fn (j=-759889) at t.c:5
#2  0x0000555555555158 in fn (j=-759792) at t.c:5
#3  0x0000555555555158 in fn (j=-759695) at t.c:5
#4  0x0000555555555158 in fn (j=-759598) at t.c:5
#5  0x0000555555555158 in fn (j=-759501) at t.c:5
#6  0x0000555555555158 in fn (j=-759404) at t.c:5
#7  0x0000555555555158 in fn (j=-759307) at t.c:5
#8  0x0000555555555158 in fn (j=-759210) at t.c:5
#9  0x0000555555555158 in fn (j=-759113) at t.c:5
(More stack frames follow...)

What you see here is the state of the program at the end, i.e. exactly what you asked for in the body of your question, but not in the title (it's a bad form to ask different questions in the body and the title).

Is there a way to break a program after it reaches a certain number of frames?

There is not, but there are various approximations.

For the case of the test program above, the answer is trivial. Since fn keeps calling itself, you can stop on Nth call. E.g. if you want to stop when recursion reaches 100 frames, do this:

(gdb) b fn
Breakpoint 1 at 0x1136: file t.c, line 4.
(gdb) ign 1 100
Will ignore next 100 crossings of breakpoint 1.
(gdb) run
Starting program: /tmp/a.out 

Breakpoint 1, fn (j=300) at t.c:4
4         buf[0] = 'a';
(gdb) bt
#0  fn (j=300) at t.c:4
#1  0x0000555555555158 in fn (j=397) at t.c:5
#2  0x0000555555555158 in fn (j=494) at t.c:5
#3  0x0000555555555158 in fn (j=591) at t.c:5
#4  0x0000555555555158 in fn (j=688) at t.c:5
...
#99 0x0000555555555158 in fn (j=9903) at t.c:5
#100 0x0000555555555158 in fn (j=10000) at t.c:5
#101 0x0000555555555169 in main () at t.c:10

Things get more complicated when fn calls itself indirectly (but if the cycle is of fixed length K, then just divide N by K).

If the cycle is not of fixed length, or if some of the calls return (i.e. not every call recurs), then getting to N levels deep is bit more complicated. The easiest way to do that is to modify the program to keep recursion count in a global. Then you can simply set a conditional watch point. Example:

int recursion_count;

void fn(int j)
{
  char buf[1024];  // consume some stack space.

  recursion_count += 1;
  buf[0] = 'a';
  fn(j - buf[0]);  // bad recursion -- should have checked for j - 'a' > 0
  recursion_count -= 1;
}

int main()
{
  fn(10000);
  return 0;
}
gcc -g t.c && gdb -q ./a.out
(gdb) start
Temporary breakpoint 1 at 0x55555555517d: file t.c, line 15.
Starting program: /tmp/a.out 

Temporary breakpoint 1, main () at t.c:15
15        fn(10000);
(gdb) p recursion_count
$1 = 0
(gdb) watch recursion_count
Hardware watchpoint 2: recursion_count
(gdb) cond 2 recursion_count == 100
(gdb) c
Continuing.

Hardware watchpoint 2: recursion_count

Old value = 99
New value = 100
fn (j=397) at t.c:8
8         buf[0] = 'a';
(gdb) bt 
#0  fn (j=397) at t.c:8
#1  0x0000555555555167 in fn (j=494) at t.c:9
#2  0x0000555555555167 in fn (j=591) at t.c:9
#3  0x0000555555555167 in fn (j=688) at t.c:9
...
#97 0x0000555555555167 in fn (j=9806) at t.c:9
#98 0x0000555555555167 in fn (j=9903) at t.c:9
#99 0x0000555555555167 in fn (j=10000) at t.c:9
#100 0x0000555555555187 in main () at t.c:15

Voila.

Employed Russian
  • 199,314
  • 34
  • 295
  • 362