1.4.7 Single-stepping through the generated code

It’s possible to debug the generated code. To do this we need to both:

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.

Note: Turning on optimizations may lead to unpredictable results when stepping through the generated code: the execution may appear to “jump around” the source code. This is analogous to turning up the optimization level in a regular compiler.