It’s possible to debug the generated code. To do this we need to both:
- Set up source code locations for our statements, so that we can meaningfully step through the code. We did this above by calling gccjit;;context;;new_location() and using the results.
- Enable the generation of debugging information, by setting GCC_JIT_BOOL_OPTION_DEBUGINFO on the gccjit;;context via gccjit;;context;;set_bool_option():
ctxt.set_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO, 1);
Having done this, we can put a breakpoint on the generated function:
$ gdb --args ./toyvm factorial.toy 10 (gdb) break factorial Function "factorial" not defined. Make breakpoint pending on future shared library load? (y or [n]) y Breakpoint 1 (factorial) pending. (gdb) run Breakpoint 1, factorial (arg=10) at factorial.toy:14 14 DUP
We’ve set up location information, which references factorial.toy
.
This allows us to use e.g. list
to see where we are in the script:
(gdb) list 9 10 # Initial state: 11 # stack: [arg] 12 13 # 0: 14 DUP 15 # stack: [arg, arg] 16 17 # 1: 18 PUSH_CONST 2
and to step through the function, examining the data:
(gdb) n 18 PUSH_CONST 2 (gdb) n 22 BINARY_COMPARE_LT (gdb) print stack $5 = {10, 10, 2, 0, -7152, 32767, 0, 0} (gdb) print stack_depth $6 = 3
You’ll see that the parts of the stack
array that haven’t been
touched yet are uninitialized.
|