作者: liigo
原文链接: http://blog.csdn.net/liigo/archive/2006/01/17/582231.aspx

1.前言

本文写给主要工作在Windows操作系统下而又需要开发一些跨平台软件的程序员朋友,以及程序爱好者。

GDB是一个由GNU开源组织发布的、UNIX/LINUX操作系统下的、基于命令行的、功能强大的程序调试工具。

可以一个可以让你在程序运行时观察程序的内部结构和崩溃时查看程序崩溃现场的”调试器”。

GDB中的命令固然很多,但我们只需掌握其中十个左右的命令,就大致可以完成日常的基本的程序调试工作。

2. GDB主要功能

启动程序并可以定制程序启动运行环境和参数
制定条件(断点)让程序停止执行
在程序停止执行时查看程序信息
修改程序运行逻辑,这样就能纠正一个错误后继续调试

3.GDB命令

 命令  解释  示例
file <文件名> 加载被调试的可执行程序文件。
因为一般都在被调试程序所在目录下执行GDB,因而文本名不需要带路径。
(gdb) file
gdb-sample
r Run的简写,运行被调试的程序。
如果此前没有下过断点,则执行完整个程序;如果有断点,则程序暂停在第一个可用断点处。
(gdb) r
c Continue的简写,继续执行被调试程序,直至下一个断点或程序结束。 (gdb) c
b <行号>
b
<函数名称>
b *<函数名称>
b *<代码地址>

d [编号]

b:
Breakpoint的简写,设置断点。两可以使用“行号”“函数名称”“执行地址”等方式指定断点位置。
其中在函数名称前面加“*”符号表示将断点设置在“由编译器生成的prolog代码处”。如果不了解汇编,可以不予理会此用法。

d: Delete
breakpoint的简写,删除指定编号的某个断点,或删除所有断点。断点编号从1开始递增。

(gdb) b 8
(gdb) b main
(gdb)
b *main
(gdb) b *0x804835c

(gdb) d

s, n s: 执行一行源程序代码,如果此行代码中有函数调用,则进入该函数;
n:
执行一行源程序代码,此行代码中的函数调用也一并执行。

s 相当于其它调试器中的“Step Into (单步跟踪进入)”;
n
相当于其它调试器中的“Step Over (单步跟踪)”。

这两个命令必须在有源代码调试信息的情况下才可以使用(GCC编译时使用“-g”参数)。

(gdb) s
(gdb)
n
si, ni si命令类似于s命令,ni命令类似于n命令。所不同的是,这两个命令(si/ni)所针对的是汇编指令,而s/n针对的是源代码。 (gdb) si
(gdb)
ni
p <变量名称> Print的简写,显示指定变量(临时变量或全局变量)的值。 (gdb) p i
(gdb) p
nGlobalVar
display …

undisplay <编号>

display,设置程序中断后欲显示的数据及其格式。
例如,如果希望每次程序中断后可以看到即将被执行的下一条汇编指令,可以使用命令
“display
/i $pc”
其中 $pc 代表当前汇编指令,/i 表示以十六进行显示。当需要关心汇编代码时,此命令相当有用。

undispaly,取消先前的display设置,编号从1开始递增。

(gdb) display /i $pc

(gdb) undisplay 1

i Info的简写,用于显示各类信息,详情请查阅“help i”。 (gdb) i r
q Quit的简写,退出GDB调试环境。 (gdb) q
help [命令名称] GDB帮助命令,提供对GDB名种命令的解释说明。
如果指定了“命令名称”参数,则显示该命令的详细说明;如果没有指定参数,则分类显示所有GDB命令,供用户进一步浏览和查询。
(gdb) help
display

 

4.GDB实践

废话不多说,下面开始实践。先给出一个示例用的小程序,C语言代码,简单的不能再简单了:

 //此程序仅作为“GDB十分钟教程”的示例代码, by liigo
//Email: liigo@sina.com
//blog: http://blog.csdn.net/liigo
//WebSite: www.liigo.com #include <stdio.h> int nGlobalVar = ; int tempFunction(int a, int b)
{
printf("tempFunction is called, a = %d, b = %d \n", a, b);
return (a + b);
} int main()
{
int n;
n = ;
n++;
n--; nGlobalVar += ;
nGlobalVar -= ; printf("n = %d, nGlobalVar = %d \n", n, nGlobalVar); n = tempFunction(, );
printf("n = %d", n); return ;
  • GCC编译

请将此代码复制出来并保存到文件 gdb-sample.c 中,然后切换到此文件所在目录,用GCC编译之:

gcc
gdb-sample.c -o gdb-sample -g

在上面的命令行中,使用 -o 参数指定了编译生成的可执行文件名为
gdb-sample,使用参数 -g 表示将源代码信息编译到可执行文件中。如果不使用参数
-g,会给后面的GDB调试造成不便。

当然,如果我们没有程序的源代码,自然也无从使用 -g
参数,调试/跟踪时也只能是汇编代码级别的调试/跟踪。

  • 启动GDB

下面“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)
”为GDB内部命令引导符,等待用户输入GDB命令。

  • 载入被调试程序

