GDB調試的三種方式:
1. 目標板直接使用GDB進(jìn)行調試。
2. 目標板使用gdbserver,主機使用xxx-linux-gdb作為客戶(hù)端。
3. 目標板使用ulimit -c unlimited,生成core文件;然后主機使用xxx-linux-gdb ./test ./core。
構造測試程序如下main.c和sum.c如下:
main.c:#include <stdio.h> #include <stdlib.h> extern int sum(int value); struct inout { int value; int result; }; int main(int argc, char * argv[]) { struct inout * io = (struct inout * ) malloc(sizeof(struct inout)); if (NULL == io) { printf("Malloc failed.\n"); return -1; } if (argc != 2) { printf("Wrong para!\n"); return -1; } io -> value = *argv[1] - '0'; io -> result = sum(io -> value); printf("Your enter: %d, result:%d\n", io -> value, io -> result); return 0; } sum.c: int sum(int value) { int result = 0; int i = 0; for (i = 0; i < value; i++) result += (i + 1); return result; }
然后gcc main.c sum.c -o main -g, 得到main可執行文件.
下面介紹了gdb大部分功能,1.1 設置斷點(diǎn)以及 1.3顯示棧幀是常用功能;調試過(guò)程中可以需要1.6 單步執行,并且1.4 顯示變量、1.5顯示寄存器、1.8 監視點(diǎn)、1.9 改變變量的值。
如果進(jìn)程已經(jīng)運行中,需要1.11 attach到進(jìn)程,或者1.10 生成轉儲文件進(jìn)行分析。當然為了提高效率可以自定義1.13 初始化文件。
設置斷點(diǎn)可以通過(guò)b或者break設置斷點(diǎn),斷點(diǎn)的設置可以通過(guò)函數名、行號、文件名+函數名、文件名+行號以及偏移量、地址等進(jìn)行設置。
格式為:
break 函數名
break 行號
break 文件名:函數名
break 文件名:行號
break +偏移量
break -偏移量
break *地址
查看斷點(diǎn),通過(guò)info break查看斷點(diǎn)列表。
刪除斷點(diǎn)通過(guò)命令包括:
delete <斷點(diǎn)id>:刪除指定斷點(diǎn)
delete:刪除所有斷點(diǎn)
clear
clear 函數名
clear 行號
clear 文件名:行號
clear 文件名:函數名
斷點(diǎn)還可以條件斷住
break 斷點(diǎn) if 條件;比如break sum if value==9,當輸入的value為9的時(shí)候才會(huì )斷住。
condition 斷點(diǎn)編號:給指定斷點(diǎn)刪除觸發(fā)條件
condition 斷點(diǎn)編號 條件:給指定斷點(diǎn)添加觸發(fā)條件
如下可以看出,當入參為9的時(shí)候被斷住,而入參為8的時(shí)候運行到結束。
斷點(diǎn)還可以通過(guò)disable/enable臨時(shí)停用啟用。
disable
disable 斷點(diǎn)編號
disable display 顯示編號
disable mem 內存區域
enable
enable 斷點(diǎn)編號
enable once 斷點(diǎn)編號:該斷點(diǎn)只啟用一次,程序運行到該斷點(diǎn)并暫停后,該斷點(diǎn)即被禁用。
enable delete 斷點(diǎn)編號
enable display 顯示編號
enable mem 內存區域
大多數時(shí)候需要在斷點(diǎn)處執行一系列動(dòng)作,gdb提供了在斷點(diǎn)處執行命令的高級功能commands。
#include <stdio.h> int total = 0; int square(int i) { int result=0; result = i*i; return result; } int main(int argc, char **argv) { int i; for(i=0; i<10; i++) { total += square(i); } return 0; }
比如需要對如上程序square參數i為5的時(shí)候斷點(diǎn),并在此時(shí)打印棧、局部變量以及total的值
編寫(xiě)gdb.init如下:
set logging on gdb.log b square if i == 5 commands bt full i locals p total print "Hit break when i == 5" end
在gdb shell中source gdb.init,然后r執行命令,結果如下:
可以看出斷點(diǎn)在i==5的時(shí)候斷住了,并且此時(shí)打印了正確的值。
“gdb 命令”之后,run可以在gdb下運行命令;如果命令需要參數則跟在run之后。
如果需要斷點(diǎn)在main()處,直接執行start就可以。
如果遇到斷點(diǎn)而暫停執行,或者coredump可以顯示棧幀。
通過(guò)bt可以顯示棧幀,bt full可以顯示局部變量。
命令格式如下:
bt
bt full:不僅顯示backtrace,還顯示局部變量
bt N:顯示開(kāi)頭N個(gè)棧幀
bt full N
“print 變量”可以顯示變量?jì)热荨?/p>
如果需要一行監控多個(gè)變量,可以通過(guò)p {var1, var2, var3}。
如果要跟蹤自動(dòng)顯示,可以使用display {var1, var2, var3}
info reg可以顯示寄存器內容。
在寄存器名之前加$可以顯示寄存器內容,
p $寄存器:顯示寄存器內容
p/x $寄存器:十六進(jìn)制顯示寄存器內容。
用x命令可以顯示內容內容,“x/格式 地址”。
x $pc:顯示程序指針內容
x/i $pc:顯示程序指針匯編。
x/10i $pc:顯示程序指針之后10條指令。
x/128wx 0xfc207000:從0xfc20700開(kāi)始以16進(jìn)制打印128個(gè)word。
還可以通過(guò)disassemble指令來(lái)反匯編。
disassemble
disassemble 程序計數器:反匯編pc所在函數的整個(gè)函數。
disassemble addr-0x40,addr+0x40:反匯編addr前后0x40大小。
單步執行有兩個(gè)命令next和step,兩者的區別是next遇到函數不會(huì )進(jìn)入函數內部,step會(huì )執行到函數內部。
如果需要逐條匯編指令執行,可以分別使用nexti和stepi。
調試時(shí),使用continue命令繼續執行程序。程序遇到斷電后再次暫停執行;如果沒(méi)有斷點(diǎn),就會(huì )一直執行到結束。
continue:繼續執行
continue 次數:繼續執行一定次數。
要想找到變量在何處被改變,可以使用watch命令設置監視點(diǎn)watchpoint。
watch <表達式>:表達式發(fā)生變化時(shí)暫停運行
awatch<表達式>:表達式被訪(fǎng)問(wèn)、改變是暫停執行
rwatch<表達式>:表達式被訪(fǎng)問(wèn)時(shí)暫停執行
其他變種還包括watch expr [thread thread-id] [mask maskvalue],其中mask需要架構支持。
GDB不能監控一個(gè)常量,比如watch 0x600850報錯。
但是可以watch *(int *)0x600850。
“通過(guò)set variable <變量>=<表達式>”來(lái)修改變量的值。
set $r0=xxx:設置r0寄存器的值為xxx。
通過(guò)“generate-core-file”生成core.xxxx轉儲文件。
然后gdb ./main ./core.xxxx查看恢復的現場(chǎng)。
另一命令gcore可以從命令行直接生成內核轉儲文件。
gcore `pidof 命令`:無(wú)需停止正在執行的程序已獲得轉儲文件。
如果程序已經(jīng)運行,或者是調試陷入死循環(huán)而無(wú)法返回控制臺進(jìn)程,可以使用attach命令。
attach pid
通過(guò)ps aux可以查看進(jìn)程的pid,然后使用bt查看棧幀。
以top為例操作步驟為:
1. ps -aux查看進(jìn)程pid,為16974.
2. sudo gdb attach 16974,使用gdb 附著(zhù)到top命令。
3. 使用bt full查看,當前棧幀。此時(shí)使用print等查看信息。
4. 還可以通過(guò)info proc查看進(jìn)程信息。
continue、step、stepi、next、nexti都可以指定重復執行的次數。
ignore 斷點(diǎn)編號 次數:可以忽略指定次數斷點(diǎn)。
Linux環(huán)境下初始化文件為.gdbinit。
如果存在.gdbinit文件,gdb在啟動(dòng)的之前就將其作為命令文件運行。
初始化文件和命令文件執行順序為:HOME/.gdbinit > 運行命令行選項 > ./.gdbinit > -x指定命令文件。
調試過(guò)程中如果需要關(guān)聯(lián)到源碼,查看更詳細的信息。
可以通過(guò)directory或者set substitute-path來(lái)制定源碼目錄。
TUI(TextUserInterface)為GDB調試的文本用戶(hù)界面,可以方便地顯示源代碼、匯編和寄存器文本窗口。
源代碼窗口和匯編窗口會(huì )高亮顯示程序運行位置并以'>'符號標記。有兩個(gè)特殊標記用于標識斷點(diǎn),第一個(gè)標記用于標識斷點(diǎn)類(lèi)型:
B:
程序至少有一次運行到了該斷點(diǎn)b:
程序沒(méi)有運行到過(guò)該斷點(diǎn)H:
程序至少有一次運行到了該硬件斷點(diǎn)h:
程序沒(méi)有運行到過(guò)該硬件斷點(diǎn)第二個(gè)標記用于標識斷點(diǎn)使能與否:
+:
斷點(diǎn)使能Breakpointisenabled.-:
斷點(diǎn)被禁用Breakpointisdisabled.
當調試程序時(shí),源代碼窗口、匯編窗口和寄存器窗口的內容會(huì )自動(dòng)更新。
catch可以根據某些類(lèi)型事件來(lái)停止程序執行。
可以通過(guò)catch syscall close,捕捉產(chǎn)生系統調用close的時(shí)候停止程序執行。
其他的catch事件還包括,throw、syscall、assert、exception等等。
命令行的入參可以通過(guò)argc和*argv獲取。
# - 為腳本添加注釋。
set - 為變量賦值,以$開(kāi)頭,以便區分gdb還是調試程序變量。
例如:set $x = 1
顯示變量可以通過(guò)echo、printf。
利用define命令可以自行定義命令,還可以使用document命令給自定義命令添加說(shuō)明。
define adder if $argc == 2 print $arg0 + $arg1 end if $argc == 3 print $arg0 + $arg1 + $arg2 end end document adder Sum two or three variables. end
執行bf自定義命令,結果如下。
無(wú)行參聲明,但可以直接用$arg0,$arg1引用, $argc 為形參個(gè)數
條件命令:if...else...end
。這個(gè)同其它語(yǔ)言中提供的if
命令沒(méi)什么區別,只是注意結尾的end
。
循環(huán)命令:while...end
。gdb同樣提供了loop_break
和loop_continue
命令分別對應其它語(yǔ)言中的break
和continue
,另外同樣注意結尾的end
。
set logging on overwrite gdb.log------------將顯示log保存到gdb.log中。 set pagination off--------------------------關(guān)閉分頁(yè)顯示功能。 tar jtag jtag://localhost:1025--------------連接上JTAG。 d-------------------------------------------刪除現有斷點(diǎn)。 b func_a------------------------------------在func_a增加斷點(diǎn)。 commands------------------------------------斷點(diǎn)后,執行如下命令。 b func_b----------------------------------在func_a斷點(diǎn)之后,在func_b增加斷點(diǎn)。 commands bt full-------------------------------打印func_b處棧幀。 c-------------------------------------繼續執行。 end b file.c:555------------------------------在file.c的555行增加斷點(diǎn) commands while 1-------------------------------無(wú)限執行next命令。 next end end c-----------------------------------------繼續執行,才會(huì )觸發(fā)func_b和file.c:555斷點(diǎn)。 end c-------------------------------------------是程序得到繼續執行。
在命令行g(shù)db -x gdb.init bin;或者gdb bin,然后在命令行soruce gdb.init同樣可以更新腳本。
在gdb調試中可能需要將一段內存導出到文件中,可以借助dump命令。
命令格式:
dump binary memory FILE START STOP
比如dump binary memory ./dump.bin 0x0 0x008000000,將內存區間從0x0到0x00800000導出到dump.bin中。
目標板gdbserver+主機gdb遠程調試的方式,比較適合目標板性能受限,只能提供gdbserver功能。
在主機上執行g(shù)db進(jìn)行遠程調試。測試程序如下。
#include <stdio.h> void C(int *p) { *p = 0x12; } void B(int *p) { C(p); } void A(int *p) { B(p); } void A2(int *p) { C(p); } int main(int argc, char **argv) { int a; int *p = NULL; A2(&a); // A2 > C printf("a = 0x%x\n", a); A(p); // A > B > C return 0; }
對目標板的設置方式是:開(kāi)啟端口2345作為gdbserver銅線(xiàn)端口。
gdbserver :2345 test_debug
主機上執行g(shù)db test_debug,然后tar remote 192.168.2.84.2345連接遠程gdbserver。
目標板會(huì )收到“Remote debugging from host 192.168.33.77”消息,表示兩者連接成功。
主機上就可以進(jìn)行遠程調試,continue之后兩端得到的結果如下:
目標板輸出“a=0x12”之后停止運行,
主機上得到SIGSEGV,并可以查看backtrace信息??梢钥闯鰡?wèn)題點(diǎn)在指針p指向NULL,0指針賦值錯誤。
在目標板上執行ulimit -c unlimited,執行應用程序。
程序出錯后,會(huì )在當前目錄下生成core文件。
將core文件拷出后,再PC上執行xxx-linux-gdb ./test ./core進(jìn)行分析。
在運行xxx-linux-gdb ./test ./core之后,可能存在庫文件關(guān)聯(lián)不上的情況。
使用info sharedlibrary,查看庫加載情況。
From To Syms Read Shared Object Library No xxx.so No /lib/libdl.so.2 No /lib/libpthread.so.0 0x2ab6ec00 0x2ac09ba4 Yes xxx/lib/libstdc++.so.6 No /lib/libm.so.6 0x2acec460 0x2acf626c Yes xxx/lib/libgcc_s.so.1 No /lib/libc.so.6 No /lib/ld.so.1
可以通過(guò)set solib-search-path和set solib-absolute-prefix來(lái)設置,對應庫所在的路徑。
From To Syms Read Shared Object Library 0x2aaca050 0x2aacc8d0 Yes xxx.so 0x2aad0ad0 0x2aad17ac Yes (*) xxx/lib/libdl.so.2 0x2aad8a50 0x2aae7434 Yes (*) xxx/lib/libpthread.so.0 0x2ab6ec00 0x2ac09ba4 Yes xxx/lib/libstdc++.so.6 0x2ac4b3d0 0x2acb1988 Yes xxx/lib/libm.so.6 0x2acec460 0x2acf626c Yes xxx/lib/libgcc_s.so.1 0x2ad17b80 0x2adf699e Yes xxx/lib/libc.so.6 0x2aaa89e0 0x2aabf66c Yes (*) xxx/lib/ld.so.1 (*): Shared library is missing debugging information.
可以看出相關(guān)庫文件都已經(jīng)加載,只是部分庫文件沒(méi)有調試信息。
查看coredump的backtrace通過(guò)bt即可,更全的信息通過(guò)bt full。
產(chǎn)看函數調用棧的幾個(gè)函數
bt:顯示所有的函數調用棧幀的信息,每個(gè)幀一行。
bt n:顯示棧定的n個(gè)幀信息。
bt -n:顯示棧底的n個(gè)幀信息。
bt full:顯示棧中所有幀的完全信息如:函數參數,本地變量。
bt full n:用法同上。
bt full -n
(gdb) bt #0 0x2ad71f1e in memcpy () from xxx/lib/libc.so.6 #1 0x2ad71ac0 in memmove () from xxx/lib/libc.so.6 #2 0x0011f36c in std::__copy_move<false, true, std::random_access_iterator_tag>::__copy_m<unsigned char> (__first=0x34dfb008 "\377\330\377", <incomplete sequence \340>, __last=0x34eeea2c "", ... #3 0x0011ee22 in std::__copy_move_a<false, unsigned char*, unsigned char*> (__first=0x34dfb008 "\377\330\377", <incomplete sequence \340>, __last=0x34eeea2c "", __result=0x2b2013c0 "\377\330\377", <incomplete sequence \340>) at xxxinclude/c++/6.3.0/bits/stl_algobase.h:386 #4 0x0011e7e2 in std::__copy_move_a2<false, __gnu_cxx::__normal_iterator<unsigned char*, std::vector<unsigned char> >, unsigned char*> (__first=..., __last=..., __result=0x2b2013c0 "\377\330\377", <incomplete sequence \340>) at xxx/bits/stl_algobase.h:424 #5 0x0011dfd2 in std::copy<__gnu_cxx::__normal_iterator<unsigned char*, std::vector<unsigned char> >, unsigned char*> (__first=..., __last=..., __result=0x2b2013c0 "\377\330\377", <incomplete sequence \340>) at xxx/6.3.0/bits/stl_algobase.h:456 #6 0x0011c948 in xxx #7 0x00133e08 in xxx #8 0x2aada31e in start_thread () from xxx/libc/lib/libpthread.so.0 #9 0x005a11b4 in ?? ()
默認情況下core文件存在應用當前路徑下,為了區分可以進(jìn)行設置。
區分core主要通過(guò)/proc/sys/kernel/core_uses_pid和/proc/sys/kernel/core_pattern進(jìn)行設置。
/proc/sys/kernel/core_uses_pid:可以控制產(chǎn)生的core文件的文件名中是否添加pid作為擴展,如果添加則文件內容為1,否則為0。
proc/sys/kernel/core_pattern:可以設置格式化的core文件保存位置或文件名,比如原來(lái)文件內容是core-%e
echo "/tmp/core-%e-%p" > core_pattern。
將會(huì )控制所產(chǎn)生的core文件會(huì )存放到/corefile目錄下,產(chǎn)生的文件名為core-命令名-pid-時(shí)間戳
以下是參數列表:
%p - insert pid into filename 添加pid
%u - insert current uid into filename 添加當前uid
%g - insert current gid into filename 添加當前gid
%s - insert signal that caused the coredump into the filename 添加導致產(chǎn)生core的信號
%t - insert UNIX time that the coredump occurred into filename 添加core文件生成時(shí)的unix時(shí)間
%h - insert hostname where the coredump happened into filename 添加主機名
%e - insert coredumping executable name into filename 添加命令名
當然,你可以用下列方式來(lái)完成:
sysctl -w kernel.core_pattern=/tmp/core-%e-%p
功能說(shuō)明:控制shell程序的資源。
語(yǔ)法:ulimit [-aHS][-c <core文件上限>][-d <數據節區大小>][-f <文件大小>][-m <內存大小>][-n <文件數目>][-p <緩沖區大小>][-s <堆疊大小>][-t <CPU時(shí)間>][-u <程序數目>][-v <虛擬內存大小>]
補充說(shuō)明:ulimit為shell內建指令,可用來(lái)控制shell執行程序的資源。
參數:
-a 顯示目前資源限制的設定。
-c <core文件上限> 設定core文件的最大值,單位為區塊。
-d <數據節區大小> 程序數據節區的最大值,單位為KB。
-f <文件大小> shell所能建立的最大文件,單位為區塊。
-H 設定資源的硬性限制,也就是管理員所設下的限制。
-m <內存大小> 指定可使用內存的上限,單位為KB。
-n <文件數目> 指定同一時(shí)間最多可開(kāi)啟的文件數。
-p <緩沖區大小> 指定管道緩沖區的大小,單位512字節。
-s <堆疊大小> 指定堆疊的上限,單位為KB。
-S 設定資源的彈性限制。
-t <CPU時(shí)間> 指定CPU使用時(shí)間的上限,單位為秒。
-u <程序數目> 用戶(hù)最多可開(kāi)啟的程序數目。
-v <虛擬內存大小> 指定可使用的虛擬內存上限,單位為KB。
Type <return> to continue, or q <return> to quit---
當現實(shí)內容多的時(shí)候,GDB會(huì )強制分頁(yè),現實(shí)就會(huì )暫停。但是可能并不需要,可以通過(guò)set pagination off關(guān)閉。
在已運行的Linux上,如果發(fā)生死機異常等問(wèn)題,這時(shí)候定位問(wèn)題需要使用jtag連接上。
連接方法是:
gdb-----------------------------------------------進(jìn)入gdb shell。
target remote localhost:1025-------------------在gdb shell中通過(guò)ip:port連接上target。
file vmlinux----------------------------------------加載符號表。
然后就可以在線(xiàn)查看運行狀態(tài)了。
以上就是詳解Linux下調試器GDB的基本使用方法的詳細內容,更多關(guān)于Linux 調試器GDB的資料請關(guān)注腳本之家其它相關(guān)文章!
免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng )、來(lái)自本網(wǎng)站內容采集于網(wǎng)絡(luò )互聯(lián)網(wǎng)轉載等其它媒體和分享為主,內容觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如侵犯了原作者的版權,請告知一經(jīng)查實(shí),將立刻刪除涉嫌侵權內容,聯(lián)系我們QQ:712375056,同時(shí)歡迎投稿傳遞力量。
Copyright ? 2009-2022 56dr.com. All Rights Reserved. 特網(wǎng)科技 特網(wǎng)云 版權所有 特網(wǎng)科技 粵ICP備16109289號
域名注冊服務(wù)機構:阿里云計算有限公司(萬(wàn)網(wǎng)) 域名服務(wù)機構:煙臺帝思普網(wǎng)絡(luò )科技有限公司(DNSPod) CDN服務(wù):阿里云計算有限公司 百度云 中國互聯(lián)網(wǎng)舉報中心 增值電信業(yè)務(wù)經(jīng)營(yíng)許可證B2
建議您使用Chrome、Firefox、Edge、IE10及以上版本和360等主流瀏覽器瀏覽本網(wǎng)站