Debugging Programs

Once you've written your program, you might need to debug it. The IDE debugger lets you detect and diagnose errors in your programs, whether they're running locally or remotely.

Suggested prior reading:

Related information:

In this chapter:

Introduction

The debugger lets you see what's going on "inside" a program while it executes, and what it was doing at the moment it crashed or misbehaved.

In order to use the full power of the Debug perspective, you must use executables compiled for debugging. These executables contain additional debug information that lets the debugger make direct associations between the source code and the binaries generated from that original source. The debuggable executables have _g appended to their filenames.

The IDE debugger uses GDB as the underlying debug engine. It translates each GUI action into a sequence of GDB commands and processes the output from GDB to display the current state of the program being debugged.

The views update only when the program is suspended.


Note: Editing the source after compiling causes the line numbering to be out of step because the debug information is tied directly to the source. Similarly, debugging optimized binaries can also cause unexpected jumps in the execution trace.

Debugging your program

To debug a program, you must build an executable and launch the debugging session. Once you've launched your debugging session, you'll want to control the session.

Building a debuggable executable

Although you can debug a regular executable, you get far more control by building debug variants of the executables. When you created your project, you may have already set the option to make the IDE build one. If so, you should have debuggable executables with _g appended to the filename. If not, you must set the IDE to build debug variants:

  1. In the C/C++ Projects view (or the Navigator view), right-click the project and select Properties.
  2. In the left pane, select QNX C/C++ Project.
  3. In the right pane, select the Options tab.
  4. Under Build Type, ensure Build debug version is enabled:

    Properties dialog; options tab

  5. Click Apply.
  6. Click OK.
  7. If it's not done automatically, rebuild the project.

For more information about setting project options, see the Common Wizards chapter.

Starting your debugging session


Note: For a full description of starting your programs and the Launch Configurations options, see the Starting Your Programs chapter.

Once you've got a debuggable executable, you must create a launch configuration.