下面使用“file”命令载入被调试程序 gdb-sample(这里的 gdb-sample
即前面 GCC 编译输出的可执行文件):

(gdb) file
gdb-sample
Reading symbols from
gdb-sample…done.

上面最后一行提示已经加载成功。

  • 运行被调试文件

下面使用“r”命令执行(Run)被调试文件,因为尚未设置任何断点,将直接执行到程序结束:

(gdb)
r
Starting program: /home/liigo/temp/test_jmp/test_jmp/gdb-sample
n = 1,
nGlobalVar = 88
tempFunction is called, a = 1, b = 2
n = 3
Program
exited normally.
  • 设置断点

下面使用“b”命令在 main
函数开头设置一个断点(Breakpoint):

(gdb) b
main
Breakpoint 1 at 0x804835c: file gdb-sample.c, line
19.

上面最后一行提示已经成功设置断点,并给出了该断点信息:在源文件 gdb-sample.c
第19行处设置断点;这是本程序的第一个断点(序号为1);断点处的代码地址为
0x804835c(此值可能仅在本次调试过程中有效)。

回过头去看源代码,第19行中的代码为“n = 1”,恰好是 main
函数中的第一个可执行语句(前面的“int n;”为变量定义语句,并非可执行语句)。

再次使用“r”命令执行(Run)被调试程序:

(gdb)
r
Starting program: /home/liigo/temp/gdb-sample

Breakpoint 1, main () at gdb-sample.c:19
19 n =
1;

程序中断在gdb-sample.c第19行处,即main函数是第一个可执行语句处。

上面最后一行信息为:下一条将要执行的源代码为“n =
1;”,它是源代码文件gdb-sample.c中的第19行。

下面使用“s”命令(Step)执行下一行代码(即第19行“n =
1;”):

  • 单步执行C代码
(gdb) s
20
n++;

上面的信息表示已经执行完“n =
1;”,并显示下一条要执行的代码为第20行的“n++;”。

既然已经执行了“n = 1;”,即给变量 n 赋值为
1,那我们用“p”命令(Print)看一下变量 n 的值是不是 1 :

(gdb) p n
$1 =
1

果然是 1。($1大致是表示这是第一次使用“p”命令——再次执行“p n”将显示“$2 =
1”——此信息应该没有什么用处。)

下面我们分别在第26行、tempFunction 函数开头各设置一个断点(分别使用命令“b
26”“b tempFunction”):

(gdb) b
26
Breakpoint 2 at 0x804837b: file gdb-sample.c, line 26.
(gdb) b
tempFunction
Breakpoint 3 at 0x804832e: file gdb-sample.c, line
12.
  • 继续执行

使用“c”命令继续(Continue)执行被调试程序,程序将中断在第二个断点(26行),此时全局变量 nGlobalVar
的值应该是 88;再一次执行“c”命令,程序将中断于第三个断点(12行,tempFunction 函数开头处),此时tempFunction 函数的两个参数
a、b 的值应分别是 1 和 2:

(gdb)
c
Continuing.

