一. 根据栈信息分析函数调用过程(如果没有回溯信息)
在函数调用中,一方面要执行,一方面要跳到返回地址(需要保存返回地址lr(在栈里面保存))
# ./firstdrvtest on
Unable to handle kernel paging request at virtual address 56000050
pgd = c3e78000
[56000050] *pgd=00000000
Internal error: Oops: 5 [#1]
Modules linked in: first_drv
CPU: 0 Not tainted (2.6.22.6 #48)
PC is at first_drv_open+0x18/0x3c [first_drv]
LR is at chrdev_open+0x14c/0x164
pc : [<bf000018>] lr : [<c008c888>] psr: a0000013
############################################################
###########################################################
看System.map确定内核的函数的地址范围:c0004000~c03265a4
先看看加载的驱动程序的函数的地址范围
cat /proc/kallsyms (内核函数、加载的函数的地址)(k代表内核,all代表所有,syms代表符号(函数))
把输出信息放到一个文件里面去,好分析
里面的t代表静态函数,T代表全局函数
从这些信息里找到一个相近的地址, 这个地址<=0xbf000018(加载函数地址以bf0开头,内核函数地址以c0开头)
############################################################
###########################################################
3.1 根据PC确定出错位置
bf000018 属于 insmod的模块
bf000000 t first_drv_open [first_drv]
3.2 确定它属于哪个函数
反汇编first_drv.ko
00000000 <first_drv_open>:
0: e1a0c00d
mov ip, sp
4: e92dd800
stmdb sp!, {fp, ip, lr, pc} //先把寄存器保存到栈里面
8: e24cb004
sub fp, ip, #4; 0x4
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
first_drv_open函数栈信息:出错时把栈打印出来,从下往上打印
由于sp指向的栈空间存储fp, ip, lr, pc
相应的寄存器可以参考<Linux应用开发完全手册>的71页。
下面部分是 first_drv_open函数的栈,往上是调用者的栈
sp : c3e69e88 ip : c3e69e98 fp : c3e69e94
r10: 00000000 r9 : c3e68000 r8 : c0490620
r7 : 00000000 r6 : 00000000 r5 : c3e320a0 r4 : c06a8300
r3 : bf000000 r2 : 56000050 r1 : bf000964 r0 : 00000000
Flags: NzCv IRQs on FIQs on Mode SVC_32 Segment user
Control: c000717f Table: 33e78000 DAC: 00000015
Process firstdrvtest (pid: 752, stack limit = 0xc3e68258)
Stack: (0xc3e69e88 to 0xc3e6a000)
//c008c888 是返回地址, first_drv_open函数调用完后就会返回到他的调用者的地址lr,因为是c00开头的,所以是内核的函数,反汇编内核,在反汇编文件里面搜索地址c008c888就可以知道是哪一个函数,往前面查找到 chrdev_open函数。后面00000000 c0490620 是调用者的栈,9个寄存器共占据9格,
9e80: c3e69ebc c3e69e98 c008c888 bf000010 | 00000000 c0490620
first_drv_open'sp (占4格) lr chrdev_open'sp(占9格)
这里把sp-4(可能需要存局部变量),也就是共10格(每格4个字节)这个解析是栈指针向下移动
9ea0: c3e320a0 c008c73c c0465e20 c3e36cb4 c3e69ee4 c3e69ec0 c0088e48c008c74c |
lr
9ec0: c0490620 c3e69f04 00000003 ffffff9c c002b044 c06e0000 c3e69efc c3e69ee8
__dentry_open'sp(共10个寄存器)后面没有对sp的加减
9ee0: c0088f64 c0088d58 |00000000 00000002 c3e69f68 c3e69f00c0088fb8 c0088f40 |
lr nameidata_to_filp'sp lr
占5个寄存器,这里sp再减4,共占据6个4字节
9f00: c3e69f04 c3e36cb4 c0465e20 00000000 00000000 c3e79000 00000101 00000001
do_filp_open'sp
这里有sp的运算,而sp-84,84/4=21,加寄存器共占27个字
9f20: 00000000 c3e68000 c04c1468 c04c1460 ffffffe8 c06e0000 c3e69f68 c3e69f48
9f40: c008916c c009ec70 00000003 00000000 c0490620 00000002 be94eee0 c3e69f94
9f60: c3e69f6c c00892f4 c0088f88| 00008520 be94eed4 0000860c 00008670 00000005
lr do_sys_open'sp
共占据11个
9f80: c002b044 4013365c c3e69fa4 c3e69f98 c00893a8 c00892b0 |00000000 c3e69fa8
lr sys_open'sp
9fa0: c002aea0 c0089394| be94eed4 0000860c 00008720 00000002 be94eee0 00000001
lr ret_fast_syscall'sp
9fc0: be94eed4 0000860c 00008670 00000002 00008520 00000000 4013365c be94eea8
9fe0: 00000000 be94ee84 0000266c 400c98e0 60000010 00008720 00000000 00000000