Linux——GDB偵錯教學(新手小白)

2020-10-22 14:00:56

目錄

1. GDB簡介

2. GDB安裝教學

1)檢查機器上是否安裝gdb

2) 下載gdb原始碼包

3) 解壓gdb原始碼包

4) 安裝

5) 檢查是否安裝成功

3. GDB入門操作

1)建立測試程式碼

2)啟動gdb

3)斷點

4)執行

5)列印變數的的值

6)退出gdb

參考文章

 


1. GDB簡介

GDB,全稱 GNU symbolic debugger,簡稱 GDB偵錯程式,是 Linux 平臺下最常用的一款程式偵錯程式

2. GDB安裝教學

CentOSx下安裝GDB

1)檢查機器上是否安裝gdb

rpm -qa | grep gdb

[root@]# rpm -qa | grep gdb
gdbm-1.10-8.el7.x86_64
gdbm-devel-1.10-8.el7.x86_64

若安裝,則採用以下命令解除安裝

rpm -e --nodeps [軟體版本]

[root@]# rpm -e --nodeps gdbm-1.10-8.el7.x86_64
[root@]# rpm -e --nodeps gdbm-devel-1.10-8.el7.x86_64

2) 下載gdb原始碼包

wget http://mirrors.ustc.edu.cn/gnu/gdb/gdb-7.9.1.tar.xz

[root@]# wget http://mirrors.ustc.edu.cn/gnu/gdb/gdb-7.9.1.tar.xz
--2020-10-19 15:05:39--  http://mirrors.ustc.edu.cn/gnu/gdb/gdb-7.9.1.tar.xz
Resolving mirrors.ustc.edu.cn (mirrors.ustc.edu.cn)... 202.141.176.110, 218.104.71.170, 2001:da8:d800:95::110
Connecting to mirrors.ustc.edu.cn (mirrors.ustc.edu.cn)|202.141.176.110|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 17867692 (17M) [application/octet-stream]
Saving to: ‘gdb-7.9.1.tar.xz’

100%[====================================================================================================================================================>] 17,867,692  36.5MB/s   in 0.5s   

2020-10-19 15:05:39 (36.5 MB/s) - ‘gdb-7.9.1.tar.xz’ saved [17867692/17867692]

3) 解壓gdb原始碼包

tar -xf gdb-7.9.1.tar.xz

[root@]# tar -xf gdb-7.9.1.tar.xz

4) 安裝

cd gdb-7.9.1

sudo yum install texinfo

./configure

make

sudo make install

[root@]# cd gdb-7.9.1
[root@]# sudo yum install texinfo
.
.
.
Dependency Installed:
  perl-Text-Unidecode.noarch 0:0.04-20.el7          perl-libintl.x86_64 0:1.20-12.el7         

Complete!
[root@]# ./configure
.
.
.
configure: creating ./config.status
config.status: creating Makefile
[root@]# make
.
.
.
make[1]: Nothing to be done for `all-target'.
make[1]: Leaving directory `/root/.vimplus/gdb-7.9.1'
[root@]# make install
.
.
.
make[1]: Nothing to be done for `install-target'.
make[1]: Leaving directory `/root/.vimplus/gdb-7.9.1'

5) 檢查是否安裝成功

gdb -v

[root@]# gdb -v
GNU gdb (GDB) 7.9.1
Copyright (C) 2015 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-unknown-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word".

3. GDB入門操作

