10

Debugger



10.1    Introduction

The Tornado debugger (CrossWind) combines the best features of graphical and command-line debugging interfaces.

The most common debugging activities, such as setting breakpoints and controlling program execution, are available through convenient point-and-click interfaces. Similarly, program listings and data-inspection windows provide an immediate visual context for the crucial portions of your application.

For complex or unpredictable debugging needs, the command-line interface gives you full access to a wealth of specialized debugging commands.You can extend or automate command-line debugger interactions by using the Tcl scripting interface that allows you to develop custom debugger commands (see 10.1 Introduction).

The underlying debugging engine is an enhanced version of GDB, the portable symbolic debugger from the Free Software Foundation (FSF). For full documentation of the GDB commands, see GDB User's Guide.



10.2    Debugger GUI

Figure 10-1 illustrates the GUI elements you can use to interact with the debugger.

Figure 10-1:   Debugging Windows

The Debug menu provides the complete list of Tornado GUI debugger commands, as well as their keyboard shortcuts (10.2.1 Debugger Toolbar, Buttons, and Menu Commands).

The Debug toolbar provides buttons for the most common debugger commands, as well as for opening and closing windows that display data, memory, and stack information (see 10.2.1 Debugger Toolbar, Buttons, and Menu Commands).

You use the editor window to keep track of the code you are debugging. You can click in this window to specify information for debugger commands (such as symbol names, or lines of code). The debugger in turn uses the attribute panel, in the left margin of the editor window, to show breakpoints and the execution context. (See 10.3 Using the Debugger.)

The debugger command line window for CrossWind provides a command-line interface to the debugger (see 10.5 Using the Debugger Command Line). The window is not needed for standard debugger operations; the graphical interface provide simpler controls.

10.2.1   Debugger Toolbar, Buttons, and Menu Commands

The Debug toolbar has buttons for the most common debugging commands, as well as for displaying auxiliary debugger windows. The toolbar shown as a floating palette in Figure 10-2.

Figure 10-2:   Debug Toolbar

The commands in the Debug menu include alternatives to the buttons in the Debug toolbar, as well as additional debugger functions. Keyboard shortcuts are also available for all graphical debugger commands

The debugger buttons and menu commands are described in Table 10-1.

Table 10-1:   Debugger Buttons and Commands 


Button
Menu Command
Description

n/a
Source Search Path
Identify source search paths for the debugger. Opens the Debugger Source Search Path dialog box. See 10.3.2 Setting the Search Path.
Run
Run a routine on the target as a new task under debugger control. Opens the Run Task dialog box, which allows you to choose the routine. See 10.3.7 Continuing Through a Program.
n/a
Detach
Detach from the task currently under debugger control, leaving it in the state present (suspended or running) when you give the command. See 10.3.10 Detaching from a Running Task.
n/a
Detach and Resume
Detach from the task currently under debugger control, first ensuring that it is running. See 10.3.10 Detaching from a Running Task
n/a
Attach
Attach the debugger to a task. See 10.3.8 Attaching to a Running Task.
Interrupt Debugger
Interrupt program execution. See 10.3.5 Interrupting a Program.
Stop Debugging
n/a
Breakpoints
Open the Breakpoints window. See 10.3.6 Setting Breakpoints.
Toggle Breakpoint
Set or remove a task-level breakpoint on the current line of the editor window. To delete a breakpoint, click this button on a line that is already marked with the breakpoint icon. See 10.3.6 Setting Breakpoints.
n/a
Toggle Global Breakpoint
Set or remove a global breakpoint on the current line of the editor window. To delete a breakpoint, click this button on a line that is already marked with the breakpoint icon.
n/a
Toggle Temp. Breakpoint
Set or remove a temporary breakpoint. See 10.3.6 Setting Breakpoints.
Step Into
Step to the next line of code, in order of execution (not necessarily the next line displayed in the editor). See 10.3.7 Continuing Through a Program.
Step Over
Step to the next line displayed on the screen. If there is a subroutine call on the current line, the button executes that subroutine in its entirety, then stops at the line after the subroutine call. See 10.3.7 Continuing Through a Program.
Continue
Continue program execution. The task you are debugging continues until the next breakpoint, exception, or until you use Interrupt Debugger to halt it. See 10.3.7 Continuing Through a Program.
Step Out
Finish the current subroutine. Execution continues until the current subroutine returns to its caller. See 10.3.7 Continuing Through a Program.
Watch
Open and close the Watch window, which displays the values of specified variables throughout the execution of the program. See Watch Window.
Variables
Open and close the Variables window, which displays the values of local variables. See Variables Window.
Registers
Open and close the Registers window, which displays values of the target registers. See Registers Window.
Back Trace
Open and close the Back Trace window, which displays stack information. See Back Trace Window.
Memory
Open and close the Memory window, which displays target memory information. See Memory Window.



10.3    Using the Debugger

The debugger allows you to download object modules, to start routines under debugger control, and to take over existing tasks in the target. Tasks under debugger control execute normally until they terminate, unless they encounter a breakpoint, or you interrupt them, or some other event sends them an interrupt or a signal.


*      
WARNING: You must compile your application using debugging symbols (the -g compiler option) to use many of the features of the debugger. The default compiler settings used by the Tornado project facility include debugging symbols.

10.3.1   Starting and Stopping the Debugger

There are two ways to start a debugging session:

  • From the Tornado Launch toolbar: Press the button. This starts a debugging session for the currently selected target server (see Tornado Launch Toolbar, p.98).

  • From the Tools menu: Click on Debugger. The dialog box shown in Figure 10-3 appears, to allow you to select a target server from the Targets drop-down list.

Figure 10-3:   Debugger Target-Selection Dialog Box

When the debugger is running, you can interact with it through the editor window, through the debugger command line window, and through the Debug menu and toolbar. (See 10.2 Debugger GUI.)

You can end the debugging session in any of the following ways:

  • In the debug toolbar, press the button.

  • Click on the Stop Debugging command in the Debug menu.

10.3.2   Setting the Search Path


Button
Shortcut
Debug Menu Command

