日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

GDB 调试指南

發(fā)布時間:2023/12/20 编程问答 55 豆豆
生活随笔 收集整理的這篇文章主要介紹了 GDB 调试指南 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

大家好,?好久沒給大家?guī)碓瓌?chuàng)干貨了,導(dǎo)致很多新來的小伙伴以為我這個號就是個機(jī)構(gòu)號,其實不是,這個是個人號,背后的小編我是一個有血有肉有情懷的人,不管怎么樣,我的目的是盡量帶給大家優(yōu)質(zhì)的干貨。

?

今天這篇總結(jié)了GDB的一個調(diào)試技巧,標(biāo)題取為「調(diào)試指南」一點都不夸張,基本濃縮了GDB調(diào)試所有會用到的功能,所有技術(shù)人都適用。如果覺得文章有幫助,煩請大家給我個在看分享,鼓勵我輸出更多干貨給大家。

?

?

00 介紹

GDB(GNU Debugger)是 UNIX 及 UNIX-like 下的強(qiáng)大調(diào)試工具,可以調(diào)試 ada, c, c++, asm, minimal, d, fortran, objective-c, go, java,pascal 等語言,這一份指南我們主要以 c 來作為例子。

01 基礎(chǔ)

1.1 判斷程序是否可調(diào)試

# gdb helloworld Reading symbols from helloWorld...(no debugging symbols found)...done.# gdb helloworld Reading symbols from helloWorld...done.

上面一種有?no debugging symbols found?表示不可調(diào)試,下面是可調(diào)式的。

或者?readelf 查看段信息:

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 信息,也不能調(diào)試。

1.2 開啟 gdb 編譯

加上?-g?選項:

gcc -g -o xxx xxx.c

1.3 gdb xxx 進(jìn)入調(diào)試

  • b 行號或函數(shù)?添加斷點

  • r?跑到下一個斷點

  • s?單步跟蹤

  • n?單步執(zhí)行

  • p?查看當(dāng)前程序的運行數(shù)據(jù) 比如:p a?輸出a變量的值 輸出格式可以設(shè)置:?比如p/d a?十進(jìn)制輸出a變量的值

  • p array@idx?可以查看數(shù)組 array 中 idx 處的值

  • 設(shè)置display,比如?display a?這樣以后每次調(diào)試都會輸出a變量的值

  • x?查看內(nèi)存地址中的值 語法:x/

  • l?查看原程序代碼,l 9?列出第9行附件的源碼(l 2,8?列出2-8行之間的數(shù)據(jù)),l func?列出指定函數(shù)附件的源碼

  • p x=8?在調(diào)試過程中修改變量x的值,下面生效

  • jump?實現(xiàn)跳轉(zhuǎn),可以是文件的行號,也可以是file:line,也可以是+num這種格式 jump address是代碼行的內(nèi)存地址

  • signal?產(chǎn)生信號量

  • return?強(qiáng)制返回

  • call?強(qiáng)制調(diào)用

  • until(簡寫u)?當(dāng)在一個循環(huán)體內(nèi)時,運行退出循環(huán)

  • until +行號?運行至某行停住,不僅僅跳出循環(huán)

  • finish?當(dāng)前函數(shù)執(zhí)行完,并打印函數(shù)返回時的堆棧地址和返回值及參數(shù)值等信息

  • skip?在 step 時跳過一些不想關(guān)注的函數(shù)或者某個文件的代碼,如?skip function add?表示跳過函數(shù) add,skip file step.c?跳過文件 step.c,info skip?查看跳過的信息。

  • c?繼續(xù)執(zhí)行 跳到下一個斷點

  • bt?查看堆棧

  • where?報錯時查看哪里出錯,與?bt?類似

  • info b?查看斷點情況

  • q?退出

  • ptype?輸出結(jié)構(gòu)體類型

  • info registers?顯示寄存器值,?info all-registers?顯示所有寄存器

  • info breakpoints?可以查看所有已設(shè)置的端點

1.5 命令進(jìn)階

