用GDB调试程序(四)
—————
當程序被停住了,你需要做的第一件事就是查看程序是在哪里停住的。當你的程序調用了一個函數,函數的地址,函數參數,函數內的局部變量都會被壓入“棧”(Stack)中。你可以用GDB命令來查看當前的棧中的信息。
下面是一些查看函數調用棧信息的GDB命令:
??? backtrace
??? bt
??????? 打印當前的函數調用棧的所有信息。如:
???????
??????? (gdb) bt
??????? #0? func (n=250) at tst.c:6
??????? #1? 0x08048524 in main (argc=1, argv=0xbffff674) at tst.c:30
??????? #2? 0x400409ed in __libc_start_main () from /lib/libc.so.6
???????
??????? 從上可以看出函數的調用棧信息:__libc_start_main --> main() --> func()
???????
???
??? backtrace <n>
??? bt <n>
??????? n是一個正整數,表示只打印棧頂上n層的棧信息。
??? backtrace <-n>
??? bt <-n>
??????? -n表一個負整數,表示只打印棧底下n層的棧信息。
???????
如果你要查看某一層的信息,你需要在切換當前的棧,一般來說,程序停止時,最頂層的棧就是當前棧,如果你要查看棧下面層的詳細信息,首先要做的是切換當前棧。
??? frame <n>
??? f <n>
??????? n是一個從0開始的整數,是棧中的層編號。比如:frame 0,表示棧頂,frame 1,表示棧的第二層。
???
??? up <n>
??????? 表示向棧的上面移動n層,可以不打n,表示向上移動一層。
???????
??? down <n>
??????? 表示向棧的下面移動n層,可以不打n,表示向下移動一層。
???????
??? 上面的命令,都會打印出移動到的棧層的信息。如果你不想讓其打出信息。你可以使用這三個命令:
???
??????????? select-frame <n> 對應于 frame 命令。
??????????? up-silently <n> 對應于 up 命令。
??????????? down-silently <n> 對應于 down 命令。
???
查看當前棧層的信息,你可以用以下GDB命令:
??? frame 或 f
??????? 會打印出這些信息:棧的層編號,當前的函數名,函數參數值,函數所在文件及行號,函數執行到的語句。
???
??? info frame
??? info f
??????? 這個命令會打印出更為詳細的當前棧層的信息,只不過,大多數都是運行時的內內地址。比如:函數地址,調用函數的地址,被調用函數的地址,目前的函數是由什么樣的程序語言寫成的、函數參數地址及值、局部變量的地址等等。如:
??????????? (gdb) info f
??????????? Stack level 0, frame at 0xbffff5d4:
???????????? eip = 0x804845d in func (tst.c:6); saved eip 0x8048524
???????????? called by frame at 0xbffff60c
???????????? source language c.
???????????? Arglist at 0xbffff5d4, args: n=250
???????????? Locals at 0xbffff5d4, Previous frame's sp is 0x0
???????????? Saved registers:
????????????? ebp at 0xbffff5d4, eip at 0xbffff5d8
?????????????
???? info args
??????? 打印出當前函數的參數名及其值。
????
???? info locals
??????? 打印出當前函數中所有局部變量及其值。
???????
???? info catch
??????? 打印出當前的函數中的異常處理信息。
???????
???????
???????
???????
查看源程序
—————
一、顯示源代碼
??? GDB 可以打印出所調試程序的源代碼,當然,在程序編譯時一定要加上-g的參數,把源程序信息編譯到執行文件中。不然就看不到源程序了。當程序停下來以后,GDB會報告程序停在了那個文件的第幾行上。你可以用list命令來打印程序的源代碼。還是來看一看查看源代碼的GDB命令吧。
???
??? list <linenum>
??????? 顯示程序第linenum行的周圍的源程序。
???
??? list <function>
??????? 顯示函數名為function的函數的源程序。
???????
??? list
??????? 顯示當前行后面的源程序。
???
??? list -
??????? 顯示當前行前面的源程序。
一般是打印當前行的上5行和下5行,如果顯示函數是是上2行下8行,默認是10行,當然,你也可以定制顯示的范圍,使用下面命令可以設置一次顯示源程序的行數。
??? set listsize <count>
??????? 設置一次顯示源代碼的行數。
???????
??? show listsize
??????? 查看當前listsize的設置。
???????
list命令還有下面的用法:
??? list <first>, <last>
??????? 顯示從first行到last行之間的源代碼。
???
??? list , <last>
??????? 顯示從當前行到last行之間的源代碼。
???????
??? list +
??????? 往后顯示源代碼。
???????
一般來說在list后面可以跟以下這們的參數:
??? <linenum>?? 行號。
??? <+offset>?? 當前行號的正偏移量。
??? <-offset>?? 當前行號的負偏移量。
??? <filename:linenum>? 哪個文件的哪一行。
??? <function>? 函數名。
??? <filename:function> 哪個文件中的哪個函數。
??? <*address>? 程序運行時的語句在內存中的地址。
???
二、搜索源代碼
不僅如此,GDB還提供了源代碼搜索的命令:
??? forward-search <regexp>
??? search <regexp>
??????? 向前面搜索。
??? reverse-search <regexp>
??????? 全部搜索。
???????
其中,<regexp>就是正則表達式,也主一個字符串的匹配模式,關于正則表達式,我就不在這里講了,還請各位查看相關資料。
三、指定源文件的路徑
某些時候,用-g編譯過后的執行程序中只是包括了源文件的名字,沒有路徑名。GDB提供了可以讓你指定源文件的路徑的命令,以便GDB進行搜索。
??? directory <dirname ... >
??? dir <dirname ... >
??????? 加一個源文件路徑到當前路徑的前面。如果你要指定多個路徑,UNIX下你可以使用“:”,Windows下你可以使用“;”。
??? directory
??????? 清除所有的自定義的源文件搜索路徑信息。
???
??? show directories
??????? 顯示定義了的源文件搜索路徑。
???????
四、源代碼的內存
你可以使用info line命令來查看源代碼在內存中的地址。info line后面可以跟“行號”,“函數名”,“文件名:行號”,“文件名:函數名”,這個命令會打印出所指定的源碼在運行時的內存地址,如:
??????? (gdb) info line tst.c:func
??????? Line 5 of "tst.c" starts at address 0x8048456 <func+6> and ends at 0x804845d <func+13>.
還有一個命令(disassemble)你可以查看源程序的當前執行時的機器碼,這個命令會把目前內存中的指令dump出來。如下面的示例表示查看函數func的匯編代碼。
??????? (gdb) disassemble func
??????? Dump of assembler code for function func:
??????? 0x8048450 <func>:?????? push?? %ebp
??????? 0x8048451 <func+1>:???? mov??? %esp,%ebp
??????? 0x8048453 <func+3>:???? sub??? $0x18,%esp
??????? 0x8048456 <func+6>:???? movl?? $0x0,0xfffffffc(%ebp)
??????? 0x804845d <func+13>:??? movl?? $0x1,0xfffffff8(%ebp)
??????? 0x8048464 <func+20>:??? mov??? 0xfffffff8(%ebp),%eax
??????? 0x8048467 <func+23>:??? cmp??? 0x8(%ebp),%eax
??????? 0x804846a <func+26>:??? jle??? 0x8048470 <func+32>
??????? 0x804846c <func+28>:??? jmp??? 0x8048480 <func+48>
??????? 0x804846e <func+30>:??? mov??? %esi,%esi
??????? 0x8048470 <func+32>:??? mov??? 0xfffffff8(%ebp),%eax
??????? 0x8048473 <func+35>:??? add??? %eax,0xfffffffc(%ebp)
??????? 0x8048476 <func+38>:??? incl?? 0xfffffff8(%ebp)
??????? 0x8048479 <func+41>:??? jmp??? 0x8048464 <func+20>
??????? 0x804847b <func+43>:??? nop
??????? 0x804847c <func+44>:??? lea??? 0x0(%esi,1),%esi
??????? 0x8048480 <func+48>:??? mov??? 0xfffffffc(%ebp),%edx
??????? 0x8048483 <func+51>:??? mov??? %edx,%eax
??????? 0x8048485 <func+53>:??? jmp??? 0x8048487 <func+55>
??????? 0x8048487 <func+55>:??? mov??? %ebp,%esp
??????? 0x8048489 <func+57>:??? pop??? %ebp
??????? 0x804848a <func+58>:??? ret
??????? End of assembler dump.
出處:http://blog.csdn.net/haoel/article/details/2882
總結
以上是生活随笔為你收集整理的用GDB调试程序(四)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 用GDB调试程序(三)
- 下一篇: 用GDB调试程序(六)