電子產(chǎn)業(yè)一站式賦能平臺

PCB聯(lián)盟網(wǎng)

搜索
查看: 71|回復: 0
收起左側(cè)

GDB動態(tài)打印,不需重新編譯

[復制鏈接]

491

主題

491

帖子

3115

積分

四級會員

Rank: 4

積分
3115
跳轉(zhuǎn)到指定樓層
樓主
發(fā)表于 2024-11-5 11:38:00 | 只看該作者 |只看大圖 回帖獎勵 |倒序瀏覽 |閱讀模式
本系列專題,旨在介紹一些非常實用,卻不為大多數(shù)人所知的調(diào)試技巧。靈活運用這些調(diào)試技巧,能夠輕松解決一些我們經(jīng)常遇到并為之困惑的問題,大大提高程序調(diào)試的效率。
感興趣的朋友,歡迎關(guān)注!
引言 - 程序調(diào)試的痛關(guān)于程序調(diào)試,有人喜歡各種調(diào)試工具,有人喜歡用簡單直接的log打印。兩種方法各有各的優(yōu)勢和不足,大多時候是可以互補的。
在Linux環(huán)境下,GDB是各種調(diào)試工具中的佼佼者,而printf則是各種日志打印方法中的典型代表。

調(diào)試問題時候,你遇到過下面的情況嗎?
  • 代碼添加打印信息進行調(diào)試,突然發(fā)現(xiàn)添加打印的位置不對,或者別的地方也需要添加打印信息。
  • 于是,重新修改源碼,重新添加打印,重新編譯,重新部署,重新運行,重新調(diào)試,重新分析。
  • 當我們費了九牛二虎之力把這些都弄好之后,很不幸地又發(fā)現(xiàn)了新的問題,然后不得不反復進行這些過程。
  • 而且,當問題定位出來之后,我們之前花費很大力氣添加的調(diào)試信息,還必須從程序中刪除掉。


    對于簡單的程序,這些尚可接受。但是,在大型項目中,單是編譯構(gòu)建過程可能就要幾十分鐘,甚至數(shù)個小時,而部署過程則更為復雜。
    你能想象得出,在這樣的項目中一直重復這些過程,是一件多么痛苦的事情嗎?
    那么,有沒有一種方法,既不需要修改源碼,又能隨時在程序中任何地方任意添加打印信息呢?
    當然有!GDB的動態(tài)打印功能正式為此而生的!

    GDB Dynamic PrintfGDB提供了Dynamic Printf功能,下文我們稱之為動態(tài)打印。利用這個功能,我們可以在不修改程序源碼的情況下,隨時在程序的任何地方添加格式化打印。
    如此一來,當然也就不需要重新編譯和部署的過程了。
    我們先看一個簡單的示例,然后再詳細介紹它的實現(xiàn)原理,和相關(guān)命令的用法。
    示例一個簡單示例,如下圖所示:

    先編譯一下:
    gcc -g test.c -o test然后用GDB進行調(diào)試:

    和期望的一樣,程序沒有任何打印輸出。
    現(xiàn)在,我們在第6行、第11行、第14行分別添加一個動態(tài)打印斷點,用下面的命令:
    dprintf 6,"Hello, World!
    "
    dprintf 11,"i = %d, a = %d, b = %d
    ",i,a,b
    dprintf 14,"Leaving! Bye bye!
    "如下圖:

    稍微解釋一下:
    第6行的語句會打印一句“Hello, World!”
    第11行會把i、a、b的值分別打印出來
    第14行打印“Leaving! Bye bye!”
    設(shè)置好之后,查看一下斷點的信息:

    已經(jīng)設(shè)置成功了。然后,重新運行:

    看到了吧,盡管我們并沒有對源碼做任何修改,且沒有重新編譯,但程序仍然按照我們的設(shè)置,打印出了我們想要的信息!
    是不是很神奇呢?GDB的動態(tài)打印功能究竟是如何工作的呢?
    GDB 動態(tài)打印實現(xiàn)原理在上面的示例中,在設(shè)置好動態(tài)打印的信息之后,我們可以用info break命令查看所設(shè)置的信息。
    可見,GDB的動態(tài)打印,本質(zhì)上也是一種特殊的斷點。但是,它與一般的斷點又有所區(qū)別。
    一般的斷點被觸發(fā)后,會中斷程序執(zhí)行,然后等待用戶操作,并且用戶必須輸入continue命令讓程序恢復執(zhí)行。
    而動態(tài)打印斷點被觸發(fā)后,程序也會暫時中斷執(zhí)行,但是不需要等待用戶響應,而是直接執(zhí)行用戶預設(shè)的格式化打印語句,并自動恢復程序的執(zhí)行。
    GDB動態(tài)打印的使用方法設(shè)置動態(tài)打印的命令是dprintf,格式如下:
    dprintf location,format string,arg1,arg2,...dprintf命令和C語言中的printf的用法很相似,支持格式化打印。
    相比printf函數(shù),dprintf命令多了一個location參數(shù),用于指定動態(tài)打印被觸發(fā)的位置。
    和break命令設(shè)置斷點時一樣,location可以是文件名:行號、函數(shù)名、或者具體的地址等。
    除了location外,剩余的幾個參數(shù),就和printf()函數(shù)一致了。format指定字符串打印的格式,后面幾個參數(shù)指定打印的數(shù)據(jù)來源。
    以上面示例中的命令為例:
    dprintf 6,"Hello, World!
    "
    dprintf 11,"i = %d, a = %d, b = %d
    ",i,a,b
    dprintf 14,"Leaving! Bye bye!
    "在功能上等價于下圖中右側(cè)的代碼:

    到這里,GDB動態(tài)打印的最基本功能就介紹完了。
    斷點信息丟失怎么辦?在實際項目的調(diào)試過程中,難免會由于各種原因而必須要反復的調(diào)試才能定位出問題的原因,或者徹底理解程序的代碼邏輯。
    然而,dprintf本質(zhì)上也是一種斷點,因此,當調(diào)試結(jié)束后,本次調(diào)試時設(shè)置的斷點信息就全部丟失了。如果要再次調(diào)試的話,就不得不重新設(shè)置一遍。
    如果每次調(diào)試過程中,只需要設(shè)置一兩個動態(tài)打印的話,那倒也簡單。
    可是,如果需要設(shè)置十幾個甚至幾十個動態(tài)打印呢?難道每次調(diào)試都要全部重新設(shè)置一遍嗎?想想都是一件比較麻煩的事情,對吧?
    其實,GDB也有對應的處理方案,很簡單就可以解決!
    保存和加載GDB斷點信息為了解決上面提到的問題,GDB很貼心地提供了對斷點信息保存和加載的功能。
    GDB中,可以把當前所設(shè)置的各種類型的斷點信息全部保存在一個腳本文件中。這其中當然也包括dprintf設(shè)置的動態(tài)打印信息。
    只需要執(zhí)行下面的命令即可:
    save breakpoints file_name這條命令會把當前所有的斷點信息都保存在file_name指定的文件中。
    等下次進行調(diào)試時,可以把file_name文件中的斷點信息重新加載起來。有兩種方法:
    啟動GDB時使用“-x file_name”參數(shù)。
    在GDB中執(zhí)行source file_name命令。
    [/ol]下面分別演示一下。
    保存斷點信息
    我們用GDB重新啟動上面示例中的test程序:
    用dprintf設(shè)置好斷點。
    用info break命令查看一下斷點信息。
    執(zhí)行“save breakpoints test.bp”命令,把斷點信息保存在test.bp文件中。
    [/ol]

    我們看下一下test.bp中究竟保存了什么內(nèi)容:

    原來,就是我們之前執(zhí)行的三條dprintf命令,并且是以文本形式存在test.bp中的。
    接下來,我們用兩種方法分別加載test.bp中的斷點信息。
    用-x參數(shù)加載斷點信息

    可見,指定-x參數(shù)后,GDB在開始調(diào)試程序之前,會從指定的文件中把斷點信息加載進來,并重新設(shè)置在程序中。因此,執(zhí)行run命令后,程序能夠按照我們的預期正常執(zhí)行動態(tài)打印功能。
    source命令加載斷點信息

    GDB把test加載起來之后,info break并沒有顯示出任何斷點信息。然后,我們執(zhí)行source test.bp命令,GDB會把斷點信息從test.bp加載進來,并重新設(shè)置在test程序中。
    結(jié)語由于篇幅所限,本文只是介紹了GDB動態(tài)打印的基本功能和使用方法。其實,它還有很多高階的用法和技巧,以后會再更新文章進行講解。
    程序調(diào)試是每個程序員必須要熟練掌握的基本技能,在整個計算機知識體系結(jié)構(gòu)中,它占據(jù)著非常重要的地位。
    猜你喜歡:
    WiFi6+藍牙+星閃,三合一開發(fā)板,真香!
    Github上熱門 C 語言項目匯總!
    嵌入式,可測試性軟件設(shè)計!
    一些低功耗軟件設(shè)計的要點!
    嵌入式 C 保護結(jié)構(gòu)體的方式
    實用 | 10分鐘教你通過網(wǎng)頁點燈
    談談嵌入式軟件的兼容性!
    點擊閱讀原文,查看更多分享。
  • 回復

    使用道具 舉報

    發(fā)表回復

    您需要登錄后才可以回帖 登錄 | 立即注冊

    本版積分規(guī)則


    聯(lián)系客服 關(guān)注微信 下載APP 返回頂部 返回列表