Breakpoint 2, main () at gdb-sample.c:26
26 printf("n = %d, nGlobalVar =
%d \n", n, nGlobalVar);
(gdb) p nGlobalVar
$2 = 88
(gdb)
c
Continuing.
n = 1, nGlobalVar = 88

Breakpoint 3, tempFunction (a=1, b=2) at gdb-sample.c:12
12
printf("tempFunction is called, a = %d, b = %d \n", a, b);
(gdb) p a
$3 =
1
(gdb) p b
$4 = 2

上面反馈的信息一切都在我们预料之中,哈哈~~~

再一次执行“c”命令(Continue),因为后面再也没有其它断点,程序将一直执行到结束:

(gdb)
c
Continuing.
tempFunction is called, a = 1, b = 2
n = 3
Program
exited normally.
  • 显示反汇编代码

有时候需要看到编译器生成的汇编代码,以进行汇编级的调试或跟踪,又该如何操作呢?

这就要用到display命令“display /i
$pc”了(此命令前面已有详细解释):

(gdb) display /i
$pc
(gdb) 

此后程序再中断时,就可以显示出汇编代码了:

(gdb)
r
Starting program: /home/liigo/temp/test_jmp/test_jmp/gdb-sample

Breakpoint 1, main () at gdb-sample.c:19
19 n = 1;
1: x/i $pc 0x804835c
<main+16>: movl $0x1,0xfffffffc(%ebp)

看到了汇编代码,“n = 1;”对应的汇编代码是“movl
$0x1,0xfffffffc(%ebp)”。

  • 单步执行反汇编代码

并且以后程序每次中断都将显示下一条汇编指定(“si”命令用于执行一条汇编代码——区别于“s”执行一行C代码):

(gdb) si
20
n++;
1: x/i $pc 0x8048363 <main+23>: lea 0xfffffffc(%ebp),%eax
(gdb)
si
0x08048366 20 n++;
1: x/i $pc 0x8048366 <main+26>: incl
(%eax)
(gdb) si
21 n–;
1: x/i $pc 0x8048368 <main+28>: lea
0xfffffffc(%ebp),%eax
(gdb) si
0x0804836b 21 n–;
1: x/i $pc 0x804836b
<main+31>: decl (%eax)
(gdb) si
23 nGlobalVar += 100;
1: x/i $pc
0x804836d <main+33>: addl $0x64,0x80494fc
  • 在编译器插入的标志处设置断点

接下来我们试一下命令“b *<函数名称>”。

为了更简明,有必要先删除目前所有断点(使用“d”命令——Delete
breakpoint):

(gdb) d
Delete
all breakpoints? (y or n) y
(gdb)

当被询问是否删除所有断点时,输入“y”并按回车键即可。

下面使用命令“b *main”在 main 函数的 prolog
代码处设置断点(prolog、epilog,分别表示编译器在每个函数的开头和结尾自行插入的代码):

(gdb) b
*main
Breakpoint 4 at 0x804834c: file gdb-sample.c, line 17.
(gdb)
r
The program being debugged has been started already.
Start it from the
beginning? (y or n) y
Starting program:
/home/liigo/temp/test_jmp/test_jmp/gdb-sample

Breakpoint 4, main () at gdb-sample.c:17
17 {
1: x/i $pc 0x804834c
<main>: push %ebp
(gdb) si
0x0804834d 17 {
1: x/i $pc 0x804834d
<main+1>: mov %esp,%ebp
(gdb) si
0x0804834f in main () at
gdb-sample.c:17
17 {
1: x/i $pc 0x804834f <main+3>: sub
$0x8,%esp
(gdb) si
0x08048352 17 {
1: x/i $pc 0x8048352 <main+6>:
and $0xfffffff0,%esp
(gdb) si
0x08048355 17 {
1: x/i $pc 0x8048355
<main+9>: mov $0x0,%eax
(gdb) si
0x0804835a 17 {
1: x/i $pc
0x804835a <main+14>: sub %eax,%esp
(gdb) si
19 n = 1;
1: x/i $pc
0x804835c <main+16>: movl
$0x1,0xfffffffc(%ebp)

  • 查看寄存器信息

此时可以使用“i r”命令显示寄存器中的当前值———“i r”即“Infomation
Register”:

(gdb) i r
eax
0xbffff6a4 -1073744220
ecx 0x42015554 1107383636
edx 0x40016bc8
1073834952
ebx 0x42130a14 1108544020
esp 0xbffff6a0 0xbffff6a0
ebp
0xbffff6a8 0xbffff6a8
esi 0x40015360 1073828704
edi 0x80483f0
134513648
eip 0x8048366 0x8048366
eflags 0x386 902
cs 0x23 35
ss
0x2b 43
ds 0x2b 43
es 0x2b 43
fs 0x0 0
gs 0x33
51

当然也可以显示任意一个指定的寄存器值:

(gdb) i r
eax
eax 0xbffff6a4 -1073744220
  • 退出GDB

最后一个要介绍的命令是“q”,退出(Quit)GDB调试环境:

(gdb) q
The
program is running. Exit anyway? (y or n) y
 

5. 参考文档

[1]kgdb.info站点 GDB文章归档:
http://www.kgdb.info/category/gdb/

[2]GDB 官方站点:
http://www.gnu.org/software/gdb/

[3]GDB 用户手册:
Debugging with
gdb

[4]GDB 内幕:
gdbint

[5]GDB远程串行协议
GDB
RSP(redhat 站点)

GDB
RSP(gdb 站点)

[6]GDB邮件列表:
GDB mailing-lists

[7]GDB Maintainers

GDB_Maintainer

本文地址:
http://www.kgdb.info/gdb_ten_minutes_tutorial/
版权所有
© 转载时必须以链接形式注明作者和原始出处!

[转]GDB-----1.GDB概述的更多相关文章

  1. GDB和GDB Server

    gdb是linux c编程标配的调试工具,平时接触比较多的可能是本机随gcc一起安装的调试工具.但是,即使是本机的gdb,也经常被printf代替,所以接触也仅限于知道. 简单程序固然可以用print ...

  2. 27 Debugging Go Code with GDB 使用GDB调试go代码

    Debugging Go Code with GDB  使用GDB调试go代码 Introduction Common Operations Go Extensions Known Issues Tu ...

  3. https://sourceware.org/gdb/onlinedocs/gdb/Forks.html

    https://sourceware.org/gdb/onlinedocs/gdb/Forks.html Next: Checkpoint/Restart, Previous: Threads, Up ...

  4. 【转载】【GDB】GDB with Python

    作者:薛定谔的喵链接:https://zhuanlan.zhihu.com/p/152274203来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 你还在用GDB调试程序 ...

  5. linux包之gdb之gdb命令与core文件产生

    gdb-7.2-64.el6_5.2.x86_64/usr/bin/gcore/usr/bin/gdb/usr/bin/gdb-add-index/usr/bin/gdbtui/usr/bin/gst ...

  6. Debugging with GDB 用GDB调试多线程程序

    Debugging with GDB http://www.delorie.com/gnu/docs/gdb/gdb_25.html GDB调试多线程程序总结 一直对GDB多线程调试接触不多,最近因为 ...

  7. GDB Core,gdb 调试大全,core文件调试

    编译: gcc -g -o hello hello.c gdb 调试: 基本 gdb 命令. 命 令 描 述 小结:常用的gdb命令 backtrace 显示程序中的当前位置和表示如何到达当前位置的栈 ...

  8. Linux高级编程--04.GDB调试程序(入门概述)

    GDB概述 GDB是GNU开源组织发布的一个强大的UNIX下的程序调试工具.或许,各位比较喜欢那种图形界面方式的,像VC.BCB等IDE的调试,但如果你是在UNIX平台下做软件,你会发现GDB这个调试 ...

  9. Linux下GDB调试

    GDB 是一个强大的命令行调试工具.大家知道命令行的强大就是在于,其可以形成执行 序列,形成脚本.UNIX 下的软件全是命令行的,这给程序开发提供了极大的便利,命令行 软件的优势在于, 他们可以非常容 ...

随机推荐

  1. 16 利用Zabbix完成windows监控

    点击返回:自学Zabbix之路 16 利用Zabbix完成windows监控 1.安装zabbix_agentd 1.1.下载zabbix_agentd监控客户端软件安装包(windows操作系统客户 ...

  2. 洛谷 P3155 [CQOI2009]叶子的染色 解题报告

    P3155 [CQOI2009]叶子的染色 题目描述 给一棵m个结点的无根树,你可以选择一个度数大于1的结点作为根,然后给一些结点(根.内部结点和叶子均可)着以黑色或白色.你的着色方案应该保证根结点到 ...

  3. 洛谷P4413 R2

    好,这是一道巨水题...... #include <cstdio> using namespace std; typedef long long LL; int main() { LL a ...

  4. A1078. Hashing

    The task of this problem is simple: insert a sequence of distinct positive integers into a hash tabl ...

  5. 【POJ1015】Jury compromise 多个费用的背包

    这是一道比较综合的动态规划问题. 首先,根据题目中的从N个人中选出M个人,并且要使得某个目标函数最优,可以想到是背包问题,且因为要取出M个人,人数也应该作为背包体积的一个维度. 其次,要求输出路径,因 ...

  6. 使用博客系统发生_STORAGE_WRITE_ERROR_错误

    因为本人有自己的vps正好又最近学习了网络的搭建,但是呢不是一番风顺的在假设好PHP.http和MySQL后吧一个博客系统放进去后出现了以下问题 好吧== 出来了这个问题到是让我看了半天,然后查了查说 ...

  7. location的三种连接方式和区别

    location.href是一个属性,要这样使用:location.href='http://www.example.com'而location.assign('http://www.example. ...

  8. 面向对象【day07】:类的继承(七)

    本节内容 1.概述 2.类的继承 3.总结 4.练习 一.概述 之前我们说到了类的公有属性和类的私有属性,其实就是类的封装,下面我们来讲讲继承,是面向对象的第二大特性. 面向对象编程 (OOP) 语言 ...

  9. python---ORM之SQLAlchemy(4)relationship多对多练习

    练习一:朋友 import sqlalchemy from sqlalchemy import create_engine from sqlalchemy import Column, String, ...

  10. HttpTool.java 【暂保留】

    备注 在 java tool util 工具类 中已存在 HttpTool.java 该类为java源生态的http 请求工具,不依赖第三方jar包 ,即插即用. package kingtool; ...