n/a
ALT+D h
Source Search Path

The debugger maintains a list of directories where it searches for source code, and for the host-resident image of the VxWorks run-time (the debugger uses the latter to load debugging symbol information). This list is called the source search path.

Normally you will not need to set the source search path because the debugger can derive the path from the object file. If GDB finds the object but cannot find the source, the GUI prompts you for the source file location and remembers it.

If necessary, click on Source Search Path to add directories to, remove directories from, or change the order of this list. Figure 10-4 illustrates the Debugger Source Search Path dialog box.

Figure 10-4:   Debugger Source Search Path Dialog Box


*      
WARNING: Do not leave more than one directory containing a VxWorks kernel image in the search path. The debugger uses the first of these it encounters; if it is not the correct core image, the results are unpredictable, and the debugging session may hang.

10.3.3   Unloading a Module

Normally you will not need to unload a module. If you update and download a module with the same name, it replaces the module loaded earlier. In the unusual case where you need to unload a module without replacing it, use the unload option from the context menu in the project Workspace window (see 4.3.5 Downloading an Application).

You can also use the debugger command line to remove any dynamically-linked module from the target. Open the debug command-line window and use the GDB unload command. See 10.5 Using the Debugger Command Line for more information about command line usage.

10.3.4   Running a Program


Button
Shortcut
Debug Menu Command

F6
Run

To run a subroutine under debugger control, use the Run command. The Run Task dialog box appears; use it to specify which routine to run, with what arguments. Click OK to start the task on the target.

Figure 10-5:   Run Task Dialog Box

