在Linux应用程序开发中,最常用的调试器是gdb,它可以在程序中设置断点、查看变量值、一步一步跟踪程序的执行过程

GDB(GNU symbolic debugger)简单地说就是一个调试工具。它是一个受通用公共许可证即GPL保护的自由软件。

像所有的调试器一样,GDB可以让你调试一个程序,包括让程序在你希望的地方停下,此时你可以查看变量、寄存器、内存及堆栈更进一步你可以修改变量及内存值。GDB是一个功能很强大的调试器,它可以调试多种语言(Ada、C++、Java、Pascal)。还有一点要说明的是,GDB是一个调试器,而不像 VC 是一个集成环境。你可以使用一些前端工具如XXGDB、DDD等。他们都有图形化界面,因此使用更方便,但它们仅是GDB的一层外壳。因此,你仍应熟悉GDB命令。事实上,当你使用这些图形化界面时间较长时,你才会发现熟悉GDB命令的重要性。

一、启动和退出gdb

首先注意一点,gdb调试的对象是可执行文件,而不是程序的源代码,所以你要先用gcc生成可执行文件

另外,如果要使一个可执行文件可以被gdb调试,那么在使用编译器gcc编译程序时需要加入-g选项。-g选项告诉gcc在编译程序时加入调试信息,这样才可以调试这个被编译的程序。 例如:gcc -g hello.c -o hello(-o是命名编译出来的可执行文件)

(一)、调试一个程序的命令格式

格式:gdb <可执程序文件名>

例:#gdb hello


1、 #gdb →( 进入gdb环境)
2、 (gdb) file hello → (把hello可执行文件加载到gdb里面)

(二)、退出

(gdb) quit

二、显示和查找程序的源代码

在调试时,一般要查看程序的源代码。list 命令用于列出程序的源代码,使用格式如下:

(gdb) list 显示10行代码,若再次运行该命令则显示接下来的10行代码(gdb默认设置)

(gdb) list 5,10 显示源代文件test.c中的第5行到第10行的代码,

(gdb) list test.c:5,10 显示源文件test.c中第5行到第10行的代码,在调试含有多个源文件的程序时使用

(gdb) list get_sum 显示get_sum函数周围的代码

(gdb) list test.c:get_sum 显示源文件test.c中get_sum函数周围的代码,在调试含多个源文件的程序时使用

(gdb) search <字符串> 用来从当前行向后查找第一个匹配的字符串

(gdb)reverse-search<字符串> 用来从当前行向前查找第一个匹配的字符串

举例:

三、执行程序和获得帮助

使用gdb hello或(gdb) file hello只是装入程序,程序并没有运行,如果要使程序运行,将文件装入gdb以后,在gdb提示符下输入run即可。

(gdb) run

如果想要详细了解gdb某个命令的使用方法,可以使用help命令

(gdb)help list

(gdb)help all

四、设置和管理断点

在调试程序时,往往需要程序在运行到某行、某个函数或某个条件发生时暂停下来,然后查看此时程序的状态,如各个变量的值、某个表达式的值等。为此,可以设置断点(break)。断点使程序运行到某个位置时暂停下来,以便检查和分析程序。

1、 以行号设置断点

在gdb中,大部分都是使用break命令为程序设置断点。而指定断点时,最常用的是为某行设置断点。例:

(gdb) break 7

Breakpoint 1 at0x80483c0: file test.c, line 7.

然后我们输入run命令运行程序:

(gdb) run

Starting program:/tmp/test

Breakpoint 1,get_sum (n=100) at test.c:7

7 sum +=i;

可以看到,程序运行完第6行的指令后就暂停了,第7行的代码并没有执行而是被gdb的断点中断了。此时,我们可以查看各个变量和表达式的值,以了解程序的当前状态。

2、以函数名设置断点

在break命令后跟上函数名,就可以为函数设置断点。例:

(gdb) break get_sum

Breakpoint 1 at0x80483aa: file test.c, line 5.

(gdb) run

Starting program:/tmp/test

Breakpoint 1,get_sum (n=100) at test.c:5

5 int sum = 0,i;

可以看到,程序在第5行停了上来。

3、以条件表达式设置断点

程序在运行过程中,当某个条件满足时,程序在某行中断暂停执行

方法1 命令格式:break行号或函数名 if 条件

例:

(gdb) clear

Deleted breakpoint1

(gdb) break7 if i==99

Breakpoint 2 at0x80483c0: file test.c, line 7.

(gdb) run

The program beingdebugged has been started already.

Start it from thebeginning? (y or n) y

Starting program:/tmp/test

Breakpoint 2,get_sum (n=100) at test.c:7

7 sum +=i;

可以看到,运行程序后在i==99时,程序中断在第7行。

