android内核出现kernelpanic的分析

android内核出现kernelpanic的分析
1 何谓OOPS
波峰焊锡条Oops是美国⼈⽐较常有的⼝语。就是有点意外,吃惊,或突然的意思。“Oops”并不是很严重,正如在Britney Spears的 “Oops I Did It Again”那⾸歌的歌词中,也是⼀种轻描淡写,有时含有抱歉的意思。
对于内核来说,Oops就意外着内核出了异常,此时会将产⽣异常时CPU的状态,出错的指令地址、数据地址及其他寄存器,函数调⽤的顺序甚⾄是栈⾥⾯的内容都打印出来,然后根据异常的严重程度来决定下⼀步的操作:杀死导致异常的进程或者挂起系统
最典型的异常是在内核态引⽤了⼀个⾮法地址,通常是未初始化的野指针Null,这将导致页表异常,最终引发Oops。
系统⾜够健壮,能够正常的反应各种异常。异常通常导致当前进程的死亡,⽽系统依然能够继续运转,但是这种运转都处在⼀种不稳定的状态,随时可能出问题。对于中断上下⽂的异常及系统关键资源的破坏,通常会导致内核挂起,不再响应任何事件。
2 内核的异常级别
2.1 Bug
Bug是指那些不符合内核的正常设计,但内核能够检测出来并且对系统运⾏不会产⽣影响的问题,⽐如在原⼦上下⽂中休眠。如:
BUG: scheduling while atomic: insmod/826/0x00000002
Call Trace:
[ef12f700] [c00081e0] show_stack+0x3c/0x194 (unreliable)
[ef12f730] [c0019b2c] __schedule_bug+0x64/0x78
[ef12f750] [c0350f50] schedule+0x324/0x34c
[ef12f7a0] [c03515c0] schedule_timeout+0x68/0xe4
[ef12f7e0] [c027938c] fsl_elbc_run_command+0x138/0x1c0
[ef12f820] [c0275820] nand_do_read_ops+0x130/0x3dc
[ef12f880] [c0275ebc] nand_read+0xac/0xe0
[ef12f8b0] [c0262d98] part_read+0x5c/0xe4
[ef12f8c0] [c017bcac] jffs2_flash_read+0x68/0x254
[ef12f8f0] [c0170550] jffs2_read_dnode+0x60/0x304
[ef12f940] [c017088c] jffs2_read_inode_range+0x98/0x180
[ef12f970] [c016e610] jffs2_do_readpage_nolock+0x94/0x1ac
[ef12f990] [c016ee04] jffs2_write_begin+0x2b0/0x330
穴盘[ef12fa10] [c005144c] generic_file_buffered_write+0x11c/0x8d0
[ef12fab0] [c0051e48] __generic_file_aio_write_nolock+0x248/0x500
[ef12fb20] [c0052168] generic_file_aio_write+0x68/0x10c
[ef12fb50] [c007ca80] do_sync_write+0xc4/0x138
[ef12fc10] [f107c0dc] oops_log+0xdc/0x1e8 [oopslog]
[ef12fe70] [f3087058] oops_log_init+0x58/0xa0 [oopslog]
[ef12fe80] [c00477bc] sys_init_module+0x130/0x17dc
[ef12ff40] [c00104b0] ret_from_syscall+0x0/0x38
--- Exception: c01 at 0xff29658
干手器
LR = 0x10031300
2.2 Oops
程序在内核态时,进⼊⼀种异常情况,⽐如引⽤⾮法指针导致的数据异常,数组越界导致的取指异常,此时异常处理机制能够捕获此异常,并将系统关键信息打印到串⼝上,正常情况下Oops消息会被记录到系统⽇志中去。
Oops发⽣时,进程处在内核态,很可能正在访问系统关键资源,并且获取了⼀些锁,当进程由于Oops异常退出时,⽆法释放已经获取的资源,导致其他需要获取此资源的进程挂起,对系统的正常运⾏造成影响。通常这种情况,系统处在不稳定的状态,很可能崩溃。
2.3 Panic
当Oops发⽣在中断上下⽂中或者在进程0和1中,系统将彻底挂起,因为中断服务程序异常后,将⽆法恢复,这种情况即称为内核panic。另外当系统设置了panic标志时,⽆论Oops发⽣在中断上下⽂还是进程上下⽂,都将导致内核Panic。由于在中断复位程序中panic后,系统将不再进⾏调度,Syslogd将不会再运⾏,因此这种情况下,Oops的消息仅仅打印到串⼝上,不会被记录在系统⽇志中。
Kernelpanic调试举例:
[ 242.788019] bluesleep_outgoing_data: tx was sleeping
[  244.012224] ******host_wake is 1
[  245.234647] Disable_key_during_touch=0
[  245.237802] huqiao___button->code=139,state =1
[  245.414640] Disable_key_during_touch=0
[  245.417542] huqiao___button->code=139,state =0
[  245.821424] ******host_wake is 0
[  245.823708] bluesleep_hostwake_isr: [I]
多媒体教室中控系统[  245.823713]
[  245.830155] bluesleep_hostwake_task: bluesleep_hostwake_task is called
[  245.838356] Unable to handle kernel NULL pointer dereference at virtualaddress 00000008
[  245.845678] pgd = c0004000
[  245.848188] [00000008] *pgd=00000000
[  245.851751] Internal error: Oops: 5 [#1] PREEMPT SMP ARM
[  245.857122] Modules linked in:
[  245.860080] CPU: 0    Tainted: G        W    (3.4.0-perf-svn874 #1)
[  245.866444] PC is at sco_connect_cfm+0x380/0x4e8
[  245.871106] LR is at 0xd880
[  245.873800] pc : [<c07446c0>]    lr :[<0000d880>]    psr: 40000013
[  245.873805] sp : dbe55e78  ip : 00000000  fp : d7d95c00
[  245.885246] r10: d8643998  r9 : d8e5b80d  r8 : d8643830
[  245.890529] r7 : dbe54000  r6 : d9e5b600  r5 : cae27c80 r4 : d8643800
[  245.896968] r3 : 00000008  r2 : 00000000  r1 : d7d96016 r0 : 00000000
[  245.903552] Flags: nZcv  IRQs on  FIQs on  Mode SVC_32 ISA ARM  Segment kernel
[  245.910772] Control: 10c5787d  Table: 5a47406a  DAC: 00000015
[  245.916576]
[  245.916579] PC: 0xc0744640:
[  245.920751] 4640  e3310000 1afffffa f57ff04f e320f004 e5973004e2433001 e5873004 e5973000
[  245.928910] 4660  ea000042 e59f0190 e300332a e19030b3 e31300040a000004 e2800fc6 e59f1198
如上图,当出现kernel panic的时候,会出现上⾯所⽰的堆栈信息。我们可以看到 [  245.866444] PC is
atsco_connect_cfm+0x380/0x4e8,就会知道在sco_connect_cfm函数这边出现问题的。⼀般来说从LR(链接寄存器)这,我们可以知道上⾯的哪个函数是被hci_proto_connect_cfm所调⽤的。当看到Unable to handle kernel NULL pointerdereference at virtual address 00000008时,就知道这个函数应⽤了⼀个⾮法地址,在linux中, 将最⾼的1G字节(从虚拟地
址0xC0000000到0xFFFFFFFF),供内核使⽤,称为“内核空间”。⽽将较低的3G字节(从虚拟地址
0x00000000到0xBFFFFFFF),供各个进程使⽤,称为“⽤户空间),现在内核⾮法使⽤了⽤户空间的地址故存在问题。
关于kernel panic⼀般很难复现,于是我计划在内核中⾃⼰⽤代码去模拟这个现象。
static inlinevoid hci_proto_connect_cfm(struct hci_conn *conn, __u8 status)
{
register struct hci_proto *hp;
hp = hci_proto[HCI_PROTO_L2CAP];
if (hp && hp->connect_cfm)
hp->connect_cfm(conn, status);
hp = hci_proto[HCI_PROTO_SCO];
if (hp && hp->connect_cfm)
hp->connect_cfm(conn, status);
if (conn->connect_cfm_cb)
conn->connect_cfm_cb(conn, status);
}
当我把函数改变为
static inlinevoid hci_proto_connect_cfm(struct hci_conn *conn, __u8 status)
{
register struct hci_proto *hp;
hp = hci_proto[HCI_PROTO_L2CAP];
if (hp && hp->connect_cfm)
hp->connect_cfm(conn, status);
conn =  = NULL - 21; // Simulation this phenomenon,
hp = hci_proto[HCI_PROTO_SCO];
if (hp && hp->connect_cfm)
hp->connect_cfm(conn, status);
if (conn->connect_cfm_cb)
conn->connect_cfm_cb(conn, status);
快门式3d
}地坑
这个现象就会完全的复现。
其实根据 hci_conn结构体定义,我们就会知道 hcon->type的地址为00000008,于是我们就会明⽩,在最初的代码中,在调
⽤sco_connect_cfm的时候,传⼊的变量conn的地址被改变为NULL - 21;但是在前⾯跑hp->connect_cfm(conn, status)却没有什么问题, conn的地址传进 hp->connect_cfm(conn, status),也没有什么改变。于是我就开始郁闷了。为什么突然地址变为⼀个⾮法的地址?
后来在⽹上查了下,才发现可能是硬件的问题,使得某⼀个地址发⽣了临时的错误⽽导致的。于是到了原因,这个bug也就分析结束了。

本文发布于:2024-09-23 03:16:18,感谢您对本站的认可!

本文链接:https://www.17tex.com/tex/2/328707.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:内核   导致   系统
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2024 Comsenz Inc.Powered by © 易纺专利技术学习网 豫ICP备2022007602号 豫公网安备41160202000603 站长QQ:729038198 关于我们 投诉建议