Running Linux, 5th Edition - Matthias Kalle Dalheimer [393]
imLoadF is a function that loads an image from a disk file. We know this function is not at fault (you'll have to trust us on that one), so we wish to step over it using the next command:
(gdb) next
20 outimage = laplacian_float(inimage);
(gdb)
Here, we are interested in tracing the suspicious-looking laplacian_float function, so we use the step command:
(gdb) step
laplacian_float (fim=0x0) at laplacian.c:21
21 i = 20.0;
(gdb)
Let's use the list command to get some idea of where we are:
(gdb) list
16 FloatImage laplacian_float(FloatImage fim) {
17
18 FloatImage mask;
19 float i;
20
21 i = 20.0;
22 mask=(FloatImage)imNew(IMAGE_FLOAT,3,3);
23 imRef(mask,0,0) = imRef(mask,2,0) = imRef(mask,0,2) = 1.0;
24 imRef(mask,2,2) = 1.0; imRef(mask,1,0) = imRef(mask,0,1) = i/5;
25 imRef(mask,2,1) = imRef(mask,1,2) = i/5; imRef(mask,1,1) = -i;
(gdb) list
26
27 return convolveFloatWithFloat(fim,mask);
28 }
(gdb)
As you can see, using list multiple times just displays more of the code. Because we don't want to step manually through this code, and we're not interested in the imNew function on line 22, let's continue execution until line 27. For this, we use the until command:
(gdb) until 27
laplacian_float (fim=0x0) at laplacian.c:27
27 return convolveFloatWithFloat(fim,mask);
(gdb)
Before we step into the convolveFloatWithFloat function, let's be sure the two parameters, fim and mask, are valid. The print command examines the value of a variable:
(gdb) print mask
$1 = (struct {...} *) 0xe838
(gdb) print fim
$2 = (struct {...} *) 0x0
(gdb)
mask looks fine, but fim, the input image, is null. Obviously, laplacian_float was passed a null pointer instead of a valid image. If you have been paying close attention, you noticed this as we entered laplacian_float earlier.
Instead of stepping deeper into the program (as it's apparent that something has already gone wrong), let's continue execution until the current function returns. The finish command accomplishes this:
(gdb) finish
Run till exit from #0 laplacian_float (fim=0x0) at laplacian.c:27
0x28c0 in main () at trymh.c:20
20 outimage = laplacian_float(inimage);
Value returned is $3 = (struct {...} *) 0x0
(gdb)
Now we're back in main. To determine the source of the problem, let's examine the values of some variables:
(gdb) list
15 FloatImage outimage;
16 BinaryImage binimage;
17 int i,j;
18
19 inimage = (FloatImage)imLoadF(IMAGE_FLOAT,stdin);
20 outimage = laplacian_float(inimage);
21
22 binimage = marr_hildreth(outimage);
23 if (binimage = = NULL) {
24 fprintf(stderr,"trymh: binimage returned NULL\n");
(gdb) print inimage
$6 = (struct {...} *) 0x0
(gdb)
The variable inimage, containing the input image returned from imLoadF, is null. Passing a null pointer into the image manipulation routines certainly would cause a core dump in this case. However, we know imLoadF to be tried and true because it's in a well-tested library, so what's the problem?
As it turns out, our library function imLoadF returns NULL on failure—if the input format is bad, for example. Because we never checked the return value of imLoadF before passing it along to laplacian_float, the program goes haywire when inimage is assigned NULL. To correct the problem, we simply insert code to cause the program to exit with an error message if imLoadF returns a null pointer.
To quit gdb, just use the command quit. Unless the program has finished execution, gdb will complain that the program is still running:
(gdb) quit
The program is running. Quit anyway (and kill it)? (y or n) y
papaya$
In the following sections we examine some specific features provided by the debugger, given the general picture just presented.
Examining a Core File
Do you hate it when a program crashes and spites you again by leaving a 20-MB core file in your working directory, wasting much-needed space? Don't be so quick to delete that core file; it can be very helpful. A core file