分类: LINUX
2019-07-06 11:40:49
常在河边走,哪能不湿鞋。用Linux,总有死机的时候,如果运气好,会看到一些所谓”Oops”信息(在屏幕上或系统日志中),比如:
Unable to handle kernel paging request at virtual address f899b670
printing eip:
c01de48c
*pde = 00737067
Oops: 0002 [#1]
Modules linked in: bluesmoke_e752x bluesmoke_mc md5 ipv6 parport_pc lp
parport nls_cp936 vfat fat dm_mod button battery asus_acpi ac joydev
yenta_socket pcmcia_core uhci_hcd ehci_hcd snd_intel8x0 snd_ac97_codec
snd_pcm_oss snd_mixer_oss snd_pcm snd_timer snd_page_alloc
snd_mpu401_uart snd_rawmidi snd_seq_device snd soundcore ipw2200
ieee80211 ieee80211_crypt sk98lin ext3 jbd
CPU: 0
EIP: 0060:[] Not tainted VLI
EFLAGS: 00210286 (2.6.9-11.21AXKProbes)
EIP is at kobject_add+0×83/0xd7
eax: c038db78 ebx: c038db04 ecx: f899b670 edx: f8a4a630
esi: c038db4c edi: f8a4a614 ebp: c038db80 esp: d7568f2c
ds: 007b es: 007b ss: 0068
Process modprobe (pid: 8227, threadinfo=d7568000 task=f4ea99b0)
Stack: f8a4a614 ffffffea f8a4a5e4 00000000 c01de4f9 f8a4a614 c038db00 c024a1d4
f8a4a5c0 f8a4a5e4 f8a4a5f4 d7568000 c024a661 1d244b3c 00000000 0000000a
c032421b 00000000 00000000 00000015 00000014 00000016 f89ddb34 f8a4a5c0
Call Trace:
[] kobject_register+0×19/0×39
[] bus_add_driver+0×36/0×97
[] driver_register+0×82/0×89
[] pci_register_driver+0×85/0xa1
[] init_module+0xa/0×14 [bluesmoke_e752x]
[] sys_init_module+0x1ec/0×323
[] syscall_call+0×7/0xb
Code: 85 d2 0f 85 06 04 00 00 85 ed 75 0d 8b 47 28 83 c0 10 e8 82 01 00
00 89 c5 8b 47 28 8d 57 1c 83 c0 08 89 47 1c 8b 48 04 89 50 04
<89> 11 89 4a 04 8b 47 28 8b 18 8d 4b 48 89 c8 ba ff ff 00 00 0f
Oops可以看成是内核级的Segmentation Fault。应用程序如果进行了非法内存访问或执行了非法指令,会得到Segfault信号,一般的行为是coredump,应用程序也可以自己截获Segfault信号,自行处理。如果内核自己犯了这样的错误,则会打出Oops信息。
有不少文章说明如何理解这些Oops (http://pczou.blogchina.com/545558.html),这里只想解释一下它所产生的过程(以2.6系列内核为例):
首先是处理硬件发出的内存访问异常(fault),有些异常是无辜的(比如demand-paging),而有些则是内核的错误所致。
1. do_page_fault() arch/i386/mm/fault.c
如果是内核进行了非法访问,do_page_fault()会先打出EIP, PDE等信息,例如:
Unable to handle kernel paging request at virtual address f899b670
printing eip:
c01de48c
*pde = 00737067
然后调用 die(“Oops”, regs, error_code);
这之后,如果系统还活着(至少要满足两个条件:1. 在进程上下文 2. 没有设置panic_on_oops),会杀死当前进程。然后继续运行,好像什么事情都没有发生一样。不过,这样的好事不经常发生,发生了也不会太持久。
2. do_page_fault() -> die() arch/i386/kernel/traps.c
die() 首先打出一行:
Oops: 0002 [#1]
其中0002代表错误码 (读错误、发生在内核空间),#1代表Oops发生次数。
* error_code:
* bit 0 == 0 means no page found, 1 means protection fault
* bit 1 == 0 means read, 1 means write
* bit 2 == 0 means kernel, 1 means user-mode
然后,调用 show_registers(regs) 输出寄存器、当前进程、堆栈、指令代码等信息:
Modules linked in: bluesmoke_e752x bluesmoke_mc md5 ipv6 parport_pc
lp parport nls_cp936 vfat fat dm_mod button battery asus_acpi ac joydev
yenta_socket pcmcia_core uhci_hcd ehci_hcd snd_intel8x0 snd_ac97_codec
snd_pcm_oss snd_mixer_oss snd_pcm snd_timer
snd_page_alloc snd_mpu401_uart snd_rawmidi snd_seq_device snd soundcore
ipw2200 ieee80211 ieee80211_crypt sk98lin ext3 jbd
CPU: 0
EIP: 0060:[] Not tainted VLI
EFLAGS: 00210286 (2.6.9-11.21AXKProbes)
EIP is at kobject_add+0×83/0xd7
eax: c038db78 ebx: c038db04 ecx: f899b670 edx: f8a4a630
esi: c038db4c edi: f8a4a614 ebp: c038db80 esp: d7568f2c
ds: 007b es: 007b ss: 0068
Process modprobe (pid: 8227, threadinfo=d7568000 task=f4ea99b0)
Stack: f8a4a614 ffffffea f8a4a5e4 00000000 c01de4f9 f8a4a614 c038db00 c024a1d4
f8a4a5c0 f8a4a5e4 f8a4a5f4 d7568000 c024a661 1d244b3c 00000000 0000000a
c032421b 00000000 00000000 00000015 00000014 00000016 f89ddb34 f8a4a5c0
Call Trace:
[] kobject_register+0×19/0×39
[] bus_add_driver+0×36/0×97
[] driver_register+0×82/0×89
[] pci_register_driver+0×85/0xa1
[] init_module+0xa/0×14 [bluesmoke_e752x]
[] sys_init_module+0x1ec/0×323
[] syscall_call+0×7/0xb
Code: 85 d2 0f 85 06 04 00 00 85 ed 75 0d 8b 47 28 83 c0 10 e8 82 01 00
00 89 c5 8b 47 28 8d 57 1c 83 c0 08 89 47 1c 8b 48 04 89 50 04
<89> 11 89 4a 04 8b 47 28 8b 18 8d 4b 48 89 c8 ba ff ff 00 00 0f
如果是在中断上下文,则直接调用panic()【panic
输出oops信息后将挂起系统】。如果是在进程上下文,则根据panic_on_oops的设置选择是否panic()。panic_on_oops的缺省设置是”0″,即在Oops发生时不会进行panic()操作。可以通过sysctl进行设置:
sysctl -w kernel.panic_on_oops=1
有panic_on_oops这样的设置,说明Oops不一定导致系统死亡,也不一定需要重新启动系统。正如用户程序segfault时可能还能坚持运行一样。不过Oops一旦发生,系统已经有些不正常了,即使表面上可能还正常,不过可能有些锁已经被占用而无法释放,很快会导致系统死锁。
那么,panic()是什么呢?panic()和用户空间的abort()类似,简单清理一下,就可以放心去死(reboot)了。
3. do_page_fault() -> die() -> panic()
panic会根据 kernel.panic 的设置决定 reboot 前的延时,如果 kernel.panic=0,则打开中断,陷入死循环。反之,则在几秒之后,reboot系统。
可以看出虽然都是死,但死因不同,死亡时的表现更是五花八门。常见的死因有:
有时候核心成心发出非法指令,比如BUG() (include/asm/bug.h) 中所做的,以引起Oops。类似用户程序中调用assert()。
死亡发生的地点也很关键,直接导致了死亡的不同表现,比如:
在中断上下文中,由于中断是关闭的,而且往往会占用一些锁,这种情况下一般除了死,没有什么别的办法。
在进程上下文中要自由一些,如果运气好的话,可以苟延残喘一段时间。
No related posts.
4、Comba 实例:
4.1 实例1
Driver athrs_gmac: Comba V1.2.1 (Mar 31 2014 19:36:40) init.
CPU 0 Unable to handle kernel paging request at virtual address 00000000, epc == 839bf170, ra == 839bf16c
Oops[#1]:
Cpu 0
$ 0 : 00000000 00000076 00000000 839b0000
$ 4 : 839b5788 00000000 00000000 000002e0
$ 8 : 00000000 800f27b0 00000000 83803168
$12 : 83803170 ffffffff 00000001 63202847
$16 : 800f13e0 839b5604 839b0000 839b5638
$20 : 839b5628 00000001 839b0000 00000074
$24 : 00000000 80118080
$28 : 838f8000 838f9e88 7ff340a8 839bf16c
Hi : 00000011
Lo : 00000007
epc : 839bf170 athr_gmac_init+0x170/0x9a4 [athrs_gmac]
Not tainted
ra : 839bf16c athr_gmac_init+0x16c/0x9a4 [athrs_gmac]
Status: 1100ff03 KERNEL EXL IE
Cause : 0080000c
BadVA : 00000000
PrId : 0001974c (MIPS 74Kc)
Modules linked in: athrs_gmac(+)
Process insmod (pid: 47, threadinfo=838f8000, task=838d24f0, tls=00000000)
Stack : 00000000 839b5604 839b5648 839b561c 839b5628 839b5638 00000000 00000000
80290000 839b5450 839bf000 00000000 2ab55008 00403564 00000002 80002468
839b5450 fffffffc 80290000 2ab55008 00403564 8003b838 fffffffc 00537008
2ab55008 80290000 839b5450 fffffffc 80290000 80045f30 00020000 00000802
00000003 2ab55008 7ff34f42 8006c3e4 2ab55008 00537008 2ab4ff50 7ff342b4
...
Call Trace:
[<839bf170>] athr_gmac_init+0x170/0x9a4 [athrs_gmac]
[<80002468>] _stext+0x68/0x1ec
Code: 0040f809 00000000 3c03839b
Disabling lock debugging due to kernel taint
Segmentation fault
在AR9344平台中,如果在有线口驱动athr_gmac_init函数定义 空指针访问,将打印上述的Oops信息,由于此Oops发生在进程上下文,
又没有开启panic_on_oops,无法进行panic()操作,最终系统依然能够正常运行,但是有线口模块异常。
建议设置panic_on_oops=1(开启)
4.2 实例2
Kernel bug detected[#1]:
Cpu 0
$ 0 : 00000000 00000000 00000028 80296470
$ 4 : 802964b0 00001565 00000001 00001565
$ 8 : 802e0000 7274696f 6e206661 696c6564
$12 : 000000cd ffffffff 839482c0 00000000
$16 : 83948000 83948030 839719a4 00001043
$20 : 00000000 00008914 7f82e308 7f82e328
$24 : 00000001 80118080
$28 : 838f8000 838f9d90 00000000 83962538
Hi : 00000000
Lo : c6edb000
epc : 83962538 athr_gmac_open+0x28/0x34 [athrs_gmac]
Not tainted
ra : 83962538 athr_gmac_open+0x28/0x34 [athrs_gmac]
Status: 1100ff03 KERNEL EXL IE
Cause : 00800024
PrId : 0001974c (MIPS 74Kc)
Modules linked in: athrs_gmac
Process ifconfig (pid: 41, threadinfo=838f8000, task=838d24f0, tls=00000000)
Stack : 00000000 8396bdc4 00000092 00000000 00000000 8014fb9c 00000041 8014b8d8
8391a224 8395a004 83948000 00000000 00001002 8014ef64 00000000 838f9e18
00008914 8014fc24 00000000 ffffff82 00000000 838f9e28 83948000 801aa8f8
83941294 838f9e18 fffffff7 80150750 8391a224 004a5be4 10433020 00000000
7f82e33c 7f82e398 65746830 00000000 00000000 00000000 10433020 00000000
...
Call Trace:
[<83962538>] athr_gmac_open+0x28/0x34 [athrs_gmac]
[<8014fb9c>] dev_open+0xe8/0x15c
[<8014ef64>] dev_change_flags+0xd0/0x1c8
[<801aa8f8>] devinet_ioctl+0x2d4/0x80c
[<8013c864>] sock_ioctl+0x29c/0x2f4
[<8007ba4c>] vfs_ioctl+0x2c/0x78
[<8007c150>] do_vfs_ioctl+0x5bc/0x610
[<8007c1f4>] sys_ioctl+0x50/0x8c
[<8000dde4>] stack_done+0x20/0x3c
Code: 2442f0dc 0040f809 24060092 <0200000d> 08e5894f 00000000 27bdffd0 afb50028 00e0a821
Disabling lock debugging due to kernel taint
Segmentation fault
ifconfig: SIOCGIFFLAGS: No such device
在AR9344平台中,修改有线口驱动中断言assert(mac),使其断言失败,将打印上述的Oops信息,由于此Oops发生在进程上下文,
又没有开启panic_on_oops,无法进行panic()操作,最终因系统死锁,而无法响应键盘的输入。
建议设置panic_on_oops=1(开启)