GDB常见用法介绍

本文主要介绍GDB的常见用法。

1. 概述

1.1 what

此处引用官方描述,如下:

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命令。

2. 加载被调试的可执行文件,如下:

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

说明:

  • 命令格式“(gdb) file execute_file”,可使用绝对路径或相对路径。

3. 设置断点(breakpoint),如下:

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

说明:

  • 命令格式“(gdb) b <行号>|<函数名称>|*<函数名称>|*<代码地址>”。在本例中,是通过“函数名称”设置的断点;
  • 断点编号从1开始递增。在我们设置完某一断点后,点击“enter”会继续执行设置断点的操作。
  • 在函数名称前面加“*”表示将断点设置在“由编译器生成的prolog代码处”,使用此方法设置断点,需要了解汇编知识。

4. 删除断,如下:

(gdb) d 1
(gdb) 

说明:

  • 命令格式“(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) 

说明:

  • 命令格式“(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) 

说明:

  • 命令格式“(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) 

说明:

  • 命令格式“(gdb) s”;
  • 此操作用于执行一行源程序代码,如果此行代码中有函数调用,则进入该函数中,继续一次一行地执行该函数的代码。在本例中,执行到23行时,由于该行存在函数调用“c = Sum(a, b);”,所以在执行该行代码时,程序流程进入了Sum函数中,后面每个“s”操作,都会继续执行该函数的每一行代码。
  • 此操作相当于其它调试器中的“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) 

说明:

  • 命令格式“(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) 

说明:

  • 命令格式“(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-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
即可成功安装debuginfo信息了。



猜你喜欢

转载自blog.csdn.net/liitdar/article/details/80700599
今日推荐