http://hi.baidu.com/jinglecode/item/cb71fd8a1a3e87d55f0ec159
你可以用 dev-cpp/bin/gdb
学习,也可以用linux来学习;
感谢http://blog.chinaunix.net/u/7918/showart_32864.html
先看一看 gdb 的命令分类:
(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.
查哪一方面的命令就用:
help + cmd
:help stack
标* 为重要命令;
下面举例说明:
//gdbtry.cpp
#include <iostream>
const int SIZE=10;
int dat[SIZE];
int out;
int fuc(int x)
{
if (x>0)
printf("%d\n",x);
else
printf("%d\n",-x);
};
int main()
{
int i,j,k;
for (i=0;i<SIZE;i++)
dat[i]=10+i;
out=5;
k=-10;
fuc(k);
for (out=0;out<SIZE;out++)
printf("int main:%d\n",dat[out]);
return 0;
}
//end gdbtry.cpp
用
g++ -g -o yjy.exe gdbtry.cpp
先编译一下,-g 用于加入调试信息
/*
g++ -S gdbtry.cpp
生成gdbtry.s 的汇编文件。以后用这个学汇编
*/
1》装载程序
gdb yjy
或进入gdb后 ,用
file yjy //装载
2》显示源文件
list 1,24
[begin,end], 行号
3》设断点
break main //加函数名
break 18//行号
del 取消所有断点
(gdb) del
Delete all breakpoints? (y or n) y
4》运行
run
5》
程序停在了
Breakpoint 1, main () at gdbtry.cpp:13
13 {
6》询问目前运行到哪
where
(gdb) where
#0 main () at gdbtry.cpp:13
7>显示变量
print i;
(gdb) print dat
$14 = {10, 11, 0, 0, 0, 0, 0, 0, 0, 0}
gdb把变量的值保存在自己设定的变量里,$NUM
print $2
也可打印变量
print 0xFF
$20 = 255
十六进制转换
8》 直接到下一断点
continue
(gdb) continue
Continuing.
Breakpoint 2, main () at gdbtry.cpp:18
9》next
按行执行,遇到函数调用不进入
10》查看断点信息
info break
(gdb) info break
Num Type Disp Enb Address What
1 breakpoint keep y 0x004013ed in main at gdbtry.cpp:13
breakpoint already hit 1 time
2 breakpoint keep y 0x00401420 in main at gdbtry.cpp:18
breakpoint already hit 1 time
3 breakpoint keep y 0x00401420 in main at gdbtry.cpp:18
11>函数调用
call fuc(100)
12》堆栈信息
先给printf 设个断点
break printf
在调用fuc
(gdb) call fuc(-1)
Breakpoint 4, 0x00410700 in printf ()
The program being debugged stopped while in a function called from GDB.
When the function (fuc(int)) is done executing, GDB will silently
stop (instead of continuing to evaluate the expression containing
the function call).
(gdb) bt
#0 0x00410700 in printf ()
#1 0x004013c6 in fuc(int) (x=-1) at gdbtry.cpp:10
#2 <function called from gdb>
#3 main () at gdbtry.cpp:21
查看堆栈,bt
有四层,程序以栈的方式管理函数调用
13》
敲入b按两次TAB键,你会看到所有b打头的命令:
(gdb) b
backtrace break bt
(gdb)
14》但前目录
pwd
15>程序信息
(gdb) info program
Using the running image of child thread 3892.0xf54.
Program stopped at 0x401445.
It stopped at a breakpoint that has since been deleted.
16》如果要调试线程的话
用thread
17》搜索源代码
gdb有好多很长的命令,打开头后,用TAB,实现命令补全
(gdb) forward-search main
12 int main()
(gdb)
18》查看地址
info line
(gdb) info line 2
Line 2 of "gdbtry.cpp" is at address 0x401390 <_Z3fuci> but contains no code.
(gdb) info line main
Line 13 of "gdbtry.cpp" starts at address 0x4013c8 <main>
and ends at 0x4013ed <main+37>.
(gdb) info line fuc
Line 6 of "gdbtry.cpp" starts at address 0x401390 <_Z3fuci>
and ends at 0x401396 <_Z3fuci+6>.
(gdb)
19>反汇编
(gdb) disassemble fuc
Dump of assembler code for function _Z3fuci:
0x401390 <_Z3fuci>: push %ebp
0x401391 <_Z3fuci+1>: mov %esp,%ebp
0x401393 <_Z3fuci+3>: sub $0x8,%esp
0x401396 <_Z3fuci+6>: cmpl $0x0,0x8(%ebp) // 用0 和x比较 if (x>0)
0x40139a <_Z3fuci+10>: jle 0x4013b1 <_Z3fuci+33> // 比较之后用跳转语句实现分支结构
0x40139c <_Z3fuci+12>: mov 0x8(%ebp),%eax
0x40139f <_Z3fuci+15>: mov %eax,0x4(%esp,1)
0x4013a3 <_Z3fuci+19>: movl $0x440000,(%esp,1)
0x4013aa <_Z3fuci+26>: call 0x410700 <printf>
0x4013af <_Z3fuci+31>: jmp 0x4013c6 <_Z3fuci+54> // 第一个分支结束跳到 函数尾部
0x4013b1 <_Z3fuci+33>: mov 0x8(%ebp),%eax
0x4013b4 <_Z3fuci+36>: neg %eax
0x4013b6 <_Z3fuci+38>: mov %eax,0x4(%esp,1)
0x4013ba <_Z3fuci+42>: movl $0x440000,(%esp,1)
0x4013c1 <_Z3fuci+49>: call 0x410700 <printf>
0x4013c6 <_Z3fuci+54>: leave
0x4013c7 <_Z3fuci+55>: ret
End of assembler dump.
(gdb)
20>查看数组
(gdb) p
$26 = {0, 0, 0, 0, 0}
print 可以用缩写 p
@后是长度
静态数组可直接加名字
动态一般这样:
21》显示格式
x 按十六进制格式显示变量。
d 按十进制格式显示变量。
u 按十六进制格式显示无符号整型。
o 按八进制格式显示变量。
t 按二进制格式显示变量。
a 按十六进制格式显示变量。
c 按字符格式显示变量。
f 按浮点数格式显示变量。
(gdb) p /x 123
$29 = 0x7b
(gdb) p /x &dat
$30 = 0x443010
(gdb) p &dat
$31 = (int (*)[10]) 0x443010
(gdb)
22》每次next/step 都显示
display
display /i $pc
$pc是GDB的环境变量,表示着指令的地址,/i则表示输出格式为机器指令码,也就是汇编。于是当程序停下后,就会出现源代码和机器指令码相对应的情形,这是一个很有意思的功能。
(gdb) display /i $pc
1: x/i $eip 0x4013ff <main+55>: mov 0xfffffffc(%ebp),%edx
(gdb) n
15 for (i=0;i<SIZE;i++)
1: x/i $eip 0x40140f <main+71>: lea 0xfffffffc(%ebp),%eax
(gdb) n
16 dat[i]=10+i;
1: x/i $eip 0x4013ff <main+55>: mov 0xfffffffc(%ebp),%edx
(gdb)
23> 显示寄存器
对学汇编很有帮助
(gdb) info registers
eax 0x22ff74 2293620
ecx 0x40ccb0 4246704
edx 0x0 0
ebx 0x4000 16384
esp 0x22ff50 0x22ff50
ebp 0x22ff78 0x22ff78
esi 0x35 53
edi 0xa 10
eip 0x4013ff 0x4013ff
eflags 0x293 659
cs 0x1b 27
ss 0x23 35
ds 0x23 35
es 0x23 35
fs 0x3b 59
gs 0x0 0
fctrl 0xffff037f -64641
fstat 0xffff0000 -65536
ftag 0xffffffff -1
fiseg 0x0 0
fioff 0x0 0
foseg 0xffff0000 -65536
fooff 0x0 0
---Type <return> to continue, or q <return> to quit---
fop 0x0 0
(gdb)
24》显示类型
whatis
(gdb) whatis i
type = int
(gdb) whatis dat
type = int [10]
(gdb)
25>显示语言
show language
(gdb) show language
The current source language is "auto; currently c++".
(gdb) help show language
Show the current source language.
(gdb)
设置语言
看看你认识几个啊
(gdb) set language
The currently understood settings are:
local or auto Automatic setting based on source file
c Use the C language
c++ Use the C++ language
asm Use the Asm language
chill Use the Chill language
fortran Use the Fortran language
java Use the Java language
modula-2 Use the Modula-2 language
pascal Use the Pascal language
scheme Use the Scheme language
(gdb)
26》大牛的后记,我也有同感
后记
——
GDB是一个强大的命令行调试工具。大家知道命令行的强大就是在于,其可以形成执行序列,形成脚本。UNIX下的软件全是命令行的,这给程序开发提代供了极大的便利,命令行软件的优势在于,它们可以非常容易的集成在一起,使用几个简单的已有工具的命令,就可以做出一个非常强大的功能。