A simple debug session

Updated: April 19, 2023

In this example, we'll be debugging our “Hello, world!” program via a TCP/IP link. We go through the following steps:

Configure the target

Let's assume an x86_64 target using a basic TCP/IP configuration. The following lines (from the buildfile you'd use to create the OS image) show what's needed to host the sample session:

io-pkt-v4-hc -d e1000  
ifconfig wm0 10.0.1.172
devc-pty &
[+session] pdebug 8000 &

The above specifies that the host IP address is 10.0.1.172. The pdebug agent is configured to use port 8000.

You could instead run qconn on the target, and the behavior would be similar: qconn listens on the same port and starts pdebug if a target qnx ip:port connection comes in, and then the communication would be the same as with pdebug alone.

Compile for debugging

We'll be using the x86_64 compiler. Note the -g option, which makes the compiler include debugging information:

$ qcc -V gcc_ntox86_64 -g -o hello hello.c  

Start the debug session

For this simple example, the source can be found in our working directory. First, let's start the session; to reduce document clutter, we'll run the debugger in quiet mode:

ntox86_64-gdb -quiet

The gdb debugger provides its own shell; by default its prompt is (gdb). Specify the target IP address and the port used by pdebug:

(gdb) target qnx 10.0.1.172:8000
Remote debugging using 10.0.1.172:8000
MsgNak received - resending
Remote target is little-endian

Upload the debug executable to the target. (This can be a slow operation. If the executable is large, you may prefer to build the executable into your target image and use the set nto-executable command to point gdb to it.) Note that the file has to be in the target system's pathname space, so we can get the executable via a network filesystem, ftp, or, if no filesystem is present, via the upload command:

(gdb) upload hello /tmp/hello

Load the symbolic debug information from the current working directory (in this case, hello must reside on the host system):

(gdb) file hello
Reading symbols from hello...done.

You don't need to use the file command if you specify the executable name when you start gdb (e.g., ntox86_64-gdb -quiet hello).

Start the program:

(gdb) run hello
Starting program:  /tmp/hello
Trying to find symbol file for ldqnx.so.2

Set a breakpoint on main():

(gdb) break main
Breakpoint 1 at 0x80483ae: file hello.c, line 8.

Allow the program to continue to the breakpoint found at main():

(gdb) c
Continuing.
Breakpoint 1, main () at hello.c:8
8       gettimeofday (&when, NULL);

Continue to debug the program as necessary.

Basic debugger commands

While you're in a debug session, you can use any of the following commands as the next action for starting the actual debugging of the project:

next
Continue to the next source line in the current (innermost) stack frame.
list
List the specified function or line.
break
Set a breakpoint on the specified function or line.
help
Get the help main menu.
help data
Get the help data menu.
help inspect
Get help for the inspect command.
inspect y
Inspect the contents of variable y.
set y=3
Assign a value to variable y.
bt
Get a back trace.

For more information about these commands and their arguments, see https://www.gnu.org/software/gdb/documentation/, or use the help cmd command in gdb.

Let's see how to use some of these basic commands. First, here's the list command:

(gdb) list
3
4   main () {
5       struct timeval when;
6       int x,y,z;
7
8       gettimeofday (&when, NULL);
9       printf ("Hi ya!\n");
10
11      x=3;
12      y=2;

Press Enter to repeat the last command:

(gdb) <enter>
13      z=3*2;
14
15      exit (0);
16
17  }

Break on line 11:

(gdb) break 11
Breakpoint 2 at 0x80483c7: file hello.c, line 11.

Continue until the first breakpoint:

(gdb) continue
Continuing.
Hi ya!

Breakpoint 2, main () at hello.c:11
11      x=3;

Notice that the above command went past the printf() statement at line 9, so the output from the call is displayed on the screen.

Inspect variable y, using the short form of the inspect command:

(gdb) inspect y
$1 = -1338755812

Get some help on the step and next commands:

(gdb) help s
Step program until it reaches a different source line.
Usage: step [N]
Argument N means step N times (or till program stops for another reason).
(gdb) help n
Step program, proceeding through subroutine calls.
Usage: next [N]
Unlike "step", if the current source line calls a subroutine,
this command does not enter the subroutine, but instead steps over
the call, in effect treating it as a single source line.

Go to the next line of execution:

(gdb) next
12      y=2;
(gdb) next
13      z=3*2;
(gdb) inspect z
$2 = 1
(gdb) next
15      exit (0);
(gdb) inspect z
$3 = 6

Continue program execution:

(gdb) continue
Continuing.

Program exited normally.

Quit the debugger session:

(gdb) quit
The program is running. Exit anyway? (y or n) y