Intel® Simics® Simulator for Intel® FPGAs: User Guide

ID 784383
Date 4/01/2024

A newer version of this document is available. Customers should click here to go to the newest version.

Document Table of Contents

6.1. Intel® Simics® Debugger and Debug Context

Intel® Simics® tool is a full-system simulator that can run target software at any different level going from bootloaders to OS applications. When you want to debug a OS application, it is possible that there are some other pieces of software running in the background such as other software threads, other applications or kernel tasks. To limit the scope of your debugging to just one process (or task, or kernel thread, and so on), you use an appropriate debug context. Each debug context corresponds to some part of the target system. It can be a processor or the memory space of a processor, or a software abstraction like a process or thread. There are also debug contexts that group other contexts.

Currently, the debug context supported must be associated to the specific processor that is running the software to debug. In this case, you must be cautious as the debugger does not track when the operating system on the target switches between different processes or tasks.

To perform source-level debugging, you need to request the debugger about the binaries (executable files and shared libraries) that the component of the system you want to debug is using. The debugger presents the target system as a set of debug contexts. Each debug context represents one interesting part of the system. It can be a software concept (like a process, a thread or a task), or a processor core or the physical memory space of a processor. To provide context, there are also debug contexts that provide grouping like a machine or a group of all user-space programs on a Linux system.

When you interact with debug contexts directly, you usually interact with a context running code, such as a thread or a processor core. The debug context allows you to step through the code and to inspect variables scoped to the current location in the code.

By default, Intel® Simics® simulator does not activate the debugger; global stepping and other commands act directly over the current processor selected, and not to a specific debug context. There are two ways to activate the debugger and get access to debug contexts.

  1. To enable the debugger with the enable-debugger command. This makes Intel® Simics® debugger to track debug contexts and automatically select an initial debug context if possible (current core selected).
  2. To explicitly select a debug context with the debug-context command. This sets a current debug context and also activates the debugger.

You can disable the debugger with the disable-debugger command and Intel® Simics® simulator returns to the default behavior of the global stepping commands.

Once Intel® Simics® debugger tracks debug contexts, it updates the current debug context to the currently running thread every time the simulation stops. The current debug context is the debug context that all global step and inspection commands interacts with. This means that when you have hit a breakpoint or complete a step, you can use the global commands to investigate the state of your software and to continue stepping through the code.

Once you have a debug context and symbols file loaded (described later in this document), you can use it to step through the code and inspect its state. When the debugger is enabled, and you have a current debug context, you can use the global versions of these commands. The commands are also implemented directly by the debug context, which means that you can use them on debug contexts different to the current debug context. You can do this even if the debugger is disabled.

There are some commands that can only operate if a context is defined. Some examples of these commands are the following:

Table 17.   Intel® Simics® Debugger and Debug Context Commands
Command Description
step-line Run forward until the debug context reaches another line in the program.
next-line Run forward until the debug context reaches another line but skip over calls made by the current function.
finish-function Run forward until the current function returns.
next-instruction Run forward until the debug context reaches another instruction but skip over calls made by the current function.
list List source code.

An active thread also has a stack of call frames or just frames. Intel® Simics® simulator provides commands to show the stack and to select which frame other commands must use to find local variables. The stack goes from the innermost frame up towards the outermost frame. The current stack frame is reset to the innermost frame every time Intel® Simics® simulator stops executing. Some of the commands that operate over call frames are the following. To use these commands, you must have a context defined.

Table 18.  Commands to Show the Stack and Select Frame
Command Description
stack-trace Shows the stack.
frame Selects the frame with the given number. The currently executing function has frame 0, its caller has frame 1, and so on.
up Selects the frame with the next higher number.
down Selects the frame with the next lower number.

The following capture shows an example of how you can set a debug context and use some of the instructions described above:

# Intel Simics simulator CLI  

simics> list-debug-contexts 
Fully Qualified Name                        

simics> enable-debugger
Debugger enabled.

simics> debug-context
dbg0 (the arm-cortex-a55 system.board.fpga.soc_inst.hps_subsys.agilex_hps.core[0])
Now debugging the arm-cortex-a55 system.board.fpga.soc_inst.hps_subsys.agilex_hps.core[0]
                                                   str w0, [x18, #340]
simics> next-instruction
                                                   cmp x0, x19

simics> debug-context object = "system.board.fpga.soc_inst.hps_subsys.agilex_hps.core[1]"
dbg5 (the arm-cortex-a55 system.board.fpga.soc_inst.hps_subsys.agilex_hps.core[1])
Now debugging the arm-cortex-a55 system.board.fpga.soc_inst.hps_subsys.agilex_hps.core[1]
                                                   b 0x28
simics> debug-context
dbg5 (the arm-cortex-a55 system.board.fpga.soc_inst.hps_subsys.agilex_hps.core[1])
simics> step-line
                                                  bl 0x80000108
simics> next-instruction
                                                  adr x0, 0x8000a800
simics> step-line
                                                  msr vbar_el3, x0
simics>  debug-context dbg0
dbg0 (the arm-cortex-a55 system.board.fpga.soc_inst.hps_subsys.agilex_hps.core[0])
Now debugging the arm-cortex-a55 system.board.fpga.soc_inst.hps_subsys.agilex_hps.core[0]
                                                  msr cptr_el3, x19
simics> stack-trace 
#0 0x80008b30 in ??()
#1 0xffff800008026a34 in ??()
#2 0xffff800008d9d768 in ??()

In the previous example, the following operations are executed:

  • Initially, the debug-context command is called and when doing this, the command response indicates that there is not any debug context selected.
  • The list-debug-contexts command is called and shows possible debug contexts that you can select, including CPU cores and memories.
  • The debugger gets enabled using the enable-debugger command. When doing this, the default debug context is selected which corresponds to the current core selected, which is core[0]. This debug context is referred to as dbg0.
  • The next-instruction command is used to advance in the simulation using core[0] as debug target.
  • You switch to the core[1] context using debug-context command. The debug context is provided with the path of this core. This debug context is referred to as dbg5.
  • You advance in the simulation again using the next-instruction and step-line which act over the core[1] this time. These commands show the current assembler instruction.
  • Finally, you return to the core[0] context using the debug-context command. This time, this command is used providing the debug context name dbg0 instead of the core[0] path. You can also print the current stack using the stack-trace command.