GDB除錯詳解

2021-10-01 15:45:49 字數 4007 閱讀 4371

gdb除錯命令

linux下的c++程式開發,makefile,cmake等編譯工具最終都是呼叫gcc這一編譯工具組。

一般要除錯某個程式,為了清晰地看到除錯的每一行**,呼叫的堆疊資訊,變數名和函式名等資訊,需要除錯程式含有除錯符號資訊。

那麼判斷乙個可執行程式是否帶有除錯資訊?

gdb hello_world檢視顯示結果。

這時候在顯示資訊的最後一行,如果帶有除錯資訊,則顯示

reading symbols from /root/testclient/hello_server…done.

如果不帶除錯資訊,則顯示

reading symbols from /root/testclient/hello_server2…(no debugging symbols found)…done.

當然,對於乙個包含了除錯資訊的程式,我們也可以通過strip移除除錯資訊。

#strip hello_wrold
實際上生成除錯程式時,同時建議關閉編譯器的優化選項。因為不優化,可以讓符號檔案顯示的除錯變數等能和源**完全對應起來。

編譯器優化選項:o0-o4 5個級別,o0表示不優化,o1-o4表示優化級別越來越高。

gdb除錯程式分三種模式:

gdb filename :直接除錯目標程式

gdb attach pid : 附加程序

gdb filename corename :除錯core檔案

除錯程序

使用場景:當我們乙個程式正在執行,我們如何在不重啟這個程式的情況下對這個程式進行除錯呢(假如執行一段時間之後發現這個程式不再接受連線了)

gdb attack pid
當我們attach上目標程序後,偵錯程式會暫停下來,這時候我們可以用continue繼續執行程式。當然,也可以設定相應的斷點。

除錯結束後,我們可以用detach命令將程序與偵錯程式分離。最後再quit退出偵錯程式即可。

除錯core檔案

當我們的程式core dump的時候,我們可以用gdb幫助除錯這個問題。我們的linux系統在程式發生core dump的時候,有產生core檔案的機制。

通過ulimit -c 我們可以看到當前系統是否開啟了core檔案生成功能。

ulimit -c unlimited // core檔案的大小不受限制。

ulimit -c 100 //設定檔案大小最大為100k

當前設定只在本會話有效。

永久生效的方法:把ulimit -c unlimited加入/etc/profile

生成的core檔案的預設命名方式是core.pid。

gdb filename corename

這時候我們可以看到core dump的位置。我們可以通過bt命令檢視奔潰時的呼叫堆疊,進一步分析找到奔潰的原因。

但是,當程式core dump的時候,我們往往找不到pid,這時候我們就需要自定義core檔案的名稱了。

自定義core檔案的名稱

控制core檔案是否新增pid作為擴充套件

/proc/sys/kernel/core_uses_pid 檔案內容為1開啟,0關閉。

格式化控制core檔案的儲存位置和檔名。

/proc/sys/kernel/core_pattern

eg: /root/testcore/core-%e-%p-%t

引數說明:

%p:新增pid

%e:新增程式名

%t:新增時間戳

當然還有其他的引數格式,這裡只列舉了常用的三個。

run

在gdb開始除錯之後,並沒有直接執行啟動這個程式。r啟動這個程式。

當然了,假如這個程式已經啟動過,則再次輸入r命令,則是重啟這個程式。

continue

當程式觸發斷點,或者我們使用ctrl+c讓程式中斷下來,想讓程式繼續執行,c繼續執行。

break

新增斷點,新增斷點的方式有三種:

b func-name:在函式入口處新增

b lineno:在當前檔案對應的行號處新增

b filename:lineno:在對應檔案行號處新增

backtrace 與 frame

bt命令用來檢視當前程式呼叫的堆疊。f可以用來切換堆疊的層數

#0 anetlisten (err=0x746bb0 「」, s=10, sa=0x7e34e0, len=16, backlog=511) at anet.c:452

#1 0x0000000000426e35 in _anettcpserver (err=err@entry=0x746bb0 「」, port=port@entry=6379, bindaddr=bindaddr@entry=0x0, af=af@entry=10, backlog=511)

at anet.c:487

#2 0x000000000042793d in anettcp6server (err=err@entry=0x746bb0 「」, port=port@entry=6379, bindaddr=bindaddr@entry=0x0, backlog=511)

at anet.c:510

#3 0x000000000042b0bf in listentoport (port=6379, fds=fds@entry=0x746ae4 , count=count@entry=0x746b24 ) at server.c:1728

#4 0x000000000042fa77 in initserver () at server.c:1852

#5 0x0000000000423803 in main (argc=1, ar**=0x7fffffffe648) at server.c:3862

這裡可以看到呼叫順序是

server.c的main函式在3862呼叫了initserver

依次類推…

info break ,enable,disable,delete

info break:檢視斷點資訊

enable + 斷點編號:重新起用斷點

disable + 斷點編號:禁用斷點

delete + 斷點編號:刪除某個斷點,不加斷點編號則直接刪除所有斷點

list

顯示當前斷點的前後10行**,繼續輸入 list 指令會以遞增行號的形式繼續顯示剩下的**行。

list 指令還可以往前和往後顯示**,命令分別是「list + (加號)」和「list - (減號)」。

print

檢視變數的值,也可以修改當前記憶體中的變數值。

ptype

顧名思義,其含義是「print type」,輸出乙個變數的型別.

info

流程控制命令:next、step、until、finish、return 和 jump

這裡的return不同於finish,return不會繼續執行下面的內容。而是直接返回。

disassemble

檢視某段**的彙編指令去排查問題。

set args 和 show args

gdb啟動之後,在run之前,使用「set args 引數內容」來設定命令列引數。

(gdb)

set args "999 xx"

"hu jj"

如果想清除掉已經設定好的命令列引數,使用 set args 不加任何引數即可

tbreak

臨時斷點,就是一旦該斷點觸發一次後就會自動刪除

watch

監視乙個變數或者一段記憶體,當這個變數或者該記憶體處的值發生變化時,gdb 就會中斷下來。被監視的某個變數或者某個記憶體位址會產生乙個 watch point(觀察點)。

display

命令監視的變數或者記憶體位址,每次程式中斷下來都會自動輸出這些變數或記憶體的值。

gdb 除錯 vs除錯

一 先要生成二進位制檔案 g g 1.cpp o 1.out g引數不要省,不然 gdb l 引數用不了 二 引數 設定斷點 設定 函式斷點break func 在某行設定斷點break 7 檢視斷點資訊 info break 刪除斷點 d 刪除所有斷點 d 3 刪除第三個 執行 r 下一步 n 逐...

C 多型原理詳解(GDB除錯分析)

在計算類大小時提及到了類中虛指標及虛函式表的結構,但並沒有相對較為充足的依據,下來借助gdb工具來分析一下c 中虛指標及虛函式表的詳細結構 以下 執行環境均為linux下的64位作業系統 無繼承的單類案例 如下 include using namespace std class a virtual ...

使用GDB除錯多執行緒例項詳解

先寫一段多執行緒程式。makefile 加上 g引數生成可調式資訊,可以進行除錯。pthread不是linux下的預設的庫,也就是在鏈結的時候,無法找到phread庫中哥函式的入口位址,於是鏈結會失敗。在gcc編譯的時候,附加要加 lpthread引數即可解決。gdb test 進入除錯 需要除錯的...