tag 标签: oops

相关博文
  • 热度 3
    2011-12-19 13:49
    1619 次阅读|
    0 个评论
     例如这样的一个Oops:  Oops: 0000 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: 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:   show_trace_log_lvl+0x1a/0x2f show_stack_log_lvl+0x9b/0xa3 show_registers+0xa3/0x1df die+0x11f/0x200   do_page_fault+0x533/0x61a   error_code+0x72/0x78 __unlink_module+0xb/0xf   do_stop+0xb8/0x108   kthread+0x3b/0x63   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: list_del+0xa/0x61 SS:ESP 0068:dec62fa4   note: kstopmachine 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 )   {              printf("%p\n", array);               *(int *)0 = 0;    } e.g. /*{{{*/ /* 注意, array一共有从array 到array 这65个元素, 其中出错的那个操作码8b == arry */ #include stdio.h #include stdlib.h const char array ) {         printf("%p\n", array);         *(int *)0 = 0; }  用gcc -g编译,在gdb里运行它: $ gdb hello  GNU gdb Fedora (6.8-1.fc9)  Copyright (C) 2008 Free Software Foundation, Inc.  License GPLv3+: GNU GPL version 3 or later ,也就是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