欢迎 nogirl 加入本站!
 免费注册  用户登陆  汇款方式  汇款确认  产品报价  联系我们  帮助中心
加入收藏
设为首页
会员体系
申请VIP
网站首页 光盘超市 软件下载 技术文章 专题 用户中心 VIP会员 技术论坛 网站留言 娱乐中心 卓越资源
今天是:2008年11月21日 星期五  您现在位于: 首页 → 技术文章 → 使用gdb调试gdb/kg...
   使用gdb调试gdb/kgdb的方法与示例
作者:snow888  出处:snow888.cublog.cn  更新时间: 2007年05月22日 
本文简单介绍了使用gdb调试gdb和kgdb的方法,供各位对gdb源代码和gdb Remote Serial Protocol分析感兴趣的朋友参考。示例系统为FreeBSD6.1。我把这种调试方法比喻为螳螂捕蝉,黄雀在后,即螳螂版gdb调试蝉版目标程序,黄雀版gdb又去调试螳螂版gdb。

1、准备螳螂版gdb
相关目录说明:
gdb的工程目录(makefile文件)存放在/usr/src/gnu/usr.bin/gdb目录下;
gdb的源代码文件存放在/usr/src/contrib/gdb目录下;
gdb的目标文件(编译结果)存放在/usr/obj/usr/src/gnu/usr.bin/gdb目录下。

(1)修改makefile
到/usr/src/gnu/usr.bin/gdb目录下编辑Makefile.inc文件,在其中的一堆给CFLAGS变量赋值的地方加上一句:

CFLAGS+= -g
(2)编译版本(在/usr/src/gnu/usr.bin/gdb目录下)

make clean
make
完成上述步骤之后,会在/usr/obj/usr/src/gnu/usr.bin/gdb目录下生成debug版本的gdb程序。这就是我们的螳螂版gdb。

2、准备蝉版目标程序
为了说明问题,这个“蝉”只需要是一个简单程序就可以了,比如:

1   int main(void)
2   {   
3       int a, b, c;
4       a = 1;
5       b = 2;
6       c = a + b;
7       return c;
8   }
带-g选项将其编译为debug版本,假设编译结果名为a.out,这就是我们的蝉。

3、准备黄雀版gdb - 这个就不用准备了,用系统自带的gdb即可

4、螳螂捕蝉
用我们刚才编译出来的螳螂版gdb调试蝉版a.out。

[~]$ /usr/obj/usr/src/gnu/usr.bin/gdb/gdb/gdb a.out
GNU gdb 6.1.1 [FreeBSD]
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i386-marcel-freebsd"...
(gdb)
5、黄雀在后
另开一个终端,用ps或者top命令看看刚才运行的螳螂版gdb的PID是多少。

2670  p0  I+     0:00.24 /usr/obj/usr/src/gnu/usr.bin/gdb/gdb/gdb a.out
我们可以看到,对于我们的例子,螳螂版的gdb的PID是2670。
现在,按以下命令运行黄雀版gdb。

[~]$ gdb -p 2670 /usr/obj/usr/src/gnu/usr.bin/gdb/gdb/gdb
GNU gdb 6.1.1 [FreeBSD]
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i386-marcel-freebsd"...
Attaching to program: /usr/obj/usr/src/gnu/usr.bin/gdb/gdb/gdb, process 2670
Reading symbols from /lib/libm.so.4...done.
Loaded symbols for /lib/libm.so.4
Reading symbols from /lib/libreadline.so.6...done.
Loaded symbols for /lib/libreadline.so.6
Reading symbols from /lib/libncurses.so.6...done.
Loaded symbols for /lib/libncurses.so.6
Reading symbols from /usr/lib/libgnuregex.so.3...done.
Loaded symbols for /usr/lib/libgnuregex.so.3
Reading symbols from /lib/libc.so.6...done.
Loaded symbols for /lib/libc.so.6
Reading symbols from /usr/lib/libthread_db.so...done.
Loaded symbols for /usr/lib/libthread_db.so
Reading symbols from /libexec/ld-elf.so.1...done.
Loaded symbols for /libexec/ld-elf.so.1
0x2834f20b in poll () from /lib/libc.so.6
(gdb)
至此,螳螂版gdb取得了蝉版a.out的控制权,而黄雀版gdb又取得了螳螂版gdb的控制权,我们现在就可以开始调试螳螂版的gdb了。

6、调试过程示例
(1) 我们首先在黄雀版gdb里面给螳螂版gdb设个断点,就选择gdb在用户输入s(单步调试)命令之后的处理函数step_1():

