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.
-
Try running your code through valgrind. If you're mismanaging memory it will tell you where. – dbush Jun 14 '20 at 19:57
-
The fact that the function calls itself is the point of a recursive function. I do not get your problem. – Yunnosch Jun 14 '20 at 20:12
-
1You might have some stack overflow. Show an [mre] in your question – Basile Starynkevitch Jun 14 '20 at 20:22
-
GDB should catch a stackoverflow and automatically pause the program for you. – PiRocks Jun 14 '20 at 20:24
-
Try looking at [this](https://stackoverflow.com/questions/310974/what-is-tail-call-optimization). – chriptus13 Jun 14 '20 at 21:38
1 Answers
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.

- 199,314
- 34
- 295
- 362