1.5.1 設(shè)斷點

  • info breakpoints?查看所有斷點

  • b 9?或者?b test.c:9?根據(jù)行號設(shè)置斷點

  • b func?根據(jù)函數(shù)名設(shè)置斷點

  • b test.c:9 if b==0?根據(jù)程序某個條件會出現(xiàn)問題,設(shè)置該條件斷點(這樣當(dāng)出現(xiàn)問題時,會卡主,用來判斷是否是該問題)

  • rbreak print*?對所有 print 開頭的函數(shù)都設(shè)斷點,rbreak test.c:.?對test.c 中所有函數(shù)設(shè)斷點

  • tbreak test.c:9?設(shè)?臨時斷點?,即這個斷點只生效一次

  • ignore 1 30?忽略某個斷點的前面 30 次執(zhí)行,從第 31 次開始生效,節(jié)約時間

  • watch a?觀察某個值或表達(dá)式,什么時候發(fā)生變化

  • disable/enable num?禁用/啟用所有/某個斷點

  • clear?清除所有斷點,用于清除某個函數(shù),某行的斷點,如?clear func?、clear linenum

  • delete?刪除所有斷點,包括watchpoints, catchpoints,用于刪除斷點號的斷點,如?delete bnum

  • 1.5.2 查看變量

  • p 'test.c'::a?打印某個文件的變量,p 'main'::b?打印某個函數(shù)定義的變量

  • p *p@10?打印指針指向的內(nèi)容,@后面為打印的長度

  • p *$.next?打印鏈表linkNode的下一個節(jié)點內(nèi)容

  • p/x c?按十六進(jìn)制打印內(nèi)容(x:十六進(jìn)制,d:十進(jìn)制,o:八進(jìn)制,t:二進(jìn)制,c:字符格式,f:浮點格式)

  • x addr?查看內(nèi)存地址值

  • display e?程序斷住顯示某個變量的值

  • 1.5.3 編輯源碼

    啟動調(diào)試后,不想退出程序而編輯源碼,如何做呢?

    gdb 模式下用的默認(rèn)編輯器是?/bin/ex?,如果沒有或者想換成其他編輯器,如VIM,可以這樣:

    export EDITOR=/usr/bin/vim

    gdb 模式下編輯源碼:

    (gdb)edit 3 # 編輯第三行 (gdb)edit func # 編輯func函數(shù) (gdb)edit test.c:5 #編輯test.c第五行

    完了之后,重新編譯程序(?注意一定要帶上 shell 命令,表明是shell命令?):

    (gdb)shell gcc -g -o main main.c test.c

    或者這樣:

    啟動是帶上 tui(Text User Interface),可以在多個窗口調(diào)試:

    gdb main -tui

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

    1. 啟動的時候帶上參數(shù)

    gdb --args xxx 參數(shù)

    2. 啟動之后 run 帶上參數(shù)

    # gdb xxx (gdb)run 參數(shù)

    3. 啟動之后 set args 設(shè)置參數(shù)

    # gdb xxx (gdb) set args 參數(shù)

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

    2.1 attach 方法

  • 首先找到需調(diào)試的子進(jìn)程:ps -ef | grep xxx?或?pidof?進(jìn)程名

  • 進(jìn)入?gdb?模式,輸入?attach pid

  • 打斷點,運行進(jìn)入調(diào)試

  • 或者直接這樣:gdb <program> pid(或?gdb <program> --pid pid),gdb 會 自動 attach。

    如果出現(xiàn)如下錯誤:

    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

    2.2 follow-fork-mode mode 方法

  • 進(jìn)入?gdb?模式,輸入?set follow-fork-mode mode?(mode 可選 parent、child,表示調(diào)試父進(jìn)程還是子進(jìn)程)

  • 打斷點

  • 2.3 調(diào)試已運行程序

    已運行程序通常沒有調(diào)試信息,但如果不能停止當(dāng)前程序重新啟動調(diào)試,可以:

    同樣的代碼,再編譯出一個帶調(diào)試信息的版本,然后:

    # gdb (gdb) file hello Reading symbols from hello...done. (gdb)attach 20829

    03 調(diào)試多線程

    gdb?有一組命令能夠輔助多線程的調(diào)試:

    • info threads:顯示當(dāng)前可調(diào)式的所有線程,線程 ID 前有 “*” 表示當(dāng)前被調(diào)試的線程。

    • thread id:調(diào)試目標(biāo) id 指定的線程

    • set scheduler-locking [on|off|step]:多線程環(huán)境下,會存在多個線程運行,這會影響調(diào)試某個線程的結(jié)果,這個命令可以設(shè)置調(diào)試的時候多個線程的運行情況,on?表示只有當(dāng)前調(diào)試的線程會繼續(xù)執(zhí)行,off?表示不屏蔽任何線程,所有線程都可以執(zhí)行,step?表示在單步執(zhí)行時,只有當(dāng)前線程會執(zhí)行。

    04 coredump 調(diào)試

    coredump 調(diào)試依賴于 core 文件,core 文件是程序非法執(zhí)行后 core dump 后產(chǎn)生的文件。這是 Linux 系統(tǒng)的一種保護(hù)機(jī)制,當(dāng)出現(xiàn)某些連開發(fā)和測試費了九牛二虎之力都沒能發(fā)現(xiàn)的問題時,Linux 系統(tǒng)還提供了最后一道屏障,通過 core 文件就可以讓這些問題原形畢露。

    4.1 開啟 core dump

    要想讓程序崩潰時產(chǎn)生 core 文件,需要開啟,輸入?ulimit -c,如果輸出為 0,表示默認(rèn)關(guān)閉 core dump。

    有兩種方式可以開啟,一種就是通過 ulimit 命令,一種是在程序中寫代碼開啟,這里只講第一種,第二種參考文末的引用1。

    ulimit -c unlimied # 表示不限制core文件大小 ulimit -c 10 # 設(shè)置最大大小,單位為塊,一塊默認(rèn)為512字節(jié)

    上面是臨時開啟,永久開啟要修改?/etc/security/limits.conf?文件,增加一行:

    # /etc/security/limits.conf # <domain> <type> <item> <value>* soft core unlimited

    這樣就可以生成 core 文件,文件名就是 core,并且默認(rèn)在當(dāng)前程序所在目錄下生成,如果要指定目錄,則可以?echo "/tmp/corefile-%e-%p-%t" > /proc/sys/kernel/core_pattern?設(shè)置 core 文件保存在目錄 "/tmp/corefile" 下,文件名格式為 “core-命令名-pid-時間戳”

    還可以通過?echo 1 > /proc/sys/kernel/core_uses_pid?使得生成的 core 文件變成?core.pid,pid 是該進(jìn)程的 pid。

    4.2 調(diào)試 core dump

    使用

    gdb <program> core文件名

    或者 gdb 啟動后,使用

    • -core?<file>

    • -c <file>

    來調(diào)試 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 0x80483efcalled by frame at 0xffd590c0source language c.Arglist at 0xffd5909c, args: p=0x0Locals at 0xffd5909c, Previous frame's sp is 0xffd590a4Saved registers:ebp at 0xffd5909c, eip at 0xffd590a0 (gdb)

    可以看到,我們可以還原 core_demo 執(zhí)行時的場景,并使用 where 查看當(dāng)前程序調(diào)用函數(shù)棧幀,還可以使用 gdb 中的命令查看寄存器,變量等信息。

    常見問題

    問題 1

    開啟 GDB 調(diào)試時出現(xiàn):

    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參數(shù),將其值修改為 1

  • yum install nss-softokn-debuginfo --nogpgcheck

  • debuginfo-install glibc?如果出現(xiàn)下面的問題:?-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

  • 參考

    1 https://www.cnblogs.com/Anker/p/6079580.html

    2 http://www.cnblogs.com/hazir/p/linxu_core_dump.htm

    3 https://linuxtools-rst.readthedocs.io/zh_CN/latest/tool/gdb.html

    總結(jié)

    以上是生活随笔為你收集整理的GDB 调试指南的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。