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

ID 784383
Date 7/08/2024
Public
Document Table of Contents

6.4.1. Loading Symbol Files in a Simulation

The command used to load a symbol file in a simulation is the following:

add-symbol-file symbolfile ["context-query"] [relocation-address][relative] 
["section"] [segment]

The arguments provided are explained next:

Table 22.   add-symbol-file Command Options
Argument Description
symbolfile This is the debug symbol file. You can define the full path in the host machine where the file is located. If the full path is not provided, Intel® Simics® simulator uses Intel® Simics® Search Path and path markers (%simics%, %script%) to find the symbol file.
context-query This is the context in which the symbol file is used. This can be a process, a debug context, or a specific core. This value can be retrieved directly from the context-query-for-object command. If no context is specified, it uses the default ‘*’, which indicates that it applies to any context.
relocation-address relative This is the address the file/segment/section must be mapped to. The -relative flag specifies if the relocation address is relative to the load address in the binary. When not set, the address is the absolute address specified.
section

This is the name of the section to relocate. See the list-sections command.

segment This is the number of the segment to relocate. See the list-segments command.

The command returns an ID that can be used with remove-symbol-file to remove the mappings that were added. This command also displays the number of contexts that match this symbol file.

The following capture shows some examples about how the symbol file can be added. In the same capture is described what is being done as a comment.

#Intel Simics simulator CLI  

# Get the objects for which the default ‘*’ context-query applies

simics> context-query-for-object object=system.   <autocomplete>

system
system.board.fpga.soc_inst.hps_subsys.agilex_hps.core[0]  
system.board.fpga.soc_inst.hps_subsys.agilex_hps.core[1]  
system.board.fpga.soc_inst.hps_subsys.agilex_hps.core[2]  
system.board.fpga.soc_inst.hps_subsys.agilex_hps.core[3]  
system.board.fpga.soc_inst.hps_subsys.agilex_hps.cpu_mem[0]
system.board.fpga.soc_inst.hps_subsys.agilex_hps.cpu_mem[1]
system.board.fpga.soc_inst.hps_subsys.agilex_hps.cpu_mem[2]
system.board.fpga.soc_inst.hps_subsys.agilex_hps.cpu_mem[3]

# Load a symbol file without any context. This applies to all contexts(9) 
simics> add-symbol-file "/home/simicsUser/TestSymFile/testSymFile" 
Context query * currently matches 9 contexts.
Symbol file added with id '1'.

# Load a symbol file that has context specific to a core. The symbol

# file can be used only with this core. Note that only matches one context.

simics> add-symbol-file context-query = "' system.board.fpga.soc_inst.hps_subsys.agilex_hps.core[2]'" "/home/simicsUser/TestSymFile/testSymFile"
Context query "system.board.fpga.soc_inst.hps_subsys.agilex_hps.core[2]" currently matches 1 context. Symbol file added with id '2'.

# Load a symbol file using a context defined by the context ID of core. 
#Note that also 1 single context matches this.

simics> context-query-for-object object = system.board.fpga.soc_inst.hps_subsys.agilex_hps.core[0]  


"ID=\"system.board.fpga.soc_inst.hps_subsys.agilex_hps.core[0]\""
simics> add-symbol-file context-query = "ID=\"system.board.fpga.soc_inst.hps_subsys.agilex_hps.core[0]\"" "/home/simicsUser/TestSymFile/testSymFile"

Context query ID="system.board.fpga.soc_inst.hps_subsys.agilex_hps.core[0]" currently matches 1 context.
Symbol file added with id '3'.

# Load a symbol file using the ID returned by context-query-for-object 
simics> $cid = (context-query-for-object object = system.board.fpga.soc_inst.hps_subsys.agilex_hps.core[3])

simics> echo $cid

ID="system.board.fpga.soc_inst.hps_subsys.agilex_hps.core[3]"
simics> add-symbol-file context-query = $cid "/home/simicsUser/TestSymFile/testSymFile"

Context query ID="system.board.fpga.soc_inst.hps_subsys.agilex_hps.core[3]" currently matches 1 context.
Symbol file added with id '4'.

# Load a symbol file using a debug session that was applied over a core

simics> debug-context name = "dbg1" object = "system.board.fpga.soc_inst.hps_subsys.agilex_hps.core[1]"