(gdb) b step_1
Breakpoint 1 at 0x8072cb5: file /usr/src/gnu/usr.bin/gdb/libgdb/../../../../contrib/gdb/gdb/infcmd.c, line 581.
(gdb)
设好断点之后,就可以让螳螂版gdb继续运行了:

(gdb) c
Continuing.
(2) 现在我们回到螳螂版gdb的终端,黄雀版gdb已经把控制权交还给了它,于是,我们可以开始用它来调试蝉版a.out了。先在main()开始处设个断点,然后让它运行到这个断点处:

(gdb) b main
Breakpoint 1 at 0x80484a8: file foo.c, line 4.
(gdb) run
Starting program: /usr/home/ysfp/a.out

Breakpoint 1, main () at foo.c:4
4           a = 1;
(gdb)
(3) 现在我们就可以在螳螂版gdb中使用s命令来触发黄雀版gdb对它的调试了:

(gdb) s
执行上述命令之后,螳螂版gdb就失去了响应。我们转到黄雀版gdb的终端:

(gdb) c
Continuing.

Breakpoint 1, step_1 (skip_subroutines=136577025, single_inst=136722816, count_string=0x0)
    at /usr/src/gnu/usr.bin/gdb/libgdb/../../../../contrib/gdb/gdb/infcmd.c:581
581     {
(gdb)
这正是我们刚才在黄雀版gdb里面给螳螂版gdb设的断点,现在由于我们在螳螂版gdb里面输入了s命令,它已经停止在了s命令的处理函数step_1处,等待黄雀版gdb的下一个指令。

我们可以来看看螳螂版gdb在step_1()之前的调用栈:

(gdb) bt
#0  step_1 (skip_subroutines=136577025, single_inst=136722816, count_string=0x0)
    at /usr/src/gnu/usr.bin/gdb/libgdb/../../../../contrib/gdb/gdb/infcmd.c:581
#1  0x080c77b3 in execute_command (p=0x8240001 "", from_tty=1)
    at /usr/src/gnu/usr.bin/gdb/libgdb/../../../../contrib/gdb/gdb/top.c:743
#2  0x08089ede in command_handler (command=0x8240000 "s")
    at /usr/src/gnu/usr.bin/gdb/libgdb/../../../../contrib/gdb/gdb/event-top.c:500
#3  0x0808a523 in command_line_handler (rl=0x8282540 "P%(\b\200%(\b")
    at /usr/src/gnu/usr.bin/gdb/libgdb/../../../../contrib/gdb/gdb/event-top.c:793
#4  0x2826897f in rl_callback_read_char () from /lib/libreadline.so.6
#5  0x08089877 in rl_callback_read_char_wrapper (client_data=0x0)
    at /usr/src/gnu/usr.bin/gdb/libgdb/../../../../contrib/gdb/gdb/event-top.c:166
#6  0x0808b230 in handle_file_event (event_file_desc=0)
    at /usr/src/gnu/usr.bin/gdb/libgdb/../../../../contrib/gdb/gdb/event-loop.c:721
#7  0x0808ace6 in process_event () at /usr/src/gnu/usr.bin/gdb/libgdb/../../../../contrib/gdb/gdb/event-loop.c:334
#8  0x0808b495 in gdb_do_one_event (data=0x0) at /usr/src/gnu/usr.bin/gdb/libgdb/../../../../contrib/gdb/gdb/event-loop.c:371
#9  0x080c72f0 in catcher (func=0x80c73f0 <do_catch_errors>, func_uiout=0x827ed00, func_args=0xbfbfe8d0, func_val=0xbfbfe8c8,
    func_caught=0xbfbfe8cc, errstring=0x0, gdberrmsg=0x0, mask=6)
    at /usr/src/gnu/usr.bin/gdb/libgdb/../../../../contrib/gdb/gdb/top.c:430
#10 0x080c743a in catch_errors (func=0, func_args=0x0, errstring=0x81d9a96 "", mask=6)
    at /usr/src/gnu/usr.bin/gdb/libgdb/../../../../contrib/gdb/gdb/top.c:535
#11 0x08154d53 in tui_command_loop (data=0x0) at /usr/src/gnu/usr.bin/gdb/libgdb/../../../../contrib/gdb/gdb/tui/tui-interp.c:150
#12 0x08071ece in current_interp_command_loop () at /usr/src/gnu/usr.bin/gdb/libgdb/../../../../contrib/gdb/gdb/interps.c:277
#13 0x080710cf in captured_command_loop (data=0x0) at /usr/src/gnu/usr.bin/gdb/libgdb/../../../../contrib/gdb/gdb/main.c:97
#14 0x080c72f0 in catcher (func=0x80c73f0 <do_catch_errors>, func_uiout=0x827ed00, func_args=0xbfbfe9f0, func_val=0xbfbfe9e8,
    func_caught=0xbfbfe9ec, errstring=0x0, gdberrmsg=0x0, mask=6)
    at /usr/src/gnu/usr.bin/gdb/libgdb/../../../../contrib/gdb/gdb/top.c:430
