ChinaUnix.net 首页 | 博客 | Linux | 论坛 | 人才 | 培训 | 知识库 | 资料 | 读书 | 手册 | 精华 | 下载 | 沙龙 | 搜索
Linux首页 | Linux论坛 | 论坛精华 | 开源新闻 | 技术文章 | 专题专栏 | 新手指南 | 迁移方案 | 产品方案 | 开源项目 | 开源图书 | 软件下载 | 人才招聘 | Linux博客
  搜索

  产品与方案
·中科红旗全面打造现代化邮政体系
·红旗助力“网上审批服务” 推动电子政务
·红旗正版化开创呼和浩特网吧建设新起点
·红旗Linux助信息产业部邮件服务器“快跑”
·中标普华Linux 为电子政务信息化保驾护航
·中标普华Linux助力基金产业
·中标普华Office率先支持UOF标准
·中标普华邮件系统助力西藏政府信息化建设
·红旗Linux助力国库集中支付系统改革
·红旗助中信卫星 掀起GIS通信应用风暴
·红旗软件助力烟草总局 全面建设“数字烟草”
·红旗助力“信访阳光工程”打造畅通信访渠道
·红帽联合FIS发布下一代实时核心银行平台
·红旗助力金盾 打造全无忧出入境信息系统
·红旗Linux全力打造中国邮政总局名址信息库
·爱尔兰证交所从Unix迁移到红帽企业Linux
·一流的意大利银行选择使用红帽企业Linux
·PLUS Finanzservice选择使用红帽企业Linux
·红帽助力TransACT Communications 公司
·法国零售业巨头Lapeyre采用Redhat Linux
·旅游预订网站选择使用红帽企业Linux
·马哈拉施特拉邦政府的红帽解决之道
·美国联邦政府案例
·红帽为慕尼黑展览会提供现代化集群系统
·Yuba郡用开源软件和红帽产品提高了效率
·红帽企业Linux助印度理工建立高性能计算中心
·采用红帽Linux 将系统维护时间缩短了65%
·从UNIX迁移到Linux使Peñoles公司获益非浅
·Hikal公司用红帽企业Linux开展任务关键的ERP项目
·KDE3.5.4新版本发布
·芝加哥商业交易所从Unix向Linux迁移
·南方基金管理有限公司成功案例 Red Hat Linux
·广东北电通讯设备有限公司成功案例
·挪威国家石油公司从UNIX迁移到红帽Linux,成本减半
·中央电视台CCTV动画部案例 Red Hat Linux

  图书

鸟哥的Linux私房菜基础学..


Linux程序设计.第3版


Linux设备驱动开发详解


  下载
·Endian Firewall
·linux kernel(Linux 内核)
·CentOS
·Fedora Core 6
·Scientific Linux
·Slackware 11.0
·Gentoo Linux
·ubuntu-6.10-i386服务器版本
·ubuntu-6.10-amd64服务器版
·ubuntu-6.10-i386桌面版
·ubuntu-6.10-amd64桌面版
·Engarde Linux
您的位置: Linux时代 > 技术文档 > 内核研究 >

使用kgdb调试linux内核及内核模块

日期:2006-08-03 作者:xcspy.com_at_gmail.com 来自:xfocus


1. 几种内核调试工具比较

kdb:只能在汇编代码级进行调试;
     优点是不需要两台机器进行调试。

gdb:在调试模块时缺少一些至关重要的功能,它可用来查看内核的运行情况,包括反汇编内核函数。

kgdb:能很方便的在源码级对内核进行调试,缺点是kgdb只能进行远程调试,它需要一根串口线及两台机器来调试内核(也可以是在同一台主机上用vmware软件运行两个操作系统来调试)

使用kdb和gdb调试内核的方法相对比较简单,这里只描述如何使用kgdb来调试内核。

2.软硬件准备

环境:
一台开发机developer(192.168.16.5 com1),一台测试机target(192.168.16.30 com2),都预装redhat 9;一根串口线

下载以下软件包:
linux内核2.4.23         linux-2.4.23.tar.bz2
kgdb内核补丁1.9版       linux-2.4.23-kgdb-1.9.patch
可调试内核模块的gdb     gdbmod-1.9.bz2

3.ok,开始

3.1 测试串口线
物理连接好串口线后,使用一下命令进行测试,stty可以对串口参数进行设置

在developer上执行:
stty ispeed 115200 ospeed 115200 -F /dev/ttyS0
echo hello > /dev/ttyS0
在target上执行:
stty ispeed 115200 ospeed 115200 -F /dev/ttyS1
cat /dev/ttyS1

串口线没问题的话在target的屏幕上显示hello

3.2 安装与配置

3.2.1 安装

下载linux-2.4.23.tar.bz2,linux-2.4.23-kgdb-1.9.patch,gdbmod-1.9.bz2到developer的/home/liangjian目录

*在developer机器上

#cd /home/liangjian
#bunzip2 linux-2.4.23.tar.bz2
#tar -xvf linux-2.4.23.tar
#bunzip2 gdbmod-1.9.bz2
#cp gdbmod-1.9 /usr/local/bin
#cd linux-2.4.23
#patch -p1 < ../linux-2.4.23-kgdb-1.9.patch
#make menuconfig

