揭开Linux系统内核调试器的神秘面纱(四)
时间:2007-05-22 来源:lingfen1552
chown -R root /lib/modules/2.4.17
lilo[/code:1:627becdd94]
现在我们可以通过改为使用内核源代码树开始的目录来启动开发机器上的 gdb 程序了。在本示例中,内核源代码树位于 /usr/src/linux-2.4.17。输入 gdb 启动程序。
如果一切正常,测试机器将在启动过程中停止。输入 gdb 命令 cont 以继续启动过程。一个常见的问题是,空调制解调器电缆可能会被连接到错误的串口。如果 gdb 不启动,将端口改为第二个串口,这会使 gdb 启动。
[color=darkblue:627becdd94]使用 kgdb 调试内核问题[/color:627becdd94]
清单 8 列出了 jfs_mount.c 文件的源代码中被修改过的代码,我们在代码中创建了一个空指针异常,从而使代码在第 109 行产生段错误。
清单 8. 修改过后的 jfs_mount.c 代码
[code:1:627becdd94]int jfs_mount(struct super_block *sb)
{
...
int ptr; /* line 1 added */
jFYI(1, ("
Mount JFS
"));
/ *
* read/validate superblock
* (initialize mount inode from the superblock)
* /
if ((rc = chkSuper(sb))) {
goto errout20;
}
108 ptr=0; /* line 2 added */
109 printk("%d
",*ptr); /* line 3 added */[/code:1:627becdd94]
清单 9 在向文件系统发出 mount 命令之后显示一个 gdb 异常。kgdb 提供了几条命令,如显示数据结构和变量值以及显示系统中的所有任务处于什么状态、它们驻留在何处、它们在哪些地方使用了 CPU 等等。清单 9 将显示回溯跟踪为该问题提供的信息;where 命令用来执行反跟踪,它将告诉被执行的调用在代码中的什么地方停止。
清单 9. gdb 异常和反跟踪
[code:1:627becdd94]mount -t jfs /dev/sdb /jfs
Program received signal SIGSEGV, Segmentation fault.
jfs_mount (sb=0xf78a3800) at jfs_mount.c:109
109 printk("%d
",*ptr);
(gdb)where
#0 jfs_mount (sb=0xf78a3800) at jfs_mount.c:109
#1 0xc01a0dbb in jfs_read_super ... at super.c:280
#2 0xc0149ff5 in get_sb_bdev ... at super.c:620
#3 0xc014a89f in do_kern_mount ... at super.c:849
#4 0xc0160e66 in do_add_mount ... at namespace.c:569
#5 0xc01610f4 in do_mount ... at namespace.c:683
#6 0xc01611ea in sys_mount ... at namespace.c:716
#7 0xc01074a7 in system_call () at af_packet.c:1891
#8 0x0 in ?? ()
(gdb)[/code:1:627becdd94]
下一部分还将讨论这个相同的 JFS 段错误问题,但不设置调试器,如果您在非 kgdb 内核环境中执行清单 8 中的代码,那么它使用内核可能生成的 Oops 消息。
[color=darkblue:627becdd94]Oops 分析[/color:627becdd94]
Oops(也称 panic,慌张)消息包含系统错误的细节,如 CPU 寄存器的内容。在 Linux 中,调试系统崩溃的传统方法是分析在发生崩溃时发送到系统控制台的 Oops 消息。一旦您掌握了细节,就可以将消息发送到 ksymoops 实用程序,它将试图将代码转换为指令并将堆栈值映射到内核符号。在很多情况下,这些信息就足够您确定错误的可能原因是什么了。请注意,Oops 消息并不包括核心文件。
让我们假设系统刚刚创建了一条 Oops 消息。作为编写代码的人,您希望解决问题并确定什么导致了 Oops 消息的产生,或者您希望向显示了 Oops 消息的代码的开发者提供有关您的问题的大部分信息,从而及时地解决问题。Oops 消息是等式的一部分,但如果不通过 ksymoops 程序运行它也于事无补。下面的图显示了格式化 Oops 消息的过程。
[color=darkblue:627becdd94]格式化 Oops 消息[/color:627becdd94]见附图
ksymoops 需要几项内容:Oops 消息输出、来自正在运行的内核的 System.map 文件,还有 /proc/ksyms、 vmlinux 和 /proc/modules。关于如何使用 ksymoops,内核源代码 /usr/src/linux/Documentation/oops-tracing.txt 中或 ksymoops 手册页上有完整的说明可以参考。Ksymoops 反汇编代码部分,指出发生错误的指令,并显示一个跟踪部分表明代码如何被调用。
首先,将 Oops 消息保存在一个文件中以便通过 ksymoops 实用程序运行它。清单 10 显示了由安装 JFS 文件系统的 mount 命令创建的 Oops 消息,问题是由清单 8 中添加到 JFS 安装代码的那三行代码产生的。
清单 10. ksymoops 处理后的 Oops 消息
[code:1:627becdd94]ksymoops 2.4.0 on i686 2.4.17. Options used
... 15:59:37 sfb1 kernel: Unable to handle kernel NULL pointer dereference at
virtual address 0000000
... 15:59:37 sfb1 kernel: c01588fc
... 15:59:37 sfb1 kernel: *pde = 0000000
... 15:59:37 sfb1 kernel: Oops: 0000
... 15:59:37 sfb1 kernel: CPU: 0
... 15:59:37 sfb1 kernel: EIP: 0010:[jfs_mount+60/704]
... 15:59:37 sfb1 kernel: Call Trace: [jfs_read_super+287/688]
lilo[/code:1:627becdd94]
现在我们可以通过改为使用内核源代码树开始的目录来启动开发机器上的 gdb 程序了。在本示例中,内核源代码树位于 /usr/src/linux-2.4.17。输入 gdb 启动程序。
如果一切正常,测试机器将在启动过程中停止。输入 gdb 命令 cont 以继续启动过程。一个常见的问题是,空调制解调器电缆可能会被连接到错误的串口。如果 gdb 不启动,将端口改为第二个串口,这会使 gdb 启动。
[color=darkblue:627becdd94]使用 kgdb 调试内核问题[/color:627becdd94]
清单 8 列出了 jfs_mount.c 文件的源代码中被修改过的代码,我们在代码中创建了一个空指针异常,从而使代码在第 109 行产生段错误。
清单 8. 修改过后的 jfs_mount.c 代码
[code:1:627becdd94]int jfs_mount(struct super_block *sb)
{
...
int ptr; /* line 1 added */
jFYI(1, ("
Mount JFS
"));
/ *
* read/validate superblock
* (initialize mount inode from the superblock)
* /
if ((rc = chkSuper(sb))) {
goto errout20;
}
108 ptr=0; /* line 2 added */
109 printk("%d
",*ptr); /* line 3 added */[/code:1:627becdd94]
清单 9 在向文件系统发出 mount 命令之后显示一个 gdb 异常。kgdb 提供了几条命令,如显示数据结构和变量值以及显示系统中的所有任务处于什么状态、它们驻留在何处、它们在哪些地方使用了 CPU 等等。清单 9 将显示回溯跟踪为该问题提供的信息;where 命令用来执行反跟踪,它将告诉被执行的调用在代码中的什么地方停止。
清单 9. gdb 异常和反跟踪
[code:1:627becdd94]mount -t jfs /dev/sdb /jfs
Program received signal SIGSEGV, Segmentation fault.
jfs_mount (sb=0xf78a3800) at jfs_mount.c:109
109 printk("%d
",*ptr);
(gdb)where
#0 jfs_mount (sb=0xf78a3800) at jfs_mount.c:109
#1 0xc01a0dbb in jfs_read_super ... at super.c:280
#2 0xc0149ff5 in get_sb_bdev ... at super.c:620
#3 0xc014a89f in do_kern_mount ... at super.c:849
#4 0xc0160e66 in do_add_mount ... at namespace.c:569
#5 0xc01610f4 in do_mount ... at namespace.c:683
#6 0xc01611ea in sys_mount ... at namespace.c:716
#7 0xc01074a7 in system_call () at af_packet.c:1891
#8 0x0 in ?? ()
(gdb)[/code:1:627becdd94]
下一部分还将讨论这个相同的 JFS 段错误问题,但不设置调试器,如果您在非 kgdb 内核环境中执行清单 8 中的代码,那么它使用内核可能生成的 Oops 消息。
[color=darkblue:627becdd94]Oops 分析[/color:627becdd94]
Oops(也称 panic,慌张)消息包含系统错误的细节,如 CPU 寄存器的内容。在 Linux 中,调试系统崩溃的传统方法是分析在发生崩溃时发送到系统控制台的 Oops 消息。一旦您掌握了细节,就可以将消息发送到 ksymoops 实用程序,它将试图将代码转换为指令并将堆栈值映射到内核符号。在很多情况下,这些信息就足够您确定错误的可能原因是什么了。请注意,Oops 消息并不包括核心文件。
让我们假设系统刚刚创建了一条 Oops 消息。作为编写代码的人,您希望解决问题并确定什么导致了 Oops 消息的产生,或者您希望向显示了 Oops 消息的代码的开发者提供有关您的问题的大部分信息,从而及时地解决问题。Oops 消息是等式的一部分,但如果不通过 ksymoops 程序运行它也于事无补。下面的图显示了格式化 Oops 消息的过程。
[color=darkblue:627becdd94]格式化 Oops 消息[/color:627becdd94]见附图
ksymoops 需要几项内容:Oops 消息输出、来自正在运行的内核的 System.map 文件,还有 /proc/ksyms、 vmlinux 和 /proc/modules。关于如何使用 ksymoops,内核源代码 /usr/src/linux/Documentation/oops-tracing.txt 中或 ksymoops 手册页上有完整的说明可以参考。Ksymoops 反汇编代码部分,指出发生错误的指令,并显示一个跟踪部分表明代码如何被调用。
首先,将 Oops 消息保存在一个文件中以便通过 ksymoops 实用程序运行它。清单 10 显示了由安装 JFS 文件系统的 mount 命令创建的 Oops 消息,问题是由清单 8 中添加到 JFS 安装代码的那三行代码产生的。
清单 10. ksymoops 处理后的 Oops 消息
[code:1:627becdd94]ksymoops 2.4.0 on i686 2.4.17. Options used
... 15:59:37 sfb1 kernel: Unable to handle kernel NULL pointer dereference at
virtual address 0000000
... 15:59:37 sfb1 kernel: c01588fc
... 15:59:37 sfb1 kernel: *pde = 0000000
... 15:59:37 sfb1 kernel: Oops: 0000
... 15:59:37 sfb1 kernel: CPU: 0
... 15:59:37 sfb1 kernel: EIP: 0010:[jfs_mount+60/704]
... 15:59:37 sfb1 kernel: Call Trace: [jfs_read_super+287/688]
相关阅读 更多 +
排行榜 更多 +