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

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

准备

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

调试过程

启动虚拟机

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

然后使用gdb连接

$ gdb
(gdb) target remote localhost:
(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= count=

对照一下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内存地址。

用 gdb 和 qemu 调试 grub的更多相关文章

  1. 使用QEMU调试Linux内核代码

    http://blog.chinaunix.net/uid-20729583-id-1884617.html http://www.linuxidc.com/Linux/2014-08/105510. ...

  2. GDB中汇编调试

    GDB中汇编调试 1.输入代码 2.使用gcc - g example.c -o example -m32指令在64位的机器上产生32位汇编,时遇到问题使用-m32指令报错,参考卢肖明同学博客知道这是 ...

  3. 使用Qemu调试内核

    利用Qemu进行内核源码级调试 http://blog.csdn.net/gdt_a20/article/details/7231652 用Qemu调试Linux内核 http://blog.chin ...

  4. GDB + gdbserver 远程调试android native code

    原文地址:GDB + gdbserver 远程调试android native code 作者:tq08g2z 以调试模拟器中的native library code为例. Host: ubuntuT ...

  5. 利用GDB进行多线程调试

    一.多线程调试 多线程调试重要就是下面几个命令: info thread 查看当前进程的线程. thread <ID> 切换调试的线程为指定ID的线程. break file.c:100 ...

  6. 3、利用GDB进行程序调试

    本文将用一个实际例子讲解如何通过GDB进行程序调试. 首先,我们需要理解的是GDB是GNU开源组织发布的一个强大的UNIX下的程序调试工具,其产生和调试的目的是让调试者知道,程序在执行时内部发生了什么 ...

  7. Lua中如何实现类似gdb的断点调试--01最小实现

    说到Lua代码调试,最常用的方法应该就是加一堆print进行打印.print大法虽好,但其缺点也是显而易见的.比如效率低下,需要修改原有函数内部代码,在每个需要的地方添加print语句,运行一次只能获 ...

  8. ucore lab1练习2 qemu+gdb 不能协作调试的问题make lab1-mon

    本练习是qemu结合gdb调试,但是我做实验的时候并不能像视频输入make lab1-mon那样顺利调试,期间有各种error,后来我找到原因,请看解决方法. 请先把ucore_lab文件删除,以下全 ...

  9. 手把手教你使用eclipse+qemu+gdb来单步调试ARM内核【学习笔记】

    平台信息:linux4.0 平台:qemu 作者:庄泽彬 说明:笨叔叔的Linux视频的笔记 一.编译linux源码 export CROSS_COMPILE=arm-linux-gnueabi- e ...

随机推荐

  1. 使用CocoaPods卡在了"pod setup"界面的解决办法

      http://blog.csdn.net/samoy/article/details/51956799   有时候,我们在执行pod install或pod search命令时,会在终端偶现卡在’ ...

  2. 关于java是值传递还是引用传递

    一.概念 实际上对这两种传递方式,知乎上有个回答说得很好: 值传递和引用传递,属于函数调用时参数的求值策略(Evaluation Strategy),这是对调用函数时,求值和传值的方式的描述,而非传递 ...

  3. CloudStack 安装时需要的第三方包

    1.mysql-connector-java 2.jakarta-commons-daemon-jsvc 3.jsvc   rpm -ivh cloudstack-common-4.1.1-0.el6 ...

  4. [C++] Const Summary (mind map)

    Const Summary

  5. js改变触发

    onchange="doEmpty($(this))"

  6. python3--多目录之间的协作的一些必备知识

    # Auther: Aaron Fan # 动态获取执行文件的相对路径路径:print(__file__) #动态获取执行文件的绝对路径:import osfile_path = os.path.ab ...

  7. AlwaysOn的数据同步原理

    摘抄自<SQL Server 2012实施与管理实战指南> 镜像的工作原理: 那么主体数据库和镜像数据库是如何同步数据的呢?SQL数据库中任何的数据变化都会先记录到事务日志中,然后才会真正 ...

  8. mysql - 简单的触发器和存储过程

    delimiter // drop PROCEDURE proc_member_preprocessor;// )) main:BEGIN SELECT COUNT(uid) INTO @proc_h ...

  9. centOS下JDK1.8的安装

    1.下载JDK1.8 http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html 有两种格式 ...

  10. kalilinux基础

    service postgresql start service metasploit start msfconsole-db_status 配置metasploit随系统启动: update-rc. ...