|
NOTE: For information about using Tcl to customize the CrossWind GUI, see 7.7 Tcl: CrossWind Customization. The discussion in this section is mainly of interest when you need complex debugger macros; you might want to skip this section 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.
To submit commands to the Tcl interpreter within GDB from the command panel, 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 Debugging with GDB: Convenience Variables) are not expanded by GDB. However, Tcl scripts can force GDB to evaluate their arguments; see 7.6.3 Tcl: Invoking GDB Facilities.
You can also define Tcl procedures from the GDB command line. The following example procedure, mld, 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 .wind/gdb.tcl under your home directory. The GDB Tcl interpreter reads this file when it begins executing. (See 7.7.1 Tcl: Debugger Initialization Files for a discussion of how all the CrossWind and GDB initialization files interact.)
The CrossWind version of GDB includes four commands to help you use Tcl. The first two were discussed in the previous section. The commands are:
|
NOTE: To execute tclproc commands automatically when GDB begins executing, you can place them in .gdbinit directly (see 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 7.6.3 Tcl: Invoking GDB Facilities to call gdb tclproc in ~/.wind/gdb.tcl.
|
||||||||||||||||||
(gdb) tcl puts stdout [expr $x+2] can't read "x": no such variable
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 B.2.9 Tcl Error Handling.
execute: command
evaluate: expression
(gdb) tcl gdbFileAddrInfo vxColor.c {239 1058 0x39e2d0 0x39fbfc}
(gdb) tcl gdbFileLineInfo vxColor.c {239 0x39e2d0 0x39e2d4} {244 0x39e2d4 0x39e2ec} ...
(gdb) tcl gdbIORedirect - /dev/ttyp2
(gdb) tcl gdbIORedirect /dev/ttyp2 @13 0x3b7c7c
symbolName [ + Offset ]
(gdb) tcl puts stdout [gdbSymbol 0x20000] floatInit+2276
symbol: value
This section shows a Tcl procedure to traverse a linked list, printing information about each node.2 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 command panel would require prefacing the text above with the tcl command, and would require additional backslashes (one 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
1: 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.
2: Remember, though, that for interactive exploration of a list the structure browser (Figure 7-12) described in CrossWind Buttons is probably more convenient.