#15 0x080c743a in catch_errors (func=0, func_args=0x0, errstring=0x81d9a96 "", mask=6)
    at /usr/src/gnu/usr.bin/gdb/libgdb/../../../../contrib/gdb/gdb/top.c:535
#16 0x08071777 in captured_main (data=0x0) at /usr/src/gnu/usr.bin/gdb/libgdb/../../../../contrib/gdb/gdb/main.c:805
#17 0x080c72f0 in catcher (func=0x80c73f0 <do_catch_errors>, func_uiout=0x821d120, func_args=0xbfbfec10, func_val=0xbfbfec08,
    func_caught=0xbfbfec0c, errstring=0x0, gdberrmsg=0x0, mask=6)
    at /usr/src/gnu/usr.bin/gdb/libgdb/../../../../contrib/gdb/gdb/top.c:430
#18 0x080c743a in catch_errors (func=0, func_args=0x0, errstring=0x81d9a96 "", mask=6)
    at /usr/src/gnu/usr.bin/gdb/libgdb/../../../../contrib/gdb/gdb/top.c:535
#19 0x08071d07 in gdb_main (args=0x0) at /usr/src/gnu/usr.bin/gdb/libgdb/../../../../contrib/gdb/gdb/main.c:814
#20 0x080710bd in main (argc=0, argv=0x0) at /usr/src/gnu/usr.bin/gdb/gdb/../../../../contrib/gdb/gdb/gdb.c:35
(gdb)
在螳螂版gdb和黄雀版gdb之间发生的其它故事,就跟普通的gdb调试一摸一样了。

7、用黄雀版gdb调试螳螂版kgdb
调试螳螂版kgdb和调试螳螂版gdb的方法大同小异。在我们前面的编译过程中,在生成螳螂版gdb的同时,也会在/usr/obj/usr/src/gnu/usr.bin/gdb/kgdb目录下生成螳螂版kgdb。

至于如何使用kgdb通过串口调试远程FreeBSD机器,我已经在另外一篇文章中进行了介绍(http://bbs.chinaunix.net/viewthread.php?tid=822692&extra=page%3D1 )。此处假设目标机已经准备就绪,我们直接使用螳螂版kgdb调试目标机:

#
# /usr/obj/usr/src/gnu/usr.bin/gdb/kgdb/kgdb -r /dev/cuad0 /usr/src/sys/i386/compile/DEBUG_KERNEL/kernel.debug
[GDB will not be able to debug user-mode threads: /usr/lib/libthread_db.so: Undefined symbol "ps_pglobal_lookup"]
GNU gdb 6.1.1 [FreeBSD]
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i386-marcel-freebsd".
Switching to remote protocol
kdb_enter (msg=0x2a "") at ../../../kern/subr_kdb.c:270
270     }
#0  kdb_enter (msg=0x2a "") at ../../../kern/subr_kdb.c:270
270     }
(kgdb)
然后在另外一个终端中查看螳螂版kgdb的PID,并通过黄雀版gdb对其进行调试,在发送远程gdb RSP协议包的函数remote_send()处设置断点,然后继续螳螂版kgdb的运行:

#
# ps
......
  PID  TT  STAT      TIME COMMAND
2725  p0  I+     0:04.53 /usr/obj/usr/src/gnu/usr.bin/gdb/kgdb/kgdb -r /dev/cuad0 /usr/src/sys/i386/compile/DEBUG_KERNEL/kernel.de
......
#
# gdb -p 2725 /usr/obj/usr/src/gnu/usr.bin/gdb/kgdb/kgdb
GNU gdb 6.1.1 [FreeBSD]
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i386-marcel-freebsd"...
Attaching to program: /usr/obj/usr/src/gnu/usr.bin/gdb/kgdb/kgdb, process 2725
Reading symbols from /lib/libkvm.so.3...done.
Loaded symbols for /lib/libkvm.so.3
Reading symbols from /lib/libm.so.4...done.
Loaded symbols for /lib/libm.so.4
Reading symbols from /lib/libreadline.so.6...done.
Loaded symbols for /lib/libreadline.so.6
Reading symbols from /lib/libncurses.so.6...done.
Loaded symbols for /lib/libncurses.so.6
Reading symbols from /usr/lib/libgnuregex.so.3...done.
Loaded symbols for /usr/lib/libgnuregex.so.3
Reading symbols from /lib/libc.so.6...done.
Loaded symbols for /lib/libc.so.6
Reading symbols from /libexec/ld-elf.so.1...done.
Loaded symbols for /libexec/ld-elf.so.1
0x283717dd in read () from /lib/libc.so.6
(gdb)
(gdb) b remote_send
Breakpoint 1 at 0x80962ed: file /usr/src/gnu/usr.bin/gdb/libgdb/../../../../contrib/gdb/gdb/remote.c, line 3895.
(gdb) c
Continuing.
转到螳螂版kgdb的终端,我们执行一个s(单步)命令。注意,我们现在是在调试远程机器,因此我们在螳螂版kgdb中输入的这些运行控制命令都要以gdb RSP协议包的方式发送给目标机处理,因此就会触发我们在黄雀版gdb中给它设置的断点。

