GDB概述

GDB组成架构

img

基本工作原理

gdb 通过系统调用 ptrace 来接管一个进程的执行。ptrace 系统调用提供了一种方法使得父进程可以观察和控制其它进程的执行,检查和改变其核心映像以及寄存器。它主要用来实现断点调试和系统调用跟踪。

三种调试方式

​ 直接运行并调试一个新进程

​ 运行并调试一个新进程

​ 运行 gdb,通过命令行或 file 命令指定目标程序。

​ 输入run命令, gdb 执行下面的操作:

​ 通过 fork() 系统调用创建一个新进程

​ 在新创建的子进程中执行操作:ptrace(PTRACE_TRACEME, 0, 0, 0)

​ 在子进程中通过 execv() 系统调用加载用户指定的可执行文件

​ attach并调试一个已经运行的进程

​ 用户确定需要进行调试的进程 PID

​ 运行 gdb,输入 attach <pid>,gdb 将对指定进程执行操作:ptrace(PTRACE_ATTACH, pid, 0, 0)

​ 远程调试目标机上新创建的进程

​ gdb 运行在调试机上,gdbserver 运行在目标机上,两者之间的通信数据格式由 gdb 远程串行协议(Remote Serial Protocol)定义

​ RSP 协议数据的基本格式为: $..........#xx

​ gdbserver 的启动方式相当于运行并调试一个新创建的进程

使用GDB前的准备

编译

​ 一般关闭-o优化选项

​ 打开-g调试选项

​ -Wall打开所有warning

GDB启动/退出/查看代码命令

启动退出

​ gdb 可执行文件 —启动调试

​ quit/ctrl+d —退出

设置参数/获取设置参数

​ set args 10 20

​ show args

GDB使用帮助

​ help

查看当前文件代码

​ list/l —从默认位置显示

​ list/l <行号> —从制定的行显示

​ list/l <函数名> —从指定的函数开始显示

​ disassemble/disas —反汇编命令

disas <func> 反汇编指定函数

disas <addr> 反汇编某地址所在函数

disas <begin_addr> <end_addr> 反汇编从开始地址到结束地址的部分

查看非当前文件代码

​ list/l <文件名:行号>

​ list/l <文件名:函数名>

设置显示的行数

​ show list/listsize

​ set list/listsize <行数>

其他

​ pwd —显示工作目录

​ shell —不离开gdb就能运行shell命令

​ directory/dir —设置查找源文件的路径(或者gdb的-d参数)

GDB断点命令

设置断点

​ b/break <行号>

​ b/break <函数名>

​ b/break <文件名:行号>

​ b/break <文件名:函数名>


​ tbreak —临时断点,如同break,只不过在一次命中后被删除

查看断点

​ i/info b/break

删除断点

​ d/del/delete 断点编号

设置断点无效

​ dis/disable 断点编号

设置断点生效

​ ena/enable 断点编号

设置条件断点

​ b/break 10 if i==5

GDB调试运行命令

运行GDB

​ start —停止于第一行

​ run —运行到下一个断点

继续运行到下一个断点

​ c/continue

向下执行一段代码(不会进入函数体)

​ n/next

向下单步调试(遇到函数步进)

​ s/step —步进

​ finish —运行直至跳出函数体

反向步进程序

​ reverse-step [n] —反向步进程序,直到到达另一个源码行的开头,n表示执行n次,或某种原因程序停止

变量操作

​ p/print 变量名 —打印值

​ ptype 变量名 —打印类型

自动变量操作

​ display num —自动打印指定变量的值

​ undisplay —取消…

​ i/info display

​ undisplay 编号

其他操作

​ until —跳出循环

​ until <行号> —在函数内,进行指定位置跳转,执行完区间代码

表达式监视/修改命令

print <表达式> —对任意正确的表达式进行求值并打印

display <表达式> —每次单步进行指令后,紧接着输出被设置的表达式及值(单步运行非常有用)

watch <表达式> —设置一个监视点,一旦被监视的"表达式"的值改变,gdb将强行终止正在被调试的程序

​ 另外 rwatch 表示在访问时停止,awatch 表示在访问和改变时都停止

whatis —查询变量或函数

info <函数> —查询函数

info locals —查看当前堆栈页所有的变量

set var 变量名=变量值 —修改变量的值

特殊执行命令

运行代码

​ call 函数(参数) —调用和执行函数

​ return —取消函数调用的执行,expression被当做函数的返回值

生成代码

​ make —不退出gdb就能重新产生可执行文件

内存查看命令

命令 子选项 解释
x x/3 内存地址 需要显示的内存单元的个数,也就是说从当前地址向后显示几个内存单元的内容,一个内存单元的大小由后面的u定义
x/f 内存地址 f 表示显示的格式 : x 按十六进制格式显示变量。 d 按十进制格式显示变量。 u 按十进制格式显示无符号整型。 o 按八进制格式显示变量。 t 按二进制格式显示变量。 a 按十六进制格式显示变量。 i 指令地址格式 c 按字符格式显示变量。 f 按浮点数格式显示变量。
x/u 内存地址 u表示一个地址单元的长度 b表示单字节, h表示双字节, w表示四字节, g表示八字节
举例 x /3dw 内存地址 打印3个四字节,按照10进制格式打印(即将上面各个部分组合起来)

例如:

image-20230729165808207

这里打印了str[0]~str[15]的所有值(以16进制)

另外,使用 $ida(“xxx”)可以通过IDA名称获取地址,例如 $ida(“main”) (?)

堆栈和寄存器处理命令

bt —查看当前函数调用栈,即当前函数调用的上一层函数以及它们的调用栈信息

up/down n —在堆栈中向上/向下移动n层

frame n —切换到第n层堆栈

info相关的命令

​ info frame —查看当前堆栈帧的信息,包括函数名、参数、返回地址等

​ info args —查看当前函数的参数信息

​ info locals —查看当前函数的局部变量信息

​ info registers —查看所有寄存器的信息

print /x $reg —以16进制格式查看指定寄存器reg的值

set $reg = value —设置指定寄存器reg的值为value

查询运行状态命令

where/bt —当前运行的堆栈列表(?)/查看程序出错原因

bt backtrace —显示当前调用堆栈

up/down —改变堆栈显示的深度

info program —查看程序的是否在运行,进程号,被暂停的原因

注意

1.GDB不会自动在程序入口点暂停,所以需要在执行前设置好断点

部分转载于: