|
|
while(fgets(buffer, BUFSIZ, infile) != 0)
$ cc -g -o walk walk.c $ walk src src/file1 src/testfile
However, when you put them together, something breaks:
$ walk src | sgetThe debugger displays the following:
Cannot read src/file1
$ debug
debug> create walk src | sgetThe debugger displays the following:
New program walk (process p1) created HALTED p1 [main in walk.c] 47: int exit_code=0; New program sget (process p2) created HALTED p2 [main in sget.c] 132: (void)signal(SIGHUP,handler);
debug> stop walk.c@37The debugger displays the following:
EVENT [1] assigned
debug> stop -p sget sget.c@copyThe debugger displays the following:
EVENT [2] assigned debug> stop -p sget sget.c@getThe debugger displays the following:
EVENT [3] assigned
debug> run -b -p p2
When you type run without a process list and without -b, it runs the current process and waits for it to stop, just as in all the previous debugging sessions:
debug> runThe debugger displays the following:
STOP EVENT TRIGGERED: walk.c@37 in p1 [walk in walk.c] 37: (void) printf("%s \n", fullpath);
If you print the string in fullpath, it looks reasonable:
debug> print fullpath "src/file1"The only thing that looks odd is the extra blank between the file name and the new-line in the call to printf. You will need to find out if this could be breaking sget.
debug> runThe debugger displays the following:
STOP EVENT TRIGGERED: sget.c@copy in p2 [copy in sget.c] 82: if ((infile = fopen(path, "r")) == 0) STOP EVENT TRIGGERED: walk.c@37 in p1 [walk in walk.c] 37: (void) printf("%s \n", fullpath);This time when you typed run you got two event notifications, one from each process, even though you only ran p1 (walk). p2 (sget) was already running, waiting for input from p1. When p1 ran, it wrote to the pipe, p2 read from the pipe, and reached the breakpoint. You can see from ps that both processes are now stopped:
debug> psThe debugger displays the following:
Program ID Pid Thread State Function Location Command sget p2 2223 -1 stopped copy sget.c@82 sget *walk p1 2221 -1 stopped walk walk.c@37 walk src
debug> set %program = sget Current process is now p2, program sget(Setting %proc to p2 would also have worked.) When you do a stack trace, it will show you the stack for sget:
debug> stack Stack Trace for p2, Program sget *[0] copy(path="src/file1 ", newfile="file1 ") [sget.c@82] [1] main(0x1,0x80479a4, 0x80479ac) [sget.c@155] [2] _start() [0x8048662]
Of course, you can still look at anything in walk with -p:
debug> stack -p walk Stack Trace for p2, Program walk *[0] walk(path="src", dir=0x8049fb0) [walk.c@37] [1] main(argc=2, argv=0x804799c, 0x80479a8) [walk.c@63] [2] _start() [0x804856e]
You can see from the stack trace that the variable path looks just like the line walk wrote (minus the new-line). The program stopped right before a call to fopen:
debug> list -c 3 82: if ((infile = fopen(path, "r")) == 0) 83: { 84: (void) fprintf(stderr, "Cannot read %s\n", path);
debug> step STEPPED p2 [copy in sget.c] 84: (void) fprintf(stderr, "Cannot read %s\n", path);That trailing blank seems more suspicious. You need to test sget after deleting this blank. You can test it quickly without editing and recompiling as follows:
debug> set path[9] = '\0' debug> print path "src/file1"
debug> jump 82 debug> step STOP EVENT TRIGGERED: sget.c@copy in p2 [copy in sget.c] 82: if ((infile = fopen(path, "r")) == 0) debug> step STEPPED p2 [copy in sget.c] 87: (void) remove(newfile);
The jump command lets you change the program counter. The next time you let the program run or step it will start at the new location, not from the point where it stopped last.
jump can occasionally be useful, but it is also dangerous, and should be used with extreme caution. You can jump to any location in your program, but you are asking for trouble if you jump out of your current function; debug will not attempt to fix up the stack. Even jumping to another location within one function can be dangerous; you may not be aware of all the side affects of code you jump over, and jumping into or out of blocks may leave your local variables in a funny state. This is especially true in debugging C++ code; it is easy to forget which variables invoke constructors and destructors.
Most of the debugger's commands take an option (-p) to specify a process list. With a process list, you can make the command apply to any or all of the controlled objects, without having to constantly set %proc or %thread. A process list may include:
(including %proc). The process identifier may be the debugger's name (p1, p2, etc.) or the system level process id.
If the process contains more than one thread, the command will be applied to each thread in the process.
debug> ps Program ID Pid Thread State Function Location Command sget p2 2223 -1 running sget *walk p1 2221 -1 stopped 0x8000afe0 walk src debug> stop -p 2223 main {print base_name} EVENT [2] assigned
This may be either the debugger variable %thread or an identifier of the form pn.n (p1.1, p1.2, p2.1).
(including %program). The command will be applied to each process and thread making up that program.
debug> stop -p sget sget.c@82 EVENT [3] assigned
A list containing any combination of process names, thread names and program names. The command will be applied to each entry in the list in turn.
debug> events -p %proc,sget Events for p1, program walk ID Type Count Condition Command List [0001] ONSTOP stack Events for p2, program sget ID Type Count Condition Command List [0002] STOP 0 main { print basen... [0003] STOP 0 sget.c@82
all objects under debugger control.
debug> events -p all Events for p2, program sget ID Type Count Condition Command List [0002] STOP 0 main { print basen... [0003] STOP 0 sget.c@82 Events for p1, program walk ID Type Count Condition Command List [0001] ONSTOP stackIf you don't give a command a process list, the command (with a few exceptions) will apply to the current object only. The exceptions are the commands that create events; these apply to the current program, not process or thread. If you have two processes forked from one program and create an event, that event will apply to
debug> ps Program ID Pid State Function Location Command *a.out p1 2316 Stopped _fork 0x8001bc49 a.out a.out p2 2319 Stopped _fork 0x8001bc49 a.out debug> stop fprintf EVENT [1] assigned debug> stop -p p2 open EVENT [2] assigned debug> stop -p p1,p2 Events for p1, program a.out ID Type Count Condition Command List [0001] STOP 0 fprintf Events for p2, program a.out ID Type Count Condition Command List [0001] STOP 0 fprintf [0002] STOP 0 openIf you re-create the program, the old events that applied to the entire program will be reset in the new program, but events that applied to only one process will not be reset. The same is true when a process forks; events applied to the program will be copied, events applied only to the parent process or one of its threads will not. (Of course, if the process calls exec(S), none of the existing events apply to the new program.) If the process creates a new thread, events that apply to the entire process or program will be copied in the new thread. Events that apply only to a single thread will not be copied.
Foreground and background processes in the debugger are similar to foreground and background processes at the shell level. If you run a process or thread in the foreground, debug waits until the process stops before prompting you for another command. If you run several processes or threads at once (say with run -p all), all of them must stop before you will get another prompt. If you start one or more processes running in the background, debug won't wait for any of them to stop before giving you a prompt. When anything running in the background stops, debug will let you know, but won't give you a prompt if you have something else running in the foreground.
debug's default behavior is to run everything in the foreground. You may change the default by setting the debugger variable %wait to background (the values no and 0 also mean background mode):
debug> print %wait "foreground" debug> set %wait no debug> run -p p2 debug> ps Program ID Pid Thread State Function Location Command sget p2 2223 -1 running sget *walk p1 2221 -1 stopped 0x800afe0 walk srcSetting %wait back to foreground (or yes or 1) will restore the normal behavior. Whichever mode you are in, you can override the default for individual run and step commands with the -f or -b options (foreground and background, respectively).
Foreground mode is most useful when you are debugging only one object. Background mode is more useful when you are debugging several objects. If you know you will be debugging multiple objects, you may want to set %wait to background when you start out.
If a process is doing something unexpected in foreground mode, hit interrupt to suspend the process and regain control. Hitting interrupt won't do anything to a process running in the background. To stop a background process, use the halt command:
debug> halt -p p2 debug> SUSPENSED p2 [_read] 0x8000ef6b (_read+12:) jae +0x0a <8000ef77> [ noerror ]