(kgdb) s
[New Thread 0]
现在,螳螂版kgdb已经因为遇到断点而失去了响应,我们转到黄雀版gdb的终端,看到以下信息:

(gdb) c
Continuing.

Breakpoint 1, remote_send (buf=0x824ecb0 "p\006&\b", sizeof_buf=8)
    at /usr/src/gnu/usr.bin/gdb/libgdb/../../../../contrib/gdb/gdb/remote.c:3895
3895      putpkt (buf);
(gdb)
我们单步跟踪进去,然后查看remote_send()函数的入参buf中的内容:

(gdb) s
3894    {
(gdb) s
3895      putpkt (buf);
(gdb) x/8bx buf  
0xbfbfd850:     0x67    0x00    0x07    0x08    0x08    0xf5    0x37    0x28
(gdb)
remote_send()的入参buf中的内容就是要发送给目标机的RSP协议包的数据部分,这是一个字符串。我们可以看到,这个字符串的长度只有一个字节,数值为0x67,这是字母g的ascii值。根据RSP协议,字符g表示调试机向目标机请求所有通用寄存器的内容。实际上,对于一个s命令而言,也会触发调试机和目标机之间的多次RSP协议交互,这里给出的只是其中的一次而已。剩下的工作就是据此进行RSP协议数据和gdb源代码的分析了。限于篇幅,本文就此打住。
 (本文已被浏览 3981 次)
 发布人:sdccf
 → 推荐给我的好友
上篇文章:使用SCO OpenServer 5.0.X通过AD...
下篇文章:部分双核处理器平台无法正确安装OSR6的解决办法
 相关文章:
GDB使用手册 UNIX开发系统程序调试例举
用gdb调试ncurses程序 GDB调试精粹及使用实例
Linux世界驰骋—Linux常用实用工具(1) 在Redhat Linux上安装 GCC 编译器过程
Linux程序应用开发环境和工具经验谈 gcc使用手册(4)
gcc使用手册(3) gcc使用手册(2)
gcc使用手册(1) GDB使用文档
Linux程序应用开发环境和工具经验谈 用gdb调试程序
用gdb调式Linux软件 用gdb调式c程序
gdb的基本用法 用 gdb 调试 C 程序
用GDB调试程序

相关搜索
查看百度中关于使用gdb调试gdb/kgdb的方法与示例的更多内容
查看google中关于使用gdb调试gdb/kgdb的方法与示例的更多内容
   文章分类
操作系统 |
SCO_UNIX  Sun_Solaris  IBM_AIX  HP_UX  Linux  BSD  Tru64_UNIX 
通用UNIX知识  Windows  Minix 
程序设计 |
Shell编程  C/C++  汇编  PHP  JAVA  Perl  Python 
ASP/HTML  XML  中间件 
数据库 |
Oracle  Informix  Sybase  Fox  DB2  SQL  MySQL 
PostgreSQL 
网络应用 |
网络应用 
计算机硬件 |
计算机主机  打印机  路由器  交换机  终端  磁带机  MO 
刻录机  终端服务器  调制解调器 
   文章评论
  → 评论内容 (点击查看)   共0条评论,每页显示5条评论   浏览所有评论
(没有相关评论)
  → 发表我的评论
您的姓名: 您的Email:
评论内容:
250字内
发表评论:      发表评论须知 →
  • 尊重网上道德,遵守《全国人大常委会关于维护互联网安全的决定》及中华人民共和国其他各项有关法律法;
  • 本站有权保留或删除您发表的任何评论内容;
  • 关于我们 ┋  网站留言 ┋  网站地图 ┋  友情链接 ┋  与我在线 ┋  汇款确认 ┋  管理 ┋  TOP
    Linux.Unix爱好者家园  http://www.unix-cd.com/
    联系我们:sdccf@163.com
    腾讯QQ: 7644599
    备案序号:鲁ICP备05000455号
    Copyright (c) 2001-2008 Unix-cd.com. All Rights Reserved.