GDB调试使用详解
參考:C語言gdb調試之精髓(常用命令、多進程、多線程、程序日志)
作者:C語言技術網
發布時間: 2020-07-15 17:13:30
網址:https://www.bilibili.com/video/BV1ei4y1V758?from=search&seid=4037367131025904962
以及:http://www.freecplus.net/b72113dda88a43b48728e0552fd8a74c.html
參考:Linux的調試器–GDB等
作者:一只青木呀
發布時間: 2020-07-14 15:31:01
網址:https://blog.csdn.net/weixin_45309916/article/details/107338210
目錄
- Linux的調試器
- 概念
- 安裝GDB增強工具 (gef)
- 簡單的安裝方法(我的Linux是Ubuntu18.04)
- 嘗試使用gdb進行小程序的調試
- GDB的命令
- GDB的基本命令
- GDB的簡單使用
- 0.編譯hello.c
- 1.啟動GDB
- 2.下斷點
- 3.讓程序運行起來
- 4.此時需要往下運行
- 5.查看運行中程序的變量
- 6.運行時程序的打印會在最上面顯示
- 7.退出gdb
- 8.補充一點(設置參數)
- GDB多進程調試
- 1.編譯
- 2.啟動gdb
- 3.下斷點(我們以man函數為例)
- 4.運行
- 5.選擇是走子進程還是父進程
- GDB多線程調試
- 1.編譯
- 2.開始調試
- 3.選擇線程
Linux的調試器
概念
程序員寫在編寫程序的時候不可能是一帆風順的,gcc編譯器可以發現程序代碼的語法錯誤,但不能發現程序的業務邏輯錯誤,調試程序是軟件開發的內容之一。調試程序的方法有很多種,例如可以用printf語句跟蹤程序的運行步驟和顯示變量的值,本章節介紹一個功能強大的調試工具gdb。
- 基于命令行的調試方法
- 所有的調試都是可以進行腳本編寫的
- 能夠調試所有架構的代碼
- 有三種調試方法供大家選擇
- GDB支持遠程調試,支持與IDA進行聯調
安裝GDB增強工具 (gef)
一般來說,gdb啟動起來就是這樣的樣子
- gdb的一直都非常強大,但是每一步調試,可能有一些要查看的信息,如果每一步都要手動輸入命令,未免有點麻煩,所以就出現了插件,把某一些經常要查看的信息每一步都自動幫你顯示出來,方便調試
簡單的安裝方法(我的Linux是Ubuntu18.04)
1、切換到用戶權限
2、切換到用戶家目錄 比如/home/qingmu
3、保持網絡通暢,然后只要輸入下面的命令 就行
克隆完之后,會在你當前目錄下面有GdbPlugins 這個文件,并且里面會有這幾個文件
- 這樣就算ok了,里面三個插件,當你想要用某一個插件的時候,只要輸入對應命令就行
- 這里我們主要使用gef 我們執行
然后我們啟動gdb就行了
至此gef插件安裝完畢
嘗試使用gdb進行小程序的調試
gcc -g的選項 gdb gdb-test 一些GDB的命令GDB的命令
啟動方法
本地普通啟動 gdb 本地段錯誤文件啟動 gdb core attch方式啟動 gdb 遠程啟動 gdbserver 0.0.0.0:1234 /path/to/file啟動選項
–symbols < file > -s < file > 從指定文件中讀取符號表 -se < file > 從指定文件中讀取符號表信息,并把它們用在可執行文件中 –core < file > 調試時core dump的core文件 –directory < directory> -d < directory> 加入一個源文件的搜索路徑。默認搜索路徑是環境變量中PATH所定義的路徑 詳細的開關可以使用gdb --help基本命令
set listsize 設置調試中可以查看的行數 set args 10 20 30 40 50 設置程序所需要的參數 path show paths save breakpoint name.bp gdb elf -x name.bp print § 查看運行數據 print *array@10 查看數組 print file::variable 查看file文件下的variable x/n、f、u 查看內存 n 是一個正整數,表示顯示內存的長度,也就是說從當前地址向后顯示幾個地址的內容。 f 表示顯示的格式,跟print 的格式參數相同 u 表示從當前地址往后請求的字節數,如果不指定的話,GDB默認是4個bytes。u參數可以用下面的字符來代替,b表示單字節,h表示雙字節,w表示四字節,g表示八字節。當我們指定了字節長度后,GDB會從指內存定的內存地址開始,讀寫指定字節,并把其當作一個值取出來。GDB的基本命令
Linux程序發布流程
確定程序是否存在符號表
readelf -s test-1
生成符號表
objcopy --only-keep-debug test-1 test-1.symbol
生成發布程序
objcopy --strip-debug test-1 test-release
使用符號表進行程序debug
gdb -q --symbol=test-1.symbol --exec=test-release
GDB中暫停/恢復程序運行
斷點
條件斷點
break if
info breakpoints
delete
disable
enable
觀察點
watch 地址
info watchpoints
rwatch
捕捉點
catch event
throw 拋出一個C++的異常 catch throw
catch 捕捉一個C++的異常 catch catch
exec 調用系統調用exev時停止 catch exec
fork 調用系統調用fork時停止 catch fork
load/load libname 載入動態鏈接庫時 catch load / catch load libname
暫停命令
commands bnum
.
.
.
.
end
GDB的簡單使用
0.編譯hello.c
gcc -g hello.c -o hello注意:編譯的時候一定要加上 -g 選項,使之加入符號表,否賊調試的時候看不到程序的源代碼。為了更方便的使用gdb 一定要安裝gdb插件gef
以hello.c為例
1.啟動GDB
gdb hello //hello 是hello.c的可執行文件2.下斷點
也就是程序運行到哪,我們以man函數為例
也可以指定在哪一行下斷點。
b
info breakpoints 可查看下的斷點
3.讓程序運行起來
r
此時程序就運行起來了
4.此時需要往下運行
" n " :執行一條語句,碰到函數會直接運行函數
" s ":執行下一條語句,碰到函數會進入到函數中
5.查看運行中程序的變量
" p "
6.運行時程序的打印會在最上面顯示
7.退出gdb
q8.補充一點(設置參數)
如果程序需要傳入參數那么 “set args” 在啟動gdb之后就可以設置參數
例如我需要傳遞兩個參數:
中間用空格隔開就可以了
GDB多進程調試
下面以process.c為例
#include<stdio.h> #include<stdio.h> #include<unistd.h> #include<sys/types.h> #include<sys/wait.h>int main() {pid_t pid = fork();//創建子進程if(pid == -1){perror("fork error");return -1;}else if(pid == 0)//child{printf("i am a child:my pid is %d,my father is %d\n",getpid(),getppid());}else//father{printf("i am a father:my pid is %d\n",getpid());wait(NULL);//等待子進程}return 0;}1.編譯
gcc -g process.c -o process //一定要加-g 把符號表載入代碼2.啟動gdb
gdb process3.下斷點(我們以man函數為例)
b main4.運行
r5.選擇是走子進程還是父進程
fork()函數
返回值為0:子進程
返回值大于0:父進程
返回值小于0:創建失敗
函數運行是他自己是走父進程還是子進程是不確定的,所以我們需要讓他按照自己的想法運行,這是我們就按自己的需要是走父進程還是子進程
跟著父進程去運行
set follow-fork-mode parent跟著子進程運行
set follow-fork-mode child設置之后我們就n往下運行就可以進入子進程
GDB多線程調試
下面以thread.c為例
#include<stdio.h> #include<pthread.h>void* thread1(void* arg) {printf("i am thread1,my tid is %u\n",pthread_self());int i=0;int result=0;for(;i<100;i++){result += i;}printf("thread1 result = %d\n",result);return NULL; }void* thread2(void* arg) {printf("i am thread2,my tid is %u\n",pthread_self());int i=0;int result=0;for(;i<100;i++){result ^= i;}printf("thread2 result = %d\n",result);return NULL; }int main() {pthread_t tid1,tid2;pthread_create(&tid1,NULL,thread1,NULL);//創建線程1pthread_create(&tid2,NULL,thread2,NULL);//創建線程2pthread_join(tid1,NULL);//等待線程1pthread_join(tid2,NULL);//等待線程2 return 0; }1.編譯
gcc -g thread.c -o thread -lpthread //線程庫不是內核自帶的 要自己加上2.開始調試
gdb thread3.選擇線程
線程比較簡單 想看哪個線程就把斷點下到哪個線程的函數上
跟線程1運行
b thread1跟線程2運行
b thread2這里我們跟線程1運行
這里我們就跟進了線程1了
可以通過:"info threads"命令來查看正在運行程序中線程信息
其余的就是基本操作了
p 打印想看的數據
x查看對應的內存等等
總結
- 上一篇: android146 360 病毒查杀
- 下一篇: cupp字典生成工具(同类工具还有cru