|
|
if (!root) { root = defn; return; }
$ macros -DMAC=123 <test1This time, it runs to completion, and for the most part gives the expected results, but what happened to the definition of A1? (A1 should have been replaced with 1 2 3 4.)this is a test
this is a test test this is a test Warning, X redefined
x A1 123 $
$ debug debug> create macros -DMAC=123 <test1 >test.out New program macros (process p1) created HALTED p1 [main in main.c] 308: for (i = 1; i < argc; ++i)
debug> stop lookup EVENT [1] assigned debug> run STOP EVENT TRIGGERED: lookup in p1 [lookup in macro.c] 86: node = root;
debug> print name->string "TEST"It may have to call lookup several times before it calls it with A1; typing print name->string and run every time it gets to lookup could get tedious quickly. You can tell debug to do that automatically whenever the stop event triggers (the program hits the breakpoint). You can also create a debugger variable to track the number of times lookup is called:
debug> set $ncalls = 1 debug> onstop { print name->string, ++$ncalls; run } EVENT [2] assigned
debug> set %verbose = quiet
debug> run "this" 2 "is" 3 "a" 4 "test" 5 "X" 6 "TEST" 7 "this" 8 "is" 9 "a" 10 "test" 11 "test" 12 "TEST" 13 "this" 14 "is" 15 "a" 16 "test" 17 Warning, X redefined "X" 18 "x" 19 "A1" 20 "MAC" 21 Process p1 has exited No more processes.
debug> create macros -DMAC=123 <test1 >test.out New program macros (process p2) created HALTED p1 [main in main.c] 308: for (i = 1; i < argc; ++i)
debug> set %verbose = allThe events that you created the first time through are still there, as you can see with the events command:
debug> eventsThe debugger displays the following:
Events for p2, program macros ID Type Count Condition Command List [0001] STOP 0 lookup [0002] ONSTOP { print name->st...You don't need those events this time, so use delete -a to delete them:
debug> delete -a
debug> stop -c 20 lookup EVENT [3] assigned debug> run Warning, X redefined STOP EVENT TRIGGERED: lookup in p2 [lookup in macro.c] 86: node = root;
debug> print *name { string="A1" type=WORD (or 0) next=0x0 }
debug> stepThe debugger displays the following:
STEPPED p2 [lookup in macro.c] 87: while (node)Check node:
debug> print *nodeThe debugger displays the following:
{ name=0x804abe0 definition=0x804ac00 left=0x0 right=0x804af24 }Check node->name:
debug> print *node->nameThe debugger displays the following:
{ string="MAC" type=WORD (or 0) next=0x0 }debug> step STEPPED p2 [lookup in macro.c] 96: } debug> step STEPPED p2 [lookup in macro.c] 89: val = strcmp(name->string, node->name->string);
debug> step STEPPED p2 function [lookup in macro.c] 90: if (val < 0) debug> print val -1
debug> step -c 3 STEPPED p2 function [lookup in macro.c] 91: node = node->left; STEPPED p2 function [lookup in macro.c] 96: } STEPPED p2 function [lookup in macro.c] 97: return 0;The problem is apparently further back in insert, when it was building the tree.
debug> create p2 killed macros -DMAC=123 <test1 >test.out HALTED p2 [main in main.c] 308: for (i = 1; i < argc; ++i) debug> delete 3 debug> stop -c 5 insert EVENT [4] assigned
debug> run STOP EVENT TRIGGERED: insert in p3 [insert in macro.c] 25: int val=0; debug> print name->string "A1"
debug> run -u 44 HALTED p3 [insert in macro.c] 44: node = root; debug> step STEPPED p3 [insert in macro.c] 47: val = node ? strcmp(name->string, node->name->string) : 0; debug> step STEPPED p3 [insert in macro.c] 48: if (val < 0)
The value returned by strcmp should be -1, and it should go off down the left branch, just as in lookup:
debug> print val -1 debug> step STEPPED p3 [insert in macro.c] 50: if (!node->left) debug> step STEPPED p3 [insert in macro.c] 52: node->right = defn;
create accepts a command line, rather than just a simple program name, so you can give the program arguments, redirect I/O, and even create pipes. create gets the program ready to run, but does not actually start it running; run or step set the program in motion. Like grabbing a process, you can also create a program directly from the command line:
$ debug macros -DMAC=123 \<test1 \>test.out New program macros (process p1) created HALTED p1 [main in main.c] 308: for (i = 1; i < argc; ++i)You must be careful to escape or quote I/O redirection operators; otherwise the shell will see them and redirect debug's I/O instead. You can also pass options to the controlled program from the command line; debug handles any options that come before the program name, but any that come after it are passed on to the program unchanged.
create without any arguments will re-create the last command line you gave it and echo the command line so you can check it:
debug> create macros -DMAC=123 <test1 >test.out New program macros (process p2) created HALTED p2 [main in main.c] 308: for (i = 1; i < argc; ++i)If the program from the last create is still around, debug will kill it before creating the new one. Any events already defined will still apply.
By default, create suspends the program in main; but you can tell it to stop at a different location by using the -l option.
Debugger variables are special variables that are maintained by the debugger instead of by the program being debugged. All debugger variables start with either a percent sign (%) or a dollar sign ($) so they won't be confused with program variables, but can be used in print commands and as arguments to several other commands just like program variables.
The debugger variables that start with % are built-in variables that describe the current debugger state and allow you to customize certain aspects of debug's behavior. You can change the value of some of these debugger variables (like %verbose or %frame) directly with set but others (including %file and %line) are read-only. They are set by debug when an event triggers or indirectly by setting certain other variables. You can examine their values but you cannot set them directly. symbols -dv (-d for debugger variables) will show you the current values of the built-in debugger variables.
The debugger variables that start with $ are user-defined variables.
These variables are similar to shell variables.
When you start up debug, the shell variables currently exported in your environment will
make up the initial set of user-defined variables in the debugger.
symbols -uv (-u for user)
will show you the
current values of the user-defined variables.
User-defined variables are useful in several different ways:
debug> set $ncalls = 0 debug> stop lookup { set $ncalls = $ncalls + 1; run }
debug> set $i = 5; while ($i < 10) { print a[$i], $i++ }
debug> set $ROOT = "/var/tmp" debug> export $ROOT debug> create progNote that in the export command, you have to type $variable, but the name will be exported to the environment without the $.
Setting a breakpoint is just one way to create an event. There are five commands that define different types of events:
debug> stop Events for p1, program macros ID Type Count Condition Command List [0001] STOP 0 lookup
debug> events Events for p1, program macros ID Type Count Condition Command List [0001] STOP 0 lookup [0002] ONSTOP { print name->st...Normally, debug prints only the beginning of the associated command list. Typing events event_num will force it to display the entire command list:
debug> events 2 Events for p1, program macros ID Type Count Condition [0002] ONSTOP Object list: p1 Command list: { print name->string,++$ncalls ; run }The event numbers are also used as arguments to several other commands: delete, disable, enable. delete gets rid of an event permanently:
debug> delete 2 debug> events Events for p1, program macros ID Type Count Condition Command List [0001] STOP 0 lookupdisable does not get rid of the event but the event is ignored until you turn it on again with enable. Disabled events are indicated with a D following the event id:
debug> disable 1 debug> events Events for p1, program macros ID Type Count Condition Command List [0001] D STOP 0 lookup
When an event triggers, debug will
In this example, there is a command (stack) associated with the stop event and an onstop event. When the process hits the breakpoint debug will do both commands:
debug> stop lookup stack EVENT [1] assigned debug> onstop print name->string EVENT [2] assigned debug> run STOP EVENT TRIGGERED: lookup in p1 [lookup in macro.c] 86: node = root; Stack Trace for p1, Program macros *[0] lookup(name=0x804a980) [macro.c@86] [1] main(argc=2, argv=0x804797c, 0x8047988) [main.c@342] [2] _start() [0x80485a2] "TEST"
Both stop and syscall take a -c n (-c for count) option to make debug continue running the process until the event occurs the n-th time. In Session 3, you created a stop event with the command stop -c 20 lookup. This resulted in the process going the first 19 times it got to lookup. If you let the program in Session 3 run again, however, it will stop again the next time it gets to lookup, not after skipping another 19 calls. This option was based on an assumption about the way people tend to use debuggers: that you would use the count option to skip over many preliminary loop iterations or function calls, but once you get to where you think the bug is, you will probably want to examine that iteration and the next (and so on) intensively.
However, if you want to skip a number of events again, you can reset the count with the change command:
change event_number -c countFor more on the change command, see ``Change Command'' under ``Technical tips''.
run and step are the two ways to get from one place to another in your program. run lets the program execute normally until an event triggers or until the program exits. step provides more control by executing one statement and stopping. There are several variations on the basic run and step commands:
Neither run -u nor run -r guarantees that the program will ever get to the target location; if your program takes an unexpected execution path, it may exit or simply bypass location.
debug> step STEPPED p1 [main in main.c] 333: token = gettok(1); debug> step STEPPED p1 [gettok in main.c] 160: if (!next_tok)If you don't want to step through the lower level function, use step -o:
debug> step STEPPED p1 [main in main.c] 333: token = gettok(1); debug> step -o STEPPED p1 [main in main.c] 334: while (token)
If you forget and accidentally step into a function you are not interested in, use run -r to get out.
debug> step STEPPED p1 [main in main.c] 333: token = gettok(1); debug> stop 173 EVENT [1] assigned debug> step -o STOP EVENT TRIGGERED: 168 in p1 [gettok in main.c] 173: token = next_tok;You can also force the program to stop by hitting interrupt; that will suspend the process (possibly in the middle of a statement or library function) and give you a debugger prompt.