您的位置:首页 > 其它

使用gdb调试运行时的程序小技巧

2012-12-07 09:58 274 查看
原文链接地址:使用gdb调试运行时的程序小技巧

下面介绍我调试时经常遇到的三种问题,如果大家也有类似的问题交流一下解决方法:

情景1:在不中止程序服务的情况下,怎么调试正在运行时的程序

情景2:需要同时看几个变量的值或者批量查看多个core文件的堆栈信息怎么办

情景3:遇到需要查看、队列、链表、树、堆等数据结构里的变量怎么办

1. 情景1:在不中止程序服务的情况下,怎么调试正在运行时的程序

我们在生产环境或者测试环境,会遇到一些异常,我们需要知道程序中的变量或者内存的值来确定程序运行状态

之前听过@淘宝褚霸讲过用systemstap可以实现这种功能,但systamstap写起来复杂一些,

还有时候在低内核版本的操作系统上用stap之后,程序或者操作系统都有可能死掉。

看过多隆调试程序时用pstack(修改了pstack代码,用gdb实现的,详见http://blog.yufeng.info/archives/873)查看和修改一个正在

执行程序的全局变量,感觉很神奇,尝试用gdb实现这种功能:

保存下面代码到文件runstack.sh

用于测试runstack.sh调试的c代码

编译c代码:gcc -g -o read_input read_input.c

执行./read_input 我们开始使用runstack.sh来调试

使用方法:sh ./runstack.sh pid “command”

来试验一下:

[shihao@xxx]$ ps aux |grep read_input|grep -v grep

shihao 10933 0.0 0.0 3668 332 pts/4 S+ 09:41 0:00 ./read_input

10933是一个read_input程序的进程号

1)打印代码

sudo sh ./runstack.sh 10933 “list main”

结果

(gdb) 35 fprintf(stderr, “ret: %d, there is %d strings, current is %s\nplease input string:”, ret, count, buf);

36 }

37 }

38

39 int main()

40 {

41 fprintf(stderr, “main run!\n”);

42

43 stdin_read(STDIN_FILENO);

44

(gdb) quit

2)显示程序全局变量值

./runstack.sh 10933 “p count”

(gdb) $1 = 1

(gdb) quit

3)修改变量值

执行下面命令前

[shihao@tfs036097 gdb]$ runstack.sh 11190 “set count=100″

结果: (gdb) (gdb) quit

我们可以用上面命令看我们修改成功没有

[shihao@tfs036097 gdb]$ runstack.sh 11190 “p count”

(gdb) $1 = 100

(gdb) quit

全局变量count变成100了。

注:1)有一些程序经过操作系统优化过,直接用上面的方法可能有找不到符号表的情况

可以把上面的代码改成下面的试试,如果不行可能是其他原因

2)需要有查看和修改运行的进程的权限

2. 情景2:需要同时看几个变量的值或者批量查看多个core文件的信息怎么办

1)多个变量的情景


我们同时看一下count和input_list里面的值和堆栈信息,我们可以写一个script.gdb

$ cat script.gdb

执行 runstack.sh 10933 “source script.gdb”

(gdb) $1 = {next = 0x597c020, data = ” }

$2 = 2

#0 0x0000003fa4ec5f00 in __read_nocancel () from /lib64/libc.so.6

#1 0x00000000004007c7 in stdin_read (fd=0) at read_input.c:23

#2 0×0000000000400803 in main () at read_input.c:43

#1 0x00000000004007c7 in stdin_read (fd=0) at read_input.c:23

23 while (ret = read(fd, buf, 4096)) {

$3 = “12345\n”, ”

(gdb) quit

这样就可以同时做多个操作

2)批处理查看core的情况

有的时候会出现很多core文件,我们想知道哪些core文件是因为相同的原因,哪些是不相同的,看一个两个的时候还比较轻松

$ ls core.*

core.12281 core.12282 core.12283 core.12284 core.12286 core.12287 core.12288 core.12311 core.12313 core.12314

像上面有很多core文件,一个一个用gdb去执行bt去看core在哪里有点麻烦,我们想有把所有的core文件的堆栈和变量信息打印出来

我对runstack稍作修改就可以实现我们的需求,我们起名叫corestack.sh

我们可以这样执行:

./corestack.sh ./read_input core.12281 “bt”

执行结果:

(gdb) #0 0x0000003fa4e30265 in raise (sig=)

at ../nptl/sysdeps/unix/sysv/linux/raise.c:64

#1 0x0000003fa4e31d10 in abort () at abort.c:88

#2 0x0000003fa4e296e6 in __assert_fail (assertion=,

file=, line=,

function=) at assert.c:78

#3 0x00000000004008ba in main () at read_input.c:55

(gdb) quit

查看多个core文件堆栈信息的准备工作差不多了,我们写个脚本就可以把所有的core文件堆栈打印出来了

执行以下:for i in `ls core.*`;do ./corestack.sh ./read_input $i “bt”; done

(gdb) #0 0x0000003fa4e30265 in raise (sig=)

at ../nptl/sysdeps/unix/sysv/linux/raise.c:64

#1 0x0000003fa4e31d10 in abort () at abort.c:88

#2 0x0000003fa4e296e6 in __assert_fail (assertion=,

file=, line=,

function=) at assert.c:78

#3 0x00000000004008ba in main () at read_input.c:55

(gdb) quit

……

(gdb) #0 0x0000003fa4e30265 in raise (sig=)

at ../nptl/sysdeps/unix/sysv/linux/raise.c:64

#1 0x0000003fa4e31d10 in abort () at abort.c:88

#2 0x0000003fa4e296e6 in __assert_fail (assertion=,

file=, line=,

function=) at assert.c:78

#3 0x00000000004008ba in main () at read_input.c:55

(gdb) quit

ok, 我们看到了所有core文件的堆栈。

3. 情景3:遇到需要查看、队列、链表、树、堆等数据结构里的变量怎么办?

下面介绍链表怎么处理,对其他数据结构感兴趣的同学可以自己尝试编写一些gdb脚本(麻烦@周哲士豪一下我,我也学习学习),

希望我们可以实现一个gdb调试工具箱

gdb是支持编写的脚本的 http://sourceware.org/gdb/onlinedocs/gdb/Command-Files.html
我们写个plist.gdb,用while循环来遍历链表

$ cat plist.gdb

我们执行一下:runstack.sh 13434 “source plist.gdb”

(gdb) $1 = {next = 0x3d61040, data = ” }

$2 = {next = 0x3d60030, data = “123456\n”, ” }

$3 = {next = 0x3d5f020, data = “12345\n”, ” }

$4 = {next = 0x3d5e010, data = “1234\n”, ” }

$5 = {next = 0×0, data = “123\n”, ” }

(gdb) quit

实际上我们可以把plist写成自定义函数,执行gdb的时候会在当前目下查找.gdbinit文件加载到gdb:

$ cat .gdbinit

这样就可以用plist命令遍历list的值

$ runstack.sh 13434 “plist &input_list”

(gdb) $1 = {next = 0x3d61040, data = ” }

$2 = {next = 0x3d60030, data = “123456\n”, ” }

$3 = {next = 0x3d5f020, data = “12345\n”, ” }

$4 = {next = 0x3d5e010, data = “1234\n”, ” }

$5 = {next = 0×0, data = “123\n”, ” }

(gdb) quit

参考资料:

霸爷的博客:http://blog.yufeng.info/archives/873

gdb从脚本加载命令:http://blog.lifeibo.com/?p=380

gdb官方文档:http://sourceware.org/gdb/onlinedocs/gdb/Command-Files.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: