Linux   发布时间:2022-03-31  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了linux oops 消息大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。

概述

大部分 bug 以解引用 NULL 指针或者使用其他不正确指针值来表现自己的. 此类 bug 通 常的输出是一个 oops 消息.   处理器使用的任何地址几乎都是一个虚拟地址, 通过一个复杂的页表结构映射为物理地址 (例外是内存管理子系统自己使用的物理地址). 当解引用一个无效的指针, 分页机制无法 映射指针到一个物理地址, 处理器发出一个页错误给操作系统. 如果地址无效, 内核无法 "页入"缺

大部分 bug 以解引用 NULL 指针或者使用其他不正确指针值来表现自己的. 此类 bug 通 常的输出一个 oops 消息.

 

处理器使用的任何地址几乎都是一个虚拟地址,通过一个复杂的页表结构映射为物理地址 (例外是内存管理子系统自己使用的物理地址). 当解引用一个无效的指针,分页机制无法 映射指针到一个物理地址,处理器发出一个错误给操作系统. 如果地址无效,内核无法 "页入"缺失的地址; 它(常常)产生一个 oops 如果在处理器处于管理模式时发生这个情况.

 

一个 oops 显示了出错时的处理器状态,包括 cpu 寄存器内容和其他看来不可理解的信息. 消息由错误处理的 printk 语句产生( arch/*/kernel/traps.c )并且如同前面 "printk" 一节中描述的被分派.

 

我们看一个这样的消息. 这是来自在运行 2.6 内核的 PC 上一个 NULL 指针导致的结果. 这里最相关的信息是指令指针(EIp),错误指令的地址.

 

Unable to handle kernel NULL pointer dereference at virtual address 00000000 prinTing eip:

d083a064

Oops: 0002 [#1] SMP

cpu:  0

EIP:  0060:[<d083a064>]  not tainted EFLAGS: 00010246          (2.6.6)

EIP is at faulty_write+0x4/0x10 [faulty]

eax: 00000000  ebx: 00000000  ecx: 00000000  edx: 00000000

esi: cf8b2460  edi: cf8b2480  ebp: 00000005  esp: c31c5f74 ds: 007b          es: 007b  ss: 0068

 

Process bash (pid: 2086,threadinfo=c31c4000 task=cfa0a6c0)

Stack: c0150558 cf8b2460 080e9408 00000005 cf8b2480 00000000 cf8b2460 cf8b2460 fffffff7 080e9408 c31c4000 c0150682 cf8b2460 080e9408 00000005 cf8b2480 00000000 00000001 00000005 c0103f8f 00000001 080e9408 00000005 00000005

Call Trace:

[<c0150558>] vfs_write+0xb8/0x130 [<c0150682>] sys_write+0x42/0x70 [<c0103f8f>] syscall_call+0x7/0xb

 

Code: 89 15 00 00 00 00 c3 90 8d 74 26 00 83 ec 0c b8 00 a6 83 d0

 

写入一个由坏模块拥有的设备而产生的消息,一个故意用来演示失效的模块. faulty.c 的 write 方法的实现是琐细的:

 

ssize_t faulty_write (struct file *filp,const char user *buf,size_t count,loff_t *pos)

{

 

/* make a simple fault by dereferencing a NULL pointer */

*(int *)0 = 0; return 0;

}

 

如你能见,我们这里做的是解引用一个 NULL 指针. 因为 0 一直是一个无效的指针值,一个错误发生,由内核转变为前面展示的 oops 消息. 调用进程接着被杀掉.

 

错误模块有不同的错误情况在它的读实现中:

 

ssize_t faulty_read(struct file *filp,char   user *buf,loff_t

*pos)

{

int ret;

char stack_buf[4];

 

/* Let‘s try a buffer overflow */ memset(stack_buf,0xff,20);

if (count > 4)

 

count = 4; /* copy 4 bytes to the user */ ret = copy_to_user(buf,stack_buf,count);

if (!ret)

 

return count; return ret;

}

 

