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

ID 784383
Date 4/01/2024
Public
Document Table of Contents

9.1.1.1. Debugging with GDB Debug from Host PC Using Forwarding Ports

This method consists of defining an incoming forwarding port in Intel® Simics® simulation that allows you to have TCP connectivity between the target system and the host PC, which is the one used to perform the debug. Besides creating the forwarding incoming port, there are two additional requirements for this method:

  • The target system must be able to setup a GDB server that allows you to connect from the PC to a GDB debug session (gdbserver is the command to launch GDB server application).
  • In the host PC, you must have the GDB debugger application installed to start the GDB debug session (normally with the gdb command to launch the GDB application).

The following captures describe the process to follow to perform the debug. In the same captures, the step numbers are listed to indicate the order in which each command must be input (host PC, target system or Intel® Simics® simulator CLI).

The following chart depicts the relationship and sequence of this method:

In the Intel® Simics® simulator CLI, set up the TFTP directory to take the test application binary to the target system using the Intel® Simics® simulator internal TFTP server. For this, set the TFTP directory in the host PC file system. Create the incoming forwarding port for TCP protocol using port 9123. Intel® Simics® simulator creates the 4001 incoming port that can be accessed by the host PC and forwards the traffic to port 9123 in the target system.

# Intel Simics simulator CLI 

# Step 1. Setup Intel Simics tftp dir: /home/simicsUser/gdbDir directory
simics> service_node_cmp0.set-tftp-directory “/home/simicsUser/gdbDir”

simics> run

# Step 3. Setup the forwarding port for gdb using port 9123
running> stop
simics> connect-real-network-port-in 9123 ethernet-link = ethernet_switch0 
target-ip = 10.10.0.100 -tcp

Host TCP port 4001 -> 10.10.0.100:9123
Warning: This can expose the target system on the host local network.
simics> run

In the target serial console first, take the testGdb binary with debugging information to the target system using TFTP and provide it with execution permissions. Start the GDB server using the binary and forwarding port created (using the 9123 port as it is the one that is visible in the target system). Once this session gets started, you can observe that the GDB server is listening to this port waiting for a connection from the host PC side. When that connection gets established and the debugging process starts, the application execution advances, and you can see all the messages that are printed by the application.

# Target Serial Console

# Step 2. Bring the testGdb binary to the target system using tftp
root@psgdevice:~# tftp –gr testGdb 10.10.0.1
root@psgdevice:~# chmod +x testGdb

# Step 4. Start GDB server in target system using testGdb binary and port 
9123. gdbserver needs to be available in the target system.
root@psgdevice:~# gdbserver localhost:9123 testGdb
Process /home/root/test created; pid = 422
Listening on port 9123
# Next message is observed after step 8.
=== My Debug example on Core 0 ===
# Next messages are observed after step 12.

2000
  core[0]: 1 times
  core[1]: 0 times
  core[2]: 0 times
  core[3]: 0 times
 
Child exited with status 0
root@psgdevice:~#

In the host PC, start the GDB debug session using the GDB software (which needs to be pre-installed in the host PC) and the application binary that includes the debug information. Once the GDB session starts, connect to the debug session created in the target system using the target remote GDB command providing as input the port that is visible in the host PC (port 4001). Once the connection gets set up, start the debug process. This starts setting up a breakpoint at the entry point of the test application, at main() function, and then running the application to get there. Once inside of the application, continue the execution and manually stop it to set a new breakpoint at the entry point of the getCore() function. Allow the application to advance until it reaches that function. At that point, call the finish GDB command that makes it finish the current function (getCore). After doing this, return to the main() function body and you can observe what is the current value of the exitVar variable(which is 0) and change the value to 1. This allows you to exit from the while loop and finish the application. The debug session finishes when calling the quit GDB command.

The debugger can be manually controlled by using the commands listed below. You can find more commands at the GNU Project Debugger official documentation.

Table 28.  Commands to Control the Debugger
Commands Description
break <symbol> Places a breakpoint at the specified <symbol> in the program.
break Injects a breakpoint at the current line.
break <N> Injects a breakpoint at line <N> in the loaded source code.
continue Continues the program until the next breakpoint or error is met.
finish Runs until the current function is finished.
step Runs the next line of the program.
quit Quits GDB.
# Linux Host Terminal
# Step 5. Create a gdb debug session in the host PC.
/home/simicsUser/gdbDir $ aarch64-none-linux-gnu-gdb testGdb
GNU gdb (GNU Toolchain for the A-profile Architecture 10.2-2020.11 (arm-10.16))
10.1.90.20201028-git
Copyright (C) 2020 Free Software Foundation, Inc.
:
Reading symbols from testGdb...
(gdb)

# Step 6. Connect from the host PC to the gdb session created in the target system
(gdb) target remote localhost:4001
Remote debugging using localhost:4001
Reading symbols from ...
0x0000fffff7fd9cf0 in __mmap64 (offset=<optimized out>, fd=0, flags=0, 
    prot=<optimized out>, len=<optimized out>, addr=<optimized out>)
    at ../sysdeps/unix/sysv/linux/mmap64.c:59
59	../sysdeps/unix/sysv/linux/mmap64.c: No such file or directory.

# Step 7. Set a breakpoint in main() function and run until get there.
(gdb) break main
 Breakpoint 1 at 0x400674: file test.c, line 28.

(gdb) continue
 Continuing.
 
Breakpoint 1, main () at test.c:28
28	    int x = 1000;
# Step 8. The debug of the application running in target system starts here

(gdb) continue
Continuing.

# Type Ctrl-c to interrupt program. 
Continuing.
^C
Program received signal SIGINT, Interrupt.
0x0000fffff7ee95d4 in ?? ()

# Step 9. Set a breakpoint at entry point of getCore() function
(gdb) break getCore
 Breakpoint 2 at 0x40060c: file test.c, line 13.

(gdb) continue
Continuing.
 
Breakpoint 2, getCore () at test.c:13
13	    core = sched_getcpu();

# Step 10. Go to exit point of the getCore() function.
(gdb) finish
Run till exit from #0  getCore () at test.c:13
0x00000000004006a0 in main () at test.c:40
40	        core = getCore();        
Value returned is $1 = 0

# Step 11. Print value of exitVar variable and change it to 1 to exit loop.
(gdb) print exitVar
$2 = 0

(gdb) set exitVar=1

(gdb) print exitVar
$3 = 1

# Step 12. Continue execution to finish the application.
(gdb) continue
Continuing.
[Inferior 1 (process 432) exited normally]

(gdb) quit