用 gdb 和 qemu 调试 grub

因为qemu内置了gdbserver,所以我们可以用gdb调试qemu虚拟机上执行的代码,而且不受客户机系统限制。

以下内容是我调试 grub 0.97 时的一份笔记。

准备

qemu, gdb,以及一份带grub的虚拟机镜像,一份grub源码。

调试过程

启动虚拟机

$ sudo qemu-system-x86_64 -s -S -m 256 -hda test.img

然后使用gdb连接

$ gdb
(gdb) target remote localhost:1234
(gdb) set architecture i8086
(gdb) break *0x7c00
(gdb) cont

一开始CPU是工作在实模式下,为了gdb显示正常我们把架构设置为i8086

BIOS会把MBR加载到内存0x7c00处,我们在这里下断点,然后执行

查看一下当前的反汇编代码

(gdb) x/4i $pc
=>  0x7c00:        jmp        0x7c4a
    0x7c02:        nop
    0x7c03:        add        %al,(%bx,%si)
    0x7c05:        add        %al,(%bx,%si)

显示的是 att 风格的汇编代码,如果不习惯可以切换成 intel 风格的。

(gdb) set disassembly-flavor intel
(gdb) x/4i $pc
=>  0x7c00:        jmp        0x7c4a
    0x7c02:        nop
    0x7c03:        add        BYTE PTR [bx+si],al
    0x7c05:        add        BYTE PTR [bx+si],al

上来就是一个无条件跳转,我们先执行一步,再查看下代码。

(gdb) ni
(gdb) x/8i $pc
=>  0x7c4a:        cli
    0x7c4b:        nop
    0x7c4c:        nop
    0x7c4d:        test       dl,0x80
    0x7c50:        jne        0x7c54
    0x7c52:        mov        dl,0x80
    0x7c54:        jmp        0x0:0x7c59
    0x7c59:        xor        ax,ax

在gdb里查看汇编代码不够方便,我们试着把MBR提取出来,再用IDA打开。

$ sudo dd if=/dev/sda of=mbr.hex bs=512 count=1

对照一下grub的源码,大致能推断出这个就是stage1的代码。

其他几个常用的gdb命令

单步步入
(gdb) si
查看断点
(gdb) info breakpoints
删除断点
(gdb) delete

grub 启动过程总结

阶段:stage1
数据来源:MBR
内存地址:0x7c00
源码:/stage1/stage1.S
这段代码的作用就是加载MBR之后的1个扇区到0x2000处。

阶段:stage1.5
数据来源:MBR之后的几个扇区
内存地址:0x2000
源码:/stage2/start.S
这段代码的作用是把stage1.5剩余的扇区加载到0x2200,因为stage1只加载了stage1.5的第一个扇区。
源码:/stage2/asm.S
这段代码的作用是初始化部分环境,最后调用 init_bios_info
源码:/stage2/common.c
这段代码的作用是初始化c语音环境,最后调用 cmain
源码:/stage2/stage1_5.c
这段代码的作用是加载stage2到0x8000处,然后跳转到0x8200执行。

阶段:stage2
数据来源:/boot/grub/stage2
内存地址:0x8000
源码:/stage2/stage2.c等
后面就是grub的主要功能,显示菜单,启动客户系统等。
客户机的Linux内核是加载到0x100000内存地址。

猜你喜欢

转载自www.cnblogs.com/LikeVirgo/p/9195326.html