这个方法拷贝一个字串到一个本地变量; 不幸的是,字串长于目的数组. 当函数返回时导 致的缓存区溢出引起一次 oops . 因为返回指令使指令指针到不知何处,这类的错误很难 跟踪,并且你得到如下的:

 

EIP: 0010:[<00000000>]

Unable to handle kernel paging request at virtual address ffffffff

 

prinTing eip: ffffffff

Oops: 0000 [#5] SMP

cpu:  0

EIP:  0060:[<ffffffff>]  not tainted EFLAGS: 00010296          (2.6.6)

EIP is at 0xffffffff

eax: 0000000c ebx: ffffffff ecx: 00000000 edx: bfffda7c esi: cf434f00 edi: ffffffff ebp: 00002000  esp: c27fff78 ds: 007b  es: 007b  ss: 0068

 

Process head (pid: 2331,threadinfo=c27fe000 task=c3226150)

Stack: ffffffff bfffda70 00002000 cf434f20 00000001 00000286 cf434f00 fffffff7 bfffda70 c27fe000 c0150612 cf434f00 bfffda70 00002000 cf434f20 00000000 00000003 00002000 c0103f8f 00000003 bfffda70 00002000 00002000 bfffda70

Call Trace: [<c0150612>] sys_read+0x42/0x70 [<c0103f8f>] syscall_call+0x7/0xb Code: Bad EIP value.

 

这个情况,我们只看到部分的调用堆栈( vfs_read 和 faulty_read 丢失 ),内核抱怨一 个"坏 EIP 值". 这个抱怨和在开头列出的犯错的地址 ( ffffffff ) 都暗示内核堆栈已 被破坏.

 

通常,当你面对一个 oops,第一件事是查看发生问题的位置,常常与调用堆栈分开列出. 在上面展示的第一个 oops,相关的行是:

 

EIP is at faulty_write+0x4/0x10 [faulty]

 

这里我们看到,我们曾在函数 faulty_write,它位于 faulty 模块( 在方括号中列出 的 ). 16 进制数指示指令指针是函数内 4 字节,函数看来是 10 ( 16 进制 )字节长. 常常这就足够来知道问题是什么.

 

如果你需要更多信息,调用堆栈展示给你如何得知在哪里坏事的. 堆栈自己是 16 机制形 式打印的; 做一点工作,你经常可以从堆栈的列表中决定本地变量的值和函数参数. 有经 验的内核开发者可以从这里的某些模式识别中获益; 例如,如果你看来自 faulty_read oops 的堆栈列表:

 

Stack: ffffffff bfffda70 00002000 cf434f20 00000001 00000286 cf434f00 fffffff7 bfffda70 c27fe000 c0150612 cf434f00 bfffda70 00002000 cf434f20 00000000 00000003 00002000 c0103f8f 00000003 bfffda70 00002000 00002000 bfffda70

 

堆栈顶部的 ffffffff 是我们坏事的字串的一部分. 在 x86 体系,缺省地,用户空间堆 栈开始于 0xc0000000; 因此,循环值 0xbfffda70 可能是一个用户堆栈地址; 实际上,它是传递给 read 系统调用的缓存地址,每次下传过系统调用链时都被复制. 在 x86 (又 一次,缺省地),内核空间开始于 0xc0000000,因此这个之上的值几乎肯定是内核空间的 地址,等等.

 

最后,当看一个 oops 列表,一直监视本章开始讨论的"slab 毒害"值. 例如,如果你得到 一个内核 oops,里面的犯错地址时 0xa5a5a5a5a5,你几乎肯定 - 某个地方在初始化动 态内存.

 

请注意,只在你的内核是打开 CONfig_KALLSymS 选项而编译时可以看到符号的调用堆栈. 否则,你见到一个裸的,16 机制列表,除非你以别的方式对其解码,它是远远无用的.

大佬总结

以上是大佬教程为你收集整理的linux oops 消息全部内容,希望文章能够帮你解决linux oops 消息所遇到的程序开发问题。

如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。