前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Linux系统下gdb调试(一)

Linux系统下gdb调试(一)

作者头像
用户6280468
发布2022-03-18 20:57:59
3.8K0
发布2022-03-18 20:57:59
举报
文章被收录于专栏:txp玩Linuxtxp玩Linux

这段时间逛了一下招聘网站上,对于嵌入式要求里面有要求会gdb调试,而且再加上昨天在交流群里面,刚好有网友问gdb怎么调试,这让我学gdb调试的欲望越来越强烈,这不,应网友的要求,今天就来给大家分享自己总结的实战调试方法(这里可能暂时写的比较基础一点,不过还请各位读者原谅,毕竟自身也是刚接触这个还没一个小时呢,同时也参考网上的博客和b站视频的学习,不过这里感觉还是老外的gdb视频讲解的比较好,hh)。

一、gdb和gdb命令介绍+实战演示:

1、什么是gdb呢

Linux 下的GDB(GNU Debugger)是-一个用来调试C、C++程序的功能强大的调试器,它能够在程序运行的过程中观察程序的内部结构和内存的使用情况。程序员也可以使用gdb来跟踪程序中的错误,从而减少了程序员的工作量。

2、gdb的功能作用:

gdb主要提供以下功能:

  • 设置断点,(断点可以是条件表达式) ,使程序在指定的代码行上暂停执行便于观察。
  • 单步执行程序,便于调试;
  • 查看程序中变量值的变化;
  • 动态改变程序的执行环境;
  • 分析崩溃程序产生的core文件。

3、gdb命令+实战演示:

gdb的使用非常简单,只要在Linux的命令提示符下输入gdb命令,系统便会启动gdb。也可以在gdb后面给出文件名,直接指定想要调试的程序,gdb就会自动调用这个可执行文件进行调试。命令形式如下:

#gdb filename

告诉gdb装入名为filename的可执行文件进行调试。

另外,为了使gdb正常工作,必须使程序在编译的时候包含调试信息,这需要在gcc编译时加上-g或者-ggdb选项。调试信息包含了程序中的每个变量的类型和在可执行文件中的地址映射以及源代码的行号。而gdb正是利用这些信息使源代码和机器码相关联。下图是在Linux下启动gdb的简单演示,具体会在下面的实战来演示:

代码语言:javascript
复制
root@ubuntu-virtual-machine:/home/ubuntu# gdb
 GNU gdb (Ubuntu 8.1-0ubuntu3) 8.1.0.20180409-git
 Copyright (C)  Free Software Foundation, Inc.
 License GPLv3+: GNU GPL version  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".
(gdb) 

a、常用命令如下:

b、断点命令:

暂时先介绍这些命令吧,我想网上大把的命令介绍,读者看到我把所有的命令都介绍一遍,估计都会看烦了,我还是以边演示,边讲解命令的形式来介绍为好。而且光看命令是很难领悟的,读者在看到这里也最好是自己去敲命令体验一下,这样才能够快速掌握它(不过这里我只是简单的使用,我比较喜欢在TUI(TextUser Interface),它为GDB调试的文本用户界面,可以方便地显示源代码、汇编和寄存器文本窗口),这里我以一个简单的程序为例,下面是源代码。好了废话不多说,我们直接开干吧:

代码语言:javascript
复制
#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", n);

      return ;
 }

演示过程:

(1)我们先来编译它,注意这里一个要加-g,这是gcc里面的一个选项(表示在生成的可执行程序中包含标准调试信息):

代码语言:javascript
复制
root@ubuntu-virtual-machine:/home/ubuntu# vim 3.c
root@ubuntu-virtual-machine:/home/ubuntu# gcc -g   3.c -o  test2   //这里-o表示把3.c指定编译指定输出生成test2
root@ubuntu-virtual-machine:/home/ubuntu# ls
    2.c    3.c    4.c    a.out  cc        
examples.desktop  gdb  hello   hello1.c  helloc.c  
server.c  test   test.c    tst                                
vmware-tools-distrib  模板  图片  下载  桌面
1.c  2.txt  3.txt  4.txt  a.txt  client.c  file              
h.c  hello1  hello.c   my.c      temp      test2  
text.txt  VMwareTools-10.0.6-3595377.tar.gz  公共的                
视频  文档  音乐

(2):启动gdb调试:

(3):开始运行程序,这里可以使用run(也可以简写r)命令,不过总这里开始我就不在这种形式下看这个了,因为后面调试不方便观察,所以我直接上TUI了,哈哈:

接着就开始进入TUI界面了,这里使用快捷键ctrl+A+X,不过你进入这个界面一开始看不到源程序,还要使用start命令,关于这个命令的使用,好像我在网上没看到,后面我去官方查了一下它的用法和解释如下:

代码语言:javascript
复制
 The ‘start’ command does the equivalent of setting a 
 temporary breakpoint
 at the beginning of the main procedure and then 
 invoking the ‘run’ command.
 Some programs contain an elaboration phase where some 
 startup code is executed before the main procedure is 
 called. This depends on the languages used
 to write your program. In C++, for instance, 
 constructors for static and global
 objects are executed before main is called. It is 
 therefore possible that the
 debugger stops before reaching the main procedure. 
 However, the temporary
 breakpoint will remain to halt execution.
 Specify the arguments to give to your program as 
 arguments to the ‘start’
command. These arguments will be given verbatim to the 
underlying ‘run’
command. Note that the same arguments will be reused if 
no argument is
provided during subsequent calls to ‘start’ or ‘run’.
It is sometimes necessary to debug the program during 
elaboration. In these
cases, using the start command would stop the execution 
of your program
too late, as the program would have already completed 
the elaboration phase.
Under these circumstances, either insert breakpoints in 
your elaboration code
before running your program or use the starti command.

上面的意思大概是这样的:

“start”命令的作用相当于设置一个临时断点

在主过程的开始,然后调用' run '命令。Some 程序 包含 一 个 精化 阶段 , 一些 启动 代码 executed called. 主 过程 之前这取决于使用的语言来编写你的程序。例如,在c++中,用于静态和全局的构造函数,对象在调用main之前执行。因此,有可能调试器在到达主过程之前停止。然而,临时断点将保留以停止执行。指定要给程序的参数作为“start”的参数命令。这些参数将被原原本本地提供给底层的“run”命令。注意,如果没有参数,则重用相同的参数在随后调用' start '或' run '时提供。有时在精化阶段调试程序是必要的。在这些在某些情况下,使用start命令将停止程序的执行太晚了,因为程序已经完成了精化阶段。在这种情况下,可以在精化代码中插入断点,在运行程序或使用starti命令之前。

好了下面我们来进入TUI界面了:

然后我们也可以使用快捷键ctrl+x+2,来调出它的底层地址变化,为下一部单步运行时,可以比较直观的可以看到程序的运行细节:

(4)设置断点,并且进行单步执行,这里我把断点设置在main函数这里,当然断点设置命令break可以简写b,同时单步执行命令step,也可以简写成s

注:

有读者就会问,设置断点从main开始,为啥是从14行开始,而不是从13开始呢?第14行中的代码为“n = 1”,恰好是 main 函数中的第一个可执行语句(前面的“int n;”为变量定义语句,并非可执行语句)。

接下来开始单步运行:

注:上面里面使用了一个命令print(也可以简写p,一般在gdb里面,命令可以简写命令的首个字母)来打印出变量n值。

下面我继续在程序的第21行和函数tempFunction设置断点:

说明:

使用“c”命令继续(Continue)执行被调试程序,程序将中断在第二个断点(21行),此时全局变量 nGlobalVar 的值应该是 88;再一次执行“c”命令,程序将中断于第三个断点(5行,tempFunction 函数开头处),此时tempFunction 函数的两个参数 a、b 的值应分别是 1 和 2。后面在继续执行的话就没断点了,可以把它想成在以前keil里面进行调试类似。同时记住退出gdb是按q键就可以退出了。

(4)小结:

这里的话,还有好多命令没有讲到,但是用这个TUI界面去调试,过程比较清楚,以前寄存器的地址都非常清楚的显示出来了。其实这里还可以跟python一起结合来玩,下次继续分享高级一点的关于gdb的用法。

二、案例演示:

代码语言:javascript
复制
   #include <stdio.h>
   int main(void)
   {
       int input =;
       printf("Input an integer:");
       scanf("%d",input);
       printf("The integer you input is %d\n",input);

       return ;
  }

说明:

上面的代码里面明显有一个错误,忘了在input前面加&。但是你在Linux环境编译的时候会报一个警告,不会报错,不细心的人,可能平常习惯了说有警告没啥关系,然后就直接运行,可以后面没想到,出现了下面这种情况:

下面我们使用gdb来调试这个程序:

代码语言:javascript
复制
root@ubuntu-virtual-machine:/home/ubuntu# gdb a.out
GNU gdb (Ubuntu 8.1-0ubuntu3) 8.1.0.20180409-git
Copyright (C)  Free Software Foundation, Inc.
License GPLv3+: GNU GPL version  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 a.out...done.
(gdb) run
Starting program: /home/ubuntu/a.out 
Input an integer:

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7a538c2 in _IO_vfscanf_internal (s=<optimized 
out>, format=<optimized out>, 
argptr=argptr@entry=0x7fffffffe350, errp=errp@entry=0x0)
at vfscanf.c:
    vfscanf.c: 没有那个文件或目录.
(gdb) backtrace
#  0x00007ffff7a538c2 in _IO_vfscanf_internal (s= 
 <optimized out>, format=<optimized out>, 
argptr=argptr@entry=0x7fffffffe350, errp=errp@entry=0x0)
at vfscanf.c:
#  0x00007ffff7a5ffd8 in __isoc99_scanf (format= 
<optimized out>) at isoc99_scanf.c:
#  0x00005555555546e0 in main () at hello1.c:
(gdb) frame 
#  0x00005555555546e0 in main () at hello1.c:
         scanf("%d",input);
(gdb) 

说明:

通过gdb调试我们发现程序的第6行出现了错误。这里两个命令的话,在上面的常规命令表格里面也有,这里我在讲解一下:backtrace命令表示追踪错误;而frame命令具体定位到错误的地方。

三、总结:

以上是今天关于的gdb的简单粗暴的使用方法,不过最好可以看一下官方的源手册说明,会更好,这里我分享一下:

链接:https://pan.baidu.com/s/1OmZvZHuvH_PkUqSE3Sp0fQ

提取码:1t7x

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-01-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 txp玩Linux 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档