调试技巧(一):OOPS调试

版权声明:转载请声明 https://blog.csdn.net/qq_40732350/article/details/84497891

当内核出现类似用户空间的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

猜你喜欢

转载自blog.csdn.net/qq_40732350/article/details/84497891