日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢(xún)
選擇下列產(chǎn)品馬上在線(xiàn)溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷(xiāo)解決方案
手把手教你使用GNU調(diào)試器

如果你是一個(gè)程序員,想在你的軟件增加某些功能,你首先考慮實(shí)現(xiàn)它的方法:例如寫(xiě)一個(gè)方法、定義一個(gè)類(lèi),或者創(chuàng)建新的數(shù)據(jù)類(lèi)型。然后你用編譯器或解釋器可以理解的編程語(yǔ)言來(lái)實(shí)現(xiàn)這個(gè)功能。但是,如果你覺(jué)得你所有代碼都正確,但是編譯器或解釋器依然無(wú)法理解你的指令怎么辦?如果軟件大多數(shù)情況下都運(yùn)行良好,但是在某些環(huán)境下出現(xiàn)缺陷怎么辦?這種情況下,你得知道如何正確使用調(diào)試器找到問(wèn)題的根源。

創(chuàng)新互聯(lián)建站專(zhuān)業(yè)為企業(yè)提供交口網(wǎng)站建設(shè)、交口做網(wǎng)站、交口網(wǎng)站設(shè)計(jì)、交口網(wǎng)站制作等企業(yè)網(wǎng)站建設(shè)、網(wǎng)頁(yè)設(shè)計(jì)與制作、交口企業(yè)網(wǎng)站模板建站服務(wù),10年交口做網(wǎng)站經(jīng)驗(yàn),不只是建網(wǎng)站,更提供有價(jià)值的思路和整體網(wǎng)絡(luò)服務(wù)。

GNU 調(diào)試器GNU Project Debugger(??GDB??)是一個(gè)發(fā)現(xiàn)項(xiàng)目缺陷的強(qiáng)大工具。它通過(guò)追蹤程序運(yùn)行過(guò)程中發(fā)生了什么來(lái)幫助你發(fā)現(xiàn)程序錯(cuò)誤或崩潰的原因。(LCTT 校注:GDB 全程是“GNU Project Debugger”,即 “GNU 項(xiàng)目調(diào)試器”,但是通常我們簡(jiǎn)稱(chēng)為“GNU 調(diào)試器”)

本文是 GDB 基本用法的實(shí)踐教程。請(qǐng)跟隨示例,打開(kāi)命令行并克隆此倉(cāng)庫(kù):

git clone https://github.com/hANSIc99/core_dump_example.git

快捷方式

GDB 的每條命令都可以縮短。例如:顯示設(shè)定的斷點(diǎn)的 ??info break??? 命令可以被縮短為 ??i break??。你可能在其他地方看到過(guò)這種縮寫(xiě),但在本文中,為了清晰展現(xiàn)使用的函數(shù),我將所寫(xiě)出整個(gè)命令。

命令行參數(shù)

你可以將 GDB 附加到每個(gè)可執(zhí)行文件。進(jìn)入你克隆的倉(cāng)庫(kù)(??core_dump_example???),運(yùn)行 ??make??? 進(jìn)行編譯。你現(xiàn)在能看到一個(gè)名為 ??coredump??? 的可執(zhí)行文件。(更多信息,請(qǐng)參考我的文章《??創(chuàng)建和調(diào)試 Linux 的轉(zhuǎn)儲(chǔ)文件??》。)

要將 GDB 附加到這個(gè)可執(zhí)行文件,請(qǐng)輸入: ??gdb coredump??。

你的輸出應(yīng)如下所示:

gdb coredump output

返回結(jié)果顯示沒(méi)有找到調(diào)試符號(hào)。

調(diào)試信息是目標(biāo)文件object file(可執(zhí)行文件)的組成部分,調(diào)試信息包括數(shù)據(jù)類(lèi)型、函數(shù)簽名、源代碼和操作碼之間的關(guān)系。此時(shí),你有兩種選擇:

  • 繼續(xù)調(diào)試匯編代碼(參見(jiàn)下文“無(wú)符號(hào)調(diào)試”)
  • 使用調(diào)試信息進(jìn)行編譯,參見(jiàn)下一節(jié)內(nèi)容

