Bochs源码分析-调试功能2

因为学习需要,要看虚拟机Bochs的源代码。写随笔主要为了学习总结,其次是分享大家共同研究,大神勿喷,欢迎评论。

手头资料:bochs源代码,下于:bochs.sourceforge.net,还有喻强写的源码分析电纸书。

Bochs模拟器具有丰富的调试功能,今天总结Bochs的调试命令,以及相应的代码实现。

首先说明因为Bochs模拟的是X86系统,而Inter的CPU本身就支持丰富的调试功能,其中有调试寄存器(DB0-DB7)主要用来设置断点,并在运行过程中监视断点,和model-specific registers(MSRs)主要用来监视分支、终端、异常并记录当时地址。(具体内容可见Intel Architecture Software Developer’s Manual Volume 3)。

再讲Bochs的命令可以分为几类。

1:显示命令。如:info CPU,info eflags,reg,print stack:查看堆栈,x /nuf addr,查看线性地址内容等等,这些命令比较简单,因为此时模拟机进入停止状态,终端处理控制界面,程序流位于debug_main.cpp的bx_dbg_user_input_loop()函数中,该函数可以直接访问CPU、内存内容,所以直接按命令输出就行,比如:输出此时的EAX:

reg = BX_CPU(dbg_cpu)->get_reg32(BX_64BIT_REG_RAX);
dbg_printf("rax: 0x%08x:%08x ", GET32H(reg), GET32L(reg));

2:CTR+C,在模拟机运行中,你可以随时按CTR+C使其停止,进入控制状态,代码实现是:debug_main.cpp455行signal(SIGINT, bx_debug_ctrlc_handler);注册一个键盘终端函数,在处理函数中: bx_guard.interrupt_requested = 1;修改该值。而在cpu_loop()函数每次指令循环都会进行检查该值,具体:cpu.cpp971行:

 if (bx_guard.interrupt_requested &&
     (bx_guard.guard_for & BX_DBG_GUARD_CTRL_C))
  {
    BX_CPU_THIS_PTR guard_found.guard_found = BX_DBG_GUARD_CTRL_C;
    return(1); // Ctrl-C pressed
  } 从而从cpu_loop()调回控制界面,当然再跳回时会使用:SIM->set_display_mode(DISP_MODE_CONFIG);进行终端模式的转换。

3:trace on/off命令,反编译每条指令,代码实现:debug_main.cpp505行:

void bx_dbg_trace_command(bx_bool enable)
{
  BX_CPU(dbg_cpu)->trace = enable;
  dbg_printf("Tracing %s for %s\n", enable ? "enabled" : "disabled",
     BX_CPU(dbg_cpu)->name);
}该函数,令变量trace=1,该变量定义于cpu.h1140行: Bit8u trace;是CPU的内部变量,在cpu_loop()每次循环会检测改变量,具体代码,cpu.cpp269行:

#if BX_DISASM
    if (BX_CPU_THIS_PTR trace) {
      // print the instruction that is about to be executed
#if BX_DEBUGGER
      bx_dbg_disassemble_current(BX_CPU_ID, 1); // only one cpu, print time stamp
#else
      debug_disasm_instruction(BX_CPU_THIS_PTR prev_eip);
#endif
    }从而实现功能。

4:show命令:

  show -          shows current show mode
  show mode     - show, when processor switch mode
  show int      - show, when interrupt is happens
  show call     - show, when call is happens
  show ret      - show, when iret is happens
  show off      - toggles off symbolic info
  show dbg-all  - turn on all show flags
  show dbg-none - turn off all show flags

该命令要求,模拟机在运行命令的过程中不断检测,可能发生的事件,如:show call,一旦遇见call命令,就要输出call+当时的地址来进行提示,应为该命令和具体的指令有关,所以该命令的实现要在call指令的实现代码中。具体实现过程:debug_main.cpp826行

void bx_dbg_show_command(const char* arg)
{

。。。。。

else if(!strcmp(arg,"call")) {
      if (dbg_show_mask & BX_DBG_SHOW_CALLRET) {
        dbg_show_mask &= ~BX_DBG_SHOW_CALLRET;
        dbg_printf("show calls/returns: OFF\n");
      }

。。。}其中函数主要改变变量dbg_show_mask的值。

而在本文件另一个函数中:会用到show_flag这个变量,该变量定义于cpu.h1127行

#if BX_DEBUGGER
  Bit32u watchpoint;
  Bit8u break_point;
#if BX_MAGIC_BREAKPOINT
  Bit8u magic_break;
#endif
  Bit8u stop_reason;
  Bit8u trace_reg;
  Bit8u mode_break;
  bx_bool dbg_cpu_mode;  /* contains current mode */
  unsigned show_flag;
  bx_guard_found_t guard_found;
#endif
  Bit8u trace;

在call指令的执行代码中cpu\ctrl_xfer32.cpp(60): 

#if BX_DEBUGGER
  BX_CPU_THIS_PTR show_flag |= Flag_ret;
#endif

进行标记。

在cpu_loop()循环时cpu.cpp857行:

 if(dbg_show_mask) {
    int rv = bx_dbg_show_symbolic();
    if (rv) return(rv);
  }

对其进行检测,并返回debug_main.cpp文件里面的int bx_dbg_show_symbolic(void)函数,该函数里面会对call指令实现代码改变的show_flag变量进行检测:

int bx_dbg_show_symbolic(void){

。。。。。

if (dbg_show_mask & BX_DBG_SHOW_IRET) {    

if(BX_CPU(dbg_cpu)->show_flag & Flag_iret) {

。。。}

从而知道发生了call指令,并输出。

总结1:可见该实现方案需要cpu_loop的每次循环都要返回该函数,处理完再继续循环,打打降低了运行效率,这也是Bochs虚拟机运行效率低的很大原因。

总结2:在这些命令里面,有一些较简单,是控制状态下的模拟机内容显示命令,还有一些命令作用于CPU的每次指令循环,如:trace-on,这要在cpu_loop()每次要加上相关的处理代码,最复杂的是和指令相关的检测命令,这需要相应指令实现代码的配合,和CPU每次循环相应的检测,一旦检测到便返回debug_main()中去。

posted @ 2013-11-07 22:14  安心编码  阅读(684)  评论(0编辑  收藏  举报