PA3.1 etrace

上山砍大树發表於2024-11-13

用etrace記錄異常處理的蹤跡,就在異常響應機制下手即可。在實現異常響應之後,記錄異常狀態:

  • 異常號
  • 程式計數器
  • 暫存器值
  • 異常處理入口地址
// etrace
/* 記錄異常處理的蹤跡 */
void etrace(const char *inst, vaddr_t epc, word_t mcause, word_t gpr, word_t mtvec){
  etrace_write("etrace: %s epc = " FMT_WORD ", mcause = "FMT_WORD", gpr(a7) = " FMT_WORD", mtvec = "FMT_WORD "\n",
  inst, epc, mcause, gpr, mtvec);
}
#define ETRACE(inst) do { bool success = true; word_t a7 = isa_reg_str2val("a7",&success); assert(success);  etrace(inst, read_csrs(CSR_MEPC), read_csrs(CSR_MCAUSE), a7, read_csrs(CSR_MTVEC));} while(0)

#define ECALL(dnpc) do { dnpc = isa_raise_intr(ENVIRONMENT_CALL_FROM_U_MODE, s->pc); ETRACE("ecall");} while(0)

但是此時檢視日誌發現並沒有關於etrace的記錄。在etrace函式中,新增printf函式,發現etrace呼叫printf函式輸出正確資訊,但是並沒有執行log_write的指令。

#define log_write(...) IFDEF(CONFIG_TARGET_NATIVE_ELF, \
  do { \
    extern FILE* log_fp; \
    extern bool log_enable(); \
    if (log_enable()) { \
      fprintf(log_fp, __VA_ARGS__); \
      fflush(log_fp); \
    } \
  } while (0) \
)

最終除錯發現是log_enable()是錯誤的。繼續檢視log_enable()的原始碼:

bool log_enable() {
  return MUXDEF(CONFIG_TRACE, (g_nr_guest_inst >= CONFIG_TRACE_START) &&
         (g_nr_guest_inst <= CONFIG_TRACE_END), false);
}

那我們先不管g_nr_guest_inst具體含義直接自定義一個etrace_write()

#define etrace_write(...) IFDEF(CONFIG_TARGET_NATIVE_ELF, \
  do { \
    extern FILE* log_fp; \
    fprintf(log_fp, __VA_ARGS__); \
    fflush(log_fp); \
  } while (0) \
)

呼叫此即可實現etrace功能。輸出例子如下:

etrace: ecall epc = 0x80001408, mcause = 0x00000008, gpr(a7) = 0xffffffff, mtvec = 0x80001418
etrace: mret  epc = 0x8000140c, mcause = 0x00000008, gpr(a7) = 0xffffffff, mtvec = 0x80001418