前言
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++,算法,數據庫等編程相關[原創]技術文章,號內包含大量經典電子書和視頻學習資源。歡迎一起交流學習,一起修煉計算機“內功”,知其然,更知其所以然。