Specify the argument list after the routine name, with the arguments separated by spaces. The argument list must contain integers or addresses only; it may not contain floating-point or double-precision values, function calls, or user-defined C++ operations. (See GDB User's Guide for other commands which allow arbitrary arguments to be passed.)

Figure 10-5 shows the Run Task dialog box with a routine name (required) and an argument list (optional). The default for required arguments that you do not supply is zero. To set a temporary breakpoint where the routine begins execution, check the Break at Entrypoint box.

Once a task stops under debugger control (most often, at a breakpoint), you can single-step through the code, jump over subroutine calls, or resume execution. Figure 10-10 shows the debugger stopped at the entry point of the routine BigBang( ). The context pointer þ indicates what statement will execute if you allow the program to resume.

Figure 10-6:   The Context Pointer

10.3.5   Interrupting a Program

You can interrupt execution with Interrupt Debugger in the Debug menu, by pressing the button, or by using the keyboard shortcut ALT+SHIFT+F5.

10.3.6   Setting Breakpoints


Button
Shortcut
Debug Menu Command
Pop-up Menu Command

n/a
n/a
Breakpoints
Breakpoints
F9
Toggle Breakpoint
Toggle Breakpoint
n/a
F8
Toggle Temp. Breakpoint
Toggle Temp. Breakpoint

To set multiple breakpoints, select Breakpoints in either the Debug or the pop-up menu (right-click in the editor window). The Breakpoints dialog box appears. (See Figure 10-7.) Enter a file name and line number in the Location box, select a scope (local task or all tasks), and click Add. The new breakpoint appears in the Breakpoints list. If Externally managed is checked, it indicates that the breakpoint was set by means other than the debugger (by the Tornado shell, for example).

Figure 10-7:   The Breakpoints Dialog Box


*      
NOTE: The breakpoints you set in this way will affect only the task to which the debugger is attached. If you want your breakpoint to stop all tasks when the attached task hits the breakpoint, set it using gbreak from the command line.

The Advanced button opens the Advanced Breakpoint dialog box (Figure 10-8).

Figure 10-8:   The Advanced Breakpoint Dialog Box

This

dialog lets you attach conditions to the break point as well as deleting or disabling it instead of keeping it when it is hit. Enter a file name and line number in the Location box. A conditional expression of type int can be used, which will be evaluated as true or false (all non-zero values being true), or to check if a value in memory has changed. The On Break options have the following meanings with regard to handling a breakpoint:

Keep

Delete

Disable

To set a breakpoint on an individual line of code, place the text cursor in the line where you want the program to stop. Then click the button, select Toggle Breakpoint from the Debug menu, or right-click on the line of code and select Toggle Breakpoint from the pop-up menu. The symbol appears in the left margin of the editor window to indicate the breakpoint location, when the attribute pane is turned on for the editor (12.3.2 Editor Preferences). Otherwise, the entire line is highlighted to indicate the breakpoint location.

If you click Toggle Breakpoint on a line that produces no object code (such as a comment line or a declaration), the breakpoint appears on the next line that does produce object code.

You can also set temporary breakpoints by using Toggle Temp. Breakpoint from the Debug menu. A temporary breakpoint stops the program only once. The debugger deletes it automatically as soon as the program stops there. A hollow breakpoint symbol ( ) marks temporary breakpoints in the editor's left margin, so that you can readily distinguish the two kinds of breakpoints there.

To remove either kind of breakpoint, click either of these commands with a line selected that already has a breakpoint or use the Breakpoints dialog box.


*      
CAUTION: If your application was compiled without debugging information, the debugger displays an error when you try to set a breakpoint using these commands. If you are forced to work on an object module without debugging information, you can still break at the start of any subroutine in either of the following ways: (1) Check the Break at Entrypoint check box in the Run Task dialog box when you start the task (10.3.7 Continuing Through a Program). (2) Use the Breakpoints dialog box (see 10.3.6 Setting Breakpoints). In either case, when the debugger stops, it displays a Disassembly window, as it does whenever no debugging information is available for the program context.


*      
NOTE: GDB software watchpoints are very intrusive. They should only be used with real-time programs if the overhead is acceptable.

Figure 10-9 shows the editor window with two breakpoints set: a temporary breakpoint þ (hollow) and a persistent breakpoint À (filled in).

Figure 10-9:   Breakpoint Marks in Editor Window

10.3.7   Continuing Through a Program


Button
Shortcut
Debug Menu Command
Pop-up Menu Command

F5
Continue
n/a
F10
Step Into
n/a
CTRL+F5
Step Over
n/a
SHIFT+F5
Step Out
n/a
n/a
n/a
n/a
Run to Cursor
n/a
n/a
n/a
Start a new task from current function

Once a task has been stopped under debugger control (most often, at a breakpoint), you can single-step through the code, jump over subroutine calls, or resume execution. Figure 10-10 shows the debugger stopped at the entry point of the routine graphInit( ). The context pointer þ indicates what statement will execute if you allow the program to resume.

Figure 10-10:   The Context Pointer

When the program is stopped, you can resume operation with the Continue command from the Debug menu. If there are no remaining breakpoints, interrupts, or signals, the task runs to completion. A common example of using Continue is to set a breakpoint at the end of a loop, then use Continue repeatedly to stop once in each iteration through the loop, while monitoring a variable used within that loop.

To step through the code one line at a time, click Step Into. If you have auxiliary debugger windows open (10.3.11 Examining Data, Memory, and the Stack), they are updated with current values as you step through the code. If there is a subroutine call in the current line, Step Into takes you to the first line of that subroutine, not to the next line currently displayed on your screen. The only exception is for calls to system subroutines and application subroutines that are compiled without debugging information; Step Into cannot step into these.

The effect of Step Into is somewhat different if the current view in the editor shows assembly instructions (when either Disassembly or Mixed is selected from the View menu, or the current routine has no debugging symbols). In this case, Step Into advances execution to the next instruction rather than to the next line of source.

To single-step without going into other subroutines, click Step Over instead of Step Into. The Step Over command is almost the same as Step Into, but instead of stepping to the very next statement executed (which, in the case of a subroutine call, is typically not the next statement displayed), Step Over steps to the next line on the screen. If there is no intervening subroutine call, this is the same thing as Step Into. But if there is an intervening subroutine call, Step Over executes that subroutine in its entirety, then stops at the line after the subroutine call.

The display style has the same effect on Step Over as on Step Into. Step Over steps to either the next machine instruction or the next source statement, and if necessary completes a subroutine call first.

While stepping through a program, you may conclude that the problem you are interested in lies in the current subroutine's caller, rather than at the stack level where your task is suspended. Use the Step Out command from the Debug menu in that situation: execution continues until the current subroutine completes, then the debugger regains control in the calling statement.

To continue a stopped task to a specific point without setting a breakpoint, place the cursor on the desired line of code, right-click to open the pop-up menu, and select Run to Cursor.


*      
NOTE: The Run to Cursor option is implemented using the GDB until location command; the GDB command always stops on return from the current function to prevent the program from running free. If you use Run to Cursor with the program stopped in a subroutine, it will stop at the return point no matter where the cursor is; to run to the cursor, select Run to Cursor again.

To start execution from a specific point, place the cursor on the desired line of code, right-click to open the pop-up menu, and select Start a new task from current function.

10.3.8   Attaching to a Running Task


Button
Shortcut
Debug Menu Command

n/a
ALT+F6
Attach

Click Attach to attach the debugging session to a task that is already running. If you were already debugging another task, the previous task is released from debugger control, remaining in its current state (running or stopped). Attach displays a scrolling list of the tasks running on the target (Figure 10-11). You can either select a task in the list, or type the name (or task ID) of a task in the Attach to: box. By default, the debugger attaches without stopping the task. The task will stop when it hits a breakpoint.

Figure 10-11:   Attach Dialog Box

Usually, a newly-attached task stops in a system routine; thus, the debugger displays an assembly listing in the editor window. Open the backtrace window using the button. Change the frame by double-clicking on the frame you want to jump to.

The first entry in the Attach dialog box is always System. Select this entry to enter system mode, as described in 10.6 System-Mode Debugging. An error display appears if your BSP is not configured to support system mode.

10.3.9   Attaching Automatically

By default, the debugger always attaches to the next task to register an exception. Thus your debugger is always attached to the task that needs debugging.

This default behavior can be changed by selecting Tools>Options>Debugger. The following options can be selected:

never

do not auto-attach at all

safely

only auto-attach if we are not attached to any task

always

always attach to the next task that gets an exception

10.3.10   Detaching from a Running Task

Click Detach and Resume to release the current task from debugger control (and allow it to continue running). This allows you to exit the debugger, or switch to system mode, without killing the task you were debugging.

10.3.11   Examining Data, Memory, and the Stack


Button
Shortcut
Debug Windows Menu Command

ALT+3
Watch
ALT+4
Variables
ALT+5
Registers
ALT+6
Memory
ALT+7
Back Trace

When a program stops under debugger control, you can use auxiliary windows to examine local and global program variables, arguments, registers, target memory, and the execution stack. The windows can be displayed docked or free-floating (Figure 10-12). When they are docked (the default), the split bars at their edges can be used to change their size.

Figure 10-12:   Auxiliary Debugger Windows: Free-Floating and Docked

Buttons for the auxiliary debugger windows are on the debugger toolbar, and provide a simple means for opening and closing the windows. They are also accessible from Debug>Debug Windows.


*      
NOTE: The windows described in this section update each time your program stops in the debugger. Each update highlights values that changed since the previous display.

Watch Window


Button
Shortcut
Debug Windows Menu Command

ALT+3
Watch

The Watch window displays the current values of symbols, throughout the execution of the program. The Watch window has four pages, which allows you to group and display sets of symbols in any manner you find useful.

To select a symbol for display in the watch window, click on or highlight the symbol name in the editor, display the pop-up menu (with the right-mouse button), and select Add to Watch. If you highlighted the symbols name, the Watch window opens, and lists the symbol and its current value. If you simply clicked on the symbol, the Add to Watch dialog box opens (Figure 10-13).

Figure 10-13:   Add to Watch Dialog Box

Enter the name of the symbol and click OK to display the symbol and its current value in the Watch window (Figure 10-14). Use the pop-up menu or the Delete key to remove symbols from the window.

Figure 10-14:   Debugger Watch Window

Variables Window


Button
Shortcut
Debug Windows Menu Command

ALT+4
Variables

Click the Variables command in the Debug Windows sub-menu to open a window that shows the values of local variables. Figure 10-15 shows an example of the Variables window.

Figure 10-15:   Debugger Variables Window

The contents of the Variables window always reflect the routine that is currently executing; when you step into a different routine, the new routine's local variables replace those in the previous display.

Registers Window


Button
Shortcut
Debug Windows Menu Command

ALT+5
Registers

Click the Registers command in the Debug menu to open a window that shows the values in the target registers. Figure 10-16 illustrates the Registers window. The contents of the window depend on the architecture of the target, and the title displayed when the window is not docked includes information about machine architecture.

Figure 10-16:   Debugger Registers Window

Back Trace Window


Button
Shortcut
Debug Windows Menu Command

ALT+7
Back Trace

To inspect the calling sequence leading to the current routine, click Back Trace in the Debug Windows sub-menu. The Back Trace window allows you to monitor the stack. You can double-click on any routine in the window to move the context pointer to that stack level in the editor window (Figure 10-17).

Figure 10-17:   Debugger Back Trace Window

Memory Window


Button
Shortcut
Debug Windows Menu Command

ALT+6
Memory

Click the Memory command to open a window that displays a range of target memory starting at the address specified in the Start Address control field. The debugger saves each address you type in the field; you can select a previously displayed address from the drop-down list associated with this box. To update the memory display, press the button. Figure 10-18 shows the window docked and maximized.

Figure 10-18:   Debugger Memory Window

The display of data in the Memory window is controlled by the Debugger page of the Options property sheet, which is accessible from Tools>Options>Debugger.

See the description of the x ("examine") command in GDB User's Guide: Examining Data for a discussion of the memory-display formats.



10.4    Source Code Display Options

While the debugger is running, you can display your program code in the editor as source code, as symbolic disassembly of object code, and as mixed source and disassembly.

The Source, Disassembly, and Mixed Source and Disassembly commands in the View menu control the display of code in the editor:

Source

Disassembly

Mixed Source and Disassembly

Figure 10-19 shows a mixed-mode code display.

Figure 10-19:   Mixed Source and Disassembly Display

Source display (in either the Source or the Mixed Source and Disassembly view) requires that your application modules be compiled with debugging information which is the default for compilations with the Tornado project facility (see 4Projects).


*      
NOTE: For some source lines, compilers generate code that is not contiguous, because it is sometimes more efficient to interleave the object code from separate source lines. In this situation, the mixed-mode display rearranges the assembly listing to group all object code below the line that generates it.

The debugger is fully operational no matter what view you select. For example, you can set breakpoints in a line of assembly code, and you can use the Step and Next commands in either assembly or source. (In views that show assembly, these commands step by instructions rather than by source lines; see 10.3.7 Continuing Through a Program.)

The editor, however, works only on source code. Thus, when you display a view with disassembled instructions, the editor display goes into read-only mode until you either stop debugging or switch to the Source view.


*      
NOTE: Disassembly takes a long time the first time you switch to a view that requires it. Subsequently, in the same debugging session, you can switch views quickly. The disassembly information is not persistent; the debugger discards it when you stop debugging (or if you close the source file with the Close command in the File menu).



10.5    Using the Debugger Command Line

The Tornado graphical interface is usually the most convenient way to run the debugger. However, you can also use the GDB command-line interface, which in some cases is the best way to perform a particular action (see Figure 10-1). The debugger command-line window provides full access to GDB commands, as well as to Tornado extensions to those commands. The command line can be displayed with Debug>Debug Windows>Debug Command Line.


*      
NOTE: The command line drop-down list displays a history of all commands the user has entered. Commands can be selected from the list to be executed again.

The following sections summarize some particularly useful commands, and describe commands added by Wind River that are not part of other versions of GDB.

10.5.1   GDB Initialization Files

One use of the debugger window is to experiment with text-based commands for actions that you might want to perform automatically each time you start debugging.

When the debugger first executes GDB, it looks for a file named .gdbinit. It first looks in the directory named by the environment variable HOME (if it is defined), then in your current working directory.1 If it finds the file in either directory, the debugger commands in it are executed; if it finds the file in both directories, the commands in both are executed.

A related initialization file, called gdb.tcl, is specifically intended for Tcl code to customize GDB with your own extensions. The Tcl code in this file executes before .gdbinit. The debugger searches for gdb.tcl in two places: first in installDir\.wind, then (if the environment variable HOME is defined) in homeDir\.wind. See 10.7 Tcl: Debugger Automation for a discussion of extending GDB through Tcl. See also 10.8.1 Tcl: Debugger Initialization Files for a discussion of how the Tornado debugger initialization files interact.

10.5.2   Selecting Modules to Debug

You can use the following commands to establish the debugging context:

add-symbol-file filename



load filename


load filename serverFilename




unload filename

The load and unload commands both request confirmation if the debugger is attached to an active task. You can disable this confirmation request, as well as all other debugger confirmation requests, with set confirm. See GDB User's Guide: Controlling GDB.

10.5.3   Running a Program

Just as with the Tornado shell, you can execute any subroutine in your application from the debugger. Use the following commands:

run routine args

call expr

When you run a routine from the debugger using one of these commands, the routine runs until it encounters a breakpoint or a signal, or until it completes execution. The normal practice is to set one or more breakpoints in contexts of interest before starting a routine. However, you can interrupt the running task by clicking Interrupt Debugger in the Debug menu or by pressing CTRL+BREAK from the Debugger window.

10.5.4   Re-Setting Application I/O

By default, any tasks you start with the run command use the standard I/O channels assigned globally in VxWorks. However, the debugger has the following mechanisms to specify input and output channels:

  • Redirection with < and >

Each time you use the run command, you can redirect I/O explicitly for that particular task by using < to redirect input and > to redirect output. For output, ordinary path names refer to files on the host where the debugger is running, and path names preceded by an @ character refer to files or devices on the target. Input cannot be redirected to host files, but input redirection to target files or devices is supported with the same @ convention for consistency. For example, the following command starts the routine appMain( ) in a task that gets input from target device /tyCo/0 and writes output to host file grab.it:

(gdb) run appMain > grab.it < @/tyCo/0
  • New Default I/O with tty Command

The debugger command tty sets a new default input and output device for all future run commands in the debugging session. The same convention used with explicit redirection on the run line allow you to specify target files or devices for I/O. For example, the following command sets the default input and output channels to target device /tyCo/0:

(gdb) tty @/tyCo/0
  • Tcl: Redirection of Global or Task-Specific I/O

Tcl extensions are available within the debugger's Tcl interpreter to redirect either all target I/O, or the I/O channels of any running task. See 10.7.3 Tcl: Invoking GDB Facilities for details.

10.5.5   Using Graphically Enhanced Commands

The GDB frame command has a Tornado graphical extension, even when used at the command line.

frame n


10.5.6   Managing Targets

Instead of using the target server list in the Tornado Launch toolbar, you can select a target from the Debugger window with the target wtx command. The two methods of selecting a target are interchangeable. However, it may sometimes be more convenient to use the GDB command language--for example, you might specify a target this way in your .gdbinit initialization file or in other debugger scripts.

target wtx servername

10.5.7   Extended Debugger Commands

The debugger also provides two kinds of extended commands:

  • Server Protocol Requests

The Tornado tools use a protocol called WTX to communicate with the target server. You can send WTX protocol requests directly from the GDB command area as well, by using a family of commands beginning with the prefix "wtx". See Tornado API Programmer's Guide: WTX Protocol for descriptions of WTX protocol requests. Convert protocol message names to lower case, and use hyphens in place of underbars. For example, issue the message WTX_CONSOLE_CREATE as the command wtx-console-create.

  • Shell Commands

You can run any of the Tornado shell's primitive facilities described in 7.2.4 Invoking Built-In Shell Routines in the Debugger window, by inserting the prefix "wind-" before the shell command name. For example, to run the shell td( ) command from the debugger, enter wind-td in the Debugger window.3 Because of GDB naming conventions, mixed-case command names cannot be used; if the shell command you need has upper-case characters, use lower case and insert a hyphen before the upper-case letter. For example, to run the semShow( ) command, enter wind-sem-show.


*      
CAUTION: The debugger does not include the Tornado shell's C interpreter. Thus, the "wind" commands are interfaces only to the underlying Tcl implementations of the shell primitives. For shell primitives that take no arguments, this makes no difference; but for shell primitives that require an argument, you must use the shell Tcl command shSymAddr to translate C symbols to the Tcl form. For example, to call the shell built-in show( ) on a semaphore ID mySemID, use the following:
    (gdb) wind-show [shSymAddr mySemId] 

10.5.8   Extended Debugger Variables

You can change many details of the debugger's behavior by using the set command to establish alternative values for internal parameters. (The show command displays these values; you can list the full set interactively with help set.)

The following additional set/show parameters are available in the Tornado debugger (CrossWind) in addition to those described in GDB User's Guide:

inhibit-gdbinit

wtx-ignore-exit-status

wtx-load-flags

wtx-load-path-qualify



wtx-load-timeout

(gdb) set wtx-load-timeout 120


wtx-task-stack-size

wtx-tool-name



10.6    System-Mode Debugging

By default, in Tornado you debug only one task at a time. The task is selected either by using the run dialog box to create a new task, or by using the Attach dialog box (10.3.8 Attaching to a Running Task) to debug an existing task. When the debugger is attached to a task, debugger commands affect only that particular task. For example, breakpoints apply only to that task. When the task reaches a breakpoint, only that task stops, not the entire system. This form of debugging is called task mode debugging. (All the material in 10.3 Using the Debugger applies to task mode debugging).

Tornado also supports an alternate form of debugging, where you can switch among multiple tasks (also called threads) and even examine execution in system routines such as ISRs. This alternative mode is called system mode debugging; it is also sometimes called external mode. In system mode, you can use global breakpoints to stop the entire system whenever any task hits the breakpoint.

Most of the debugger features described elsewhere in this manual, and the debugging commands described in GDB User's Guide, are available regardless of which debugging mode you select. However, certain debugging commands (discussed below in 10.6.3 Thread Facilities in System Mode) are useful only in system mode.


*      
CAUTION: The run command is not available in system mode, because its use of a new subordinate task is more intrusive in that mode. In system mode, use the shell to start new tasks as discussed in 7.2.7 Using the Shell for System Mode Debugging, then attach to them with the thread command.

10.6.1   Configuring System Mode

In order for system mode debugging to work properly, the following items must be set correctly.

Table 10-2:   Definitions for System Mode Debugging


# Define
Required Value

#define WDB_COMM_TYPE
WDB_SERIAL
#define WDB_MODE
WDB_MODE_DUAL
#define INCLUDE_PC_CONSOLE
#define PC_CONSOLE
#define CONSOLE_TTY
#define NUM_TTY
#define WDB_TTY_CHANNEL
#define WDB_TTY_DEV_NAME
#define WDB_TTY_BAUD
As appropriate.

10.6.2   Entering System Mode

To debug in system mode, click on the System entry displayed in the Attach dialog box (use the Attach command in the Debug menu to display the dialog box).

You can also switch to system mode from the debugger window or an initialization file, but first make sure your debugger session is not attached to any task (type detach). Then issue the following command:

attach system

The response to a successful attach system is output similar to the following:

(gdb) attach system 
Attaching to system. 
0x5b58 in wdbSuspendSystemHere ()

Once in system mode, the entire target system stops. In the example above, the system stopped in wdbSuspendSystemHere( ), the normal suspension point after attach system.


*      
WARNING: Not all targets support system mode, because the BSP must include a special driver for that purpose (see 4.7 Configuring the Target-Host Communication Interface). If your target does not support system mode, attempting to use attach system produces an error.

10.6.3   Thread Facilities in System Mode

In system mode, the GDB thread-debugging facilities become useful. Thread is the general term for processes with some independent context, but a shared address space. In VxWorks, each task is a thread. The system context (including ISRs and drivers) is also a thread. GDB identifies each thread with a thread ID, a single arbitrary number internal to the debugger.

You can use the following GDB commands to manage threads:

info threads

thread idNo

break linespec thread idNo

For a general description of these commands, see GDB User's Guide: Debugging Programs with Multiple Threads. The sections below discuss the thread commands in the context of debugging a VxWorks target in system mode.

Displaying Summary Thread Information

The command info threads shows what thread ID corresponds to which VxWorks task. For example, immediately after attaching to the system, the info threads display resembles the following:

(gdb) info threads 
  4 task 0x4fc868   tExcTask    0x444f58 in ?? () 
  3 task 0x4f9f40   tLogTask    0x444f58 in ?? () 
  2 task 0x4c7380 + tNetTask    0x4151e0 in ?? () 
  1 task 0x4b0a24   tWdbTask    0x4184fe in ?? () 
(gdb)

In the info threads output, the left-most number on each line is the debugger's thread ID. The single asterisk (*) at the left margin indicates which thread is the current thread. The current thread identifies the "most local" perspective: debugger commands that report task-specific information, such as bt and info regs (as well as the corresponding debugger displays) apply only to the current thread.

The next two columns in the thread list show the VxWorks task ID and the task name. If the system context is shown, the single word system replaces both of these columns. The thread (either a task, or the system context) currently scheduled by the kernel is marked with a + to the right of the task identification.


*      
CAUTION: The thread ID of the system thread is not constant. To identify the system thread at each suspension, you must use info threads whenever the debugger regains control, in order to see whether the system thread is present and, if so, its current ID.

The remainder of each line in the info threads output shows a summary of each thread's current stack frame: the program counter value and the corresponding routine name.

The thread ID is required to specify a particular thread with commands such as break and thread.

Switching Threads Explicitly

To switch to a different thread (making that thread the current one for debugging, but without affecting kernel task scheduling), use the thread command. For example:

(gdb) thread 2 
[Switching to task 0x3a4bd8   tShell    ] 
#0  0x66454 in semBTake () 
(gdb) bt 
#0  0x66454 in semBTake () 
#1  0x66980 in semTake () 
#2  0x63a50 in tyRead () 
#3  0x5b07c in iosRead () 
#4  0x5a050 in read () 
#5  0x997a8 in ledRead () 
#6  0x4a144 in execShell () 
#7  0x49fe4 in shell () 
(gdb) thread 3 
[Switching to task 0x3aa9d8   tFtpdTask ] 
#0  0x66454 in semBTake () 
(gdb) print/x $i0 
$3 = 0x3bdb50

As in the display shown above, each time you switch threads the debugger exhibits the newly current thread's task ID and task name.

Thread-Specific Breakpoints

In system mode, unqualified breakpoints (set with graphical controls on the editor window, or in the Debugger window with the break command and a single argument) apply globally: any thread stops when it reaches such a breakpoint. You can also set thread-specific breakpoints, so that only one thread stops there.

To set a thread-specific breakpoint, append the word thread followed by a thread ID to the break command. For example:

(gdb) break printf thread 2 
Breakpoint 1 at 0x568b8 
(gdb) cont 
Continuing. 
[Switching to task 0x3a4bd8 + tShell    ] 
 
Breakpoint 1, 0x568b8 in printf ()
(gdb) i th 
  8 task 0x3b8ef0   tExcTask    0x9bfd0 in qJobGet () 
  7 task 0x3b6580   tLogTask    0x9bfd0 in qJobGet () 
  6 task 0x3b15b8   tNetTask    0x66454 in semBTake () 
  5 task 0x3ade80   tRlogind    0x66454 in semBTake () 
  4 task 0x3abf60   tTelnetd    0x66454 in semBTake () 
  3 task 0x3aa9d8   tFtpdTask   0x66454 in semBTake () 
* 2 task 0x3a4bd8 + tShell      0x568b8 in printf () 
  1 task 0x398688   tWdbTask    0x66454 in semBTake () 
(gdb) bt 
#0  0x568b8 in printf () 
#1  0x4a108 in execShell () 
#2  0x49fe4 in shell ()

Internally, the debugger still gets control every time any thread encounters the breakpoint; but if the thread ID is not the one you specified with the break command, the debugger silently continues program execution without prompting you.


*      
CAUTION: Because the thread ID for the system context is not constant, it is not possible to set a breakpoint specific to system context. The only way to stop when a breakpoint is encountered in system context is to use a non-task-specific breakpoint.

Switching Threads Implicitly

Your program may not always suspend in the thread you expect. If any breakpoint or other event (such as an exception) occurs while in system mode, in any thread, the debugger gets control. Whenever the target system is stopped, the debugger switches to the thread that was executing. If the new current thread is different from the previous value, a message beginning with "Switching to" shows which thread is suspended:

(gdb) thread 2 
(gdb) cont 
Continuing. 
Interrupt... 
Program received signal SIGINT, Interrupt. 
[Switching to system +] 
 
0x5b58 in wdbSuspendSystemHere () 

Whenever the debugger does not have control, you can interrupt the target system by clicking Interrupt Debugger in the Debug menu, or by keying CTRL+BREAK. This usually suspends the target in the system thread rather than in any task.

When you step program execution (with any of the commands step, stepi, next, or nexti, or the equivalent buttons or ), the target resumes execution where it left off, which is in the thread marked + in the info threads display. However, in the course of stepping that thread, other threads may begin executing. The debugger may stop in another thread before the stepping command completes, due to an event in that other thread.



10.7    Tcl: Debugger Automation

The debugger exploits Tcl at two levels: like other Tornado tools, it uses Tcl to build the graphical interface, but it also includes a Tcl interpreter at the GDB command level. This section discusses using the Tcl interpreter inside the Tornado enhanced GDB, at the command level.


*      
NOTE: For information about using Tcl to customize the Tornado GUI, see 10.8 Tcl: Debugger Customization. This section is mainly of interest when you need complex debugger macros; thus, you might want to skip it on first reading.

Tcl has two major advantages over the other GDB macro facility (the define command). First, Tcl provides control and looping (such as for, foreach, while, and case). Second, Tcl procedures can take parameters. Tcl, building on the command interface, extends the scripting facility of GDB to allow you to create new commands.

10.7.1   Tcl: A Simple Debugger Example

To submit commands to the Tcl interpreter within GDB from the Tornado Debugger window, use the tcl command. For example:

(gdb) tcl info tclversion

This command reports which version of Tcl is integrated with GDB. All the text passed as arguments to the tcl command (in this example, info tclversion) is provided to the Tcl interpreter exactly as typed. Convenience variables (described in GDB User's Guide: Convenience Variables) are not expanded by GDB. However, Tcl scripts can force GDB to evaluate their arguments; see 10.7.3 Tcl: Invoking GDB Facilities.

You can also define Tcl procedures from the GDB command line. The following example procedure, mload, calls the load command for each file in a list:

(gdb) tcl proc mload args {foreach obj $args {gdb load $obj}}

You can run the new procedure from the GDB command line; for example:

(gdb) tcl mload vxColor.o priTst.o

To avoid typing tcl every time, use the tclproc command to assign a new GDB command name to the Tcl procedure. For example:

(gdb) tclproc mld mload

This command creates a new GDB command, mld. Now, instead of typing tcl mload, you can run mld as follows:

(gdb) mld vxColor.o priTst.o

You can collect Tcl procedures in a file, and load them into the GDB Tcl interpreter with this command:

(gdb) tcl source tclFile

If you develop a collection of Tcl procedures that you want to make available automatically in all your debugging sessions, write them in the file gdb.tcl. The GDB Tcl interpreter reads this file when it begins executing. (See 10.8.1 Tcl: Debugger Initialization Files for a discussion of where you can put this file, and of how all the Tornado debugger and GDB initialization files interact.)

10.7.2   Tcl: Specialized GDB Commands

The Tornado debugger (CrossWind) includes four commands to help you use Tcl. The first two were discussed in the previous section. The commands are:

tcl command

tclproc gdbName TclName


*      
NOTE: To execute tclproc commands automatically when GDB begins executing, you can place them in .gdbinit directly (see 10.5.1 GDB Initialization Files), because tclproc is a GDB command rather than a Tcl command. However, if you want to keep the tclproc definition together with supporting Tcl code, you can exploit the gdb Tcl extension described in 10.7.3 Tcl: Invoking GDB Facilities to call gdb tclproc in gdb.tcl.

tcldebug

tclerror

(gdb) tcl puts stdout [expr $x+2] 
can't read "x": no such variable
(gdb) tclerror 
TCL verbose error reporting is ON.
(gdb) tcl puts stdout [expr $x+2] 
can't read "x": no such variable 
    while executing 
"expr $x..." 
    invoked from within 
"puts stdout [expr $x..."

Tcl also stores the error stack in a global variable, errorInfo. To see the error stack when Tcl verbose error mode is OFF, examine this variable as follows:

(gdb) tcl $errorInfo

For more information about error handling in Tcl, see C.2.9 Tcl Error Handling.

10.7.3   Tcl: Invoking GDB Facilities

You can access GDB facilities from Tcl scripts with the following Tcl extensions:

gdb arguments



    execute: command 

gdbEvalScalar exprlist


    evaluate: expression 

gdbFileAddrInfo fileName


    (gdb) tcl gdbFileAddrInfo vxColor.c 
    {239 1058 0x39e2d0 0x39fbfc}
gdbFileLineInfo fileName


    (gdb) tcl gdbFileLineInfo vxColor.c  
    {239 0x39e2d0 0x39e2d4} {244 0x39e2d4 0x39e2ec} ...
gdbIORedirect inFile outFile [ taskId ]


    (gdb) tcl gdbIORedirect - grab.it
gdbIOClose

gdbLocalsTags

gdbStackFrameTags

gdbSymbol integer

    symbolName [ + Offset ]

    (gdb) tcl puts stdout [gdbSymbol 0x20000] 
    floatInit+2276

    symbol: value 
gdbSymbolExists symbolName


    symbol exists: symbolName 

10.7.4   Tcl: A Linked-List Traversal Macro Example

This section shows a Tcl procedure to traverse a linked list, printing information about each node.5 The example is tailored to a list where each node has the following structure:

    struct node 
        { 
        int data; 
        struct node *next; 
        }

A common method of list traversal in C is a for loop like the following:

    for (pNode = pHead; pNode; pNode = pNode->next) 
    ...

We imitate this code in Tcl, with the important difference that all Tcl data is in strings, not pointers.

The argument to the Tcl procedure will be an expression (called head in our procedure) representing the first node of the list.

Use gdbEvalScalar to convert the GDB expression for a pointer into a Tcl string:

    set pNode [gdbEvalScalar "$head"]

To get the pointer to the next element in the list:

    set pNode [gdbEvalScalar "( (struct node *) $pNode)->next"]

Putting these lines together into a Tcl for loop, the procedure (in a form suitable for a Tcl script file) looks like the following:

    proc traverse head {  
        for {set pNode [gdbEvalScalar "$head"] }  \ 
            {$pNode}      \ 
            {set pNode [gdbEvalScalar "( (struct node *)$pNode)->next"]}   \ 
                {puts stdout $pNode}  
    }

In the body of the loop, the Tcl command puts prints the address of the node.

To type the procedure directly into the Debugger window would require prefacing the text above with the tcl command, and would require a backslash at the end of every line.

If pList is a variable of type (struct *node), you can execute:

(gdb) tcl traverse pList

The procedure displays the address of each node in the list. For a list with two elements, the output would look something like the following:

0xffeb00 
0xffea2c

It might be more useful to redefine the procedure body to print out the integer member data, instead. For example, replace the last line with the following:

    {puts stdout [format "data = %d"  \ 
        [gdbEvalScalar "((struct node *) $pNode)->data"]]}

You can bind a new GDB command to this Tcl procedure by using tclproc (typically, in the same Tcl script file as the procedure definition):

    tclproc traverse traverse

The traverse command can be abbreviated, like any GDB command. With these definitions, you can type the following command:

(gdb) trav pList

The output now exhibits the contents of each node in the list:

data = 1 
data = 2


10.8    Tcl: Debugger Customization

Like every other Tornado tool, the debugger's graphical user interface is "soft" (amenable to customizing) because it is written in Tcl, which is an interpreted language. The Tornado API Reference describes the graphical building blocks available. You can also study the Tcl implementation of the debugger graphical interface itself, in host\resource\tcl\CrossWind.win32.tcl.

10.8.1   Tcl: Debugger Initialization Files

You can write Tcl code to customize the debugger's graphical presentation in a file called crosswind.tcl. The debugger looks for this file in two places: first under c:\tornado (or whatever directory you specify with the environment variable WIND_BASE), and then in the directory specified by the HOME environment variable (if that environment variable is defined). Use this file to collect your custom modifications, or to incorporate shared modifications from a central repository of Tcl extensions at your site.

Recall that the debugger uses two separate Tcl interpreters. Previous sections described the .gdbinit and gdb.tcl initialization files for the debugger command language (see 10.7 Tcl: Debugger Automation). The following outline summarizes the role of all the Tornado debugger customization files. The files are listed in the order in which they execute:

installDir\.wind\gdb.tcl


homeDir\.wind\gdb.tcl

homeDir\.gdbinit

.gdbinit

installDir\.wind\crosswind.tcl


homeDir\.wind\crosswind.tcl

You can prevent the Tornado debugger from looking for the two .gdbinit files, if you choose, by setting the internal GDB parameter inhibit-gdbinit to yes. Because the initialization files execute in the order they are listed above, you have the opportunity to set this parameter before the debugger reads either .gdbinit file. To do this, insert the following in gdb.tcl:

gdb set inhibit-gdbinit yes 

10.8.2   Tcl: Passing Control between the Two Tornado Debugger Interpreters

You can use the following specialized Tcl commands to pass control between the two Tornado debugger (CrossWind) Tcl interpreters:

uptcl

downtcl

writeDebugInput

The major use of uptcl is to experiment with customizing or extending the graphical interface. For example, if you have a file myXWind containing experimental Tcl code for extending the interface, you can try it out by entering the following in the Debugger window:

(gdb) tcl upctl source myXWind

By contrast, downtcl and writeDebugInput are likely to be embedded in Tcl procedures, because (in conjunction with the commands discussed in 10.7.3 Tcl: Invoking GDB Facilities) they are the path to debugger functionality from the graphical front end.

Most of the examples in 10.8.3 Tcl: Experimenting with Tornado Debugger Extensions, below, center around calls to downtcl.

10.8.3   Tcl: Experimenting with Tornado Debugger Extensions

The examples in this section use the Tcl extensions summarized in Table 10-3. For detailed descriptions of these and other Tornado graphical building blocks in Tcl, see Tornado API Programmer's Guide or the online Tornado API Reference.

Table 10-3:   Tornado UI Tcl Procedures Used in Debugger Extensions


Tcl Extension
Description

menuItemAppend
Add a command or a separator to the end of an existing menu.
menuItemInsert
Add a command within the list of existing commands in a menu.

Tcl: An Add-Symbols Command for the File Menu

As explained in 10.5.2 Selecting Modules to Debug, you sometimes need to tell the debugger explicitly to load symbols for modules that were downloaded to the target using other programs (such as the shell).

Example 10-1 illustrates a Debug menu command Add Symbols to handle this through the graphical user interface, instead of typing the add-symbol-file command.

Example 10-1:   Add-Symbols Command

    # MENU COMMAND: "Add Symbols", additional entry under "Debug" 
 
    menuItemInsert -after {"&Debug" "Do&wnload...\tShift+F6"} \ 
                    {"Add Symbols..."} {windAddSyms} 
 
############################################################################## 
# 
# windAddSyms - called from Debug menu to add symbols from chosen object file 
# 
# This routine implements the "Add Symbols" command in the Debug menu.  
# It prompts the user for a filename; if the user selects one, it tells 
# GDB to load symbols from that file. 
# 
# SYNOPSIS: 
#   xwindAddSyms 
# 
# RETURNS: N/A 
# 
# ERRORS: N/A 
#proc windAddSyms {} { 
    set result [fileDialogCreate -title "Symbols from file" -filemustexist \ 
            -filefilters "Object Files (*.o;*.out)|*.o;*.out| 
                            All Files (*.*)|*.*||" \ 
            -okbuttontitle "&Add"] 
         
 
    if {$result != ""} { 
 
        # we violate good taste here by not capturing or testing the result 
        # of catch, because an error notification appears in the command panel. 
 
        catch {downtcl gdb add-symbol-file [lindex $result 0]} 
    } 
}   

Tcl: "this" Menu Command for C++

In C++ programs, one particular named value has special interest: this, which is a pointer to the object where the currently executing routine is a member.

Example 10-2 defines a Debug menu command to launch an inspection window for the value where this points. The Tcl primitive catch is used in the definition in order to avoid propagating error conditions (for instance, if the buttons are pressed with no code loaded) from GDB back to the controlling Tornado debugger session.

Example 10-2:   Command to Display C++ this Value

# Insert a separator line after default menu commands 
 
menuItemAppend -separator {&Debug} 
 
# Debug Menu Command: *this - Inspect window on current C++ class (*this) 
 
menuItemAppend {"&Debug"} {"*this"} { 
        catch {downtcl gdb display/W *this} 
}
         


1:  The graphical interface to the debugger has a separate initialization file crosswind.tcl, which runs after .gdbinit.

2:  See also the description of wtx-load-path-qualify in 10.5.8 Extended Debugger Variables for another way of managing how the debugger reports load path names to the target server.

3:  You can exploit command completion to see a list of all the shell primitives as they appear in the debugger: type "wind-" followed by two tabs.

4:  A more restricted form of this command, called gdbEvalAddress, can only evaluate a single expression (constructed by concatenating all its arguments). gdbEvalAddress is only supported to provide compatibility with Tcl debugger extensions written for an older debugger, VxGDB. Use the more general gdbEvalScalar in new Tcl extensions.

5:  Keep in mind that for interactive exploration of a list the window (Figure 10-14) described in Watch Window is probably more convenient.