linux gdb調試

Linux下gdb單步調試 
用 GDB 調試程序

GDB 概述 
————

GDB 是 GNU開源組織發佈的一個強大的 UNIX下的程序調試工具。或許,各位比較喜歡那種圖形界面方式的,像 VC、 BCB等 IDE的調試,但如果你是在 UNIX平臺下做軟件,你會發現 GDB這個調試工具有比 VC、 BCB的圖形化調試器更強大的功能。所謂 “寸有所長,尺有所短 ”就是這個道理。

一般來說, GDB主要幫忙你完成下面四個方面的功能:

1 、啓動你的程序,可以按照你的自定義的要求隨心所欲的運行程序。
2 、可讓被調試的程序在你所指定的調置的斷點處停住。(斷點可以是條件表達式)
3 、當程序被停住時,可以檢查此時你的程序中所發生的事。
4 、動態的改變你程序的執行環境。

從上面看來, GDB和一般的調試工具沒有什麼兩樣,基本上也是完成這些功能,不過在細節上,你會發現 GDB這個調試工具的強大,大家可能比較習慣了圖形化的調試工具,但有時候,命令行的調試工具卻有着圖形化工具所不能完成的功能。讓我們一一看來。

一個調試示例 
——————

源程序: tst.c

 1 #include <stdio.h>
 2
 3 int func(int n)
 4 {
 5         int sum=0,i;
 6         for(i=0; i<n; i++)
 7         {
 8                 sum+=i;
 9         }
10         return sum;
11 }
12
13
14 main()
15 {
16         int i;
17         long result = 0;
18         for(i=1; i<=100; i++)
19         {
20                 result += i;
21         }
22
23        printf("result[1-100] = %d \n", result );
24        printf("result[1-250] = %d \n", func(250) );
25 }

編譯生成執行文件:( Linux下) 
hchen/test> cc -g tst.c -o tst

使用 GDB調試:

hchen/test> gdb tst <———- 啓動 GDB 
GNU gdb 5.1.1 
Copyright 2002 Free Software Foundation, Inc. 
GDB is free software, covered by the GNU General Public License, and you are 
welcome to change it and/or distribute copies of it under certain conditions. 
Type “show copying” to see the conditions. 
There is absolutely no warranty for GDB. Type “show warranty” for details. 
This GDB was configured as “i386-suse-linux”… 
(gdb) l <——————– l 命令相當於 list,從第一行開始例出原碼。 
1 #include

0 func (n=250) at tst.c:5

1 0x080484e4 in main () at tst.c:24

2 0x400409ed in __libc_start_main () from /lib/libc.so.6

(gdb) finish <——————— 退出函數。 
Run till exit from #0 func (n=250) at tst.c:5 
0x080484e4 in main () at tst.c:24 
24 printf(“result[1-250] = %d \n”, func(250) ); 
Value returned is $6 = 31375 
(gdb) c <——————— 繼續運行。 
Continuing. 
result[1-250] = 31375 <———- 程序輸出。

Program exited with code 027. <——– 程序退出,調試結束。 
(gdb) q <——————— 退出 gdb。 
hchen/test>

好了,有了以上的感性認識,還是讓我們來系統地認識一下 gdb吧。

使用 GDB 
————

一般來說 GDB主要調試的是 C/C++的程序。要調試 C/C++的程序,首先在編譯時,我們必須要把調試信息加到可執行文件中。使用編譯器( cc/gcc/g++)的 -g參數可以做到這一點。如:

> cc -g hello.c -o hello
> g++ -g hello.cpp -o hello

如果沒有 -g,你將看不見程序的函數名、變量名,所代替的全是運行時的內存地址。當你用 -g把調試信息加入之後,併成功編譯目標代碼以後,讓我們來看看如何用 gdb來調試他。

啓動 GDB的方法有以下幾種:

1 、 gdb <program>
   program 也就是你的執行文件,一般在當然目錄下。

2 、 gdb <program> core
   用 gdb同時調試一個運行程序和 core文件, core是程序非法執行後 core dump後產生的文件。

3 、 gdb <program> <PID>
   如果你的程序是一個服務程序,那麼你可以指定這個服務程序運行時的進程 ID。 gdb會自動 attach上去,並調試他。 program應該在 PATH環境變量中搜索得到。

