我应该如何在 u-boot linux 引导调试期间应用 add-symbol-file 命令?
How should I apply add-symbol-file command during u-boot linux boot debug?
我正在 qemu 虚拟机上使用 u-boot(使用 SPL falcon 模式,其中 u-boot-spl 直接启动 linux)进行引导加载。现在代码跳转到 linux 内核,因为我已经完成了 add-symbol-file vmlinux 0x80081000
我可以使用连接到虚拟机的 gdb 一步步跟随内核代码。实际上我加载了内核映像到0x80080000但是我不得不将地址设置为0x80081000以使源代码根据PC值正确地出现在gdb上(我不知道为什么需要这个0x1000的差异)。
后来我发现内核设置页面table(身份映射和交换table)并跳转到__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
符号与文本开头的偏移量很重要吗?
另一个问题:我可以使用 gdb 跟踪内核源代码,但在 __primary_switched 之后,我看不到源代码。根据现在的内核虚拟 PC 值,调试器没有显示正确的源位置。我是否应该再次使用 add-symbol-file 告诉调试器使用正确的偏移量?如果是怎么办?
添加(UTC,2022 年 1 月 12 日星期三上午 8:32)
我从 gdb 手册中找到,
"add-symbol-file filename [ -readnow | -readnever ] [ -o offset ] [
textaddress ] [ -s section address ... ] The add-symbol-file command
reads additional symbol table information from the file filename. You
would use this command when filename has been dynamically loaded (by
some other means) into the program that is running. The textaddress
parameter gives the memory address at which the file's text section
has been loaded. You can additionally specify the base address of
other sections using an arbitrary number of '-s section address'
pairs. If a section is omitted, gdb will use its default addresses as
found in filename. Any address or textaddress can be given as an
expression. ..."
我稍微更改了我的程序以解决问题。 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”(物理的
地址)到添加符号文件命令无济于事。我的命令错了吗?或者这可能是来自页面 table(虚拟 -> 物理)的问题,因为我在输入 __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
(应用所有部分信息)。
我正在 qemu 虚拟机上使用 u-boot(使用 SPL falcon 模式,其中 u-boot-spl 直接启动 linux)进行引导加载。现在代码跳转到 linux 内核,因为我已经完成了 add-symbol-file vmlinux 0x80081000
我可以使用连接到虚拟机的 gdb 一步步跟随内核代码。实际上我加载了内核映像到0x80080000但是我不得不将地址设置为0x80081000以使源代码根据PC值正确地出现在gdb上(我不知道为什么需要这个0x1000的差异)。
后来我发现内核设置页面table(身份映射和交换table)并跳转到__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
符号与文本开头的偏移量很重要吗?
另一个问题:我可以使用 gdb 跟踪内核源代码,但在 __primary_switched 之后,我看不到源代码。根据现在的内核虚拟 PC 值,调试器没有显示正确的源位置。我是否应该再次使用 add-symbol-file 告诉调试器使用正确的偏移量?如果是怎么办?
添加(UTC,2022 年 1 月 12 日星期三上午 8:32)
我从 gdb 手册中找到,
"add-symbol-file filename [ -readnow | -readnever ] [ -o offset ] [ textaddress ] [ -s section address ... ] The add-symbol-file command reads additional symbol table information from the file filename. You would use this command when filename has been dynamically loaded (by some other means) into the program that is running. The textaddress parameter gives the memory address at which the file's text section has been loaded. You can additionally specify the base address of other sections using an arbitrary number of '-s section address' pairs. If a section is omitted, gdb will use its default addresses as found in filename. Any address or textaddress can be given as an expression. ..."
我稍微更改了我的程序以解决问题。 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”(物理的 地址)到添加符号文件命令无济于事。我的命令错了吗?或者这可能是来自页面 table(虚拟 -> 物理)的问题,因为我在输入 __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
(应用所有部分信息)。