Running Linux, 5th Edition - Matthias Kalle Dalheimer [396]
#2 0x13c6 in stream_drawimage (wgt=0x38330000, sn=4)\
at stream_display.c:94
#3 0x1497 in stream_refresh_all () at stream_display.c:116
#4 0x49c in control_update_all () at control_init.c:73
#5 0x224 in play_timeout (Cannot access memory at address 0x602b7676.
(gdb)
This is a list of stack frames for the process. The most recently called function is frame 0, which is the "function" _end in this case. Here, we see that play_timeout called control_update_all, which called stream_refresh_all, and so on. Somehow, the program jumped to _end, where it crashed.
However, _end is not a function; it is simply a label that specifies the end of the process data segment. When a program branches to an address such as _end, which is not a real function, it is a sign that something must have caused the process to go haywire, corrupting the call stack. (This is known in hacker jargon as "jumping to hyperspace.") In fact, the error Cannot access memory at address 0x602b7676 is another indication that something bizarre has occurred.
We can see, however, that the last "real" function called was stream_drawimage, and we might guess that it is the source of the problem. To examine the state of stream_drawimage, we need to select its stack frame (frame number 2), using the frame command:
(gdb) frame 2
#2 0x13c6 in stream_drawimage (wgt=0x38330000, sn=4)\
at stream_display.c:94
94 XCopyArea(mydisplay,streams[sn].frames[currentframe],\
XtWindow(wgt),
(gdb) list
91
92 printf("CopyArea frame %d, sn %d, wid %d\n",currentframe,sn,wgt);
93
94 XCopyArea(mydisplay,streams[sn].frames[currentframe],\
XtWindow(wgt),
95 picGC,0,0,streams[sn].width,streams[sn].height,0,0);
(gdb)
Well, not knowing anything else about the program at hand, we can't see anything wrong here, unless the variable sn (being used as an index into the array streams) is out of range. From the output of frame, we see that stream_drawimage was called with an sn parameter of 4. (Function parameters are displayed in the output of backtrace, as well as whenever we change frames.)
Let's move up another frame, to stream_refresh_all, to see how stream_display was called. To do this, we use the up command, which selects the stack frame above the current one:
(gdb) up
#3 0x1497 in stream_refresh_all () at stream_display.c:116
116 stream_drawimage(streams[i].drawbox,i);
(gdb) list
113 void stream_refresh_all(void) {
114 int i;
115 for (i=0; i<=numstreams; i++) {
116 stream_drawimage(streams[i].drawbox,i);
117
(gdb) print i
$2 = 4
(gdb) print numstreams
$3 = 4
(gdb)
Here, we see that the index variable i is looping from 0 to numstreams, and indeed i here is 4, the second parameter to stream_drawimage. However, numstreams is also 4. What's going on?
The for loop on line 115 looks funny; it should read as follows:
for (i=0; i The error is in the use of the <= comparison operator. The streams array is indexed from 0 to numstreams-1, not from 0 to numstreams. This simple off-by-one error caused the program to go berserk. As you can see, using gdb with a core dump allows you to browse through the image of a crashed program to find bugs. Never again will you delete those pesky core files, right? Debugging a Running Program gdb can also debug a program that is already running, allowing you to interrupt it, examine it, and then return the process to its regularly scheduled execution. This is very similar to running a program from within gdb, and there are only a few new commands to learn. The attach command attaches gdb to a running process. In order to use attach you must also have access to the executable that corresponds to the process. For example, if you have started the program pgmseq with process ID 254, you can start up gdb with papaya$ gdb pgmseq and once inside gdb, use the command (gdb) attach 254 Attaching program `/home/loomer/mdw/pgmseq/pgmseq', pid 254 _ _select (nd=4, in=0xbffff96c, out=0xbffff94c, ex=0xbffff92c, tv=0x0) at _ _select.c:22 _ _select.c:22: No such file or directory. (gdb)