7.5   System-Mode Debugging

By default, in CrossWind you debug only one task at a time. The task is selected either by using the run command to create a new task, or by using attach to debug an existing task. When the debugger is attached to a task, debugger commands affect only that particular task. For example, when a breakpoint is set it applies 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.

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.

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


*

NOTE: 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 5.2.6 Using the Shell for System Mode Debugging, then attach to them with the thread command.

7.5.1   Entering System Mode

To debug in system mode, first make sure your debugger session is not attached to any task (type the command detach, or select Detach from the Targets menu).

Then issue the following command:

attach system
Switches the target connection into system mode (if supported by the target agent) and stops the entire target system.

Or, select Target>Attach System from the CrossWind menu.

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.


*

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

7.5.2   Thread Facilities in System Mode

In system mode, the GDB thread-debugging facilities become useful. A 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 thread context.

info threads
Displays summary information (including thread ID) for every thread in the target system.

thread idNo
Selects the specified thread as the current thread.

break linespec thread idNo
Sets a breakpoint affecting only the specified thread.

For a general description of these commands, see Debugging with GDB: 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 executing attach system to stop a VxWorks target, 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 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, what its ID is currently.

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 function 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 VxWorks task ID and task name.

Thread-Specific Breakpoints

In system mode, unqualified breakpoints (set with graphical controls on the program-display window, or in the command panel 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 "Switching to" shows what thread 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 on the interrupt button or by keying the interrupt character (usually CTRL+C). 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, in the thread marked with + in the info threads display. However, in the course of stepping that thread, other threads may begin executing. Hence, the debugger may stop in another thread before the stepping command completes, due to an event in that other thread.