Skip to content

Program Debugging

View as Markdown

The thru-replay tool can be used to replay transactions run on Thru, and supports debugging with GDB. This can help you debug crashes and other issues in your program.

Step 1: Build and run with debug information

Section titled “Step 1: Build and run with debug information”

To make it easier to debug programs, you should build your program with debug information.

In C and C++, you can do this with the SDK_EXTRAS environment variable:

Terminal window
SDK_EXTRAS=debug make

In addition to the .bin file, you’ll find a file at target/thruvm/bin/<program-name>.elf that contains the program’s debug information. Make a note of this file for later use.

After this, upload your program in debug mode to the network, and run a transaction.

Step 2: Prepare the command to run with GDB

Section titled “Step 2: Prepare the command to run with GDB”

Next, you’ll need to gather all the information to replay your program. You’ll need:

  • The transaction signature. It will look something like this:
    tsX2EQZzPxVgI23KmdAByeVj-yZ9JE-46q_AhjURj0vRnHdMRP3at6H_dVXDFdUtUwnW_ICnLnk0ROJWWdTIWbDh1P
  • For each program in your transaction, you’ll need the program’s address as well as the path to the program’s debug information. For instance:
    tafhdJHH_OVQYN4-Cimt7Y1XclSytf9Ox_iuetV8CKmz=./build/thruvm/bin/tn_token_program_rust.elf
    If you don’t have the debug information for a program, you can skip it. However, you won’t be able to view the source information for that program.

Now you can run the command to replay the transaction with GDB. You’ll need to pass the transaction signature, and for each program in your transaction, you’ll need to pass the program’s address and the path to the program’s debug information.

Terminal window
thru-replay --gdb \
--signature $transaction-signature \
--elf $program-address-1=$program-debug-info-path-1 \
--elf $program-address-2=$program-debug-info-path-2 ...

For example:

Terminal window
thru-replay --gdb \
--signature tsX2EQZzPxVgI23KmdAByeVj-yZ9JE-46q_AhjURj0vRnHdMRP3at6H_dVXDFdUtUwnW_ICnLnk0ROJWWdTIWbDh1P \
--elf tafhdJHH_OVQYN4-Cimt7Y1XclSytf9Ox_iuetV8CKmz=./build/thruvm/bin/tn_token_program_rust.elf

You should see some output like this. You’ll be in an interactive GDB session.

Terminal window
Fetching transaction tsCRsKwMAupg5jUbus7GSeN8XgUS_lafAIo6YPUCfJW_zIYTgNJ5xCufxghWfiL1LGAPBWsCWHFHa0srws70WEAx38...
Fetching 3 account states at slot 66 (pre-transaction)...
Fetching state roots ending at slot 66...
--log-path not specified; using autogenerated path
Log at "/tmp/fd-0.0.0_3872496_user_machine-1_2025_12_16_17_38_45_883488412_GMT+00"
Note: RW account ta1kDh1kmoJuRkoBChLLRk-ZOvzAHFNWNrK1iDCBJToaxR not in pre-tx state - will be created by transaction
Starting debug server on port 9001...
GDB connected!
add symbol table from file "./build/thruvm/bin/tn_token_program_rust.elf" at
.text_addr = 0x3000000
Reading symbols from ./build/thruvm/bin/tn_token_program_rust.elf...
add symbol table from file "./build/thruvm/bin/tn_token_program_rust.elf" at
.text_addr = 0x30001000000
Reading symbols from ./build/thruvm/bin/tn_token_program_rust.elf...
Remote debugging using localhost:9001
warning: No executable has been specified and target does not support
determining executable automatically. Try using the "file" command.
0x0000030001000000 in _start ()
(gdb)

You can debug the program as you would normally do with GDB:

Terminal window
(gdb) break start
Breakpoint 1 at 0x300006c: start. (2 locations)
(gdb) c
Continuing.
Breakpoint 1.2, token_program::start (instr_data=0x0 $core::intrinsics::cold_path, instr_data_sz=0)
at examples/token_program/main.rs:20
20 #[entry(stack_size = 8192)]