驱动调试(四)oops确定调用树


title: 驱动调试(四)oops确定调用树
date: 2019/1/14 19:30:32
toc: true
---

驱动调试(四)oops确定调用树

内核开启调用树

如果内核开启调用信息的打印

# 这个需要配置内核
#│ Symbol: FRAME_POINTER [=y]                     │
#│ Prompt: Compile the kernel with frame pointers │
#│   Defined at lib/Kconfig.debug:357             │
#│   Depends on: DEBUG_KERNEL && ...............  │
#│   Location:                                    │
#│     -> Kernel hacking                          │
#│       -> Kernel debugging (DEBUG_KERNEL [=y])  

为什么这个选项叫做FRAME_POINTER,因为实际上使用了ARM中的fp寄存器,在A函数调用B函数时,B在开头保存了fb,ip,lr,pc等到栈中,一般情况下就是倒数第4个是fp,这个栈里面的fp也就是父函数的栈底

所以,在栈里面通过寻找fp,倒数第二个就能依次找到LR,依次找到调用树了

mark

能显示出调用关系在oops中

Backtrace:
[<bf000000>] (first_drv_open+0x0/0x3c [first_drv]) from [<c008d888>] (chrdev_open+0x14c/0x164)
[<c008d73c>] (chrdev_open+0x0/0x164) from [<c0089e48>] (__dentry_open+0x100/0x1e8)
 r8:c2ca741c r7:c0474d20 r6:c008d73c r5:c04b2e5c r4:c3e9b700
[<c0089d48>] (__dentry_open+0x0/0x1e8) from [<c0089f64>] (nameidata_to_filp+0x34/0x48)
[<c0089f30>] (nameidata_to_filp+0x0/0x48) from [<c0089fb8>] (do_filp_open+0x40/0x48)
 r4:00000002
[<c0089f78>] (do_filp_open+0x0/0x48) from [<c008a2f4>] (do_sys_open+0x54/0xe4)
 r5:be848ee0 r4:00000002
[<c008a2a0>] (do_sys_open+0x0/0xe4) from [<c008a3a8>] (sys_open+0x24/0x28)
[<c008a384>] (sys_open+0x0/0x28) from [<c002bea0>] (ret_fast_syscall+0x0/0x2c)
Code: e24cb004 e59f1024 e3a00000 e5912000 (e5923000)
Segmentation fault


调用关系如下
ret_fast_syscall
    sys_open
        do_filp_open
            nameidata_to_filp
                __dentry_open
                    chrdev_open
                        first_drv_open
    

栈指针分析

原理

在C函数的调用中,会先保存返回地址(LR)到栈中,也就是说LR的值是调用者的PC值.我们依次找到栈底,找到lr即可.

A()
    B()
        C()
        {
            //B的LR存到C分配的栈中
        }

寄存器别名

  • r15 PC The Program Counter.
  • r14 LR The Link Register.
  • r12 IP The Intra-Procedure-call scratch register. (可简单的认为暂存SP)
  • r11 frame pointer

基础解释

  • 栈底指的是堆栈指针sp所指的起始位置

  • STMDB 先存储,后做减法,也就是sp指向的位置是栈有效的数据,寄存器高地址存高字节

    !:表示最后的地址写回到Rn中
    stmdb   sp!, {fp, ip, lr, pc}

例子分析

找到PC地址的位置

可以看下上一个章节,这里使用模块装载的例子

pc : [<bf000018>]

mark

栈分析

可以看出来栈中的fp指向了父函数的栈底,最后一个函数的fb为0,也就是一个中断函数了图片这里可能看不清,左键拖动可以查看原图(高清)

mark

mark

这里有具体的txt分析,还是excel的图片好看,拖动放大

r15 PC The Program Counter.
r14 LR The Link Register.
r13 SP The Stack Pointer.
r12 IP The Intra-Procedure-call scratch register. (可简单的认为暂存SP)
r11 frame pointer。

栈底指的是堆栈指针sp所指的起始位置


stmdb   sp!, {fp, ip, lr, pc}  
# 高地址存高字节
也就是存储如下
-------------------------------------------------------------------------------
r15 PC The Program Counter.
r14 LR The Link Register.
r12 IP The Intra-Procedure-call scratch register. (可简单的认为暂存SP)
r11 frame pointer。
-------------------------------------------------------------------------------
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


00000000 <first_drv_open>:
   0:   e1a0c00d    mov ip, sp
   4:   e92dd800    stmdb   sp!, {fp, ip, lr, pc}
   8:   e24cb004    sub fp, ip, #4  ; 0x4                           #这里是fp运算后是 c2c81e94
   c:   e59f1024    ldr r1, [pc, #36]   ; 38 <__mod_vermagic5>
  10:   e3a00000    mov r0, #0  ; 0x0
  14:   e5912000    ldr r2, [r1]
  18:   e5923000    ldr r3, [r2]  // 在这里出错 r2=56000050

#****************************************************************************
sp : c2c81e88  ip : c2c81e98  fp : c2c81e94
Stack: (0xc2c81e88 to 0xc2c82000)
1e80: xxxxxxxx xxxxxxxx c2c81ebc c2c81e98 c008d888 bf000010 00000000 c3e38be0
               fp(now)  ↑--fp(old)  ip      LR      PC  ---↑
               
1ea0: c2c3b100 c008d73c c0474e20 c2c8e3c0 c2c81ee4 c2c81ec0 c0089e48 c008d74c
1ec0: c3e38be0 c2c81f04 00000003 ffffff9c c002c044 c070b000 c2c81efc c2c81ee8
#****************************************************************************


>>>>>>>c008d888

c008d73c <chrdev_open>:
c008d73c:   e1a0c00d    mov ip, sp
c008d740:   e92dd9f0    stmdb   sp!, {r4, r5, r6, r7, r8, fp, ip, lr, pc}
c008d744:   e24cb004    sub fp, ip, #4  ; 0x4
c008d748:   e24dd004    sub sp, sp, #4  ; 0x4
...
c008d888:   e2507000    subs    r7, r0, #0  ; 0x0

    
#****************************************************************************
        0       4       8           C       10      14      18      1C
        
Stack: (0xc2c81e88 to 0xc2c82000)
1e80:                   c2c81ebc c2c81e98 c008d888 bf000010 00000000 c3e38be0
               fp(now)  ↑--fp(old)  ip      LR      PC  --↑↑
1ea0: c2c3b100 c008d73c c0474e20 c2c8e3c0 c2c81ee4 c2c81ec0 c0089e48 c008d74c
                                          fp(old)       IP      LR      pc  ↑--------这个位置正好是上面那个被调用函数存储在栈中的fp,也是这里的栈底(起始位置)
1ec0: c3e38be0 c2c81f04 00000003 ffffff9c c002c044 c070b000 c2c81efc c2c81ee8
1ee0: c0089f64 c0089d58 00000000 00000002 c2c81f68 c2c81f00 c0089fb8 c0089f40
1f00: c2c81f04 c2c8e3c0 c0474e20 00000000 00000000 c2cd9000 00000101 00000001
1f20: 00000000 c2c80000 c046dec8 c046dec0 ffffffe8 c070b000 c2c81f68 c2c81f48
#****************************************************************************

这里sp存储了r4, r5, r6, r7, r8, fp, ip, lr, pc,然后再减去4,也就是存储了10个32位数据
这里我们看到
lr=c0089e48
fp(old)=c2c81ee4   上一级函数的栈底

>>>c0089e48

c0089d48 <__dentry_open>:
c0089d48:   e1a0c00d    mov ip, sp
c0089d4c:   e92dddf0    stmdb   sp!, {r4, r5, r6, r7, r8, sl, fp, ip, lr, pc}
....
c0089e38:   e1a00005    mov r0, r5
c0089e3c:   e1a01004    mov r1, r4
c0089e40:   e1a0e00f    mov lr, pc
c0089e44:   e1a0f006    mov pc, r6
c0089e48:   e250a000    subs    sl, r0, #0  ; 0x0

#****************************************************************************
        0       4       8           C       10      14      18      1C
        
Stack: (0xc2c81e88 to 0xc2c82000)
1e80:                   c2c81ebc c2c81e98 c008d888 bf000010 00000000 c3e38be0
               fp(now)  ↑--fp(old)  ip      LR      PC  --↑↑
1ea0: c2c3b100 c008d73c c0474e20 c2c8e3c0 c2c81ee4 c2c81ec0 c0089e48 c008d74c
                                          fp(old)       IP      LR      pc  ↑--------这个位置正好是上面那个被调用函数存储在栈中的fp,也是这里的栈底(起始位置)
1ec0: c3e38be0 c2c81f04 00000003 ffffff9c c002c044 c070b000 c2c81efc c2c81ee8
      ↑                                                     fp(old)     ip
1ee0: c0089f64 c0089d58 00000000 00000002 c2c81f68 c2c81f00 c0089fb8 c0089f40
        lr      pc   ↑ 
                这个地址是 c2c81ee4
                正好是上一级的存在栈中的fp
1f00: c2c81f04 c2c8e3c0 c0474e20 00000000 00000000 c2cd9000 00000101 00000001
1f20: 00000000 c2c80000 c046dec8 c046dec0 ffffffe8 c070b000 c2c81f68 c2c81f48
#****************************************************************************

lr=c0089f64
fp(old)=c2c81efc



c0089f30 <nameidata_to_filp>:
c0089f30:   e1a0c00d    mov ip, sp
c0089f34:   e92dd810    stmdb   sp!, {r4, fp, ip, lr, pc}
c0089f38:   e24cb004    sub fp, ip, #4  ; 0x4
c0089f3c:   e24dd004    sub sp, sp, #4  ; 0x4    ;sp=sp-4 也就是再多4个字节
...
c0089f5c:   e58de000    str lr, [sp]
c0089f60:   ebffff78    bl  c0089d48 <__dentry_open>
c0089f64:   e1a04000    mov r4, r0


#****************************************************************************
        0       4       8           C       10      14      18      1C
        
Stack: (0xc2c81e88 to 0xc2c82000)
1e80:                   c2c81ebc c2c81e98 c008d888 bf000010 00000000 c3e38be0
               fp(now)  ↑--fp(old)  ip      LR      PC  --↑↑
1ea0: c2c3b100 c008d73c c0474e20 c2c8e3c0 c2c81ee4 c2c81ec0 c0089e48 c008d74c
                                          fp(old)       IP      LR      pc  ↑--------这个位置正好是上面那个被调用函数存储在栈中的fp,也是这里的栈底(起始位置)
1ec0: c3e38be0 c2c81f04 00000003 ffffff9c c002c044 c070b000 c2c81efc c2c81ee8
      ↑                                                     fp(old)     ip
1ee0: c0089f64 c0089d58 00000000 00000002 c2c81f68 c2c81f00 c0089fb8 c0089f40
        lr      pc   ↑                    fp(old)       ip      lr      pc这个地址是被调用的存在栈中的fp
                这个地址是 c2c81ee4
                正好是上一级的存在栈中的fp
1f00: c2c81f04 c2c8e3c0 c0474e20 00000000 00000000 c2cd9000 00000101 00000001
1f20: 00000000 c2c80000 c046dec8 c046dec0 ffffffe8 c070b000 c2c81f68 c2c81f48

lr=c0089fb8
fp(old)=c2c81f68




c0089f78 <do_filp_open>:
c0089f78:   e1a0c00d    mov ip, sp
c0089f7c:   e92dd830    stmdb   sp!, {r4, r5, fp, ip, lr, pc}       ;6个
c0089f80:   e24cb004    sub fp, ip, #4  ; 0x4
c0089f84:   e24dd054    sub sp, sp, #84 ; 0x54                      #84/4=21个 21+6=27个
.....
c0089fb4:   0bffffdd    bleq    c0089f30 <nameidata_to_filp>
c0089fb8:   e24bd014    sub sp, fp, #20 ; 0x14


#****************************************************************************
        0       4       8           C       10      14      18      1C
        
Stack: (0xc2c81e88 to 0xc2c82000)
1e80:                   c2c81ebc c2c81e98 c008d888 bf000010 00000000 c3e38be0
               fp(now)  ↑--fp(old)  ip      LR      PC  --↑↑
1ea0: c2c3b100 c008d73c c0474e20 c2c8e3c0 c2c81ee4 c2c81ec0 c0089e48 c008d74c
                                          fp(old)       IP      LR      pc  ↑--------这个位置正好是上面那个被调用函数存储在栈中的fp,也是这里的栈底(起始位置)
1ec0: c3e38be0 c2c81f04 00000003 ffffff9c c002c044 c070b000 c2c81efc c2c81ee8
      ↑                                                     fp(old)     ip
1ee0: c0089f64 c0089d58 00000000 00000002 c2c81f68 c2c81f00 c0089fb8 c0089f40
        lr      pc   ↑                    fp(old)       ip      lr      pc这个地址是被调用的存在栈中的fp
                这个地址是 c2c81ee4
                正好是上一级的存在栈中的fp
1f00: c2c81f04 c2c8e3c0 c0474e20 00000000 00000000 c2cd9000 00000101 00000001
1f20: 00000000 c2c80000 c046dec8 c046dec0 ffffffe8 c070b000 c2c81f68 c2c81f48
1f40: c008a16c c009fc70 00000003 00000000 c3e38be0 00000002 bedd1edc c2c81f94
                                                                      fp(old)
1f60: c2c81f6c c008a2f4 c0089f88 00008520 bedd1ed4 0000860c 00008670 00000005
        Ip      LR      PC↑刚好也是(fp_old)
1f80: c002c044 4013365c c2c81fa4 c2c81f98 c008a3a8 c008a2b0 00000000 c2c81fa8
1fa0: c002bea0 c008a394 bedd1ed4 0000860c 00008720 00000002 bedd1edc 00000001
1fc0: bedd1ed4 0000860c 00008670 00000001 00008520 00000000 4013365c bedd1ea8
1fe0: 00000000 bedd1e84 0000266c 400c98e0 60000010 00008720 00000000 00000000


fp(old)=c2c81f94
lr=c008a2f4



c008a2a0 <do_sys_open>:
c008a2a0:   e1a0c00d    mov ip, sp
c008a2a4:   e92dddf0    stmdb   sp!, {r4, r5, r6, r7, r8, sl, fp, ip, lr, pc}
c008a2a8:   e24cb004    sub fp, ip, #4  ; 0x4
c008a2ac:   e24dd004    sub sp, sp, #4  ; 0x4                                   ;10+1=11
.....
c008a2ec:   ba00001d    blt c008a368 <do_sys_open+0xc8>
c008a2f0:   ebffff20    bl  c0089f78 <do_filp_open>
c008a2f4:   e1a08000    mov r8, r0

  
#****************************************************************************
        0       4       8           C       10      14      18      1C
        
Stack: (0xc2c81e88 to 0xc2c82000)
1e80:                   c2c81ebc c2c81e98 c008d888 bf000010 00000000 c3e38be0
               fp(now)  ↑--fp(old)  ip      LR      PC  --↑↑
1ea0: c2c3b100 c008d73c c0474e20 c2c8e3c0 c2c81ee4 c2c81ec0 c0089e48 c008d74c
                                          fp(old)       IP      LR      pc  ↑--------这个位置正好是上面那个被调用函数存储在栈中的fp,也是这里的栈底(起始位置)
1ec0: c3e38be0 c2c81f04 00000003 ffffff9c c002c044 c070b000 c2c81efc c2c81ee8
      ↑                                                     fp(old)     ip
1ee0: c0089f64 c0089d58 00000000 00000002 c2c81f68 c2c81f00 c0089fb8 c0089f40
        lr      pc   ↑                    fp(old)       ip      lr      pc这个地址是被调用的存在栈中的fp
                这个地址是 c2c81ee4
                正好是上一级的存在栈中的fp
1f00: c2c81f04 c2c8e3c0 c0474e20 00000000 00000000 c2cd9000 00000101 00000001
1f20: 00000000 c2c80000 c046dec8 c046dec0 ffffffe8 c070b000 c2c81f68 c2c81f48
1f40: c008a16c c009fc70 00000003 00000000 c3e38be0 00000002 bedd1edc c2c81f94
                                                                        fp(old)
1f60: c2c81f6c c008a2f4 c0089f88 00008520 bedd1ed4 0000860c 00008670 00000005
        Ip      LR      PC↑刚好也是(fp_old)
1f80: c002c044 4013365c c2c81fa4 c2c81f98 c008a3a8 c008a2b0 00000000 c2c81fa8
                        fp_old          ip      lr      pc ↑
                                                 
1fa0: c002bea0 c008a394 bedd1ed4 0000860c 00008720 00000002 bedd1edc 00000001
1fc0: bedd1ed4 0000860c 00008670 00000001 00008520 00000000 4013365c bedd1ea8
1fe0: 00000000 bedd1e84 0000266c 400c98e0 60000010 00008720 00000000 00000000
  
  
  
 lr=c008a3a8 
 fp_old=c2c81fa4
 
 
 
 c008a384 <sys_open>:
c008a384:   e1a0c00d    mov ip, sp
c008a388:   e92dd800    stmdb   sp!, {fp, ip, lr, pc}
...
c008a3a4:   ebffffbd    bl  c008a2a0 <do_sys_open>
c008a3a8:   e89da800    ldmia   sp, {fp, sp, pc}


#****************************************************************************
        0       4       8           C       10      14      18      1C
        
Stack: (0xc2c81e88 to 0xc2c82000)
1e80:                   c2c81ebc c2c81e98 c008d888 bf000010 00000000 c3e38be0
               fp(now)  ↑--fp(old)  ip      LR      PC  --↑↑
1ea0: c2c3b100 c008d73c c0474e20 c2c8e3c0 c2c81ee4 c2c81ec0 c0089e48 c008d74c
                                          fp(old)       IP      LR      pc  ↑--------这个位置正好是上面那个被调用函数存储在栈中的fp,也是这里的栈底(起始位置)
1ec0: c3e38be0 c2c81f04 00000003 ffffff9c c002c044 c070b000 c2c81efc c2c81ee8
      ↑                                                     fp(old)     ip
1ee0: c0089f64 c0089d58 00000000 00000002 c2c81f68 c2c81f00 c0089fb8 c0089f40
        lr      pc   ↑                    fp(old)       ip      lr      pc这个地址是被调用的存在栈中的fp
                这个地址是 c2c81ee4
                正好是上一级的存在栈中的fp
1f00: c2c81f04 c2c8e3c0 c0474e20 00000000 00000000 c2cd9000 00000101 00000001
1f20: 00000000 c2c80000 c046dec8 c046dec0 ffffffe8 c070b000 c2c81f68 c2c81f48
1f40: c008a16c c009fc70 00000003 00000000 c3e38be0 00000002 bedd1edc c2c81f94
                                                                        fp(old)
1f60: c2c81f6c c008a2f4 c0089f88 00008520 bedd1ed4 0000860c 00008670 00000005
        Ip      LR      PC↑刚好也是(fp_old)
1f80: c002c044 4013365c c2c81fa4 c2c81f98 c008a3a8 c008a2b0 00000000 c2c81fa8
                        fp_old          ip      lr      pc ↑ fp(old)    ip
                                                 
1fa0: c002bea0 c008a394 bedd1ed4 0000860c 00008720 00000002 bedd1edc 00000001
        lr      pc ↑
1fc0: bedd1ed4 0000860c 00008670 00000001 00008520 00000000 4013365c bedd1ea8
1fe0: 00000000 bedd1e84 0000266c 400c98e0 60000010 00008720 00000000 00000000


lr=c008a3a8
fp(old)=00000000 这里没有了,从下面来看 确实没有了,没有再操作fp了

ret_fast_syscall 软中断了

c002bea0 <ret_fast_syscall>:
c002bea0:   e321f093    msr CPSR_c, #147    ; 0x93
c002bea4:   e5991000    ldr r1, [r9]
c002bea8:   e31100ff    tst r1, #255    ; 0xff
c002beac:   1a000006    bne c002becc <fast_work_pending>
c002beb0:   e59d1048    ldr r1, [sp, #72]
c002beb4:   e5bde044    ldr lr, [sp, #68]!
c002beb8:   e16ff001    msr SPSR_fsxc, r1
c002bebc:   e95d7ffe    ldmdb   sp, {r1, r2, r3, r4, r5, r6, r7, r8, r9, sl, fp, ip, sp, lr}^
c002bec0:   e1a00000    nop         (mov r0,r0)
c002bec4:   e28dd00c    add sp, sp, #12 ; 0xc
c002bec8:   e1b0f00e    movs    pc, lr  

附录:原文的excel

点击下载

转载于:https://www.cnblogs.com/zongzi10010/p/10271373.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值