命令               簡寫形式         說明
backtrace          bt、where       顯示backtrace
break              b               設定斷點
continue           c、cont         繼續執行
delete             d               刪除斷點
finish                             執行到函數結束
info breakpoints                   顯示斷點資訊
next               n               執行下一行
print              p               顯示錶示式
run                r               執行程式
step               s               一次執行一行,包括函數內部
x                                  顯示記憶體內容
until              u               執行到指定行
其他命令
directory          dir             插入目錄
disable            dis             禁用斷點
down               do              在當前呼叫的棧幀中選擇要顯示的棧幀
edit               e               編輯檔案或者函數
frame              f               選擇要顯示的棧幀
forward-search     fo              向前搜尋
generate-core-file gcore           生成核心轉儲存
help                h              顯示幫助一覽
info                i              顯示資訊
list                l              顯示函數或行
nexti               ni             執行下一行(以組合程式碼為單位)
print-object        po             顯示目標資訊
sharelibrary        share          載入共用的符號
stepi               si             執行下一行

1)建立測試程式碼

vim test.c

gcc -g -o test.exe test.c

關於vim/vi的用法這裡不再概述,推薦vim的設定程式vimplus

寫完程式碼後,gcc編譯程式碼(PS. 如果gcc編譯的時候沒有加上-g引數,那麼就不會保留偵錯引數,就不能用gdb偵錯)

測試程式碼如下:

#include<stdio.h>
#include<stdlib.h>
 
int main( int argc , char *argv[] )  
{
    int a = 1;
    int i = 0;
    int b[3] = {0,1,2};
    for(i = 0; i < 3;i++)
        b[i] = b[i] + 1;
    printf("%d\n",a);
    int *p;
    p = b;
    printf("%d\n",p[0]);
    return 0;
}

2)啟動gdb

       在 Linux 作業系統中,當程式執行發生異常崩潰時,系統可以將發生崩潰時的記憶體資料、呼叫堆疊情況等資訊自動記錄下載,並儲存到一個檔案中,該檔案通常稱為 core 檔案,Linux 系統所具備的這種功能又稱為核心轉儲(core dump)。幸運的是,GDB 對 core 檔案的分析和偵錯提供有非常強大的功能支援,當程式發生異常崩潰時,通過 GDB 偵錯產生的 core 檔案,往往可以更快速的解決問題。

  • 檢視是否開啟 core dump 這一功能

ulimit -a

[root@]# ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 7284
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 65535
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 7284
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

如果 core file size(core 檔案大小)對應的值為 0,表示當前系統未開啟 core dump 功能

  • 開啟 core dump

ulimit -c unlimited

[root@]# ulimit -c unlimited
[root@]# ulimit -a
core file size          (blocks, -c) unlimited
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 7284
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 65535
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 7284
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

unlimited 表示不限制 core 檔案的大小

測試程式碼:

1 #include <stdio.h>
  2 
  3 int main()
  4 {
  5     char *p = NULL;                                                                    
  6     *p = 123;
  7     return 0;
  8 }

測試結果:

[root@]# vim main.c
[root@]# gcc -g -o main.exe main.c
[root@]# ls
main.c  main.exe  test.c  test.exe
[root@]# ./main.exe
Segmentation fault (core dumped)
[root@]# ls
core.17313  main.c  main.exe  test.c  test.exe

測試程式碼中,發生記憶體存取錯誤,程式崩潰,崩潰資訊存入core.17313檔案中

  • 啟動gdb

gdb test.exe

[root@]# gdb test.exe
GNU gdb (GDB) 7.9.1
Copyright (C) 2015 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-unknown-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from test.exe...done.
(gdb)_

3)斷點

  • 根據行號設定斷點

第一種  (gdb) b 5 

第二種  (gdb) b test.c:5

  • 根據函數設定斷點

(gdb) b main

  • 根據條件設定斷點

(gdb) b test.c:10 if a == 1

  • 根據偏移量設定斷點

(gdb) b +12

  • 根據地址設定斷點

(gdb) b *0x40059b

  • 設定臨時斷點

臨時斷點只生效一次

(gdb) tbreak test.c:12

