1. 程式人生 > 實用技巧 >gdb除錯程式記錄

gdb除錯程式記錄

  實現一個將結構類資料寫入二進位制檔案中,程式碼test6_12.c

 1 //This is c program code!
 2 /* *=+=+=+=+* *** *=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
 3   * 文件資訊: *** :~/WORKM/stutyCode/cCode/recipesProblemSolution/chapter06/test6_12.c
 4   * 版權宣告: *** :(魎魍魅魑)MIT
 5   * 聯絡信箱: *** :[email protected]
 6   * 建立時間: *** :2020年11月21日的下午04:25
 7   * 文件用途: *** :資料結構與演算法分析-c語言描述
 8   * 作者資訊: *** :guochaoxxl(
http://cnblogs.com/guochaoxxl) 9 * 修訂時間: *** *2020年第46周 11月21日 星期六 下午05:03 (326天) 10 * 檔案描述: *** :自行新增 11 * *+=+=+=+=* *** *+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+*/ 12 #include <stdio.h> 13 14 typedef struct _bio{ 15 char name[15]; 16 int rollNo; 17 int age;
18 float weight; 19 } Bio; 20 21 void closeState(int clo, FILE *fPtr){ 22 clo = fclose(fPtr); 23 if(clo == -1){ 24 puts("File-closing failed!"); 25 } 26 if(clo == 0){ 27 puts("File is closed successfully."); 28 } 29 30 return; 31 } 32 33 int main(int argc, char
**argv) 34 { 35 char flag = 'y'; 36 FILE *fPtr = fopen("agentsb.dat", "wb"); 37 if(fPtr != NULL){ 38 printf("File agentsb.dat is opened successfully.\n"); 39 Bio bio; 40 while(flag == 'y'){ 41 printf("Enter name, rooNo, age and weight of agent: "); 42 scanf("%s %d %d %f", bio.name, &bio.rollNo, &bio.age, &bio.weight); 43 fwrite(&bio, sizeof(bio), 1, fPtr); 44 int tmp = getchar(); 45 //fflush(stdin); 46 printf("Any more records(y/n): "); 47 scanf("%c", &flag); 48 } 49 int clo = fclose(fPtr); 50 closeState(clo, fPtr); 51 }else{ 52 puts("File-open failed!"); 53 } 54 55 return 0; 56 }

  編譯:

gcc -g test6_12.c -o test6_12

  執行錯誤如下:

File agentsb.dat is opened successfully.
Enter name, rooNo, age and weight of agent: zhangsan 1 21 74.5
Any more records(y/n): y
Enter name, rooNo, age and weight of agent: wangsi 2 22 75.5
Any more records(y/n): y
Enter name, rooNo, age and weight of agent: liwu 3 33 76.5
Any more records(y/n): y      
Enter name, rooNo, age and weight of agent: zhaoliu 4 44 77.5
Any more records(y/n): y
Enter name, rooNo, age and weight of agent: zhouqi 5 55 78.5
Any more records(y/n): n
free(): double free detected in tcache 2

  拿出除錯的40米大刀長,GDB上場; 輸入:gdb test6_12

 1 GNU gdb (GDB) 10.1
 2 Copyright (C) 2020 Free Software Foundation, Inc.
 3 License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
 4 This is free software: you are free to change and redistribute it.
 5 There is NO WARRANTY, to the extent permitted by law.
 6 Type "show copying" and "show warranty" for details.
 7 This GDB was configured as "x86_64-pc-linux-gnu".
 8 Type "show configuration" for configuration details.
 9 For bug reporting instructions, please see:
10 <https://www.gnu.org/software/gdb/bugs/>.
11 Find the GDB manual and other documentation resources online at:
12     <http://www.gnu.org/software/gdb/documentation/>.
13 
14 For help, type "help".
15 Type "apropos word" to search for commands related to "word"...
16 Reading symbols from test6_12...
17 (gdb) 

  基本都是關於gdb的資訊,主要有版本,版權即說明,

  1、第14行開始,可以鍵入help獲取幫助

  2、第15行開始,可以apropos word查詢關鍵字資訊

  3、第16行開始,從檔案test6_12讀取除錯符號

help資訊為:

 1 help
 2 List of classes of commands:
 3 
 4 aliases -- User-defined aliases of other commands.
 5 breakpoints -- Making program stop at certain points.
 6 data -- Examining data.
 7 files -- Specifying and examining files.
 8 internals -- Maintenance commands.
 9 obscure -- Obscure features.
10 running -- Running the program.
11 stack -- Examining the stack.
12 status -- Status inquiries.
13 support -- Support facilities.
14 text-user-interface -- TUI is the GDB text based interface.
15 tracepoints -- Tracing of program execution without stopping the program.
16 user-defined -- User-defined commands.
17 
18 Type "help" followed by a class name for a list of commands in that class.
19 Type "help all" for the list of all commands.
20 Type "help" followed by command name for full documentation.
21 Type "apropos word" to search for commands related to "word".
22 Type "apropos -v word" for full documentation of commands related to "word".
23 Command name abbreviations are allowed if unambiguous.

檢視原始碼:l

(gdb) l
20
21      void closeState(int clo, FILE *fPtr){
22              clo = fclose(fPtr);
23              if(clo == -1){
24                      puts("File-closing failed!");
25              }
26              if(clo == 0){
27                      puts("File is closed successfully.");
28              }
29

設定斷點:b closeState,通過函式名

(gdb) b closeState
Breakpoint 1 at 0x11b8: file test6_12.c, line 22.

設定斷點:b 36,通過行號

(gdb) l
30              return;
31      }
32
33      int main(int argc, char **argv)
34      {
35              char flag = 'y';
36              FILE *fPtr = fopen("agentsb.dat", "wb");
37              if(fPtr != NULL){
38                      printf("File agentsb.dat is opened successfully.\n");
39                      Bio bio;
(gdb) b 36
Breakpoint 2 at 0x1211: file test6_12.c, line 36.

設定斷點:b 49

(gdb) l
40                      while(flag == 'y'){
41                              printf("Enter name, rooNo, age and weight of agent: ");
42                              scanf("%s %d %d %f", bio.name, &bio.rollNo, &bio.age, &bio.weight);
43                              fwrite(&bio, sizeof(bio), 1, fPtr);
44                              int tmp = getchar();
45                              //fflush(stdin);
46                              printf("Any more records(y/n): ");
47                              scanf("%c", &flag);
48                      }
49                      int clo = fclose(fPtr);
(gdb) b 49
Breakpoint 3 at 0x12e2: file test6_12.c, line 49.

執行到斷點停下:

(gdb) r
Starting program: /home/nication/WORKM/stutyCode/cCode/recipesProblemSolution/chapter06/test6_12 

Breakpoint 2, main (argc=1, argv=0x7fffffffd518) at test6_12.c:36
36              FILE *fPtr = fopen("agentsb.dat", "wb");

檢視資訊:

(gdb) n
37              if(fPtr != NULL){
(gdb) p *fPtr
$1 = {_flags = -72539004, _IO_read_ptr = 0x0, _IO_read_end = 0x0, _IO_read_base = 0x0, 
  _IO_write_base = 0x0, _IO_write_ptr = 0x0, _IO_write_end = 0x0, _IO_buf_base = 0x0, 
  _IO_buf_end = 0x0, _IO_save_base = 0x0, _IO_backup_base = 0x0, _IO_save_end = 0x0, 
  _markers = 0x0, _chain = 0x7ffff7f5e440 <_IO_2_1_stderr_>, _fileno = 3, _flags2 = 0, 
  _old_offset = 0, _cur_column = 0, _vtable_offset = 0 '\000', _shortbuf = "", 
  _lock = 0x555555559380, _offset = -1, _codecvt = 0x0, _wide_data = 0x555555559390, 
  _freeres_list = 0x0, _freeres_buf = 0x0, __pad5 = 0, _mode = 0, 
  _unused2 = '\000' <repeats 19 times>}
(gdb) p fPtr
$2 = (FILE *) 0x5555555592a0
(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/nication/WORKM/stutyCode/cCode/recipesProblemSolution/chapter06/test6_12 

Breakpoint 2, main (argc=1, argv=0x7fffffffd518) at test6_12.c:36
36              FILE *fPtr = fopen("agentsb.dat", "wb");
(gdb) n
37              if(fPtr != NULL){
(gdb) n
38                      printf("File agentsb.dat is opened successfully.\n");
(gdb) n
File agentsb.dat is opened successfully.
40                      while(flag == 'y'){
(gdb) n
41                              printf("Enter name, rooNo, age and weight of agent: ");
(gdb) n
42                              scanf("%s %d %d %f", bio.name, &bio.rollNo, &bio.age, &bio.weight);
(gdb) n
Enter name, rooNo, age and weight of agent: zhangsan 1 11 11.1
43                              fwrite(&bio, sizeof(bio), 1, fPtr);
(gdb) n
44                              int tmp = getchar();
(gdb) n
46                              printf("Any more records(y/n): ");
(gdb) n
47                              scanf("%c", &flag);
(gdb) n
Any more records(y/n): y
40                      while(flag == 'y'){
(gdb) n
41                              printf("Enter name, rooNo, age and weight of agent: ");
(gdb) p flag
$3 = 121 'y'
(gdb) n
42                              scanf("%s %d %d %f", bio.name, &bio.rollNo, &bio.age, &bio.weight);
(gdb) n
Enter name, rooNo, age and weight of agent: wangsi 2 22 22.1
43                              fwrite(&bio, sizeof(bio), 1, fPtr);
(gdb) n
44                              int tmp = getchar();
(gdb) n
46                              printf("Any more records(y/n): ");
(gdb) n
47                              scanf("%c", &flag);
(gdb) n
Any more records(y/n): n
40                      while(flag == 'y'){
(gdb) n

Breakpoint 3, main (argc=1, argv=0x7fffffffd518) at test6_12.c:49
49                      int clo = fclose(fPtr);
(gdb) p flag
$4 = 110 'n'

當輸入n時,退出while迴圈,

(gdb) n
50                      closeState(clo, fPtr);
(gdb) n

Breakpoint 1, closeState (clo=0, fPtr=0x5555555592a0) at test6_12.c:22
22              clo = fclose(fPtr);
(gdb) n
free(): double free detected in tcache 2

Program received signal SIGABRT, Aborted.
0x00007ffff7dd8615 in raise () from /usr/lib/libc.so.6

可以看出,程式碼執行到22行,出現了SIGABRT訊號,程式被中斷, 出現了free(): double free detected in tcache 2錯誤

再次開啟GDB除錯:

(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/nication/WORKM/stutyCode/cCode/recipesProblemSolution/chapter06/test6_12 

Breakpoint 2, main (argc=1, argv=0x7fffffffd518) at test6_12.c:36
36              FILE *fPtr = fopen("agentsb.dat", "wb");
(gdb) info b
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x00005555555551b8 in closeState at test6_12.c:22
2       breakpoint     keep y   0x0000555555555211 in main at test6_12.c:36
        breakpoint already hit 1 time
3       breakpoint     keep y   0x00005555555552e2 in main at test6_12.c:49
(gdb) n
37              if(fPtr != NULL){
(gdb) n
38                      printf("File agentsb.dat is opened successfully.\n");
(gdb) c
Continuing.
File agentsb.dat is opened successfully.
Enter name, rooNo, age and weight of agent: zhangsan 1 21 71.5
Any more records(y/n): y
Enter name, rooNo, age and weight of agent: wangsi 2 22 72.5
Any more records(y/n): y
Enter name, rooNo, age and weight of agent: liwu 3 23 73.5
Any more records(y/n): y
Enter name, rooNo, age and weight of agent: zhaoliu 4 24 74.5
Any more records(y/n): n

Breakpoint 3, main (argc=1, argv=0x7fffffffd518) at test6_12.c:49
49                      int clo = fclose(fPtr);
(gdb) s
50                      closeState(clo, fPtr);
(gdb) p clo
$6 = 0
(gdb) n

Breakpoint 1, closeState (clo=0, fPtr=0x5555555592a0) at test6_12.c:22
22              clo = fclose(fPtr);
(gdb) p clo
$7 = 0
(gdb) s
free(): double free detected in tcache 2

Program received signal SIGABRT, Aborted.
0x00007ffff7dd8615 in raise () from /usr/lib/libc.so.6

s進入closeState()函式內部,執行了第22行程式碼出錯了,clo的值為0,

而在第49行的程式碼執行結果clo的值也是0,原來是主函式中已經關閉過函式,釋放了一次函式指標fPtr,進入函式後,再次釋放同一個指標。進而導致了段錯誤,刪除主函式中的第49行的程式碼。

  搞定了。總的來說,除錯程式就是讓程式按照自己的要求,隨心所欲執行一遍,讓錯誤重現,從而發現程式碼的問題:

  1、設定斷點,讓程式在合適的時機停下,檢視此時程式碼中的變數值

  2、使用n c s等命令逐步執行程式碼,精確到每一行程式碼

  3、通過輸入變數的值,改變程式碼的執行環境,檢視程式碼的執行結果