Linux下gdb调试
一、Part1
1.1 测试代码
#include <stdio.h>
int g_var = 0;
int add(int a, int b) {
printf("add callad, a: %d, b: %d \n", a, b);
return a + b;
}
int main(int argc, char *argv[]) {
int n = 1;
printf("one n = %d, g_var = %d\n", n, g_var);
++n;
--n;
g_var += 20;
g_var -= 10;
n = add(1, g_var);
printf("two n = %d, g_var = %d\n", n, g_var);
return 0;
}
编译
gcc gdb_test.c -o test
,这里生成与一个test可执行文件
运行它./test
,可以得到下面的结果
1.2 使用gdb
像上面那样,我们没有办法看到中间变量,除非去在代码内逐个逐个地去print出来,于是我们使用gdb
1)编译
如果需要使用gdb调试,需添加-g选项去编译程序
gcc -g -Wall gdb_test.c -o test
这里的-Wall表示不显示任何警告
2)进入gdb模式和查看源码
在编译之后会得到一个可执行文件test,
使用gdb加载可执行文件test:gdb test
这样,就进入了gdb模式
在gdb模式下,使用命令l可以加载源码内容,同时还显示了行号
3)加断点
使用命令b,这里使用的模式有
① 在相应的函数处加断点:b 函数名
② 在指定的行号处加断点:b 行号
4)运行和打印变量
使用命令r,让调试的程序开始运行
可以看到,程序在第一个断点的地方停了下来
使用命令n进入过程调试,跳到下一个断点,不管中间过程
此时,变量n的值应当是1,可以使用命令p 变量名
查看
5)退出gdb模式
使用命令q,退出gdb模式
二、Part2
2.1 测试代码
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
/*
* arr 只能是数组
* 返回当前数组长度
*/
#define LEN(arr) (sizeof(arr)/sizeof(*arr))
// 简单数组打印函数
static void _parrs(int a[], int len) {
int i = -1;
puts("当前数组内容值如下:");
while(++i < len)
printf("%d ", a[i]);
putchar('\n');
}
// 简单包装宏, arr必须是数组
#define PARRS(arr) \
_parrs(arr, LEN(arr))
#define _INT_OLD (23)
/*
* 主函数,简单测试
* 测试 core文件,
* 测试 宏调试
* 测试 堆栈内存信息
*/
int main(void) {
int i;
int a[_INT_OLD];
int* ptr = NULL;
// 来个随机数填充值吧
srand((unsigned)time(NULL));
for(i=0; i<LEN(a); ++i)
a[i] = rand()%222;
PARRS(a);
//全员加double, 包含一个错误方便测试
for(i=1; i<=LEN(a); ++i)
a[i] <<= 1;
PARRS(a);
// 为了错,强制错
*ptr = 0;
return 0;
}
1)编译并进入gdb模式
gcc -g -Wall gdb_test.c -o test
gdb test
2)执行它
r
发现程序出现了段错误
3)开始调试
这里首先在43行处设一断点,并执行程序
这里数组a已经有值了,可以print a
查看堆栈信息
由于此时已经到了子函数调用处,于是在13行处设一个断点
b 13
再使用命令n过程调试,进入子函数
使用命令
info args
,可以查看当前函数的参数值
这里a就是形参数组的地址
使用命令
info locals
,可以查看当前函数栈上值信息
使用命令info registers
,可以查看寄存器值
查看内存信息,命令
x
格式为:x /nfu ptr
说明
x 是 examine 的缩写
① n表示要显示的内存单元的个数
② f表示显示方式, 可取如下值
x 按十六进制格式显示变量。
d 按十进制格式显示变量。
u 按十进制格式显示无符号整型。
o 按八进制格式显示变量。
t 按二进制格式显示变量。
a 按十六进制格式显示变量。
i 指令地址格式
c 按字符格式显示变量。
f 按浮点数格式显示变量。
③ u表示一个地址单元的长度
b表示单字节,
h表示双字节,
w表示四字节,
g表示八字节
删除断点
① 使用命令d 断点索引
② 使用命令clear 行号