一、安装与卸载
1.1 安装
sudo apt-get install gdb
1.2 卸载
sudo rpm -qa | grep gdb
1.3 其他
// centOS系统
yum -y intall gdb
yum -y remove gdb
// 在 gdb 下使用 wi 启动可视化调试(图形界面都是用字符显示的)
(gdb) wi
二、调试前的准备
程序被调试,编译需要加”-g“参数。
一些常用调试参数:
命令 | 命令缩写 | 命令说明 |
set args | 设置主程序的参数。 例如:./book119 /oracle/c/book1.c /tmp/book1.c 设置参数的方法是: gdb book119 (gdb) set args /oracle/c/book1.c /tmp/book1.c | |
break | b | 设置断点,b 20 表示在第20行设置断点,可以设置多个断点。 |
run | r | 开始运行程序, 程序运行到断点的位置会停下来,如果没有遇到断点,程序一直运行下去。 |
next | n | 执行当前行语句,如果该语句为函数调用,不会进入函数内部执行。 |
step | s | 执行当前行语句,如果该语句为函数调用,则进入函数执行其中的第一条语句。 注意了,如果函数是库函数或第三方提供的函数,用s也是进不去的,因为没有源代码,如果是您自定义的函数,只要有源码就可以进去。 |
| p | 显示变量值,例如:p name表示显示变量name的值。 |
continue | c | 继续程序的运行,直到遇到下一个断点。 |
set var name=value | 设置变量的值,假设程序有两个变量:int ii; char name[21]; set var ii=10 把ii的值设置为10; set var name="西施" 把name的值设置为"西施",注意,不是strcpy。 | |
quit | q | 退出gdb环境。 |
until | u | 当你厌倦了在一个循环体内单步跟踪时,单纯使用 until 命令,可以运行程序直到退出循环体。 until n 命令中,n 为某一行代码的行号,该命令会使程序运行至第 n 行代码处停止。 |
list | l | 显示源程序代码的内容,包括各行代码所在的行号。 |
finish | fi | 结束当前正在执行的函数,并在跳出函数后暂停程序的执行。 |
return | 结束当前调用函数并返回指定值,到上一层函数调用处停止程序执行。 | |
jump | j | 使程序从当前要执行的代码处,直接跳转到指定位置处继续执行后续的代码。 |
clear | 删除指定位置处的断点,常用的语法格式如下所示:clear location | |
backtrace | bt | 查看函数调用信息(堆栈),注意是从下往上看。 |
部分命令参数详解:博客1
三、调试core文件
有时候,服务器程序运行一段时间后会突然崩溃,在复现当时场景比较难,但又需要解决这个问题。这个时候只要程序在崩溃的时候有 core 文件产生,就可以使用这个 core 文件来定位崩溃的原因。core文件是一个内存映像,同时加上调试信息。
一般调试方法如下:
- 运行某段代码出现段错误出现后,再运行ulimit -a查看core file size的默认参数;
- 运行ulimit -c unlimited命令,设置成无限制(该命令是临时开启的);
- 运行出错的程序;
- 使用ls命令查看core文件,比如会出现core.19356;
- 使用gdb调试程序,命令如:gdb testDemo core.19356;testDemo是程序名;
- 如果没有问题则会输出程序出错的位置及代码;
- 当然也可以用bt查看堆栈信息,也可以定位到出错位置;
上述操作是临时的,可以将ulimit -c unlimited命令写入到/etc/profile 中,步骤如下:
- 将ulimit -c unlimited 放入/etc/profile;
- source /etc/profile;
- 再次查看 ulimit -a;
四、调试正在运行的程序
需要知道正在运行程序的ID,执行如下命令:
ps -ef|grep testDemo
其中testDemo是程序的名字,执行上述命令后,会输出如下内容:
UID PID PPID C STIME TTY TIME CMD
它们的含义如下:
- UID: 程序被该 UID 所拥有
- PID :就是这个程序的 ID(我们需要的,我们假设ID为666)
- PPID :则是其上级父程序的ID
- C: CPU 使用的资源百分比
- STIME :系统启动时间
- TTY: 登入者的终端机位置
- TIME: 使用掉的 CPU 时间
- CMD :所下达的指令为何
获取程序的ID后,执行gdb testDemo -p 666即可进入程序,此时正在运行的程序会暂停,退出调试又会继续运行。
五、使用log辅助调试
设置断点或者单步跟踪可能会严重干扰多进程(多线程)之间的竞争状态。导致调试时看的不是真实场景。所以使用log方式可以避免上述的问题。这里需要输出log的代码。不同的类有不同方法,不具体举例。