基于GDB的程序调试

基于GDB的程序调试

程序调试工具GDB

编译器GCC,项目构建工具Make(又称gmake),以及GDB。

image-20230224165344672

GDB是什么?

GDB:GNU symbolic debugger是Linux下常用的程序调试器

GDB可以做什么?

image-20230224165606636

GDB官网:GDB: The GNU Project Debugger (sourceware.org)

调试案例一

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>
int main()
{
unsigned long long int n,sum;
n = 1;
sum = 0;
while( n <= 100)
{
sum = sum + n;
n = n + 1;
}
return 0;
}

在编译程序的时候,需要加调试选项: -g

1
gcc gdb001.c -g -o ex1

使用gdb启动程序:

1
gdb ./ex1

进入gdb调试环境

image-20230224170419171

在调试环境中:使用l选项会显示带行号的源代码

image-20230224170620617

但是默认情况下,l选项只显示10行源代码,如果查看后续代码,在调试界面Enter回车即可

image-20230224170804048

在第7行源代码处打断点:

image-20230224171858691

运行程序,遇到断点停止:

image-20230224172105514

查看代码中变量n的值

image-20230224172200662

当前n的值为1,$1表示该变量所在存储区的名称

在程序第12行处打断点

image-20230224172321002

继续执行程序

image-20230224172356622

查看当前n变量的值

image-20230224172422998

当前n的值为101

退出调试

image-20230224172456626

查看调试环境所有断点:

image-20230224172650422

删除第7行的断点:

image-20230224172745323

禁用编号为2的断点:

image-20230224172832507

注意断点状态Enb(enable)由y变成n,代表禁用

恢复编号为2的断点:

image-20230224173006975

小结

GDB有三种调试模式:

调试执行程序:(前面的案例),注意编译加调试信息(-g)

调试core文件 :需要对系统设置的core文件大小作调整(ulimit - c unlimlited),否则可能无法 产生core文件

调试正在执行的程序(gdb attach) :Top找到进程编号pid,Gdb attach pid

GDB结构组成:

image-20230224173613247

常用调试指令:

启动指令

调试程序:gdb program

根据core文件调试程序:gdb program corefile

跟踪调试进程:gdb attach pid

程序运行

run,该命令会运行至程序结束,除非遇到断点或报错

单步执行

步进执行不进栈?next

步进执行,进栈step

代码查看

列出断点附近或程序所有代码list

设置现实代码的行数 set listsize <n>

退出调试

quit

查看栈信息

bt 打印当前的函数调用栈的所有信息

bt <n> n是一个正整数,表示只打印栈顶上n层的栈信息

bt <-n> 表示只打印栈底下n层的栈信息

设置断点

代码断点:

  • break lineNumber | functionName
  • break lineNumber | functionName if condition
  • tbreak lineNumber | functionName 临时断点,仅能使用一次

内存断点(观察点):

  • 监控内存值改变 watch expr [if condition]
  • 监控内存值被读取 rwatch expr [if condition]
  • 监控内存值被读取和写入 awatch wxpr [if condition]

事件断点:

  • C++ exception,使用catch exception [name]
  • Ada exception,使用catch handlers [name]
  • exec事件,使用catch exec
  • fork事件,使用catch fork 或者 catch vfork
  • 加载和卸载动态so事件,使用catch load|unload [regexp]
  • 监听系统信号,使用catch signal [signal]
  • 监听系统调用,使用catch syscall[name|number|group:groupname|g:groupname]…

打印变量:

  • Print [file | func]::variable 查看局部变量或全局变量
  • Print *array@len 数组首地址@查看长度
  • x/[n | u] <addr> x命令查看内存地址钟的值,n:表示显示内存的长度,u:表示从当前地址往后请求的字节数

打印寄存器:

info register 查看寄存器(除了浮点寄存器)

all-registers 查看所有寄存器

info registers <reg_name …>查看所指定寄存器

参考资料

来源培训PPT 作者:Relax 邮箱:wangw111@icloud.com