调试Linux C/C++后台程序,常常会gdb attach到对应进程进行调试,然后各种断点,观察点,观察内存等。但是,有时候我们需要能在gdb中做一些基本逻辑操作,主动call一个函数,甚至循环call几次等,这时就可以用gdb的环境变量和一些基本的控制语句。一个例子如下:
#include <stdlib.h>
#include <stdio.h>
int add(int a, int b, int *re)
{
if (!re) {
return 1;
} else {
*re = a + b;
return 0;
}
}
int main()
{
int *re = malloc(sizeof(int));
add(1, 2, re);
printf("1 + 2 = %d\n", *re);
while (1) {
printf("--- sleep ---\n");
sleep(10);
}
return 0;
}
编译运行这个程序,编译的时候记得加上 -g 选项。在一个终端窗口,编译运行:
root@ubuntu:/media/psf/Home/iLearn/project# gcc -g main.c
root@ubuntu:/media/psf/Home/iLearn/project# ./a.out
1 + 2 = 3
--- sleep ---
在另一个终端窗口,gdb attach 对应的进程,进行针对性调试:
root@ubuntu:/media/psf/Home/iLearn/project# ps afx|grep a.out
27487 pts/1 S+ 0:00 | \_ grep --color=auto a.out
27388 pts/11 S+ 0:00 \_ ./a.out
root@ubuntu:/media/psf/Home/iLearn/project# gdb - 27388
(gdb) set $re = (int*)malloc(sizeof(int)) # set 这里为了使用GDB的环境变量
(gdb) pt $re # print type,GDB环境变量赋值后,就会自动推导类型了
type = int *
(gdb) call add(1, 2, $re) # GDB call对应函数, pt看下函数原型,有调试信息才行(-g)
$1 = 0 # 函数的返回值
(gdb) p *$re
$2 = 3
(gdb) set pagination off # 关闭显示分页
(gdb) set $i = 0
(gdb) while $i < 3
>call add(100, $i, $re)
>set $i++
>p *$re
>end
$3 = 0 #call add的返回值
$4 = 100 #结果
$5 = 0
$6 = 101
$7 = 0
$8 = 102
如果想在运行到断点后,自动触发一些操作,可以配合GDB的command
命令,这样就更方便了。还有,如果在线上环境定位问题,没有调试信息, 可以进行汇编级调试,这两个命令layout asm
和ni
(next instruct)就用起来比较方便。
最后,GDB可以通过source
加载预先写好的GDB脚本,进行更加自动化的调试,非常的有用 :)