dbg1 (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]
??()
simics> $cid = "ID="+"\"" + dbg1->cid + "\""
simics> echo $cid

ID="system.board.fpga.soc_inst.hps_subsys.agilex_hps.core[1]"
simics> add-symbol-file context-query = $cid "/home/simicsUser/TestSymFile/testSymFile"

Context query ID="system.board.fpga.soc_inst.hps_subsys.agilex_hps.core[1]" currently matches 1 context.
Symbol file added with id '5'.

# Removing a symbols file using an ID and the name of the symbol file. 
# At this point the 5 IDs of symbol files were created. In this example 
# each instance of a symbol file adds 2 memory maps entries (see show- 
# memorymap command).

simics> remove-symbol-file id=1

simics> remove-symbol-file id=2

simics> remove-symbol-file "/home/simicsUser/TestSymFile/testSymFile"

Removed 6 Memory Map entries.

Intel® Simics® simulator provides some commands that allow you to obtain information about the symbol file. The following capture shows some examples of these commands:

Table 23.  Commands to Obtain Information About the Symbol File
Command Description
list-segments Lists the sections of the symbol file symbol-file.
list-sections Lists the sections of the symbol file symbol-file.
show-memorymap Shows all memory map entries that were setup when the symbol file was loaded.
add-pathmap-entry Adds a translation from a path in the debug information to a path on the host. This is used to make available to the debugger the source code that was used to create the symbol files (if the source code is in a single directory and the symbols file is also there, this command is not needed).

For additional information about any command, you can use help <command> from Intel® Simics® simulator CLI.

The following capture shows an example of the use of some of the commands described above:

#Intel Simics simulator CLI 

simics> add-symbol-file "/home/simicsUser/TestSymFile/test"
Context query * currently matches 9 contexts.
Symbol file added with id '1'.
simics> list-segments "/home/simicsUser/TestSymFile/test"
Segments  Sections
---------------------------------------------------------
       0  <segment is empty>
       1  .interp
       2  .interp, .note.ABI-tag, .hash, .gnu.hash, .dynsym, …, .eh_frame
       3  .init_array, .fini_array, .dynamic, .got, .got.plt, .data, .bss
       4  .dynamic
       5  .note.ABI-tag
       6  .eh_frame_hdr
       7  <segment is empty>
       8  .init_array, .fini_array, .dynamic, .got
simics> list-sections "/home/simicsUser/TestSymFile/test"
.interp, .note.ABI-tag, .hash, .gnu.hash, .dynsym, .dynstr, .gnu.version, .gnu.version_r, .rela.dyn, .rela.plt, .init, .plt, .text, .fini, .rodata, .eh_frame_hdr, .eh_frame, .init_array, .fini_array, .dynamic, .got, .got.plt, .data, .bss, .comment, .debug_aranges, .debug_info, .debug_abbrev, .debug_line, .debug_str, .debug_loc, .debug_ranges, .symtab, .strtab, .shstrtab
simics> show-memorymap 
Contexts matching *
--------------------------------------------------------------------
ID  Address  Size    Flags  Offset   File    
--------------------------------------------------------------------                             
1   0x400000 0x86c    rx    0x0    /home/simicsUser/TestSymFile/test
1   0x410de8 0x258    rw    0xde8  /home/simicsUser/TestSymFile/test
-------------------------------------------------------------------- 

To support the debug process, Intel® Simics® simulator provides some additional commands that operate over debug context using the information provided by the symbol file. These commands are described next.

Table 24.  Commands to Support the Debug Process
Command Description
sym-value* Gets the value of a symbol or a C expression.
sym-write* Writes a new value to a variable.
sym-type* Gets the type of a C expression.
sym-address* Gets the address of a C value expression.
list* Lists source code.
stack-trace* Shows the stack.
bp.source_location.break Adds a breakpoint on a particular location.
bp.source_location.run-until Runs until the specified location is reached. Equivalent to bp.source_location.break + run.
bp.source_location.wait-for Waits in the current script branch until the specified location is reached. Must be used inside a script branch.
bp.source_location.trace Enables tracing of the events that the specified location is reached.
bp.source_line.break Adds a breakpoint at a given source code line.
Note: * Requires a debug context.