方法2 watch <条件表达式>

例:(gdb) watchi==99

No symbol"i" in current context.

(gdb) list 6

1 #include <stdio.h>

2

3 int get_sum(int n)

4 {

5 int sum = 0,i;

6 for (i=0;i<n;i++)

7 sum +=i;

8 return sum;

9 }

10

(gdb) break 6

Breakpoint 1 at0x80483b1: file test.c, line 6.

(gdb) run

Starting program:/tmp/test

Breakpoint 1,get_sum (n=100) at test.c:6

6 for (i=0;i<n;i++)

Gdb运行后,以命令watch i==99设置条件断点,但是失败了,gdb提示在当前程序的上下文中没有符号i,这是因为此时test程序没有运行,变量i还没有被定义。

为了解决这个问题,首先在第6行设置断点,然后使用run命令运行程序,程序暂停在第6行,此时第5行的语句已经被执行,所以变量i已经定义。这时就可以使用watch i==99设置断点了。

4、查看当前设置的断点

使用info breakpoints命令可以查看当前所有的中断点,例如:

(gdb) break 7

Breakpoint 1 at0x80483c0: file test.c, line 7.

(gdb) break 15 if result=5050

Breakpoint 2 at0x8048405: file test.c, line 15.

(gdb) info breakpoints

Num     Type       Disp Enb  Address    What1   breakpoint     keep y  0x080483c0 in get_sum at test.c:72   breakpoint     keep y  0x08048405 in main at test.c:15

stop only if result = 5050

其中:

Num 表示断点的编号

Type 说明类型,类型为breakpoint是指中断

Disp 指明中断点在生效一次后是否失去作用,是则为disp,不是则为keep

Enb 说明中断点是否有效,有效则为y,无效则为n

Address列 说明中断所处的内存地址

What列 列出中断发生在哪个函数的第几行

Stop only if result==5050 说明这是一个条件中断

5、使中断失效或有效

disable <断点编号> 可以使某个断点失效,程序运行到该断点时不会停下来而是继续运行

enable <断点编号> 可以使某个断点恢复有效

例:

(gdb) info breakpoints

Num    Type       Disp Enb    Address    What1  breakpoint     keep y   0x080483c0 in get_sum at test.c:72  breakpoint     keep y   0x08048405 in main at test.c:15

stop only if result = 5050

(gdb) disable 2

(gdb) info breakpoints

Num Type          Disp Enb  Address    What1  breakpoint     keep y   0x080483c0 in get_sum at test.c:72  breakpoint     keep n   0x08048405 in main at test.c:15stop only if result = 5050

(gdb) enable 2

(gdb) info breakpoints

Num Type          Disp Enb   Address    What1  breakpoint     keep y   0x080483c0 in get_sum at test.c:72  breakpoint     keep y   0x08048405 in main at test.c:15stop only if result = 5050

6、删除断点

(gdb) clear 删除程序中所有的断点

(gdb) clear<行号> 删除此行的断点

(gdb) clear<函数名> 删除该函数的断点

(gdb) delete<断点编号> 删除指定编号的断点。如果一次要删除多个断点,各个断点编号以空格隔开

例:

(gdb) break 6

Breakpoint 1 at0x80483b1: file test.c, line 6.

(gdb) break 7

Breakpoint 2 at0x80483c0: file test.c, line 7.

(gdb) break 8 ifsum==5050

Breakpoint 3 at0x80483cf: file test.c, line 8.

(gdb) info breakpoints

Num Type           Disp Enb Address    What1   breakpoint     keep y  0x080483b1 in get_sum at test.c:62   breakpoint     keep y  0x080483c0 in get_sum at test.c:73   breakpoint     keep y  0x080483cf in get_sum at test.c:8stop only if sum == 5050

(gdb) clear 6

Deleted breakpoint1

(gdb) info breakpoints

Num Type           Disp Enb Address    What2   breakpoint     keep y  0x080483c0 in get_sum at test.c:73   breakpoint     keep y  0x080483cf in get_sum at test.c:8stop only if sum == 5050

(gdb) delete 2 3

(gdb) info breakpoints

No breakpoints orwatchpoints.

7、display <表示式>

在每次程序停在断点位置时,自动显示表达式中的内容

8、commands

>命令>end      结束命令输入作用:指定在程序到达断点位置时需要执行的调试器命令

五、查看和设置变量的值

当程序执行到中断点暂停执行时,需要查看变量或表达式的值,借此了解程序的执行状态

1、print命令

作用:print命令一般用来打印变量或表达式的值,也可以用来打印内存中从某个变量开始的一段存区域的内容,还可以用来对某个变量进行赋值。

格式:

print <变量或表达式> 打印变量或表达式的当前值,gdb会用伪变量($n)来保存输出值以备用

