> Debuggers aren't very good at handling this situation. Because once the control flow jumps to the NULL page, you'd need to find a way to rewind execution history to figure out how it got there.
This is one place where reversible debuggers shine. Try rr[1].
In my experience debuggers handles this fine. Some archs also has a link register (jump and link) which may help finding back. This test is from x86-64 Linux.
/*
gcc -g -Wall -o x x.c
gdb ./x
(gdb) r
(gdb) bt
#0 0x0000000000000000 in ?? ()
#1 0x0000555555554617 in foo () at x.c:6
#2 0x0000555555554628 in main () at x.c:10
(gdb) f 1
#1 0x0000555555554617 in foo () at x.c:6
6 bar();
(gdb) p bar
$1 = (void (*)(void)) 0x0
*/
#include <stddef.h>
void (*bar)(void) = NULL;
void foo() {
bar();
}
int main() {
foo();
}
#include <string.h>
void foo() {
int array[1];
memset(array, 0, 100); /\* Oh no, trash the stack! */
}
int main() {
foo();
}
This gets us:
Program received signal SIGSEGV, Segmentation fault.
0x0000000000000000 in ?? ()
(gdb) bt
#0 0x0000000000000000 in ?? ()
#1 0x0000000000000000 in ?? ()
But with a time travel debugger (I'm using UDB because - disclaimer - it's what I work on. `rr` would work just as well):
Program received signal SIGSEGV, Segmentation fault.
0x0000000000000000 in ?? ()
recording 10,617> backtrace
#0 0x0000000000000000 in ?? ()
#1 0x0000000000000000 in ?? ()
^ Because we returned to NULL we have segfaulted but the stack is also trashed due to the memset. We don't know how we got here.
recording 10,617> reverse-stepi
0x0000000000401146 6 }
99% 10,616> bt
#0 0x0000000000401146 in foo () at smash.c:6
#1 0x0000000000000000 in ?? ()
^ We've stepped back before the return, so we can now see how we got to NULL. Still incomplete stack because it's still trashed.
99% 10,616> reverse-step
5 memset(array, 0, 100); /* Oh no, trash the stack! \*/
99% 10,586> bt
#0 foo () at smash.c:5
#1 0x0000000000401155 in main () at smash.c:9
99% 10,586>
^ We've gone back before the stack smash happened, so now we get the full backtrace.
This is one place where reversible debuggers shine. Try rr[1].
[1] https://rr-project.org/