zoukankan      html  css  js  c++  java
  • 驱动调试(四)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

    点击下载

  • 相关阅读:
    latex
    slab着色,可以减少cache conflict miss概率么?
    内存管理 初始化(八) 至kswapd_init
    内存管理 初始化(七)kmem_cache_init_late 初始化slab分配器(下)
    vmwareubuntu18.04网络配置
    高德地图的一些使用心得
    mongodb聚合管道用法
    python学习链接
    python开发者常犯的10个错误(转)
    vim配置python开发环境(转)
  • 原文地址:https://www.cnblogs.com/zongzi10010/p/10271373.html
Copyright © 2011-2022 走看看