GDB 啓動時,可以加上一些 GDB的啓動開關,詳細的開關可以用 gdb -help查看。我在下面只例舉一些比較常用的參數:

-symbols <file>
-s <file>
從指定文件中讀取符號表。

-se file
從指定文件中讀取符號表信息,並把他用在可執行文件中。

-core <file>
-c <file>
調試時 core dump的 core文件。

-directory <directory>
-d <directory>
加入一個源文件的搜索路徑。默認搜索路徑是環境變量中 PATH所定義的路徑。

GDB 的命令概貌 
———————

啓動 gdb後,就你被帶入 gdb的調試環境中,就可以使用 gdb的命令開始調試程序了,gdb的命令可以使用 help命令來查看,如下所示:

/home/hchen> gdb
GNU gdb 5.1.1
Copyright 2002 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i386-suse-linux".
(gdb) help
List of classes of commands:

aliases -- Aliases of other commands
breakpoints -- Making program stop at certain points
data -- Examining data
files -- Specifying and examining files
internals -- Maintenance commands
obscure -- Obscure features
running -- Running the program
stack -- Examining the stack
status -- Status inquiries
support -- Support facilities
tracepoints -- Tracing of program execution without stopping the program
user-defined -- User-defined commands

Type "help" followed by a class name for a list of commands in that class.
Type "help" followed by command name for full documentation.
Command name abbreviations are allowed if unambiguous.
(gdb)

gdb 的命令很多, gdb把之分成許多個種類。 help命令只是例出 gdb的命令種類,如果要看種類中的命令,可以使用 help 命令,如: help breakpoints,查看設置斷點的所有命令。也可以直接 help 來查看命令的幫助。

gdb 中,輸入命令時,可以不用打全命令,只用打命令的前幾個字符就可以了,當然,命令的前幾個字符應該要標誌着一個唯一的命令,在 Linux下,你可以敲擊兩次 TAB鍵來補齊命令的全稱,如果有重複的,那麼 gdb會把其例出來。

示例一:在進入函數 func時,設置一個斷點。可以敲入 break func,或是直接就是 b func
(gdb) b func
Breakpoint 1 at 0x8048458: file hello.c, line 10.

示例二:敲入 b按兩次 TAB鍵,你會看到所有 b打頭的命令:
(gdb) b
backtrace  break      bt
(gdb)

示例三:只記得函數的前綴,可以這樣:
(gdb) b make_ < 按 TAB鍵 >
(再按下一次 TAB鍵,你會看到 :)
make_a_section_from_file     make_environ
make_abs_section             make_function_type
make_blockvector             make_pointer_type
make_cleanup                 make_reference_type
make_command                 make_symbol_completion_list
(gdb) b make_
GDB 把所有 make開頭的函數全部例出來給你查看。

示例四:調試 C++的程序時,有可以函數名一樣。如:
(gdb) b 'bubble( M-?
bubble(double,double)    bubble(int,int)
(gdb) b 'bubble(
你可以查看到 C++中的所有的重載函數及參數。(注: M-?和 “按兩次 TAB鍵 ”是一個意思)

要退出 gdb時,只用發 quit或命令簡稱 q就行了。

GDB 中運行 UNIX 的 shell 程序 
————————————

在 gdb環境中,你可以執行 UNIX的 shell的命令,使用 gdb的 shell命令來完成:

shell <command string>
調用 UNIX的 shell來執行 <command string>,環境變量 SHELL中定義的 UNIX的 shell將會被用來執行 <command string>,如果 SHELL沒有定義,那就使用 UNIX的標準shell: /bin/sh。(在 Windows中使用 Command.com或 cmd.exe)

還有一個 gdb命令是 make: 
make 
可以在 gdb中執行 make命令來重新 build自己的程序。這個命令等價於 “ shell make ”。

在 GDB 中運行程序 
————————

當以 gdb 方式啓動 gdb後, gdb會在 PATH路徑和當前目錄中搜索 的源文件。如要確認 gdb是否讀到源文件,可使用 l或 list命令,看看 gdb是否能列出源代碼。

在 gdb中,運行程序使用 r或是 run命令。程序的運行,你有可能需要設置下面四方面的事。

