本文首發於個人公衆號 Linux雲計算網絡(id: cloud_dev),專一於乾貨分享,號內有 10T 書籍和視頻資源,後臺回覆 「1024」 便可領取,歡迎你們關注,二維碼文末能夠掃。
GDB(GNU Debugger)是 UNIX 及 UNIX-like 下的強大調試工具,能夠調試 ada, c, c++, asm, minimal, d, fortran, objective-c, go, java,pascal 等語言,這一份指南咱們主要以 c 來做爲例子。html
# gdb helloworld Reading symbols from helloWorld...(no debugging symbols found)...done. # gdb helloworld Reading symbols from helloWorld...done.
上面一種有 no debugging symbols found
表示不可調試,下面是可調式的。java
或者 readelf 查看段信息:linux
1# readelf -S helloworld|grep debug 2 [28] .debug_aranges PROGBITS 0000000000000000 0000106d 3 [29] .debug_info PROGBITS 0000000000000000 0000109d 4 [30] .debug_abbrev PROGBITS 0000000000000000 0000115b 5 [31] .debug_line PROGBITS 0000000000000000 000011b9 6 [32] .debug_str PROGBITS 0000000000000000 000011fc
若是沒有輸出任何 debug 信息,也不能調試。c++
加上 -g
選項:objective-c
gcc -g -o xxx xxx.c
b 行號或函數
添加斷點r
跑到下一個斷點s
單步跟蹤n
單步執行p
查看當前程序的運行數據 好比:p a
輸出a變量的值 輸出格式能夠設置: 好比p/d a
十進制輸出a變量的值p array@idx
能夠查看數組 array 中 idx 處的值display a
這樣之後每次調試都會輸出a變量的值x
查看內存地址中的值 語法:x/l
查看原程序代碼,l 9
列出第9行附件的源碼(l 2,8
列出2-8行之間的數據),l func
列出指定函數附件的源碼p x=8
在調試過程當中修改變量x的值,下面生效jump
實現跳轉,能夠是文件的行號,也能夠是file:line,也能夠是+num這種格式 jump address是代碼行的內存地址signal
產生信號量return
強制返回call
強制調用until(簡寫u)
當在一個循環體內時,運行退出循環until +行號
運行至某行停住,不只僅跳出循環finish
當前函數執行完,並打印函數返回時的堆棧地址和返回值及參數值等信息skip
在 step 時跳過一些不想關注的函數或者某個文件的代碼,如 skip function add
表示跳過函數 add,skip file step.c
跳過文件 step.c,info skip
查看跳過的信息。c
繼續執行 跳到下一個斷點bt
查看堆棧where
報錯時查看哪裏出錯,與 bt
相似info b
查看斷點狀況q
退出ptype
輸出結構體類型info registers
顯示寄存器值, info all-registers
顯示全部寄存器info breakpoints
能夠查看全部已設置的端點info breakpoints
查看全部斷點b 9
或者 b test.c:9
根據行號設置斷點b func
根據函數名設置斷點b test.c:9 if b==0
根據程序某個條件會出現問題,設置該條件斷點(這樣當出現問題時,會卡主,用來判斷是不是該問題)rbreak print*
對全部 print 開頭的函數都設斷點,rbreak test.c:.
對test.c 中全部函數設斷點tbreak test.c:9
設 臨時斷點 ,即這個斷點只生效一次ignore 1 30
忽略某個斷點的前面 30 次執行,從第 31 次開始生效,節約時間watch a
觀察某個值或表達式,何時發生變化disable/enable num
禁用/啓用全部/某個斷點clear
清除全部斷點,用於清除某個函數,某行的斷點,如 clear func
、clear linenum
delete
刪除全部斷點,包括watchpoints, catchpoints,用於刪除斷點號的斷點,如 delete bnum
p 'test.c'::a
打印某個文件的變量,p 'main'::b
打印某個函數定義的變量p *p@10
打印指針指向的內容,@後面爲打印的長度p *$.next
打印鏈表linkNode的下一個節點內容p/x c
按十六進制打印內容(x:十六進制,d:十進制,o:八進制,t:二進制,c:字符格式,f:浮點格式)x addr
查看內存地址值display e
程序斷住顯示某個變量的值啓動調試後,不想退出程序而編輯源碼,如何作呢?shell
gdb 模式下用的默認編輯器是 /bin/ex
,若是沒有或者想換成其餘編輯器,如VIM,能夠這樣:編程
export EDITOR=/usr/bin/vim
gdb 模式下編輯源碼:vim
(gdb)edit 3 # 編輯第三行 (gdb)edit func # 編輯func函數 (gdb)edit test.c:5 #編輯test.c第五行
完了以後,從新編譯程序( 注意必定要帶上 shell 命令,代表是shell命令 ):數組
(gdb)shell gcc -g -o main main.c test.c
或者這樣:bash
啓動是帶上 tui(Text User Interface),能夠在多個窗口調試:
gdb main -tui
1. 啓動的時候帶上參數
gdb --args xxx 參數
2. 啓動以後 run 帶上參數
# gdb xxx (gdb)run 參數
3. 啓動以後 set args 設置參數
# gdb xxx (gdb) set args 參數
ps -ef | grep xxx
或 pidof
進程名gdb
模式,輸入 attach pid
或者直接這樣:gdb <program> pid
(或 gdb <program> --pid pid
),gdb 會 自動 attach。
若是出現以下錯誤:
Could not attach to process. If your uid matches the uid of the target process, check the setting of /proc/sys/kernel/yama/ptrace_scope, or try again as the root user. For more details, see /etc/sysctl.d/10-ptrace.conf ptrace: Operation not permitted.
切換到 root 用戶,將 /etc/sysctl.d/10-ptrace.conf
中的
kernel.yama.ptrace_scope = 1
改成:
kernel.yama.ptrace_scope = 0
gdb
模式,輸入 set follow-fork-mode mode
(mode 可選 parent、child,表示調試父進程仍是子進程)已運行程序一般沒有調試信息,但若是不能中止當前程序從新啓動調試,能夠:
一樣的代碼,再編譯出一個帶調試信息的版本,而後:
# gdb (gdb) file hello Reading symbols from hello...done. (gdb)attach 20829
gdb
有一組命令可以輔助多線程的調試:
info threads
:顯示當前可調式的全部線程,線程 ID 前有 「*」 表示當前被調試的線程。thread id
:調試目標 id 指定的線程set scheduler-locking [on|off|step]
:多線程環境下,會存在多個線程運行,這會影響調試某個線程的結果,這個命令能夠設置調試的時候多個線程的運行狀況,on
表示只有當前調試的線程會繼續執行,off
表示不屏蔽任何線程,全部線程均可以執行,step
表示在單步執行時,只有當前線程會執行。coredump 調試依賴於 core 文件,core 文件是程序非法執行後 core dump 後產生的文件。這是 Linux 系統的一種保護機制,當出現某些連開發和測試費了九牛二虎之力都沒能發現的問題時,Linux 系統還提供了最後一道屏障,經過 core 文件就可讓這些問題原形畢露。
要想讓程序崩潰時產生 core 文件,須要開啓,輸入 ulimit -c
,若是輸出爲 0,表示默認關閉 core dump。
有兩種方式能夠開啓,一種就是經過 ulimit 命令,一種是在程序中寫代碼開啓,這裏只講第一種,第二種參考文末的引用1。
ulimit -c unlimied # 表示不限制core文件大小 ulimit -c 10 # 設置最大大小,單位爲塊,一塊默認爲512字節
上面是臨時開啓,永久開啓要修改 /etc/security/limits.conf
文件,增長一行:
# /etc/security/limits.conf # <domain> <type> <item> <value> * soft core unlimited
這樣就能夠生成 core 文件,文件名就是 core,而且默認在當前程序所在目錄下生成,若是要指定目錄,則能夠 echo "/tmp/corefile-%e-%p-%t" > /proc/sys/kernel/core_pattern
設置 core 文件保存在目錄 "/tmp/corefile" 下,文件名格式爲 「core-命令名-pid-時間戳」
還能夠經過 echo 1 > /proc/sys/kernel/core_uses_pid
使得生成的 core 文件變成 core.pid
,pid 是該進程的 pid。
使用
gdb <program> core文件名
或者 gdb 啓動後,使用
-core <file>
-c <file>
來調試 core 文件
下面是一個例子:
#include <stdio.h> int func(int *p) { int y = *p; return y; } int main() { int *p = NULL; return func(p); }
編譯:gdb -g -o core_dump core_dump.c
,用 gdb 查看 core 文件
root@root:~$ gcc core_demo.c -o core_demo -g root@root:~$ ./core_demo Segmentation fault (core dumped) root@root:~$ gdb core_demo core_demo.core.24816 ... Core was generated by './core_demo'. Program terminated with signal 11, Segmentation fault. #0 0x080483cd in func (p=0x0) at core_demo.c:5 5 int y = *p; (gdb) where #0 0x080483cd in func (p=0x0) at core_demo.c:5 #1 0x080483ef in main () at core_demo.c:12 (gdb) info frame Stack level 0, frame at 0xffd590a4: eip = 0x80483cd in func (core_demo.c:5); saved eip 0x80483ef called by frame at 0xffd590c0 source language c. Arglist at 0xffd5909c, args: p=0x0 Locals at 0xffd5909c, Previous frame's sp is 0xffd590a4 Saved registers: ebp at 0xffd5909c, eip at 0xffd590a0 (gdb)
能夠看到,咱們能夠還原 core_demo 執行時的場景,並使用 where 查看當前程序調用函數棧幀,還可使用 gdb 中的命令查看寄存器,變量等信息。
開啓 GDB 調試時出現:
Missing separate debuginfos, use: debuginfo-install libgcc-4.8.5-28.el7_5.1.x86_64 numactl-libs-2.0.9-7.el7.x86_64
解決:
/etc/yum.repos.d/CentOS-Debuginfo.repo
中的enabled
參數,將其值修改成 1yum install nss-softokn-debuginfo --nogpgcheck
debuginfo-install glibc
若是出現下面的問題: -bash: debuginfo-install: command not found
,則先安裝yum-utils
,使用命令: yum install yum-utils
use: debuginfo-install libgcc-4.8.5-28.el7_5.1.x86_64 numactl-libs-2.0.9-7.el7.x86_64
3 GDB 調試利器
公衆號後臺回覆「加羣」,帶你進入高手如雲交流羣
個人公衆號 「Linux雲計算網絡」(id: cloud_dev) ,號內有 10T 書籍和視頻資源,後臺回覆 「1024」 便可領取,分享的內容包括但不限於 Linux、網絡、雲計算虛擬化、容器Docker、OpenStack、Kubernetes、工具、SDN、OVS、DPDK、Go、Python、C/C++編程技術等內容,歡迎你們關注。