linux中GDB详细使用手册
文章目錄
- 代碼調試記錄
- 使用方法,在主目錄下執(zhí)行make
- 準備
- 顯示寄存器
- 單步執(zhí)行
- 繼續(xù)執(zhí)行
- 監(jiān)視點
- 刪除斷點和監(jiān)視點
- 生成核心轉存儲文件
- attach 到進程
- detach 與進程分離
- 條件斷點
- 該命令可以給指定的斷點添加或者刪除觸發(fā)條件
- 反復執(zhí)行
- 刪除斷點和禁用斷點
- 斷點命令
- 常用命令即省略形式
- 值的歷史
- 變量
- 命令歷史
- 初始化文件(.gdbinit)
- 命令定義
- 調試必需的棧知識
- 調試器的backtrace
- GDB提供了操作棧幀的命令
- #內核調試的準備
- 應用程序調試實踐
- 發(fā)生SIGSEGV,應用程序異常停止
- 棧溢出導致SIGSEGV的應對方法
- backtrace 無法正確顯示
- 查看寄存器信息
- 數(shù)組非法訪問導致內存破壞
- 調查棧的方法
同步github地址
同步github地址: https://github.com/zzu-andrew/linux-sys/tree/dfew/DEBUG
QQ: 564631192
代碼調試記錄
使用方法,在主目錄下執(zhí)行make
因為執(zhí)行腳本的時候會自動新啟用一個子 bash因此在腳本中設置的ulimit -c unlimited
并不能產(chǎn)生核心轉存儲文件,需要執(zhí)行可執(zhí)行文件之前手動設置一下
ulimit -c unlimited
DEBUG 是在linux下使用dbg的記錄,一下的文件是在UBUNTU 16.04上驗證通過的
準備
1.通過gcc 的 -g 選項生成調試信息。
gcc -Wall -O2 -g 源文件2.如果使用Makefile構建,一般要給CFLAGS中指定 -g 選項
CFLAGS = -Wall -O2 -g CFLAGS = -Wall -Werror -O2 -g 加上 -Werror會在警告發(fā)生時,將其當成錯誤處理3.如果使用configure腳本生成Makefile文件,可以這樣使用。
./configure CFLAGS = "-Wall -O2 -g"啟動
gdb 可執(zhí)行文件名
可以在函數(shù)名和行號等上設置斷點,程序運行后,達到斷點就會自動暫停運行。此時可以查看時刻的變量值、顯示棧幀、重新設置斷點或重新運行等。斷點命令(break),可以簡寫為b.
##格式:
break 斷點
(gdb) b main
斷點可以通過函數(shù)名、當前文件內的行號來設置,也可以先指定文件名在指定行號,還可以指定與暫停位置的偏移量,或者地址來設置。
#格式說明:
例:
在函數(shù)處加斷點 (gdb)b iseq_compile 在文件名和行號處加斷點 (gdb)b compile.c:516 設置偏移量 (gdb)b +3 在某地址處加斷點 (gdb)b *0x88116fd6 如果不指定位置,就是在下一行代碼上設置斷點 (gdb)b 設置好的斷點可以通過 info break 查看 andrew@andrew-Thurley:/work/linux-sys/DEBUG/segmentation$ gdb segment GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1 Copyright (C) 2016 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "x86_64-linux-gnu". Type "show configuration" for configuration details. For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>. Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>. For help, type "help". Type "apropos word" to search for commands related to "word"... Reading symbols from segment...done. (gdb) b main Breakpoint 1 at 0x4004e1: file segment.c, line 12. (gdb) info b Num Type Disp Enb Address What 1 breakpoint keep y 0x00000000004004e1 in main at segment.c:12 (gdb) b +2 Note: breakpoint 1 also set at pc 0x4004e1. Breakpoint 2 at 0x4004e1: file segment.c, line 5. (gdb) info break Num Type Disp Enb Address What 1 breakpoint keep y 0x00000000004004e1 in main at segment.c:12 2 breakpoint keep y 0x00000000004004e1 in main at segment.c:5 (gdb)##運行
使用run命令開始運行,不加參數(shù)直接執(zhí)行run 就會執(zhí)行到設置斷點的位置后暫停運行。可以簡寫為 r
##格式
run 參數(shù) run 后面跟的參數(shù),也就是你執(zhí)行可執(zhí)行文件后面需要跟的參數(shù) (gdb)run -a start命令會達到同樣的效果。 格式: start##顯示棧幀
backtrace 命令可以在遇到斷點而停止執(zhí)行時顯示棧幀。該命令簡寫為 bt 。此外,backtrace的別名還有
where 和 info stack(info s)
##格式:
顯示所有棧幀backtrace bt只顯示開頭N個棧幀 backtrace N bt N只顯示最后N個棧幀 backtrace -N bt -N不僅顯示backtrace,還要顯示局部變量。N與前述的意思相同,表示N個(或者最后N個)棧幀 backtrace full bt fullbacktrace full N bt full Nbacktrace full -N bt full -N例: 顯示所有棧幀 (gdb)bt 只顯示前三個棧幀 (gdb)bt 3從外向內顯示3個棧幀,及局部變量 (gdb)bt full -3#顯示變量
print命令可以顯示變量。print可以簡寫為p
##格式;
print 變量(gdb)p argv顯示寄存器
info registers 可以顯示寄存器,簡寫info reg(gdb) info reg rax 0x0 0 rbx 0x0 0 rcx 0x0 0 rdx 0x7ffcab228958 140723179653464 rsi 0x7ffcab228948 140723179653448 rdi 0x1 1 rbp 0x7ffcab228860 0x7ffcab228860 rsp 0x7ffcab228860 0x7ffcab228860 r8 0x400570 4195696 r9 0x7f2203168ab0 139784057424560 r10 0x846 2118 r11 0x7f2202dae740 139784053516096 r12 0x4003e0 4195296 r13 0x7ffcab228940 140723179653440 r14 0x0 0 r15 0x0 0 rip 0x4004ed 0x4004ed <main+23> eflags 0x10246 [ PF ZF IF RF ] cs 0x33 51 ss 0x2b 43 ds 0x0 0 es 0x0 0 fs 0x0 0 gs 0x0 0--------------------- 在寄存器之前添加 $,即可以顯示各個寄存器的內容 (gdb)p $eax (gdb) p $rip $1 = (void (*)()) 0x4004ed <main+23> (gdb) p $eflags $2 = [ PF ZF IF RF ] (gdb) p $eax $3 = 0 (gdb) p $r8 $4 = 4195696 (gdb) p $rax $5 = 0 (gdb) p $rdx $6 = 140723179653464顯示時可以使用一下格式: p/格式 變量 顯示寄存器可以使用的格式: 格式 說明 x 顯示為十六進制數(shù) d 顯示為十進制數(shù) u 顯示為無符號十進制數(shù) o 顯示為八進制數(shù) t 顯示為二進制數(shù),t的由來是two a 地址 c 顯示為字符(ASCII) f 浮點小數(shù) s 顯示為字符串 i 顯示為機器語言(僅在顯示內存的X命令中可以使用) ------------------------------------------------------使用x命令可以顯示內存的內容,x這個名字的由來是eXamining。格式: x/格式 地址 (gdb) x $pc 0x4004ed <main+23>: 0x000100c7 (gdb) x /x 0x4004ed 0x4004ed <main+23>: 0x000100c7 (gdb) x/i $pc => 0x4004ed <main+23>: movl $0x1,(%rax)##x/i 的意思是顯示匯編指令 一般使用 x 命令時,格式為 x/NFU ADDR。此處ADDR為希望顯示的地址,N為重復的次數(shù),F為前面講過的格式(x,d,u,,o,t,a,c,f,s,i),U為表示2-4中所示的單位。---------------------------------------------- U代表的單位 單位 說明 b 字節(jié) h 半字(2字節(jié)) w 字(4字節(jié))(默認值) g 雙字(8字節(jié)) ----------------------------------------------#--> 從pc處顯示十條指令(gdb) x/10i0x4004f3 <main+29>: mov $0x0,%eax0x4004f8 <main+34>: pop %rbp0x4004f9 <main+35>: retq0x4004fa: nopw 0x0(%rax,%rax,1)0x400500 <__libc_csu_init>: push %r150x400502 <__libc_csu_init+2>: push %r140x400504 <__libc_csu_init+4>: mov %edi,%r15d0x400507 <__libc_csu_init+7>: push %r130x400509 <__libc_csu_init+9>: push %r120x40050b <__libc_csu_init+11>: lea 0x2008fe(%rip),%r12 # 0x600e10 --------------------------------------------------------1.disassemble. 2.disassemble 程序計數(shù)器 3.disassemble 開始地址 結束地址1 --> 反匯編當前整個函數(shù) 2 --> 反匯編程序計數(shù)器所在函數(shù)的整個函數(shù) 3 --> 反匯編從開始地址到結束地址之間的部分(gdb) disassemble $pc $pc+50單步執(zhí)行
單步執(zhí)行的意思是根據(jù)源代碼一行一行執(zhí)行。
執(zhí)行源代碼中的一行的命令為next(簡寫為 n)。執(zhí)行時如果遇到函數(shù)調用,可能想執(zhí)行到函數(shù)內部,此時可以使用step(簡寫為p) 命令。
也就是說當有子函數(shù)調用的時候,使用n命令直接執(zhí)行子函數(shù)獲得返回值,但是 step命令會進入子函數(shù)中執(zhí)行;
next命令和step命令都是執(zhí)行源代碼中的一行,若果要逐條執(zhí)行匯編指令,可以分別使用nexti命令和stepi命令
繼續(xù)執(zhí)行
調試時,可以使用continue(簡寫為c)命令繼續(xù)運行程序,程序會在遇到斷點后再次暫停運行,
如果 沒有遇到斷點就會一直運行到結束。
監(jiān)視點
大型軟件或大量使用指針的程序中,很難男女感情變量在什么地方被改變。想要找到變量在何處被改變,可以使用watch命令(監(jiān)視點,watchpoint)。
格式:
watch <表達式>
<表達式>發(fā)生變化時暫停運行。
此處表達式的意識是常量或變量等。
格式:
awatch <表達式>
<表達式>被訪問,改變時暫停運行。
格式:
rwatch <表達式>
<表達式>被訪問時暫停運行。
刪除斷點和監(jiān)視點
用delete(簡寫為 d)命令刪除斷點和監(jiān)視點。
格式:
生成核心轉存儲文件
使用generate-core-file可將調試中的進程生成核心轉存儲文件
功能,將正在調試的文件生成核心轉存儲文件
有了內核轉存儲文件和調試對象,以后就能查看生成轉存儲文件時的運行歷史(寄存器值,內存值等)。
例:
此外,gcore命令可以從命令行直接生成內核轉存儲文件。
gcore 'pidof emacs' 該命令無須停止正在運行的程序以獲得內核轉存儲文件,當需要在其他機器上單獨分析問題原因,或者是分心客戶現(xiàn)場發(fā)生的問題時,十分有用。attach 到進程
detach 與進程分離
確認行為之后,需要在gdb和進程分離時使用detach命令,這樣調試中的進程就被從gdb的控制下釋放出來,進程被detach后會繼續(xù)運行
進程信息可以使用info proc命令顯示
(gdb) info proc process 22440 cmdline = '/work/linux-sys/DEBUG/watch/watch' cwd = '/work/linux-sys/DEBUG/watch' exe = '/work/linux-sys/DEBUG/watch/watch'要調試守護進程(daemon process)等已經(jīng)啟動的進程,或者調試陷入死循環(huán)而無法返回的控制臺進程時,可以使用attach命令
格式:
執(zhí)行這一命令就可以attach到進程ID為pid的進程上。
下面使用sleep命令進行GDB調試
條件斷點
在特定條件下執(zhí)行中斷
格式:
break 斷點 if 條件這條命令將測試給定的條件,如果條件為真暫停運行。
例:
格式:
刪除指定斷點的出發(fā)條件condition 斷點編號 添加指定斷點的出發(fā)條件condition 斷點編號 條件該命令可以給指定的斷點添加或者刪除觸發(fā)條件
反復執(zhí)行
ignore 斷點編號 次數(shù)在指定的斷點、監(jiān)視點(watchpoint)或捕獲點(catchpoint)忽略指定的次數(shù)。
continue命令與ignore命令一樣,可以指定次數(shù),達到指定次數(shù)前執(zhí)行到斷點時不暫停,
二者意義相同。
格式;
continue 次數(shù) step 次數(shù) stepi 次數(shù) next 次數(shù) nexti 次數(shù)這些命分別執(zhí)行指定次數(shù)的相應命令。
格式:
finish 命令執(zhí)行完當前函數(shù)后暫停,until命令執(zhí)行完當前函數(shù)等代碼塊后暫停,
若果是循環(huán),則執(zhí)行完循環(huán)后暫停,常用于跳出循環(huán)。
刪除斷點和禁用斷點
用clear 命令刪除已定義的斷點,如果要保留定義,只想臨時禁用斷點的話,可以使用disable命令;
將禁用的斷點重新啟用,可以使用enable命令;
格式:
格式:
disable [breakpoints] disable [breakpoints] 斷點編號 disable display 顯示編號 disable mem 內存區(qū)域如果不指定斷點編號,則禁用多有的斷點,否則禁用指定斷點
第3種命令禁用display命令定義的自動顯示
第4中格式禁用mem命令定義的內存區(qū)域
可以省略breakpoints關鍵字
格式:
enable [breakpoints] enable [breakpoints] 斷點編號 enable [breakpoints] once 斷點編號 enable [breakpoints] delete 斷點編號 enable display 顯示編號 enable mem 內存區(qū)域這些格式用于顯示斷點,once指定的斷點只啟用一次,也就是說,程序運行到該斷點并暫停后,該斷點即被禁用。
這與delete命令助攻的once不同,后者在運行暫停后刪除斷點
斷點命令
斷點命令(commands)可以定義在斷點中斷后執(zhí)行的命令
格式:
程序在執(zhí)行到斷點處暫停后,就會自動執(zhí)行命令
(gdb)b main (gdb)command 2>p *b>end (gdb)c與前面的條件斷點組合使用,就可以在斷點暫停時,執(zhí)行復雜的顯示動作等
break foo if x>0commandssilentprintf "x is %d\n", xcontend常用命令即省略形式
命令 簡寫形式 說明 backtrace bt、where 顯示backtrace break b 設置斷點 continue c、cont 繼續(xù)執(zhí)行 delete d 刪除斷點 finish 運行到函數(shù)結束 info breakpoints 顯示斷點信息 next n 執(zhí)行下一行 print p 顯示表達式 run r 運行程序 step s 一次執(zhí)行一行,包括函數(shù)內部 x 顯示內存內容 until u 執(zhí)行到指定行 其他命令 directory dir 插入目錄 disable dis 禁用斷點 down do 在當前調用的棧幀中選擇要顯示的棧幀 edit e 編輯文件或者函數(shù) frame f 選擇要顯示的棧幀 forward-search fo 向前搜索 generate-core-file gcore 生成內核轉存儲 help h 顯示幫助一覽 info i 顯示信息 list l 顯示函數(shù)或行 nexti ni 執(zhí)行下一行(以匯編代碼為單位) print-object po 顯示目標信息 sharelibrary share 加載共享的符號 stepi si 執(zhí)行下一行
info命令能夠顯示調試對象的各種各樣的信息,另外show命令能夠顯示GDB內部的功能、變量和選項等。
值的歷史
通過print 命令顯示過的值會記錄在內部的值歷史中,這些值可以在其他表達式中使用
(gdb)p argc (gdb)p *argc最后的值可以通過 p $ 訪問 也就說在這種情況下, p $ == > p *argc用 show value 命令可以顯示歷史中的最后 10 個值
(gdb)show value $1 $2 $3 $4 . . .值歷史的訪問說明
變量 說明 $ 值歷史的最后一個值 $n 值歷史的第n個值 $$ 值歷史的倒數(shù)第2個值 $$n 值歷史倒數(shù)第n個值 $_ x命令顯示過的最后的地址 $__ x命令顯示過的最后的地址的值 $_exitcode 調試中的程序的返回碼 $bpnum 最后設置的斷點編號變量
可以隨意的定義變量,變量以$ 開頭,由英文字母和數(shù)字組成
(gdb)set $i = 0 (gdb)p $i $1 = 0命令歷史
可以將命令歷史保存在文件中,保存命令歷史后,就能在其它調試會話中重復利用這些命令(通過箭頭鍵以查找以前的命令)、
十分方便,默認的歷史文件位于 ./.gdb_history
顯示歷史命令
格式:
set hitory expansion show history expansion可以使用csh風格的!字符
格式:
set hitory filename 文件名 show history filename可將命令歷史保存到文件中,可以通過環(huán)境變量GDBHISTFILE改變默認文件名
格式:
set history save show history save啟用命令歷史保存到文件和恢復的功能
格式:
set history size 數(shù)字 show history size設置保存到命令歷史中的命令數(shù)量,默認值是256
星期六, 23. 二月 2019 12:20下午
初始化文件(.gdbinit)
linux環(huán)境下初始化文件為 .gdbinit。如果存在.gdbinit 文件,GDB就會在啟動之前將其作為命令文件運行,初始化文件和命令文件的運行順序如下:
1、$HOME/.gdbinit
2、運行命令選項
3、./.gdbinit
4、通過 -x 選項給出的命令文件
初始化文件的語法和命令文件的語法相同,都由gdb命令組成
命令定義
利用define命令可以定義命令,還可以使用document命令給自定義的命令添加說明,用help命令名,可以查看定義的命令名
格式:
格式:
document 命令名說明end格式:
help 命令名例:
定義了一個 名為 li的命令,它能顯示當前 $pc 所指的位置開始的10條指令。另外,用document命令給li命令定義了說明,使用help li可以查看說明;
除了使用初始化文件,還可以將各種設置文件寫在文件中,,在運行調試器時讀取這些文件
格式;
調試必需的棧知識
棧是程序存放數(shù)據(jù)的內存區(qū)域之一,其特征是LIFO(last in first out,后進先出)式數(shù)據(jù)結構,即后放進的數(shù)據(jù)先被取出,向棧中存儲數(shù)據(jù)的操作稱為PUSH(壓入),從棧中取出數(shù)據(jù)稱為POP(彈出),保存動態(tài)分配的自動變量時要使用棧,此外在函數(shù)調用時,棧還用于傳遞函數(shù)參數(shù),以及用于保存返回地址和返回值。
-mno-red-zoneDo not use a so-called "red zone" for x86-64 code. The red zone ismandated by the x86-64 ABI; it is a 128-byte area beyond thelocation of the stack pointer that is not modified by signal orinterrupt handlers and therefore can be used for temporary datawithout adjusting the stack pointer. The flag -mno-red-zonedisables this red zone.調試選擇棧幀,除了使用frame n 指定,還可以使用up down up是選擇上一層棧幀,dowm是選擇下一層棧幀
使用 info 命令的 frame 選項可以查看到更詳細的棧幀信息,可以用幀編號作為該命令的選項
x/i $pc --> 以匯編的形式查看當前棧幀處的代碼
(gdb) x/i $pc => 0x400590 <main>: sub $0x18,%rsp(gdb) info proc mapping --> 查看該進程內存映射的命令
process 13193
Mapped address spaces:
說明:
可以使用info proc mapping 查看進程的內存映射,要保證占空間的棧頂端的值小于pc的,否則就是出現(xiàn)了棧溢出進程的內存映射也就是/proc/<PID>/maps信息注意后面顯示的[stack]。它表示棧空間,占空間的頂端的值要小于pc的,否則就是出現(xiàn)了棧溢出 進程的內存映射也就是 /proc/<PID>/maps信息 注意后面顯示的[stack] 。它表示棧空間,占空間的頂端的值要小于pc的,否則就是出現(xiàn)了棧溢出進程的內存映射也就是/proc/<PID>/maps信息注意后面顯示的[stack]。它表示棧空間,占空間的頂端的值要小于pc的值,程序才能正常運行,說明棧沒有溢出
但是使用該命令時,GDB文件會打開/proc//maps,因此在分析coredump文件的時候無法使用,分析coredump文件的時候
可以使用下面的命令得到相同的信息。
(gdb)info files
或者
(gdb)info target
星期六, 23. 二月 2019 12:20下午
調試器的backtrace
GDB等調試器的backtrace功能是通過搜索棧中的保存信息來實現(xiàn)的。
棧信息對于調試器來說非常重要,關于棧破壞可以看HACK#27 backtrace無法正確顯示和 HACK#28 數(shù)組非法訪問導致內存破壞
編譯時使用GCC指定 -formit-frame-pointer選項,即可生成不使用棧指針的二進制文件即使這樣使用GDB依然能夠正確理解幀,
因為GDB是根據(jù)記錄在調試信息中的棧使用量來計算幀的位置的
GDB提供了操作棧幀的命令
使用bt命令可以查棧的狀態(tài)
使用frame可以查看現(xiàn)在選擇的幀
調試沒有調試信息的程序,使用 b *func 即函數(shù)前面加上 * 因為不使用 斷點就不會設置到匯編語言層次的函數(shù)開頭,
而是設置到地址偏后一點的源代碼級別的開頭,如果在break命令中不加 直接使用函數(shù)名,就無法用于參數(shù)確認。
#內核調試的準備
Oops信息的解讀方法Oops信息是內核發(fā)生致命錯誤時輸出的內核信息
應用程序調試實踐
發(fā)生SIGSEGV,應用程序異常停止
- 由于棧溢出導致segmentation fault的調試
應用程序執(zhí)行了非法訪問內存等操作之后,就會發(fā)生SIGSEGV異常而停止。SIGSEGV發(fā)生的情況包括: - NULL指針訪問
- 指針被破壞等原因導致的非法地址訪問
- 棧溢出導致訪問超出了已分配的地址空間
棧溢出導致SIGSEGV的應對方法
backtrace 無法正確顯示
- 線程沖突導致的棧破壞為例講述backtrace無法正確顯示時的調試方法
棧破壞有事會導致問題難以分析,特別是,由于無法獲取bcktrace信息,追溯到問題發(fā)生的路徑非常難
為什么會產(chǎn)生這種信息不全的core文件 - 什么是backtrace
調試器的backtrace是根據(jù)棧里面保存的函數(shù)返回地址來顯示的,根據(jù)棧空間上的返回地址和調試信息得出棧的使用量,以此求出調用者函數(shù)
也就是說,調試器的backtrace的地址是來自進程的棧上,
因此當backreace不正確的情況基本上就是因為棧被破壞了
說明棧被破壞的就不嗯給你信任調試器生成的backtrace信息,極端一點說,新來backtrace只有在棧沒有被破壞的前提下才成立
認為調試器的信息絕對正確是十分危險的
查看寄存器信息
利用GDB進行調試,寄存器信息是絕對不能忽視的
調查棧破壞的方法有很多種,但是最顯示的方法就是根據(jù)被破壞的數(shù)據(jù)內容,判斷執(zhí)行寫入的位置,看看又沒喲對棧空間(也就是自動變量空間)的引用、指針傳遞處理。
數(shù)組非法訪問導致內存破壞
數(shù)組的錯誤操作
錯誤的操作數(shù)組導致典型的bug之一就是緩存區(qū)溢出,也就是說向已分配的內存空間寫入數(shù)據(jù),特別是如果這類bug發(fā)生在棧上的緩存區(qū)中,就可能引發(fā)安全漏洞
當使用-g編譯選項之后利用GDB讀入core并顯示backtrace之后棧中的還是沒有顯示符號名,可以懷疑是緩沖區(qū)溢出的情況
這時使用 x/i +地址顯示查看棧中地址的匯編語言,再根據(jù)程序在該架構中常放置的地址和共享內存常放置的地址判斷是否是數(shù)組越界
調查棧的方法
(gdb) x/30c $esp-15 p (char *) $esp-20魔法鍵 = CTRL+PgUp鍵 之后按鍵 h p打印寄存器信息
總結
以上是生活随笔為你收集整理的linux中GDB详细使用手册的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: debug-段错误
- 下一篇: 【2017年第2期】深度学习在化学信息学