Linux内核调试之Oops信息
int * ptest = NULL;
*ptest = 0xabcd;
如下:
Linux内核执行到这里就会出错,产生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,%eax
c1000015: 8e d8 mov %eax,%ds
c1000017: 8e c0 mov %eax,%es
c1000019: 8e e0 mov %eax,%fs
c100001b: 8e e8 mov %eax,%gs
c100001d: fc cld
c100001e: 31 c0 xor %eax,%eax
c1000020: bf 00 90 7a 01 mov $0x17a9000,%edi
c1000025: b9 5c b8 83 01 mov $0x183b85c,%ecx
c100002a: 29 f9 sub %edi,%ecx
c100002c: c1 e9 02 shr $0x2,%ecx
c100002f: f3 ab rep stos %eax,%es:(%edi)
c1000031: bf e0 99 73 01 mov $0x17399e0,%edi
c1000036: b9 00 04 00 00 mov $0x400,%ecx
c100003b: fc cld
c100003c: f3 a5 rep movsl %ds:(%esi),%es:(%edi)
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,%edi
c100004d: b9 00 02 00 00 mov $0x200,%ecx
c1000052: f3 a5 rep movsl %ds:(%esi),%es:(%edi)
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,%eax
c1000064: 3d 04 00 00 00 cmp $0x4,%eax
c1000069: 73 0e jae c1000079
c100006b: 8b 04 85 c0 72 73 01 mov 0x17372c0(,%eax,4),%eax
c1000072: 2d 00 00 00 c0 sub $0xc0000000,%eax
c1000077: ff e0 jmp *%eax
..................................................
BUG: unable to handle kernel NULL pointer dereference at (null)
这是Oops信息的字符串说明,说明我们访问了NULL指针
IP: [] i2c_init+0x9/0x63
c172f5fe: 5e pop %esi
c172f5ff: 5f pop %edi
c172f600: 5d pop %ebp
c172f601: c3 ret
c172f602 :
c172f602: 55 push %ebp
c172f603: b8 20 c0 6d c1 mov $0xc16dc020,%eax
c172f608: 89 e5 mov %esp,%ebp
c172f60a: 53 push %ebx
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 %eax,%eax
c172f61c: 89 c3 mov %eax,%ebx
c172f61e: 75 40 jne c172f660
c172f620: b8 67 ee 63 c1 mov $0xc163ee67,%eax
c172f625: e8 36 ab bd ff call c130a160
c172f62a: 85 c0 test %eax,%eax
c172f62c: a3 d4 76 83 c1 mov %eax,0xc18376d4
c172f631: 74 1e je c172f651
这正好是在i2c_init函数中。
i2c_init+0x9/0x63
表示出错的是在i2c_init函数的起始地址(0xc172f602)偏移0x9的位置,而i2c_init函数的大小为0x63个字节,出错处的ip=c172f60b,正好等于0xc172f602+0x9
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
出错指令附近的指令的机器码
利用上面这些信息,我们就可以很快的找到错误的位置啦~~