• 沒有找到結果。

第 5 章 ARM LINUX 驱动程序开发入门

5.3 L INUX 驱动程序开发要点

5.3.5 内核调试

内核调试是驱动开发人员必须掌握的一项技能,和调试其他程序一样,内核也属于一种 特殊的程序。调试内核问题时,能够跟踪内核执行情况并查看其内存和数据结构是非常有用 的。Linux 中的内置内核调试器 KDB(Kernel Debugger 的缩写)提供了这种功能。Linux 内 核调试器(KDB)允许你调试 Linux 内核。这个恰如其名的工具实质上是内核代码的补丁,

它允许开发人员访问内核内存和数据结构。KDB 的主要优点之一就是它只需要用一台机器 就可以进行调试,比如你可以调试正在运行的内核。设置一台用于 KDB 的机器需要花费 一些工作,因为需要给内核打补丁并进行重新编译。KDB 的用户应当熟悉 Linux 内核的编 译(在一定程度上还要熟悉内核内部机理),KDB 项目是由 Silicon Graphics 维护的,需要 从它的 ftp://oss.sgi.com/www/projects/kdb/download/站点下载与内核版本有关的补丁。

5.3.5.1 准备内核调试环境

首先从上述的站点中下载并应用两个补丁,一个是公共的补丁,包含了对通用内核代码 的更改,另一个是特定于体系结构的补丁。目前可用最新的 KDB 版本是 4.4,以运行 2.6.10 内核的 x86 机器为例,需要下载 kdb-v4.4-2.6.10-common-1.bz2 和 kdb-v4.4-2.6.10-i386-1.bz2 文件。

接下来将这两个压缩补丁拷贝到/usr/src/linux 目录下,也就是你放内核源码的目录。然 后解压。

# bzip2 –d kdb-v4.4-2.6.10-common-1.bz2 # bzip2 –d kdb-v4.4-2.6.10-i386-1.bz2

执行上面的压缩命令将会生成 kdb-v4.4-2.6.10-common-1 和 kdb-v4.4-2.6.10-i386-1 两个 补丁文件。然后应用这两个补丁文件,具体命令如下:

# patch –p1 >kdb-v4.4-2.6.10-common-1

# patch –p1 >kdb-v4.4-2.6.10-i386-1

接下来需要构建内核以支持 KDB。第一步是设置 CONFIG_KDB 选项,使用你喜欢的 配置方法(make xconfig 和 make menuconfig 等)来完成这一步。选择“Kernel hacking”选 项并选择“Built-in Kernel Debugger support”选项。还可以根据自己的偏好选择其它两个选 项 。 选 择 “ Compile the kernel with frame pointers ” 选 项 ( 如 果 有 的 话 ) 则 设 置 CONFIG_FRAME_POINTER 标志。这将产生更好的堆栈回溯,因为帧指针寄存器被用作帧 指 针 而 不 是 通 用 寄 存 器 。 还 可 以 选 择 “ KDB off by default ” 选 项 。 这 将 设 置 CONFIG_KDB_OFF 标 志 , 并 且 在 缺 省 情况 下 将 关 闭 KDB。 如 果 编译 期 间 没有 选 中 CONFIG_KDB_OFF ,那么在缺省情况下 KDB 是活动的。否则,你需要显式地激活它,

可以通过在引导期间将 kdb=on 标志传递给内核或者通过在挂装了/proc 之后执行以下命令

激活:

# echo "1" >/proc/sys/kernel/kdb

相反,如果缺省情况下 KDB 是打开的,那么将 kdb=off 标志传递给内核或者执行下 面这个操作将会取消激活 KDB:

# echo "0" >/proc/sys/kernel/kdb

最后,保存配置,然后退出。重新编译内核。建议在构建内核之前执行“make clean”。

使用格式 1:md [vaddr [line-count [output-radix]] ] 其中显示地址为 vaddr 的内存的 内容。line-count 为要显示的内存的行数,output-radix 指定以 8 进制、10 进制或者 16 进制显示。如果省略 line-count 和 output-radix,那么将以设置的环境变量 MDCOUNT 和 RADIX 方式显示。如果不带任何参数,md 命令将接着上次 md 命

