diff options
Diffstat (limited to 'gdb/riscv-tdep.c')
-rw-r--r-- | gdb/riscv-tdep.c | 686 |
1 files changed, 681 insertions, 5 deletions
diff --git a/gdb/riscv-tdep.c b/gdb/riscv-tdep.c index 91f6dff..a735c09 100644 --- a/gdb/riscv-tdep.c +++ b/gdb/riscv-tdep.c @@ -54,9 +54,12 @@ #include "observable.h" #include "prologue-value.h" #include "arch/riscv.h" +#include "record-full.h" #include "riscv-ravenscar-thread.h" #include "gdbsupport/gdb-safe-ctype.h" +#include <vector> + /* The stack must be 16-byte aligned. */ #define SP_ALIGNMENT 16 @@ -1669,6 +1672,11 @@ public: int imm_signed () const { return m_imm.s; } + /* Fetch instruction from target memory at ADDR, return the content of + the instruction, and update LEN with the instruction length. */ + static ULONGEST fetch_instruction (struct gdbarch *gdbarch, + CORE_ADDR addr, int *len); + private: /* Extract 5 bit register field at OFFSET from instruction OPCODE. */ @@ -1814,11 +1822,6 @@ private: m_rs2 = decode_register_index_short (ival, OP_SH_CRS2S); } - /* Fetch instruction from target memory at ADDR, return the content of - the instruction, and update LEN with the instruction length. */ - static ULONGEST fetch_instruction (struct gdbarch *gdbarch, - CORE_ADDR addr, int *len); - /* The length of the instruction in bytes. Should be 2 or 4. */ int m_length; @@ -4433,6 +4436,9 @@ riscv_gdbarch_init (struct gdbarch_info info, set_gdbarch_stap_register_indirection_suffixes (gdbarch, stap_register_indirection_suffixes); + /* Process record-replay */ + set_gdbarch_process_record (gdbarch, riscv_process_record); + /* Hook in OS ABI-specific overrides, if they have been registered. */ gdbarch_init_osabi (info, gdbarch); @@ -4866,3 +4872,673 @@ equivalent change in the disassembler output."), &setriscvcmdlist, &showriscvcmdlist); } + +/* A wrapper to read register under number regnum to address addr. + Returns false if error happened and makes warning. */ + +static bool +try_read (struct regcache *regcache, int regnum, ULONGEST &addr) +{ + gdb_assert (regcache != nullptr); + + if (regcache->raw_read (regnum, &addr) + != register_status::REG_VALID) + { + warning (_("Can not read at address %lx"), addr); + return false; + } + return true; +} + +/* Helper class to record instruction. */ + +class riscv_recorded_insn final +{ +public: + /* Type for saved register. */ + using regnum_type = int; + /* Type for saved memory. First is address, second is length. */ + using memory_type = std::pair<CORE_ADDR, int>; + + /* Enum class that represents which type does recording belong to. */ + enum class record_type + { + UNKNOWN, + ORDINARY, + + /* Corner cases. */ + ECALL, + EBREAK, + }; + +private: + /* Type for set of registers that need to be saved. */ + using recorded_regs = std::vector<regnum_type>; + /* Type for set of memory records that need to be saved. */ + using recorded_mems = std::vector<memory_type>; + + /* Type for memory address, extracted from memory_type. */ + using mem_addr = decltype (std::declval<memory_type> ().first); + /* Type for memory length, extracted from memory_type. */ + using mem_len = decltype (std::declval<memory_type> ().second); + + /* Record type of current instruction. */ + record_type m_record_type = record_type::UNKNOWN; + + /* Flag that represents was there an error in current recording. */ + bool m_error_occured = false; + + /* Set of registers that need to be recorded. */ + recorded_regs m_regs; + /* Set of memory chunks that need to be recorded. */ + recorded_mems m_mems; + + /* Width in bytes of the general purpose registers for GDBARCH, + where recording is happening. */ + int m_xlen = 0; + + /* Helper for decode 16-bit instruction RS1. */ + static regnum_type + decode_crs1_short (ULONGEST opcode) noexcept + { + return ((opcode >> OP_SH_CRS1S) & OP_MASK_CRS1S) + 8; + } + + /* Helper for decode 16-bit instruction RS2. */ + static regnum_type + decode_crs2_short (ULONGEST opcode) noexcept + { + return ((opcode >> OP_SH_CRS2S) & OP_MASK_CRS2S) + 8; + } + + /* Helper for decode 16-bit instruction CRS1. */ + static regnum_type + decode_crs1 (ULONGEST opcode) noexcept + { + return ((opcode >> OP_SH_RD) & OP_MASK_RD); + } + + /* Helper for decode 16-bit instruction CRS2. */ + static regnum_type + decode_crs2 (ULONGEST opcode) noexcept + { + return ((opcode >> OP_SH_CRS2) & OP_MASK_CRS2); + } + + /* Helper for decode 32-bit instruction RD. */ + static regnum_type + decode_rd (ULONGEST ival) noexcept + { + return (ival >> OP_SH_RD) & OP_MASK_RD; + } + + /* Helper for decode 32-bit instruction RS1. */ + static regnum_type + decode_rs1 (ULONGEST ival) noexcept + { + return (ival >> OP_SH_RS1) & OP_MASK_RS1; + } + + /* Helper for decode 32-bit instruction RS2. */ + static regnum_type + decode_rs2 (ULONGEST ival) noexcept + { + return (ival >> OP_SH_RS2) & OP_MASK_RS2; + } + + /* Helper for decode 32-bit instruction CSR. */ + static regnum_type + decode_csr (ULONGEST ival) noexcept + { + return (ival >> OP_SH_CSR) & OP_MASK_CSR; + } + + /* Set ordinary record type. Always returns true. */ + bool + set_ordinary_record_type () noexcept + { + m_record_type = record_type::ORDINARY; + return true; + } + + /* Set error happened. Always returns false. */ + bool + set_error () noexcept + { + m_error_occured = true; + return false; + } + + /* Check if current recording has an error. */ + bool + has_error () const noexcept + { + return m_error_occured; + } + + /* Reads register. Sets error and returns false if error happened. */ + bool + read_reg (struct regcache *regcache, regnum_type reg, + ULONGEST &addr) noexcept + { + gdb_assert (regcache != nullptr); + + if (!try_read (regcache, reg, addr)) + return set_error (); + return true; + } + + /* Save register. Returns true or aborts if exception happened. */ + bool + save_reg (regnum_type regnum) noexcept + { + m_regs.emplace_back (regnum); + return true; + } + + /* Save memory chunk. Returns true or aborts if exception happened. */ + bool + save_mem (mem_addr addr, mem_len len) noexcept + { + m_mems.emplace_back (addr, len); + return true; + } + + /* Returns true if instruction needs only saving pc. */ + static bool + need_save_pc (ULONGEST ival) noexcept + { + return (is_beq_insn (ival) || is_bne_insn (ival) || is_blt_insn (ival) + || is_bge_insn (ival) || is_bltu_insn (ival) || is_bgeu_insn (ival) + || is_fence_insn (ival) || is_pause_insn (ival) + || is_fence_i_insn (ival)); + } + + /* Returns true if instruction is classified. */ + bool + try_save_pc (ULONGEST ival) noexcept + { + if (!need_save_pc (ival)) + return false; + + return set_ordinary_record_type (); + } + + /* Returns true if instruction needs only saving pc and rd. */ + static bool + need_save_pc_rd (ULONGEST ival) noexcept + { + return (is_lui_insn (ival) || is_auipc_insn (ival) || is_jal_insn (ival) + || is_jalr_insn (ival) || is_lb_insn (ival) || is_lh_insn (ival) + || is_lw_insn (ival) || is_lbu_insn (ival) || is_lhu_insn (ival) + || is_addi_insn (ival) || is_slti_insn (ival) + || is_sltiu_insn (ival) || is_xori_insn (ival) || is_ori_insn (ival) + || is_andi_insn (ival) || is_slli_rv32_insn (ival) + || is_srli_rv32_insn (ival) || is_srai_rv32_insn (ival) + || is_add_insn (ival) || is_sub_insn (ival) || is_sll_insn (ival) + || is_slt_insn (ival) || is_sltu_insn (ival) || is_xor_insn (ival) + || is_srl_insn (ival) || is_sra_insn (ival) || is_or_insn (ival) + || is_and_insn (ival) || is_lwu_insn (ival) || is_ld_insn (ival) + || is_slli_insn (ival) || is_srli_insn (ival) || is_srai_insn (ival) + || is_addiw_insn (ival) || is_slliw_insn (ival) + || is_srliw_insn (ival) || is_sraiw_insn (ival) + || is_addw_insn (ival) || is_subw_insn (ival) || is_sllw_insn (ival) + || is_srlw_insn (ival) || is_sraw_insn (ival) || is_mul_insn (ival) + || is_mulh_insn (ival) || is_mulhsu_insn (ival) + || is_mulhu_insn (ival) || is_div_insn (ival) || is_divu_insn (ival) + || is_rem_insn (ival) || is_remu_insn (ival) || is_mulw_insn (ival) + || is_divw_insn (ival) || is_divuw_insn (ival) + || is_remw_insn (ival) || is_remuw_insn (ival) + || is_lr_w_insn (ival) || is_lr_d_insn (ival) + || is_fcvt_w_s_insn (ival) || is_fcvt_wu_s_insn (ival) + || is_fmv_x_s_insn (ival) || is_feq_s_insn (ival) + || is_flt_s_insn (ival) || is_fle_s_insn (ival) + || is_fclass_s_insn (ival) || is_fcvt_l_s_insn (ival) + || is_fcvt_lu_s_insn (ival) || is_feq_d_insn (ival) + || is_flt_d_insn (ival) || is_fle_d_insn (ival) + || is_fclass_d_insn (ival) || is_fcvt_w_d_insn (ival) + || is_fcvt_wu_d_insn (ival) || is_fcvt_l_d_insn (ival) + || is_fcvt_lu_d_insn (ival) || is_fmv_x_d_insn (ival)); + } + + /* Returns true if instruction is classified. This function can set + m_error_occured. */ + bool + try_save_pc_rd (ULONGEST ival) noexcept + { + if (!need_save_pc_rd (ival)) + return false; + + return (!save_reg (decode_rd (ival)) || set_ordinary_record_type ()); + } + + /* Returns true if instruction needs only saving pc and + floating point rd. */ + static bool + need_save_pc_fprd (ULONGEST ival) noexcept + { + return (is_flw_insn (ival) || is_fmadd_s_insn (ival) + || is_fmsub_s_insn (ival) || is_fnmsub_s_insn (ival) + || is_fnmadd_s_insn (ival) || is_fadd_s_insn (ival) + || is_fsub_s_insn (ival) || is_fmul_s_insn (ival) + || is_fdiv_s_insn (ival) || is_fsqrt_s_insn (ival) + || is_fsgnj_s_insn (ival) || is_fsgnjn_s_insn (ival) + || is_fsgnjx_s_insn (ival) || is_fmin_s_insn (ival) + || is_fmax_s_insn (ival) || is_fcvt_s_w_insn (ival) + || is_fcvt_s_wu_insn (ival) || is_fmv_s_x_insn (ival) + || is_fcvt_s_l_insn (ival) || is_fcvt_s_lu_insn (ival) + || is_fld_insn (ival) || is_fmadd_d_insn (ival) + || is_fmsub_d_insn (ival) || is_fnmsub_d_insn (ival) + || is_fnmadd_d_insn (ival) || is_fadd_d_insn (ival) + || is_fsub_d_insn (ival) || is_fmul_d_insn (ival) + || is_fdiv_d_insn (ival) || is_fsqrt_d_insn (ival) + || is_fsgnj_d_insn (ival) || is_fsgnjn_d_insn (ival) + || is_fsgnjx_d_insn (ival) || is_fmin_d_insn (ival) + || is_fmax_d_insn (ival) || is_fcvt_s_d_insn (ival) + || is_fcvt_d_s_insn (ival) || is_fcvt_d_w_insn (ival) + || is_fcvt_d_wu_insn (ival) || is_fcvt_d_l_insn (ival) + || is_fcvt_d_lu_insn (ival) || is_fmv_d_x_insn (ival)); + } + + /* Returns true if instruction is classified. This function can set + m_error_occured. */ + bool + try_save_pc_fprd (ULONGEST ival) noexcept + { + if (!need_save_pc_fprd (ival)) + return false; + + return (!save_reg (RISCV_FIRST_FP_REGNUM + decode_rd (ival)) + || set_ordinary_record_type ()); + } + + /* Returns true if instruction needs only saving pc, rd and csr. */ + static bool + need_save_pc_rd_csr (ULONGEST ival) noexcept + { + return (is_csrrw_insn (ival) || is_csrrs_insn (ival) || is_csrrc_insn (ival) + || is_csrrwi_insn (ival) || is_csrrsi_insn (ival) + || is_csrrc_insn (ival)); + } + + /* Returns true if instruction is classified. This function can set + m_error_occured. */ + bool + try_save_pc_rd_csr (ULONGEST ival) noexcept + { + if (!need_save_pc_rd_csr (ival)) + return false; + + return (!save_reg (decode_rd (ival)) + || !save_reg (RISCV_FIRST_CSR_REGNUM + decode_csr (ival)) + || set_ordinary_record_type ()); + } + + /* Returns the size of the memory chunk that needs to be saved if the + instruction belongs to the group that needs only saving pc and memory. + Otherwise returns 0. */ + static mem_len + need_save_pc_mem (ULONGEST ival) noexcept + { + if (is_sb_insn (ival)) + return 1; + if (is_sh_insn (ival)) + return 2; + if (is_sw_insn (ival) || is_fsw_insn (ival)) + return 4; + if (is_sd_insn (ival) || is_fsd_insn (ival)) + return 8; + return 0; + } + + /* Returns true if instruction is classified. This function can set + m_error_occured. */ + bool + try_save_pc_mem (ULONGEST ival, struct regcache *regcache) noexcept + { + gdb_assert (regcache != nullptr); + + mem_addr addr = mem_addr{}; + mem_len len = need_save_pc_mem (ival); + if (len <= 0) + return false; + + mem_len offset = EXTRACT_STYPE_IMM (ival); + return (!read_reg (regcache, decode_rs1 (ival), addr) + || !save_mem (addr + offset, len) || set_ordinary_record_type ()); + } + + /* Returns the size of the memory chunk that needs to be saved if the + instruction belongs to the group that needs only saving pc, rd and memory. + Otherwise returns 0. */ + static mem_len + need_save_pc_rd_mem (ULONGEST ival) noexcept + { + if (is_sc_w_insn (ival) || is_amoswap_w_insn (ival) + || is_amoadd_w_insn (ival) || is_amoxor_w_insn (ival) + || is_amoand_w_insn (ival) || is_amoor_w_insn (ival) + || is_amomin_w_insn (ival) || is_amomax_w_insn (ival) + || is_amominu_w_insn (ival) || is_amomaxu_w_insn (ival)) + return 4; + if (is_sc_d_insn (ival) || is_amoswap_d_insn (ival) + || is_amoadd_d_insn (ival) || is_amoxor_d_insn (ival) + || is_amoand_d_insn (ival) || is_amoor_d_insn (ival) + || is_amomin_d_insn (ival) || is_amomax_d_insn (ival) + || is_amominu_d_insn (ival) || is_amomaxu_d_insn (ival)) + return 8; + return 0; + } + + /* Returns true if instruction is classified. This function can set + m_error_occured. */ + bool + try_save_pc_rd_mem (ULONGEST ival, struct regcache *regcache) noexcept + { + gdb_assert (regcache != nullptr); + + mem_len len = need_save_pc_rd_mem (ival); + mem_addr addr = 0; + if (len <= 0) + return false; + + return (!read_reg (regcache, decode_rs1 (ival), addr) + || !save_mem (addr, len) || !save_reg (decode_rd (ival)) + || set_ordinary_record_type ()); + } + + /* Returns true if instruction is successfully recordered. The length of + the instruction must be equal 4 bytes. */ + bool + record_insn_len4 (ULONGEST ival, struct regcache *regcache) noexcept + { + gdb_assert (regcache != nullptr); + + if (is_ecall_insn (ival)) + { + m_record_type = record_type::ECALL; + return true; + } + + if (is_ebreak_insn (ival)) + { + m_record_type = record_type::EBREAK; + return true; + } + + if (try_save_pc (ival) || try_save_pc_rd (ival) || try_save_pc_fprd (ival) + || try_save_pc_rd_csr (ival) || try_save_pc_mem (ival, regcache) + || try_save_pc_rd_mem (ival, regcache)) + return !has_error (); + + warning (_("Currently this instruction with len 4(%lx) is unsupported"), + ival); + return false; + } + + /* Returns true if instruction is successfully recordered. The length of + the instruction must be equal 2 bytes. */ + bool + record_insn_len2 (ULONGEST ival, struct regcache *regcache) noexcept + { + gdb_assert (regcache != nullptr); + + mem_addr addr = mem_addr{}; + + /* The order here is very important, because + opcodes of some instructions may be the same. */ + + if (is_c_addi4spn_insn (ival) || is_c_lw_insn (ival) + || (m_xlen == 8 && is_c_ld_insn (ival))) + return (!save_reg (decode_crs2_short (ival)) + || set_ordinary_record_type ()); + + if (is_c_fld_insn (ival) || (m_xlen == 4 && is_c_flw_insn (ival))) + return (!save_reg (RISCV_FIRST_FP_REGNUM + decode_crs2_short (ival)) + || set_ordinary_record_type ()); + + if (is_c_fsd_insn (ival) || (m_xlen == 8 && is_c_sd_insn (ival))) + { + ULONGEST offset = ULONGEST{EXTRACT_CLTYPE_LD_IMM (ival)}; + return (!read_reg (regcache, decode_crs1_short (ival), addr) + || !save_mem (addr + offset, 8) || set_ordinary_record_type ()); + } + + if ((m_xlen == 4 && is_c_fsw_insn (ival)) || is_c_sw_insn (ival)) + { + ULONGEST offset = ULONGEST{EXTRACT_CLTYPE_LW_IMM (ival)}; + return (!read_reg (regcache, decode_crs1_short (ival), addr) + || !save_mem (addr + offset, 4) || set_ordinary_record_type ()); + } + + if (is_c_nop_insn (ival)) + return set_ordinary_record_type (); + + if (is_c_addi_insn (ival)) + return (!save_reg (decode_crs1 (ival)) || set_ordinary_record_type ()); + + if (m_xlen == 4 && is_c_jal_insn (ival)) + return (!save_reg (RISCV_RA_REGNUM) || set_ordinary_record_type ()); + + if ((m_xlen == 8 && is_c_addiw_insn (ival)) || is_c_li_insn (ival)) + return (!save_reg (decode_crs1 (ival)) || set_ordinary_record_type ()); + + if (is_c_addi16sp_insn (ival)) + return (!save_reg (RISCV_SP_REGNUM) || set_ordinary_record_type ()); + + if (is_c_lui_insn (ival)) + return (!save_reg (decode_crs1 (ival)) || set_ordinary_record_type ()); + + if (is_c_srli_insn (ival) || is_c_srai_insn (ival) || is_c_andi_insn (ival) + || is_c_sub_insn (ival) || is_c_xor_insn (ival) || is_c_or_insn (ival) + || is_c_and_insn (ival) || (m_xlen == 8 && is_c_subw_insn (ival)) + || (m_xlen == 8 && is_c_addw_insn (ival))) + return (!save_reg (decode_crs1_short (ival)) + || set_ordinary_record_type ()); + + if (is_c_j_insn (ival) || is_c_beqz_insn (ival) || is_c_bnez_insn (ival)) + return set_ordinary_record_type (); + + if (is_c_slli_insn (ival)) + return (!save_reg (decode_crs1 (ival)) || set_ordinary_record_type ()); + + if (is_c_fldsp_insn (ival) || (m_xlen == 4 && is_c_flwsp_insn (ival))) + return (!save_reg (RISCV_FIRST_FP_REGNUM + decode_crs1 (ival)) + || set_ordinary_record_type ()); + + if (is_c_lwsp_insn (ival) || (m_xlen == 8 && is_c_ldsp_insn (ival))) + return (!save_reg (decode_crs1 (ival)) || set_ordinary_record_type ()); + + if (is_c_jr_insn (ival)) + return set_ordinary_record_type (); + + if (is_c_mv_insn (ival)) + return (!save_reg (decode_crs1 (ival)) || set_ordinary_record_type ()); + + if (is_c_ebreak_insn (ival)) + { + m_record_type = record_type::EBREAK; + return true; + } + + if (is_c_jalr_insn (ival)) + return (!save_reg (RISCV_RA_REGNUM) || set_ordinary_record_type ()); + + if (is_c_add_insn (ival)) + return (!save_reg (decode_crs1 (ival)) || set_ordinary_record_type ()); + + if (is_c_fsdsp_insn (ival) || (m_xlen == 8 && is_c_sdsp_insn (ival))) + { + ULONGEST offset = ULONGEST{EXTRACT_CSSTYPE_SDSP_IMM (ival)}; + return (!read_reg (regcache, RISCV_SP_REGNUM, addr) + || !save_mem (addr + offset, 8) || set_ordinary_record_type ()); + } + + if (is_c_swsp_insn (ival) || (m_xlen == 4 && is_c_fswsp_insn (ival))) + { + ULONGEST offset = ULONGEST{EXTRACT_CSSTYPE_SWSP_IMM (ival)}; + return (!read_reg (regcache, RISCV_SP_REGNUM, addr) + || !save_mem (addr + offset, 4) || set_ordinary_record_type ()); + } + + warning (_("Currently this instruction with len 2(%lx) is unsupported"), + ival); + return false; + } + +public: + /* Iterator for registers that need to be recorded. */ + using regs_iter = recorded_regs::const_iterator; + /* Iterator for memory chunks that need to be recorded. */ + using mems_iter = recorded_mems::const_iterator; + + /* Record instruction at address addr. Returns false if error happened. */ + bool + record (gdbarch *gdbarch, struct regcache *regcache, CORE_ADDR addr) noexcept + { + gdb_assert (gdbarch != nullptr); + gdb_assert (regcache != nullptr); + + int m_length = 0; + m_xlen = riscv_isa_xlen (gdbarch); + ULONGEST ival = riscv_insn::fetch_instruction (gdbarch, addr, &m_length); + if (!save_reg (RISCV_PC_REGNUM)) + return false; + + if (m_length == 4) + return record_insn_len4 (ival, regcache); + + if (m_length == 2) + return record_insn_len2 (ival, regcache); + + /* 6 bytes or more. If the instruction is longer than 8 bytes, we don't + have full instruction bits in ival. At least, such long instructions + are not defined yet, so just ignore it. */ + gdb_assert (m_length > 0 && m_length % 2 == 0); + + warning (_("Can not record unknown instruction (opcode = %lx)"), ival); + return false; + } + + /* Get record type of instruction. */ + record_type + get_record_type () const noexcept + { + return m_record_type; + } + + /* Returns an iterator to the beginning of the registers that need + to be saved. */ + regs_iter + regs_begin () const noexcept + { + return m_regs.begin (); + } + + /* Returns an iterator to the end of the registers that need + to be saved. */ + regs_iter + regs_end () const noexcept + { + return m_regs.end (); + } + + /* Returns an iterator to the beginning of the memory chunks that need + to be saved. */ + mems_iter + mems_begin () const noexcept + { + return m_mems.begin (); + } + + /* Returns an iterator to the end of the memory chunks that need + to be saved. */ + mems_iter + mems_end () const noexcept + { + return m_mems.end (); + } +}; + +/* A helper function to record instruction using record API. */ + +static int +riscv_record_insn_details (struct gdbarch *gdbarch, struct regcache *regcache, + const riscv_recorded_insn &insn) +{ + gdb_assert (gdbarch != nullptr); + gdb_assert (regcache != nullptr); + + riscv_gdbarch_tdep *tdep = gdbarch_tdep<riscv_gdbarch_tdep> (gdbarch); + auto regs_begin = insn.regs_begin (); + auto regs_end = insn.regs_end (); + if (std::any_of (regs_begin, + regs_end, + [®cache] (auto &®_it) + { + return record_full_arch_list_add_reg (regcache, reg_it); + })) + return -1; + + auto mems_begin = insn.mems_begin (); + auto mems_end = insn.mems_end (); + if (std::any_of (mems_begin, + mems_end, + [] (auto &&mem_it) + { + return record_full_arch_list_add_mem (mem_it.first, + mem_it.second); + })) + return -1; + + switch (insn.get_record_type ()) + { + case riscv_recorded_insn::record_type::ORDINARY: + break; + + case riscv_recorded_insn::record_type::ECALL: + { + if (!tdep->riscv_syscall_record) + { + warning (_("Syscall record is not supported")); + return -1; + } + ULONGEST reg_val = ULONGEST{}; + if (!try_read (regcache, RISCV_A7_REGNUM, reg_val)) + return -1; + return tdep->riscv_syscall_record (regcache, reg_val); + } + + case riscv_recorded_insn::record_type::EBREAK: + break; + + default: + return -1; + } + return 0; +} + +/* Parse the current instruction and record the values of the registers and + memory that will be changed in current instruction to record_arch_list. + Return -1 if something is wrong. */ + +int +riscv_process_record (struct gdbarch *gdbarch, struct regcache *regcache, + CORE_ADDR addr) +{ + gdb_assert (gdbarch != nullptr); + gdb_assert (regcache != nullptr); + + riscv_recorded_insn insn; + if (!insn.record (gdbarch, regcache, addr)) + { + record_full_arch_list_add_end (); + return -1; + } + + int ret_val = riscv_record_insn_details (gdbarch, regcache, insn); + + if (record_full_arch_list_add_end ()) + return -1; + + return ret_val; +} |