我学习了所有由Free Electrons创建的免费 Linux 培训材料。在上一个实验中,我们学习了使用 kgdb 远程调试可加载模块中的简单崩溃。崩溃是由 memzero 函数调用中的空指针取消引用引起的。
我正在使用 Linux 内核 4.9 和 BeagleBone Black 作为目标,所有这些都是根据实验室的建议进行的,到目前为止我还没有遇到任何问题。我的主机是 Ubuntu xenial,我正在使用 ARM 工具链 (Ubuntu/Linaro 5.4.0-6ubuntu1~16.04.4) 和 gdb (7.11.1-0ubuntu1~16.04) 调试器的标准包。
gdb 能够从 vmlinux 和包含 bug 的模块(称为 drvbroken.ko)中读取符号表。该模块在其 init 函数中有一个错误,因此当我对其进行安装时它会立即崩溃。
gdb 输出:
(gdb) backtrace
#0 __memzero () at arch/arm/lib/memzero.S:69
#1 0x00000000 in ?? ()
Backtrace stopped: previous frame identical to this frame (corrupt stack?)
(gdb) list 69
64 ldmeqfd sp!, {pc} @ 1/2 quick exit
65 /*
66 * No need to correct the count; we're only testing bits from now on
67 */
68 tst r1, #32 @ 1
69 stmneia r0!, {r2, r3, ip, lr} @ 4
70 stmneia r0!, {r2, r3, ip, lr} @ 4
71 tst r1, #16 @ 1 16 bytes or more?
72 stmneia r0!, {r2, r3, ip, lr} @ 4
73 ldr lr, [sp], #4 @ 1
无论我使用 CONFIG_ARM_UNWIND(默认值)还是禁用它并使用 CONFIG_FRAME_POINTER(实验室笔记推荐的旧方法)构建内核,结果都是一样的。
我在 kdb 中尝试了相同的过程,在这里我看到了一个很长的回溯,其中包括调用函数。memzero 的调用者是 cdev_init。
kdb 输出:
Entering kdb (current=0xde616240, pid 106) on processor 0 Oops: (null)
due to oops @ 0xc04c2be0
CPU: 0 PID: 106 Comm: insmod Tainted: G O 4.9.0-dirty #1
Hardware name: Generic AM33XX (Flattened Device Tree)
task: de616240 task.stack: de676000
PC is at __memzero+0x40/0x7c
LR is at 0x0
pc : [<c04c2be0>] lr : [<00000000>] psr: 00000013
sp : de677da4 ip : 00000000 fp : de677dbc
r10: bf000240 r9 : 219a3868 r8 : 00000000
r7 : de65c7c0 r6 : de6420c0 r5 : bf0000b4 r4 : 00000000
r3 : 00000000 r2 : 00000000 r1 : fffffffc r0 : 00000000
Flags: nzcv IRQs on FIQs on Mode SVC_32 ISA ARM Segment none
Control: 10c5387d Table: 9e69c019 DAC: 00000051
CPU: 0 PID: 106 Comm: insmod Tainted: G O 4.9.0-dirty #1
Hardware name: Generic AM33XX (Flattened Device Tree)
Backtrace:
... pruned function calls related to kdb itself ...
[<c08326cc>] (do_page_fault) from [<c010138c>] (do_DataAbort+0x3c/0xbc)
r10:bf000240 r9:de676000 r8:de677d50 r7:00000000 r6:c08326cc r5:00000817
r4:c0d0bb2c
[<c0101350>] (do_DataAbort) from [<c0831d04>] (__dabt_svc+0x64/0xa0)
Exception stack(0xde677d50 to 0xde677d98)
7d40: 00000000 fffffffc 00000000 00000000
7d60: 00000000 bf0000b4 de6420c0 de65c7c0 00000000 219a3868 bf000240 de677dbc
7d80: 00000000 de677da4 00000000 c04c2be0 00000013 ffffffff
r8:00000000 r7:de677d84 r6:ffffffff r5:00000013 r4:c04c2be0
[<c02bf44c>] (cdev_init) from [<bf002048>] (init_module+0x48/0xb4 [drvbroken])
r5:bf002000 r4:bf000480
[<bf002000>] (init_module [drvbroken]) from [<c01018d4>] (do_one_initcall+0x44/0x180)
r5:bf002000 r4:ffffe000
[<c0101890>] (do_one_initcall) from [<c024fa2c>] (do_init_module+0x64/0x1d8)
r8:00000001 r7:de65c7c0 r6:de6420c0 r5:c0dbfa84 r4:bf000240
[<c024f9c8>] (do_init_module) from [<c01e10e8>] (load_module+0x1d6c/0x23d8)
r6:c0d0512c r5:c0dbfa84 r4:c0d4c70f
[<c01df37c>] (load_module) from [<c01e18ac>] (SyS_init_module+0x158/0x17c)
r10:00000051 r9:de676000 r8:e0a95100 r7:00000000 r6:000ac118 r5:00004100
使用这些信息很容易找出在哪里查找错误,但遗憾的是,无法直接从 kdb 获取行号或列出源代码。假设我可以获得完整的回溯,这在 gdb 中要容易得多。