博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
A gdb Example
阅读量:7226 次
发布时间:2019-06-29

本文共 17699 字,大约阅读时间需要 58 分钟。

 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. 

转载于:https://www.cnblogs.com/lpfrylzx/archive/2013/05/24/3096553.html

你可能感兴趣的文章
core_framework —— 基于libev的轻量级lua网络开发框架
查看>>
回到顶部
查看>>
DES/3DES(TripleDES)加密、解密测试数据
查看>>
Maven项目标准目录结构
查看>>
Tomcat 系统架构与设计模式,第 1 部分: 工作原理
查看>>
Hadoop输出参数信息详解(16)
查看>>
ERROR 2002 (HY000): Can't connect to local MySQL错误
查看>>
Java版冒泡排序法
查看>>
关于FB4.6插件安装后默认语言环境的更改问题
查看>>
免费分区助手
查看>>
Javascript通过Name调用Function
查看>>
统计当前在线用户数量
查看>>
IntelliJ IDEA 乱码解决方案 (项目代码、控制台等)
查看>>
PHP项目记录
查看>>
.net面试题系列文章七(附答案)
查看>>
FastSocket
查看>>
ionic $ionicSlideBoxDelegate 滑动框事件
查看>>
点击文字,把input type="radio"也选中
查看>>
第一章 Java多线程技能
查看>>
Java 集合系列-第八篇-Map架构
查看>>