A gdb Example
In this section we will introduce gdb by showing a script file record of its use on an actual program.In order to distinguish between line numbers in the scriptfile from line numbers within the C source files, I have placed a `g' at the beginning of each of the former. For example, Line g56 means Line 56 within the scriptfile, not Line 56 within one of the C source files.)
First, use cat to show the program source files:
g2 mole.matloff% cat Main.c g3 g4 g5 /* prime-number finding program g6 g7 will (after bugs are fixed) report a list of all primes which are g8 less than or equal to the user-supplied upper bound g9 g10 riddled with errors! */ g11 g12 g13 g14 #include "Defs.h" g15 g16 g17 int Prime[MaxPrimes], /* Prime[I] will be 1 if I is prime, 0 otherwi */ g18 UpperBound; /* we will check all number up through this one for g19 primeness */ g20 g21 g22 main() g23 g24 { int N; g25 g26 printf("enter upper bound\n"); g27 scanf("%d",UpperBound); g28 g29 Prime[2] = 1; g30 g31 for (N = 3; N <= UpperBound; N += 2) g32 CheckPrime(); g33 if (Prime[N]) printf("%d is a prime\n",N); g34 } g35 g36 mole.matloff% g37 mole.matloff% g38 mole.matloff% g39 mole.matloff% cat CheckPrimes.c g40 cat: CheckPrimes.c: No such file or directory g41 mole.matloff% cat CheckPrime.c g42 g43 g44 #include "Defs.h" g45 #include "Externs.h" g46 g47 g48 CheckPrime(K) g49 int K; g50 g51 { int J; g52 g53 /* the plan: see if J divides K, for all values J which are g54 g55 (a) themselves prime (no need to try J if it is nonprime), and g56 (b) less than or equal to sqrt(K) (if K has a divisor larger g57 than this square root, it must also have a smaller one, g58 so no need to check for larger ones) */ g59 g60 J = 2; g61 while (1) { g62 if (Prime[J] == 1) g63 if (K % J == 0) { g64 Prime[K] = 0; g65 return; g66 } g67 J++; g68 } g69 g70 /* if we get here, then there were no divisors of K, so it is g71 prime */ g72 Prime[K] = 1; g73 } g74 g75 mole.matloff% g76 mole.matloff% g77 mole.matloff% g78 mole.matloff% cat Defs.h g79 g80 #define MaxPrimes 50 g81 mole.matloff% cat Externs.h g82 g83 g84 #include "Defs.h" g85 g86 g87 extern int Prime[MaxPrimes];
The comments in Lines g5-g10 state what the program goal is, i.e. finding prime numbers.
OK, let's get started. First we compile the program:
g92 mole.matloff% make g93 cc -g -c Main.c g94 cc -g -c CheckPrime.c g95 "CheckPrime.c", line 31: warning: statement not reached g96 cc -g -o FindPrimes Main.o CheckPrime.o
The warning concerning Line 31 of CheckPrime.c sounds ominous (and it is), but let's ignore it, and see what happens. Let's run the program:
g100 mole.matloff% FindPrimesg101 enter upper boundg102 20g103 Segmentation fault
Well, this sounds scary, but actually it usually is the easiest type of bug to fix. The first step is to determine where the error occurred; gdb will do this for us: We enter gdb and then re-run the program, so as to reproduce the error:
g104 mole.matloff% gdb FindPrimesg105 GDB is free software and you are welcome to distribute copies of itg106 under certain conditions; type "show copying" to see the conditions.g107 There is absolutely no warranty for GDB; type "show warranty" for detailsg108 GDB 4.7, Copyright 1992 Free Software Foundation, Inc...
OK, gdb is now ready for my command (it indicates this by giving me a special prompt, which looks like this:
(gdb)
I now invoke gdb's r command, to run the program (if the program had any command-line arguments, I would have typed them right after the `r'):
g109 (gdb) rg110 Starting program: /tmp_mnt/lion/d/guest/matloff/tmp/FindPrimes g111 enter upper boundg112 20g113 g114 Program received signal 11, Segmentation faultg115 0xf773cb88 in _doscan ()
So, the error occurred within the function _doscan(). This is not one of my functions, so it must have been called by one of the C library functions which I am using, i.e. printf() or scanf(). Given the name _doscan, it does sound like it must have been the latter, but at any rate, the way to find out is to use gdb's bt(``backtrace'') command, to see where _doscan() was called from:
g116 (gdb) btg117 #0 0xf773cb88 in _doscan ()g118 #1 0xf773c2e8 in _doscan ()g119 #2 0xf773b9dc in scanf ()g120 #3 0x22dc in main () at Main.c:25
Aha! So it was indeed called from scanf(), which in turn was called from main(), at Line 25.
Now since scanf() is a C library function, it presumably is well debugged already, so the error was probably not in scanf(). So, the error must have been in our call to scanf() on Line 25 of Main.c.
Let's take a look at that latter call. To do so, we use gdb's l (''list'') command, to list some lines of the file Main.c at and arround the line which led to the error:
g121 (gdb) l Main.c:25g122 20 main()g123 21 g124 22 { int N;g125 23 g126 24 printf("enter upper bound\n");g127 25 scanf("%d",UpperBound);g128 26 g129 27 Prime[2] = 1;g130 28 g131 29 for (N = 3; N <= UpperBound; N += 2)
Yep, a famous ``C-learner's error''-we forgot the ampersand in before UpperBound! Line 25 of Main.c should have been
scanf(``%d'',&UpperBound);
So, in another window (hopefully an X11 window, but if you are just using a text-based terminal, you can use the GNU screen program to get windows), we will fix line 25 of Main.c, and recompile. Note that we do not leave gdb while doing this, since gdb takes a long time to load. In order to do this, though, we must first tell gdbto relinquish our executable file:
(gdb) kill
(Otherwise when we tried to recompile our program, the ld linker would tell us that the executable file is ``busy'' and thus cannot be replaced.)
After fixing and recompiling Main.c, the next time we give gdb the run command
(gdb) r
gdb will automatically load the newly-recompiled executable for our program (it will notice that we recompiled, because it will see that our .c source file is newer than the executable file). Note that we do not have to state the command-line arguments (if any), because gdb remembers them from before. It also remembers our breakpoints, so we do not have to set them again. (And gdb will automatically update the line numbers for those breakpoints, adjusting for whatever line-number changes occurred when we modified the source file.)
Main.c is now the following:
g137 mole.matloff% cat Main.cg138 g139 g140 /* prime-number finding programg141 g142 will (after bugs are fixed) report a list of all primes which areg143 less than or equal to the user-supplied upper boundg144 g145 riddled with errors! */g146 g147 g148 g149 #include "Defs.h"g150 g151 g152 int Prime[MaxPrimes], /* Prime[I] will be 1 if I is prime, 0 otherwi */g153 UpperBound; /* we will check all number up through this one forg154 primeness */g155 g156 g157 main()g158 g159 { int N;g160 g161 printf("enter upper bound\n");g162 scanf("%d",&UpperBound);g163 g164 Prime[2] = 1;g165 g166 for (N = 3; N <= UpperBound; N += 2)g167 CheckPrime();g168 if (Prime[N]) printf("%d is a prime\n",N);g169 }
Now we run the program again (not in gdb, though we do still have gdb open in the other window):
g174 mole.matloff% !Fg175 FindPrimesg176 enter upper boundg177 20g178 Segmentation fault
Don't get discouraged! Let's see where this new seg fault is occurring.
g188 (gdb) rg189 Starting program: /tmp_mnt/lion/d/guest/matloff/tmp/FindPrimes g190 enter upper boundg191 20g192 g193 Program received signal 11, Segmentation faultg194 0x2388 in CheckPrime (K=1) at CheckPrime.c:21g195 21 if (Prime[J] == 1)
Now, remember, as mentioned earlier, one of the most common causes of a seg fault is a wildly-erroneous array index. Thus we should be highly suspicious of J in this case, and should check what its value is, using gdb's p (``print'') command:
g207 (gdb) p Jg208 $1 = 4024
Wow! Remember, I only had set up the array Prime to contain 50 integers, and yet here we are trying to access Prime[4024]!
So, gdb has pinpointed the exact source of our error-the value of J is way too large on this line. Now we have to determine why J was so big. Let's take a look at the entire function, using gdb's l command:
g196 (gdb) l CheckPrime.c:12 g53 /* the plan: see if J divides K, for all values J which are g54 g55 (a) themselves prime (no need to try J if it is nonprime), and g56 (b) less than or equal to sqrt(K) (if K has a divisor larger g57 than sqrt(K), it must also have a smaller one, g58 so no need to check for larger ones) */ g59 g200 19 J = 2;g201 20 while (1) {g202 21 if (Prime[J] == 1)g203 22 if (K % J == 0) {g204 23 Prime[K] = 0;g205 24 return;g206 25 }
Look at the comments in Lines g56-g58. We were supposed to stop searching after J got to sqrt(K). Yet you can see in Lines g201-g206 that we never made this check, so J just kept growing and growing, eventually reaching the value 4024 which triggered the seg fault.
After fixing this problem, the new CheckPrime.c looks like this:
g214 mole.matloff% cat CheckPrime.cg215 g216 g217 #include "Defs.h"g218 #include "Externs.h"g219 g220 g221 CheckPrime(K)g222 int K;g223 g224 { int J;g225 g226 /* the plan: see if J divides K, for all values J which areg227 g228 (a) themselves prime (no need to try J if it is nonprime), andg229 (b) less than or equal to sqrt(K) (if K has a divisor largerg230 than this square root, it must also have a smaller one,g231 so no need to check for larger ones) */g232 g233 for (J = 2; J*J <= K; J++) g234 if (Prime[J] == 1)g235 if (K % J == 0) {g236 Prime[K] = 0;g237 return;g238 }g239 g240 /* if we get here, then there were no divisors of K, so it isg241 prime */g242 Prime[K] = 1; g243 }
OK, let's give it another try:
g248 mole.matloff% !Fg249 FindPrimesg250 enter upper boundg251 20g252 mole.matloff%
What?! No primes reported up to the number 20? That's not right. Let's use gdb to step through the program. We will pause at the beginning of main(), and take a look around. To do that, we set up a ``breakpoint,'' i.e. a place where gdb will suspend execution of our program, so that we can assess the situation before resuming execution:
g261 (gdb) b maing262 Breakpoint 1 at 0x22b4: file Main.c, line 24.
So, gdb will pause execution of our program whenever it hits Line 24 of the file Main.c. This is Breakpoint 1; we might (and will) set other breakpoints later, so we need numbers to distinguish them, e.g. in order to specify which one we want to cancel.
Now let's run the program, using the r command:
g286 (gdb) rg287 Starting program: /tmp_mnt/lion/d/guest/matloff/tmp/FindPrimes g288 g289 Breakpoint 1, main () at Main.c:24g290 24 printf("enter upper bound\n");
We see that, as planned, gdb did stop at the first line of main() (Line 24). Now we will execute the program one line at a time, using gdb's n (``next'') command:
g291 (gdb) ng292 enter upper boundg293 25 scanf("%d",&UpperBound);
What happened was that gdb executed Line 24 of Main.c as requested-the message from the call to printf() appears on Line g292-and now has paused again, at Line 25 of Main.c, displaying that line for us (Line g293 of the script file).
OK, let's execute Line 25, by typing `n' again:
g294 (gdb) ng295 20g296 27 Prime[2] = 1;
Since Line 25 was a scanf() call, at Line g295 of the script file, gdb waited for our input, which we typed as 20. Gdb then executed the scanf() call, and paused again, now at Line 27 of Main.c (Line 296 of the script file.
Now let's check to make sure that UpperBound was read in correctly. We think it was, but remember, the basic principle of debugging is to check anyway. To do this, we will use gdb's p (``print'') command:
g297 (gdb) p UpperBoundg298 $1 = 20
OK, that's fine. So, let's continue to execute the program one line at a time, by using n:
g299 (gdb) ng300 29 for (N = 3; N <= UpperBound; N += 2)
Also, let's keep track of the value of N, using gdb's disp (``display'') command. The latter is just like the p, except that disp will print out the value of the variable each time the program pauses, as opposed to p, which prints out the value only once.
g301 (gdb) disp Ng302 1: N = 0g303 (gdb) ng304 30 CheckPrime();g305 1: N = 3g306 (gdb) ng307 29 for (N = 3; N <= UpperBound; N += 2)g308 1: N = 3
Hey, what's going on here? After executing Line 30, the program then went back to Line 29-skipping Line 31. Here is what the loop looked like:
29 for (N = 3; N <= UpperBound; N += 2)30 CheckPrime();31 if (Prime[N]) printf("%d is a prime\n",N);
Oops! We forgot the braces. Thus only Line 30, not Lines 30 and 31, forms the body of the loop. No wonder Line 31 wasn't executed.
After fixing that, Main.c looks like this:
g314 mole.matloff% cat Main.cg315 g316 g317 /* prime-number finding programg318 g319 will (after bugs are fixed) report a list of all primes which areg320 less than or equal to the user-supplied upper boundg321 g322 riddled with errors! */g323 g324 g325 g326 #include "Defs.h"g327 g328 g329 int Prime[MaxPrimes], /* Prime[I] will be 1 if I is prime, 0 otherwise */g330 UpperBound; /* we will check all number up through this one forg331 primeness */g332 g333 g334 main()g335 g336 { int N;g337 g338 printf("enter upper bound\n");g339 scanf("%d",&UpperBound);g340 g341 Prime[2] = 1;g342 g343 for (N = 3; N <= UpperBound; N += 2) {g344 CheckPrime();g345 if (Prime[N]) printf("%d is a prime\n",N);g346 }g347 }
OK, try again:
g352 mole.matloff% !Fg353 FindPrimesg354 enter upper boundg355 20g356 mole.matloff%
Still no output! Well, we will now need to try a more detailed line-by-line execution of the program. Last time, we did not go through the function CheckPrime() line-by-line, so we will need to now:
g586 (gdb) l Main.c:1g587 1 g588 2 g589 3 /* prime-number finding programg590 4 g591 5 will (after bugs are fixed) report a list of all primes which g592 (gdb) g593 6 are less than or equal to the user-supplied upper boundg594 7 g595 8 riddled with errors! */g596 9 g597 10 g598 11 g599 12 #include "Defs.h"g600 13 g601 14 g602 15 int Prime[MaxPrimes], /* Prime[I] will be 1 if I is prime, 0 g603 (gdb) g604 16 UpperBound; /* we will check all number up through this oneg605 17 primeness */g606 18 g607 19 g608 20 main()g609 21 g610 22 { int N;g611 23 g612 24 printf("enter upper bound\n");g613 25 scanf("%d",&UpperBound);g614 (gdb) g615 26 g616 27 Prime[2] = 1;g617 28 g618 29 for (N = 3; N <= UpperBound; N += 2) {g619 30 CheckPrime();g620 31 if (Prime[N]) printf("%d is a prime\n",N);g621 32 }g622 33 }g623 34 g624 (gdb) b 30g625 Breakpoint 1 at 0x2308: file Main.c, line 30.
Here we have placed a breakpoint at the call to CheckPrime.
Now, let's run the program:
g626 (gdb) rg627 Starting program: /tmp_mnt/lion/d/guest/matloff/tmp/FindPrimes g628 enter upper boundg629 20g630 g631 Breakpoint 1, main () at Main.c:30g632 30 CheckPrime();
Gdb has stopped at Line 30, as we requested. Now, instead of using the n command, we will use s (``step''). This latter command is the same as n, except that it willenter the function rather than skipping over the function like n does:
g633 (gdb) sg634 CheckPrime (K=1) at CheckPrime.c:19g635 19 for (J = 2; J*J <= K; J++)
Sure enough, s has gotten us to the first line within CheckPrime().
Another service gdb provides for us is to tell us what the values of the parameters of the function are, in this case K = 1. But that doesn't sound right-we shouldn't be checking the number 1 for primeness. So gdb has uncovered another bug for us.
In fact, our plan was to check the numbers 3 through UpperBound for primeness: The for loop in main() had the following heading:
for (N = 3; N <= UpperBound; N += 2)
Well, what about the call to CheckPrime()? Here is the whole loop from main():
29 for (N = 3; N <= UpperBound; N += 2) {30 CheckPrime();31 if (Prime[N]) printf("%d is a prime\n",N);32 }
Look at Line 30-we forgot the parameter! This line should have been
30 CheckPrime(N);
After fixing this, try running the program again:
g699 mole.matloff% !Fg700 FindPrimesg701 enter upper boundg702 20g703 3 is a primeg704 5 is a primeg705 7 is a primeg706 11 is a primeg707 13 is a primeg708 17 is a primeg709 19 is a prime
OK, the program now seems to be working.
======================================
To see a full document, go here:, which is the Guide to Faster, Less Frustrating Debugging writen by Professor Norm Matloff.