Linux gdb调试
一丶GDB
1.1 简介
GDB是一个在UNIX(LINUX)环境下的命令行调试工具。如果调试C/C++程序可以在gcc/g++
编译生成的时候加上-g选项。
二丶命令介绍
2.1 GDB调试程序
2.1.1 GDB调试
GDB调试一个程序有多种方法
首先可以使用命令生成调试文件。然后看下表所示来进行调试。
命令:
gcc -m32 -g main.cpp -o main.out
GDB命令表
命令 | 说明 |
---|---|
gdb |
指定你要调试的程序的文件名直接开始调试 |
gdb |
用gdb同时调试一个运行程序和一个core文件。core文件就是程序非法执行后的coredump后产生的文件。记录了程序在出错的时候的一些内存环境和出错信息。 可以理解为windows平台上的dump文件 |
gdb |
如果你的程序是一个服务程序,那么可以制定这个服务程序运行时的进程id. gdb则会自动attach上去,并且调试他。 program应能在环境变量PATH中搜索得到。 |
2.1.2 GDB启动时候的参数
gdb命令在启动的时候可以附加一些参数,这些参数也称为GDB的启动开关。
如果想看详细的开关可以用gdb-help查看。
下面列举一下常见的参数
参数 | 作用 |
---|---|
-symbols |
一个是全名称,一个是缩写。 代表的意思是从指定文件中读取符号表. |
-se file | 从指定文件中读取符号表信息,并把它用在可执行文件中。 |
-core |
调试core dump的core文件 |
-directory |
加入一个源文件的搜索路径。默认搜索路径是PATH环境中所能搜索到的路径。 |
提示:
GDB支持全名和缩写。所以在使用的时候任选其一即可。
2.1.3 GDB的基本命令
直接做成表
命令 | 作用 |
---|---|
l | 不是一 也不是 ai(i) 是L ,作用是查看源码,源码会进行行号提示。如果要查看的函数是其他文件中定义的函数,那么在l后面加上函数名即可定位到这个函数的定义,以及查看附近的其他源码,或者使用断点 或者单步执行,到了某个函数处使用s进入这个函数也可以。 |
b | b指令设置断点: b 6 在源码的第六行下断点。 这个行号是gdb的行号 |
info b | info b 可以查看断点列表。 |
r | 运行代码 |
p | p是打印变量名,但是你需要在程序暂停的时候使用。例如有个n变量。 可以 p n 来查看n的值。 GDB在显示变量值的时候都会在对应值前面加上$N标记,它是当前变量值的引用标记,当你想再次使用的时候可以直接写作 “$N”,而无需写冗长的变量名。 |
watch | watch查看某一个变量的变化情况,一般用于循环的时候使用。 watch n |
n | 单步执行 |
c | 程序继续运行,直到遇到断点或者程序结束。 |
q | 退出gdb |
2.1.4 GDB中的断点调试
命令格式 | 例子 | 作用 |
---|---|---|
break + 设置断点的行号 | break n | 在n行处设置断点 |
tbreak + 行号或函数名 | tbreak n/func | 设置临时断点,到达后被自动删除 |
break + filename + 行号 | break main.c:10 | 用于在指定文件对应行设置断点 |
break + <0x...> | break 0x3400a | 用于在内存某一位置处暂停 |
break + 行号 + if + 条件 | break 10 if i==3 | 用于设置条件断点,在循环中使用非常方便 |
info breakpoints/watchpoints [n] | info break | n表示断点号,查看断点/观察点的情况 |
clear + 要清除的断点行号 | clear 10 | 用于清除对应行的断点,要给出断点的行号,清除时GDB会给出提示 |
delete + 要清除的断点编号 | delete 3 | 用于清除断点和自动显示的表达式的命令,要给出断点的编号,清除时GDB不会给出任何提示 |
disable/enable + 断点编号 | disable 3 | 让所设断点暂时失效/使能,如果要让多个编号处的断点失效/使能,可将编号之间用空格隔开 |
awatch/watch + 变量 | awatch/watch i | 设置一个观察点,当变量被读出或写入时程序被暂停 |
rwatch + 变量 | rwatch i | 设置一个观察点,当变量被读出时,程序被暂停 |
catch | 设置捕捉点来补捉程序运行时的一些事件。如:载入共享库(动态链接库)或是C++的异常 | |
tcatch | 只设置一次捕捉点,当程序停住以后,应点被自动删除 |
2.1.5 数据操作命令
命令格式 | 例子 | 作用 |
---|---|---|
display +表达式 | display a | 用于显示表达式的值,每当程序运行到断点处都会显示表达式的值 |
info display | 用于显示当前所有要显示值的表达式的情况 | |
delete + display 编号 | delete 3 | 用于删除一个要显示值的表达式,被删除的表达式将不被显示 |
disable/enable + display 编号 | disable/enable 3 | 使一个要显示值的表达式暂时失效/使能 |
undisplay + display 编号 | undisplay 3 | 用于结束某个表达式值的显示 |
whatis + 变量 | whatis i | 显示某个表达式的数据类型 |
print(p) + 变量/表达式 | p n | 用于打印变量或表达式的值 |
set + 变量 = 变量值 | set i = 3 | 改变程序中某个变量的值 |
补充:
在使用print命令时,可以对变量按指定格式进行输出,其命令格式为print /变量名 + 格式
其中常用的变量格式:x:十六进制;d:十进制;u:无符号数;o:八进制;c:字符格式;f:浮点数。
2.1.6 调试运行环境相关命令
命令格式 | 例子 | 作用 |
---|---|---|
set args | set args arg1 arg2 | 设置运行参数 |
show args | show args | 查看运行参数 |
set width + 数目 | set width 70 | 设置GDB的行宽 |
cd + 工作目录 | cd ../ | 切换工作目录 |
run | r/run | 程序开始执行 |
step(s) | s | 进入式(会进入到所调用的子函数中)单步执行,进入函数的前提是,此函数被编译有debug信息 |
next(n) | n | 非进入式(不会进入到所调用的子函数中)单步执行 |
finish | finish | 一直运行到函数返回并打印函数返回时的堆栈地址和返回值及参数值等信息 |
until + 行数 | u 3 | 运行到函数某一行 |
continue(c) | c | 执行到下一个断点或程序结束 |
return <返回值> | return 5 | 改变程序流程,直接结束当前函数,并将指定值返回 |
call + 函数 | call func | 在当前位置执行所要运行的函数 |
2.1.7 堆栈相关命令
更多操作命令格式 | 例子 | 作用 |
---|---|---|
backtrace/bt | bt | 用来打印栈帧指针,也可以在该命令后加上要打印的栈帧指针的个数,查看程序执行到此时,是经过哪些函数呼叫的程序,程序“调用堆栈”是当前函数之前的所有已调用函数的列表(包括当前函数)。每个函数及其变量都被分配了一个“帧”,最近调用的函数在 0 号帧中(“底部”帧) |
frame | frame 1 | 用于打印指定栈帧 |
info reg | info reg | 查看寄存器使用情况 |
info stack | info stack | 查看堆栈使用情况 |
up/down | up/down | 跳到上一层/下一层函数 |
2.1.8 跳转执行指令
跳转执行指令就一个jump 此指令可以指定下一条语句的运行点。也可以是文件的行号。
也可以是 file:line 格式。 也可以是+offset偏移的格式。 如果在ARM汇编中其实就是修改了PC寄存器的指向值。 如果在INTER X86平台中就是修改了IP的指向(EIP/RIP)