Print <变量=值>; 对变量进行赋值

Print <表达式@要打印的值的个数n> 打印以表达式值开始的n个数

例:

(gdb) break 7

Breakpoint 4 at0x80483c0: file test.c, line 7.

(gdb) run

Starting program:/tmp/test

Breakpoint 4,get_sum (n=100) at test.c:7

7 sum += i;

(gdb)print i<n 打印出i<n表达式的值,显然这个表达式为真,因此值为1

$1 = 1

(gdb) print i

$2 = 0

(gdb) print sum

$3 = 0

(gdb) print i=200

$4 = 200

(gdb) continue

Continuing.

1+2+…+100=200

Program exitednormally.

2、whatis 命令

作用:用来显示某个变量或表达式值的数据类型

格式:whatis <变量或表达式>

例:

(gdb) break 7

Note: breakpoint 4also set at pc 0x80483c0.

Breakpoint 5 at0x80483c0: file test.c, line 7.

(gdb) run

Starting program:/tmp/test

Breakpoint 4,get_sum (n=100) at test.c:7

7 sum += i;

(gdb) whatis i

type = int

(gdb) whatis sum+0.5

type = double

3、set 命令

作用:用来给变量赋值

格式:set variable 变量=值 相当于print 变量=值

例:set variable i=200,相当于print i=200

六、控制程序的执行

当程序执行到指定的中断点,查看了变量或表达式的值后,可以让程序继续运行。也可以让程序一步一步地执行,或可以让程序地直运行下去直到下一个断点或运行完为止。

1、 continue命令

作用:让程序继续运行,直到下一个断点或运行完为止。

格式:continue

2、 kill命令

作用:用于结束当前程序的调试

例:(gdb) kill

Kill the program being debugged? (y or n) y

3、 next和step命令

作用:一次一条地执行程序代码

next和step的区别:

1)、如果遇到函数调用,next会把该函数调用当作一条语句来执行,再次输入next会执行函数调用后的语句

2)、step则会跟踪进入函数,一次一条地执行函数内的代码,直到函数的代码执行完,才执行函数调用后的语句

例:next语句的用法

(gdb) list 1,171      #include <stdio.h>23      int get_sum(int n)4      {5        int sum = 0,i;6        for(i=0;i<n;i++)7         sum += i;8        return sum;9      }1011     int main()12     {13       int i=100,result;14       result = get_sum(i);15       printf("1+2+...+%d=%d\n",i,result);16       return 0;17      }
(gdb) break 13Breakpoint 1 at 0x80483f0: file test.c, line13.(gdb) runStarting program: /tmp/testBreakpoint 1, main () at test.c:1313       int i=100,result;(gdb) next14       result = get_sum(i);(gdb) next15       printf("1+2+...+%d=%d\n",i,result);(gdb) next1+2+...+100=495016       return 0;(gdb) next17     }(gdb) next0x4003328b in __libc_start_main () from/lib/libc.so.6(gdb) nextSingle stepping until exit from function__libc_start_main,which has no line number information.Program exited normally.

例:step语句的用法

(gdb) list 1,171       #include <stdio.h>23       int get_sum(int n)4       {5         int sum = 0,i;6         for(i=0;i<n;i++)7          sum += i;8         return sum;9       }1011      int main()12      {13        int i=100,result;14        result = get_sum(i);15       printf("1+2+...+%d=%d\n",i,result);16        return 0;17      }
(gdb) break 13Breakpoint 1 at 0x80483f0: filetest.c, line 13.(gdb) runStarting program: /tmp/testBreakpoint 1, main () at test.c:1313        int i=100,result;(gdb) step14        result = get_sum(i);(gdb) stepget_sum (n=100) at test.c:55         int sum = 0,i;(gdb) step6         for(i=0;i<n;i++)(gdb) step7          sum += i;(gdb) step6         for(i=0;i<n;i++)(gdb) step7          sum += i;(gdb) step6         for(i=0;i<n;i++)(gdb) step7          sum += i;

4、 nexti和stepi命令

作用:用来单步执行一条机器指令,注意不是单步执行一行语句。单步执行一行语句的命令是next和step命令

注意:

nexti和next类似,不会跟踪进入函数内部去执行
Stepi和step类似,跟踪进入函数执行。

参考:

https://blog.csdn.net/sanganqi_wusuierzi/article/details/54783958

https://sourceware.org/gdb/

https://blog.csdn.net/haoel/article/details/2879

https://blog.csdn.net/liigo/article/details/582231

https://www.cnblogs.com/chenmingjun/p/8280889.html

https://www.cnblogs.com/hanframe/p/3585622.html

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

gdb 的用法(Linux调试器)相关推荐

  1. 【Linux】Linux调试器--gdb详解

    Linux环境基础开发工具使用(二) 一.Linux调试器-gdb使用 1.背景 2.使用 二.Linux项目自动化构建工具-make/Makefile 1.背景 2.依赖关系和依赖方法 3.原理 4 ...

  2. linux的静态编译elf无法调试,[翻译]自己动手编写一个Linux调试器系列之4 ELF文件格式与DWARF调试格式 by lantie@15PB...

    自己动手编写一个Linux调试器系列之4 ELF文件格式与DWARF调试格式 by lantie@15PB 在上一节中,你已经听说了DWARF调试格式,它是程序的调试信息,是一种可以更好理解源码的方式 ...

  3. Linux调试器-gdb使用

    目录 1. 背景 2. 开始使用 3. 理解 创建需要调试的代码 debug&&release 4 详细调试 list/l 行号 list/l 函数名 r或run break(b) i ...

  4. 优秀的gdb图形化前端调试器

    目前我自己最喜欢的还是 ddd . gdbgui 和 vim-vebugger插件或vimgdb插件 三种. You could try using Insight a graphical front ...

  5. Linux调试器工作原理——基础篇

    英文原文:Eli Bendersky编译:伯乐在线-陈舸 本文是一系列探究调试器工作原理的文章的第一篇.我还不确定这个系列需要包括多少篇文章以及它们所涵盖的主题,但我打算从基础知识开始说起. 关于本文 ...

  6. 开发一个 Linux 调试器(四):Elves 和 dwarves

    https://linux.cn/article-8719-1.html 到目前为止,你已经偶尔听到了关于 dwarves.调试信息.一种无需解析就可以理解源码方式.今天我们会详细介绍源码级的调试信息 ...

  7. found dwarf version #039;4#039; linux,开发一个Linux调试器(四):Elves和dwarves

    到目前为止,你已经偶尔听到了关于 dwarves.调试信息.一种无需解析就可以理解源码方式.今天我们会详细介绍源码级的调试信息,作为本指南后面部分使用它的准备. 系列文章索引 随着后面文章的发布,这些 ...

  8. linux如何调试elf程序,开发一个Linux调试器就需要了解ELF和DWARF

    到目前为止,可能你已经听到了关于调试信息或者关于除了解析代码以外的理解源代码的方法的DWARF的只言片语.今天,我们将介绍源代码级的调试信息的细节,以备在该系列的余下部分使用它. ELF和DWARF简 ...

  9. linux调试器(dbg)使用

    1 用例 2 进入调试器 使用调试器进行观察: $gdb ./a.out 进入下面界面,可以进行调试了 3 调试器命令 (1)starti:程序执行的第一条指令停下来,第一条应该是个动态库 (2)   ...

最新文章

  1. cd命令无法切换路径(Windows下)
  2. Visual Studio提示“无法启动IIS Express Web服务器”的解决方法
  3. 13个代码注释的小贴士
  4. editor.md 实现拖拽剪切复制粘贴上传图片,文件插件
  5. hdata datax交流总结
  6. Docker的简单使用
  7. 洛谷 P1008 [NOIP1998 普及组] 三连击
  8. springboot快速入门(一)——HelloWorld搭建
  9. Checkpoint 发布恶意软件规避分析的技术百科
  10. csv 中 数值被自动转换成科学计数法 的问题 excel打开后数字用科学计数法显示且低位变0的解决方法
  11. zTree根据ID选中节点
  12. 装箱问题 BPP first fit、best fit、first fit decreasing、best fit decreasing
  13. 一步一步教你做微博用户画像分析:Python微博爬虫+词云生成
  14. java的封装 继承 多态_java继承多态是什么意思?java封装继承多态的例子
  15. 人体反应测试仪 c语言,FD.12-FD-HRT-A
  16. 高通滤波与低通滤波的简单理解
  17. 共识算法PBFT资料整理
  18. 缓冲区溢出漏洞_缓冲区溢出漏洞简介
  19. [转] 介绍深度学习和长期记忆网络
  20. 入耳式降噪蓝牙耳机哪款好用?主动降噪耳机排行榜10强!

热门文章

  1. Human-level concept learning through probabilistic program induction学习与验证
  2. 为外部硬件设置一键连接WiFi HF-SmartLink V7的使用
  3. 软考中级程序设计师复习——数据库基础(2)
  4. oracle表空间文件离线,oracle 表空间 数据文件 笔记
  5. 特殊场景下的个人信息
  6. 有关Batch Size的玄学被打破了!
  7. 在线域名批量查询工具-未注册域名批量查询软件
  8. 还是很想喷一下Xbox360 natal……
  9. 探索神经网络的奥秘:如何优化模型和提高训练速度
  10. GPIO模拟串口TX与RX,波特率115200