使用調(diào)試信息進(jìn)行編譯

為了在二進(jìn)制文件中包含調(diào)試信息,你必須重新編譯。打開(kāi) ??Makefile???,刪除第 9 行的注釋標(biāo)簽(??#??)后重新編譯:

CFLAGS =-Wall -Werror -std=c++11 -g

??-g??? 告訴編譯器包含調(diào)試信息。運(yùn)行 ??make clean???,接著運(yùn)行 ??make??,然后再次調(diào)用 GDB。你得到如下輸出后就可以調(diào)試代碼了:

GDB output with symbols

新增的調(diào)試信息會(huì)增加可執(zhí)行文件的大小。在這種情況下,執(zhí)行文件增加了 2.5 倍(從 26,088 字節(jié) 增加到 65,480 字節(jié))。

輸入 ??run -c1???,使用 ??-c1??? 開(kāi)關(guān)啟動(dòng)程序。當(dāng)程序運(yùn)行到達(dá) ??State_4?? 時(shí)將崩潰:

gdb output crash on c1 switch

你可以檢索有關(guān)程序的其他信息,??info source?? 命令提供了當(dāng)前文件的信息:

gdb info source output

  • 101 行代碼
  • 語(yǔ)言: C++
  • 編譯器(版本、調(diào)優(yōu)、架構(gòu)、調(diào)試標(biāo)志、語(yǔ)言標(biāo)準(zhǔn))
  • 調(diào)試格式:??DWARF 2??
  • 沒(méi)有預(yù)處理器宏指令(使用 GCC 編譯時(shí),宏僅在??使用 -g3 標(biāo)志編譯?? 時(shí)可用)。

??info shared?? 命令打印了動(dòng)態(tài)庫(kù)列表機(jī)器在虛擬地址空間的地址,它們?cè)趩?dòng)時(shí)被加載到該地址,以便程序運(yùn)行:

gdb info shared output

如果你想了解 Linux 中的庫(kù)處理方式,請(qǐng)參見(jiàn)我的文章 ??在 Linux 中如何處理動(dòng)態(tài)庫(kù)和靜態(tài)庫(kù)??。

調(diào)試程序

你可能已經(jīng)注意到,你可以在 GDB 中使用 ??run??? 命令啟動(dòng)程序。??run??? 命令接受命令行參數(shù),就像從控制臺(tái)啟動(dòng)程序一樣。??-c1??? 開(kāi)關(guān)會(huì)導(dǎo)致程序在第 4 階段崩潰。要從頭開(kāi)始運(yùn)行程序,你不用退出 GDB,只需再次運(yùn)行 ??run??? 命令。如果沒(méi)有 ??-c1??? 開(kāi)關(guān),程序?qū)⑾萑胨姥h(huán),你必須使用 ??Ctrl+C?? 來(lái)結(jié)束死循環(huán)。

gdb output stopped by sigint

你也可以一步一步運(yùn)行程序。在 C/C++ 中,入口是 ??main??? 函數(shù)。使用 ??list main??? 命令打開(kāi)顯示 ??main?? 函數(shù)的部分源代碼:

gdb output list main

??main??? 函數(shù)在第 33 行,因此可以輸入 ??break 33?? 在 33 行添加斷點(diǎn):

gdb output breakpoint added

輸入 ??run??? 運(yùn)行程序。正如預(yù)期的那樣,程序在 ??main??? 函數(shù)處停止。輸入 ??layout src?? 并排查看源代碼:

gdb output break at main

你現(xiàn)在處于 GDB 的文本用戶(hù)界面(TUI)模式??梢允褂面I盤(pán)向上和向下箭頭鍵滾動(dòng)查看源代碼。

GDB 高亮顯示當(dāng)前執(zhí)行行。你可以輸入 ??next???(??n??)命令逐行執(zhí)行命令。如果你沒(méi)有指定新的命令,GBD 會(huì)執(zhí)行上一條命令。要逐行運(yùn)行代碼,只需按回車(chē)鍵。

有時(shí),你會(huì)發(fā)現(xiàn)文本的輸出有點(diǎn)顯示不正常:

gdb output corrupted

如果發(fā)生這種情況,請(qǐng)按 ??Ctrl+L?? 重置屏幕。

使用 ??Ctrl+X+A??? 可以隨時(shí)進(jìn)入和退出 TUI 模式。你可以在手冊(cè)中找到 ??其他的鍵綁定?? 。

要退出 GDB,只需輸入 ??quit??。

設(shè)置監(jiān)察點(diǎn)

這個(gè)示例程序的核心是一個(gè)在無(wú)限循環(huán)中運(yùn)行的狀態(tài)機(jī)。??n_state?? 變量枚舉了當(dāng)前所有狀態(tài):

while(true){
switch(n_state){
case State_1:
std::cout << "State_1 reached" << std::flush;
n_state = State_2;
break;
case State_2:
std::cout << "State_2 reached" << std::flush;
n_state = State_3;
break;

(.....)

}
}

如果你希望當(dāng) ??n_state??? 的值為 ??State_5??? 時(shí)停止程序。為此,請(qǐng)?jiān)?nbsp;??main??? 函數(shù)處停止程序并為 ??n_state?? 設(shè)置監(jiān)察點(diǎn):

watch n_state == State_5

只有當(dāng)所需的變量在當(dāng)前上下文中可用時(shí),使用變量名設(shè)置監(jiān)察點(diǎn)才有效。

當(dāng)你輸入 ??continue?? 繼續(xù)運(yùn)行程序時(shí),你會(huì)得到如下輸出:

gdb output stop on watchpoint_1

如果你繼續(xù)運(yùn)行程序,當(dāng)監(jiān)察點(diǎn)表達(dá)式評(píng)估為 ??false?? 時(shí) GDB 將停止:

gdb output stop on watchpoint_2

你可以為一般的值變化、特定的值、讀取或?qū)懭霑r(shí)來(lái)設(shè)置監(jiān)察點(diǎn)。

更改斷點(diǎn)和監(jiān)察點(diǎn)

輸入 ??info watchpoints?? 打印先前設(shè)置的監(jiān)察點(diǎn)列表:

gdb output info watchpoints

刪除斷點(diǎn)和監(jiān)察點(diǎn)

如你所見(jiàn),監(jiān)察點(diǎn)就是數(shù)字。要?jiǎng)h除特定的監(jiān)察點(diǎn),請(qǐng)先輸入 ??delete??? 后輸入監(jiān)察點(diǎn)的編號(hào)。例如,我的監(jiān)察點(diǎn)編號(hào)為 2;要?jiǎng)h除此監(jiān)察點(diǎn),輸入 ??delete 2??。

注意: 如果你使用 ??delete?? 而沒(méi)有指定數(shù)字,所有 監(jiān)察點(diǎn)和斷點(diǎn)將被刪除。

這同樣適用于斷點(diǎn)。在下面的截屏中,我添加了幾個(gè)斷點(diǎn),輸入 ??info breakpoint?? 打印斷點(diǎn)列表:

gdb output info breakpoints

要?jiǎng)h除單個(gè)斷點(diǎn),請(qǐng)先輸入 ??delete??? 后輸入斷點(diǎn)的編號(hào)。另外一種方式:你可以通過(guò)指定斷點(diǎn)的行號(hào)來(lái)刪除斷點(diǎn)。例如,??clear 78?? 命令將刪除第 78 行設(shè)置的斷點(diǎn)號(hào) 7。

禁用或啟用斷點(diǎn)和監(jiān)察點(diǎn)

除了刪除斷點(diǎn)或監(jiān)察點(diǎn)之外,你可以通過(guò)輸入 ??disable??,后輸入編號(hào)禁用斷點(diǎn)或監(jiān)察點(diǎn)。在下文中,斷點(diǎn) 3 和 4 被禁用,并在代碼窗口中用減號(hào)標(biāo)記:

disabled breakpoints

也可以通過(guò)輸入類(lèi)似 ??disable 2 - 4??? 修改某個(gè)范圍內(nèi)的斷點(diǎn)或監(jiān)察點(diǎn)。如果要重新激活這些點(diǎn),請(qǐng)輸入 ??enable??,然后輸入它們的編號(hào)。

條件斷點(diǎn)

首先,輸入 ??delete??? 刪除所有斷點(diǎn)和監(jiān)察點(diǎn)。你仍然想使程序停在 ??main??? 函數(shù)處,如果你不想指定行號(hào),可以通過(guò)直接指明該函數(shù)來(lái)添加斷點(diǎn)。輸入 ??break main??? 從而在 ??main?? 函數(shù)處添加斷點(diǎn)。

輸入 ??run??? 從頭開(kāi)始運(yùn)行程序,程序?qū)⒃?nbsp;??main?? 函數(shù)處停止。

??main??? 函數(shù)包括變量 ??n_state_3_count??,當(dāng)狀態(tài)機(jī)達(dá)到狀態(tài) 3 時(shí),該變量會(huì)遞增。

基于 ??n_state_3_count?? 的值添加一個(gè)條件斷點(diǎn),請(qǐng)輸入:

break 54 if n_state_3_count == 3

Set conditional breakpoint

繼續(xù)運(yùn)行程序。程序?qū)⒃诘?54 行停止之前運(yùn)行狀態(tài)機(jī) 3 次。要查看 ??n_state_3_count?? 的值,請(qǐng)輸入:

print n_state_3_count

print variable

使斷點(diǎn)成為條件斷點(diǎn)

你也可以使現(xiàn)有斷點(diǎn)成為條件斷點(diǎn)。用 ??clear 54??? 命令刪除最近添加的斷點(diǎn),并通過(guò)輸入 ??break 54?? 命令添加一個(gè)簡(jiǎn)單的斷點(diǎn)。你可以輸入以下內(nèi)容使此斷點(diǎn)成為條件斷點(diǎn):

condition 3 n_state_3_count == 9

??3?? 指的是斷點(diǎn)編號(hào)。

modify breakpoint

在其他源文件中設(shè)置斷點(diǎn)

如果你的程序由多個(gè)源文件組成,你可以在行號(hào)前指定文件名來(lái)設(shè)置斷點(diǎn),例如,??break main. cpp:54??。

捕捉點(diǎn)

除了斷點(diǎn)和監(jiān)察點(diǎn)之外,你還可以設(shè)置捕獲點(diǎn)。捕獲點(diǎn)適用于執(zhí)行系統(tǒng)調(diào)用、加載共享庫(kù)或引發(fā)異常等事件。

要捕獲用于寫(xiě)入 STDOUT 的 ??write?? 系統(tǒng)調(diào)用,請(qǐng)輸入:

catch syscall write

catch syscall write output

每當(dāng)程序?qū)懭肟刂婆_(tái)輸出時(shí),GDB 將中斷執(zhí)行。

在手冊(cè)中,你可以找到一整章關(guān)于 ??斷點(diǎn)、監(jiān)察點(diǎn)和捕捉點(diǎn)?? 的內(nèi)容。

評(píng)估和操作符號(hào)

用 ??print??? 命令可以打印變量的值。一般語(yǔ)法是 ??print <表達(dá)式> <值>??。修改變量的值,請(qǐng)輸入:

set variable  .

在下面的截屏中,我將變量 ??n_state_3_count??? 的值設(shè)為 ??123??。

catch syscall write output

??/x??? 表達(dá)式以十六進(jìn)制打印值;使用 ??&?? 運(yùn)算符,你可以打印虛擬地址空間內(nèi)的地址。

如果你不確定某個(gè)符號(hào)的數(shù)據(jù)類(lèi)型,可以使用 ??whatis?? 來(lái)查明。

whatis output

