GDB 快速上手

安装好GDB后,接下来就要快速上手GDB的使用。GDBshell类似,采用命令行形式的命令来调试程序,GDB常用的命令也就10来个,掌握了这些常用的调试命令,基本上就可以满足日常程序的调试需求。

第01步:编译要调试的程序

首先,要将需要调试的源程序编译为可执行文件。以下面的C语言程序为例:

#include <stdio.h>

int main(void)
{
    int sum = 0;
    int i, num;

    printf("breakpoint 1\n");

    printf("input num: ");
    scanf("%d", &num);
    printf("breakpoint 2\n");

    if(num <= 0)
        printf("input invalid!\n");
    else
    {
        for(i = 1; i <= num; i++)
            sum += i;
        printf("sum = %d\n", sum);
    }

    printf("breakpoint 3\n");
    printf("goodbye!\n");
    return 0;
}

麻雀虽小,五脏俱全,上面的C语言程序实现了数据求和的简单功能,但包含了程序的三种基本结构:顺序程序结构、选择程序结构和循环程序结构。为方便演示,我们分别在第8行、第12行、第23行设置了三个打印断点的函数。接下来我们编译这个程序:

# gcc -g -O0 main.c -o a.out

生成的可执行文件a.out里都是二进制的机器指令,如果你想要源码级调试,就需要在编译程序时选中:debug选项(-g),生成的debug模式下的可执行文件a.out就包含了各种调试信息,其中最重要的一个信息就是:二进制机器指令和源程序代码之间的对应关系,有了这个调试信息,当程序运行二进制机器指令的时候,就可以实时显示对应的源代码,更方便我们阅读和调试。如果你在编译的时候不使用debug模式,而使用release模式,那么程序在运行时,显示给你的就是二进制的机器代码或汇编指令,不适合人类阅读。

为提高程序的运行效率和性能,编译器在编译程序时,往往会对源程序进行优化,比如常量折叠、缓存、内联展开等。我们在编译程序时,也可以通过参数来控制编译优化级别,一般可分为如下等级:

  • -O0:不对程序进行编译优化,默认的优化等级
  • -O1:可以减少目标文件的体积和程序执行时间
  • -O2:在-O1优化的基础上,编译器不执行循环展开和函数内联,增加了代码的性能
  • -Os:在-O2优化的基础上,专门优化目标文件的大小
  • -O3:在-O2优化的基础上,打开了-finline-functions, -funswitch-loops等标签

源程序经过编译器优化后,生成的二进制和源代码之间可能就不是一一对应的关系了。为了更好的演示源码级调试,我们在编译时选择-O0选项,不对程序进行编译优化。

第02步:进入GDB调试环境

需要调试的可执行程序a.out生成以后,接下来就可以使用gdb进行调试了,可以使用下面的命令来进入GDB调试环境,调试a.out(编译生成的a.out文件位于/home/gdb目录下):

root@ubuntu:/home/gdb# gdb a.out 
GNU gdb (Ubuntu 9.2-0ubuntu1~20.04) 9.2
Copyright (C) 2020 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 a.out...
(gdb) r
Starting program: /home/gdb/a.out 
breakpoint 1
input num: 3
breakpoint 2
sum = 6
breakpoint 3
goodbye!
[Inferior 1 (process 2768) exited normally]
(gdb) q
root@ubuntu:/home/gdb#

当我们使用# gdb a.out时,就会进入交互式的gdb调试环境,运行run(可简写为 r)命令即可启动a.out的运行。程序在运行过程中的输出、输入和正常运行模式下一样,程序结束后,输入quit(可简写为q)命令即可退出GDB调试环境,重新返回到SHELL环境下。

第03步:设置断点、打印变量

GDB作为一个调试器,调试器该有的功能他都有,比如:设置断点、打印变量、单步等。我们在调试程序时,如果想让程序在某行暂停,观察此时的一些寄存器、变量值,此时可以通过GDB的断点设置和变量打印功能来实现。

接下来就给大家演示下如何设置断点和打印变量:

root@ubuntu:/home/gdb# gdb a.out 
GNU gdb (Ubuntu 9.2-0ubuntu1~20.04) 9.2
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from a.out...
(gdb) b 8
Breakpoint 1 at 0x11cb: file main.c, line 8.
(gdb) b 12
Breakpoint 2 at 0x1200: file main.c, line 12.
(gdb) b 23
Breakpoint 3 at 0x1252: file main.c, line 23.
(gdb) r
Starting program: /home/gdb/a.out 

Breakpoint 1, main () at main.c:8
8        printf("breakpoint 1\n");
(gdb) print sum
$1 = 0
(gdb) c
Continuing.
breakpoint 1
input num: 3

Breakpoint 2, main () at main.c:12
12        printf("breakpoint 2\n");
(gdb) c
Continuing.
breakpoint 2
sum = 6

Breakpoint 3, main () at main.c:23
23        printf("breakpoint 3\n");
(gdb) print sum
$2 = 6
(gdb) c
Continuing.
breakpoint 3
goodbye!
[Inferior 1 (process 2780) exited normally]
(gdb) q
root@ubuntu:/home/gdb#

重新进入GDB调试环境,使用break(可简写为b)命令可以在源代码的具体某一行设置断点。设置好断点后,使用run命令即可运行程序,程序在运行过程中遇到断点会暂停下来,程序暂停后,你可以使用print命令来打印某一个具体变量的值。

如果想要程序继续运行,可以使用continue命令(可简写为c),程序会继续运行,直到遇到下一个断点暂停下来。如果没有再遇到断点,程序则会一直执行下去,直到运行结束。

在设置断点的时候,如果想查看某一行代码的具体行数,可以使用list(可简写为l)命令查看部分源代码。多次输入list命令,GDB就会依次显示不同的代码片段,直到你找到要设置的断点的行数为止。

GDB交互环境下,当你不输入任何命令,直接敲击回车键(Enter键)时,GDB会默认执行上一次你输入的命令。所以,当你需要多次运行同一个命令时,不需要每次都输入相同的命令,直接回车,就可以多次重复执行一个命令了。

《Linux三剑客》视频教程,从零开始快速掌握Linux开发常用的工具:Git、Makefile、vim、autotools、debug,免费赠送C语言视频教程,C语言项目实战:学生成绩管理系统。详情请点击淘宝链接:Linux三剑客