从零开始学GDB

启动gdb后,可以进入到交互模式,通过以下命令对程序完成调试工作!

g++ -g -std=c++11 main.cpp gdb a.out

运行指令

指令 说明
run(简写r) 运行程序,当遇到断点后,程序会在断点处停止运行,等待用户输入下一步命令
continue(简写c) 继续执行,到下一个断点停止(或运行结束)
next(简写n) 单步跟踪程序,当遇到函数调用时,也不进入此函数体;此命令同 step 的主要区别是,step 遇到用户自定义的函数,将步进到函数中去运行,而 next 则直接调用函数,不会进入到函数体内。
step(简写s) 单步调试如果有函数调用,则进入函数;与命令n不同,n是不进入调用的函数的
until(简写u) 当你厌倦了在一个循环体内单步跟踪时,这个命令可以运行程序直到退出循环体。
until+行号 运行至某行,不仅仅用来跳出循环
finish 运行程序,直到当前函数完成返回,并打印函数返回时的堆栈地址和返回值及参数值等信息。
call函数(参数) 调用程序中可见的函数,并传递“参数”,如:call gdb_test(55)
quit(简写q) 退出gdb

带参运行

进入调试之前可以 gdb --args ./grogram arg1 arg2

进入调试之后可以两种方式添加参数

1)run arg1 arg2

2)set args arg1 arg2

设置断点

指令 说明
break n (简写b n) 在第n行处设置断点(可以带上代码路径和代码名称: b OAGUPDATE.cpp:578)
break func(break缩写为b) 在函数func()的入口处设置断点,如:break cb_button
b fn1 if a>b 条件断点设置
b *0x12345678 内存地址下断(代码段地址)
delete 断点号n 删除第n个断点
disable 断点号n 暂停第n个断点
enable 断点号n 开启第n个断点
clear 行号n 清除第n行的断点
info b (info breakpoints) 示当前程序的断点设置情况
delete breakpoints 清除所有断点:
watch *(int*)0x22cbc0 监视内存地址写操作

查看内存

x/20xb 0x7ffff7ff6000

第一个X表示查看内存的命令
20表示显示20字节
x表示按十六进制格式显示
b表示单字节

查看栈 x/20 $sp

查看格式 说明
x 按十六进制格式显示变量。
d 按十进制格式显示变量。
u 按十六进制格式显示无符号整型。
o 按八进制格式显示变量。
t 按二进制格式显示变量。
a 按十六进制格式显示变量。
c 按字符格式显示变量。
f 按浮点数格式显示变量
数据长度 说明
b 表示单字节
h 表示双字节
w 表示四字节
g 表示八字节

查看汇编

指令 说明
disas/disass 查看汇编代码
display /i $pc 单步调试显示汇编指令
set disassemble-flavor intel 切换intel格式
set disassemble-flavor att 切换att格式
layout asm 可视化汇编调试
continue(c) 放行
s 代码级步入
n 代码级步过
si 汇编级步入
ni 汇编级步过
i reg 查看所有寄存器
i reg rax 查看rax寄存器
display \(rax|监视rax| |p (char*)\)eax 查看字符串

正确的命令是:

sudo echo "set disassembly-flavor intel"> ~/.gdbinit

GDB 在启动的时候会按一定的路径顺序(通常是先当前目录而后用户目录)寻找 .gdbinit 文件,一旦找到,就会自动执行里面的命令。这个功能允许用户把常用的一些命令放在这个文件里,这样就不用每次进入 gdb 后再去手动执行这些命令。事实上,.gdbinit 就是一个脚本,甚至可在里面把常用的若干 gdb命令序列定义成一个新命令,这样只要在 gdb 里面输入这个新命令就等于自动执行了被定义的那个命令序列。

查看源代码

list 简记为 l ,其作用就是列出程序的源代码,默认每次显示10行。 list行号 将显示当前文件以“行号”为中心的前后10行代码,如:list 12 list函数名 将显示“函数名”所在函数的源代码,如:list main list不带参数 将接着上一次 list 命令的,输出下边的内容。

打印表达式

指令 说明
print 表达式(简记p) 其中“表达式”可以是任何当前正在被测试程序的有效表达式,比如当前正在调试C语言的程序,那么“表达式”可以是任何C语言的有效表达式,包括数字,变量甚至是函数调用。
print a 将显示整数 a 的值
print ++a 将把 a 中的值加1,并显示出来
print name 将显示字符串 name 的值
print gdb_test(22) 将以整数22作为参数调用 gdb_test() 函数
print gdb_test(a) 将以变量 a 作为参数调用 gdb_test() 函数
display 表达式 在单步运行时将非常有用,使用display命令设置一个表达式后,它将在每次单步进行指令后,紧接着输出被设置的表达式及值。如: display a
watch 表达式 设置一个监视点,一旦被监视的“表达式”的值改变,gdb将强行终止正在被调试的程序。如: watch a
whatis 查询变量或函数
info function 查询函数
扩展info locals 显示当前堆栈页的所有变量

實時顯示表達式

和 print 命令一样,display 命令也用于调试阶段查看某个变量或表达式的值,它们的区别是,使用 display 命令查看变量或表达式的值,每当程序暂停执行(例如单步执行)时,GDB 调试器都会自动帮我们打印出来,而 print 命令则不会。

也就是说,使用 1 次 print 命令只能查看 1 次某个变量或表达式的值,而同样使用 1 次 display 命令,每次程序暂停执行时都会自动打印出目标变量或表达式的值。因此,当我们想频繁查看某个变量或表达式的值从而观察它的变化情况时,使用 display 命令可以一劳永逸。

(gdb) display expr
(gdb) display/fmt expr
display/fmt $rax
/fmt 功 能
/x 以十六进制的形式打印出整数。
/d 以有符号、十进制的形式打印出整数。
/u 以无符号、十进制的形式打印出整数。
/o 以八进制的形式打印出整数。
/t 以二进制的形式打印出整数。
/f 以浮点数的形式打印变量或表达式的值。
/c 以字符形式打印变量或表达式的值。

查询运行信息

指令 说明
where/bt 当前运行的堆栈列表;
bt backtrace 显示当前调用堆栈
up/down 改变堆栈显示的深度
set args 参数 指定运行时的参数
show args 查看设置好的参数
info program 来查看程序的是否在运行,进程号,被暂停的原因。