前言 GDB(GNU Debugger)是UNIX及UNIX-like下的強大調試工具,可以調試ada, c, c++, asm, minimal, d, fortran, objective-c, go, java,pascal等語言。本文以C程式為例,介紹GDB啟動調試的多種方式。 哪類程式可被 ...
前言
GDB(GNU Debugger)是UNIX及UNIX-like下的強大調試工具,可以調試ada, c, c++, asm, minimal, d, fortran, objective-c, go, java,pascal等語言。本文以C程式為例,介紹GDB啟動調試的多種方式。
哪類程式可被調試
對於C程式來說,需要在編譯時加上-g參數,保留調試信息,否則不能使用GDB進行調試。
但如果不是自己編譯的程式,並不知道是否帶有-g參數,如何判斷一個文件是否帶有調試信息呢?
gdb 文件
例如:
$ gdb helloworld
Reading symbols from helloWorld...(no debugging symbols found)...done.
如果沒有調試信息,會提示no debugging symbols found。
如果是下麵的提示:
Reading symbols from helloWorld...done.
則可以進行調試。
readelf查看段信息
例如:
$ readelf -S helloWorld|grep debug
[28] .debug_aranges PROGBITS 0000000000000000 0000106d
[29] .debug_info PROGBITS 0000000000000000 0000109d
[30] .debug_abbrev PROGBITS 0000000000000000 0000115b
[31] .debug_line PROGBITS 0000000000000000 000011b9
[32] .debug_str PROGBITS 0000000000000000 000011fc
helloWorld為文件名,如果沒有任何debug信息,則不能被調試。
file查看strip狀況
下麵的情況也是不可調試的:
file helloWorld
helloWorld: (省略前面內容) stripped
如果最後是stripped,則說明該文件的符號表信息和調試信息已被去除,不能使用gdb調試。但是not stripped的情況並不能說明能夠被調試。
調試方式運行程式
程式還未啟動時,可有多種方式啟動調試。
調試啟動無參程式
例如:
$ gdb helloWorld
(gdb)
輸入run命令,即可運行程式
調試啟動帶參程式
假設有以下程式,啟動時需要帶參數:
#include<stdio.h>
int main(int argc,char *argv[])
{
if(1 >= argc)
{
printf("usage:hello name\n");
return 0;
}
printf("Hello World %s!\n",argv[1]);
return 0 ;
}
編譯:
gcc -g -o hello hello.c
這種情況如何啟動調試呢?需要設置參數:
$ gdb hello
(gdb)run 編程珠璣
Starting program: /home/shouwang/workspaces/c/hello 編程珠璣
Hello World 編程珠璣!
[Inferior 1 (process 20084) exited normally]
(gdb)
只需要run的時候帶上參數即可。
或者使用set args,然後在用run啟動:
gdb hello
(gdb) set args 編程珠璣
(gdb) run
Starting program: /home/hyb/workspaces/c/hello 編程珠璣
Hello World 編程珠璣!
[Inferior 1 (process 20201) exited normally]
(gdb)
調試core文件
當程式core dump時,可能會產生core文件,它能夠很大程式幫助我們定位問題。但前提是系統沒有限制core文件的產生。可以使用命令limit -c查看:
$ ulimit -c
0
如果結果是0,那麼恭喜你,即便程式core dump了也不會有core文件留下。我們需要讓core文件能夠產生:
ulimit -c unlimied #表示不限制core文件大小
ulimit -c 10 #設置最大大小,單位為塊,一塊預設為512位元組
上面兩種方式可選其一。第一種無限制,第二種指定最大產生的大小。
調試core文件也很簡單:
gdb 程式文件名 core文件名
具體可參看《linux常用命令-開發調試篇》gdb部分。
調試已運行程式
如果程式已經運行了怎麼辦呢?
首先使用ps命令找到進程id:
ps -ef|grep 進程名
attach方式
假設獲取到進程id為20829,則可用下麵的方式調試進程:
$ gdb
(gdb) attach 20829
接下來就可以繼續你的調試啦。
可能會有下麵的錯誤提示:
Could not attach to process. If your uid matches the uid of the target
process, check the setting of /proc/sys/kernel/yama/ptrace_scope, or try
again as the root user. For more details, see /etc/sysctl.d/10-ptrace.conf
ptrace: Operation not permitted.
解決方法,切換到root用戶:
將/etc/sysctl.d/10-ptrace.conf中的
kernel.yama.ptrace_scope = 1
修改為
kernel.yama.ptrace_scope = 0
直接調試相關id進程
還可以是用這樣的方式gdb program pid,例如:
gdb hello 20829
或者:
gdb hello --pid 20829
已運行程式沒有調試信息
為了節省磁碟空間,已經運行的程式通常沒有調試信息。但如果又不能停止當前程式重新啟動調試,那怎麼辦呢?還有辦法,那就是同樣的代碼,再編譯出一個帶調試信息的版本。然後使用和前面提到的方式操作。對於attach方式,在attach之前,使用file命令即可:
$ gdb
(gdb) file hello
Reading symbols from hello...done.
(gdb)attach 20829
總結
本文主要介紹了兩種類型的GDB啟動調試方式,分別是調試未運行的程式和已經運行的程式。對於什麼樣的程式能夠進行調試也進行了簡單說明。
歡迎留言補充。
微信公眾號【編程珠璣】:專註但不限於分享電腦編程基礎,Linux,C語言,C++,演算法,資料庫等編程相關[原創]技術文章,號內包含大量經典電子書和視頻學習資源。歡迎一起交流學習,一起修煉電腦“內功”,知其然,更知其所以然。