很多文章写调试qemu都是从start_kernel开始的,那么start_kernel之前的函数如何调试呢。尤其是 startup_64
即使打上了断点也无法跟踪。
原因是 startup_64 在 vmlinux 里面对应的是链接地址。
7262499 ffffffff81000000 <_text>:
7262500 ffffffff81000000: 48 8d 2d f9 ff ff ff lea -0x7(%rip),%rbp # ffffffff81000000 <_text>
而实际上 startup_64 执行的时候, 页表还没有建立, 使用的虚拟地址跟物理地址是1:1对应的, 也就是其执行的时候, 虚拟地址和物理地址是相等的。
那么怎么找到其开始运行的时候的物理地址呢?
rlk@ubuntu:runninglinuxkernel_4.0_x86$ cat .config | grep CONFIG_RELOCATABLE
CONFIG_RELOCATABLE=y
rlk@ubuntu:runninglinuxkernel_4.0_x86$ cat .config | grep CONFIG_PHYSICAL_START
CONFIG_PHYSICAL_START=0x1000000
rlk@ubuntu:runninglinuxkernel_4.0_x86$
rlk@ubuntu:kernel$ vi vmlinux.lds
SECTIONS
{
. = (0xffffffff80000000 + ALIGN(0x1000000, 0x200000));
phys_startup_64 = startup_64 - 0xffffffff80000000;
}
调试代码对应的汇编语言如下
7262497 Disassembly of section .text:
7262498
7262499 ffffffff81000000 <_text>:
7262500 ffffffff81000000: 48 8d 2d f9 ff ff ff lea -0x7(%rip),%rbp # ffffffff81000000 <_text>
7262501 ffffffff81000007: 48 81 ed 00 00 00 01 sub $0x1000000,%rbp
7262502 ffffffff8100000e: 48 89 e8 mov %rbp,%rax
7262503 ffffffff81000011: 25 ff ff 1f 00 and $0x1fffff,%eax
7262504 ffffffff81000016: 85 c0 test %eax,%eax
7262505 ffffffff81000018: 0f 85 a7 01 00 00 jne ffffffff810001c5 <bad_address>
7262506 ffffffff8100001e: 48 8d 05 db ff ff ff lea -0x25(%rip),%rax # ffffffff81000000 <_text>
7262507 ffffffff81000025: 48 c1 e8 2e shr $0x2e,%rax
7262508 ffffffff81000029: 0f 85 96 01 00 00 jne ffffffff810001c5 <bad_address>
7262509 ffffffff8100002f: 48 01 2d c2 7f f4 00 add %rbp,0xf47fc2(%rip) # ffffffff81f47ff8 <early_level4_pgt+0xff8>
7262510 ffffffff81000036: 48 01 2d b3 ff e0 00 add %rbp,0xe0ffb3(%rip) # ffffffff81e0fff0 <level3_kernel_pgt+0xff0>
7262511 ffffffff8100003d: 48 01 2d b4 ff e0 00 add %rbp,0xe0ffb4(%rip) # ffffffff81e0fff8 <level3_kernel_pgt+0xff8>
7262512 ffffffff81000044: 48 01 2d 85 1f e1 00 add %rbp,0xe11f85(%rip) # ffffffff81e11fd0 <level2_fixmap_pgt+0xfd0>
7262513 ffffffff8100004b: 48 8d 3d ae ff ff ff lea -0x52(%rip),%rdi # ffffffff81000000 <_text>
所以打断点要基于物理地址打断点:
(gdb) target remote localhost:1234
Remote debugging using localhost:1234
0x000000000000fff0 in scsi_format_log ()
(gdb) b *0x1000000 // 其中, 0x1000000 是 startup_64 运行时的虚拟地址。给地址打断点, 前面需要加上 *
Breakpoint 1 at 0x1000000
(gdb) c
Continuing.
Breakpoint 1, 0x0000000001000000 in ?? ()
(gdb) info reg // 打印寄存器
rax 0x1000000 16777216
rbx 0x1f19000 32608256
rcx 0x780 1920
rdx 0x3d5 981
rsi 0x140a0 82080
rdi 0x3d5 981
rbp 0x1000000 0x1000000
rsp 0x23fa540 0x23fa540
r8 0x4e1580 5117312
r9 0x14d9000 21860352
r10 0xd 13
r11 0xa 10
r12 0x0 0
r13 0x0 0
r14 0x0 0
r15 0x0 0
rip 0x1000000 0x1000000
eflags 0x2 [ IOPL=0 ]
cs 0x10 16
ss 0x0 0
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
fs_base 0x0 0
gs_base 0x0 0
k_gs_base 0x0 0
cr0 0x80000011 [ PG ET PE ]
cr2 0x0 0
cr3 0x23fb000 [ PDBR=1 PCID=0 ]
cr4 0x20 [ PAE ]
cr8 0x0 0
efer 0x500 [ LMA LME ]
mxcsr 0x1f80 [ IM DM ZM OM UM PM ]
(gdb) n
Cannot find bounds of current function
(gdb) s
Cannot find bounds of current function
(gdb) b *0x1000007
Breakpoint 2 at 0x1000007
(gdb) c
Continuing.
Breakpoint 2, 0x0000000001000007 in ?? ()
(gdb) info reg
rax 0x1000000 16777216
rbx 0x1f19000 32608256
rcx 0x780 1920
rdx 0x3d5 981
rsi 0x140a0 82080
rdi 0x3d5 981
rbp 0x1000000 0x1000000
rsp 0x23fa540 0x23fa540
r8 0x4e1580 5117312
r9 0x14d9000 21860352
r10 0xd 13
r11 0xa 10
r12 0x0 0
r13 0x0 0
r14 0x0 0
r15 0x0 0
rip 0x1000007 0x1000007
eflags 0x2 [ IOPL=0 ]
cs 0x10 16
ss 0x0 0
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
fs_base 0x0 0
gs_base 0x0 0
k_gs_base 0x0 0
(gdb) b *0x100001e
Breakpoint 3 at 0x100001e
(gdb) c
Continuing.
Breakpoint 3, 0x000000000100001e in ?? ()
(gdb) info reg
rax 0x0 0 // 这条语句讲rax清零 ffffffff81000011: 25 ff ff 1f 00 and $0x1fffff,%eax
rbx 0x1f19000 32608256
rcx 0x780 1920
rdx 0x3d5 981
rsi 0x140a0 82080
rdi 0x3d5 981
rbp 0x0 0x0 <irq_stack_union>
rsp 0x23fa540 0x23fa540
r8 0x4e1580 5117312
r9 0x14d9000 21860352
r10 0xd 13
r11 0xa 10
r12 0x0 0
r13 0x0 0
r14 0x0 0
r15 0x0 0
rip 0x100001e 0x100001e
eflags 0x46 [ IOPL=0 ZF PF ]
cs 0x10 16
ss 0x0 0
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
fs_base 0x0 0
gs_base 0x0 0
k_gs_base 0x0 0
cr0 0x80000011 [ PG ET PE ]
cr2 0x0 0
cr3 0x23fb000 [ PDBR=1 PCID=0 ]
cr4 0x20 [ PAE ]
cr8 0x0 0
efer 0x500 [ LMA LME ]
(gdb) b *0x1000025
Breakpoint 4 at 0x1000025
(gdb) c
Continuing.
Breakpoint 4, 0x0000000001000025 in ?? ()
(gdb) info reg
rax 0x1000000 16777216 // ffffffff8100001e: 48 8d 05 db ff ff ff lea -0x25(%rip),%rax # ffffffff81000000 <_text>
rbx 0x1f19000 32608256
rcx 0x780 1920
rdx 0x3d5 981
rsi 0x140a0 82080
rdi 0x3d5 981
rbp 0x0 0x0 <irq_stack_union>
rsp 0x23fa540 0x23fa540
r8 0x4e1580 5117312
r9 0x14d9000 21860352
r10 0xd 13
r11 0xa 10
r12 0x0 0
r13 0x0 0
r14 0x0 0
r15 0x0 0
rip 0x1000025 0x1000025
eflags 0x46 [ IOPL=0 ZF PF ]