1. GDB的简单介绍

GDB是由GNU软件系统社区提供的调试工具,同GCC配套组成了一套完成的开发环境,GDB是Linux和许多类Unix系统中的标准开发环境。 具备以下四点功能:

  • 启动程序,可以按照自定义方式运行程序;
  • 可以让程序停在断点处(断点可以是条件表达式);
  • 当程序停止,可以检查此时程序中所发生的事(变量的值等);
  • 可以改变程序,将一个BUG产生的影响修正从而测试其他BUG

2.GDB命令

#启动和退出
gdb 可执行程序
quit

#给程序设置参数、获取参数
set args 10 20
show args

#GDB使用帮助
help

#查看当前文件代码
list/l (从默认位置显示)
list/l 行号 (从指定行显示)
list/l 函数名 (从指定函数显示)

#查看非当前文件代码
list/l 文件名:行号
list/l 文件名:函数名

#设置显示的行数
show list/listsize
set list/listsize行数

3.调试基本流程

#include <stdio.h>
#include <stdlib.h>

int test(int a);

int main(int argc, char* argv[]) {
    int a, b;
    printf("argc = %d\n", argc);

    if(argc < 3) {
        a = 10;
        b = 30;
    } else {
        a = atoi(argv[1]);
        b = atoi(argv[2]);
    }
    printf("a = %d, b = %d\n", a, b);
    printf("a + b = %d\n", a + b);

    for(int i = 0; i < a; ++i) {
        printf("i = %d\n", i);
        // 函数调用
        int res = test(i);
        printf("res value: %d\n", res);
    }

    printf("THE END !!!\n");
    return 0;
}

int test(int a) {
    int num = 0;
    for(int i = 0; i < a; ++i) {
        num += i;
    }
    return num;
}

一个简单的程序,来自 牛客大学的视频。这个函数会接收外界的参数,然后进行一些简单操作。
在这里插入图片描述
首先得通过-g生成具备调试信息的可执行文件,-g表示在编译的时候加入调试信息,该调试信息可以被调试器(GDB)调试。同时生成一个不含调试信息的test1,通过文件大小对比,可以看出含有调试信息的test大小为10K,明显大于8.6K。通过rm test1删除test1文件。
在这里插入图片描述
通过启动命令gdb test进入GDB模式,终端出现了很多信息。
在这里插入图片描述
通过set args 10 20给可执行程序输入两个参数,并通过show args显示参数。
在这里插入图片描述
通过help 命令 可以查看命令的帮助。
在这里插入图片描述
通过list 行号可以查看对应行的代码,可以看到显示出来的10行代码,20行处于中间位置。
在这里插入图片描述
通过list 函数名可以查看对应函数的代码,可以看到显示出来的10行代码,main函数处于中间位置。
在这里插入图片描述
通过set list 5将显示的代码行数设置为5(默认是10行)。

4.断点操作命令

斜杠代表可选,不是命令的一部分。

#设置断点
b/break 行号
b/break 函数
b/break 文件名:行号
b/break 文件名:函数

#查看断点
i/info b/break

#删除断点
d/del/delete

#失能/使能断点
dis/disable 断点编号
ena/enable 断点编号

#设置条件断点(一般用于循环)
b/break 10 if i==5

存在这样几个文件,bubble.cpp、select.cpp、main.cpp、sort.h。

//bubble.cpp
#include "sort.h"
#include <iostream>

using namespace std;

void bubbleSort(int *array, int len) {

    for (int i = 0; i < len - 1; i++) {
		for (int j = 0; j < len - 1 - i; j++) {
			if (array[j] > array[j + 1]) {
				int temp = array[j];
				array[j] = array[j + 1];
				array[j + 1] = temp;
			}
		}
	}

}

//select.cpp
#include "sort.h"
#include <iostream>

using namespace std;

void selectSort(int *array, int len) {

    for (int j = 0; j < len - 1; j++) {
		for (int i = j + 1; i < len; i++) {
			if (array[j] > array[i]) {
				int temp = array[j];
				array[j] = array[i];
				array[i] = temp;
			}
		}
	}

}

//sort.h
#ifndef SORT_H_
#define SORT_H_

void bubbleSort(int *array, int len);

void selectSort(int *array, int len);

#endif

//main.cpp
#include <iostream>
#include "sort.h"

using namespace std;

int main() {

    int array[] = {12, 27, 55, 22, 67};
    int len = sizeof(array) / sizeof(int);

    bubbleSort(array, len);
    
    // 遍历
    cout << "冒泡排序之后的数组: ";
    for(int i = 0; i < len; i++) {
        cout << array[i] << " ";
    }
    cout << endl;
    cout << "===================================" << endl;

    int array1[] = {25, 47, 36, 80, 11};
    len = sizeof(array1) / sizeof(int);
    
    selectSort(array1, len);
    
    // 遍历
    cout << "选择排序之后的数组: ";
    for(int i = 0; i < len; i++) {
        cout << array1[i] << " ";
    }
    cout << endl;

    return 0;
}

在这里插入图片描述
通过gcc编译器生成可执行文件main,记得带上编译选项-g。
在这里插入图片描述
通过list查看代码,通过break 行号打下断点,中断会显示断点的编号、地址、所在文件、所在行号。通过info break可以查看所有断点的信息,包括编号、类型、是否激活等信息。

5.GDB调试命令

#运行GDB程序
start(程序停在第一行)
run(遇到断点才停)

#继续运行,到下一个断点停
c/continue

#向下执行一行代码(不会进入函数体)
n/next

#变量操作
p/print 变量名(打印变量值)
ptype 变量名(打印变量类型)

#向下单步调试(遇到函数进入函数体)
s/step
finish(跳出函数体)

#自动变量操作
display num(自动打印指定变量的值)
i/info display
undisplay 编号

#其他操作
set var 变量名=变量值
until (跳出循环)

在这里插入图片描述
通过start命令让程序停在了第一行,也就是main函数。
在这里插入图片描述
通过c/continue命令,让程序继续运行,直到遇到下一个断点;如果没有设置断点,就直接程序运行到结束。
在这里插入图片描述
在11行打个断点,输入命令run,程序直接运行到断点处。
在这里插入图片描述
通过b 16在16行打下断点,16行是一个for循环内容。通过continue运行到第16行,进入循环体。通过print i可以查看变量i的值。

6. GDB多进程调试

使用GDB调试的时候,GDB默认只能跟踪一个进程,可以在fork函数之前,通过指令设置GDB调试工具跟踪父进程或子进程,默认是跟踪父进程,通过下述命令可以更改。

set follow-fork-mode parent	//默认情况
set follow-fork-mode child	//跟踪子进程
set detach-on-fork on
set detach-on-fork off

默认调试模式是on,表示调试当前进程时,其他的进程继续运行;如果是off,调试当前进程的时候其他进程被GDB挂起。

info inferiors //查看调试的进程
inferior id    //切换当前调试的进程
detach inferiors id  //使进程脱离GDB调试


Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