在Kernel hacking配置项中将以下三项编译进内核
KGDB: Remote (serial) kernel debugging with gdb
KGDB: Thread analysis
KGDB: Console messages through gdb

注意在编译内核的时候需要加上-g选项
#make dep;make bzImage

使用scp进行将相关文件拷贝到target上(当然也可以使用其它的网络工具)
#scp arch/i386/boot/bzImage root@192.168.16.30:/boot/vmlinuz-2.4.23-kgdb
#scp System.map root@192.168.16.30:/boot/System.map-2.4.23-kgdb
#scp arch/i386/kernel/gdbstart  root@192.168.16.30:/sbin
gdbstart为kgdb提供的一个工具,用于激活内核钩子,使内核处于调试状态

3.2.2 配置

*在developer机器上

在内核源码目录下编辑一文件.gdbinit(该文件用以对gdb进行初始化),内容如下:
#vi .gdbinit
define rmt
set remotebaud 115200
target remote /dev/ttyS0
end
#
以上在.gdbinit中定义了一个宏rmt,该宏主要是设置使用的串口号和速率

*在target机器上

编辑/etc/grub.conf文件,加入以下行:
#vi /etc/grub.conf
title Red Hat Linux (2.4.23-kgdb)
    root (hd0,0)
    kernel /boot/vmlinuz-2.4.23-kgdb ro root=/dev/hda1
#

在root目录下建立一个脚本文件debugkernel,内容如下:
#vi debug
#!/bin/bash
gdbstart -s 115200 -t /dev/ttyS1 <<EOF

EOF
#chmod +x debugkernel
这个脚本主要是调用gdbstart程序设置target机上使用的串口及其速率,并使内核处于调试状态

3.3 开始调试

target上的内核或内核模块处于调试状态时,可以查看其变量、设置断点、查看堆栈等,并且是源码级的调试,和用gdb调试用户程序一样

3.3.1 内核启动后调试

*在target机器上

重启系统,选择以 2.4.23-kgdb内核启动,启动完成后运行debugkenel,
这时内核将停止运行,在控制台屏幕上显示信息,并等待来自developer的
串口连接

#./debug
About to activate GDB stub in the kernel on /dev/ttyS1
Waiting for connection from remote gdb...

*在developer机器上

#cd /home/liangjian/linux-2.4.23
# gdb vmlinux
GNU gdb Red Hat Linux (5.3post-0.20021129.18rh)
Copyright 2003 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-redhat-linux-gnu"...

执行rmt宏
(gdb) rmt
breakpoint () at kgdbstub.c:1005
1005                    atomic_set(&kgdb_setting_breakpoint, 0);

这时target上的内核处于调试状态,可以查看其变量、设置断点、查看堆栈等,和用gdb调试用户程序一样

查看堆栈
(gdb) bt
#0  breakpoint () at kgdbstub.c:1005
#1  0xc0387f48 in init_task_union ()
#2  0xc01bc867 in gdb_interrupt (irq=3, dev_id=0x0, regs=0xc0387f98) at
gdbserial.c:158
#3  0xc010937b in handle_IRQ_event (irq=3, regs=0xc0387f98, action=0xce5a9860)
at irq.c:452
#4  0xc0109597 in do_IRQ (regs=
      {ebx = -1072671776, ecx = -1, edx = -1070047232, esi = -1070047232, edi
= -1070047232, ebp = -1070039092, eax = 0, xds
= -1070071784, xes = -1070071784, orig_eax = -253, eip = -1072671729, xcs =
16, eflags = 582, esp = -1070039072, xss = -1072671582}) at irq.c:639
#5  0xc010c0e8 in call_do_IRQ ()

查看jiffies变量的值
(gdb) p jiffies
$1 = 76153

如果想让target上的内核继续运行,执行continue命令
(gdb) continue
Continuing.

3.3.2 内核在引导时调试

kgdb可以在内核引导时就对其进行调试,但并不是所有引导过程都是可调试的,如在kgdb 1.9版中,它在init/main.c的start_kernel()函数中插入以下代码:
start_kernel()
{
    ......
        smp_init();
#ifdef CONFIG_KGDB
        if (gdb_enter) {
                gdb_hook();             /* right at boot time */
        }
#endif
    ......
}

所以在smp_init()之前的初始化引导过程是不能调试的。

另外要想让target的内核在引导时就处于调试状态,需要修改其/etc/grub.conf文件为如下形式:
title Red Hat Linux (2.4.23-kgdb)
    root (hd0,0)
    kernel /boot/vmlinuz-2.4.23-kgdb ro root=/dev/hda1 gdb gdbttyS=1 gdbbaud=115200

*在target机器上

引导2.4.23-kgdb内核,内核将在短暂的运行后暂停并进入调试状态,打印如下信息:
Waiting for connection from remote gdb...

*在developer机器上

#cd /home/liangjian/linux-2.4.23
# gdb vmlinux
GNU gdb Red Hat Linux (5.3post-0.20021129.18rh)
Copyright 2003 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-redhat-linux-gnu"...

