本文是100个GDB小技巧阅读总结,100个GDB小技巧.
在这个例子中源代码如下:
#include
#include
void *thread_func(void *p_arg)
{
while (1)
{
sleep(10);
}
}
int main(void)
{
pthread_t t1, t2;
pthread_create(&t1, NULL, thread_func, "Thread 1");
pthread_create(&t2, NULL, thread_func, "Thread 2");
sleep(1000);
return;
}
然后保存文件为fucntion.c
gcc -g function.c -o function提示如下错误:
/tmp/ccCIJDjs.o: In function main':
pthread_create’
/root/function.c:14: undefined reference to
/root/function.c:15: undefined reference to `pthread_create’
collect2: error: ld returned 1 exit status
错误产生的原因是:
pthread库不是标准linux库,修改为如下方式即可:
gcc -pthread -g function.c -o function
然后gdb function即可.
例子
#include
int func(void)
{
int i = 0;
i += 2;
i *= 10;
return i;
}
int main(void)
{
int a = 0;
a = func();
printf("%d\n", a);
return 0;
}
技巧
当单步调试一个函数时,如果不想继续跟踪下去了,可以有两种方式退出。
第一种用“finish”命令,这样函数会继续执行完,并且打印返回值,然后等待输入接下来的命令。以上面代码为例:
(gdb) n
17 a = func();
(gdb) s
func () at a.c:5
5 int i = 0;
(gdb) n
7 i += 2;
(gdb) fin
find finish
(gdb) finish
Run till exit from #0 func () at a.c:7
0x08050978 in main () at a.c:17
17 a = func();
Value returned is $1 = 20
可以看到当不想再继续跟踪func函数时,执行完“finish”命令,gdb会打印结果:“20”,然后停在那里。
第二种用“return”命令,这样函数不会继续执行下面的语句,而是直接返回。也可以用“return expression”命令指定函数的返回值。仍以上面代码为例:
(gdb) n
17 a = func();
(gdb) s
func () at a.c:5
5 int i = 0;
(gdb) n
7 i += 2;
(gdb) n
8 i *= 10;
(gdb) re
record remove-inferiors return reverse-next reverse-step
refresh remove-symbol-file reverse-continue reverse-nexti reverse-stepi
remote restore reverse-finish reverse-search
(gdb) return 40
Make func return now? (y or n) y
#0 0x08050978 in main () at a.c:17
17 a = func();
(gdb) n
18 printf("%d\n", a);
(gdb) 40
19 return 0;
可以看到“return”命令退出了函数并且修改了函数的返回值。
例子
#include
int func(int a, int b)
{
int c = a * b;
printf("c is %d\n", c);
}
int main(void)
{
func(1, 2);
return 0;
}
技巧
使用gdb调试程序时,可以使用“i frame”命令(i是info命令缩写)显示函数堆栈帧信息。以上面程序为例:
(gdb) b func
Breakpoint 1 at 0x4004d2: file main.c, line 4.
(gdb) r
Starting program: /root/play/main
Breakpoint 1, func (a=1, b=2) at a.c:5
5 printf(“c is %d\n”, c);
(gdb) i frame
Stack level 0, frame at 0x7fffffffe590:
rip = 0x40054e in func (a.c:5); saved rip = 0x400577
called by frame at 0x7fffffffe5a0
source language c.
Arglist at 0x7fffffffe580, args: a=1, b=2
Locals at 0x7fffffffe580, Previous frame’s sp is 0x7fffffffe590
Saved registers:
rbp at 0x7fffffffe580, rip at 0x7fffffffe588
(gdb) i registers
rax 0x2 2
rbx 0x0 0
rcx 0x0 0
rdx 0x7fffffffe688 140737488348808
rsi 0x2 2
rdi 0x1 1
rbp 0x7fffffffe580 0x7fffffffe580
rsp 0x7fffffffe560 0x7fffffffe560
r8 0x7ffff7dd4e80 140737351863936
r9 0x7ffff7dea560 140737351951712
r10 0x7fffffffe420 140737488348192
r11 0x7ffff7a35dd0 140737348066768
r12 0x400440 4195392
r13 0x7fffffffe670 140737488348784
r14 0x0 0
r15 0x0 0
rip 0x40054e 0x40054e
#include
#include
typedef struct
{
int a;
int b;
int c;
int d;
pthread_mutex_t mutex;
}ex_st;
int main(void) {
ex_st st = {1, 2, 3, 4, PTHREAD_MUTEX_INITIALIZER};
printf("%d,%d,%d,%d\n", st.a, st.b, st.c, st.d);
return 0;
}
技巧
在使用gdb时,如果想让断点只生效一次,可以使用“tbreak”命令(缩写为:tb)。以上面程序为例:
(gdb) tb a.c:15
Temporary breakpoint 1 at 0x400500: file a.c, line 15.
(gdb) i b
Num Type Disp Enb Address What
1 breakpoint del y 0x0000000000400500 in main at a.c:15
(gdb) r
Starting program: /data2/home/nanxiao/a
Temporary breakpoint 1, main () at a.c:15
15 printf(“%d,%d,%d,%d\n”, st.a, st.b, st.c, st.d);
(gdb) i b
No breakpoints or watchpoints.
首先在文件的第15行设置临时断点,当程序断住后,用“i b”(”info breakpoints”缩写)命令查看断点,发现断点没有了。也就是断点命中一次后,就被删掉了。
#include
int main(void)
{
int i = 0;
int sum = 0;
for (i = 1; i <= 200; i++)
{
sum += i;
}
printf("%d\n", sum);
return 0;
}
技巧
gdb可以设置条件断点,也就是只有在条件满足时,断点才会被触发,命令是“break … if cond”。以上面程序为例:
(gdb) start
Temporary breakpoint 1 at 0x4004cc: file a.c, line 5.
Starting program: /data2/home/nanxiao/a
Temporary breakpoint 1, main () at a.c:5
5 int i = 0;
(gdb) b 10 if i==101
Breakpoint 2 at 0x4004e3: file a.c, line 10.
(gdb) c
Continuing.
Breakpoint 2, main () at func.c:10
10 sum += i;
(gdb) p sum
$1 = 5050
可以看到设定断点只在i的值为101时触发,此时打印sum的值为5050。
#include
int main(void)
{
int i = 0;
int sum = 0;
for (i = 1; i <= 200; i++)
{
sum += i;
}
printf("%d\n", sum);
return 0;
}
在设置断点以后,可以忽略断点,命令是“ignore bnum count”:意思是接下来count次编号为bnum的断点触发都不会让程序中断,只有第count + 1次断点触发才会让程序中断。以上面程序为例:
(gdb) b 9
Breakpoint 1 at 0x4004e3: file hello.c, line 9.
(gdb) ignore 1 5
Will ignore next 5 crossings of breakpoint 1.
(gdb) r
Starting program: /root/play/hello
Breakpoint 1, main () at hello.c:9
9 sum += i;
Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.149.el6.x86_64
(gdb) p i
$1 = 6
可以看到设定忽略断点前5次触发后,第一次断点断住时,打印i的值是6。如果想让断点从i=1处开始生效,可以将count置为0:“ignore 1 0”.