gdb調試當前運行的程序
爲什麼使用gdb調試正在運行的程序?
因爲有時候bug很難復現、或者環境搭建起來比較困難,所以在出現bug的時候可以使用gdb的attach功能調試正在運行的GCC編譯出來的程序,注意編譯選項要加-g,否則沒有符號表。
調試步驟?
1. 編譯時候帶-g選項。
2. 運行程序。
3. ps找到進程號。
4. 啓動gdb,使用attach選項,這時gdb會停止在程序的某處。
5. 按照GDB調試方法調試。當程序退出之後,依然可以使用run命令重啓程序。
用gdb可以調試當前的程序的使用情況,讀出他的參數。
以下用一個簡單的程序做爲例子:來說明gdb的調試。
第一步 編譯一個死循環程序。
/* File name malloc.c*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void getmem(void **p, int num){
*p = (void *)malloc(num);
}
void test(void){
char *str = NULL;
getmem((void **)&str, 100);
strcpy(str, "Hello");
printf("%s/n", str);
}
int main(void){
int i = 0;
while(1){
if (i == 1){
test();
return 1;
}
}
return 0;
}
我們可以看出,這個程序就是malloc一段內存空間,用來供strcpy使用,由於只是調試一下,就沒有在test程序中加上一些關於strcpy的正確性判斷語句。
函數的正常退出的情況是i==1,但是程序運行過程中根本無法使i==1成立。i的變量的值將會在使用gdb時用到。
開始編譯
$gcc -g malloc.c
得用gdb,加上-g還是需要的。生成的可執行文件爲a.out
第二步 讓gdb連接到正在執行的進程上去
首先運行程序。
$./a.out
明顯的,是一個死循環。
重新開一個shell
$ps -u
我的機器的運行情況如下所示:
Warning: bad ps syntax, perhaps a bogus '-'? See http://procps.sf.net/faq.html
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
wyc 7712 0.0 0.1 6092 3644 pts/8 Ss 10:24 0:00 bash
wyc 7880 0.0 0.1 6092 3608 pts/9 Ss 10:27 0:00 bash
wyc 7929 0.0 0.3 10848 6468 pts/9 S+ 10:28 0:00 gdb
wyc 8347 93.0 0.0 1652 284 pts/8 R+ 10:42 0:13 ./a.out
...
看到沒有? ./a.out的進程號是8347。
現在啓動gdb
$gdb
由於是調試運行的進程,不是可執行文件,後面不需要跟任何參數。在用 gdb調試運行狀態下的程序時,最核心的就是gdb內部的attach命令
用法爲
(gdb) attach
這是我的機器上的例子:
$ gdb
GNU gdb (GDB) 7.1.50.20100621
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "i686-pc-linux-gnu".
For bug reporting instructions, please see:
.
(gdb) attach 8347
Attaching to process 8347
Reading symbols from /home/wyc/desktop/my_program/review/a.out...done.
Reading symbols from /lib/tls/i686/cmov/libc.so.6...(no debugging symbols found)...done.
Loaded symbols for /lib/tls/i686/cmov/libc.so.6
Reading symbols from /lib/ld-linux.so.2...(no debugging symbols found)...done.
Loaded symbols for /lib/ld-linux.so.2
main () at malloc.c:19
19 if (i == 1){
(gdb) p i
$1 = 0
(gdb) set i=1
Ambiguous set command "i=1": .
(gdb) i=1
Undefined info command: "=1". Try "help info".
(gdb) set i=1
Ambiguous set command "i=1": .
(gdb) set var i=1
(gdb) l
14 }
15
16 int main(void){
17 int i = 0;
18 while(1){
19 if (i == 1){
20 test();
21 return 1;
22 }
23 }
(gdb) n
20 test();
(gdb)
21 return 1;
(gdb)
25 }
(gdb)
0xb7f47775 in __libc_start_main () from /lib/tls/i686/cmov/libc.so.6
(gdb)
Single stepping until exit from function __libc_start_main,
which has no line number information.
Program exited with code 01.
(gdb)
在運行到第20行命令的時候,可以看一下到運行./a.out的那個shell,應該hello字符串在標準輸出上了。當gdb中顯示進程退出時,./a.out的shell應該結束了當前進程了。
在gdb中用set var i=1 來修改變量i的值(用set i=1不能識別命令),使程序能夠正常退出。
在調試時,當前程序調用的所有庫也全部都出來了。這個例子中的
Reading symbols from /home/wyc/desktop/my_program/review/a.out...done.
Reading symbols from /lib/tls/i686/cmov/libc.so.6...(no debugging symbols found)...done.
Loaded symbols for /lib/tls/i686/cmov/libc.so.6
Reading symbols from /lib/ld-linux.so.2...(no debugging symbols found)...done.
Loaded symbols for /lib/ld-linux.so.2
是a.out程序所調用的全部庫。可以用這種辦法分析當前運行的程序的庫的調用情況。
千萬不要關掉gdb,以下調試更精彩:
第三步 在gdb中重啓程序
在上面已經知道了程序正常退出了,但是gdb還沒有退出,這時在gdb中運行run效果如何?
(gdb) run
Starting program: /home/wyc/desktop/my_program/review/a.out
下面是死循環了...
接下Ctrl+c,給gdb發個SIGINT的信號。
^C
Program received signal SIGINT, Interrupt.
main () at malloc.c:19
19 if (i == 1){
(gdb) p i
$2 = 0
(gdb) set var i=1
(gdb) n
20 test();
(gdb) n
Hello
21 return 1;
(gdb) n
25 }
(gdb) n
0xb7e7b775 in __libc_start_main () from /lib/tls/i686/cmov/libc.so.6
(gdb) n
Single stepping until exit from function __libc_start_main,
which has no line number information.
Program exited with code 01.
可以看出,用gdb連接進程後,他會找到運行這個進程所需的全部文件,當前進程關閉後,仍然可以在gdb中啓動這個程序。
不得不佩服GDB的調試功能的強大
gdb中的其它命令,就看你分析程序時是否用到了,例如下面的一些簡單的命令:
常用的bt, p , p/x , setp, info registers, break , jump ......