如果你要列出 ??main??? 函數(shù)范圍內(nèi)可用的所有變量,請(qǐng)輸入 ??info scope main?? :

info scope main output

??DW_OP_fbreg?? 值是指基于當(dāng)前子程序的堆棧偏移量。

或者,如果你已經(jīng)在一個(gè)函數(shù)中并且想要列出當(dāng)前堆棧幀上的所有變量,你可以使用 ??info locals?? :

info locals output

查看手冊(cè)以了解更多 ??檢查符號(hào)?? 的內(nèi)容。

附加調(diào)試到一個(gè)正在運(yùn)行的進(jìn)程

??gdb attach <進(jìn)程 ID>??? 命令允許你通過(guò)指定進(jìn)程 ID(PID)附加到一個(gè)已經(jīng)在運(yùn)行的進(jìn)程進(jìn)行調(diào)試。幸運(yùn)的是,??coredump??? 程序?qū)⑵洚?dāng)前 PID 打印到屏幕上,因此你不必使用 ??ps??? 或 ??top?? 手動(dòng)查找 PID。

啟動(dòng) ??coredump?? 應(yīng)用程序的一個(gè)實(shí)例:

./coredump

coredump application

操作系統(tǒng)顯示 PID 為 ??2849???。打開(kāi)一個(gè)單獨(dú)的控制臺(tái)窗口,移動(dòng)到 ??coredump?? 應(yīng)用程序的根目錄,然后用 GDB 附加到該進(jìn)程進(jìn)行調(diào)試:

gdb attach 2849

attach GDB to coredump

當(dāng)你用 GDB 附加到進(jìn)程時(shí),GDB 會(huì)立即停止進(jìn)程運(yùn)行。輸入 ??layout src??? 和 ??backtrace?? 來(lái)檢查調(diào)用堆棧:

layout src and backtrace output

輸出顯示在 ??main.cpp??? 第 92 行調(diào)用 ??std::this_thread::sleep_for<...>(. ..)?? 函數(shù)時(shí)進(jìn)程中斷。

只要你退出 GDB,該進(jìn)程將繼續(xù)運(yùn)行。

你可以在 GDB 手冊(cè)中找到有關(guān) ??附加調(diào)試正在運(yùn)行的進(jìn)程?? 的更多信息。

在堆棧中移動(dòng)

在命令窗口,輸入 ??up??? 兩次可以在堆棧中向上移動(dòng)到 ??main.cpp?? :

moving up the stack to main.cpp

通常,編譯器將為每個(gè)函數(shù)或方法創(chuàng)建一個(gè)子程序。每個(gè)子程序都有自己的棧幀,所以在棧幀中向上移動(dòng)意味著在調(diào)用棧中向上移動(dòng)。

你可以在手冊(cè)中找到有關(guān) ??堆棧計(jì)算?? 的更多信息。

指定源文件

當(dāng)調(diào)試一個(gè)已經(jīng)在運(yùn)行的進(jìn)程時(shí),GDB 將在當(dāng)前工作目錄中尋找源文件。你也可以使用 ??目錄命令?? 手動(dòng)指定源目錄。

評(píng)估轉(zhuǎn)儲(chǔ)文件

閱讀 ??創(chuàng)建和調(diào)試 Linux 的轉(zhuǎn)儲(chǔ)文件?? 了解有關(guān)此主題的信息。

參考文章太長(zhǎng),簡(jiǎn)單來(lái)說(shuō)就是:

  1. 假設(shè)你使用的是最新版本的 Fedora
  2. 使用??-c1??? 開(kāi)關(guān)調(diào)用 coredump:??coredump -c1???
  3. 使用 GDB 加載最新的轉(zhuǎn)儲(chǔ)文件:??coredumpctl debug??
  4. 打開(kāi) TUI 模式并輸入??layout src??

coredump output

??backtrace??? 的輸出顯示崩潰發(fā)生在距離 ??main.cpp??? 五個(gè)棧幀之外。回車(chē)直接跳轉(zhuǎn)到 ??main.cpp?? 中的錯(cuò)誤代碼行:

up 5 output

看源碼發(fā)現(xiàn)程序試圖釋放一個(gè)內(nèi)存管理函數(shù)沒(méi)有返回的指針。這會(huì)導(dǎo)致未定義的行為并引起 ??SIGABRT??。

無(wú)符號(hào)調(diào)試

如果沒(méi)有源代碼,調(diào)試就會(huì)變得非常困難。當(dāng)我在嘗試解決逆向工程的挑戰(zhàn)時(shí),我第一次體驗(yàn)到了這一點(diǎn)。了解一些 ??匯編語(yǔ)言?? 的知識(shí)會(huì)很有用。

我們用例子看看它是如何運(yùn)行的。

找到根目錄,打開(kāi) ??Makefile??,然后像下面一樣編輯第 9 行:

CFLAGS =-Wall -Werror -std=c++11 #-g

要重新編譯程序,先運(yùn)行 ??make clean???,再運(yùn)行 ??make??,最后啟動(dòng) GDB。該程序不再有任何調(diào)試符號(hào)來(lái)引導(dǎo)源代碼的走向。

no debugging symbols

??info file?? 命令顯示二進(jìn)制文件的內(nèi)存區(qū)域和入口點(diǎn):

info file output

??.text??? 區(qū)段始終從入口點(diǎn)開(kāi)始,其中包含實(shí)際的操作碼。要在入口點(diǎn)添加斷點(diǎn),輸入 ??break *0x401110??? 然后輸入 ??run?? 開(kāi)始運(yùn)行程序:

breakpoint at the entry point

要在某個(gè)地址設(shè)置斷點(diǎn),使用取消引用運(yùn)算符 ??*?? 來(lái)指定地址。

選擇反匯編程序風(fēng)格

在深入研究匯編之前,你可以選擇要使用的 ??匯編風(fēng)格??。 GDB 默認(rèn)是 AT&T,但我更喜歡 Intel 語(yǔ)法。變更風(fēng)格如下:

changing assembly flavor

現(xiàn)在輸入 ??layout asm??? 調(diào)出匯編代碼窗口,輸入 ??layout reg?? 調(diào)出寄存器窗口。你現(xiàn)在應(yīng)該看到如下輸出:

set disassembly-flavor intel

layout asm and layout reg output

保存配置文件

盡管你已經(jīng)輸入了許多命令,但實(shí)際上還沒(méi)有開(kāi)始調(diào)試。如果你正在大量調(diào)試應(yīng)用程序或嘗試解決逆向工程的難題,則將 GDB 特定設(shè)置保存在文件中會(huì)很有用。

該項(xiàng)目的 GitHub 存儲(chǔ)庫(kù)中的 ??gdbinit?? 配置文件包含最近使用的命令:

set disassembly-flavor intel
set write on
break *0x401110
run -c2
layout asm
layout reg

??set write on?? 命令使你能夠在程序運(yùn)行期間修改二進(jìn)制文件。

退出 GDB 并使用配置文件重新啟動(dòng) GDB : ??gdb -x gdbinit coredump??。

閱讀指令

應(yīng)用 ??c2??? 開(kāi)關(guān)后,程序?qū)⒈罎?。程序在入口函?shù)處停止,因此你必須寫(xiě)入 ??continue?? 才能繼續(xù)運(yùn)行:

continuing execution after crash

??idiv??? 指令進(jìn)行整數(shù)除法運(yùn)算:??RAX??? 寄存器中為被除數(shù),指定參數(shù)為除數(shù)。商被加載到 ??RAX??? 寄存器中,余數(shù)被加載到 ??RDX?? 中。

從寄存器角度,你可以看到 ??RAX??? 包含 ??5???,因此你必須找出存儲(chǔ)堆棧中位置為 ??rbp-0x4?? 的值。

讀取內(nèi)存

