|
|
node->left = defn;
$ cc -g -o macros main.c macro.c main.c: macro.c:You are now ready to test out the more complicated case: macros with parameters.
$ macros <test2The debugger displays the following:
a andAnother error is found. Since the program seems to work correctly for parameterless macros, the bug is probably in either getargs, which collects the macro's actual arguments, or in expand where it does the substitution.
debug> create macrosThe debugger displays the following:
New program macros (process p1) created HALTED p1 [main in main.c] 308: for (i = 1; i < argc; ++i)Type in the following:
debug> stop getargsThe debugger displays the following:
EVENT [1] assignedSince you did not redirect macros' input, this time when you let it run the program will wait for you to type in something.
debug> run
define(a1,$1 and $2)The debugger displays the following:a1(a,b)
STOP EVENT TRIGGERED: getargs in p1 [getargs in main.c] 234: struct arglist *head = 0;If you look at the listing of main.c, you will see that the primary action in getargs is looping on a list of input tokens.
debug> stop 250The debugger displays the following:
EVENT [2] assignedRun the program:
debug> runThe debugger displays the following:
STOP EVENT TRIGGERED: 250 in p1 [getargs in main.c] 250: if (tok->type == COMMA && !parens)Print out the first token:
debug> print *tokThe debugger displays the following:
{ string="a" type=WORD (or 0) next=0x804ac90 }Print out the second token in the list:
debug> print *tok->nextThe debugger displays the following:
{ string=NULL type=COMMA (or 4) next=0x804aca0 }The first and second tokens in the list are just what you expected, so let it continue:
debug> runThe debugger displays the following:
a and
Process p1 has exited No more processes.What happened to the rest of the list of tokens? It should have stopped at the top of the loop on each token.
debug> create macros <test2The debugger displays the following:
New program macros (process p2) created HALTED p2 [main in main.c] 308: for (i = 1; i < argc; ++i)Run the program:
debug> runThe debugger displays the following:
STOP EVENT TRIGGERED: getargs in p2 [getargs in main.c] 234: struct arglist *head = 0;P
debug> delete 2 debug> b 250||289 print *tok
The debugger displays the following:
EVENT [3] assigned
debug> runThe debugger displays the following:
STOP EVENT TRIGGERED: 250 || 289 in p2 [getargs in main.c] 250: if (tok->type == COMMA && !parens) { string="a" type=WORD (or 0) next=0x804ac90 }
debug> runThe debugger displays the following:
STOP EVENT TRIGGERED: 250 || 289 in p2 [getargs in main.c] 289: *inlist = tok->next; { string="a" type=WORD (or 0) next=0x0 }It looks like the token's next pointer got stepped on somewhere; that would explain why it left the loop after only one token.
debug> createThe debugger displays the following:
p2 killed macros <test2 New program macros (process p3) created HALTED p3 [main in main.c] 308: for (i = 1; i < argc; ++i)
debug> runThe debugger displays the following:
STOP EVENT TRIGGERED: getargs in p3 [getargs in main.c] 226: struct arglist *head = 0;
debug> runThe debugger displays the following:
STOP EVENT TRIGGERED: 250 || 289 in p3 [getargs in main.c] 242: if (tok->type == COMMA && !parens) { string="a" type=WORD (or 0) next=0x804ac90 }
debug> stop *tok->next { print *tok } EVENT [4] assigned
debug> runThe debugger displays the following:
Warning: Stepping p3 to watch stop expression STOP EVENT TRIGGERED: *tok->next in p3 [getargs in main.c] 289: *inlist = tok->next; { string="a" type=WORD (or 0) next=0x0 }
debug> list -c 3 287The debugger displays the following:
287: argtail = tok; 288: argtail->next = 0; 289: *inlist = tok->next;
Setting a watchpoint tells debug to stop the program when a variable changes value. This is just another form of stop event. There are three types of stop events, each of which has some action that will make the debugger notice the event. When the action occurs, the debugger evaluates the entire stop expression, and if true, stops the process and executes any associated commands. The three types of stop events are:
Watchpoints can be particularly helpful in tracking down stray pointer problems. If you have a variable that is being overwritten but you aren't sure by what, set a watchpoint on the variable and debug will stop the process when the variable is overwritten. Keep in mind, however, that watchpoints can be expensive. Not all machines have the hardware support needed to make watchpoints efficient, and the debugger must single-step the program and constantly check the watchpoint until it changes. Also, it may single step if the variable is allocated to a register instead of a memory location. As you may guess, this can be slow. Even on machines with hardware support for watchpoints, the hardware usually can only watch a few locations at a time, and setting too many watchpoints can also slow things down. Used sparingly, however, watchpoints can be indispensable, and debug will at least warn you (with WARNING: Stepping p2 to watch stop expression) when it is using the slower method.
The examples so far have all set breakpoints on global functions or on static functions and lines in the current compilation unit. To set a breakpoint on a static function or line in a different compilation unit, you have to use a qualified location:
debug> stop main.c@gettok . . . debug> stop macro.c@16 . . .
debug> stop foo || *ptr ... debug> stop getargs && malloc ... debug> stop 229 && (a > b) ...In the first example, debug will set a breakpoint on the function foo and a watchpoint on ptr; whichever event trigger happens first will make the process stop.
The second example is more interesting. For locations that refer to function names, the expression is true as long as the function is active (until the process returns from that function). Here the debugger will stop the process in malloc only when it is called from the function getargs. This is a handy way to debug a function that is called from several places but shows up a problem in only one area.
For locations that refer to addresses or line numbers, the expression is true only when the process is at that address or the beginning of the line. In the third example, the debugger will stop the process when it reaches line 229 only if a is greater than b.