( 来自Linus Torvalds的讨论: https://groups.google.com/group/linux.kernel/browse_thread/thread/b70bffe9015a8c41/ed9c0a0cfcd31111 又,http://kerneltrap.org/Linux/Further_Oops_Insights ) 例如这样的一个Oops: Oops: 0000 [#1] PREEMPT SMP Modules linked in: capidrv kernelcapi isdn slhc ipv6 loop dm_multipath snd_ens1371 gameport snd_rawmidi snd_ac97_codec ac97_bus snd_seq_dummy snd_seq_oss snd_seq_midi_event snd_seq snd_seq_device snd_pcm_oss snd_mixer_oss snd_pcm snd_timer snd parport_pc floppy parport pcnet32 soundcore mii pcspkr snd_page_alloc ac i2c_piix4 i2c_core button power_supply sr_mod sg cdrom ata_piix libata dm_snapshot dm_zero dm_mirror dm_mod BusLogic sd_mod scsi_mod ext3 jbd mbcache uhci_hcd ohci_hcd ehci_hcd Pid: 1726, comm: kstopmachine Not tainted (2.6.24-rc3-module #2) EIP: 0060:[<c04e53d6>] EFLAGS: 00010092 CPU: 0 EIP is at list_del+0xa/0x61 EAX: e0c3cc04 EBX: 00000020 ECX: 0000000e EDX: dec62000 ESI: df6e8f08 EDI: 000006bf EBP: dec62fb4 ESP: dec62fa4 DS: 007b ES: 007b FS: 00d8 GS: 0000 SS: 0068 Process kstopmachine (pid: 1726, ti=dec62000 task=df8d2d40 task.ti=dec62000) Stack: 000006bf dec62fb4 c04276c7 00000020 dec62fbc c044ab4c dec62fd0 c045336c df6e8f08 c04532b4 00000000 dec62fe0 c043deb0 c043de75 00000000 00000000 c0405cdf df6e8eb4 00000000 00000000 00000000 00000000 00000000 Call Trace: [<c0406081>] show_trace_log_lvl+0x1a/0x2f [<c0406131>] show_stack_log_lvl+0x9b/0xa3 [<c04061dc>] show_registers+0xa3/0x1df [<c0406437>] die+0x11f/0x200 [<c0613cba>] do_page_fault+0x533/0x61a [<c06123ea>] error_code+0x72/0x78 [<c044ab4c>] __unlink_module+0xb/0xf [<c045336c>] do_stop+0xb8/0x108 [<c043deb0>] kthread+0x3b/0x63 [<c0405cdf>] kernel_thread_helper+0x7/0x10 ======================= Code: 6b c0 e8 2e 7e f6 ff e8 d1 16 f2 ff b8 01 00 00 00 e8 aa 1c f4 ff 89 d8 83 c4 10 5b 5d c3 90 90 90 55 89 e5 53 83 ec 0c 8b 48 04 <8b> 11 39 c2 74 18 89 54 24 08 89 44 24 04 c7 04 24 be 32 6b c0 EIP: [<c04e53d6>] list_del+0xa/0x61 SS:ESP 0068:dec62fa4 note: kstopmachine[1726] exited with preempt_count 1 1, 有自己编译的vmlinux: 使用gdb 编译时打开complie with debug info选项。 注意这行: EIP is at list_del+0xa/0x61 这告诉我们,list_del函数有0x61这么大,而Oops发生在0xa处。 那么我们先看一下list_del从哪里开始: # grep list_del /boot/System.map-2.6.24-rc3-module c10e5234 T plist_del c10e53cc T list_del c120feb6 T klist_del c12d6d34 r __ksymtab_list_del c12dadfc r __ksymtab_klist_del c12e1abd r __kstrtab_list_del c12e9d03 r __kstrtab_klist_del 于是我们知道,发生Oops时的EIP值是: c10e53cc + 0xa == c10e53d6 然后用gdb查看: # gdb /home/arc/build/linux-2.6/vmlinux (gdb) b *0xc10e53d6 Breakpoint 1 at 0xc10e53d6: file /usr/src/linux-2.6.24-rc3/lib/list_debug.c, line 64. 看,gdb直接就告诉你在哪个文件、哪一行了。 gdb中还可以这样: # gdb Sources/linux-2.6.24/vmlinux (gdb) l *do_fork+0x1f 0xc102b7ac is in do_fork (kernel/fork.c:1385). 1380 1381 static int fork_traceflag(unsigned clone_flags) 1382 { 1383 if (clone_flags & CLONE_UNTRACED) 1384 return 0; 1385 else if (clone_flags & CLONE_VFORK) { 1386 if (current->ptrace & PT_TRACE_VFORK) 1387 return PTRACE_EVENT_VFORK; 1388 } else if ((clone_flags & CSIGNAL) != SIGCHLD) { 1389 if (current->ptrace & PT_TRACE_CLONE) (gdb) 也可以直接知道line number。 或者: (gdb) l *(0xffffffff8023eaf0 + 0xff) /* 出错函数的地址加上偏移 */ 2, 没有自己编译的vmlinux: TIPS 如果在lkml或bugzilla上看到一个Oops,而自己不能重现,那就只能反汇编以"Code:"开始的行。 这样可以尝试定位到 源代码中。 注意,Oops中的Code:行,会把导致Oops的第一条指令,也就是EIP的值的第一个字节, 用尖括号<>括起来。 但是,有些 体系结构(例如常见的x86)指令是不等长的(不一样的指令可能有不一样的长度),所以要不断的尝试(trial-and-error)。 Linus通常使用一个小程序,类似这样: const char array[] = "/xnn/xnn/xnn..."; int main(int argc, char *argv[]) { printf("%p/n", array); *(int *)0 = 0; } e.g. /*{{{*/ /* 注意, array一共有从array[0]到array[64]这65个元素, 其中出错的那个操作码<8b> == arry[43] */ #include <stdio.h> #include <stdlib.h> const char array[] ="/x6b/xc0/xe8/x2e/x7e/xf6/xff/xe8/xd1/x16/xf2/xff/xb8/x01/x00/x00/x00/xe8/xaa/x1c/xf4/xff/x89/xd8/x83/xc4/x10/x5b/x5d/xc3/x90/x90/x90/x55/x89/xe5/x53/x83/xec/x0c/x8b/x48/x04/x8b/x11/x39/xc2/x74/x18/x89/x54/x24/x08/x89/x44/x24/x04/xc7/x04/x24/xbe/x32/x6b/xc0"; int main(int argc, char *argv[]) { printf("%p/n", array); *(int *)0 = 0; } /*}}}*/ 用gcc -g编译,在gdb里运行它: [arc@dhcp-cbjs05-218-251 ~]$ gdb hello GNU gdb Fedora (6.8-1.fc9) Copyright (C) 2008 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 "x86_64-redhat-linux-gnu"... (no debugging symbols found) (gdb) r Starting program: /home/arc/hello 0x80484e0 Program received signal SIGSEGV, Segmentation fault. 注意,这时候就可以反汇编0x80484e0这个地址: (gdb) disassemble 0x80484e0 Dump of assembler code for function array: 0x080484e0 <array+0>: imul $0xffffffe8,%eax,%eax 0x080484e3 <array+3>: jle,pn 0x80484dc <__dso_handle+20> 0x080484e6 <array+6>: ljmp *<internal disassembler error> 0x080484e8 <array+8>: rcll (%esi) 0x080484ea <array+10>: repnz (bad) 0x080484ec <array+12>: mov $0x1,%eax 0x080484f1 <array+17>: call 0x7f8a1a0 0x080484f6 <array+22>: mov %ebx,%eax 0x080484f8 <array+24>: add $0x10,%esp 0x080484fb <array+27>: pop %ebx 0x080484fc <array+28>: pop %ebp 0x080484fd <array+29>: ret 0x080484fe <array+30>: nop 0x080484ff <array+31>: nop 0x08048500 <array+32>: nop 0x08048501 <array+33>: push %ebp 0x08048502 <array+34>: mov %esp,%ebp 0x08048504 <array+36>: push %ebx 0x08048505 <array+37>: sub $0xc,%esp 0x08048508 <array+40>: mov 0x4(%eax),%ecx 0x0804850b <array+43>: mov (%ecx),%edx 0x0804850d <array+45>: cmp %eax,%edx 0x0804850f <array+47>: je 0x8048529 0x08048511 <array+49>: mov %edx,0x8(%esp) 0x08048515 <array+53>: mov %eax,0x4(%esp) 0x08048519 <array+57>: movl $0xc06b32be,(%esp) 0x08048520 <array+64>: add %ah,0xa70 End of assembler dump. (gdb) OK, 现在你知道出错的那条指令是array[43],也就是mov (%ecx),%edx,也就是说,(%ecx)指向了一个错误内存地址。 补充: 为了使汇编代码和C代码更好的对应起来, Linux内核的Kbuild子系统提供了这样一个功能: 任何一个C文件都可以单独编译成汇编文件,例如: make path/to/the/sourcefile.s 例如我想把kernel/sched.c编译成汇编,那么: make kernel/sched.s V=1 或者: make kernel/sched.lst V=1 编译出*.s文件 有时侯需要对*.s文件进行分析,以确定BUG所在的位置。 对任何一个内核build目录下的*.c文件,都可以 直接编译出*.s文件。 # make drivers/net/e100.s V=1 而对于自己写的module,就需要在Makefile中有一个灵活的target写法: # cat Makefile obj-m := usb-skel.o KDIR := /lib/modules/`uname -r`/build traget := modules default: make -C $(KDIR) M=$(shell pwd) $(target) clean: rm -f *.o *.ko .*.cmd *.symvers *.mod.c rm -rf .tmp_versions # make target=usb-skel.s V=1 这样,kbuild系统才知道你要make的目标不是modules,而是usb-skel.s。 另外, 内核源代码目录的./scripts/decodecode文件是用来解码Oops的: ./scripts/decodecode < Oops.txt (我没用过,就只提一下。) [ 本帖最后由 albcamus 于 2008-6-5 13:57 编辑 ] hongmy525 回复于:2008-06-02 11:15:12 学习了:) 好东西:em02: Guanqun 回复于:2008-06-02 13:52:41 我觉得要更自信的读懂这些东西,要先把汇编弄弄懂才行。 crspo 回复于:2008-06-02 20:59:33 好贴子,谢谢版主老大 W.Z.T 回复于:2008-06-02 22:08:03 我cao, 终于知道怎么定位具体的出错代码了, 顶! zx_wing 回复于:2008-06-02 23:08:41 引用:原帖由 albcamus 于 2008-6-2 11:04 发表 [url=http://linux.chinaunix.net/bbs/redirect.php?goto=findpost&pid=6603251&ptid=1008573] ![]() ( 来自Linus Torvalds的讨论: https://groups.google.com/group/linux.kernel/browse_thread/thread/b70bffe9015a8c41/ed9c0a0cfcd31111 又,http://kerneltrap.org/Linux/Further_Oops_Insights ) ... 哈哈,最后一个方法我也用过的,这简直是不得已的土手段。 当时是请一个朋友写了个脚本把项目里面所有可以dump的文件全objdump出来,有上百个.lst文件,把出错指令用grep搜,搜出的结果和这里反汇编出来出错指令前后的几条指令对比,找到出错的在哪个文件,再去看对应的c文件。 albcamus 回复于:2008-06-03 10:19:44 引用:原帖由 zx_wing 于 2008-6-2 23:08 发表 [url=http://linux.chinaunix.net/bbs/redirect.php?goto=findpost&pid=6603882&ptid=1008573] ![]() 哈哈,最后一个方法我也用过的,这简直是不得已的土手段。 当时是请一个朋友写了个脚本把项目里面所有可以dump的文件全objdump出来,有上百个.lst文件,把出错指令用grep搜,搜出的结果和这里反汇编出来出错 ... Andi Kleen回复这封邮件说, 他更推荐用kbuild 来make path/to/the/file.lst, 还有用scripts/decodecode来解码Oops ^_^ zx_wing 回复于:2008-06-03 13:00:14 引用:原帖由 albcamus 于 2008-6-3 10:19 发表 [url=http://linux.chinaunix.net/bbs/redirect.php?goto=findpost&pid=6604029&ptid=1008573] ![]() Andi Kleen回复这封邮件说, 他更推荐用kbuild 来make path/to/the/file.lst, 还有用scripts/decodecode来解码Oops ^_^ 这些高级东西都不会用啊,我觉得大多数时候我还在手工劳动。 al版要不出个教程?或者给个可以学习的连接和文档? anaconda 回复于:2008-06-03 13:32:13 我一直用crash来分析OOPS,很容易定位出错位置。 albcamus 回复于:2008-06-05 13:57:33 更新了一下内容, 设置为保留, 大家看看。 zx_wing 回复于:2008-06-05 14:09:38 如果有个自动objdump的功能就好了,因为编译生成的.s文件都没连接,好多地址都没替换,有时候不好用 12013396 回复于:2008-06-06 23:34:37 是打开编译选项 complie the kernel with debug info 但不知道,这个选项是什么时候出来的??? xiaojianredhat 回复于:2008-06-07 15:32:44 引用: ( 来自Linus Torvalds的讨论: https://groups.google.com/group/linux.kernel/browse_thread/thread/b70bffe9015a8c41/ed9c0a0cfcd31111 又,http://kerneltrap.org/Linux/Further_Oops_Insights ) 例如这样的一个Oops: Oops: 0000 [#1] PREEMPT SMP Modules linked in: capidrv kernelcapi isdn slhc ipv6 loop dm_multipath snd_ens1371 gameport snd_rawmidi snd_ac97_codec ac97_bus snd_seq_dummy snd_seq_oss snd_seq_midi_event snd_seq snd_seq_device snd_pcm_oss snd_mixer_oss snd_pcm snd_timer snd parport_pc floppy parport pcnet32 soundcore mii pcspkr snd_page_alloc ac i2c_piix4 i2c_core button power_supply sr_mod sg cdrom ata_piix libata dm_snapshot dm_zero dm_mirror dm_mod BusLogic sd_mod scsi_mod ext3 jbd mbcache uhci_hcd ohci_hcd ehci_hcd Pid: 1726, comm: kstopmachine Not tainted (2.6.24-rc3-module #2) EIP: 0060:[<c04e53d6>] EFLAGS: 00010092 CPU: 0 EIP is at list_del+0xa/0x61 EAX: e0c3cc04 EBX: 00000020 ECX: 0000000e EDX: dec62000 ESI: df6e8f08 EDI: 000006bf EBP: dec62fb4 ESP: dec62fa4 DS: 007b ES: 007b FS: 00d8 GS: 0000 SS: 0068 Process kstopmachine (pid: 1726, ti=dec62000 task=df8d2d40 task.ti=dec62000) Stack: 000006bf dec62fb4 c04276c7 00000020 dec62fbc c044ab4c dec62fd0 c045336c df6e8f08 c04532b4 00000000 dec62fe0 c043deb0 c043de75 00000000 00000000 c0405cdf df6e8eb4 00000000 00000000 00000000 00000000 00000000 Call Trace: [<c0406081>] show_trace_log_lvl+0x1a/0x2f [<c0406131>] show_stack_log_lvl+0x9b/0xa3 [<c04061dc>] show_registers+0xa3/0x1df [<c0406437>] die+0x11f/0x200 [<c0613cba>] do_page_fault+0x533/0x61a [<c06123ea>] error_code+0x72/0x78 [<c044ab4c>] __unlink_module+0xb/0xf [<c045336c>] do_stop+0xb8/0x108 [<c043deb0>] kthread+0x3b/0x63 [<c0405cdf>] kernel_thread_helper+0x7/0x10 ======================= Code: 6b c0 e8 2e 7e f6 ff e8 d1 16 f2 ff b8 01 00 00 00 e8 aa 1c f4 ff 89 d8 83 c4 10 5b 5d c3 90 90 90 55 89 e5 53 83 ec 0c 8b 48 04 <8b> 11 39 c2 74 18 89 54 24 08 89 44 24 04 c7 04 24 be 32 6b c0 EIP: [<c04e53d6>] list_del+0xa/0x61 SS:ESP 0068:dec62fa4 note: kstopmachine[1726] exited with preempt_count 1 1, 有自己编译的vmlinux: 使用gdb 编译时打开complie with debug info选项。 注意这行: EIP is at list_del+0xa/0x61 这告诉我们,list_del函数有0x61这么大,而Oops发生在0xa处。 那么我们先看一下list_del从哪里开始: # grep list_del /boot/System.map-2.6.24-rc3-module c10e5234 T plist_del c10e53cc T list_del c120feb6 T klist_del c12d6d34 r __ksymtab_list_del c12dadfc r __ksymtab_klist_del c12e1abd r __kstrtab_list_del c12e9d03 r __kstrtab_klist_del 于是我们知道,发生Oops时的EIP值是: c10e53cc + 0xa == c10e53d6 然后用gdb查看: # gdb /home/arc/build/linux-2.6/vmlinux (gdb) b *0xc10e53d6 Breakpoint 1 at 0xc10e53d6: file /usr/src/linux-2.6.24-rc3/lib/list_debug.c, line 64. 看,gdb直接就告诉你在哪个文件、哪一行了。 gdb中还可以这样: # gdb Sources/linux-2.6.24/vmlinux (gdb) l *do_fork+0x1f 0xc102b7ac is in do_fork (kernel/fork.c:1385). 1380 1381 static int fork_traceflag(unsigned clone_flags) 1382 { 1383 if (clone_flags & CLONE_UNTRACED) 1384 return 0; 1385 else if (clone_flags & CLONE_VFORK) { 1386 if (current->ptrace & PT_TRACE_VFORK) 1387 return PTRACE_EVENT_VFORK; 1388 } else if ((clone_flags & CSIGNAL) != SIGCHLD) { 1389 if (current->ptrace & PT_TRACE_CLONE) (gdb) 也可以直接知道line number。 或者: (gdb) l *(0xffffffff8023eaf0 + 0xff) /* 出错函数的地址加上偏移 */ 2, 没有自己编译的vmlinux: TIPS 如果在lkml或bugzilla上看到一个Oops,而自己不能重现,那就只能反汇编以"Code:"开始的行。 这样可以尝试定位到 源代码中。 注意,Oops中的Code:行,会把导致Oops的第一条指令,也就是EIP的值的第一个字节, 用尖括号<>括起来。 但是,有些 体系结构(例如常见的x86)指令是不等长的(不一样的指令可能有不一样的长度),所以要不断的尝试(trial-and-error)。 Linus通常使用一个小程序,类似这样: const char array[] = "/xnn/xnn/xnn..."; int main(int argc, char *argv[]) { printf("%p/n", array); *(int *)0 = 0; } e.g. /*{{{*/ /* 注意, array一共有从array[0]到array[64]这65个元素, 其中出错的那个操作码<8b> == arry[43] */ #include <stdio.h> #include <stdlib.h> const char array[] ="/x6b/xc0/xe8/x2e/x7e/xf6/xff/xe8/xd1/x16/xf2/xff/xb8/x01/x00/x00/x00/xe8/xaa/x1c/xf4/xff/x89/xd8/x83/xc4/x10/x5b/x5d/xc3/x90/x90/x90/x55/x89/xe5/x53/x83/xec/x0c/x8b/x48/x04/x8b/x11/x39/xc2/x74/x18/x89/x54/x24/x08/x89/x44/x24/x04/xc7/x04/x24/xbe/x32/x6b/xc0"; int main(int argc, char *argv[]) { printf("%p/n", array); *(int *)0 = 0; } /*}}}*/ 用gcc -g编译,在gdb里运行它: [arc@dhcp-cbjs05-218-251 ~]$ gdb hello GNU gdb Fedora (6.8-1.fc9) Copyright (C) 2008 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 "x86_64-redhat-linux-gnu"... (no debugging symbols found) (gdb) r Starting program: /home/arc/hello 0x80484e0 Program received signal SIGSEGV, Segmentation fault. 注意,这时候就可以反汇编0x80484e0这个地址: (gdb) disassemble 0x80484e0 Dump of assembler code for function array: 0x080484e0 <array+0>: imul $0xffffffe8,%eax,%eax 0x080484e3 <array+3>: jle,pn 0x80484dc <__dso_handle+20> 0x080484e6 <array+6>: ljmp *<internal disassembler error> 0x080484e8 <array+8>: rcll (%esi) 0x080484ea <array+10>: repnz (bad) 0x080484ec <array+12>: mov $0x1,%eax 0x080484f1 <array+17>: call 0x7f8a1a0 0x080484f6 <array+22>: mov %ebx,%eax 0x080484f8 <array+24>: add $0x10,%esp 0x080484fb <array+27>: pop %ebx 0x080484fc <array+28>: pop %ebp 0x080484fd <array+29>: ret 0x080484fe <array+30>: nop 0x080484ff <array+31>: nop 0x08048500 <array+32>: nop 0x08048501 <array+33>: push %ebp 0x08048502 <array+34>: mov %esp,%ebp 0x08048504 <array+36>: push %ebx 0x08048505 <array+37>: sub $0xc,%esp 0x08048508 <array+40>: mov 0x4(%eax),%ecx 0x0804850b <array+43>: mov (%ecx),%edx 0x0804850d <array+45>: cmp %eax,%edx 0x0804850f <array+47>: je 0x8048529 0x08048511 <array+49>: mov %edx,0x8(%esp) 0x08048515 <array+53>: mov %eax,0x4(%esp) 0x08048519 <array+57>: movl $0xc06b32be,(%esp) 0x08048520 <array+64>: add %ah,0xa70 End of assembler dump. (gdb) OK, 现在你知道出错的那条指令是array[43],也就是mov (%ecx),%edx,也就是说,(%ecx)指向了一个错误内存地址。 补充: 为了使汇编代码和C代码更好的对应起来, Linux内核的Kbuild子系统提供了这样一个功能: 任何一个C文件都可以单独编译成汇编文件,例如: make path/to/the/sourcefile.s 例如我想把kernel/sched.c编译成汇编,那么: make kernel/sched.s V=1 或者: make kernel/sched.lst V=1 编译出*.s文件 有时侯需要对*.s文件进行分析,以确定BUG所在的位置。 对任何一个内核build目录下的*.c文件,都可以 直接编译出*.s文件。 # make drivers/net/e100.s V=1 而对于自己写的module,就需要在Makefile中有一个灵活的target写法: # cat Makefile obj-m := usb-skel.o KDIR := /lib/modules/`uname -r`/build traget := modules default: make -C $(KDIR) M=$(shell pwd) $(target) clean: rm -f *.o *.ko .*.cmd *.symvers *.mod.c rm -rf .tmp_versions # make target=usb-skel.s V=1 这样,kbuild系统才知道你要make的目标不是modules,而是usb-skel.s。 另外, 内核源代码目录的./scripts/decodecode文件是用来解码Oops的: ./scripts/decodecode < Oops.txt (我没用过,就只提一下。) 不错,以前调试都是乱摸索 albcamus 回复于:2008-06-13 16:09:33 引用:原帖由 zx_wing 于 2008-6-5 14:09 发表 [url=http://linux.chinaunix.net/bbs/redirect.php?goto=findpost&pid=6606261&ptid=1008573] ![]() 如果有个自动objdump的功能就好了,因为编译生成的.s文件都没连接,好多地址都没替换,有时候不好用 你要的是不是: make kernel/sched.lst ? wifi 回复于:2008-06-19 15:34:27 好贴,留个影先,慢慢看。 cyq526 回复于:2008-06-24 18:15:23 [size=5]通过死机位置和栈信息查找死机所在模块[/size] RIP: 0010:[<ffffffff8016e5a9>] <ffffffff8016e5a9>{free_block+233} Call Trace: <IRQ><ffffffff8016e0ba>{cache_flusharray+138} <ffffffff8016e2c7>{kmem_cache_free+55} <ffffffff80168b14>{mempool_free+100} <ffffffff80192dc4>{bio_destructor+52} <ffffffff80192d79>{bio_put+57} <ffffffff8018f18a>{end_bio_bh_io_sync+58} <ffffffff80192e3d>{bio_endio+93} <ffffffff802858d6>{__end_that_request_first+550} <ffffffffa0006271>{:scsi_mod:scsi_end_request+129} <ffffffffa00065ee>{:scsi_mod:scsi_io_completion+670} <ffffffffa0000496>{:scsi_mod:scsi_finish_command+214} <ffffffffa0000e3a>{:scsi_mod:scsi_softirq+234} <ffffffff80142a23>{__do_softirq+83} <ffffffff80142ab5>{do_softirq+53} <ffffffff80113d2d>{do_IRQ+317} <ffffffff80110c0d>{ret_from_intr+0} <EOI> Code: 48 89 50 08 48 89 02 48 2b 7e 18 48 c7 06 00 01 10 00 48 c7 [size=6] 如何反汇编及定位死机所在代码[/size] #objdump -DSslt vmlinux > kernel-2.6.9-55.S ffffffff8016e58f: 00 ffffffff8016e590: 48 29 d0 sub %rdx,%rax ffffffff8016e593: 48 c1 e0 03 shl $0x3,%rax ffffffff8016e597: 48 03 81 e0 cc 00 00 add 0xcce0(%rcx),%rax ffffffff8016e59e: 48 8b 70 20 mov 0x20(%rax),%rsi ffffffff8016e5a2: 48 8b 56 08 mov 0x8(%rsi),%rdx ffffffff8016e5a6: 48 8b 06 mov (%rsi),%rax ffffffff8016e5a9: 48 89 50 08 mov %rdx,0x8(%rax) ffffffff8016e5ad: 48 89 02 mov %rax,(%rdx) ffffffff8016e5b0: 48 2b 7e 18 sub 0x18(%rsi),%rdi ffffffff8016e5b4: 48 c7 06 00 01 10 00 movq $0x100100,(%rsi) ffffffff8016e5bb: 48 c7 46 08 00 02 20 movq $0x200200,0x8(%rsi) ffffffff8016e5c2: 00 static inline void __list_del(struct list_head * prev, struct list_head * next) { ffffffff80152b1c: 48 8b 56 08 mov 0x8(%rsi),%rdx ffffffff80152b20: 48 8b 06 mov (%rsi),%rax include/linux/list.h:151 next->prev = prev; ffffffff80152b23: 48 89 50 08 mov %rdx,0x8(%rax) include/linux/list.h:152 prev->next = next; ffffffff80152b27: 48 89 02 mov %rax,(%rdx) mm/slab.c:2160 ffffffff80152b2a: 48 2b 4e 18 sub 0x18(%rsi),%rcx [size=5]反汇编出来的代码没有对应的源码怎么办?[/size] 修改Makefile或export CONFIG_DEBUG_INFO=1 ifdef CONFIG_DEBUG_INFO CFLAGS += -g endif # Use LINUXINCLUDE when you must reference the include/ directory. # Needed to be compatible with the O= option LINUXINCLUDE := -Iinclude / $(if $(KBUILD_SRC),-Iinclude2 -I$(srctree)/include) CPPFLAGS := -D__KERNEL__ $(LINUXINCLUDE) CFLAGS := -Wall -Wstrict-prototypes -Wno-trigraphs / -fno-strict-aliasing -fno-common AFLAGS := -D__ASSEMBLY__ [size=5] 死机信息分析[/size] Oops: 0002 [1] SMP CPU 2 Pid: 22827, comm: stress Tainted: GF U (2.6.5-7.244-smp SLES9_SP3_BRANCH-200512121832250000) RIP: 0010:[<ffffffff8016e5ad>] <ffffffff8016e5ad>{free_block+237} Oops:表示当前内核故障类型 002:页面错误码,表示内核试图写一个不存在的页面 [1]:死机计数器,记录册从上次系统重启以来的死机次数 CPU:表示系统运行故障时所在的CPU Pid:系统故障时,运行的进程 RIP:系统故障时,执行的指令位置 Tainted:表示内核被一些模块污染 寄存器和栈信息对深入分析故障原因有一定帮助。 [size=5]通过出错打印信息,在内核源码中查找出错位置[/size] 这种情况下为没有出错栈信息时用,多为非死机时内核打印出的故障信息,如文件系统只读、杀死进程。 Aborting journal on device mtdblock51. EXT3-fs error (device mtdblock51) in ext3_reserve_inode_write: Journal has aborted EXT3-fs error (device mtdblock51) in ext3_truncate: Journal has aborted EXT3-fs error (device mtdblock51) in ext3_delete_inode: IO failure EXT3-fs error (device mtdblock51) in ext3_reserve_inode_write: Journal has aborted EXT3-fs error (device mtdblock51) in ext3_orphan_del: Journal has aborted EXT3-fs error (device mtdblock51) in ext3_reserve_inode_write: Journal has aborted EXT3-fs error (device mtdblock51) in ext3_delete_inode: Journal has aborted ext3_abort called. EXT3-fs error (device mtdblock51): ext3_journal_start_sb: Detected aborted journal Remounting filesystem read-only __journal_remove_journal_head: freeing b_committed_data __journal_remove_journal_head: freeing b_committed_data __journal_remove_journal_head: freeing b_committed_data satfire 回复于:2008-07-02 21:17:33 mark.. 好帖. Godbach 回复于:2008-10-29 11:55:41 请教版主一个问题,如果是我自己写的内核模块程序,他的oops信息该如何解析。 OOPS最后一行的,EIP is at ********按照本帖提供的方法,该如何查找模块的BUG所在呢 [ 本帖最后由 Godbach 于 2008-10-29 11:56 编辑 ] albcamus 回复于:2008-10-29 12:28:27 $ grep sd_mod /proc/modules sd_mod 29504 11 - Live 0xffffffffa007c000 scsi_mod 163000 5 usb_storage,sr_mod,sg,libata,sd_mod, Live 0xffffffffa0053000 (gdb) add-symbol-files <path to your sd_mod.ko> 0xffffffffa007c000 Godbach 回复于:2008-10-29 13:39:30 引用:原帖由 albcamus 于 2008-10-29 12:28 发表 [url=http://linux.chinaunix.net/bbs/redirect.php?goto=findpost&pid=6799138&ptid=1008573] ![]() $ grep sd_mod /proc/modules sd_mod 29504 11 - Live 0xffffffffa007c000 scsi_mod 163000 5 usb_storage,sr_mod,sg,libata,sd_mod, Live 0xffffffffa0053000 (gdb) add-symbol-files 0xffffffffa007c000 多谢斑竹指点。 引用:(gdb) add-symbol-files 0xffffffffa007c000 这一行没搞清楚怎么用。 albcamus 回复于:2008-10-29 23:38:10 怎么还没看懂? grep hello /proc/module, 是为了知道module被加载到什么地址了; gdb中add-symbol-file /home/sb./hello.ko 0xf2231233,是为了让gdb读取hello.ko文件中的负号表,并且和那个地址对应起来。 你可以执行一下,然后l一下你模块中的函数。 Godbach 回复于:2008-10-30 09:39:34 引用:原帖由 albcamus 于 2008-10-29 23:38 发表 [url=http://linux.chinaunix.net/bbs/redirect.php?goto=findpost&pid=6800078&ptid=1008573] ![]() 怎么还没看懂? grep hello /proc/module, 是为了知道module被加载到什么地址了; gdb中add-symbol-file /home/sb./hello.ko 0xf2231233,是为了让gdb读取hello.ko文件中的负号表,并且和那个地址对应起来。 ... 呵呵,版主说的真细致,多谢。以前没怎么用过,惭愧。今天再试一下,一定要把oops的分析学会。 pengxihan 回复于:2009-06-04 20:42:17 在不使用gdb的情况下,C和汇编怎么对应起来呢?就像最后一个方法中知道了是“mov (%ecx),%edx”这条指令引起OOPS,那怎么将它和C语言语句对应起来呢? Solaris12 回复于:2009-06-04 23:30:31 引用:原帖由 pengxihan 于 2009-6-4 20:42 发表 [url=http://linux.chinaunix.net/bbs/redirect.php?goto=findpost&pid=7032961&ptid=1008573] ![]() 在不使用gdb的情况下,C和汇编怎么对应起来呢?就像最后一个方法中知道了是“mov (%ecx),%edx”这条指令引起OOPS,那怎么将它和C语言语句对应起来呢? 一个简单的办法就是平时就练习反汇编和源代码对照看,熟练以后就能很容易看明白了。 Godbach 回复于:2009-06-05 09:43:38 引用:原帖由 Solaris12 于 2009-6-4 23:30 发表 [url=http://linux.chinaunix.net/bbs/redirect.php?goto=findpost&pid=7033041&ptid=1008573] ![]() 一个简单的办法就是平时就练习反汇编和源代码对照看,熟练以后就能很容易看明白了。 恩,Linux下还是要多了解一下汇编 |
![]() |
原文链接:http://linux.chinaunix.net/bbs/viewthread.php?tid=1008573 转载请注明作者名及原文出处 |
定位Oops的具体代码行(发生oops时,用于定位,太有用了)
最新推荐文章于 2025-08-05 09:01:34 发布