内核异常级别:
1、 bug
Bug是指那些不符合内核的正常设计,但内核能够检测出来并且对系统运行不会产生影响的问题,比如在原子上下文中休眠。
2、 Oops
程序在内核态时,进入一种异常情况,比如引用非法指针导致的数据异常,数组越界导致的取指异常,此时异常处理机制能够捕获此异常,并将系统关键信息打印到串口上,正常情况下Oops消息会被记录到系统日志中去。
3、 Panic
当Oops发生在中断上下文中或者在进程0和1中,系统将彻底挂起,因为中断服务程序异常后,将无法恢复,这种情况即称为内核panic。
参考链接:https://www.cnblogs.com/dyllove98/archive/2013/07/16/3194225.html
错误类型:
1、 段错误segment fault,产生core dump
一、内存访问越界
a) 由于使用错误的下标,导致数组访问越界;
b) 搜索字符串时,依靠字符串结束符来判断字符串是否结束,但是字符串没有正常的使用结束符;
c) 使用strcpy, strcat, sprintf, strcmp, strcasecmp等字符串操作函数,将目标字符串读/写爆。应该使用strncpy, strlcpy, strncat, strlcat, snprintf, strncmp, strncasecmp等函数防止读写越界;
二、多线程程序使用了线程不安全的函数。
三、多线程读写的数据未加锁保护。对于会被多个线程同时访问的全局数据,应该注意加锁保护,否则很容易造成core dump
四、非法指针
a) 使用空指针;
b) 随意使用指针转换。一个指向一段内存的指针,除非确定这段内存原先就分配为某种结构或类型,或者这种结构或类型的数组,否则不要将它转换为这种结构或类型 的指针,而应该将这段内存拷贝到一个这种结构或类型中,再访问这个结构或类型。这是因为如果这段内存的开始地址不是按照这种结构或类型对齐的,那么访问它 时就很容易因为bus error而core dump;
5 堆栈溢出.不要使用大的局部变量(因为局部变量都分配在栈上),这样容易造成堆栈溢出,破坏系统的栈和堆结构,导致出现莫名其妙的错误;
参考链接:https://blog.csdn.net/weiyuefei/article/details/79383608
2、 kernel panic
1、Linux在中断处理程序中,它不处于任何一个进程上下文,如果使用可能睡眠的函数,则系统调度会被破坏,导致kernel panic。因此,在中断处理程序中,是不能使用有可能导致睡眠的函数(例如信号量等)。
在中断发起的软中断中,其上下文环境有可能是中断上下文,同理,也不能调用可能导致睡眠的函数。软中断执行时,全局中断是打开的,而中断程序执行时,全局中断是禁止的。
软中断除了系统调度进入点,当软中断数量频繁时,内核中有一个专门的软中断的后台程序daemon来处理其事务。
2、 内核堆栈溢出,或者指针异常访问时,会出现kernel panic。
堆栈溢出:程序循环或者多层嵌套的深度过多时,可能会导致栈溢出。参考Linux的内存模型
3、 除0异常、内存访问越界、缓冲区溢出等错误时,当这些事件发生在应用程序时,Linux内核的异常处理机制可以对这些由应用程序引起的情况予以处理。当应用程序出现不可恢复性错误时,Linux内核可以仅仅终止产生错误的应用程序,而不影响其他程序。
如果上述操作发生在内核空间,就会引起kernel panic。
4、 内核陷入死锁状态,自旋锁有嵌套使用的情况。
5、 在内核线程中,存在死循环的操作。
参考链接:https://www.cnblogs.com/cherishui/p/3881428.html
3、Unhandled kernel unaligned access问题
举例:
<4>[ 181.905000] USB enable : [0x1]USB enable : [0x3]<0>4:Unhandled kernel unaligned access[#1]:
Entering kdb (current=0xa8000007d8a93020, pid 491) on processor 4 Oops: Unhandled kernel unaligned access due to oops @ 0xffffffffc00ed1bc
<4>[39673.858000] epc : ffffffffc00ed1bc <0>28:Bad page state in process ‘kdrv
dp28’
<0>[39673.859000] page:a80000011a70ad00 flags:0x4000000000000000 mapping:
(null) mapcount:0 count:-2
<0>[39673.859000] 28:Trying to fix it up, but a reboot is needed
flag表示页的状态
_count表示引用次数,为负值时表示空闲,可以调用page_count查询_count值,返回0表示空闲。
_count == 0:表示该页面位空闲或即将要被释放。
_count > 0:表示该页面已经被分配切内核正在使用,暂不会被释放。
_mapcount == -1:表示没有pte映射到页面中。
_mapcount == 0:表示只有父进程映射了页面。
mapping:
当page->mapping == NULL,该page属于交换高速缓存页(swap cache),当需要使用地址空间时会指定交换分区的地址空间swapper_space。
当page->mapping != NULL,并且bit[0] == 0,该page属于页缓存或文件映射,mapping指向inode address_space。
当page->mapping != NULL,并且bit[0] != 0,该page属于匿名映射,且设置了PAGE_MAPPING_ANON位(bit[0] )被,page->mapping指向struct anon_vma对象。
当page->mapping != NULL,并且bit[1] != 0,bit[0] != 0,该page映射在VM_MERGEABLE区域的匿名页面上,如果启用了CONFIG_KSM,那么PAGE_MAPPING_KSM(bit[1]) 位与PAGE_MAPPING_ANON位一起被设置;然后page->mapping,不是指向anon_vma, 而是指向KSM与合并页相关联的private数据结构。
epc :exception program counter , 异常程序计数器,
ra : return address 返回地址
参考链接:
https://www.cnblogs.com/arnoldlu/p/8335481.html
4、 Unable to handle kernel paging request at virtual address
是内存访问异常的错误,原因通常有三种:
1、 virtual address 为 0x00000000 时,说明使用了空指针;
2、 virtual address 没有越出内核地址空间范围,说明指针指向的内存受到某种限制;
3、 除此以外就是指针越出内核地址空间范围。
当 virtual addresss 地址指向的是用户空间时,强制读或者写用户空间地址中的内容会引起报错。
原文链接:https://blog.csdn.net/m0_38066161/java/article/details/81813269
5、BUG: sleeping function called from invalid context at …
这个错误就是在might_sleep函数中打印的,内核只是用它来做一件事,就是提醒你,调用该函数的函数可能会sleep。
CONFIG_DEBUG_ATOMIC_SLEEP选项主要用来排查是否在一个ATOMIC操作的上下文中有函数发生sleep行为,关于什么是 ATOMIC操作,内核源码在might_sleep函数前也有一段注释:
this macro will print a stack trace if it is executed in an atomic context (spinlock, irq-handler, …)
所以很明显,一个进程获得了spinlock之后它就进入了这里所谓的atomic context,或者是在一个irq-handler,也就是一个中断上下文中 。
这两种上下文中理论上不应该让当前的execution path进入sleep状态(虽然不是强制规定,换句话说,一个拥有spinlock的进程进入sleep并不必然意味着系统就一定会deadlock 等,但是对内核编程而言,还是应该尽力避开这个雷区)
参考链接:https://blog.csdn.net/hp0773/article/details/12658501
6、BUG: scheduling while atomic:
函数在原子上文中,如关闭中断中调用了schedule,需要排查该函数相关定义。
7、BUG: spinlock bad magic on CPU:
函数使用spinlock没有初始化,查找该函数定义,缺少spinlock init之类 。
8、[ 464.446045] watchdog: BUG: soft lockup - CPU#30 stuck for 22s! [kill:2031]
https://www.cnblogs.com/xingmuxin/p/11317794.html
*MIPS异常处理介绍
https://blog.csdn.net/whuzm08/article/details/79536361
MIPS 通用寄存器 + 指令
https://blog.csdn.net/gujing001/article/details/8476685
https://blog.csdn.net/qq_41191281/article/details/85933985
https://blog.csdn.net/jackixzj/article/details/54923904
ARM通用寄存器
A64通用寄存器:
X0~X7 : 参数/结果寄存器;
X8 : 直接结果位置寄存器;
X9~X15 : 临时寄存器;
X16 : 第1个内部过程调用寄存器或临时寄存器IP0;
X17 : 第2个内部过程调用寄存器或临时寄存器IP1;
X18 : 平台寄存器/临时寄存器;
X19~X28: 程序计数器/调用备份寄存器;
X29 : 用作帧指针寄存器FP;
X30 : 用作过程链接寄存器PLR(Produce Link Register)
SP : 栈指针寄存器;
1:寄存器如下
(1)、X0-X31
X0-X7 用于参数传递
X9-X15 在子函数中使用这些寄存器时,直接使用即可, 无需save/restore. 在汇编代码中x9-x15出现的频率极低
在子函数中使用这些寄存器时,直接使用即可, 无需save/restore. 在汇编代码中x9-x15出现的频率极低
X19-X29 在callee子函数中使用这些寄存器时,需要先save这些寄存器,在退出子函数时再resotre
在callee子函数中使用这些寄存器时,需要先save这些寄存器,在退出子函数时再resotre
X8, X16-X18, X29, X30 这些都是特殊用途的寄存器
– X8: 用于返回结果
– X16、X17 :进程内临时寄存器
– X18 :resrved for ABI
– X29 :FP(frame pointer register)
– X30 :LR
2:进入KDB 后rd 查看各个寄存器(不要输入简写r)
来自 https://www.cnblogs.com/konf/p/9213487.html
主要寄存器:
(1)通用寄存器R0-R30
这些寄存器可以作为31个64位寄存器X0-X30或31个32位寄存器W0-W30进行访问
(2)堆栈指针寄存器SP
(3)保存的程序状态寄存器SPSR
保存的程序状态寄存器SPSR(Saved Program Status Registers)用于在发生异常时保存处理器状态
(4)异常链接寄存器(ELR)
异常链接寄存器ELR(Exception Link Registers)包含异常返回地址。当处理器发生异常时,返回地址将保存在异常级别对应的ELR中。
(5)ESR(Exception Syndrome Register)
异常综合表征寄存器ESR_ELn包含的异常信息用以异常处理程序确定异常原因。
• pc, program counter,程序计数器。程序当前运行的指令会放入到pc寄存器中
• fp, 即frame pointer,帧指针。通常指向一个函数的栈帧底部,表示一个函数栈的开始位置。
• sp, stack pointer,栈顶指针。指向当前栈空间的顶部位置,当进行push和pop时会一起移动。
• lr, link register。在进行函数调用时,会将函数返回后要执行的下一条指令放入lr中,对应x86架构下的返回地址。
http://superedu.hqyj.com/xuexi/bowen/328.html
9、bad: scheduling from the idle thread!
通常是在中断处理函数中调用了可以休眠的函数,
如semaphore,mutex,sleep之类的可休眠的函数,而linux内核要求在中断处理的时候,不允许系统高度,不允许抢占,要等到中断处理完成才能做其他事情。因此,要充分考虑中断处理的时间,一定不能太久。
https://blog.csdn.net/hunhunzi/article/details/6230951?utm_medium=distribute.pc_relevant_t0.none-task-blog-2~default~CTRLIST~default-1.no_search_link&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2~default~CTRLIST~default-1.no_search_link
10、 Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b
可能跟编译器、内核版本有关
https://blog.csdn.net/chuanzhilong/article/details/52901973
https://bbs.elecfans.com/jishu_1731390_1_1.html
https://winddoing.github.io/post/7653.html
11、 Data bus error
12、 kernel BUG at mm/vmalloc.c:2050!
<4>[ 61.332181] ------------[ cut here ]------------
<2>[ 61.332187] kernel BUG at mm/vmalloc.c:2050! BUG_ON(in_interrupt());
<0>[ 61.332194] Internal error: Oops - BUG: 0 [#1] SMP
[2]kdb> bt
__get_vm_area_node+0x17c/0x190
get_vm_area_caller+0x50/0x60
__ioremap_caller+0x78/0xd0
__ioremap+0x3c/0x50
BUG_ON放在这里意思是在不允许在中断里调用__get_vm_area_node()函数。
问题解决:
如果是在中断里调用ioremap()函数则可以考虑在初始化时就map好。比如上面的例子,就应该在初始化时就map好,在中断里直接用就行了。
如果是vmalloc(),可以考虑用kmalloc()替换。
https://blog.csdn.net/yqj2011/article/details/53374454
13、module PLT section missing
[ 79.983608] addon: loading out-of-tree module taints kernel.
[ 80.051559] addon: module PLT section missing
insmod: can’t insert ‘/lib/modules/addon.ko’: in[ 80.140092] system: module PLT section missing
valid module format
insmod: can[ 80.227923] random: patch: uninitialized urandom read (32 bytes read, 16 bits of entropy available)
't insert ‘/lib/modules/system.ko’: invalid module format
[1970-01-01 00:01:20] insmod /lib/modules/system.ko failed!error
[1970-01-01 00:01:20] open socket server failed!error
[1970-01-01 00:01:20] pipe init error!error
[1970-01-01 00:01:20] add epoll failed!error
[1970-01-01 00:01:20] monitor init error!error
[1970-01-01 00:01:20] SCM init failed!
[ 84.984204] random: eshell: uninitialized urandom read (32 bytes read, 16 bits of entropy available)
[ 85.100905] addon: module PLT section missing
查看module.lds文件是否缺少 :
.plt : { BYTE(0)}
.init.plt : {BYTE(0)}
SECTIONS {
.text : {
*(.text)
*(.text.*)
}
.plt : { BYTE(0)}
.init.plt : {BYTE(0)}
.data : {
*(.data)
*(.data.*)
}
.bss : {
*(.bss)
*(.bss.*)
}
.rodata : {
*(.rodata)
*(.rodata.*)
}
.comware.init : {
__comware_initcall_start = .;
*(.comware_initcall)
*(.comware_initcall.*)
__comware_initcall_end = .;
}
.mdcevent.init : {
__comware_mdcevent_start = .;
*(.comware_mdcevent)
*(.comware_mdcevent.*)
__comware_mdcevent_end = .;
}
}
14、
<2>[ 1017.142976] Bad mode in Synchronous Abort handler detected, code 0x86000006 -- IABT (current EL)
<0>[ 1017.142979] Internal error: Oops - bad mode: 0 [#1] SMP
<4>[ 1017.142982] Modules linked in: system(O) addon(O)
<4>[ 1017.142985] CPU: 0 PID: 1285 Comm: kdrvdppkt0 Tainted: G O 4.4.131-bex01a #1
<4>[ 1017.142986] Hardware name: FT2000plus (DT)
<4>[ 1017.142987] task: ffff80812412e240 ti: ffff808103e40000 task.ti: ffff808103e40000
<4>[ 1017.142989] PC is at 0x0
<4>[ 1017.142993] LR is at tasklet_action+0x6c/0xf8
<4>[ 1017.142995] pc : [<0000000000000000>] lr : [<ffff8000000b7c3c>] pstate: 20000145
<4>[ 1017.142995] sp : ffff808103e4f630
<4>[ 1017.142997] x29: ffff808103e4f630 x28: ffff7ffff1aede78
<4>[ 1017.142999] x27: fffffffffffffff8 x26: ffff800000832000
<4>[ 1017.143000] x25: 0000000000000100 x24: ffff808103e40000
<4>[ 1017.143002] x23: 0000000000000040 x22: ffff8000008119d8
<4>[ 1017.143003] x21: 0000000000000000 x20: ffff7ffff2602040
<4>[ 1017.143005] x19: ffff7ffff2602038 x18: ffff80008092259f
<4>[ 1017.143006] x17: 00000000004c3de0 x16: ffff8000000b7780
<4>[ 1017.143008] x15: ffff8000009225ad x14: 0ffffffffffffffe
<4>[ 1017.143009] x13: 0000000000000030 x12: 0000000000000005
<4>[ 1017.143011] x11: 0000000000000d5b x10: 0000000000000790
<4>[ 1017.143012] x9 : ffff8000000b7190 x8 : 0000000000000000
<4>[ 1017.143014] x7 : ffff8080c0000008 x6 : 000000009a12be7c
<4>[ 1017.143015] x5 : 0000000000000000 x4 : 0000000000000001
<4>[ 1017.143016] x3 : 0000000000000000 x2 : 0000000000000002
<4>[ 1017.143018] x1 : 0000000000000000 x0 : 0000000000000000
<4>[ 1017.143018]
[0]kdb> bt
Stack traceback for pid 1285
0xffff80812412e240 1285 2 1 0 R 0xffff80812412e9d0 *kdrvdppkt0
Call trace:
[< (null)>] (null)
[<ffff8000000b7c3c>] tasklet_action+0x6c/0xf8
[<ffff8000000b7190>] __do_softirq+0x150/0x320
[<ffff8000000b766c>] irq_exit+0x9c/0xc8
[<ffff8000000fdde4>] __handle_domain_irq+0x6c/0xc0
[<ffff800000081dd8>] gic_handle_irq+0xe0/0x180
Exception stack(0xffff808103e4f970 to 0xffff808103e4fa90)
f960: ffff7ffff25fd128 00000001000af51d
f980: ffff808103e4fce0 ffff7ffff0071060 0000000020000145 ffff7ffff25fd138
f9a0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
f9c0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
f9e0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
fa00: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
fa20: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
fa40: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
fa60: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
fa80: 0000000000000000 0000000000000000
[<ffff800000084ce8>] el1_irq+0x68/0xc0
[<ffff7ffff00459ac>] M9kecn_I210_Rev_Task+0xd4/0x180 [system]
[<ffff8000000d1f58>] kthread+0x100/0x118
[<ffff800000085140>] ret_from_fork+0x10/0x50
a)从 CPU: 0 PID: 1285 Comm: kdrvdppkt0
可以看出出问题的是CPU0,线程名是kdrvdppkt0
b)从
<4>[ 1017.142989] PC is at 0x0 <4>[ 1017.142993] LR is at tasklet_action+0x6c/0xf8
可以看出,
根据kernel pacnic的信息,程序计数器PC的值竟然是0x0,而链接寄存器LR的值是tasklet_action+0x6c/0xf8,而这则说明了错误正是出在了tasklet_action+0x6c/0xf8函数中,好像是在tasklet_action+0x6c/0xf8函数中调用了一个函数,而那个函数的地址竟然是奇怪的0。因为如果没有跳转语句的话,PC值断然是不会莫名其妙的变为0的。
经确认,这里是报中断但没有写对应的中断响应函数导致程序跑飞。
https://blog.csdn.net/weixin_34321753/article/details/85722005
http://blog.chinaunix.net/uid-12567959-id-161023.html
https://www.icxbk.com/ask/detail?tid=24971
15、linux随机数
[ 223.644981] random: mdcagentd: uninitialized urandom read (32 bytes read, 122 bits of entropy available)
[ 227.620270] random: nonblocking pool is initialized