1 、程序運行參數。 
set args 可指定運行時參數。(如: set args 10 20 30 40 50) 
show args 命令可以查看設置好的運行參數。

2 、運行環境。 
path

3 、工作目錄。 
cd

4 、程序的輸入輸出。 
info terminal 顯示你程序用到的終端的模式。 
使用重定向控制程序輸出。如: run > outfile 
tty 命令可以指寫輸入輸出的終端設備。如: tty /dev/ttyb

調試已運行的程序 
————————

兩種方法: 
1 、在 UNIX下用 ps查看正在運行的程序的 PID(進程 ID),然後用 gdb PID格式掛接正在運行的程序。 
2 、先用 gdb 關聯上源代碼,並進行 gdb,在 gdb中用 attach命令來掛接進程的 PID。並用 detach來取消掛接的進程。

暫停 / 恢復程序運行 
—————————

調試程序中,暫停程序運行是必須的, GDB可以方便地暫停程序的運行。你可以設置程序的在哪行停住,在什麼條件下停住,在收到什麼信號時停往等等。以便於你查看運行時的變量,以及運行時的流程。

當進程被 gdb停住時,你可以使用 info program來查看程序的是否在運行,進程號,被暫停的原因。

在 gdb中,我們可以有以下幾種暫停方式:斷點( BreakPoint)、觀察點(WatchPoint)、捕捉點( CatchPoint)、信號( Signals)、線程停止( Thread Stops)。如果要恢復程序運行,可以使用 c或是 continue命令。

一、設置斷點( BreakPoint )

我們用 break命令來設置斷點。正面有幾點設置斷點的方法:

break <function>
    在進入指定函數時停住。 C++中可以使用 class::function或 function(type,type)格式來指定函數名。

break <linenum>
    在指定行號停住。

break +offset
break -offset
    在當前行號的前面或後面的 offset行停住。 offiset爲自然數。

break filename:linenum
    在源文件 filename的 linenum行處停住。

break filename:function
    在源文件 filename的 function函數的入口處停住。

break *address
    在程序運行的內存地址處停住。

break
    break 命令沒有參數時,表示在下一條指令處停住。

break ... if <condition>
    ... 可以是上述的參數, condition表示條件,在條件成立時停住。比如在循環境體中,可以設置 break if i=100,表示當 i爲 100時停住程序。

查看斷點時,可使用 info命令,如下所示:(注: n表示斷點號)
info breakpoints [n]
info break [n]

二、設置觀察點( WatchPoint )

觀察點一般來觀察某個表達式(變量也是一種表達式)的值是否有變化了,如果有變化,馬上停住程序。我們有下面的幾種方法來設置觀察點:

watch <expr>
    爲表達式(變量) expr設置一個觀察點。一量表達式值有變化時,馬上停住程序。

rwatch <expr>
    當表達式(變量) expr被讀時,停住程序。

awatch <expr>
    當表達式(變量)的值被讀或被寫時,停住程序。

info watchpoints
    列出當前所設置了的所有觀察點。

三、設置捕捉點( CatchPoint )

你可設置捕捉點來補捉程序運行時的一些事件。如:載入共享庫(動態鏈接庫)或是C++的異常。設置捕捉點的格式爲:

catch <event>
    當 event發生時,停住程序。 event可以是下面的內容:
    1 、 throw一個 C++拋出的異常。( throw爲關鍵字)
    2 、 catch一個 C++捕捉到的異常。( catch爲關鍵字)
    3 、 exec調用系統調用 exec時。( exec爲關鍵字,目前此功能只在 HP-UX下有用)
    4 、 fork調用系統調用 fork時。( fork爲關鍵字,目前此功能只在 HP-UX下有用)
    5 、 vfork調用系統調用 vfork時。( vfork爲關鍵字,目前此功能只在 HP-UX下有用)
    6 、 load或 load <libname>載入共享庫(動態鏈接庫)時。( load爲關鍵字,目前此功能只在 HP-UX下有用)
    7 、 unload或 unload <libname>卸載共享庫(動態鏈接庫)時。( unload爲關鍵字,目前此功能只在 HP-UX下有用)

tcatch <event>
    只設置一次捕捉點,當程序停住以後,應點被自動刪除。