(gdb) b test.c:5
Breakpoint 1 at 0x40053c: file test.c, line 5.
(gdb) b main
Note: breakpoint 1 also set at pc 0x40053c.
Breakpoint 2 at 0x40053c: file test.c, line 6.
(gdb) b test.c:10 if a == 1
Breakpoint 3 at 0x400568: file test.c, line 10.
(gdb) b +12
Breakpoint 4 at 0x40059b: file test.c, line 13.
(gdb) b *0x40059b
Note: breakpoint 4 also set at pc 0x40059b.
Breakpoint 5 at 0x40059b: file test.c, line 13.
(gdb) tbreak test.c:12
Note: breakpoints 4 and 5 also set at pc 0x40059b.
Temporary breakpoint 6 at 0x40059b: file test.c, line 12.
  • 顯示所有斷點

(gdb) info break

(gdb) info break
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x000000000040053c in main at test.c:5
2       breakpoint     keep y   0x000000000040053c in main at test.c:6
3       breakpoint     keep y   0x0000000000400568 in main at test.c:10
        stop only if a == 1
4       breakpoint     keep y   0x000000000040059b in main at test.c:13
5       breakpoint     keep y   0x000000000040059b in main at test.c:13
6       breakpoint     del  y   0x000000000040059b in main at test.c:12
  • 清除斷點

清除某個斷點 (gdb) delete 4

清除所有斷點 (gdb) delete 

(gdb) delete 4
(gdb) delete
Delete all breakpoints? (y or n) y
(gdb) info break
No breakpoints or watchpoints.

清除當前行斷點  (gdb) clear

Breakpoint 3, main (argc=1, argv=0x7fffffffe508) at test.c:13
13          p = b;
(gdb) clear
Deleted breakpoint 3 

4)執行

  • 執行和繼續

執行 r

繼續單步偵錯 n

繼續執行到下一個斷點 c

  • 檢視原始碼和行號

l

(gdb) l
1       #include <stdio.h>
2       #include <stdlib.h>
3
4       int main( int argc, char *argv[])
5       {
6           int a = 1;
7           int i = 0;
8           int b[3] = {0, 1, 2};
9           for (i = 0; i < 3; i++)
10              b[i] = b[i] + 1;
(gdb) l
11          printf("%d\n", a);
12          int *p;
13          p = b;
14          printf("%d\n", p[0]);
15          return 0;
16      }
(gdb) l
Line number 17 out of range; test.c has 16 lines.

5)列印變數的的值

  • 列印變數

p a

  • 列印指標

p p

  • 列印main函數中的變數a

p 'main'::a

  • 列印指標指向的內容,@後面跟的是列印的長度

p *p@3

(gdb) run
Starting program: /root/daizhh/test.exe 

Breakpoint 1, main (argc=1, argv=0x7fffffffe508) at test.c:11
11          printf("%d\n", a);
(gdb) p a
$1 = 1
(gdb) p b
$2 = {1, 2, 3}
(gdb) n
1
13          p = b;
(gdb) c
Continuing.

Breakpoint 2, main (argc=1, argv=0x7fffffffe508) at test.c:14
14          printf("%d\n", p[0]);
(gdb) p p
$3 = (int *) 0x7fffffffe400
(gdb) p 'main'::a
$4 = 1
(gdb) p *p@3
$5 = {1, 2, 3}
  • 設定變數列印

set $index = 0

p p[$index]

(gdb) set $index = 0
(gdb) p p[$index]
$6 = 1
  • 設定列印格式
  1. x 按十六進位制格式顯示變數
  2. d 按十進位制格式顯示變數
  3. u 按十六進位制格式顯示無符號整型
  4. o 按八進位制格式顯示變數
  5. t 按二進位制格式顯示變數
  6. a 按十六進位制格式顯示變數
  7. c 按字元格式顯示變數
  8. f 按浮點數格式顯示變數

(gdb) p/x a(按十六進位制格式顯示變數)

(gdb) p/x a
$7 = 0x1

6)退出gdb

q


參考文章

http://c.biancheng.net/gdb/

https://blog.csdn.net/wh_computers/article/details/94618240

https://blog.csdn.net/andrewgithub/article/details/88210949