我正在 qemu 虚拟机上使用 u-boot (使用 SPL falcon 模式,其中 u-boot-spl 直接启动 Linux)跟踪 linux 引导加载。现在代码跳转到linux内核,因为我已经完成了
add-symbol-file vmlinux 0x80081000
我可以使用连接到虚拟机的gdb一步步跟踪内核代码。实际上我将内核映像加载到了 0x80080000,但我必须将地址设置为 0x80081000,以使源代码根据 PC 值正确出现在 gdb 上(我不知道为什么需要这个 0x1000 的差异)。__primary_switched
,这是PC第一次使用纯内核虚拟地址的地方。这是在 head.S 文件末尾进行调用的地方。
ldr x8, =__primary_switched
adrp x0, __PHYS_OFFSET
br x8
在符号文件(vmlinux,一个elf文件)中,__primary_switched之前的符号都映射到虚拟地址(从0xffffffc0.....高地址开始),但即使PC值使用物理值,gdb也可以跟踪源地址。 (PC 最初加载了内核启动的物理地址,并且使用了 PC 相对跳转,直到跳转到
__primary_switched
,mmu 禁用或使用身份映射)这是否意味着,在执行 add-symbol-file
时仅使用文本开头的符号很重要吗?添加(世界标准时间 2022 年 1 月 12 日星期三上午 8:32)
我从gdb手册中找到了,
“添加符号文件文件名 [ -readnow | -readnever ] [ -o offset ] [ textaddress ] [ -s 节地址 ... ] add-symbol-file 命令 从文件 filename 中读取附加符号表信息。你 当文件名已动态加载时(通过 其他方式)进入正在运行的程序。文本地址 参数给出文件文本部分所在的内存地址 已加载。您还可以指定基地址 其他节使用任意数量的“-s节地址” 对。如果省略某个部分,gdb 将使用其默认地址作为 在文件名中找到。任何地址或文本地址都可以作为 表达。 ...”
我稍微改变了我的程序来解决一个问题。 readelf 显示从 ffffffc010080800 开始的 .text 部分。 所以我将命令调整为“add-symbol-file vmlinux 0x80000800”,并且gdb在跳转到linux后显示了正确的内核源代码。 它仍然没有向我显示 __primary_switched 之后的源代码。
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[ 1] .head.text PROGBITS ffffffc010080000 00010000
0000000000000040 0000000000000000 AX 0 0 4
[ 2] .text PROGBITS ffffffc010080800 00010800
0000000000304370 0000000000000000 AX 0 0 2048
[ 3] .rodata PROGBITS ffffffc010390000 00320000
.... (skip) ...
[12] .notes NOTE ffffffc01045be18 003ebe18
000000000000003c 0000000000000000 A 0 0 4
[13] .init.text PROGBITS ffffffc010470000 003f0000
0000000000027ec8 0000000000000000 AX 0 0 4
[14] .exit.text PROGBITS ffffffc010497ec8 00417ec8
000000000000046c 0000000000000000 AX 0 0 4
由于“__primary_switched”位于.init.text部分,我尝试添加“-s .init.text 0xffffffc010470000”或“-s .init_text 0x803ef800”(物理 地址)到 add-symbol-file 命令无济于事。难道是我的命令错了?或者这可能是来自页表(虚拟 -> 物理)问题,因为我在输入 __primary_switched 后立即看到同步异常(我看到 PC 值已变为 0x200。如果异常向量位于 0x0,则这是同步异常的向量条目就像未定义的指令一样。我还应该检查向量基地址是否设置正确。)
我发现我的内核加载地址错误(__PHYS_OFFSET 低于物理 ddr 地址开始)。
修复后,PC 会随着内核虚拟地址正常递增,我应该使用虚拟地址应用 add-symbol-file 命令。
这是新的部分地址。
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[ 1] .head.text PROGBITS ffffffc010080000 00010000
0000000000000040 0000000000000000 AX 0 0 4
[ 2] .text PROGBITS ffffffc010080800 00010800
0000000000304370 0000000000000000 AX 0 0 2048
[ 3] .rodata PROGBITS ffffffc010390000 00320000
00000000000a6385 0000000000000000 WA 0 0 4096
[ 4] .modinfo PROGBITS ffffffc010436385 003c6385
00000000000018ff 0000000000000000 A 0 0 1
[ 5] .pci_fixup PROGBITS ffffffc010437c90 003c7c90
00000000000020f0 0000000000000000 A 0 0 16
[ 6] __ksymtab PROGBITS ffffffc010439d80 003c9d80
0000000000006d20 0000000000000000 A 0 0 4
[ 7] __ksymtab_gpl PROGBITS ffffffc010440aa0 003d0aa0
0000000000005808 0000000000000000 A 0 0 4
[ 8] __ksymtab_strings PROGBITS ffffffc0104462a8 003d62a8
00000000000134f2 0000000000000000 A 0 0 1
[ 9] __param PROGBITS ffffffc0104597a0 003e97a0
0000000000000b68 0000000000000000 A 0 0 8
[10] __modver PROGBITS ffffffc01045a308 003ea308
0000000000000cf8 0000000000000000 A 0 0 8
[11] __ex_table PROGBITS ffffffc01045b000 003eb000
0000000000000e18 0000000000000000 A 0 0 8
[12] .notes NOTE ffffffc01045be18 003ebe18
000000000000003c 0000000000000000 A 0 0 4
[13] .init.text PROGBITS ffffffc010470000 003f0000
0000000000027ec8 0000000000000000 AX 0 0 4
[14] .exit.text PROGBITS ffffffc010497ec8 00417ec8
最终内核映像加载于0x80080000。然后 __PHYS_OFFSET 变为 0x80000000。 (TEXT_OFFSET 默认为 0x80000)。现在我可以使用此命令在 __primary_switch 之前调试内核源代码。
add-symbol-file images/vmlinux 0x80080800 -s .head.text 0x80080000 -s .init.text 0x803f7800
在内核进入 __primary_switched (现在使用内核虚拟地址)后,我添加了此命令来查看源代码,我可以使用 qemu 和 gdb 逐步跟踪代码。
add-symbol-file images/vmlinux 0xffffffc010080800 -s .head.text 0xffffffc010080000 -s .init.text 0xffffffc010470000 Hope this helps someone later.
但是几天后,我想我可以使用
add-symbol-file images/vmlinux 0xffffffc010080800
(应用所有部分信息)。
-o
的add-symbol-file
选项可以是负数,所以我们可以使用-o
设置相对于.head.text
节的全局偏移量,那么后面的所有节也会被偏移,不需要单独设置节地址。
举个例子: 内核入口的虚拟地址或
.head.text
是0xffffffc010080800
,加载的内核物理地址是0x80080000
,则0xffffffc010080800
- 0x80080000
= 0xFFFFFFBF90000800
,然后可以使用add-symbol-file vmlinux -o -0xFFFFFFBF90000800
来调整偏移量。