官网:https://www.gnu.org/software/gdb/ Debugging with GDB:https://sourceware.org/gdb/current/onlinedocs/gdb/
简介
GDB, the GNU Project debugger, allows you to see what is going on `inside’ another program while it executes – or what another program was doing at the moment it crashed.
GDB的功能:
Start your program, specifying anything that might affect its behavior.
Make your program stop on specified conditions.
Examine what has happened, when your program has stopped.
Change things in your program, so you can experiment with correcting the effects of one bug and go on to learn about another.
启动gdb
启动gdb之前,需要编译出debug版本的程序,编译时加-g选项
$ gcc -g main.c
启动方法:
调试直接启动程序
调试一个正在运行的程序,attach
调试core文件
调试直接启动程序:
语法: gdb
$ gdb a.out
调试一个正在运行的程序,attach:
语法: gdb
$ gdb a.out 11127
调试core文件:
可以通过core文件调试程序来找到错误原因.比如跟踪常见的断错误
语法: gdb
$ gdb program core
通用
help
help <keyword>
tab键补全
Enter回车:执行上一条命令
大多命令都有简写
断点
设置断点:break/b
查看断点:info breakpoints
删除断点:delete
关闭或开启断点:disable/enable
disable <断点序列号>:关闭指定序列号的断点
enable <断点序列号>:开启指定序列号的断点
设置断点:break语法
* break <行号>
* break <文件名>:<行号>
* break <函数名>
* break <文件名>:<函数名>
(gdb) break 30 # 设置30行为断点
(gdb) break main.c:30 # 设置main.c的30行断点
(gdb) break main # 设置main函数为断点
(gdb) break main.c:main # 设置main.c文件的main函数为断点
查看断点
(gdb) info breakpoints
删除断点:delete语法
* delete <断点序列号>
* delete breakpoints
(gdb) delete 3 # 删除序列号为3的断点
(gdb) delete breakpoints # 删除所有断点
其它操作:disable/enable
* disable <断点序列号>:关闭指定序列号的断点
* enable <断点序列号>:开启指定序列号的断点
(gdb) disable 3
(gdb) enable 3
运行
run/r:运行程序,当遇到断点后,程序会在断点处停止运行,等待用户输入下一步的命令
next/n:单步跟踪程序,不会跳进去函数
nexti:单步跟踪程序(汇编)
continue/c:继续执行,到下一个断点处(或运行结束)
step/s:单步调试如果有函数调用,则进入函数
finish:运行程序,直到当前函数完成返回
call:调用程序中可见的函数
quit/q:退出
查看源代码
两种方式
list/l
list <行号>:默认显示10行代码信息
list <函数名>:以函数为中心,显示10行代码信息
list <文件名>:<函数名>:
show listsize:查看list命令显示的大小
set listsize:设置list命令显示的大小
layout(src源代码/asm汇编/regs寄存器/分屏)
layout src:源代码
layout asm:汇编
layout regs:寄存器
layout prev:上一种布局
layout next:下一种布局
refresh/Ctrl+L:刷新(屏幕出现花屏时使用)
信息查看显示
print/p:打印一个变量,取地址,表达式,函数
backtrace full:打印栈里的所有局部变量
display:类似print,每次单步调试都会输出
undisplay:取消display的设置
watch:监控变量,当变量变化时输出(删除watch使用delete命令)
whatis:查询变量或函数信息
info:查看相关信息
info breakpoints:查看断点设置
info display:查看display设置
info watchpoints:查看watch设置
print语法: print
* print <变量>
* print <变量取地址>
* print <表达式>
* print <函数调用>
(gdb) print a # 变量值
(gdb) print &a # 取地址
(gdb) print a++ # 表达式
(gdb) print random_range(10, 20) # 函数调用
print 数组
* print <数据变量名>
* print <数据变量名[index]@lenght>
(gdb) print array # 打印数组
(gdb) print array[5]@10 # 从第五个元素开始,打印10个元素
调试core文件
core文件:核心文件通常在系统收到特定的信号时由操作系统生成. 信号可以由程序执行过程中的异常触发,也可以由外部程序发送. 动作的结果一般是生成一个某个进程的内存转储的文件,文件包含了此进程当前的运行堆栈信息.
系统默认不会产生core文件,默认core文件大小为0,需要设置ulimit -c unlimited
$ ulimit -a # 查看一个进程启动时的资源限制参数
$ ulimit -c unlimited # 设置core文件大小不设限制
$ gdb a.out core
(gdb) backtrace full
多线程调试
todo…
远程调试
如果远程和本地两台机架构相同:远程使用gdbserver,本地使用gdb 如果远程和本地两台机架构不同:远程使用gdbserver,本地使用gdb-multiarch
远程
$ gdbserver :12345 a.out
本地
$ gdb
(gdb) target remote 127.0.0.1:post # 连接远程gdbserver
(gdb) break main # 设置main函数断点
(gdb) continue # 开始调试
(gdb) next # 单步调试
(gdb) monitor exit # 关闭远程gdbserver
演示
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
int random_range(int min_num, int max_num) {
if (min_num > max_num) {
exit(EXIT_FAILURE);
}
int ret = 1 + rand() % (max_num - min_num) + min_num;
return ret;
}
int main(int argc, char* argv[]) {
int* nil = NULL;
srand(time(NULL));
int ret = 0;
for (int i = 0; i < 200; i++) {
ret = random_range(-100, 100);
if (ret == 13) {
printf(“zhong jiang\n”);
memcpy(nil, &ret, sizeof(nil)); // segmentation fault
}
printf(“ret = %d\n”, ret);
usleep(10000);
}
return 0;
}
Refrences: https://wizardforcel.gitbooks.io/100-gdb-tips/content/index.html https://linuxtools-rst.readthedocs.io/zh_CN/latest/tool/gdb.html