gdb調試總結筆記

一、介紹

GDB是GNU開源組織發佈的一個強大的UNIX下的程序調試工具

注意:利用gdb調試,需要在gcc編譯過程中加上-g選項,這樣編譯生成的可執行文件纔可以利用gdb進行源碼調試。-g 選項的作用是在可執行文件中加入源代碼的信息,比如可執行文件中第幾條機器指令對應源代碼的第幾行,但並不是把整個源文件嵌入到可執行文件中,所以在調試時必須保證gdb能找到源文件。如果把當前的gdb.c改名爲g.c或者將gdb.c移動到其他地方,則gdb無法進行調試。

二、簡單操作

1)啓動gdb

gdb hello

或者

gdb
file hello

2)顯示程序

list 或者 l

3)打斷點

break(b) main()   //函數的入口處
break(b) 11       //行號
break(b) hello.c:14 //特定文件的行號
break(b) 12 if i=10 //if語句滿足後在行號處打斷點

4)獲取斷點信息

info break

5)刪除斷點

delete 13(斷點編號)

6)運行程序

run(r)

7)單步(不進入子函數)

next(n)

8)單步(進入子函數)

step(s)

9)繼續運行

continue(c)

10)查看變量

print(p) i(變量名)

11)運行程序到當前函數結束

finish

12)監控變量

watch i(變量名)

13)退出gdb

quit(q)

三、用gdb調試多進程程序

如果一個進程通過fork系統調用創建了子進程,gdb會繼續調試原來的進程,子進程則正常運行。
那麼如何調試子進程呢?

1、單獨調試子進程
子進程本質也是一個進程,因此也可通過gdb來調試,首先找到目標子進程的PID,再將其附加(attach)到
gdb調試器
上,具體操作如下:

$ps -ef|grep 進程名 //找到待調試進程的PID
$gdb 
(gdb) attach "PID"

2、使用調試器選項follow-fork-mode

gdb調試器的選項follow-fork-mode允許我們
選擇程序在執行fork系統調用後是繼續調試父進程還是調試子進程

用法:

(gdb)set follow-fork-mode m
m 可以選parent 或 child, 分別表示調試父進程和子進程
舉例:
$gdb XX
(gdb) set follow-fork-mode child
(gdb) b process.h:264
//打斷點

四、用gdb調試多線程程序

gdb有一組命令可輔助多線程程序的調試。

info threads

顯示當前可調試的所有線程。gdb會爲每個線程分配一個ID,我們可以使用這個ID來操作對應的線程。
ID前面有“*”的線程是當前被調試的線程

thread ID
調試目標ID指定的線程。
查看所有線程的棧信息:thread apply all bt

調試多線程程序時,默認除了被調試的線程在執行外,其他線程也在繼續執行,
但有的時候我們希望只讓被調試的線程運行。這可以通過這個命令來實現

set scheduler-locking [off|on|step]

該命令設置sceduler-locking的值:

  • off表示不鎖定任何線程,即所有線程都可以繼續執行,這是默認值。
  • on表示只有當前被調試的線程會繼續執行。
  • step表示在單步執行的時候,只有當前線程會執行。

五、用gdb工具分析core文件

在Unix系統下,應用程序崩潰,一般會產生core文件,如何根據core文件查找問題的所在,
 並做相應的分析和調試,是非常重要的。

許多程序出錯時都會產生一個Core 文件,通過工具分析這個文件,
 我們可以定位到程序異常退出時對應的堆棧調用等信息,找出問題所在並進行及時解決

段錯誤,就是大名鼎鼎的Segmentation Fault,這通常是由指針錯誤引起的。

簡而言之,產生段錯誤就是訪問了錯誤的內存段,一般是你沒有權限,
 或者根本就不存在對應的物理內存,尤其常見的是訪問0 地址。

在編程中有以下幾種做法容易導致段錯誤,基本都是錯誤地使用指針引起的:

  • 訪問系統數據區,尤其是往系統保護的內存地址寫數據,最常見的就是給指針以0地址
  • 內存越界(數據越界、變量類型不一致等)訪問到不屬於你的內存區域

程序在運行過程中如果出現段錯誤,那麼就會收到SIGSEGV 信號,
SIGSEGV 默認handler 的動作是打印“段錯誤”的出錯信息,併產生Core 文件。

1、core文件開關

ulimit -c 查看core開關,如果爲0表示關閉,不會生成core文件;

使用 ulimit -c [filesize]

設置core文件大小,當最小設置爲4之後纔會生成core文件;
使用 ulimit -c unlimited 設置core文件大小爲不限制,這是常用的做法;

如果需要開機就執行,則需要將這句命令寫到 /etc/profile 等文件。
core文件路徑一般在可執行文件同一目錄

2、core文件命名和保存路徑

core文件有默認的名稱和路徑,但爲了方便,我們通常會自己命名和指定保存路徑;
可以通過 /proc/sys/kernel/core_pattern 設置 core 文件名和保存路徑,方法如下:

echo "/corefile/core-%e-%p-%t" > /proc/sys/kernel/core_pattern

命名的參數列表:

  • %p - insert pid into filename 添加pid
  • %u - insert current uid into filename 添加當前uid
  • %g - insert current gid into filename 添加當前gid
  • %s - insert signal that caused the coredump into the filename 添加導致產生core的信號
  • %t - insert UNIX time that the coredump occurred into filename 添加core文件生成時的unix時間
  • %h - insert hostname where the coredump happened into filename 添加主機名
  • %e - insert coredumping executable name into filename 添加命令名。

3、分析Core 文件

設置Core文件大小,運行程序生成Core文件
執行ulimit -c unlimited表示不限制生成的Core 文件的大小,

4、運行這個有bug 的程序,可以在當前目錄下生成core文件

執行 gdb [exec file] [core file]啓動gdb後,
調用gdb的where或bt命令可以查看當時的調用棧信息,
進入某個棧:f N,f是frame的縮寫,N是棧號,如0、1、2、3…
進入到某個棧後,才能通過p命令查看這個棧的臨時變量,否則只能查看全局變量。

六、調試一個正在運行的程序

使用gdb -p PID命令,PID即程序的pid
需要注意的是,gdb調試正在運行的程序會導致程序掛起,因此請記住不要gdb調試正在運行的在線服務。

七、設置斷點的方式

有很多種,最常見的有兩種:一是設置程序運行到源代碼的某一行,二是設置程序運行到某個函數。
設置程序運行到某一行,通過“文件名:行號”的形式

b test.cpp:100

設置程序運行到某個函數,通過“名字空間::函數名”的形式:

b namespace_a::func

八、斷點操作

查看斷點:info b

刪除斷點:d N,d是delete的縮寫,N是斷點的編號,可以通過info b查看。

無論哪種方式設置斷點,都要執行c命令(continue),讓程序繼續運行。

九、在調試程序時,gdb常用命令總結

常用:n、s、p

  • n即next,單步執行,執行下一步的意思,遇到函數會調用函數。
  • s即step,也是單步執行,但是會進入函數內部,然後結合n命令來調試函數。
  • p即print,打印變量,最常用的命令。p可以打印普通變量、std::string字符串、指針、數組等。gdb打印字符串支持c_str()、length()等
    std::string str;
    p str,p str.c_str()查看字符串內容,p str.length(),查看字符串長度
    有時會遇到字符串太長不能顯示全,最後顯示"…",可以通過命令取消長度限制:
set print elements 0

這樣就能打印完整的字符串。

命令 描述
backtrace(或bt) 查看各級函數調用及參數
finish 連續運行到當前函數返回爲止,然後停下來等待命令
frame(或f) 幀編號 選擇棧幀
info(或i) locals 查看當前棧幀局部變量的值
list(或l) 列出源代碼,接着上次的位置往下列,每次列10行
list 行號 列出從第幾行開始的源代碼
list 函數名 列出某個函數的源代碼
next(或n) 執行下一行語句
print(或p) 打印表達式的值,通過表達式可以修改變量的值或者調用函數
quit(或q) 退出gdb調試環境
set var 修改變量的值
start 開始執行程序,停在main函數第一行語句前面等待命令
step(或s) 執行下一行語句,如果有函數調用則進入到函數中

最後說一下gdb中如何打印STL的vector和map,gdb默認不支持STL,

需要從網上下載一個txt文件,然後將其內容追加到.gdbinit文件中,就可以使用pvector命令查看vector容器數據。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章