您的位置:首页 > 其它

使用GDB调试程序

2014-09-13 18:47 363 查看
1、GDB简单使用教程

(1)源文件

//func.h
#ifndef _TEST_H_
#define _TEST_H_

void print(int value);
void set_and_print(int *a, int index, int value);

#endif


//func.c
#include <stdio.h>

void print(int value)
{
printf("%d\n", value);
}

void set_and_print(int *a, int index, int value)
{
a[index] = value;
print(a[index]);
}


//gdb_main.c
#include <stdio.h>
#include <stdlib.h>
#include "func.h"

int main(int argc, char **argv)
{
int a[10] = {0};
int array_size = sizeof(a) / sizeof(a[0]);
int set_nums = 0;

set_nums = argc - 1;

set_nums = set_nums > array_size ? array_size : set_nums;

int i;
for (i = 0; i < set_nums; ++i)
{
set_and_print(a, i, atoi(argv[i+1]));
}

printf("The\n");
printf("End\n");
return 0;
}

(2)调试过程

[root@localhost ~]# gcc -g func.c gdb_main.c -o gdb_main <---------- 编译生成可执行文件

[root@localhost ~]# gdb gdb_main <---------- 启动GDB

GNU gdb (GDB) CentOS (7.0.1-45.el5.centos)

Copyright (C) 2009 Free Software Foundation, Inc.

License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

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 "i386-redhat-linux-gnu".

For bug reporting instructions, please see:

<http://www.gnu.org/software/gdb/bugs/>...

Reading symbols from /root/gdb_main...done.

(gdb) l <---------- l命令表示list,从第一行显示源码

1 #include <stdio.h>

2 #include <stdlib.h>

3 #include "func.h"

4

5 int main(int argc, char **argv)

6 {

7 int a[10] = {0};

8 int array_size = sizeof(a) / sizeof(a[0]);

9 int set_nums = 0;

10

(gdb) l

11 set_nums = argc - 1;

12

13 set_nums = set_nums > array_size ? array_size : set_nums;

14

15 int i;

16 for (i = 0; i < set_nums; ++i)

17 {

18 set_and_print(a, i, atoi(argv[i+1]));

19 }

20

(gdb) <---------- 回车,表示重复上一个命令

21 printf("The\n");

22 printf("End\n");

23 return 0;

24 }

(gdb) b 9 <---------- 设置断点,在第9行

Breakpoint 1 at 0x804847c: file gdb_main.c, line 9.

(gdb) b 21 <---------- 设置断点,在第21行

Breakpoint 2 at 0x80484f5: file gdb_main.c, line 21.

(gdb) l func.c:1 <---------- 显示源码,从func.c文件的第一行开始

1 #include <stdio.h>

2

3 void print(int value)

4 {

5 printf("%d\n", value);

6 }

7

8 void set_and_print(int *a, int index, int value)

