热度 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