You are probably not going to like this - all I can say in its favour is that it works for me, and I have similar but not identical requirements: I am writing a compiler/transpiler for a 1970's Algol-like language which uses C as it's output and then compiles the C so that as far as the user is concerned, they're generally not aware of C being involved, so although you might call it a transpiler, it's effectively a compiler that uses C as it's intermediate code. The language being compiled has a history of providing good diagnostics and a full backtrace in the original native compilers. I've been able to find gcc compiler flags and libraries etc that allow me to trap most of the runtime errors that the original compilers did (although with one glaring exception - unassigned variable trapping). When a runtime error occurs (eg arithmetic overflow, divide by zero, array index out of bounds, etc) the original compilers output a backtrace to the console listing all variables in the stack frames of every active procedure call. I struggled to get this effect in C, but eventually did so with what can only be described as a hack... When the program is invoked, the wrapper that supplies the C "main" looks at its argv, and if a special option is not present, it restarts itself under gdb with an altered argv containing both gdb options and the 'magic' option string for the program itself. This restarted version then hides those strings from the user's code by restoring the original arguments before calling the main block of the code written in our language. When an error occurs (as long as it is not one explicitly trapped within the program by user code), it exits to gdb which prints the required backtrace.
Keys lines of code in the startup sequence include:
if ((argc >= 1) && (strcmp(origargv[argc-1], "--restarting-under-gdb")) != 0) {
// initial invocation
// the "--restarting-under-gdb" option is how the copy running under gdb knows
// not to start another gdb process.
and
char *gdb [] = {
"/usr/bin/gdb", "-q", "-batch", "-nx", "-nh", "-return-child-result",
"-ex", "run",
"-ex", "bt full",
"--args"
};
The original arguments are appended to the gdb options above. That should be enough of a hint for you to do something similar for your own system.
I did look at other library-supported backtrace options (eg libbacktrace,
https://codingrelic.geekhold.com/2010/09/gcc-function-instrumentation.html, etc) but they only output the procedure call stack, not the local variables. However if anyone knows of any cleaner mechanism to get a similar effect, do please let us know. The main downside to this is that the variables are printed in C syntax, not the syntax of the language the user writes in. And (until I add suitable #line directives on every generated line of C :-() the backtrace lists the C source file and line numbers.
G
PS The gcc compile options I use are:
GCCOPTS=" -Wall -Wno-return-type -Wno-comment -g -fsanitize=undefined
-fsanitize-undefined-trap-on-error -fno-sanitize-recover=all -frecord-gcc-switches
-fsanitize=float-divide-by-zero -fsanitize=float-cast-overflow -ftrapv
-grecord-gcc-switches -O0 -ggdb3 "