如何gdb调试一个运行中的进程

如何gdb调试一个运行中的进程,第1张

第一步 编译一个死循环程序

/* 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 %MEMVSZ RSS TTY STAT START TIME COMMAND

wyc 7712 0.0 0.1 6092 3644 pts/8Ss 10:24 0:00 bash

wyc 7880 0.0 0.1 6092 3608 pts/猛野辩9Ss 10:27 0:00 bash

wyc 7929 0.0 0.3 10848 6468 pts/9S+ 10:28 0:00 gdb

wyc 8347 93.0 0.0 1652 284 pts/8R+ 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

19if (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

16int main(void){

17int i = 0

18while(1){

19if (i == 1){

20test()

21return 1

22}

23}

(gdb) n

20test()

(gdb)

21return 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

19if (i == 1){

(gdb) p i

$2 = 0

(gdb) set var i=1

(gdb) n

20test()

(gdb) n

Hello

21return 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 ......

gdb调试命令如下:

1、启动gdb

$gdb

这样可以和gdb进行交互了。

2、启动gdb,并且分屏显示源代码

$gdb -tui

这样,使用了'-tui'选项,启动可以直接将屏幕分成两个部分,上面显示源代码,比丛历用list方便多了。这时候使用上下方向键可以查看源代码,想要命令行使用上下键就用[Ctrl]n和[Ctrl]p。

3、启动gdb调试指定程序app

$gdb app

这样就在基郑者启动gdb之后直接载入了app可执行程序,需要注意的是,载入的app程序必须在编译的时候有gdb调试选项,例搏薯如'gcc -g app app.c',注意,如果修改了程序的源代码,但是没有编译,那么在gdb中显示的会是改动后的源代码,但是运行的是改动前的程序,这样会导致跟踪错乱的。

4、启动程序之后,再用gdb调试

$gdb <program><PID>

这里,<program>是程序的可执行文件名,<PID>是要调试程序的PID.如果你的程序是一个服务程序,那么你可以指定这个服务程序运行时的进程ID。gdb会自动attach上去,并调试他。program应该在PATH环境变量中搜索得到。

5、启动程序之后,再启动gdb调试

$gdb <PID>

这里,程序是一个服务程序,那么你可以指定这个服务程序运行时的进程ID,<PID>是要调试程序的PID.这样gdb就附加到程序上了,但是现在还没法查看源代码,用file命令指明可执行文件就可以显示源代码了。

其原因是生成的二进制可执行文件没有使用-g选项。

gcc中-g选项是为了获得有关调试信息,要用gdb进行调乎薯试,必须使用-g生成二进制可执行文件,

1.删除该程序原有的可执行文件

2.gcc

-g

example.c

-o

example

这样就可以了,用gdb调用example救瞎悄木有问题磨顷渣鸟。


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/12468345.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-25
下一篇 2023-05-25

发表评论

登录后才能评论

评论列表(0条)

保存