溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

如何分析gdb的使用技巧

發(fā)布時(shí)間:2022-01-06 16:14:20 來源:億速云 閱讀:150 作者:柒染 欄目:云計(jì)算

如何分析gdb的使用技巧,針對(duì)這個(gè)問題,這篇文章詳細(xì)介紹了相對(duì)應(yīng)的分析和解答,希望可以幫助更多想解決這個(gè)問題的小伙伴找到更簡(jiǎn)單易行的方法。

01 概念

    GDB是一個(gè)由GNU開源組織發(fā)布的、UNIX/LINUX操作系統(tǒng)下的、基于命令行的、功能強(qiáng)大的程序調(diào)試工具。

    在實(shí)際應(yīng)用中,有兩種調(diào)試方法:在線調(diào)試和離線調(diào)試。

    離線調(diào)試適用于開發(fā)測(cè)試環(huán)境,可以自由啟停進(jìn)程,設(shè)置斷點(diǎn);在線調(diào)試一般用于現(xiàn)場(chǎng)問題分析,不能隨便啟停進(jìn)程,對(duì)于技術(shù)要求較高。

02 前提條件

2.1 編譯

    若想執(zhí)行g(shù)db調(diào)試,在Makefile文件中需要增加編譯調(diào)試選項(xiàng)-g,例如:

    gdb dup_file.c –o dum_file_elf –g –lpthread

    說明:-g選項(xiàng)的作用是在可執(zhí)行文件(ELF)中加入源代碼的相關(guān)信息,比如ELF中第幾條機(jī)器指令對(duì)應(yīng)源代碼的行數(shù)。但不是把整個(gè)源文件嵌入到可執(zhí)行文件中,所以在調(diào)試時(shí)必須保證gdb能找到源文件。

    -g完整格式是-glevel,其中,level中指定了調(diào)試信息中包含了調(diào)試信息的多少,默認(rèn)的是2,level=1最少,level=3最多。

2.2 readelf查看段信息

    例如:

    readelf -S helloWorld|grep debug

    注:helloWorld為文件名,如果沒有任何debug信息,則不能被調(diào)試。

2.3 file查看strip狀況

    下面的情況也是不可調(diào)試的:

    file helloWorld

    helloWorld: (省略前面內(nèi)容) stripped

    注:如果最后是stripped,則說明該文件的符號(hào)表信息和調(diào)試信息已被去除,不能使用gdb調(diào)試。但是not stripped的情況并不能說明能夠被調(diào)試。

03 使用方法

3.1 啟動(dòng)調(diào)試

    在開發(fā)中可以將源碼和可執(zhí)行文件拷貝到某一目錄下,使用gdb啟動(dòng)進(jìn)程進(jìn)行調(diào)試,也可以不拷貝源碼和可執(zhí)行文件,使用NFS掛載到編譯環(huán)境執(zhí)行調(diào)試;在現(xiàn)場(chǎng)環(huán)境中使用ps獲取進(jìn)程的pid,然后gdb –p pid執(zhí)行在線調(diào)試。

    離線調(diào)試:

    gdb 進(jìn)程名

    gdb –tui 進(jìn)程名

    在線調(diào)試:

    ps –A | grep 進(jìn)程名

    gdb –p pid/gdb attach pid

    說明:使用-tui參數(shù)可以將調(diào)試窗口分為兩部分:上面是源碼,下面是調(diào)試信息,使用Ctrl+n/Ctrl+p或者方向鍵進(jìn)行翻頁。

    帶參數(shù)調(diào)試:

    1、啟動(dòng)的時(shí)候帶上參數(shù)

    gdb --args xxx 參數(shù)

    2、啟動(dòng)之后 run 帶上參數(shù)

    # gdb xxx

    (gdb)run 參數(shù)

    3、啟動(dòng)之后 set args 設(shè)置參數(shù)

    # gdb xxx

    (gdb)set args 參數(shù)

    core文件調(diào)試

    當(dāng)程序core dump時(shí),可能會(huì)產(chǎn)生core文件,它能夠很大程序幫助我們定位問題。但前提是系統(tǒng)沒有限制core文件的產(chǎn)生??梢允褂妹頻imit -c查看:

    $ ulimit -c

    如果結(jié)果是0,即便程序core dump了也不會(huì)有core文件留下。我們需要讓core文件能夠產(chǎn)生:

    ulimit -c unlimied  #表示不限制core文件大小

ulimit -c 10  #設(shè)置最大大小,單位為塊,一塊默認(rèn)為512字節(jié)

    上面兩種方式可選其一。第一種無限制,第二種指定最大產(chǎn)生的大小。

    針對(duì)生成core文件進(jìn)行調(diào)試,可以采用在線加載和離線加載的方式,如下:

  gdb 可執(zhí)行文件 core文件

3.2 SET命令

如何分析gdb的使用技巧  

    注:有時(shí)候使用p打印調(diào)試信息不完整或者不便于閱讀,可以使用set print elelent 0和setprint pretty on設(shè)置。

3.3 handle命令

    handle命令

    handle SIGUSR1 nostop noprint

    handle SIGUSR2 nostop noprint

    handle SIGPIPE nostop noprint

    handle SIGALARM nostop

    handle SIGHUP nostop

    handle SIGTERM nostop noprint

    注:設(shè)置GDB調(diào)試時(shí)對(duì)信號(hào)的相關(guān)動(dòng)作。

3.4 設(shè)置斷點(diǎn)

    打斷點(diǎn)還是比較有技巧的,雖然有很多打斷點(diǎn)的方法,但是實(shí)際調(diào)試中一般就使用以下幾種:

   函數(shù)打斷點(diǎn):b 函數(shù)名

   某一行打斷點(diǎn):b 源文件:行號(hào)

    條件斷點(diǎn):

    break 斷點(diǎn) if 條件

    continue 斷點(diǎn)編號(hào)(執(zhí)行一次表示設(shè)定,再次執(zhí)行表示取消)

    continue 斷點(diǎn)編號(hào) 條件

    注:條件斷點(diǎn)非常有用,實(shí)際調(diào)試中往往需要調(diào)試特定場(chǎng)景下函數(shù)調(diào)用關(guān)系,此時(shí)就需要設(shè)置斷點(diǎn)觸發(fā)的條件。

    查看斷點(diǎn):info breakpoint/info break/info b

    刪除斷點(diǎn):delete 斷點(diǎn)號(hào)/delete(刪除所有斷點(diǎn))

    禁用/開啟斷點(diǎn):disable/enable breakpoint

    ignore:

    斷點(diǎn)條件的一個(gè)特殊用法是,程序只有在到達(dá)斷點(diǎn)一定次數(shù)之后才會(huì)停止,此時(shí)可以使用指令:

    ignore 斷點(diǎn)編號(hào) 次數(shù)

    ignore 2 10觸發(fā)斷點(diǎn)10次后才會(huì)停止,每次觸發(fā)斷點(diǎn)count自動(dòng)減1

    說明:打完斷點(diǎn)是不是執(zhí)行continue就可以等待著運(yùn)行到斷點(diǎn)了呢?不一定,有時(shí)候斷點(diǎn)處代碼的執(zhí)行需要外部出發(fā),比如web發(fā)送特定消息后才可以觸發(fā)執(zhí)行,如果一直等待沒有消息出發(fā)永遠(yuǎn)執(zhí)行不到斷點(diǎn)處,此時(shí)就需要結(jié)合自己的業(yè)務(wù)邏輯,手動(dòng)設(shè)置出發(fā)條件。

3.5 執(zhí)行程序

    執(zhí)行程序的方法有兩種:一種是從main函數(shù)開始執(zhí)行逐步分析,一種是執(zhí)行到斷點(diǎn)處。

    重新運(yùn)行:r/run

    繼續(xù)執(zhí)行:c/continue

    單步執(zhí)行:n/next/next N(執(zhí)行N次next)

    單步進(jìn)入:step(遇到函數(shù)進(jìn)入函數(shù)內(nèi)部,退出函數(shù)時(shí)使用finish)

    結(jié)束函數(shù):finish

    強(qiáng)制返回:return(忽略當(dāng)前未執(zhí)行的部分,強(qiáng)制返回)

3.6 顯示堆棧

    (gbd) backstrace/bt

    有時(shí)候跳轉(zhuǎn)的次數(shù)太多,不知道具體調(diào)用的層級(jí)關(guān)系了,可以使用bt查看堆棧,該命令會(huì)產(chǎn)生一張列表,包含著運(yùn)行過程和相關(guān)的參數(shù)。

