zoukankan      html  css  js  c++  java
  • 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 ", 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 ");
          }

    。。。}其中函数主要改变变量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指令的执行代码中cpuctrl_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()中去。

  • 相关阅读:
    nodejs使用superagent写爬虫dns超时
    react部署nginx刷新路由404
    ubuntu安装mongodb添加账户以及远程连接
    laravel使用layui富文本编辑器layedit上传图片419解决办法
    编写前端统计网页流量,来源,停留时间等
    laravel模版共用数据解决方法
    解决MySQL导入中文乱码
    yii2 jui DatePicker widget 设置显示默认时间
    装饰器
    python函数计时器(通过装饰器实现)
  • 原文地址:https://www.cnblogs.com/zeng2013/p/3413352.html
Copyright © 2011-2022 走看看