四、維護停止點

上面說了如何設置程序的停止點, GDB中的停止點也就是上述的三類。在 GDB中,如果你覺得已定義好的停止點沒有用了,你可以使用 delete、 clear、 disable、 enable這幾個命令來進行維護。

clear
    清除所有的已定義的停止點。

clear <function>
clear <filename:function>
    清除所有設置在函數上的停止點。

clear <linenum>
clear <filename:linenum>
    清除所有設置在指定行上的停止點。

delete [breakpoints] [range...]
    刪除指定的斷點, breakpoints爲斷點號。如果不指定斷點號,則表示刪除所有的斷點。 range表示斷點號的範圍(如: 3-7)。其簡寫命令爲 d。

比刪除更好的一種方法是 disable停止點, disable了的停止點, GDB不會刪除,當你還需要時, enable即可,就好像回收站一樣。

disable [breakpoints] [range...]
    disable 所指定的停止點, breakpoints爲停止點號。如果什麼都不指定,表示disable所有的停止點。簡寫命令是 dis.

enable [breakpoints] [range...]
    enable 所指定的停止點, breakpoints爲停止點號。

enable [breakpoints] once range...
    enable 所指定的停止點一次,當程序停止後,該停止點馬上被 GDB自動 disable。

enable [breakpoints] delete range...
    enable 所指定的停止點一次,當程序停止後,該停止點馬上被 GDB自動刪除。

五、停止條件維護

前面在說到設置斷點時,我們提到過可以設置一個條件,當條件成立時,程序自動停止,這是一個非常強大的功能,這裏,我想專門說說這個條件的相關維護命令。一般來說,爲斷點設置一個條件,我們使用 if關鍵詞,後面跟其斷點條件。並且,條件設置好後,我們可以用 condition命令來修改斷點的條件。(只有 break和 watch命令支持 if, catch目前暫不支持 if)

condition <bnum> <expression>
    修改斷點號爲 bnum的停止條件爲 expression。

condition <bnum>
    清除斷點號爲 bnum的停止條件。

還有一個比較特殊的維護命令 ignore,你可以指定程序運行時,忽略停止條件幾次。

ignore <bnum> <count>
    表示忽略斷點號爲 bnum的停止條件 count次。

六、爲停止點設定運行命令

我們可以使用 GDB提供的 command命令來設置停止點的運行命令。也就是說,當運行的程序在被停止住時,我們可以讓其自動運行一些別的命令,這很有利行自動化調試。對基於 GDB的自動化調試是一個強大的支持。

commands [bnum]
... command-list ...
end

爲斷點號 bnum指寫一個命令列表。當程序被該斷點停住時, gdb會依次運行命令列表中的命令。

例如:

    break foo if x>0
    commands
    printf "x is %d\n",x
    continue
    end
    斷點設置在函數 foo中,斷點條件是 x>0,如果程序被斷住後,也就是,一旦 x的值在 foo函數中大於 0, GDB會自動打印出 x的值,並繼續運行程序。

如果你要清除斷點上的命令序列,那麼只要簡單的執行一下 commands命令,並直接在打個 end就行了。

七、斷點菜單

在 C++中,可能會重複出現同一個名字的函數若干次(函數重載),在這種情況下,break 不能告訴 GDB要停在哪個函數的入口。當然,你可以使用 break

0 func2 () at gdb_test.c:35

1 0x080484a9 in func1 (iptr=0xbf98a2f0) at gdb_test.c:28

2 0x08048453 in main (argc=Cannot access memory at address 0xc) at gdb_test.c:14

l 可以使用frame(縮寫爲f)命令查看當前棧幀,即當前所在的函數。

l GDB只能查看當前函數內的變量。如果要查看其它函數內的變量,需要切換棧幀,方法是爲frame命令傳遞幀號。

(gdb) p i

No symbol “i” in current context.

(gdb) frame 2

2 0x08048453 in main (argc=Cannot access memory at address 0xc) at gdb_test.c:14

(gdb) p i

$1 = 3

運行程序

l 要在GDB中運行程序,可以在shell中輸入gdb ./filename。

l 或者在運行GDB後,通過file命令打開程序。