[0]kdb> md 0x1000000 10

mdr 命令带有地址或符号以及字节计数,显示从指定的地址开始的 count 字节数的 初始内存内容。它本质上和 md 一样,但是它不显示起始地址并且不在结尾显示 字符转换。mdr 命令较少使用。使用格式:mdr <vaddr> <count>

mm 命令修改内存内容。它以地址/符号和新内容作为参数,用 new-contents 替 换地址处的内容。使用格式:mm <vaddr> <new content>

mmW 命令更改从地址开始的 W 个字节。请注意, mm 更改一个机器字。使用

制寄存器。使用格式:rm <register-name> <register-content> 例如,修改 eax 寄存器 内容为 0x10,具体操作如下:

[0]kdb> rm %eax 0x10

ef 命令以一个地址作为参数,它显示指定地址处的异常帧。使用格式:ef <vaddr> 令可能会产生错误的结果。使用格式:bt [<stack-frame addr>]

btp 命令将进程标识作为参数,并对这个特定进程进行堆栈回溯。使用格式:btp

cpu 命令用于切换到另一个 CPU。使用格式:cpu <cpunum> 这条命令仅仅在 SMP 结构下有用,它切换到由 cpunum 指定的 CPU。

ps 命令用于显示所有活动的进程。使用格式:ps 显示当前的活动的进程。包括 pid、

ppid、CPU 号、当前状态,以及对应的线程。

reboot 命令用来重新启动机器。使用格式:reboot 在某些情况下,内核无法返回到 正常工作状态,这时可以利用 reboot 重新启动机器。注意在重启机器前,它不进 行任何状态保存的工作。

sections 命令列出内核中所有已知的段的信息。使用格式:sections 列出模块和内 核的所有已知的段的信息。首先是模块信息,最后是内核信息。包括模块名和一个 或者多个段的信息。段信息包括段名、段起始地址、段结束地址和段标识。本命令 仅仅是为外部调试器而设立的。

sr 命令激活 SysRq 代码,也就是调用 MAGIC_SYSRQ 函数。格式:sr <sysrq key> 将 sysrq key 字符作为参数传递给 SysRq 函数进行处理,就像你已经键入了 SysRq 键 和该字符一样。如果要使用这个命令,需要在配置内核时,选择 Magic SysRq Key。

然后在新内核启动后,使用如下命令激活 SysRq 功能。

# echo “1” > /proc/sys/kernel/sysrq

这是一个功能强大的命令,它使得在 kdb 中可以使用操作系统提供的 SysRq 处理 函数。

lsmod 命令列出内核中加载的所有模块。使用格式:lsmod 显示所有模块的信息。

包括模块名、模块大小、模块结构地址、引用计数,以及被哪个模块所引用。

rmmod 命令卸载一个模块。使用格式:rmmod <modname> 将由 modname 指定的 模块从内核中卸载。

ll 命令对链表中的每个元素重复执行命令。使用格式:ll <addr> <link-offset> <cmd>

它对以地址 addr 开头的链表的头 link-offset 个元素,重复执行 cmd 命令。

help 和?命令显示帮助信息。使用格式:help 或者? 显示 kdb 的命令以及简单的 用法。

总之,KDB 是一个强大的内核调试工具,通常 GDB 需要两台机器通过串口才能进行调 试,而 KDB 只需要一台机器即可进行调试,对于普通用户来说,是非常方便的。对于编写 内核程序(如可加载模块)的程序员来说,KDB 提供的这些命令使得调试工作难度大大降 低,使得调试效率得以提高。另外对于内核感兴趣的读者可以使用 KDB 来查看内核的数据 结构和运行状态,从而加深对内核的理解。不足之处是 KDB 无法提供源码级的调试,要求 程序员有一定的汇编程序基础。但总的来说,KDB 提供了一种强有力的内核调试手段,值 得读者去学习和使用。