oops消息的产生
网上一分析oop流程的帖子, 留着以后看.
http://blog.sina.com.cn/s/blog_3e4774e30100ooey.html
oops消息的例子
1. 引用空指针
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_write 后 四个字节。
2. 堆栈被破坏
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.
这个错误信息比较隐晦的。 说的是,找不到一个虚拟地址。 EIP一看就是个乱七八糟的值。
call trace不完整,只指示到了 sys_read。
造成错误的源代码是:
ssize_t faulty_read(struct file *filp, char __user *buf,
size_t count, 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;
}
出错的这段,是memset的时候,把stack破坏了。
利用oops消息定位出错位置
网上这两个例子不错
http://www.jishuziyuan.com/archive/myxemu/8252895.html
http://blog.chinaunix.net/uid-26318308-id-3395285.html
还有一个linus老人家自己的邮件
http://yarchive.net/comp/linux/oops_decoding.html
1. 有编译好的源代码
gdb vmlinux
(gdb)b *func+offset
or
(gdb)l *func+offset
2. 有编译好的源代码, 用objdump看
objdump -S net/core/dev.o > /tmp/dev.s
然后自己数...
3. 有编译好的源代码,用addr2line看
addr2line -e vmlinux func+offset
算好这个值,或者直接用oops上值.
4. 没有编译好的源代码,只有消息
在代码中是哪里输出的oops消息
在x86的系统中,die函数在arch/x86/kernel/dumpstack.c