9 {

10 a[index] = value;

(gdb) l func.c:set_and_print <---------- 显示源码,从func.c文件的set_and_print函数开始

4 {

5 printf("%d\n", value);

6 }

7

8 void set_and_print(int *a, int index, int value)

9 {

10 a[index] = value;

11 print(a[index]);

12 }

(gdb) b func.c:print <---------- 设置断点,在func.c文件的print函数

Breakpoint 3 at 0x804840a: file func.c, line 5.

(gdb) b set_and_print if index>0 <---------- 设置断点,当set_and_print函数的参数index>1

Breakpoint 4 at 0x8048425: file func.c, line 10.

(gdb) info break <---------- 显示所有断点信息

Num Type Disp Enb Address What

1 breakpoint keep y 0x0804847c in main at gdb_main.c:9

2 breakpoint keep y 0x080484f5 in main at gdb_main.c:21

3 breakpoint keep y 0x0804840a in print at func.c:5

4 breakpoint keep y 0x08048425 in set_and_print at func.c:10

stop only if index>0

(gdb) set args 10 20 30 <---------- 设置主函数的参数

(gdb) show args <---------- 显示主函数的参数

Argument list to give program being debugged when it is started is "10 20 30".

(gdb) r <---------- r表示run,运行程序

Starting program: /root/gdb_main 10 20 30

Breakpoint 1, main (argc=4, argv=0xbfffea74) at gdb_main.c:9

9 int set_nums = 0;

(gdb) watch set_nums <---------- 设置观察点,一旦set_nums的值发生变化就停住

Hardware watchpoint 5: set_nums

(gdb) info watch <---------- 查看所有断点信息

Num Type Disp Enb Address What

1 breakpoint keep y 0x0804847c in main at gdb_main.c:9

breakpoint already hit 1 time

2 breakpoint keep y 0x080484f5 in main at gdb_main.c:21

3 breakpoint keep y 0x0804840a in print at func.c:5

4 breakpoint keep y 0x08048425 in set_and_print at func.c:10

stop only if index>0

5 hw watchpoint keep y set_nums

(gdb) c <---------- c表示continue,继续运行

Continuing.

Hardware watchpoint 5: set_nums

Old value = -1073747480

New value = 3

main (argc=4, argv=0xbfffea74) at gdb_main.c:13

13 set_nums = set_nums > array_size ? array_size : set_nums;

(gdb) clear 9 <---------- 删除第9行的断点

Deleted breakpoint 1

(gdb) d 5 <---------- d表示delete,删除第5个断点

(gdb) info watch

Num Type Disp Enb Address What

2 breakpoint keep y 0x080484f5 in main at gdb_main.c:21

3 breakpoint keep y 0x0804840a in print at func.c:5

4 breakpoint keep y 0x08048425 in set_and_print at func.c:10

stop only if index>0

(gdb) p set_nums <---------- p表示print,打印set_nums的值

$1 = 3

(gdb) p/a set_nums <---------- 打印set_nums的十六进制

$2 = 0x3

(gdb) p &set_nums <---------- 打印set_nums的地址

$3 = (int *) 0xbfffe9c8

(gdb) c

Continuing.

Breakpoint 3, print (value=10) at func.c:5

5 printf("%d\n", value);

(gdb) bt <---------- bt表示backtrace,打印当前函数调用栈的信息

#0 print (value=10) at func.c:5

#1 0x08048448 in set_and_print (a=0xbfffe99c, index=0, value=10) at func.c:11

#2 0x080484e9 in main (argc=4, argv=0xbfffea74) at gdb_main.c:18

(gdb) f 1 <---------- f表示frame,切换到栈的第二层

#1 0x08048448 in set_and_print (a=0xbfffe99c, index=0, value=10) at func.c:11

11 print(a[index]);

(gdb) info f <---------- 查看当前栈的信息

Stack level 1, frame at 0xbfffe970:

eip = 0x8048448 in set_and_print (func.c:11); saved eip 0x80484e9

called by frame at 0xbfffe9e0, caller of frame at 0xbfffe960

source language c.

Arglist at 0xbfffe968, args: a=0xbfffe99c, index=0, value=10

Locals at 0xbfffe968, Previous frame's sp is 0xbfffe970

Saved registers:

ebp at 0xbfffe968, eip at 0xbfffe96c

(gdb) up <---------- 向栈的前面移动

#2 0x080484e9 in main (argc=4, argv=0xbfffea74) at gdb_main.c:18

18 set_and_print(a, i, atoi(argv[i+1]));

(gdb) down 2 <---------- 向栈的后面移动

#0 print (value=10) at func.c:5

5 printf("%d\n", value);

(gdb) c

Continuing.

10

Breakpoint 4, set_and_print (a=0xbfffe99c, index=1, value=20) at func.c:10

10 a[index] = value;

(gdb) disable 4 <---------- 停止掉第4个断点,但不会删除

(gdb) c

Continuing.

Breakpoint 3, print (value=20) at func.c:5

5 printf("%d\n", value);

(gdb) c

Continuing.

20

Breakpoint 3, print (value=30) at func.c:5

5 printf("%d\n", value);

(gdb) c

Continuing.

30

Breakpoint 2, main (argc=4, argv=0xbfffea74) at gdb_main.c:21

21 printf("The\n");

(gdb) n <---------- n表示next,单步调试

The

22 printf("End\n");

(gdb) s <---------- s表示step,单步调试,会进入被调用函数

End

23 return 0;

(gdb) c

Continuing.

Program exited normally.

(gdb) q <---------- q表示quit,退出gdb

(3)多线程调试

如果是多线程的程序,可以定义断点是在所有的线程上,还是是在某个特定的线程。

break <linespec> thread <threadno>

break <linespec> thread <threadno> if ...

linespec指定了断点设置在的源程序的行号。

threadno指定了线程的ID,这个ID是GDB分配的,可以通过“info threads”命令来查看正在运行程序中的线程信息。如果不指定thread <threadno>则表示你的断点设在所有线程上面。

if语句可以为某线程指定断点条件。

当程序被GDB停住时,所有的运行线程都会被停住。在恢复程序运行时,所有的线程也会被恢复运行。哪怕是主进程在被单步调试时。

2、程序输出重定向

[root@localhost ~]# gdb gdb_main

GNU gdb (GDB) CentOS (7.0.1-45.el5.centos)

Copyright (C) 2009 Free Software Foundation, Inc.

License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

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 "i386-redhat-linux-gnu".

For bug reporting instructions, please see:

<http://www.gnu.org/software/gdb/bugs/>...

Reading symbols from /root/gdb_main...done.

(gdb) r > debug.log <---------- 把程序的输出重定向到文件debug.log

Starting program: /root/gdb_main > debug.log

Program exited normally.

(gdb) q

3、调试正在运行的程序

[root@localhost ~]# ps -e | grep gdb_main //假设gdb_main还在运行,当然此处的源码不符合要求,可以在主函数添加while循环

21363 pts/2 00:00:12 gdb_main

[root@davelin ~]# gdb -p 21363

GNU gdb (GDB) CentOS (7.0.1-45.el5.centos)

Copyright (C) 2009 Free Software Foundation, Inc.

License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

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 "i386-redhat-linux-gnu".

For bug reporting instructions, please see:

<http://www.gnu.org/software/gdb/bugs/>.

Attaching to process 21363

Reading symbols from /root/gdb_main...done.

Reading symbols from /lib/libc.so.6...(no debugging symbols found)...done.

Loaded symbols for /lib/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 (argc=1, argv=0xbfcbaf64) at gdb_main.c:22

22 ;

(gdb) call creat("dbg.log", 0600) <---------- 创建文件dbg.log

$1 = 3

(gdb) call dup2(3, 1) <---------- 3为dbg.log的fd,把stdout重定向到文件dbg.log

$2 = 1

(gdb) q

A debugging session is active.

Inferior 1 [process 21363] will be detached.

Quit anyway? (y or n) y

Detaching from program: /root/gdb_main, process 21363

4、根据coredump定位崩溃进程

(1)如何生成core file

ulimit -c unlimited //设置core file为无限大,可以修改unlimited为具体数字

(2)生成core file的位置

core file的生成路径定义在/proc/sys/kernel/core_pattern中,可以改为root用户指定的路径

echo "pattern" > /proc/sys/kernel/core_pattern

"pattern"类似C语言打印字符串的格式,相关标识如下:

%%: 相当于%

%p: 相当于<pid>

%u: 相当于<uid>

%g: 相当于<gid>

%s: 相当于导致dump的信号的数字

%t: 相当于dump的时间

%h: 相当于hostname

%e: 相当于执行文件的名称

这时用如下命令设置生成的core file到当前目录下,并记录pid以及执行文件名

echo "core-%e-%p" > /proc/sys/kernel/core_pattern

(3)修改源码,以引起coredump

把func.c中printf("%d\n", value)改为 printf("%s\n",
value)


(4)编译调试

[root@localhost ~]# ulimit -c unlimited

[root@localhost ~]# echo "core-%e-%p" > /proc/sys/kernel/core_pattern

[root@localhost ~]# gcc -g func.c gdb_main.c -o gdb_main

[root@localhost ~]# ./gdb_main 10 20 30

Segmentation fault (core dumped)

[root@localhost ~]# gdb gdb_main core-gdb_main-21300

GNU gdb (GDB) CentOS (7.0.1-45.el5.centos)

Copyright (C) 2009 Free Software Foundation, Inc.

License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

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 "i386-redhat-linux-gnu".

For bug reporting instructions, please see:

<http://www.gnu.org/software/gdb/bugs/>...

Reading symbols from /root/gdb_main...done.

[New Thread 21300]

Reading symbols from /lib/libc.so.6...(no debugging symbols found)...done.

Loaded symbols for /lib/libc.so.6

Reading symbols from /lib/ld-linux.so.2...(no debugging symbols found)...done.

Loaded symbols for /lib/ld-linux.so.2

Core was generated by `./gdb_main 10 20 30'.

Program terminated with signal 11, Segmentation fault.

#0 0x00bb1a3b in strlen () from /lib/libc.so.6

(gdb) bt

#0 0x00bb1a3b in strlen () from /lib/libc.so.6

#1 0x00b82380 in vfprintf () from /lib/libc.so.6

#2 0x00b87ce3 in printf () from /lib/libc.so.6

#3 0x0804841d in print (value=10) at func.c:5

#4 0x08048448 in set_and_print (a=0xbf89b6bc, index=0, value=10) at func.c:11

#5 0x080484e9 in main (argc=4, argv=0xbf89b794) at gdb_main.c:18

(gdb)

以上内容参考了陈浩的用GDB调试程序系列文章,以及文章【gdb结合coredump定位崩溃进程】
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: