|
|
while ((c = *next++) != '\0')This will fix the looping problem.
$ cc -g -o macros main.c macro.cRun macros. This time macros dumps core:
$ macros <test1 Warning, TEST redefined Segmentation fault(coredump)
$ ls -lt core.* -rw-r--r-- 1 user 14237 32860 Jul 22 10:56 core.2088
$ debug debug> grab -c core.2088 macrosThe debugger displays the following:
Core image of macros (process p1) created CORE FILE [insert in macro.c] Signal: sigsegv Fault address: 0xc 65: node->definition = list;
You can see that it received the signal SIGSEGV in insert, while it was assigning defn to node->right. That's suspicious; assigning through a null pointer is a sure way to get a segmentation violation (and core dump) on most machines.
debug> print node 0x0
debug> list insert 22: { 23: struct macro_def *defn; 24: struct macro_def *node; 25: int val=0; 26: 27: if ((defn = (struct macro_def *)malloc( 28: sizeof(struct macro_def))) == 0) 29: { 30: (void) fprintf(stderr, "malloc failed!\n"); 31: exit(1);
debug> list /node 38: node = root;
It is set to the value of root. Find the value of root.
debug> print root 0x0
debug> print name, list 0x804abec 0x804ac0c
debug> print *name, *list { string="TEST" type=WORD (or 0) next=0x0 } { string="this" type=WORD (or 0) next=0x804ac1c }The name of the macro being defined is TEST.
debug> !cat test1The debugger displays the following:
define(TEST,this is a test) TEST define(X,TEST test TEST) X define(X,x) X define(A1,1 2 3 4) A1 MACSince this is the first time insert is called, it is reasonable that root is still zero. On the other hand, insert shouldn't be walking the tree looking for a match when there is nothing there. It would be more reasonable to just set root and return.
debug> list /root 80: node = root;
debug> l /The debugger displays the definition.
16: static struct macro_def *root;
debug> l / 38: node = root; debug> l / 80: node = root;This last list puts you back to where you started, with root being referenced twice, but never set. Since it is declared static, it could not have been set in some other file, so you have found the root cause of this bug.
A core file is a file produced by the operating system to record the process state at the time the process dies abnormally. When you grab a core file, debug will tell you where it died and the signal that made the operating system produce the core file. You can do anything with the program that you can do with a running program except make it run any further; you can look at the stack trace, print variables, list the source, and so on.
In addition to the grab command, you can tell debug directly on the command line that you want to examine a core file:
$ debug -c core.pid macros
Both the symbols and print commands are useful in different circumstances. symbols is useful for quickly examining several symbols, but it may give more information than you want, for example, when one of the variables is a large array or structure. print provides more control over what is printed and how the information is formatted, but you have to do more typing to get the information. The syntax of the print command is
print [-f format] expr, ...where expr may be a variable, a structure or array member, or any valid C expression.
If you do not give it a format string, debug will evaluate the expression and judge how to print the result based on the type of the expression.
debug> print val, name # integer and pointer to structure 0 0x804abec debug> print *name # dereference a pointer to a structure { string="TEST" type=WORD (or 0) next=0x0 } debug> print name->string[0] # single character 84 (or 'T') debug> p list[val] # an array element { string="this" type=WORD (or 0) next=0x804ac1c } debug> print list->next->next->string # character string "is"
format is a simplified version of the printf [see fprintf(3S)] format string. The format specifier %z stands for the debugger's default format style, and lets you print out entire structures or arrays at once:
debug> print -f "val = %d, *name = %z\n" val, *name val = 0, *name = { string="TEST" type=WORD (or 0) next=0x0 }However, if you supply a format string, you are also responsible for the new-line; otherwise you will get this:
debug> print -f"val = %d" val val = 0debug>
You can examine the source of the program you are debugging using the list command. There are three ways to tell list where to start printing:
debug> list 16 16: static struct macro_def *root; . . .a function name:
debug> list insert 22: { . . .or a line number or function name qualified with a file name:
debug> l main.c@main . . . debug> l macro.c@18 . . .The unqualified forms work only if the line or function is in the current file. If it is in a different file you have to use the qualified form. You can see what the current file is by printing the debugger variable %file:
debug> print %file "macro.c"
Use /expression/ to search forwards, ?expression? to search backwards. ? (or /) by itself will continue the search using the last regular expression given:
debug> l /look.*(/ 75: lookup(struct token *name) debug> l / 107: && (macro = lookup(tok_list)) != 0)
debug> print %list_file, %list_line "macro.c" 107 debug> set %list_file = "main.c" debug> set %list_line = 12 debug> list 12: error(const char *msg) . . . {
Normally list displays 10 lines at a time, but you can control the number of lines displayed with the -c option:
debug> l -c 3 insert 22: { 23: struct macro_def *defn; 24: struct macro_def *node;or by setting the debugger variable %num_lines:
debug> print %num_lines 10 debug> set %num_lines = 3 debug> l insert 22: { 23: struct macro_def *defn; 24: struct macro_def *node;All the examples assume that the source files are in the current directory. If they aren't, you have to tell debug how to find them with the -s (for source path) option on the command line:
$ debug -s macros/common:macros/mach -c core macrosor by setting the debugger variable %global_path:
debug> set %global_path = "macros/common"Setting %global_path overrides the source path set on the command line. In either case, the path is a colon-separated ordered list of directories that debug will look in to find the source files.