使用GDB来定位调试内核模块


Creative Commons LicenseCreative Commons LicenseCreative Commons License

使用GDB来定位调试内核模块的Crash,本文根据一个内核模块空指针访问的实例来简单的说明如何调试定位空指针访问的位置

1 现场Crash实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
Unable to handle kernel NULL pointer dereference at virtual address 00000024
[  587.678347] pgd = c0004000
[  587.678352] [00000024] *pgd=00000000
[  587.678363] Internal error: Oops: 17 [#1] PREEMPT SMP
[  587.678369] Modules linked in: drv_svip drv_tapi drv_event_logger drv_ifxos
[  587.678417] CPU: 3    Not tainted  (3.0.35 #158)
[  587.678526] PC is at VMMC_SIG_CIDR_OnEvent+0x68/0x1c4 [drv_svip]
[  587.678546] LR is at get_parent_ip+0x10/0x2c
[  587.678555] pc : [<bf3aee34>]    lr : [<c00611e0>]    psr: 20000113
[  587.678559] sp : e54c1f28  ip : c002de80  fp : e54c0000
[  587.678565] r10: 00000002  r9 : 31000002  r8 : bf3ceec0
[  587.678572] r7 : ec0a7000  r6 : e5473f60  r5 : ec0b9004  r4 : ec0b9000
[  587.678579] r3 : 00000000  r2 : e54c1f18  r1 : 60000013  r0 : 00000000
[  587.678588] Flags: nzCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment user
[  587.678596] Control: 10c53c7d  Table: 3540c04a  DAC: 00000015
[  587.678604] Process tSVIP0_Hnd (pid: 12287, stack limit = 0xe54c02f0)
[  587.678612] Stack: (0xe54c1f28 to 0xe54c2000)
[  587.678621] 1f20: bf3d11f0 e5473f60 bf3ceec0 bf3d1204 ec0a7000 34000006
[  587.678633] 1f40: 31000002 34000005 e54c0000 c03a5e50 e5473f60 e5473f60 bf3ceec0 bf3d1204
[  587.678644] 1f60: ec0a7000 34000006 34000005 bf3a7e08 e9ef8ea4 c002d760 20000093 c00a4704
[  587.678655] 1f80: bf3d11a8 e9ef8e40 c0514944 e5173c40 ffffffff c0087c64 00000001 e54c0000
[  587.678666] 1fa0: e54c1fb4 c0061290 e54c0000 00000000 00000000 00000000 00000000 00000000
[  587.678677] 1fc0: 00000000 00000000 e54c0000 bf3d11a8 bf33e438 c0035a50 00000013 00000000
[  587.678688] 1fe0: 00000000 00000000 00000000 bf33e4c0 bf3d11a8 c0035a50 00000000 00000000
[  587.678762] [<bf3aee34>] (VMMC_SIG_CIDR_OnEvent+0x68/0x1c4 [drv_svip]) from [<bf3a7e08>] (SVIP_HandlerTask+0x65c/0x1100 [drv_svip])
[  587.678845] [<bf3a7e08>] (SVIP_HandlerTask+0x65c/0x1100 [drv_svip]) from [<bf33e4c0>] (IFXOS_KernelThreadStartup+0x88/0xa8 [drv_ifxos])
[  587.678886] [<bf33e4c0>] (IFXOS_KernelThreadStartup+0x88/0xa8 [drv_ifxos]) from [<c0035a50>] (kernel_thread_exit+0x0/0x8)
[  587.678902] Code: e1a00005 ebfe3ddd e5943000 e35a0000 (e5937024)

2 基本步骤

2.1 首先你的运行内核模块不能strip,需要带上调试符号

1
2
CC=arm-linux-gcc COPTS=-g make ARCH=arm -C dir modules
//不同的编译环境可能加调试的方法不一样,请根据实际情况增加

2.2 找到内核模块加载的位置

1
2
3
4
cat /proc/modules |grep drv_svip
drv_svip 245576 0 - Live 0xbf3a6000
///如果你的内核模块在加载过程中就出现crash了,那么你可能在你看不到加载之后的地址,
// 那么就需要使用其他的方式来跟踪,比如直接加prink来跟踪

2.3 找到模块代码中 (text section) 的偏移量

1
2
3
4
5
6
7
arm-none-linux-gnueabi-objdump --section-headers drv_svip.o
Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         000248d8  00000000  00000000  00000034  2**2
....
这里text section的偏移为00000034,模块代码运行的位置就是:
0xbf3a6000 + 00000034  = 0xbf3a6034

2.4 使用GDB来跟踪代码位置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
arm-none-linux-gnueabi-gdb vmlinux
...
Reading symbols from vmlinux...done.
/*使用add-symbol-file命令加载模块的符号表,指定偏移为0xbf3a6000
* 上诉模块的加载地址,如果不可以使用加text section偏移后的地址
* 0xbf3a6034
*/
(gdb) add-symbol-file drv_svip.ko 0xbf3a6000
add symbol table from file "drv_svip.ko" at
.text_addr = 0xbf3a6034
(y or n) y
Reading symbols from drv_svip.ko...done
/*使用list命令显示crash现象里的PC指针的位置*/
(gdb) l *0xbf3aee34
0xbf3aee34 is in VMMC_SIG_CIDR_OnEvent (drv_svip_cid.c:3522).
3517
3518    /* protect resource */
3519    SVIP_OS_MutexGet (&pCidr->mtxAcc);
3520
3521    /* retrieve handler for error stack */
3522    pCh = pCidr->pSig->pCh;
3523
3524    if (nLength)
/*使用list命令显示函数地址加偏移的位置*/
(gdb) l *(VMMC_SIG_CIDR_OnEvent+0x68)
0xbf3aee68 is in VMMC_SIG_CIDR_OnEvent (drv_svip_cid.c:3522).
3517
3518    /* protect resource */
3519    SVIP_OS_MutexGet (&pCidr->mtxAcc);
3520
3521    /* retrieve handler for error stack */
3522    pCh = pCidr->pSig->pCh;
3523
3524    if (nLength)
3525    {

3 其他方式

如果设备现场被破坏,找不到模块加载地址,如何只是要查看某个函数偏移,比如VMMC_SIG_UTG_OnEvent+ 0x124
可以直接利用.o文件来定位位置

1
2
3
4
5
6
7
VMMC_SIG_UTG_OnEvent (../vmmc/drv_vmmc_sig_utg.c:634)
add-symbol-file ../vmmc/drv_vmmc_sig_utg.o 0x0
add symbol table from file "../vmmc/drv_vmmc_sig_utg.o" at
.text_addr = 0x0
(y or n) y
Reading symbols from ../vmmc/drv_vmmc_sig_utg.o...done.
(gdb) l *(VMMC_SIG_UTG_OnEvent+0x124)

4 总结

总结:本文只是一个简单使用GDB来定位内核模块crash的方法,实际情况多少会有些不同。如果有什么不对的地方欢迎指正。

-------------本文结束感谢您的阅读-------------
如果文章对您有帮助,也可以打赏支持喔!