Reference: http://www.cnblogs.com/xd502djj/archive/2012/08/30/2663960.html
linux下的c/c++調試器gdb
gdb
Linux 包含了一個叫 gdb 的 GNU 調試程序. gdb 是一個用來調試 C 和 C++ 程序的強力調試器. 它使你能在程序運行時觀察程序的內部結構和內存的使用情況. 以下是 gdb 所提供的一些功能:
* 設置斷點;
* 監視程序變量的值;
* 程序的單步執行;
* 修改變量的值。
gdb支持下列語言C, C++ ,FORTRAN, PACAL, Java, Chill, assembly, Modula-2. 一般來說,GDB會根據調試的程序來確定的相應的調試語言,比如說,擴展名為.c, GDB should it is a c programme,extern_name is .c, .cc, .cp, .cxx, .cpp, .c++, GDB should they are c++ programme
在命令行上鍵入 gdb 並按回車鍵就可以運行 gdb 了, 如果一切正常的話, gdb 將被啟動並且你將在屏幕上看到類似的內容:
GNU gdb Red Hat Linux (5.3post-0.20021129.18rh)
Copyright 2003 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-redhat-linux-gnu".
(gdb)
在可以使用 gdb 調試程序之前,必須使用 -g 選項編譯源文件。也就是說,如果你寫了下面的一個程序,名字命名為test.c++, 編譯時使用如下語句:
#g++ -o test -g test.c++
#./test
test.c++ 源程序如下:
#include <iostream.h>
static char buff [256];
static char* string;
int main ()
{
printf ("Please input a string: ");
gets (string);
printf (" Your string is: %s ", string);
}
運行后,程序出現了錯誤,這時你就可以使用gdb來查錯了,方法如下:
#gdb test
(gdb)run 運行test(二進制)程序
如果你在編譯時沒有加上參數-g選項,你也可以通過如下語句來達到相同的效果
#gdb
(gdb)file test
如果你想查看源程序的部分代碼,你可以用list命令來實現,如:
(gdb)list
可在 makefile 中如下定義 CFLAGS 變量:
CFLAGS = -g
運行 gdb 調試程序時通常使用如下的命令:
gdb progname
在 gdb 提示符下按回車健將重復上一個命令.
gdb命 令 描 述
file FILE 裝入想要調試的可執行文件.
kill 終止正在調試的程序.
list 列出產生執行文件的源代碼的一部分.
next 執行一行源代碼但不進入函數內部.
step 執行一行源代碼而且進入函數內部.
run 執行當前被調試的程序
q(quit) 終止 gdb
watch expr 使你能監視一個變量的值而不管它何時被改變.
rwatch expr 當expr被程序讀出時,程序被暫停
awatch expr 當expr被程序讀出時然后再被寫入時,程序被暫停
info whatchpoints 顯示所設置的觀測點的列表 the same as info break
make 使你能不退出 gdb 就可以重新產生可執行文件.
shell 使你能不離開 gdb 就執行 UNIX shell 命令. such as:(gdb)shell gedit
set and unset 分別用來設置和取消參數和環境變量,such as: (gdb)set i=9 (gdb)unset i
whatis 告訴你變量的類型,如(gdb)whatis i
如果你想得到結構體的定義,可用ptype command, such as: have a structive s, (gdb)ptype s
break NUM 在指定的行上設置斷點。
b(abbreviate of break) +offset
b(abbreviate of break) -offset
以上兩個命令在當前運行到的前幾行或后幾行設置斷點
break filename:linenum
在文件名的的第linenum處設置斷點
break filename:functionname
在函數前設置斷點
info break 顯示當前斷點清單,包括到達斷點處的次數等。
disable make the breakpoint don't execute
enable make the breakpoint can exec
example:
(gdb) l
39 pro1=pro2;
40 pro2.display();
41 pro1.display();
42 return 0;
43 }
(gdb) b 39
Breakpoint 3 at 0x8048862: file debug.c++, line 39.
(gdb) b -6
Breakpoint 4 at 0x804883f: file debug.c++, line 38.
(gdb) info bre
Num Type Disp Enb Address What
3 breakpoint keep y 0x08048862 in main at debug.c++:39
4 breakpoint keep y 0x0804883f in main at debug.c++:38
(gdb) disable 4
(gdb) info bre
Num Type Disp Enb Address What
3 breakpoint keep y 0x08048862 in main at debug.c++:39
4 breakpoint keep n 0x0804883f in main at debug.c++:38
(gdb) enable 4
(gdb) info bre
Num Type Disp Enb Address What
3 breakpoint keep y 0x08048862 in main at debug.c++:39
4 breakpoint keep y 0x0804883f in main at debug.c++:38
(gdb) disable 3 4
(gdb) info bre
Num Type Disp Enb Address What
3 breakpoint keep n 0x08048862 in main at debug.c++:39
4 breakpoint keep n 0x0804883f in main at debug.c++:38
tbreak 設置的斷點,當使用一次后就不能再使用了
bt 顯示所有的調用棧幀。該命令可用來顯示函數的調用順序。
clear 刪除設置在特定源文件、特定行上的斷點。其用法為:clear FILENAME:NUM。
delete 刪除所有設置的斷點
continue 繼續執行正在調試的程序。該命令用在程序由於處理信號或斷點而
導致停止運行時。
display EXPR 每次程序停止后顯示表達式的值。表達式由程序定義的變量組成。
help NAME 顯示指定命令的幫助信息。
info files 顯示被調試文件的詳細信息。
info func 顯示所有的函數名稱。
info local 顯示當函數中的局部變量信息。
info prog 顯示被調試程序的執行狀態。
info var 顯示所有的全局和靜態變量名稱。
make 在不退出 gdb 的情況下運行 make 工具。
print EXPR 顯示表達式 EXPR 的值。
使用where命令查看程序出錯的地方
顯示當前路徑變量的設置情況
(gdb)show path
顯示當前環境變量的設置情況
(gdb)show envir(abbreviate of environment)
也可以用cd and pwd commands
terminate a child thread use kill command
如果想查看命令的列表或選項,可以在命令行下輸入:
(gdb)M-?(就是ESC+?)
不過這種方式在遠程調試下不起作用。
break [file:]function(types) (函數重載時,就需加上類型)
用於函數的命令
call, finish, return
call name(flags) 調用並執行名為name,參數為args的函數
finish 如果可以則中止當前函數並打印它的返回值
return value 停止執行當前函數,並將value返回給調用者
such as:(gdb)call max(max1,mini1)
使用return函數退出函數,你也可以使用return命令返回一個隨意的值來測試邊界條件
要指定一個或多個其他的目錄,可以用一個或多個-d <路徑名>選項啟動GDB,如
$gdb -d /source/project test
要定位一個特定字符串在當前文件中的下一次出現可以使用search<字符串> 命令。使用反向查找命令reverse-search<字符串>來查找字符串上一次出現的地方
附加一個正在運行的進程將會自動將其停止以便你能使用常規的GDB命令來檢查它的狀態,such as:
(gdb)attach 1158(PID)
使用detach命令以允許該進程繼續執行,或者使用quit命令分離並退出GDB
GDB有能力在調試程序時處理任何一種信號,可以告訴GDB需要處理哪一種信號。可以要求GDB收到所指定的信號后立刻停止正大運行的程序,以便進行調試,你可以用GDB的handle命令來完成這一功能,如下如示:
(gdb)handle <signal><keywords....>
gdb下的多線程調試(摘錄)
gdb對於多線程程序的調試有如下的支持:
* 線程產生通知:在產生新的線程時, gdb會給出提示信息
(gdb) r
Starting program: /root/thread
[New Thread 1073951360 (LWP 12900)]
[New Thread 1082342592 (LWP 12907)]---以下三個為新產生的線程
[New Thread 1090731072 (LWP 12908)]
[New Thread 1099119552 (LWP 12909)]
* 查看線程:使用info threads可以查看運行的線程。
(gdb) info threads
4 Thread 1099119552 (LWP 12940) 0xffffe002 in ?? ()
3 Thread 1090731072 (LWP 12939) 0xffffe002 in ?? ()
2 Thread 1082342592 (LWP 12938) 0xffffe002 in ?? ()
* 1 Thread 1073951360 (LWP 12931) main (argc=1, argv=0xbfffda04) at thread.c:21
(gdb)
注意,行首的藍色文字為gdb分配的線程號,對線程進行切換時,使用該該號碼,而不是上文標出的綠色數字。
另外,行首的紅色星號標識了當前活動的線程
* 切換線程:使用 thread THREADNUMBER 進行切換,THREADNUMBER 為上文提到的線程號。下例顯示將活動線程從 1 切換至 4。
(gdb) info threads
4 Thread 1099119552 (LWP 12940) 0xffffe002 in ?? ()
3 Thread 1090731072 (LWP 12939) 0xffffe002 in ?? ()
2 Thread 1082342592 (LWP 12938) 0xffffe002 in ?? ()
* 1 Thread 1073951360 (LWP 12931) main (argc=1, argv=0xbfffda04) at thread.c:21
(gdb) thread 4
[Switching to thread 4 (Thread 1099119552 (LWP 12940))]#0 0xffffe002 in ?? ()
(gdb) info threads
* 4 Thread 1099119552 (LWP 12940) 0xffffe002 in ?? ()
3 Thread 1090731072 (LWP 12939) 0xffffe002 in ?? ()
2 Thread 1082342592 (LWP 12938) 0xffffe002 in ?? ()
1 Thread 1073951360 (LWP 12931) main (argc=1, argv=0xbfffda04) at thread.c:21
(gdb)
以上即為使用gdb提供的對多線程進行調試的一些基本命令。另外,gdb也提供對線程的斷點設置以及對指定或所有線程發布命令的命令。
初次接觸gdb下多線程的調試,往往會忽視gdb中活動線程的概念。一般來講,在使用gdb調試的時候,只有一個線程為活動線程,如果希望得到其他的線程的輸出結果,必須使用thread命令切換至指定的線程,才能對該線程進行調試或觀察輸出結果。
以下這部分是轉載的
gdb 應用舉例
本節用一個實例教你一步步的用 gdb 調試程序. 被調試的程序相當的簡單, 但它展示了 gdb 的典型應用.
下面列出了將被調試的程序. 這個程序被稱為 greeting , 它顯示一個簡單的問候, 再用反序將它列出.
#include <stdio.h>
main ()
{
char my_string[] = "hello there";
my_print (my_string);
my_print2 (my_string);
}
void my_print (char *string)
{
printf ("The string is %s\n", string);
}
void my_print2 (char *string)
{
char *string2;
int size, i;
size = strlen (string);
string2 = (char *) malloc (size + 1);
for (i = 0; i < size; i++)
string2[size - i] = string[i];
string2[size+1] = `\0';
printf ("The string printed backward is %s\n", string2);
}
用下面的命令編譯它:
gcc -o test test.c
這個程序執行時顯示如下結果:
The string is hello there
The string printed backward is
輸出的第一行是正確的, 但第二行打印出的東西並不是我們所期望的. 我們所設想的輸出應該是:
The string printed backward is ereht olleh
由於某些原因, my_print2 函數沒有正常工作. 讓我們用 gdb 看看問題究竟出在哪兒, 先鍵入如下命令:
gdb greeting
注意: 記得在編譯 greeting 程序時把調試選項打開.
如果你在輸入命令時忘了把要調試的程序作為參數傳給 gdb , 你可以在 gdb 提示符下用 file 命令來載入它:
(gdb) file greeting
這個命令將載入 greeting 可執行文件就象你在 gdb 命令行里裝入它一樣.
這時你能用 gdb 的 run 命令來運行 greeting 了. 當它在 gdb 里被運行后結果大約會象這樣:
(gdb) run
Starting program: /root/greeting
The string is hello there
The string printed backward is
Program exited with code 041
這個輸出和在 gdb 外面運行的結果一樣. 問題是, 為什么反序打印沒有工作? 為了找出症結所在, 我們可以在 my_print2 函數的 for 語句后設一個斷點, 具體的做法是在 gdb 提示符下鍵入 list 命令三次,列出源代碼:
(gdb) list
(gdb) list
(gdb) list
技巧: 在 gdb 提示符下按回車健將重復上一個命令.
第一次鍵入 list 命令的輸出如下:
1 #include <stdio.h>
2
3 main ()
4 {
5 char my_string[] = "hello there";
6
7 my_print (my_string);
8 my_print2 (my_string);
9 }
10
如果按下回車, gdb 將再執行一次 list 命令, 給出下列輸出:
11 my_print (char *string)
12 {
13 printf ("The string is %s\n", string);
14 }
15
16 my_print2 (char *string)
17 {
18 char *string2;
19 int size, i;
20
再按一次回車將列出 greeting 程序的剩余部分:
21 size = strlen (string);
22 string2 = (char *) malloc (size + 1);
23 for (i = 0; i < size; i++)
24 string2[size - i] = string[i];
25 string2[size+1] = `\0';
26 printf ("The string printed backward is %s\n", string2);
27 }
根據列出的源程序, 你能看到要設斷點的地方在第24行, 在 gdb 命令行提示符下鍵入如下命令設置斷點:
(gdb) break 24
gdb 將作出如下的響應:
Breakpoint 1 at 0x139: file greeting.c, line 24
(gdb)
現在再鍵入 run 命令, 將產生如下的輸出:
Starting program: /root/greeting
The string is hello there
Breakpoint 1, my_print2 (string = 0xbfffdc4 "hello there") at greeting.c :24
24 string2[size-i]=string[i]
你能通過設置一個觀察 string2[size - i] 變量的值的觀察點來看出錯誤是怎樣產生的, 做法是鍵入:
(gdb) watch string2[size - i]
gdb 將作出如下回應:
Watchpoint 2: string2[size - i]
現在可以用 next 命令來一步步的執行 for 循環了:
(gdb) next
經過第一次循環后, gdb 告訴我們 string2[size - i] 的值是 `h`. gdb 用如下的顯示來告訴你這個信息:
Watchpoint 2, string2[size - i]
Old value = 0 `\000'
New value = 104 `h'
my_print2(string = 0xbfffdc4 "hello there") at greeting.c:23
23 for (i=0; i<size; i++)
這個值正是期望的. 后來的數次循環的結果都是正確的. 當 i=10 時, 表達式 string2[size - i] 的值等於 `e`, size - i 的值等於 1, 最后一個字符已經拷到新串里了.
如果你再把循環執行下去, 你會看到已經沒有值分配給 string2[0] 了, 而它是新串的第一個字符, 因為 malloc 函數在分配內存時把它們初始化為空(null)字符. 所以 string2 的第一個字符是空字符. 這解釋了為什么在打印 string2 時沒有任何輸出了.
現在找出了問題出在哪里, 修正這個錯誤是很容易的. 你得把代碼里寫入 string2 的第一個字符的的偏移量改為 size - 1 而不是 size. 這是因為 string2 的大小為 12, 但起始偏移量是 0, 串內的字符從偏移量 0 到 偏移量 10, 偏移量 11 為空字符保留.
為了使代碼正常工作有很多種修改辦法. 一種是另設一個比串的實際大小小 1 的變量. 這是這種解決辦法的代碼:
#include <stdio.h>
main ()
{
char my_string[] = "hello there";
my_print (my_string);
my_print2 (my_string);
}
my_print (char *string)
{
printf ("The string is %s\n", string);
}
my_print2 (char *string)
{
char *string2;
int size, size2, i;
size = strlen (string);
size2 = size -1;
string2 = (char *) malloc (size + 1);
for (i = 0; i < size; i++)
string2[size2 - i] = string[i];
string2[size] = `\0';
printf ("The string printed backward is %s\n", string2);
}
以下是英文解釋,用man gdb就可以了
You can run gdb with no arguments or options; but the most usual way to
start GDB is with one argument or two, specifying an executable program
as the argument:
gdb program
You can also start with both an executable program and a core file
specified:
gdb program core
You can, instead, specify a process ID as a second argument, if you
want to debug a running process:
gdb program 1234
would attach GDB to process 1234 (unless you also have a file named
`1234'; GDB does check for a core file first).
Here are some of the most frequently needed GDB commands:
break [file:]function(types) (函數重載時,就需加上類型)
You can, instead, specify a process ID as a second argument, if you
want to debug a running process:
gdb program 1234
would attach GDB to process 1234 (unless you also have a file named
`1234'; GDB does check for a core file first).
Here are some of the most frequently needed GDB commands:
break [file:]function
You can, instead, specify a process ID as a second argument, if you
want to debug a running process:
gdb program 1234
would attach GDB to process 1234 (unless you also have a file named
`1234'; GDB does check for a core file first).
Here are some of the most frequently needed GDB commands:
break [file:]function
You can, instead, specify a process ID as a second argument, if you
want to debug a running process:
gdb program 1234
would attach GDB to process 1234 (unless you also have a file named
`1234'; GDB does check for a core file first).
Here are some of the most frequently needed GDB commands:
break [file:]function
Set a breakpoint at function (in file).
run [arglist]
Start your program (with arglist, if specified).
bt Backtrace: display the program stack.
print expr
Display the value of an expression.
c Continue running your program (after stopping, e.g. at a break-
point).
run [arglist]
Start your program (with arglist, if specified).
bt Backtrace: display the program stack.
print expr
Display the value of an expression.
c Continue running your program (after stopping, e.g. at a break-
point).
next Execute next program line (after stopping); step over any func-
tion calls in the line.
edit [file:]function
look at the program line where it is presently stopped.
list [file:]function
type the text of the program in the vicinity of where it is
presently stopped.
step Execute next program line (after stopping); step into any func-
next Execute next program line (after stopping); step over any func-
tion calls in the line.
edit [file:]function
look at the program line where it is presently stopped.
list [file:]function
type the text of the program in the vicinity of where it is
presently stopped.
step Execute next program line (after stopping); step into any func-
tion calls in the line.
help [name]
Show information about GDB command name, or general information
about using GDB.
quit Exit from GDB.
For full details on GDB, see Using GDB: A Guide to the GNU Source-Level
Debugger, by Richard M. Stallman and Roland H. Pesch. The same text is
available online as the gdb entry in the info program.
摘自 http://blog.chinaunix.net/space.php?uid=20535175&do=blog&id=1651304
調試Linux程序的時候,出現Segmentation Fault是最郁悶的事情了,程序代碼量很大的時候,可能花很多時間都找不到出錯原因。
這里介紹一種對你調試Segmentation Fault很有幫助的方法,可能能迅速幫助你找到出錯的代碼行。
這種方法需要用到Linux提供的core dump機制:當程序中出現內存操作錯誤時,會發生崩潰並產生核心文件(core文件)。使用GDB可以對產生的核心文件進行分析,找出程序是在什么時候崩潰的和在崩潰之前程序都做了些什么。
首先,你的Segmentation Fault錯誤必須要能重現(廢話…)。
然后,依參照下面的步驟來操作:
(1)無論你是用Makefile來編譯,還是直接在命令行手工輸入命令來編譯,都應該加上 -g 選項。
(2)一般來說,在默認情況下,在程序崩潰時,core文件是不生成的(很多Linux發行版在默認時禁止生成核心文件)。所以,你必須修改這個默認選項,在命令行執行:
ulimit -c unlimited
表示不限制生成的core文件的大小。
(3)運行你的程序,不管用什么方法,使之重現Segmentation Fault錯誤。
(4)這時,你會發現在你程序同一目錄下,生成了一個文件名為 core.*** 的文件,即核心文件。例如,“core.15667”這樣的文件。
(5)用GDB調試它。假設你的可執行程序名為test,則在命令行執行:
gdb test core.15667
然后可能會顯示出一堆信息:
GNU gdb Fedora (6.8-27.el5)
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "i386-redhat-linux-gnu"...
warning: Can't read pathname for load map: Input/output error.
…………………(中間還有很多內容,此處省略)……………………………
Loaded symbols for /usr/lib/libgpg-error.so.0
Core was generated by `./test'.
Program terminated with signal 11, Segmentation fault.
[New process 15668]
#0 0x0804c760 in thread _handler () at test.cpp:707
707 CDev* cur_dev = *it_d;
然后我們輸入並執行命令bt:
(gdb) bt
就會得到類似於下面的信息:
#0 0x0804c760 in thread _handler () at test.cpp:707
#1 0x006b149b in start_thread () from /lib/libpthread.so.0
#2 0x0060842e in clone () from /lib/libc.so.6
於是,我們一眼就看出來了:程序是在第707行使用指針時出的問題。
怎么樣,方便吧?
http://blog.csdn.net/learnhard/article/details/4879834