To launch a debuggable executable:

  1. From the main menu, select Run-->Debug. (This menu item appears by default in the C/C++ Development perspective. If it doesn't, or you wish to add it to another perspective, select Window-->Customize Perspective. In the left pane, select Other-->Launch. Enable Launch.) The Launch Configurations dialog appears.
  2. Create a launch configuration as you normally would, but don't click OK.
  3. Select the Debugger tab.
  4. Ensure Run program in debugger is selected.
  5. Ensure Stop at main() on startup is enabled.
  6. Click Apply.
  7. By default, the IDE automatically changes to the Debug perspective when you debug a program. If the default is no longer set, or you wish to change to a different perspective when you debug, see the "Setting execution options (Launch Configurations tabs)" section in the Starting Your Programs chapter.
  8. Click Debug.

Controlling your debug session (Debug view)

The Debug view shows a listing of your debug sessions and lets you run your code step-by-step. The IDE is powerful; you can simultaneously debug multiple processes, each with multiple threads.

Understanding the Debug view

The Debug view lets you manage the debugging or running of a program in the workbench. This view displays the stack frame for the suspended threads for each target you're debugging. Each thread in your program appears as a node in the tree. The view displays the process for each program you're running.

Debug view

The Debug view shows the target information in a tree hierarchy as follows (shown here with a sample of the possible icons):

Session item Description Possible
icons
Launch instance Launch configuration name and launch type (e.g. Stack Builder [C/C++ QNX QConn (IP)]) Icon: Debug executable Icon: Run executable
Debugger instance Debugger name and state (e.g. GDB Debugger (Breakpoint hit)) Icon: Debugger
Thread instance Thread number and state (e.g. Thread[1] (Suspended)) Icon: Thread; suspended Icon: Thread; running Icon: Thread; stopped
Stack frame instance Stack frame number, function, filename, and file line number Icon: Stackframe Icon: Stack frame; running

Note: The number beside the thread label is a reference counter for the IDE, not a thread identification number (TID).

The IDE displays stack frames as child elements. It displays the reason for the suspension beside the target, such as end of stepping range, breakpoint hit, signal received, and so on. When a program exits, the IDE displays the exit code.

The label includes the thread's state. In the example above, the label indicates that the thread was suspended because the program hit a breakpoint. You can't suspend only one thread in a process; when one thread is suspended, they all are.

The Debug view also drives the C/C++ Editor; as you step through your program, the C/C++ Editor highlights the location of the execution pointer.

Controlling your debug execution

After you start your debug execution, it stops (by default) in main() and waits for your input. (For information about changing this setting, see the "Debugger tab" section in the Starting Your Programs chapter.) You can control your debug execution in various ways, but they all rely on a core set of debug controls.

Debug execution controls

The debug execution controls appear in the following places (though they don't all appear in any one place):

The debug execution controls are superceded by breakpoints. For example, if you ask the program to step over a function (i.e. run until it finishes that function) and the program hits a breakpoint, it pauses, even though it hasn't finished the function.

The icons and menu items are context-sensitive. For example, you can terminate a process, but you can't terminate a stack frame.

Action Icon Hotkey Description
Resume Icon: Resume F8 Run the process freely from current point
Suspend Icon: Suspend   Regain control of the running process
Terminate Icon: Terminate   Kill the process
Restart Icon: Restart   Rerun the process from the beginning
Step into Icon: Step Into F5 Step forward one line, going into function calls
Step over Icon: Step Over F6 Step forward one line, not going into function calls
Run to return Icon: Step Return F7 Finish this function

Controlling your debug execution (Debug view)

You can control how many steps the program runs before it suspends again (if you want it to suspend at all). You'll probably use the Debug view primarily to control your program flow.

To control your debug execution:

  1. In the Debug view, select the thread you wish to control.
  2. Click one of the debug stepping icons described in the "Debug execution controls" section, above.
  3. Repeat step 2 as desired.
  4. Finish the debug session by choosing one of the controls described in the "Debug launch controls" section in this chapter.

Controlling your debug execution (hotkeys)

If you're running your debug session without the Debug view showing, you can use either the hotkeys or the Run menu to step through your program. The customization works on a per-perspective basis; if you want to use the hotkeys in another perspective, you must enable them there, too.

To enable the debug hotkeys:

  1. Open the perspective you want to enable the hotkeys for.
  2. From the menu, select Window-->Customize Perspective.
  3. In the left pane, select Other-->Debug.
  4. In the left pane, enable Debug.
  5. Click OK. The hotkeys are enabled for that particular perspective. You can also access the controls from the Run menu.

Controlling your debug execution (C/C++ Editor)

You can control your debug session using the C/C++ Editor by having the program run until it hits the line your cursor is sitting on. (This is the same as the gdb until command.) If the program never hits that line, the program runs until it finishes.

You enable this option on a per-perspective basis. The option is enabled by default in the Debug perspective.

To enable debug execution using the C/C++ Editor:

  1. From the menu, select Window-->Customize Perspective.
  2. In the left pane, select Other-->C/C++ Debug.
  3. In the left pane, enable C/C++ Debug.
  4. Click OK. The controls for debug execution in the C/C++ Editor are enabled for your active perspective.

To debug using the C/C++ Editor:

  1. In the C/C++ Editor, select a file associated with the process being debugged (e.g. myProgram.c).
  2. Left-click to insert the cursor where you want to interrupt the execution.
  3. Right-click near the cursor and select Run to C/C++ Line:

    Debug view; run to line

    The program continues running until it hits that line.

Debug launch controls

In addition to controlling the individual stepping of your programs, you can also control the debug session itself. You can perform actions such as terminating the session, stopping the program, and so on, using the debug launch controls available in the Debug view or in the Debug view's right-click context menu. As with the other debug controls, these are context-sensitive; some are disabled depending on whether you've selected a thread, a process, and so on, in the Debug view.

Action Icon Description
Terminate Icon: Terminate Kill the selected process
Terminate & Remove Icon: Terminate and Remove Kill the selected process and remove it from the Debug view
Terminate All Icon: Terminate All Kill all active processes in the Debug view
Disconnect Icon: Disconnect Detach the debugger (i.e. gdb) from the selected process (useful for debugging attached processes)
Remove All Terminated Launches Icon: Remove All Terminated Clear all the killed processes from the Debug view
Relaunch Icon: Relaunch Restart the process

Disassembly mode

When you're debugging, you can also examine your program as it steps into functions that you don't have source code for, such as printf(). Normally, the debugger steps over these functions, even when you click Step Into. When the instruction pointer enters functions for which it doesn't have the source, the IDE shows the function in the Assembly Editor.

To step into assembler functions during debugging:

=>> In the Debug view, click the Disassembly Mode On/Off toggle button Icon: Disassembly Mode On/Off. As you Step Into assembler functions, the IDE shows the execution trace in the Assembly Editor.

More debugging features

This section contains the following subsections:

Inspecting your variables (Variables view)

The Variables view displays information about the variables in the currently selected stack frame:

Variables view

When the execution stops, the changed values are highlighted in red (by default). Like the other debug-related views, the Variables view doesn't try to keep up with the execution of a running program; it updates only when execution stops.

You can set whether or not the variable type (e.g. int) is displayed by clicking the Show Type Names toggle button Icon: Show Type Names.

Customizing the Variables view

You can customize the look of the Variables view and set the color of changed variables (red by default).

To access the Variables view preferences:

  1. From the main menu, select Window-->Preferences.
  2. In the left pane, select Debug-->Variables View:

    Variables view; customization

Changing variable values

During the course of debugging, you may wish to artificially change the value of a variable to test how your program handles the setting or to speed through a loop.

To change a variable value while debugging:

  1. In the Variables view, right-click the variable and select Change Variable Value.
  2. Enter the new value in the available field.

Using breakpoints and watchpoints (Breakpoints view)

The Breakpoints view lists all the breakpoints and watchpoints you've set in your open projects:

Breakpoints view

A breakpoint makes your program stop whenever a certain point in the program is reached. For each breakpoint, you can add conditions to better control whether or not your program stops.

A watchpoint is a special breakpoint that stops the program's execution whenever the value of an expression changes, without specifying where this may happen. Unlike breakpoints, which are line-specific, watchpoints are event-specific and take effect whenever a specified condition is true, regardless of when or where it occurred.

Object Icon
Breakpoint Icon: Breakpoint
Watchpoint (read) Icon: Watchpoint; read
Watchpoint (write) Icon: Watchpoint; write
Watchpoint (read and write) Icon: Watchpoint; read and write

If the breakpoint or watchpoint is for a connected target, a check mark Icon: Checkmark; overlay is superimposed on the icon.

The rest of this section describes how to:


Note: While the Breakpoints view displays both breakpoints and watchpoints, the procedures for setting them differ somewhat.

Adding breakpoints

You set breakpoints on an executable line of a program. If the breakpoint is enabled when you debug, the execution suspends before that line of code executes.

To add a breakpoint:

  1. In the editor area, open the file that you want to add the breakpoint to (e.g. myProgram.c).
  2. Notice that the left edge of the C/C++ Editor has a blank space called a marker bar.
  3. Hover your pointer over the marker bar, beside the exact line of code where you want to add a breakpoint. Right-click the marker bar and select Add Breakpoint:

    Breakpoints view; adding breakpoints

    A dot Icon: Breakpoint object appears, indicating a breakpoint. A corresponding dot Icon: Breakpoint object also appears in the Breakpoints view, along with the name of the file in which you set the breakpoint:

    Breakpoints view; breakpoint added

Adding watchpoints

To add a watchpoint:

  1. From the main menu, select Run-->Add C/C++ Watchpoint. (If this option isn't available, select Window-->Customize Perspective. In the left pane, select Other. Enable C/C++ Debug. Click OK.) The Add C/C++ Watchpoint dialog appears:

    Breakpoints view; adding watchpoints

  2. Enter an expression in the Expression to watch field. The expression may be anything that can be evaluated inside an if statement. (e.g. y==1)
  3. If you want the program to stop when it reads the watch expression, enable Read; to have the program stop when it writes the watch expression, enable Write. You must enable at least one.
  4. Click OK. The watchpoint appears in the Breakpoints view list.

Setting properties of breakpoints and watchpoints

After you've set your breakpoint or watchpoint, the IDE unconditionally halts the program when:

To set the properties for a breakpoint or watchpoint:

  1. In the Breakpoints view, right-click the breakpoint or watchpoint and select Properties. (Or for breakpoints only, in the C/C++ Editor, right-click the breakpoint and select Breakpoint Properties.) The C/C++ Line Breakpoint Properties or C/C++ Watchpoint Properties dialog appears (they're very similar). You need to fill in at least one field:

    Breakpoints view; setting breakpoint properties

  2. In the Condition field, enter the Boolean expression to evaluate. The expression may be anything that can be evaluated inside an if statement (e.g. x > y ). The default is TRUE.
  3. In the Ignore Count field, enter the number of times the breakpoint or watchpoint may be hit before it begins to take effect (not the number of times the condition is true). The default is 0.
  4. Click OK. When in debug mode, your program stops when it meets the conditions you've set for the breakpoint or watchpoint.

Disabling and enabling breakpoints and watchpoints

You may wish to temporarily deactivate a breakpoint or watchpoint without losing the information it contains.

To disable or enable a breakpoint or watchpoint:

=>> In the Breakpoints view, right-click the breakpoint or watchpoint and select Disable or Enable (Or for breakpoints only, right-click the breakpoint in the editor area and select Disable Breakpoint or Enable Breakpoint):

Breakpoints view; disabling breakpoints

To disable or enable all (or many) breakpoints or watchpoints:

  1. In the Breakpoints view, use any of the following methods:
  2. Right-click the highlighted breakpoints and watchpoints and select Disable or Enable.

Removing breakpoints and watchpoints

To remove one or more breakpoints and watchpoints:

=>> Follow the procedure described in "Disabling and enabling breakpoints and watchpoints", with the following exceptions:
  • Instead of selecting Disable or Enable, select Remove.

To remove all breakpoints and watchpoints:

=>> In the Breakpoints view, right-click and select Remove All.

Evaluating your expressions (Expressions view)

The Expressions view lets you evaluate and examine the value of expressions:

Expressions view

To evaluate an expression:

  1. From the menu, select Run-->Add C/C++ Expression. (Or, right-click in the C/C++ Editor and select Add C/C++ Expression.) The Add Expression dialog opens:

    Expressions view; add expressions

  2. Enter the expression you want to evaluate (e.g. (x-5)*3 ).
  3. Click OK. The expression and its value appear in the Expressions view. When the execution of a program is suspended, the IDE reevaluates all expressions and highlights the changed values.

Inspecting your registers (Registers view)

The Registers view displays information about the registers in the currently selected stack frame. When the execution stops, the changed values are highlighted. The functionality of the Registers view is very similar to that of the Variables view; for more information, see the "Inspecting your variables (Variables view)" section in this chapter.

Registers view

You can also customize the colors in the Registers view and change the default value of the Show Type Names option.

To access the Registers view customization dialog:

  1. From the main menu, select Window-->Preferences.
  2. In the left pane, select Debug-->Registers View.

Inspecting your process memory (Memory view)

The Memory view lets you inspect and change your process memory. The view consists of four tabs that let you inspect multiple sections of memory:

Memory view

Inspecting memory

The Memory view supports the same addressing as the C language. You can address memory using expressions such as 0x0847d3c, (&y)+1024, and *ptr.

To inspect your process memory:

  1. In the Debug view, select a process. Selecting a thread automatically selects the associated process.
  2. In the Memory view, select one of the four tabs labeled Memory 1, Memory 2, and so on.
  3. In the Address field, type the address and press Enter.

Changing memory


Caution: Changing your process memory can make your program crash.

To change your process memory:

  1. Follow the procedure for inspecting your process memory.
  2. In the memory pane, type the new value for the memory. The Memory view works in "typeover" mode; use the arrow keys to jump from byte to byte:

    Memory view; changing

  3. Click the Save Changes buttonIcon: Save Changes. The changed memory appears in red.

Configuring output format

You can configure your output to display hexadecimal or decimal. You can also set the number of display columns and the memory unit size. You can configure each memory tab independently.

To configure the output format:

  1. In the Memory view, select one of the four tabs labeled Memory 1, Memory 2, and so on.
  2. Right-click the pane and select any of Format, Memory Unit Size, or Number of Columns. Choose your desired output format:

    Memory view; configure

    The output reflects your selection. Note that some output formats are best viewed in a nonproportional font such as Courier.

Customizing the Memory view

You can customize the Memory view to display in different colors and fonts. You can also customize some of its behavior. The customizations affect the entire Memory view.

To access the Memory view customization dialog:

  1. From the menu, select Window-->Preferences.
  2. In the left pane, select Debug-->Memory View.
  3. You can now change the colors, font, and behavior of the Memory view. When you're done, click Apply, then OK.

Viewing your output (Console view)

The Console view shows you the output of the execution of your program and lets you supply input to your program:

Console view


Note: See also the "Debugging with GDB (Console view)" section, below.

The console shows three different kinds of text, each in a different default color:

You can choose different colors for these kinds of text on the preferences pages.

To access the Console view customization dialog:

  1. From the menu, select Window-->Preferences.
  2. In the left pane, select Debug-->Console.

Debugging with GDB (Console view)

The IDE lets you debug using a subset of the commands that the gdb utility offers:

Console view; GDB


Note: See also the "Viewing your output (Console view)" section, above.

Enabling the GDB Console view

The GDB Console view is part of the regular Console view but isn't accessible until you toggle to it. Once you do, GDB output appears in place of the regular Console view output.

To enable the GDB Console view:

  1. In the Debug view, select a debug session.
  2. In the Debug view, click the Show Debugger Console on Target Selection button Icon: Show Debugger Console on Target Selection. The Console view changes to the GDB Debugger Console view.

Using the GDB Console view

The GDB Console view lets you bypass the IDE and talk directly to GDB; the IDE is unaware of anything done in the GDB Console view. Thus, items such as breakpoints that you set from the GDB Console view don't appear in the C/C++ Editor.


Note: You can't use the Tab key for line completion because the commands are sent to GDB only when you press Enter.

To use the GDB Console view:

=>> In the GDB Console view, enter a command. For example, enter help to get a list of commands; nexti to step one instruction, proceeding through subroutine calls; nexti 3 to step three:

Console view; GDB; using