除錯技巧(一):OOPS除錯
阿新 • • 發佈:2018-11-26
當核心出現類似使用者空間的Segmentation Fault時(例如核心訪問一個並不存在的虛擬地址), Oops會被列印到控制檯和寫入核心log緩衝區。
我們在globalmem.c的globalmem_read()函式中加上下面一行程式碼
} else {
*ppos += count;
ret = count;
*(unsigned int *)0 = 1; /* a kernel panic */
printk(KERN_INFO "read %u bytes(s) from %lu\n", count, p
}
假設這個字元裝置對應的裝置節點是/dev/globalmem,通過cat/dev/globalmem命令讀裝置檔案,將得到如下Oops資訊:
# cat /dev/globalmem Unable to handle kernel NULL pointer dereference at virtual address 0000 pgd = 9ec08000 [00000000] *pgd=7f733831, *pte=00000000, *ppte=00000000 Internal error: Oops: 817 [#1] SMP ARM Modules linked in: globalmem CPU: 0 PID: 609 Comm: cat Not tainted 3.16.0+ #13 task: 9f7d8000 ti: 9f722000 task.ti: 9f722000 PC is at globalmem_read+0xbc/0xcc [globalmem] LR is at 0x0 pc : [<7f000200>] lr : [<00000000>] psr: 00000013 sp : 9f723f30 ip : 00000000 fp : 00000000 r10: 9f414000 r9 : 00000000 r8 : 00001000 r7 : 00000000 r6 : 00001000 r5 : 00001000 r4 : 00000000 r3 : 00000001 r2 : 00000000 r1 : 00001000 r0 : 7f0003cc Flags: nzcv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user Control: 10c53c7d Table: 7ec08059 DAC: 00000015 Process cat (pid: 609, stack limit = 0x9f722240) Stack: (0x9f723f30 to 0x9f724000) 3f20: 7ed5ff91 9f723f80 00000000 9f7 3f40: 00001000 7ed5eb18 9f723f80 00000000 00000000 800cb114 00000020 9f7 3f60: 9f5e4628 9f79ab40 9f79ab40 00001000 7ed5eb18 00000000 00000000 800 3f80: 00001000 00000000 9f7168c0 00001000 7ed5eb18 00000003 00000003 800 3fa0: 9f722000 8000e360 00001000 7ed5eb18 00000003 7ed5eb18 00001000 000 3fc0: 00001000 7ed5eb18 00000003 00000003 7ed5eb18 00000001 00000003 000 3fe0: 0015c23c 7ed5eb00 0000f718 00008d8c 60000010 00000003 00000000 000 [<7f000200>] (globalmem_read [globalmem]) from [<800cb114>] (vfs_read+0x [<800cb114>] (vfs_read) from [<800cb2ec>] (SyS_read+0x44/0x84) [<800cb2ec>] (SyS_read) from [<8000e360>] (ret_fast_syscall+0x0/0x30) Code: e1a05008 e2a77000 e1c360f0 e3a03001 (e58c3000) ---[ end trace 5a36d6470da50d02 ]--- Segmentation fault
上述Oops的第一行給出了“原因”,即訪問了NULLpointer。 Oops中的PC is at globalmem_read+0xbc/0xcc這一行程式碼也比較關鍵,給出了“事發現場”,即globalmem_read()函式偏移0xbc位元組的指令處。
通過反彙編globalmem.o可以尋找到globalmem_read()函式開頭位置偏移0xbc的指令,反彙編方法如下:
arm-linux-objdump -d -S globalmem.o > err.txt
對應的反彙編程式碼如下, global_read()開始於0x144,偏移0xbc的位置為0x200:
static ssize_t globalmem_read(struct file *filp, char __user * buf, size
loff_t * ppos)
{
144: e92d45f0 push {r4, r5, r6, r7, r8, sl, lr}
148: e24dd00c sub sp, sp, #12
//unsigned long p = *ppos;
14c: e5934000 ldr r4, [r3]
//*ppos += count;
1f4: e2a77000 adc r7, r7, #0
1f8: e1c360f0 strd r6, [r3]
//ret = count;
//*(unsigned int *)0 = 1; /* a kernel panic */
1fc: e3a03001 mov r3, #1
200: e58c3000 str r3, [ip]
//printk(KERN_INFO "read %u bytes(s) from %lu\n", count, p);
//return ret;
}
“str r3, [ip]”是引起Oops的指令。這裡僅僅給出了一個例子,工程實踐中的“事發現場”並不全那麼容易找到,但方法都是類似的。
也可以參考:
https://www.cnblogs.com/haomcu/p/4385517.html