执行rmt宏
(gdb) rmt
breakpoint () at kgdbstub.c:1005
1005                    atomic_set(&kgdb_setting_breakpoint, 0);

查看当前堆栈
(gdb) bt
#0  breakpoint () at kgdbstub.c:1005
#1  0xc0387fe0 in init_task_union ()
#2  0xc01bc984 in gdb_hook () at gdbserial.c:250
#3  0xc0388898 in start_kernel () at init/main.c:443

在do_basic_setup函数处设置断点,并让内核恢复运行
(gdb) b do_basic_setup
Breakpoint 1 at 0xc0388913: file current.h, line 9.
(gdb) continue
Continuing.
[New Thread 1]
[Switching to Thread 1]

Breakpoint 1, do_basic_setup () at current.h:9
9               __asm__("andl %%esp,%0; ":"=r" (current) : "0" (~8191UL));

内核在do_basic_setup断点处停止运行后查看当前堆栈
(gdb) bt
#0  do_basic_setup () at current.h:9
(gdb)

3.3.3 内核模块调试调试

要想调试内核模块,需要相应的gdb支持,kgdb的主页上提供了一个工具gdbmod,它修正了gdb 6.0在解析模块地址时的错误,可以用来正确的调试内核模块

*在developer机器上

写了个测试用的内核模块orig,如下:
void xcspy_func()
{
    printk("<1>xcspy_func\n");
    printk("<1>aaaaaaaaaaa\n");
}

int xcspy_init()
{
    printk("<1>xcspy_init_module\n");
        
    return 0;
}

void xcspy_exit()
{
    printk("<1>xcspy_cleanup_module\n");
}

module_init(xcspy_init);
module_exit(xcspy_exit);

编译该模块:
#cd /home/liangjian/lkm
#gcc -D__KERNEL__ -DMODULE -I/home/liangjian/linux-2.4.23/include -O -Wall -g -c -o orig.o orig.c
#scp orig.o root@192.168.16.30:/root

开始调试:
# gdbmod vmlinux
GNU gdb 6.0
Copyright 2003 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 "i686-pc-linux-gnu"...

设置符号文件的搜索路径
(gdb) set solib-search-path /home/liangjian/lkm

执行rmt宏
(gdb) rmt
breakpoint () at kgdbstub.c:1005
1005                    atomic_set(&kgdb_setting_breakpoint, 0);

设置断点使得可以调试内核模块的init函数,查内核源码可知,内核是通过module.c文件的第566行(sys_init_module函数中)mod->init来调用模块的init函数的
(gdb) b module.c:566
Breakpoint 1 at 0xc011cd83: file module.c, line 566.
(gdb) c
Continuing.
[New Thread 1352]
[Switching to Thread 1352]

这时在target机器上执行insmod orig.o,developer则相应的在断点处被暂停,如下
                                                                                                                          
Breakpoint 1, sys_init_module (name_user=0xc03401bc "\001",
mod_user=0x80904d8) at module.c:566
566             if (mod->init && (error = mod->init()) != 0) {

使用step命令进入模块的init函数
(gdb) step
xcspy_init () at orig.c:12
12              printk("<1>xcspy_init_module\n");
(gdb) n
15      }
(gdb)

说明:
调试内核模块的非init函数相对比较简单,只要先在target上执行insmod orig.o,这时由于模块的符号被加载,可以直接在developer的gdb中对想调试的模块函数设置断点,如bt xcspy_func,后面当xcspy_func被调用时就进入了调试状态。
如果想调试内核模块的init函数,由于在执行insmod之前模块的符号还没有被加载,不能直接对模块的init函数设置断点,所以相对来说要困难一些。可以采用两种变通的方法:1,采用上面介绍的在内核调用模块的init函数被调用之前的某处插入断点,如bt sys_init_module()或bt module.c:566;2,在developer上让内核处于运行状态,在target上先执行一遍insmod orig.o,这时orig.o的符号已经被加载到内存中,可以直接在developer的gdb中对模块的init函数设置断点,如bt xcspy_init,然后在target上rmmod orig.o,当下次在target上重新加载orig.o时就进入了调试状态,developer在xcspy_init处被暂停。

原文链接:http://www.xfocus.net/articles/200509/820.html

本文被浏览



 相关新闻

遵守GPL Novell对Linux内核中专有代码说不2006-08-02 13:39:11
破解Linux内核2.62006-08-02 10:23:30
Jani Taskinen 离开了PHP内核开发团队!2006-07-31 17:37:56
Xen:用于Linux?内核的虚拟化技术简介2006-07-27 17:58:29
关于Linux内核级后门的原理和简单实战2006-01-20 14:08:34
Linux内核阅读工具--Source Insight2006-01-09 11:14:23
Linux 2.6.15内核发布2006-01-05 10:19:03


 相关评论
关于我们 | 联系方式 | 广告合作 | 诚聘英才 | 网站地图 | 免费注册

Copyright © 2001-2006 ChinaUnix.net All Rights Reserved

感谢所有关心和支持过ChinaUnix的朋友们

京ICP证041476号