GDB学习指北

GDB学习

本篇文章是GDB debugging tutorial for beginners学习实践记录,若内容有误,恳请指正!

本篇文章需要Linux 环境

### 安装gdb build-essential gcc

​ 如果没有相应软件 可以执行一下命令(Ubuntu)

1
hsudo apt install gdb build-essential gcc

验证安装

1
gdb --version && gcc --version
image-20250304195501513

编译文件

比如我们可以编写一个c程序,命名为test.c,代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int actual_calc(int a, int b){
int c;
c=a/b;
return 0;
}

int calc(){
int a;
int b;
a=13;
b=0;
actual_calc(a, b);
return 0;
}

int main(){
calc();
return 0;
}

使用gcc编译

  • 使用 -ggdb 生成调试符号在可执行文件中,以便调试

  • 使用 -O0(一般为默认)

    禁用优化,确保调试信息与代码行号对齐

1
gcc -ggdb test.c -o test.out 

编译后执行

会出现 Floating point exception (core dumped) 提示,但是此时我们在目录下面并找不到 core文件

image-20250304190415308

生成/core文件

用bash执行/修改文件使系统生成 Core Dump

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 设置核心转储文件名格式
if ! grep -qi 'kernel.core_pattern' /etc/sysctl.conf; then
sudo sh -c 'echo "kernel.core_pattern=core.%p.%u.%s.%e.%t" >> /etc/sysctl.conf'
sudo sysctl -p
fi

# 解除核心转储大小限制(临时,仅对当前终端会话有效)
ulimit -c unlimited

# 永久生效(编辑limits.conf,后需 重新登录用户 或 重启系统 生效)
sudo bash -c "cat << EOF > /etc/security/limits.conf
* soft core unlimited
* hard core unlimited
EOF

我们可以通过以下命令来检查

1
2
3
cat /etc/security/limits.conf

cat /etc/sysctl.conf

能在输出结果中发现

image-20250304191212816 image-20250304191415560

说明修改成功

在程序运行错误时,会在程序目录生成Core Dump文件

image-20250304191559121

file 指令

1
2
$ file core.18763.1000.8.test.out.1741086940 
core.18763.1000.8.test.out.1741086940: ELF 64-bit LSB core file, x86-64, version 1 (SYSV), SVR4-style, from './test.out', real uid: 1000, effective uid: 1000, real gid: 1000, effective gid: 1000, execfn: './test.out', platform: 'x86_64'

通过file指令 我们可以看到,这是一个64位核心转储文件,它显示了当时使用的用户ID、平台信息,以及最后使用的可执行文件。我们还可以从文件名(.8.)中看出,是一个信号8终止了程序。信号8是SIGFPE,即浮点异常。

信号8对应 SIGFPE(浮点异常),通常由除以零或整数溢出触发

GDB 基本操作

进入gdb模式

1
$ gdb ./程序文件 CoreDump文件

输出

1
2
#0  0x0000599ac055c13b in actual_calc (a=13, b=0) at test.c:3
3 c=a/b;

我们可以看到是 c=a/b; 这个代码发生了错误,因为0不能作为分母

bt

  • backtrace

  • 输出结果是程序运行函数调用的倒叙

    image-20250304193623181

f

  • 后面接帧的深度(如 f0f1

  • 注:在递归调用中,同一个函数会生成多个栈帧,每个栈帧保存了不同调用层次的变量值

image-20250304193707490

p

  • 切换到对应的栈帧后

  • 使用 p 变量名称 查看变量具体值

    image-20250304193804314

    切换到对应的栈帧 我们便能输出变量。

    要注意 我们切换到 f 2(main函数)时,没有定义 a b变量,所以无法输出

    变量的可见性由其作用域决定,跨帧访问需确保变量在对应函数中定义

list

  • 查看对应帧附近源码

    image-20250304193957291

quit

  • 退出gdb

注意事项

  • GDB不会检查core文件和源码的对应关系,需确保调试时的代码版本与生成Core Dump时的版本一致,如果不是使用源码,可能会导致指向错误,误导debug

    可使用版本控制工具(如Git)标记代码版本,确保调试时签出与Core Dump对应的提交

引用资料

GDB debugging tutorial for beginners