gdb 调试 qemu virt 板 arm64 linux Image boot 过程

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 的符号,一个都对不上
	

你可能感兴趣的:(杂七杂八总览,linux,运维,服务器)