Execution tracing in Renode

Renode has complete awareness of the internal state of all simulated components and can use this information to trace the execution of unmodified binaries without any behavioral changes to the simulation.

Note

Some logging features may significantly impact the simulation’s performance, but they do not affect the execution itself.

Note

Commands listed below assume that you have a platform loaded, a CPU node named cpu and that the using sysbus command was executed. For more details, see documentation chapters on Renode Script syntax and Accessing and manipulating peripherals.

Logging executed function names

Renode can log the names of functions currently executed by the guest application. This requires you to use the sysbus LoadELF @path/to/elf command to load your application or sysbus LoadSymbolsFrom @path/to/elf if you prefer executing a binary or a hex file. Function name logging can be enabled using:

cpu LogFunctionNames true

You can disable function name logging using:

cpu LogFunctionNames false

Note

You can also add another true at the end of this command to remove duplicate function names from subsequent code blocks and achieve better overall performance.

To filter function names based on a prefix, add the prefix as a string at the end of the function:

cpu LogFunctionNames true "uart"

To use more than one prefix and log functions that start with either of these two prefixes, simply separate them with a space:

cpu LogFunctionNames true "uart irq"

Note

Renode will try to demangle C++ function names. It will also use the names stored in the ELF file.

If you want to learn more about logging executed function names in Renode, visit the Using the logger chapter

Logging peripheral accesses

While the information about the executed functions gives you an overall understanding of the execution, it is often beneficial to know the additional context and understand why the application took a specific path.

To provide this additional context, Renode can log access to peripherals. This feature allows you to see how your program uses or doesn’t use specific parts of the SoC.

You can enable this feature by using the following:

sysbus LogPeripheralAccess <peripheral-name> true

Note

In most cases, your peripheral names need a prefix sysbus like sysbus.uart0. You can omit this prefix if you’re using the using sysbus command in your script.

The logs contain:

  • the name of the peripheral

  • current value of the program counter

  • type and width of the access

  • offset of the access (relative to the peripheral’s base address) and the name of the register that this offset maps to

  • the value that was either loaded to or returned from the register

You can also log accesses to all peripherals connected to the system bus:

sysbus LogAllPeripheralsAccess true

You can disable both peripheral access logging commands by providing false instead of true as the last parameter:

sysbus LogAllPeripheralsAccess false

If you want to learn more about logging peripheral accesses in Renode, visit the Using the logger chapter

Execution tracing

In Renode, you can see what the CPU does at any given time without changing the code or using specialized hardware. To enable execution tracing, use:

cpu CreateExecutionTracing "tracer_name" @path-to-file <mode>

Additionally, you can use the tracer to track memory accesses. To do so, type:

tracer_name TrackMemoryAccesses

Similarly, to track vector configuration for the RISC-V architecture, use:

tracer_name TrackVectorConfiguration

mode can be one of the following values:

  • PC - this mode saves all program counter values. Example:

0x20400000
0x20400004
0x20400008
0x2040000c
0x20401bc4
0x20401bc8
...
  • Opcode - this mode saves all executed opcodes. Example:

0x0297
0x1028293
0x30529073
0x3B90106F
0x5FC00297
0x88C28293
...
  • PCAndOpcode - this mode saves program counter values and the corresponding opcode that was executed. Example:

0x20400000: 0x0297
0x20400004: 0x1028293
0x20400008: 0x30529073
0x2040000c: 0x3B90106F
0x20401bc4: 0x5FC00297
0x20401bc8: 0x88C28293
...
  • Disassembly - in addition to the value of the program counter and the corresponding opcode, this mode uses a built-in LLVM-based disassembler to convert opcodes to human-readable instruction names with all of the used arguments. The output also includes the name of the symbol that this entry belongs to. Example:

0x20400000:   00000297  auipc t0, 0           [vinit (entry)]
0x20400004:   01028293  addi t0, t0, 16       [vinit+0x4 (guessed)]
0x20400008:   30529073  csrw mtvec, t0        [vinit+0x8 (guessed)]
0x2040000c:   3b90106f  j 7096                [vinit+0xC (guessed)]
0x20401bc4:   5fc00297  auipc t0, 392192      [__start (entry)]
0x20401bc8:   88c28293  addi t0, t0, -1908    [__start+0x4 (guessed)]
...

You can save the output from the PC, Opcode, and PCAndOpcode modes to a binary format that can optionally be compressed. This format is faster to encode and produces smaller output files. To save to a binary file, use the following:

cpu CreateExecutionTracing "tracer_name" @path-to-file <mode> true

If you also want to compress the output, you can add another true to this command:

cpu CreateExecutionTracing "tracer_name" @path-to-file <mode> true true

You can view the content of the binary file by using a script bundled with Renode. It can be invoked by running this command in your shell:

python3 <renode>/tools/execution_tracer/execution_tracer_reader.py inspect path-to-dump-file

This command will print the file’s text content to the standard output.

To disable execution tracing, simply use:

cpu DisableExecutionTracing

Usage of gathered data

Certain tools shipped with Renode can use the obtained execution traces for post-mortem analysis of a program’s execution. These include:

Specialized uses of execution tracing

In addition to generic program execution tracing, Renode also has more specialized tracing-related facilities, such as:

Refer to the Execution metrics, profiling and opcode counting section for more details.


Last update: 2025-03-06