make ARCH=arm64 CROSS_COMPILE=${CROSS_COMPILE} defconfig
make ARCH=arm64 CROSS_COMPILE=${CROSS_COMPILE} Image
qemu-system-aarch64 -M virt -cpu cortex-a53 -m 512M -kernel arch/arm64/boot/Image -nographic -S -s
---
gdb-multiarch -x gdb_init -tui
set logging file log_gdb.txt
set logging on
set architecture aarch64
target remote localhost:1234
include/linux/init.h:95:#define __HEAD .section ".head.text","ax"
include/linux/init.h:96:#define __INIT .section ".init.text","ax"
$ aarch64-linux-gnu-readelf -S vmlinux
There are 39 section headers, starting at offset 0x84d6060:
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 ffff800008000000 00010000
0000000000010000 0000000000000000 AX 0 0 65536
[ 2] .text PROGBITS ffff800008010000 00020000
0000000000f1a008 0000000000000008 AX 0 0 65536
[ 3] .got.plt PROGBITS ffff800008f2a008 00f3a008
0000000000000018 0000000000000008 WA 0 0 8
[ 4] .rodata PROGBITS ffff800008f30000 00f40000
00000000007f24d8 0000000000000000 WA 0 0 4096
(gdb) x/16xw 0x40200000
0x40200000 <_text>: 0xfa405a4d 0x145e7fff 0x00000000 0x00000000
0x40200010 <_text+16>: 0x021b0000 0x00000000 0x0000000a 0x00000000
0x40200020 <_text+32>: 0x00000000 0x00000000 0x00000000 0x00000000
0x40200030 <_text+48>: 0x00000000 0x00000000 0x644d5241 0x00000040
$ xxd arch/arm64/boot/Image | head -5
00000000: 4d5a 40fa ff7f 5e14 0000 0000 0000 0000 MZ@...^.........
00000010: 0000 1b02 0000 0000 0a00 0000 0000 0000 ................
00000020: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000030: 0000 0000 0000 0000 4152 4d64 4000 0000 ........ARMd@...
00000040: 5045 0000 64aa 0200 0000 0000 0000 0000 PE..d...........
head.o: file format elf64-littleaarch64
$ cat arch/arm64/kernel/head.asm
Disassembly of section .head.text:
0000000000000000 <.head.text>:
0: fa405a4d ccmp x18, #0x0, #0xd, pl // pl = nfrst
4: 14000000 b 0 <.head.text>
...
38: 644d5241 fcmla z1.h, p4/m, z18.h, z13.h, #180
3c: 00000040 .inst 0x00000040 ; undefined
40: 00004550 .inst 0x00004550 ; undefined
44: 0002aa64 .inst 0x0002aa64 ; undefined
...
54: 020600a0 .inst 0x020600a0 ; undefined
58: 1402020b b 80884 <__primary_switch+0x8046c>
System.map
12 ffff800008000000 t __efistub__text
13 ffff800008000000 T _text
arch/arm64/kernel/vmlinux.lds
. = ((((-(((1)) << ((((48))) - 1)))) + (0x08000000)));
.head.text : {
_text = .;
KEEP(*(.head.text))
}
ffff800008000000 -> 0x0000000040200000
ffff800008010000 -> 0x0000000040210000
ffff800008f30000 -> 0x0000000041130000
add-symbol-file vmlinux -s .text 0x0000000040210000 -s .head.text 0x0000000040200000 -s .rodata 0x0000000041130000
arm64-linux boot 过程,如果要用gdb调试,需要换多少次符号信息?
- 没有配置 CONFIG_RANDOMIZE_BASE
1. Image 过程中
1. gdb attach 上去 , 需要加载一次 symbol
// 加载命令 : add-symbol-file vmlinux -s .text 0x0000000040210000 -s .head.text 0x0000000040200000 -s .rodata 0x0000000041130000
// 更新时间 : target remote localhost:1234 之后
// 更新后第一个符号 : arch/arm64/kernel/head.S 中的 __HEAD
2. 由于开mmu后,从恒等映射页表切换到同一pgd的kernel页表 , 需要更新一次
// 更新命令 : symbol 和 add-symbol-file vmlinux
// 更新时间 : arch/arm64/kernel/head.S ldr x8, =__primary_switched adrp x0, __PHYS_OFFSET blr x8
// 更新后第一个符号 : arch/arm64/kernel/head.S 中的 __primary_switched
// 其他 : 所以如果你直接加载 vmlinux 的符号,第一个可以停止的符号是 __primary_switched
// 其他 : 因为是恒等映射, __enable_mmu 的 "set_sctlr_el1 x0" 执行后不用马上切换符号
// start_kernel 及其之后也是用这个符号来调试
// 如果没有配置 CONFIG_RANDOMIZE_BASE , 则 用 add-symbol-file vmlinux 即可
// 其他 : 所以如果你在 CONFIG_RANDOMIZE_BASE 的情况下 ,直接加载 vmlinux 的符号,一个都对不上
- 配置了CONFIG_RANDOMIZE_BASE
注意 : 该过程 第三步 做了 CONFIG_RANDOMIZE_BASE 的 大部分工作
1. Image 过程中
1. gdb attach 上去 , 需要加载一次 symbol
// 加载命令 : add-symbol-file vmlinux -s .text 0x0000000040210000 -s .head.text 0x0000000040200000 -s .rodata 0x0000000041130000
// 更新时间 : target remote localhost:1234 之后
// 更新后第一个符号 : arch/arm64/kernel/head.S 中的 __HEAD
2. 由于开mmu后,从恒等映射页表切换到同一pgd的kernel页表 , 需要更新一次
// 更新命令 : symbol 和 add-symbol-file vmlinux
// 更新时间 : arch/arm64/kernel/head.S ldr x8, =__primary_switched adrp x0, __PHYS_OFFSET blr x8
// 更新后第一个符号 : arch/arm64/kernel/head.S 中的 __primary_switched
// 其他 : 所以如果你直接加载 vmlinux 的符号,第一个可以停止的符号是 __primary_switched
// 其他 : 因为是恒等映射, __enable_mmu 的 "set_sctlr_el1 x0" 执行后不用马上切换符号
3. return to __primary_switch()
// 更新命令 : symbol 和 add-symbol-file vmlinux -s .text 0x0000000040210000 -s .head.text 0x0000000040200000 -s .rodata 0x0000000041130000
// 更新时间 : ldp x29, x30, [sp], #16 ret
// 更新后第一个符号 : arch/arm64/kernel/head.S 中的 __primary_switch 中的 "43c: d5033fdf isb"
// 更新后第一个符号 : 即 __primary_switch 中的 pre_disable_mmu_workaround
// __primary_switch 在 0000000000000418
// ffff800008f24418 + (43c-418) -> 0x000000004112443c
//
// 减了 0xFFFF7FFFC7E00000
ffff800008000000 -> 0x0000000040200000
ffff800008010000 -> 0x0000000040210000
ffff800008f30000 -> 0x0000000041130000
add-symbol-file vmlinux -s .text 0x0000000040210000 -s .head.text 0x0000000040200000 -s .rodata 0x0000000041130000
4. 跳转到 __primary_switched
// 更新命令 : symbol 和 add-symbol-file vmlinux -o OFFSET4
// 更新时间 : arch/arm64/kernel/head.S __primary_switch 中的 ldr x8, =__primary_switched adrp x0, __PHYS_OFFSET br x8
// 更新后第一个符号 : arch/arm64/kernel/head.S 中的 __primary_switched
// ffff8000097a032c -> 0xffffb94e7bfa032c(0xffffa15e779a032c) // 目的地址不固定,随机值(是因为CONFIG_RANDOMIZE_BASE , KASLR技术)
// 对于 0xffffb94e7bfa032c 加 0x394E72800000
ffff800008000000 -> 0XFFFFB94E7A800000
ffff800008010000 -> 0XFFFFB94E7A810000
ffff800008f30000 -> 0XFFFFB94E7B730000
// 对于 0xffffa15e779a032c 加 0x215E6E200000
// OFFSET4 = 目的地址 - (addr of __primary_switched)
// start_kernel 及其之后也是用这个符号来调试
// 其他 : 所以如果你在 CONFIG_RANDOMIZE_BASE 的情况下 ,直接加载 vmlinux 的符号,一个都对不上