3.7 變量操作

  設(shè)置變量:set 變量=表達(dá)式

    在調(diào)試的時(shí)候,有時(shí)候需要設(shè)置一些假數(shù)據(jù)查看對(duì)應(yīng)輸出,比如根據(jù)布爾值查看流程執(zhí)行情況,此時(shí)就需要在執(zhí)行到指定位置時(shí)手動(dòng)設(shè)置一下數(shù)據(jù)的取值。

   監(jiān)控變量:

    watch 變量 (數(shù)值改變時(shí)暫停運(yùn)行)

    awatch <表達(dá)式> (被訪問或改變時(shí)暫停運(yùn)行)

    rwatch <表達(dá)式>  (被訪問時(shí)暫停運(yùn)行)

    有時(shí)候我們需要觀察一個(gè)變量的變化過程,比如一個(gè)全局變量如何初始化,如何調(diào)用的,這就需要使用watch監(jiān)控變量。

    變量類型:

    ptype var 變量類型

    whatis var 顯示一個(gè)變量var的類型

    打印變量/表達(dá)式:

    打印變量:p 變量      

    打印字符/表達(dá)式:p “%s”,字符/表達(dá)式

    格式化輸出:p/格式控制符 打印內(nèi)容

    說明:

    gdb可支持的變量顯示格式有:

    x:按16進(jìn)制格式顯示變量

    d:按10進(jìn)制格式顯示變量

    u:按16進(jìn)制格式顯示無符號(hào)整型

    o:按8進(jìn)制格式顯示變量

    t:按2進(jìn)制格式顯示變量

    c:按字符格式顯示變量

    f:按浮點(diǎn)數(shù)格式顯示變量

    也可以使用x(Examination)來打印需要顯示的字符信息,格式如下:

    x/格式 地址

    格式(可選)一般是NFU:

    1、N表示重復(fù)次數(shù)(表示顯示內(nèi)存的長(zhǎng)度,也就是說從當(dāng)前向后顯示幾個(gè)地址的內(nèi)容)

    2、F表示顯示格式

    3、U表示單位(b:字節(jié),h:半字[2字節(jié)],w:字[4字節(jié),默認(rèn)],g:雙字[8字節(jié)])。表示多少個(gè)字節(jié)作為一個(gè)值取出來,如果不指定的話,GDB默認(rèn)是1個(gè)byte,當(dāng)我們指定了字節(jié)長(zhǎng)度后,GDB會(huì)從指定內(nèi)存的地址開始,讀取指定字節(jié),并把其作為一個(gè)值取出來。

    參數(shù)u可使用下面字符代替:

    b:表示單字節(jié)

    h:表示雙字節(jié)

    w:表示四字節(jié)

    g:表示八字節(jié)

3.8 調(diào)試函數(shù)

    disassemble    

    可以使用反匯編的指令disassemble去探究究竟在函數(shù)中發(fā)生了哪些操作,具體如下:

    1、disassemble

    2、disassemble 程序計(jì)數(shù)器

    3、disassemble 開始地址 結(jié)束地址

    格式1表示反匯編當(dāng)前整個(gè)函數(shù),格式2表示反匯編計(jì)數(shù)器所在函數(shù)的整個(gè)函數(shù),格式3表示反匯編從開始地址到結(jié)束地址的部分。

    call

    強(qiáng)制調(diào)用函數(shù):call 表達(dá)式

3.9 退出調(diào)試

    q/quit

    在執(zhí)行到斷點(diǎn)后,采用q/quit指令退出。

04 多進(jìn)程調(diào)試

4.1 配置

    detach-on-fork

    該屬性決定了gdb是同時(shí)調(diào)試父子進(jìn)程,還是在fork了子進(jìn)程之后,將子進(jìn)程分離出去。

    on:子進(jìn)程(或者父進(jìn)程,取決于gdb在初始時(shí),要調(diào)試的進(jìn)程,也就是follow-fork-mode的值)

    off:同時(shí)調(diào)試父子進(jìn)程,一個(gè)進(jìn)程處于被調(diào)試的狀態(tài),而另一個(gè)則被gdb掛起

設(shè)置:set detach-on-fork on/off

    follow-fork-mode

    該屬性決定了gdb在進(jìn)程調(diào)用fork之后的行為。

    set follow-fork-mode parent:默認(rèn)情況下,在調(diào)用fork之后,gdb選擇跟隨(也就是調(diào)試)父進(jìn)程,而子進(jìn)程則在處于運(yùn)行的狀態(tài)(此時(shí)父進(jìn)程處于阻塞的狀態(tài))。

    set follow-fork-mode child:fork之后gdb選擇調(diào)試子進(jìn)程,而父進(jìn)程處于運(yùn)行的狀態(tài)。

4.2 查看進(jìn)程

    查看當(dāng)前調(diào)試的進(jìn)程:info inferiors

05 多線程調(diào)試

5.1查看線程

    查看線程:info threads

    注:輸出信息前面有“*”表示調(diào)試的當(dāng)前線程(一般thread切換線程后查看)。

    有的程序會(huì)在運(yùn)行過程中主線程創(chuàng)建多個(gè)子線程,所以前后執(zhí)行info threads顯示的線程數(shù)是會(huì)動(dòng)態(tài)變化的。

5.2 查看線程堆棧

    查看所有線程堆棧:thread apply all bt

    查看指定線程堆棧:thread apply thread1 thread2... bt

5.3 切換線程

    切換線程:thread N

    注:通過打印counter,可以看到多個(gè)線程都是在運(yùn)行的,如果想要讓其他線程處于停止?fàn)顟B(tài),只有當(dāng)前調(diào)試的線程執(zhí)行,可以采用set scheduler-locking on。

5.4 阻塞線程

    阻塞其他線程,僅調(diào)試當(dāng)前線程工作:

 set scheduler-locking [on|off|step]

    運(yùn)行指定線程并允許其他線程并行執(zhí)行:

    thread apply N command

關(guān)于如何分析gdb的使用技巧問題的解答就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關(guān)注億速云行業(yè)資訊頻道了解更多相關(guān)知識(shí)。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

gdb
AI