例子:为了测试Oops信息,这里我们可以任意选择一个内核文件做测试,我以i2c为例:
1.
修改linux源代码/drivers/i2c/i2c-core.c
在函数static int __init i2c_init(void)的开头添加如下语句:
- int
* ptest = NULL; - *ptest
= 0xabcd;
如下:
Linux内核执行到这里就会出错,产生Oops信息
2.
然后在menuconfig中将i2c编译进内核:
make menuconfig
在Device Drivers中选择I2C support,把I2C编译进内核
3.
重新编译内核,然后用该内核启动
4.
果然出现了Oops信息啦~~如下图:

上图中的从第7行Bug开始到最后就是Oops信息
5.
为了将Oops信息中的机器码地址和源文件相对应,我们还要将编译好的内核镜像反汇编以便对照,但由于我们之前用make bzImage命令来生成bzImage内核压缩镜像,无法反汇编,所以我们运行如下命令:
make vmlinux
这样生成的内核镜像大约150M!
6.
将第5步生成的无压缩的内核镜像反汇编:
objdump -D vmlinux > vmlinux.dis
生成的vmlinux.dis大约500M!呵呵,如下:
- vmlinux:
file format elf32-i386 -
-
- Disassembly
of section .text: -
- c1000000
<_text>: - c1000000:
f6 86 11 02 00 00 40 testb $0x40,0x211(%esi) - c1000007:
75 14 jne c100001d <_text+0x1d> - c1000009:
0f 01 15 16 4e 6a 01 lgdtl 0x16a4e16 - c1000010:
b8 18 00 00 00 mov $0x18,�x - c1000015:
8e d8 mov �x,%ds - c1000017:
8e c0 mov �x,%es - c1000019:
8e e0 mov �x,%fs - c100001b:
8e e8 mov �x,%gs - c100001d:
fc cld - c100001e:
31 c0 xor �x,�x - c1000020:
bf 00 90 7a 01 mov $0x17a9000,�i - c1000025:
b9 5c b8 83 01 mov $0x183b85c,�x - c100002a:
29 f9 sub �i,�x - c100002c:
c1 e9 02 shr $0x2,�x - c100002f:
f3 ab rep stos �x,%es:(�i) - c1000031:
bf e0 99 73 01 mov $0x17399e0,�i - c1000036:
b9 00 04 00 00 mov $0x400,�x - c100003b:
fc cld - c100003c:
f3 a5 rep movsl %ds:(%esi),%es:(�i) - c100003e:
8b 35 08 9c 73 01 mov 0x1739c08,%esi - c1000044:
21 f6 and %esi,%esi - c1000046:
74 0c je c1000054 <_text+0x54> - c1000048:
bf 00 73 73 01 mov $0x1737300,�i - c100004d:
b9 00 02 00 00 mov $0x200,�x - c1000052:
f3 a5 rep movsl %ds:(%esi),%es:(�i) - c1000054:
66 81 3d e6 9b 73 01 cmpw $0x207,0x1739be6 - c100005b:
07 02 - c100005d:
72 1c jb c100007b - c100005f:
a1 1c 9c 73 01 mov 0x1739c1c,�x - c1000064:
3d 04 00 00 00 cmp $0x4,�x - c1000069:
73 0e jae c1000079 - c100006b:
8b 04 85 c0 72 73 01 mov 0x17372c0(,�x,4),�x - c1000072:
2d 00 00 00 c0 sub $0xc0000000,�x - c1000077:
ff e0 jmp *�x -
-
..................................................
- BUG:
unable to handle kernel NULL pointer dereference at (null)
这是Oops信息的字符串说明,说明我们访问了NULL指针
- IP:
[] i2c_init+0x9/0x63
表示内核错误处的ip指针,在vmlinux.dis中搜索“c172f60b”,找到如下:
- c172f5fe:
5e pop %esi - c172f5ff:
5f pop �i - c172f600:
5d pop �p - c172f601:
c3 ret -
- c172f602
: - c172f602:
55 push �p - c172f603:
b8 20 c0 6d c1 mov $0xc16dc020,�x - c172f608:
89 e5 mov %esp,�p - c172f60a:
53 push �x - c172f60b:
c7 05 00 00 00 00 cd movl $0xabcd,0x0 - c172f612:
ab 00 00 - c172f615:
e8 c6 92 bd ff call c13088e0 - c172f61a:
85 c0 test �x,�x - c172f61c:
89 c3 mov �x,�x - c172f61e:
75 40 jne c172f660 - c172f620:
b8 67 ee 63 c1 mov $0xc163ee67,�x - c172f625:
e8 36 ab bd ff call c130a160 - c172f62a:
85 c0 test �x,�x - c172f62c:
a3 d4 76 83 c1 mov �x,0xc18376d4 - c172f631:
74 1e je c172f651
- i2c_init+0x9/0x63
- Pid:
1
发生错误的进程ID
- [
0.992003] EIP: 0060:[] EFLAGS: 00010246 CPU: 0 - [
0.992003] EIP is at i2c_init+0x9/0x63 - [
0.992003] EAX: c16dc020 EBX: c1785e34 ECX: 00000000 EDX: 00000000 - [
0.992003] ESI: c16fe164 EDI: 00000000 EBP: df071f98 ESP: df071f94 - [
0.992003] DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068 - [
0.992003] Process swapper (pid: 1, ti=df070000 task=df068000 task.ti=df070)
发生错误时的各个寄存器的值,其中的CPU: 0表示发生错误的CPU编号,对于单处理器系统来说,编号为0
- [
1.240004] Call Trace: - [
1.240004] [] ? do_one_initcall+0x32/0x1a0 - [
1.240004] [] ? i2c_init+0x0/0x63 - [
1.240004] [] ? kernel_init+0x12d/0x183 - [
1.240004] [] ? kernel_init+0x0/0x183 - [
1.240004] [] ? kernel_thread_helper+0x7/0x10
- Code:
89 18 83 7d ec 00 0f 85 64 ff ff ff 31 db b8 00 c0 6d c1 e8
利用上面这些信息,我们就可以很快的找到错误的位置啦~~