前言
對於想要學習gdb
調試的童鞋,網上搜一下就是一大堆資料,信息太多而不知道該如何篩選了,當然最有效的方式是去看gdb的手冊,但是對於想快速上手的我,需要掌握最常用的一些指令和一些技巧,期間,我找到了一個很全很強大的教材,感覺就是gdb bible
——100-gdb-tips,100-gdb-tips-gitbook;強烈推薦參考這個文檔。文檔裏已經基本涵蓋了gdb
使用的各種操作和技巧,但是都相互比較獨立和分散,沒有一個完整的使用流程,下面我會總結一下整體使用的一個流程。
使用gdb
通常我們編寫一個程序,具體程序如下所示;並且編譯成帶調試信息的可執行文件,然後在用gdb
加載調試;
/*
* demo learning gdb
* gdb-sample.c
*/
#include <stdio.h>
void func_a(int *p){
printf("%s:p is %d | valuse is %d \n",__func__,p,*p);
}
void func_b(int *p){
*p = 12345;
func_a(p);
}
void func_c(int *p){
p = NULL;
func_b(p);
}
int main(void) {
int i = 0,j=0;
int *p = &j;
for(; i<6; i++){
if(i<2){
func_a(p);
}else if(i<4){
func_b(p);
}else{
func_c(p);
}
}
return 0;
}
gcc -g gdb-sample.c -o gdb-sample
記得帶上-g
選項,最後編譯成功並生成可執行文件gdb-sample
;
一個完整流程一般所需步驟
1 加載程序
gdb -q gdb-sample
2 查看
2.1 查看函數
使用i functions
或者info functions
可以查看當前的可執行文件的函數接口;
(gdb) i functions
All defined functions:
File gdb-sample.c:
void func_a(int *);
void func_b(int *);
void func_c(int *);
int main(void);
Non-debugging symbols:
0x0000000000400460 _init
0x0000000000400490 puts@plt
0x00000000004004a0 __stack_chk_fail@plt
0x00000000004004b0 printf@plt
0x00000000004004c0 __libc_start_main@plt
0x00000000004004e0 _start
0x0000000000400510 deregister_tm_clones
0x0000000000400550 register_tm_clones
0x0000000000400590 __do_global_dtors_aux
0x00000000004005b0 frame_dummy
0x00000000004006f0 __libc_csu_init
0x0000000000400760 __libc_csu_fini
0x0000000000400764 _fini
3 設置斷點
3.1 根據函數名設置斷點
(gdb) b main
Breakpoint 1 at 0x400658: file gdb-sample.c, line 19.
3.2 根據程序位置(第幾行)
(gdb) l
1 #include <stdio.h>
2
3 void func_a(int *p){
4 printf("%s:p is %d | valuse is %d \n",__func__,p,*p);
5 }
6
7 void func_b(int *p){
8 *p = 12345;
9 func_a(p);
10 }
(gdb)
11
12 void func_c(int *p){
13 p = NULL;
14 func_b(p);
15 }
16
17
18
19 int main(void) {
20 int i = 0,j=0;
(gdb)
21 int *p = &j;
22 for(; i<6; i++){
23 if(i<2){
24 func_a(p);
25 }else if(i<4){
26 func_b(p);
27 }else{
28 func_c(p);
29 }
30 }
(gdb) b 19
Breakpoint 3 at 0x400618: file gdb-sample.c, line 19.
刪除斷點
(gdb) d
刪除所有斷點嗎? (y or n) y
4 運行程序
使用run
或r
運行程序,如果被斷點中斷,可以使用c
繼續運行程序;
(gdb) r
Starting program: /home/thinkpad/code/gdb-tips/core_dump/gdb-sample
Breakpoint 1, main () at gdb-sample.c:19
19 int main(void) {
使用next
或者n
可以進行單步調試;不會進入到子函數內部;
使用step
或者s
可以進行單步調試;會進入到子函數內部;
5 查看變量
查看變量可以使用print
和p
(gdb) b main
Breakpoint 6 at 0x400618: file gdb-sample.c, line 19.
(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/zhaojh/code/gdb-tips/core_dump/gdb-sample
Breakpoint 6, main () at gdb-sample.c:19
19 int main(void) {
(gdb) n
20 int i = 0,j=0;
(gdb) p i
$1 = 0
(gdb) n
21 int *p = &j;
(gdb) n
22 for(; i<6; i++){
(gdb) p p
$2 = (int *) 0x7fffffffe2f8
(gdb) p *p
$3 = 0
(gdb)
6 查看寄存器
使用i r
,info register
,i register
,info r
可以查看寄存器;
(gdb) i r
rax 0x7fffffffe2f8 140737488347896
rbx 0x0 0
rcx 0x0 0
rdx 0x7fffffffe408 140737488348168
rsi 0x7fffffffe3f8 140737488348152
rdi 0x1 1
rbp 0x7fffffffe310 0x7fffffffe310
rsp 0x7fffffffe2f0 0x7fffffffe2f0
r8 0x400710 4196112
r9 0x7ffff7de7ac0 140737351940800
r10 0x846 2118
r11 0x7ffff7a2d740 140737348032320
r12 0x4004a0 4195488
r13 0x7fffffffe3f0 140737488348144
r14 0x0 0
r15 0x0 0
rip 0x40063f 0x40063f <main+47>
eflags 0x293 [ CF AF SF IF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
總結
記錄了一些比較簡單並且會被普遍用到的gdb
指令,作爲入門使用還是比較好的,更多高級的調試參考gdb bible
——100-gdb-tips,100-gdb-tips-gitbook。
參考
https://github.com/hellogcc/100-gdb-tips
https://wizardforcel.gitbooks.io/100-gdb-tips/content/