免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
除錯專家---程序調(diào)試的利器GDB
除錯專家---程序調(diào)試的利器GDB

來源:ChinaITLab 收集整理

2004-11-29 16:46:00


   無論是多么優(yōu)秀的程序員,都難以保證自己在編寫代碼時不會出現(xiàn)任何錯誤,因此調(diào)試是軟件開發(fā)過程中的一個必不可少的組成部分。當(dāng)程序完成編譯之后,它很 可能無法正常運(yùn)行,或者會徹底崩潰,或者不能實(shí)現(xiàn)預(yù)期的功能。此時如何通過調(diào)試找到問題的癥結(jié)所在,就變成了擺在開發(fā)人員面前最嚴(yán)峻的問題。通常說來,軟 件項(xiàng)目的規(guī)模越大,調(diào)試起來就會越困難,越需要一個強(qiáng)大而高效的調(diào)試器作為后盾。對于Linux程序員來講,目前可供使用的調(diào)試器非常多,GDB(GNU DeBugger)就是其中較為優(yōu)秀的。
  
  初識GDB
  
  GDB是自由軟件基金會(Free Software Foundation,F(xiàn)SF)的軟件工具之一。它的作用是協(xié)助程序員找到代碼中的錯誤。如果沒有GDB的幫助,程序員要想跟蹤代碼的執(zhí)行流程,唯一的辦 法就是添加大量的語句來產(chǎn)生特定的輸出。但這一手段本身就可能會引入新的錯誤,從而也就無法對那些導(dǎo)致程序崩潰的錯誤代碼進(jìn)行分析。GDB的出現(xiàn)減輕了開 發(fā)人員的負(fù)擔(dān),他們可以在程序運(yùn)行的時候單步跟蹤自己的代碼,或者通過斷點(diǎn)暫時中止程序的執(zhí)行。此外,他們還能夠隨時察看變量和內(nèi)存的當(dāng)前狀態(tài),并監(jiān)視關(guān) 鍵的數(shù)據(jù)結(jié)構(gòu)是如何影響代碼運(yùn)行的。
  
  調(diào)試方法
  
  如果想對程序進(jìn)行調(diào)試,必須先在用GCC編譯源代碼時加上-g選項(xiàng),以便產(chǎn)生GDB所需要的調(diào)試符號信息。例如,debugme.c是一個存在錯誤程序,可以使用如下的命令對其進(jìn)行編譯,同時產(chǎn)生調(diào)試符號:
  # gcc -g debugme.c -o debugme
  
   如果愿意的話,還可以在編譯時使用“-ggdb”選項(xiàng)來生成更多的調(diào)試信息。由于這些調(diào)試信息中的相當(dāng)一部分是GDB所特有的,所以生成的代碼將無法在 其它調(diào)試器中正常調(diào)試。對于大多數(shù)情況來說,普通的-g選項(xiàng)就足夠了。需要注意的是,GCC雖然允許同時使用-g(調(diào)試)和-o(優(yōu)化)選項(xiàng),但優(yōu)化會影 響最終生成的代碼,導(dǎo)致程序源代碼和二進(jìn)制代碼之間的關(guān)系變得復(fù)雜起來。如果不想為調(diào)試制造障礙,建議不要將-g和-o選項(xiàng)一同使用,并且只在程序徹底調(diào) 試完后才開始進(jìn)行代碼優(yōu)化。這樣調(diào)試過程將變得相對輕松和愉快。
  
  基本應(yīng)用
  
  現(xiàn)在可以啟動GDB來調(diào)試已經(jīng)生成的可執(zhí)行程序debugme,命令如下:
  
  # gdb debugme
  GNU gdb Red Hat Linux (5.3post-0.20021129.18rh)
  ……
  (gdb)
  
  如果一切正常,GDB將被啟動并在屏幕上輸出版權(quán)信息,但如果使用了-q或--quiet選項(xiàng)則不會顯示它們。啟動GDB時另外一個有用的命令行選項(xiàng)是“-d dirname”,其中dirname是一個目錄名。該目錄名告訴GDB應(yīng)該到哪里去尋找源代碼。
  
   一旦出現(xiàn)GDB的命令提示符(gdb),就表明GDB已經(jīng)準(zhǔn)備好接收來自用戶的各種調(diào)試命令了。如果想在調(diào)試環(huán)境下運(yùn)行這個程序,可以使用GDB提供的 “run”命令,而程序在正常運(yùn)行時所需的各種參數(shù)可以作為“run”命令的參數(shù)傳入,或者使用單獨(dú)的“set args”命令進(jìn)行設(shè)置。如果在執(zhí)行“run”命令時沒有給出任何參數(shù),GDB將使用上一次“run”或“set args”命令指定的參數(shù)。如果想取消上次設(shè)置的參數(shù),可以執(zhí)行不帶任何參數(shù)的“set args”命令。下面嘗試在調(diào)試器中運(yùn)行這個程序:
  
  (gdb) run
  ……
  Program received signal SIGSEGV, Segmentation fault.
  0x4000c6ac in _dl_fini () from /lib/ld-linux.so.2
  
   最后一行輸出表明程序在調(diào)用動態(tài)鏈接庫/lib/ld-linux.so.2中的_dl_fini()函數(shù)時出現(xiàn)了錯誤,地址是0x4000c6ac。 這些對調(diào)試是非常重要的線索。另外還有一種信息對調(diào)試也很重要,就是錯誤發(fā)生時的函數(shù)調(diào)用層級關(guān)系,可以通過執(zhí)行“backtrace”命令來獲得。在使 用GDB調(diào)試命令時,用戶可以不必輸入完整的命令名稱,使用任何惟一的縮寫都可以。例如“backtrace”命令就可以縮寫成“back”甚至 “bt”。GDB還支持很多常用的Shell命令編輯特征,比如可以像在bash或tcsh中那樣按Tab鍵補(bǔ)齊命令。如果相關(guān)命令不惟一的話,則列出所 有可能的匹配項(xiàng)。此外鍵盤上的方向鍵可用來翻動歷史命令。
  
  GDB是一個源代碼級的調(diào)試器,使用“list”命令可以查看當(dāng)前調(diào)試對象的源代碼。該命令的通用格式為“list [m,n]”,表示顯示從m行開始到n行結(jié)束的代碼段,而不帶任何參數(shù)的“list”命令將顯示最近10行源代碼。
  
  設(shè)置斷點(diǎn)
   在調(diào)試有問題的代碼時,在某一點(diǎn)停止運(yùn)行往往很管用。這樣程序運(yùn)行到此外時會暫時掛起,等待用戶的進(jìn)一步輸入。GDB允許在幾種不同的代碼結(jié)構(gòu)上設(shè)置斷 點(diǎn),包括行號和函數(shù)名等,并且還允許設(shè)置條件斷點(diǎn),讓程序只有在滿足一定的條件時才停止執(zhí)行。要根據(jù)行號設(shè)置斷點(diǎn),可以使用“ break linenum”命令。要根據(jù)函數(shù)名設(shè)置斷點(diǎn),則應(yīng)該使用“break funcname”命令。
  
  在以上兩種情況中,GDB將在 執(zhí)行指定的行號或進(jìn)入指定的函數(shù)之前停止執(zhí)行程序。此時可以使用“print”顯示變量的值,或者使用“list”查看將要執(zhí)行的代碼。對于由多個源文件 組成的項(xiàng)目,如果想在執(zhí)行到非當(dāng)前源文件的某行或某個函數(shù)時停止執(zhí)行,可以使用如下形式的命令:
  
  # break filename:linenum
  # break filename:funcname
  
  條件斷點(diǎn)允許當(dāng)一定條件滿足時暫時停止程序的執(zhí)行。它對于調(diào)試來講非常有用。設(shè)置條件斷點(diǎn)的正確語法如下:
  
  break linenum if expr
  break funcname if expr
  
  其中expr是一個邏輯表達(dá)式。當(dāng)該表達(dá)式的值為真時,程序?qū)⒃谠摂帱c(diǎn)處暫時掛起。例如,下面的命令將在debugme程序的第38行設(shè)置一個條件斷點(diǎn)。當(dāng)程序運(yùn)行到該行時,如果count的值等于3,就將暫時停止執(zhí)行:
  (gdb) break 38 if count==3
  
  設(shè)置斷點(diǎn)是調(diào)試程序時最常用到的一種手段。它可以中斷程序的運(yùn)行,給程序員一個單步跟蹤的機(jī)會。使用命令“ break main”在main函數(shù)上設(shè)置斷點(diǎn)可以在程序啟動時就開始進(jìn)行跟蹤。
  
   接下去使用“continue”命令繼續(xù)執(zhí)行程序,直到遇到下一個斷點(diǎn)。如果在調(diào)試時設(shè)置了很多斷點(diǎn),可以隨時使用“info breakpoints”命令來查看設(shè)置的斷點(diǎn)。此外,開發(fā)人員還可以使用“delete”命令刪除斷點(diǎn),或者使用“disable”命令來使設(shè)置的斷點(diǎn) 暫時無效。被設(shè)置為無效的斷點(diǎn)在需要的時候可以用“enable”命令使其重新生效。
  
  觀察變量
  GDB最有用的特性之 一是能夠顯示被調(diào)試程序中幾乎任何表達(dá)式、變量或數(shù)組的類型和值,并且能夠用編寫程序所用的語言打印出任何合法表達(dá)式的值。查看數(shù)據(jù)最簡單的辦法是使用 “print”命令,只需在“print”命令后面加上變量表達(dá)式,就可以打印出此變量表達(dá)式的當(dāng)前值,示例如下:
  
  (gdb) print str
  $1 = 0x40015360 "Happy new year!\n"
  
   從輸出信息中可以看出,輸入字符串被正確地存儲在了字符指針str所指向的內(nèi)存緩沖區(qū)中。除了給出變量表達(dá)式的值外,“print”命令的輸出信息中還 包含變量標(biāo)號($1)和對應(yīng)的內(nèi)存地址(0x40015360)。變量標(biāo)號保存著被檢查數(shù)值的歷史記錄,如果此后還想訪問這些值,就可以直接使用別名而不 用重新輸入變量表達(dá)式。
  
  如果想知道變量的類型,可以使用“whatis”命令,示例如下:
  
  (gdb) whatis str
  type = char *
  
  對于第一次調(diào)試別人的代碼,或者面對的是一個異常復(fù)雜的系統(tǒng)時,“whatis”命令的作用不容忽視。
  
  單步執(zhí)行
  為了單步跟蹤代碼,可以使用單步跟蹤命令“step”,它每次執(zhí)行源代碼中的一行。
  
  在GDB中可以使用許多方法來簡化操作,除了可以將“step”命令簡化為“s”之外,還可以直接輸入回車鍵來重復(fù)執(zhí)行前面一條命令。
  
  除了可以用“step”命令來單步運(yùn)行程序之外,GDB還提供了另外一條單步調(diào)試命令“next”。兩者功能非常相似,差別在于如果將要被執(zhí)行的代碼行中包含函數(shù)調(diào)用,使用step命令將跟蹤進(jìn)入函數(shù)體內(nèi),而使用next命令則不進(jìn)入函數(shù)體內(nèi)。
  
  在進(jìn)入下一部分之前,使用下面的命令退出GDB:
  (gdb) quit
  
  分析核心(core)文件
  
   在程序發(fā)生崩潰時,有時可能無法直接運(yùn)行GDB來進(jìn)行調(diào)試。比如程序可能是在另外一臺機(jī)器上運(yùn)行的,或者因?yàn)槌绦驅(qū)r間比較敏感,所以手動跟蹤調(diào)試會產(chǎn) 生無法接受的延遲等。遇到這些情況,就只能等到程序運(yùn)行結(jié)束后才能判斷崩潰的原因了。這時需要用到Linux提供的core dump機(jī)制。當(dāng)程序中出現(xiàn)內(nèi)存操作錯誤時,會發(fā)生崩潰并產(chǎn)生核心文件。使用GDB可以對產(chǎn)生的核心文件進(jìn)行分析,找出程序是在什么時候崩潰的和在崩潰之 前程序都做了些什么。當(dāng)然,如果要用GDB來分析核心文件,也必須在編譯時加上-g選項(xiàng)來產(chǎn)生調(diào)試符號表。
  
  在分析核心文件之前必須確認(rèn)系統(tǒng)是否允許生成核心文件,很多Linux發(fā)行版在默認(rèn)時禁止生成核心文件。為了生成核心文件,首先必須執(zhí)行下面的命令:
  # ulimit -c unlimited
  
  然后就可以生成核心文件了。這里仍以前面的debugme程序?yàn)槔?,再次?zhí)行下面命令將產(chǎn)生核心文件:
  
  # ./debugme
  Enter a string to count words:Happy new year!
  The number of words is 3.
  Segmentation fault (core dumped)
  
  生成的核心文件名根據(jù)系統(tǒng)配置的不同會有所差異。要在GDB中分析核心文件,除了要給出核心文件的文件名外,還必須給出生成該核心文件的可執(zhí)行程序的名稱,示例如下:
  
  #gdb debugme core.547
  ……
  Program terminated with signal 11, Segmentation fault.
  Reading symbols from /lib/libc.so.6...done.
  ……
  
  從GDB的輸出信息中可以看出,產(chǎn)生這個核心文件的原因是因?yàn)槌绦蚴盏搅诵蛱枮?1的信號。如果想知道程序在崩潰之前運(yùn)行到了哪里,可以使用“backtrace”或“info stack”命令查看一下堆棧的歷史記錄。示例如下:
  
  (gdb) info stack
  #0 0x4000c6ac in _dl_fini () from /lib/ld-linux.so.2
  #1 0x40057940 in exit () from /lib/libc.so.6
  #2 0x4004291f in _libc_start_main () from /lib/libc.so.6
  
   由上可知,程序崩潰時正處于_dl_fini()函數(shù)之中。但很多時候程序員感興趣的可能并不是這個,而是exit()或 _libc_start_main()函數(shù),因?yàn)樗鼈儾趴赡苁菃栴}真正的癥結(jié)所在。GDB提供的“frame”命令可以用來在不同的調(diào)用上下文中切換。例 如下面的命令可以查看exit()函數(shù)在執(zhí)行時的狀況:
  
  (gdb) frame 1
  #1 0x40057940 in exit () from /lib/libc.so.6
  
  此外還可以用“up”或“down”命令在不同的函數(shù)調(diào)用上下文中切換。開發(fā)人員使用這三條命令可以很輕松地實(shí)現(xiàn)調(diào)用棧的遍歷。在分析核心文件時,通過將遍歷棧的命令和檢查變量值的“print”命令結(jié)合起來,就能夠復(fù)原程序運(yùn)行時的全部景象。
  
  調(diào)試其它進(jìn)程
  
   有時會遇到一種很特殊的調(diào)試需求,對當(dāng)前正在運(yùn)行的其它進(jìn)程進(jìn)行調(diào)試。這種情況有可能發(fā)生在那些無法直接在調(diào)試器中運(yùn)行的進(jìn)程身上,例如有的進(jìn)程只能在 系統(tǒng)啟動時運(yùn)行。另外如果需要對進(jìn)程產(chǎn)生的子進(jìn)程進(jìn)行調(diào)試的話,也只能采用這種方式。GDB可以對正在執(zhí)行的程序進(jìn)行調(diào)度,它允許開發(fā)人員中斷程序并查看 其狀態(tài),之后還能讓這個程序正常地繼續(xù)執(zhí)行。
  
  GDB提供了兩種方式來調(diào)試正在運(yùn)行的進(jìn)程:一種是在GDB命令行上指定進(jìn)程的PID,另一種是在GDB中使用“attach”命令。例如,開發(fā)人員可以先啟動debugme程序,讓其開始等待用戶的輸入。示例如下:
  
  #./debugme
  Enter a string to count words:
  
  接下去在另一個虛擬控制臺中用下面的命令查出該進(jìn)程對應(yīng)的進(jìn)程號:
  
  # ps -ax | grep debugme
  555 pts/1 S 0:00 ./debugme
  
  得到進(jìn)程的PID后,就可以使用GDB對其進(jìn)行調(diào)試了:
  
  # gdb debugme 555
  GNU gdb Red Hat Linux (5.3post-0.20021129.18rh)
  Attaching to program: /home/xiaowp/debugme, process 555
  Reading symbols from /lib/libc.so.6...done.
  ……
  
  在上面的輸出信息中,以Attaching to program開始的行表明GDB已經(jīng)成功地附加在PID為555的進(jìn)程上了。另外一種連接到其它進(jìn)程的方法是先用file命令加載調(diào)試時所需的符號表,然后再通過“attaché”命令進(jìn)行連接:
  
  (gdb) file /home/xiaowp/debugme
  Reading symbols from /home/xiaowp/debugme...done.
  (gdb) attach 555
  ……
  
  如果想知道程序現(xiàn)在運(yùn)行到了哪里,同樣可以使用“backtrace”命令。當(dāng)然也可以使用“step”命令對程序進(jìn)行單步調(diào)試。
  
  在完成調(diào)試之后,不要忘記用detach命令斷開連接,讓被調(diào)試的進(jìn)程可以繼續(xù)正常運(yùn)行:
  
  GDB是Linux下一個最基本的調(diào)試器,其功能非常豐富。完整地介紹GDB的功能可能需要幾百頁,本文只涵蓋了GDB的一些最常見的用法。作為一個合格的Linux程序員,花在GDB上的功夫和時間越多,從調(diào)試中獲得的益處就越多。

本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
關(guān)于在Linux系統(tǒng)中的gdb命令知識
linux下的C語言開發(fā)(gdb調(diào)試)
gdb 如何調(diào)用函數(shù)? | Linux 中國
Linux環(huán)境下的C/C++基礎(chǔ)調(diào)試技術(shù)1——初步了解 - gnuhpc的專欄 - CSD...
GDB調(diào)試-從入門實(shí)踐到原理
Gdb調(diào)試精粹及使用實(shí)例
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服