要讀取原始內(nèi)存內(nèi)容,你必須指定比讀取符號(hào)更多的參數(shù)。在匯編輸出中向上滾動(dòng)一點(diǎn),可以看到堆棧的劃分:

stack division output

你最感興趣的應(yīng)該是 ??rbp-0x4??? 的值,因?yàn)樗?nbsp;??idiv??? 的存儲(chǔ)參數(shù)。你可以從截圖中看到??rbp-0x8??? 位置的下一個(gè)變量,所以 ??rbp-0x4?? 位置的變量是 4 字節(jié)寬。

在 GDB 中,你可以使用 ??x?? 命令查看任何內(nèi)存內(nèi)容:

??x/??? < 可選參數(shù) ??n???、??f???、??u??? > < 內(nèi)存地址 ??addr?? >

可選參數(shù):

  • ??n??:?jiǎn)卧笮〉闹貜?fù)計(jì)數(shù)(默認(rèn)值:1)
  • ??f???:格式說(shuō)明符,如??printf??
  • ??u??:?jiǎn)卧笮?/li>
  • ??b??:字節(jié)
  • ??h??:半字(2 個(gè)字節(jié))
  • w: 字(4 個(gè)字節(jié))(默認(rèn))
  • g: 雙字(8 個(gè)字節(jié))

要打印 ??rbp-0x4??? 的值,請(qǐng)輸入 ??x/u $rbp-4?? :

print value

如果你能記住這種模式,則可以直接查看內(nèi)存。參見(jiàn)手冊(cè)中的 ??查看內(nèi)存?? 部分。

操作匯編

子程序 ??zeroDivide()?? 發(fā)生運(yùn)算異常。當(dāng)你用向上箭頭鍵向上滾動(dòng)一點(diǎn)時(shí),你會(huì)找到下面信息:

0x401211 <_Z10zeroDividev>              push   rbp
0x401212 <_Z10zeroDividev+1> mov rbp,rsp

這被稱(chēng)為 ??函數(shù)前言??:

  1. 調(diào)用函數(shù)的基指針(??rbp??)存放在棧上
  2. 棧指針(??rsp???)的值被加載到基指針(??rbp??)

完全跳過(guò)這個(gè)子程序。你可以使用 ??backtrace??? 查看調(diào)用堆棧。在 ??main??? 函數(shù)之前只有一個(gè)堆棧幀,所以你可以用一次 ??up??? 回到 ??main?? :

Callstack assembly

在你的 ??main?? 函數(shù)中,你會(huì)找到下面信息:

0x401431      cmp    BYTE PTR [rbp-0x12],0x0
0x401435 je 0x40145f
0x401437 call 0x401211<_Z10zeroDividev>

子程序 ??zeroDivide()??? 僅在 ??jump equal (je)??? 為 ??true??? 時(shí)進(jìn)入。你可以輕松地將其替換為 ??jump-not-equal (jne)??? 指令,該指令的操作碼為 ??0x75???(假設(shè)你使用的是 x86/64 架構(gòu);其他架構(gòu)上的操作碼不同)。輸入 ??run?? 重新啟動(dòng)程序。當(dāng)程序在入口函數(shù)處停止時(shí),設(shè)置操作碼:

set *(unsigned char*)0x401435 = 0x75

最后,輸入 ??continue??? 。該程序?qū)⑻^(guò)子程序 ??zeroDivide()?? 并且不會(huì)再崩潰。

總結(jié)

你會(huì)在許多集成開(kāi)發(fā)環(huán)境(IDE)中發(fā)現(xiàn) GDB 運(yùn)行在后臺(tái),包括 Qt Creator 和 VSCodium 的 ??本地調(diào)試?? 擴(kuò)展。

GDB in VSCodium

了解如何充分利用 GDB 的功能很有用。一般情況下,并非所有 GDB 的功能都可以在 IDE 中使用,因此你可以從命令行使用 GDB 的經(jīng)驗(yàn)中受益。


本文題目:手把手教你使用GNU調(diào)試器
瀏覽地址:http://www.5511xx.com/article/dhcgjoc.html