GDB是一个由GNU开源组织发布的、UNIX/LINUX操作系统下的、基于命令行的、功能强大的程序调试工具。
常用命令如下:
命令
|
解释
|
示例
|
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
|
废话不多说,下面开始实践。
先给出一个示例用的小程序,C语言代码,简单的不能再简单了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
|
//此程序仅作为“GDB十分钟教程”的示例代码, by liigo //Email: liigo@sina.com //blog: http://blog.csdn.net/liigo //WebSite: www.liigo.com
#include <stdio.h>
int nGlobalVar = 0;
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 = 1; n++; n--;
nGlobalVar += 100; nGlobalVar -= 12;
printf("n = %d, nGlobalVar = %d /n", n, nGlobalVar);
n = tempFunction(1, 2); printf("n = %d", n);
return 0; }
|
请将此代码复制出来并保存到文件 gdb-sample.c 中,然后切换到此文件所在目录,用GCC编译之:
gcc gdb-sample.c -o gdb-sample -g |
在上面的命令行中,使用 -o 参数指定了编译生成的可执行文件名为 gdb-sample,使用参数 -g 表示将源代码信息编译到可执行文件中。如果不使用参数 -g,会给后面的GDB调试造成不便。当然,如果我们没有程序的源代码,自然也无从使用 -g 参数,调试/跟踪时也只能是汇编代码级别的调试/跟踪。
下面“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. |
上面最后一行提示已经加载成功。
(gdb) l <-------------------- l命令相当于list,从第一行开始例出原码。
下面使用“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;”):
上面的信息表示已经执行完“n = 1;”,并显示下一条要执行的代码为第20行的“n++;”。
既然已经执行了“n = 1;”,即给变量 n 赋值为 1,那我们用“p”命令(Print)看一下变量 n 的值是不是 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 |
最后一个要介绍的命令是“q”,退出(Quit)GDB调试环境:
(gdb) q
The program is running. Exit anyway? (y or n)
分享到:
相关推荐
《GDB简明教程》由张健撰写,主要聚焦于UNIX环境下的一款强大的C/C++调试工具——GDB。GDB,全称为GNU调试器(GNU Debugger),是GNU项目中的一个核心组件,它为程序员提供了全面的功能,以帮助他们在源代码级别上对...
### GDB简明教程知识点详解 #### 一、关于调试的重要性 在软件开发的过程中,调试是至关重要的一环。很多时候,调试程序所花费的时间远超实际编写代码的时间。当程序的实际运行逻辑与预期不符时,传统的手动逐行...
GDB简明教程,简要介绍了GDB的用途和基础命令,并列举了一些用例。
《C语言简明教程》是针对已经学习过C语言但需要进行系统复习的读者而设计的教程。C语言作为一门基础且强大的编程语言,对于理解计算机工作原理和深入学习其他高级语言具有重要的作用。本教程将对C语言的核心概念、...
这个简明教程将深入讲解NIOS II的基本概念、架构以及如何在实际应用中使用它。 一、NIOS II处理器概述 1. 架构:NIOS II处理器有三种不同的变体,包括E型(经济型)、F型(快速型)和S型(小尺寸型),以满足不同...
《生物信息学简明教程》是一本针对生物信息学初学者的指南,旨在介绍这个交叉学科的基本概念、工具和数据库。生物信息学是生物学、计算机科学、数学和统计学的结合,它在现代生命科学研究中扮演着至关重要的角色,...
本教程“C语言简明教程”旨在为初学者提供一个全面且易懂的学习平台。 首先,C语言的基础部分包括变量、数据类型、运算符和表达式。变量是存储数据的容器,而数据类型则定义了变量可以存储的数据种类,如整型(int...
此外,本教程还将涵盖汇编语言程序的设计与调试技巧,包括如何使用伪指令(如ORG、EQU、DB等)来组织代码,如何使用汇编器(Assembler)将源代码转换成机器码,以及如何利用调试工具(如Debug或GDB)来查找和修复...
《汇编语言教程及答案》是一份非常宝贵的教育资源,它为学习者提供了深入理解计算机底层运作机制的关键途径。汇编语言是一种低级编程语言,直接对应于机器指令,每个指令都与特定的CPU操作码相对应。这使得汇编语言...
这个简明的C语言教程可能还会涉及编码规范和最佳实践,帮助你编写出清晰、可维护的代码。通过深入学习和实践这些内容,你将能够提升你的C语言编程技能,更好地理解和解决复杂问题。无论你是打算开发操作系统、游戏...
了解如何使用GDB等调试工具可以极大地提高开发效率。 总的来说,《从C语言到嵌入式C语言开发》这本书将帮助读者从理论到实践,全面掌握嵌入式系统开发所需的技能。通过学习,读者不仅能够编写出高效的C代码,还能...
### Lazarus简明使用手册知识点解析 #### 一、Lazarus概述 Lazarus是一款免费的集成开发环境(IDE),它使用FreePascal编译器作为后台支持,专为Pascal语言编程而设计。这款IDE是用Pascal语言自身编写的,其界面...
《汇编语言程序设计简明教程电子教案》是一份深入浅出的教学资源,旨在帮助学习者掌握汇编语言编程的基础知识和技能。汇编语言,作为计算机科学中的底层语言,是计算机硬件与高级语言之间的桥梁,它允许程序员直接对...
6. 使用说明.txt:提供简明扼要的使用教程,帮助用户快速上手。 7. SN.txt:可能包含了软件的序列号信息,确保合法使用。 使用GetDataBack for FAT v3.66进行数据恢复的过程包括以下几个关键步骤: 1. 扫描:软件...
这个简明教程只是一个起点,随着你对NetBeans IDE的深入使用,你可能会探索更高级的主题,如单元测试、版本控制集成、性能分析和多模块项目管理。 总的来说,NetBeans IDE为C和C++开发者提供了一站式的解决方案,...
本压缩包包含两份珍贵的学习资料:“Ubuntu命令行简明教程”和“Ubuntu+命令技巧”,旨在帮助用户快速掌握Ubuntu系统的操作和管理。 “Ubuntu命令行简明教程”PDF文件是学习Linux基础操作的绝佳资料。命令行界面...
本教程“C++ 入门--非C程序员自学教程”将逐步引导你深入这些主题,以简明易懂的方式讲解每个概念,使非C背景的初学者也能快速掌握C++语言。无论你是希望扩展编程技能的开发者,还是对计算机科学感兴趣的学生,这都...