l 調用run(縮寫爲r)命令開始執行。可以爲run命令傳遞命令行參數。set args命令撤銷之前傳遞的參數。

(gdb) run 1 2 3

Starting program: /home/pydeng/gdb_test/gdb_test 1 2 3

There are 4 args.

l 調用kill(縮寫爲k)命令停止程序的執行,然後使用run重新運行。

l 或者在程序運行的時候再次調用run命令,GDB將詢問是否重新運行程序。

查看代碼

l 可以使用list(縮寫爲l)命令顯示當前位置後面的十行代碼。加上負號則顯示前面十行,如list -。

l 可以以多種方式指定顯示的位置,如:

從第5行開始

(gdb) list 5,

到28行結束

(gdb) list ,28

顯示21到25行之間的代碼

(gdb) list 21,25

顯示func1函數

(gdb) list func1

顯示其它文件的12行

(gdb) list otherfile.c:12

顯示其它文件的函數

(gdb) list otherfile.c:func

l 可以通過set命令改變顯示的代碼行數,如set listsize 5。

設置斷點

l 使用break命令設置斷點,斷點的位置可以通過四種方式指定。

通過函數名指定

(gdb) break func1

通過行號指定

(gdb) break 9

通過文件名和行號指定

(gdb) break main.c:10

通過內存地址指定

(gdb) break *0x80483f4

l 也可以在到達斷點的時候,根據當前的位置設置斷點。如break +2在當前位置後面第2行的位置設置斷點,break -3在當前位置的前面第3行的位置設置斷點。

l 可以通過where命令查看當前所在的位置。

l 可以爲斷點添加條件,只有當條件滿足時纔會在斷點處暫停程序。

(gdb) b 17 if i==1

Breakpoint 8 at 0x8048455: file gdb_test.c, line 17.

l 程序到達斷點暫停後,可以使用continue命令恢復執行。

l 或者使用step或next命令單步執行。兩者的區別在於,step命令將進入被調用的函數,而next命令將函數調用看作一條語句。

l info breakpoints(縮寫爲i b)命令能夠查看設置的所有端點。Num爲斷點號,Enb標識端點是否啓用。

(gdb) i b

Num Type Disp Enb Address What

6 breakpoint keep n 0x08048436 in main at gdb_test.c:12

8 breakpoint keep y 0x08048455 in main at gdb_test.c:17

 stop only if i==1

l 可以使用clear或delete命令刪除斷點,前者使用上述四種指定斷點位置的方式標識斷點,後者使用斷點號標識斷點。

l 通過傳遞斷點號,disable或enable命令能夠暫時停用或重新啓用斷點。

查看變量

l 使用ptype(縮寫爲pt)命令查看變量的類型。要記住,只能查看當前棧幀內的變量。

l 使用print(縮寫爲p)命令加變量名,可以查看變量的值,也可以使用取地址符查看變量的地址,並且能夠指點顯示的格式。

o octal x hex d decimal u unsigned decimal

t binary f float a address c char

(gdb) p /x i

$3 = 0x1

l 查看數組時,可以指定顯示的元素起始位置和元素個數,但是不會檢查是否越界。

(gdb) p array[2]@5

$4 = {3, 4, 5, 6, 134514064}

l 也可以查看結構體。使用set print pretty命令優化顯示格式。

(gdb) p p

$6 = {age = 25, name = 0x80485a7 “cying”}

(gdb) set print pretty

(gdb) p p

$7 = {

age = 25,

name = 0x80485a7 “cying”

}

l 可以使用set或print命令,在程序執行過程中,改變變量的值,如set i = 5或print i = 5。兩者區別在於,後者打印改變後的值。

(gdb) set array[0]=11

(gdb) p array[1]=22

$8 = 22

(gdb) p array

$9 = {11, 22, 3, 4, 5, 6}

後記 
——

GDB 是一個強大的命令行調試工具。大家知道命令行的強大就是在於,其可以形成執行序列,形成腳本。 UNIX下的軟件全是命令行的,這給程序開發提代供了極大的便利,命令行軟件的優勢在於,它們可以非常容易的集成在一起,使用幾個簡單的已有工具的命令,就可以做出一個非常強大的功能。

文章來源: http://www.cnblogs.com/lidabo/p/4234362.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章