Linux操作系统中GDB工具介绍

本文主要介绍Linux操作系统中GDB(The GNU Project Debugger)工具,及其常见用法。

1 概述

1.1 What

引用GDB官网中的介绍,内容如下:

GDB, the GNU Project debugger, allows you to see what is going on 'inside' another program while it executes -- or what another program was doing at the moment it crashed.

GDB can do four main kinds of things (plus other things in support of these) to help you catch bugs in the act:

  • Start your program, specifying anything that might affect its behavior.
  • Make your program stop on specified conditions.
  • Examine what has happened, when your program has stopped.
  • Change things in your program, so you can experiment with correcting the effects of one bug and go on to learn about another.

Those programs might be executing on the same machine as GDB (native), on another machine (remote), or on a simulator. GDB can run on most popular UNIX and Microsoft Windows variants, as well as on Mac OS X.

2 常见用法

本章通过调试示例程序的方式,介绍GDB工具的常见用法。

2.1 示例程序1

2.1.1 源码及编译

示例程序的源代码(gdb_test1.cpp)内容如下:

#include <iostream>

using namespace std;

int Sum(int& x, int& y)
{
    cout << "Func Sum begin" << endl;
    int z;
    z = x + y;

    cout << "Func Sum end" << endl;
    return z;
}

int main()
{
    cout << "Func main begin" << endl;
    
    int a = 1;
    int b = 2;
    int c;

    c = Sum(a, b);
    cout << "c is: " << c << endl;

    cout << "Func main end" << endl;

    return 0;
}

编译上述代码,命令如下:

g++ -o gdb_test1 gdb_test1.cpp -g

注意:在编译过程中添加“-g”选项,将源代码信息添加到可执行文件中,便于后面进行gdb调试。

2.1.2 gdb调试

1. 启动gdb,命令及过程信息如下:

[root@node1 /opt/liitdar/mydemos/simples/gdb_test]# gdb
GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-110.el7
Copyright (C) 2013 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-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
(gdb) 

说明:

  • 启动gdb的命令格式为:“gdb”;
  • 启动gdb后,就可以在gdb命令行中输入gdb的调试命令了,后面介绍的gdb调试命令,都是在gdb命令行中输入并执行的。

2. 加载被调试的可执行文件,命令及过程信息如下:

(gdb) file gdb_test1
Reading symbols from /opt/liitdar/mydemos/simples/gdb_test/gdb_test1...done.
(gdb) 

说明:

  • 加载被调试的可执行文件的命令格式为:“file execute_file”,其中execute_file为可执行文件名称,其路径可以为绝对路径或相对路径。

3. 设置断点(breakpoint),命令及过程信息如下:

(gdb) b main
Breakpoint 1 at 0x400923: file gdb_test1.cpp, line 17.
(gdb) 

说明:

  • 设置断点的命令格式为:“b <行号>|<函数名称>|*<函数名称>|*<代码地址>”。在本例中,通过“函数名称”设置断点的;
  • 断点编号从“1”开始递增;
  • 在设置完某一断点后,点击“Enter”键时,会在前一个断点对应的代码位置继续执行断点设置操作(即重复设置断点),同时断点编号递增,命令及过程信息如下:
    (gdb) b main
    Breakpoint 1 at 0x400873: file gdb_test1.cpp, line 17.
    (gdb) 
    Note: breakpoint 1 also set at pc 0x400873.
    Breakpoint 2 at 0x400873: file gdb_test1.cpp, line 17.
    (gdb) 
    Note: breakpoints 1 and 2 also set at pc 0x400873.
    Breakpoint 3 at 0x400873: file gdb_test1.cpp, line 17.
    (gdb) 
  • 在函数名称前面加“*”表示将断点设置在“由编译器生成的prolog代码处”。建议了解相关的汇编知识后,再使用此方法设置断点。

4. 删除断点,命令及过程信息如下:

(gdb) d 1
(gdb) 

说明:

  • 删除断点的命令格式为:“d [断点编号]”;
  • 如果指定了断点编号,此操作会删除该编号对应的断点,否则,会删除所有断点;
  • 执行删除断点命令后,再次添加断点时,断点编号会(在上一个断点编号基础上)递增,即删除的断点编号不会回收。

5. 运行被调试的可执行文件,命令及过程信息如下:

【未设置断点时】:

(gdb) r
Starting program: /opt/liitdar/mydemos/simples/gdb_test/gdb_test1 
Func main begin
Func Sum begin
Func Sum end
c is: 3
Func main end
[Inferior 1 (process 7432) exited normally]
(gdb) 

【设置断点时】:

(gdb) r
Starting program: /opt/liitdar/mydemos/simples/gdb_test/gdb_test1 

Breakpoint 2, main () at gdb_test1.cpp:17
17	    cout << "Func main begin" << endl;
(gdb) 

说明:

  • 运行被调试的可执行文件的命令格式为:“r”;
  • 如果没有设置过断点,则执行完整程序;如果已经设置了断点,则程序运行到第一个可用的断点处暂停。在本例中,分别展示了设置断点和未设置断点的情况。

6. 继续执行被调试程序,命令及过程信息如下:

(gdb) c
Continuing.
Func main begin
Func Sum begin
Func Sum end
c is: 3
Func main end
[Inferior 1 (process 7548) exited normally]
(gdb) 

说明:

  • 继续执行被调试程序的命令格式为:“c”;
  • 此操作会继续执行被调试程序,直至下一个断点或程序结束。在本例中,由于后面没有断点了,所以完整程序执行结束。

7. 执行一行调试程序源码(如果此行代码中有函数调用,则会进入该函数中,继续一次一行地执行该函数的代码,命令及过程信息如下:

(gdb) s
23	    c = Sum(a, b);
(gdb) 
Sum (x=@0x7fffffffe498: 1, y=@0x7fffffffe494: 2) at gdb_test1.cpp:7
7	    cout << "Func Sum begin" << endl;
(gdb) 

说明:

  • 执行一行调试程序源码(每次一行执行调用的函数语句)的命令格式为:“s”;
  • 此操作用于执行一行源程序代码,如果此行代码中有函数调用,则会进入该函数中,继续一次一行地执行该函数的代码。在本例中,执行到23行时,由于该行存在函数调用语句“c = Sum(a, b);”,所以在执行该行代码时,程序流程进入了Sum函数中,后面每个“s”操作,都会继续执行Sum函数的每一行代码;
  • 此操作相当于其它调试器中的“Step Into(单步跟踪进入)”;
  • 此操作必须在程序包含源代码调试信息的情况下才可以使用(gcc编译时使用“-g”参数)。

8. 执行一行调试程序源码(如有函数调用,会执行该函数的所有内容),命令及过程信息如下:

(gdb) n
23	    c = Sum(a, b);
(gdb) 
Func Sum begin
Func Sum end
24	    cout << "c is: " << c << endl;
(gdb) 

说明:

  • 执行一行调试程序源码(一次执行完成所有的调用的函数语句)的命令格式为:“n”;
  • 此操作用于执行一行源程序代码,如果此行代码中有函数调用,则执行该函数的所有内容。在本例中,执行到23行时,由于该行存在函数调用语句“c = Sum(a, b);”,所以在执行该行代码时,函数Sum的全部内容都被执行了;
  • 此操作相当于其它调试器中的“Step Over(单步跟踪)”;
  • 此操作必须在程序包含源代码调试信息的情况下才可以使用(gcc编译时使用“-g”参数);
  • 在执行“s”或“n”操作时,gdb显示出来的代码是当前执行到的代码位置,而实际上该行代码尚未执行。例如,本例中第一个n操作后,gdb中显示了“23     c = Sum(a, b);”内容,但此时该行(即23行)代码尚未执行(可通过打印“c”的值证实)。

9. 打印变量的值,命令及过程信息如下:

(gdb) n
Func main begin
19	    int a = 1;
(gdb) 
20	    int b = 2;
(gdb) 
23	    c = Sum(a, b);
(gdb) p c
$19 = 0
(gdb) n
Func Sum begin
Func Sum end
24	    cout << "c is: " << c << endl;
(gdb) p c
$20 = 3
(gdb) 

说明:

  • 打印变量的值的命令格式为:“p <变量名称>”;
  • 此操作用于打印指定变量(临时变量或全局变量)的值。在本例中,打印了变量“c”的值。

3 常见问题

3.1 Missing separate debuginfos

在运行gdb时,如果遇到此问题,说明系统中缺少debug信息,此问题的错误信息后面通常都会给出问题解决方法,如下:

Missing separate debuginfos, use: debuginfo-install glibc-2.17-196.el7_4.2.x86_64 libgcc-4.8.5-16.el7_4.2.x86_64 libstdc++-4.8.5-16.el7_4.2.x86_64

1. 根据提示的问题解决方法,运行相关的命令,操作如下:

[root@node1 /opt/liitdar/mydemos/simples/gdb_test]# debuginfo-install glibc-2.17-196.el7_4.2.x86_64 libgcc-4.8.5-16.el7_4.2.x86_64 libstdc++-4.8.5-16.el7_4.2.x86_64
Loaded plugins: fastestmirror
enabling epel-debuginfo
epel-debuginfo/x86_64/metalink                                                                                                                                                                                       | 7.0 kB  00:00:00     
epel-debuginfo                                                                                                                                                                                                       | 1.5 kB  00:00:00     
epel-debuginfo/x86_64/primary                                                                                                                                                                                        | 503 kB  00:00:02     
Loading mirror speeds from cached hostfile
 * base: mirrors.aliyun.com
 * epel: mirror01.idc.hinet.net
 * epel-debuginfo: mirror01.idc.hinet.net
 * extras: mirrors.aliyun.com
 * updates: mirrors.aliyun.com
epel-debuginfo                                                                                                                                                                                                                    2783/2783
Could not find debuginfo for main pkg: glibc-2.17-196.el7_4.2.x86_64
Could not find debuginfo pkg for dependency package nss-softokn-freebl-3.28.3-8.el7_4.x86_64
Could not find debuginfo for main pkg: libgcc-4.8.5-16.el7_4.2.x86_64
Could not find debuginfo for main pkg: libstdc++-4.8.5-16.el7_4.2.x86_64
No debuginfo packages available to install
[root@node1 /opt/liitdar/mydemos/simples/gdb_test]# 

2. 运行“debuginfo-install”命令,安装debug信息时,提示找不到debuginfo包,这是因为yum源中没有配置debuginfo、或者未打开debuginfo源的开关。所以,首先需要保证yum源中的debuginfo配置可用。本文中使用的yum配置文件(CentOS-Base.repo)中的debuginfo相关信息如下:

#Debug Info
[debuginfo]
name=CentOS-$releasever - DebugInfo
baseurl=http://debuginfo.centos.org/$releasever/$basearch/
gpgcheck=0
enabled=1

说明:

  • 上述yum配置信息可以添加到“/etc/yum.repos.d/CentOS-Base.repo”中,或新增的一个文件,例如“/etc/yum.repos.d/CentOS-Debug.repo”;
  • CentOS官方对于debuginfo的描述:debuginfo - Packages with debugging symbols generated when the primary packages were built. No repo config is provided by default. Tools like oprofile, crash, and systemtap require debuginfo packages. Note that debuginfo packages may not be signed so must be installed with "--nogpgcheck" or using "gpgcheck=0" in the repo definition. These packages are found at http://debuginfo.centos.org/

3. 配置完yum源后,更新yum缓存;

4. 再次运行前面的gdb提示命令(内容如下),此时即可成功安装debuginfo信息了。

debuginfo-install glibc-2.17-196.el7_4.2.x86_64 libgcc-4.8.5-16.el7_4.2.x86_64 libstdc++-4.8.5-16.el7_4.2.x86_64

4 分析core文件

gdb工具的一个常见的使用场景,就是对于程序崩溃同时产生core文件时,对程序崩溃原因进行调试分析。

使用gdb分析程序及其core文件的命令样式如下:

gdb program文件 core文件

下面通过一个示例,来介绍一下使用gdb分析可执行程序及其core文件的过程。

示例项目文件中包含一个可执行程序“h264_rtsp_server”,以及一个对其对应的core文件“core.25313”,如下图所示:

现使用gdb对该程序及core文件进行分析,命令为:

gdb h264_rtsp_server core.25313

上述命令运行后,gdb的终端打印信息如下图所示:

在上图中,gdb的终端信息中给出了程序终止的简要信息,但通常来说,只有这些信息还不够。为了进一步分析程序终止的问题原因,通常会使用一个常见的命令“bt”,来回溯程序崩溃时的栈(stack)信息,如下图所示:

通过上图中的gdb终端信息,就可以轻易地找到导致程序崩溃的代码位置了,然后就需要根据具体的错误场景,分析找出代码所存在的问题了。

在上面的示例中,使用到的gdb的bt命令的介绍如下:

bt  Backtrace: display the program stack.

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

liitdar

赠人玫瑰,手有余香,君与吾共勉

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值