For additional information about any command, you can use help <command> from Intel® Simics® simulator CLI.

An example that shows how some of these commands are executed is shown next. For this example, simple C application (testSymFile.c) source code has been created and compiled to create a symbol file (testSymFile). The source code includes the main() function and inside of this, some variables are being printed. The exitVar variable is initialized in 0 and is declared as volatile to control the value of this using the Intel® Simics® debugger. In the application, an initial debug message is printed and then, it gets into a loop and remains there if the exitVar variable remains with its initial value. If the value of this exitVar variable changes, some arithmetic operations are done with the variables defined and finally the value of the c variable is printed just after finishing the application.

# Source code snippet (testSymFile.c)
#include <stdio.h>
 
int main()
{
 
    int x = 1000;
    int a;
    int b;
    int c;
    volatile int exitVar = 0;
 
    printf("=== My Debug example ===\n"); 
    while(exitVar==0);
    a = x;
    b = x;
    c = a + b;
    printf("%d\n", c);
    return 0;
}

The following is a capture of a debug session over the testSymFile application. The explanation of the example is embedded in the capture. An assumption about this debug example is that the application is ready to be executed in the target system.

# Intel Simics simulator CLI  

# Loading the symbol file from the host system file system 
simics> add-symbol-file "~/myTestDir/test" 
Context query * currently matches 9 contexts. 
Symbol file added with id '1'. 

# Set a breakpoint at the main() function of the application and the 
# sumulation is run. This can be done in a single step using run-until. 
simics> bp.source_location.break main 
Breakpoint 1: 0x1 (planted) 

simics> bp.list
--------------------------------------------------------------------
ID  Description       Enabled    Oneshot  Ignore count   Hit count 
--------------------------------------------------------------------
1  execution of main   true       false             0            0 
--------------------------------------------------------------------
# Intel Simics simulator CLI 
simics> run

# At this time, the application must be run in the target system. So the 
# breakpoint triggers.
simics> r
Setting new inspection object: system.board.fpga.soc_inst.hps_subsys.agilex_hps.core[0]
[tcf] Breakpoint 1 on execution in context system.board.fpga.soc_inst.hps_subsys.agilex_hps.core[0]

# The application reached the main() function. This was executed on core3.
simics> psel
"system.board.fpga.soc_inst.hps_subsys.agilex_hps.core[0]"

# Crate a debug context with the current core selected.
simics> (psel).debug
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]

main() at /home/rolando/tasks/gdbLearn/arm/test.c:6
6	    int x = 1000;

# List the current line in core03.
simics> list
       4  {
       5  
->     6      int x = 1000;
       7      int a;
       8      int b;

# Advance few line in the application code execution, list the code again 
# to observe the new location. Get the value of the exitVar variable. 
# Observe that the value is 0, so it means that the application remains
# in the loop until a new value is set in the variable. Check that the type
# of variable can be retrieved from the debugger.
simics> next-line
simics> next-line
simics> next-line
simics> list
      10      volatile int exitVar = 0;
      11  
->    12      printf("=== My Debug example ===\n");
      13      while(exitVar==0);
      14      a = x;
simics> sym-type exitVar
volatile int

simics> sym-value exitVar
0

# Run the simulation. The debug message is printed in the target
# system console. Stop the simulation and list again to see where the code
# is located now. This time, it must be inside of the while loop. (Note:
# depending on how the application is run, it is possible that the OS
# changes the core in which the application runs or by the time the
# simulation is stopped the core is executing something different than what
# is in the loop).
simics> r
simics> stop
simics> list
      11  
      12      printf("=== My Debug example ===\n");
->    13      while(exitVar==0);
      14      a = x;
      15      b = x;

# Update the value of exitVar to 1. Once it changes the application must
# exit from the loop and the value of c variable is printed before
# finishing the application.
simics> sym-write exitVar 1
exitVar = 1

simics> r

After running this example, the output in the target system terminal must look like the following:

# Target Serial Console
root@psgdevice:~# ./test 
=== My Debug example ===
2000

In the last example, you are using global scope debug commands (list, next-line, sym-write, etc.) that apply to the current debug context selected, but you can also use local scope commands using the dbg0 debug context (dbg0.list, dbg0.next-line, dbg0.sym-write, etc.).