GDB简介
GDB(GNU Debugger)是Linux下一款C/C++程序调试工具,通过在命令行中执行相应的命令实现程序的调试,使用GDB时只需要在shell中输入gdb命令或gdb filename(filename为可执行程序文件名)即可进入GDB调试环境。

GDB主要有以下功能:

  • 设置断点

  • 单步调试

  • 查看变量的值

  • 动态改变程序的执行环境

  • 分析崩溃程序产生的core文件

GDB常用命令



调试示例1
gdbtest.c:

#include <stdio.h>int add(int start, int end){    int i, sum;    for(i=start; i<=end; i++)        sum += i;    return sum;}int main(){    int result;    result = add(1, 10);    printf("result=%d\n", result);    return 0;}

编译,需要添加-g参数,用于GDB调试:

$ gcc -o gdbtest gdbtest.c -g

该程序是计算1~10电脑的和,正确结果应该输出55,我们先运行一下程序:

$ ./gdbtestresult=55

程序在本电脑上运行正确,但是,该程序是存在问题的,add()函数中的sum变量应该赋初值0,否则在其它电脑上运行,如果该变量被初始化了随机数,则会计算出错误的结果。本次运行未出错的原因应该是该变量被默认初始化为0,所以计算无误。

下面使用GDB对该可执行程序进程调试:

$ gdb gdbtest

输出以下信息:

GNU gdb (Ubuntu 8.1-0ubuntu3.2) 8.1.0.20180409-gitCopyright (C) 2018 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 "x86_64-linux-gnu".Type "show configuration" for configuration details.For bug reporting instructions, please see:<http://www.gnu.org/software/gdb/bugs/>.Find the GDB manual and other documentation resources online at:<http://www.gnu.org/software/gdb/documentation/>.For help, type "help".Type "apropos word" to search for commands related to "word"...Reading symbols from gdbtest...done.(gdb)

首先输出一些系统信息,最后一行开头的(gdb)为命令提示符,输入start命令开始调试:

(gdb) startTemporary breakpoint 1 at 0x67b: file gdbtest.c, line 14.Starting program: /home/deeplearning/dcj/linuxCTest/GDBtest/gdbtestTemporary breakpoint 1, main () at gdbtest.c:1414          result = add(1, 10);(gdb)

程序直接运行至主函数处的第一条实质性的运行语句处,即第14行的子程序调用处,此处可以使用step命令步入该语句的程序内部:

(gdb) stepadd (start=1, end=10) at gdbtest.c:66           for(i=start; i<=end; i++)(gdb)

继续使用backtrace命令查看函数调用帧栈:

(gdb) backtrace#0  add (start=1, end=10) at gdbtest.c:6#1  0x000055555555468a in main () at gdbtest.c:14(gdb)

可以看出函数add()被主函数调用,主函数传入的start和end参数值。add()函数的栈帧号为0,主函数的栈帧号为1。

可以继续使用info locals命令查看add()函数中的局部变量的值,也可以使用frame 1命令先选择主函数所在的1号帧栈,再使用info locals命令查看主函数中的局部变量的值:

(gdb) info localsi = 0sum = 0(gdb) frame 1#1  0x000055555555468a in main () at gdbtest.c:1414          result = add(1, 10);(gdb) info localsresult = 0(gdb)

可以看到,add()函数中两个局部变量的值均被默认初始化为0,主函数中的局部变量result也被初始化为0。

如果局部变量默认不是初始化为0,可以在GDB环境下通过set var命令修改变量的值,并查看运行效果。由于程序在本电脑上运行无误,我们现在故意修改sum的初始值为100,并查看最终的运行结果:

(gdb) set var sum=100No symbol "sum" in current context.(gdb) frame 0#0  add (start=1, end=10) at gdbtest.c:66           for(i=start; i<=end; i++)(gdb) set var sum=100(gdb) print sum$1 = 100(gdb) info localsi = 0sum = 100(gdb) finishRun till exit from #0  add (start=1, end=10) at gdbtest.c:60x000055555555468a in main () at gdbtest.c:1414          result = add(1, 10);Value returned is $2 = 155(gdb)

使用set var sum=100将sum的值修改为100,注意要切换到sum变量所在的帧栈环境中执行,然后可以使用print或info locals命令查看修改后的结果,接着使用finish命令使程序自动运行结果,可以看出最终的输出的结果为155,符合预期。最后可以使用quit命令退出GDB环境:

(gdb) quitA debugging session is active.        Inferior 1 [process 31210] will be killed.Quit anyway? (y or n) y$

键入y确认退出即可。

调试示例2
计算从1到n是和,gdbbreakpoint.c:

#include <stdio.h>int main(){    int sum=0, i, data;    while(1)    {        printf("please input a num(<100)\n");        scanf("%d", &data);        for(i=1; i<=data; i++)            sum += i;        printf("sum from 1 to %d is: %d\n", data, sum);    }    return 0;}

编译并运行测试:

$ gcc -o gdbbreakpoint gdbbreakpoint.c -g$ ./gdbbreakpointplease input a num(<100)2sum from 1 to 2 is: 3please input a num(<100)3sum from 1 to 3 is: 9please input a num(<100)4sum from 1 to 4 is: 19please input a num(<100)^C

可以看到只有第一次计算正确,其后的都计算错误。

这次对程序设置断点进行调试,进入GDB环境后,可以先使用list命令查看源程序,确定所需加断点和行号:

(gdb) list1       #include <stdio.h>23       int main()4       {5           int sum=0, i, data;6           while(1)7           {8               printf("please input a num(<100)\n");9               scanf("%d", &data);10(gdb)11              for(i=1; i<=data; i++)12                  sum += i;1314              printf("sum from 1 to %d is: %d\n", data, sum);15          }1617          return 0;18      }(gdb)

list每次显示10行,可以使用Enter键继续显示,for循环语句位于第11行,使用break加行号命令设置断点:

(gdb) break 11Breakpoint 1 at 0x73c: file gdbbreakpoint.c, line 11.(gdb) info breakpointsNum     Type           Disp Enb Address            What1       breakpoint     keep y   0x000000000000073c in main                                                   at gdbbreakpoint.c:11(gdb)

此处还使用了info breakpoints查看当前已设置的所有断点。

然后使用start命令启动调试:

(gdb) startTemporary breakpoint 2 at 0x702: file gdbbreakpoint.c, line 4.Starting program: /home/deeplearning/dcj/linuxCTest/GDBtest/gdbbreakpointTemporary breakpoint 2, main () at gdbbreakpoint.c:44       {(gdb) continueContinuing.please input a num(<100)2Breakpoint 1, main () at gdbbreakpoint.c:1111              for(i=1; i<=data; i++)(gdb) info localssum = 0i = 32767data = 2(gdb)

程序先运行到主函数处暂停,继续使用continue命令使程序继续运行,然后程序提示输入一个数字,先输入2,之后程序执行至11行断点处,此时使用info locals命令查看局部变量的值,i此时为随机数(对后续结果不影响),sum和data为预期结果。

继续使用continue命令,此次输入3,并在11行断点再次使用info locals命令查看局部变量的值,发现sum的值在每次循环后没有清零,因此导致之后的计算结果出错。

(gdb) continueContinuing.sum from 1 to 2 is: 3please input a num(<100)3Breakpoint 1, main () at gdbbreakpoint.c:1111              for(i=1; i<=data; i++)(gdb) info localssum = 3i = 3data = 3(gdb)

找到原因,手动修改源程序,在while循环体的开始处将sum赋值0修正程序问题。

参考:

《精通Linux C编程》- 程国钢

《Linux C编程完全解密》- 闫敬 吴淑坤

©著作权归作者所有:来自51CTO博客作者mb5fdb1021b5992的原创作品,如需转载,请注明出处,否则将追究法律责任

更多相关文章

  1. 【redis】有关redis面试那些事(一)
  2. 微信小程序使用export和import
  3. 配置微信小程序自动更新
  4. 详解微信小程序登录wx.login(Object object)
  5. 小程序对IPhone全面屏手机底部黑线的安全区域处理
  6. 轻度Linux服务器维护人员常用的Shell脚本命令
  7. 多种详细讲解小程序页面传值
  8. 微信小程序从开发到发布流程
  9. 微信小程序实现带参分享并消息卡片获取参数

随机推荐

  1. Send JSON object to Struts 2 action by
  2. jquery 插件bgStretcher 切换背景图片
  3. jquery select(每个)所有选中的复选框?
  4. jquery ajax基本用法
  5. 谷歌地图信息窗口按钮没有显示?
  6. 为什么在使用jquery读写表单输入时必须对
  7. 在Rails应用程序中结合Scriptaculous和JQ
  8. jQuery对象和DOM对象
  9. jquery中的attr和prop深度理解
  10. 在2个不同的Div中播放/淡出声音