Skip to content

Commit

Permalink
Add access support for RISC-V (#2393)
Browse files Browse the repository at this point in the history
* resolve conflict for loongarch and RISCV in Mapping.c and Mapping.h

* Use RISCV_get_detail for simplicity

Co-authored-by: Rot127 <45763064+Rot127@users.noreply.github.com>

* Use detail_is_set for simplicity

Co-authored-by: Rot127 <45763064+Rot127@users.noreply.github.com>

* Change comment style

Co-authored-by: Rot127 <45763064+Rot127@users.noreply.github.com>

* remove redundant add_str

* fix bug for RISCV_add_detail

* fix operands for csr instructions

* add python binding and tester for RISC-V

* add more test cases for RISC-V (M,A,F,D,C instructions)

* fix incorrect operand and access for sc.w and sc.d

* fix incorrect operand for fence and sfence.vma

* assert -> CS_ASSERT

* some instructions in test_riscv.c should be RISCV64

* add cs details test

* update python testers

---------

Co-authored-by: Rot127 <45763064+Rot127@users.noreply.github.com>
  • Loading branch information
wxrdnx and Rot127 committed Jul 10, 2024
1 parent 9c5b48b commit 404912f
Show file tree
Hide file tree
Showing 16 changed files with 3,159 additions and 36 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -572,6 +572,7 @@ if(CAPSTONE_RISCV_SUPPORT)
arch/RISCV/RISCVGenRegisterInfo.inc
arch/RISCV/RISCVGenSubtargetInfo.inc
arch/RISCV/RISCVMappingInsn.inc
arch/RISCV/RISCVMappingInsnOp.inc
)
set(TEST_SOURCES ${TEST_SOURCES} test_riscv.c)
endif()
Expand Down
1 change: 1 addition & 0 deletions Mapping.c
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,7 @@ DEFINE_get_detail_op(aarch64, AArch64);
DEFINE_get_detail_op(alpha, Alpha);
DEFINE_get_detail_op(hppa, HPPA);
DEFINE_get_detail_op(loongarch, LoongArch);
DEFINE_get_detail_op(riscv, RISCV);

/// Returns true if for this architecture the
/// alias operands should be filled.
Expand Down
4 changes: 4 additions & 0 deletions Mapping.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ DECL_get_detail_op(aarch64, AArch64);
DECL_get_detail_op(alpha, Alpha);
DECL_get_detail_op(hppa, HPPA);
DECL_get_detail_op(loongarch, LoongArch);
DECL_get_detail_op(riscv, RISCV);

/// Increments the detail->arch.op_count by one.
#define DEFINE_inc_detail_op_count(arch, ARCH) \
Expand Down Expand Up @@ -167,6 +168,8 @@ DEFINE_inc_detail_op_count(hppa, HPPA);
DEFINE_dec_detail_op_count(hppa, HPPA);
DEFINE_inc_detail_op_count(loongarch, LoongArch);
DEFINE_dec_detail_op_count(loongarch, LoongArch);
DEFINE_inc_detail_op_count(riscv, RISCV);
DEFINE_dec_detail_op_count(riscv, RISCV);

/// Returns true if a memory operand is currently edited.
static inline bool doing_mem(const MCInst *MI)
Expand Down Expand Up @@ -195,6 +198,7 @@ DEFINE_get_arch_detail(aarch64, AArch64);
DEFINE_get_arch_detail(alpha, Alpha);
DEFINE_get_arch_detail(hppa, HPPA);
DEFINE_get_arch_detail(loongarch, LoongArch);
DEFINE_get_arch_detail(riscv, RISCV);

static inline bool detail_is_set(const MCInst *MI)
{
Expand Down
2 changes: 1 addition & 1 deletion arch/Alpha/AlphaMapping.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ static const insn_map insns[] = {
#include "AlphaGenCSMappingInsn.inc"
};

const map_insn_ops insn_operands[] = {
static const map_insn_ops insn_operands[] = {
#include "AlphaGenCSMappingInsnOp.inc"
};

Expand Down
29 changes: 28 additions & 1 deletion arch/RISCV/RISCVDisassembler.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "../../MCRegisterInfo.h"
#include "../../MCDisassembler.h"
#include "../../MathExtras.h"
#include "../../Mapping.h"
#include "RISCVBaseInfo.h"
#include "RISCVDisassembler.h"

Expand Down Expand Up @@ -322,16 +323,36 @@ static void markLSInsn(MCInst *MI, uint32_t in)
st 0100011 = 0x23
F/D ld 0000111 = 0x07
st 0100111 = 0x27
st 0101111 = 0x2f
*/
#define MASK_LS_INSN 0x0000007f
uint32_t opcode = in & MASK_LS_INSN;
if (0 == (opcode ^ 0x03) || 0 == (opcode ^ 0x07) ||
0 == (opcode ^ 0x23) || 0 == (opcode ^ 0x27))
0 == (opcode ^ 0x23) || 0 == (opcode ^ 0x27) ||
0 == (opcode ^ 0x2f))
MI->flat_insn->detail->riscv.need_effective_addr = true;
#undef MASK_LS_INSN
return;
}

static void markCLSInsn(MCInst *MI, uint32_t in)
{
// Unfortunately there is no obvious pattern in terms of RISC-V C instructions
// Thus, we compare the instruction IDs to see if it is a load/store instruction
unsigned id = MCInst_getOpcode(MI);
if (id == RISCV_C_FLD || id == RISCV_C_LW ||
id == RISCV_C_FLW || id == RISCV_C_LD ||
id == RISCV_C_FSD || id == RISCV_C_SW ||
id == RISCV_C_FSW || id == RISCV_C_SD ||
id == RISCV_C_FLDSP || id == RISCV_C_LWSP ||
id == RISCV_C_FLWSP || id == RISCV_C_LDSP ||
id == RISCV_C_FSDSP || id == RISCV_C_SWSP ||
id == RISCV_C_FSWSP || id == RISCV_C_SDSP) {
RISCV_get_detail(MI)->need_effective_addr = true;
}
return;
}

static DecodeStatus RISCVDisassembler_getInstruction(int mode, MCInst *MI,
const uint8_t *code, size_t code_len,
uint16_t *Size, uint64_t Address,
Expand Down Expand Up @@ -382,6 +403,12 @@ static DecodeStatus RISCVDisassembler_getInstruction(int mode, MCInst *MI,
init_MI_insn_detail(MI);
// Calling the auto-generated decoder function.
Result = decodeInstruction(DecoderTable16, MI, Inst, Address, MRI, mode);
// Now we need mark what instruction need fix effective address output.
// Note that we mark it AFTER the instruction is decoded
// This is because there is no obvious pattern in terms of RISC-V C instructions
// So we compare the instruction IDs one by one
if (detail_is_set(MI))
markCLSInsn(MI, Inst);
*Size = 2;
}

Expand Down
204 changes: 174 additions & 30 deletions arch/RISCV/RISCVInstPrinter.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "../../SStream.h"
#include "../../MCRegisterInfo.h"
#include "../../utils.h"
#include "../../Mapping.h"
#include "RISCVMapping.h"

//#include "RISCVDisassembler.h"
Expand Down Expand Up @@ -54,28 +55,180 @@ static const char *getRegisterName(unsigned RegNo, unsigned AltIdx);

static void fixDetailOfEffectiveAddr(MCInst *MI)
{
// Operands for load and store instructions in RISCV vary widely
unsigned id = MI->flat_insn->id;
unsigned reg = 0;
int64_t imm = 0;

CS_ASSERT(3 == MI->flat_insn->detail->riscv.op_count);
CS_ASSERT(RISCV_OP_REG == MI->flat_insn->detail->riscv.operands[0].type);

if (RISCV_OP_IMM == MI->flat_insn->detail->riscv.operands[1].type) {
CS_ASSERT(RISCV_OP_REG == MI->flat_insn->detail->riscv.operands[2].type);
imm = MI->flat_insn->detail->riscv.operands[1].imm;
reg = MI->flat_insn->detail->riscv.operands[2].reg;
} else if (RISCV_OP_REG == MI->flat_insn->detail->riscv.operands[1].type) {
CS_ASSERT(RISCV_OP_IMM == MI->flat_insn->detail->riscv.operands[2].type);
reg = MI->flat_insn->detail->riscv.operands[1].reg;
imm = MI->flat_insn->detail->riscv.operands[2].imm;
uint8_t access = 0;

switch (id) {
case RISCV_INS_C_FLD:
case RISCV_INS_C_LW:
case RISCV_INS_C_FLW:
case RISCV_INS_C_LD:
case RISCV_INS_C_FSD:
case RISCV_INS_C_SW:
case RISCV_INS_C_FSW:
case RISCV_INS_C_SD:
case RISCV_INS_C_FLDSP:
case RISCV_INS_C_LWSP:
case RISCV_INS_C_FLWSP:
case RISCV_INS_C_LDSP:
case RISCV_INS_C_FSDSP:
case RISCV_INS_C_SWSP:
case RISCV_INS_C_FSWSP:
case RISCV_INS_C_SDSP:
case RISCV_INS_FLW:
case RISCV_INS_FSW:
case RISCV_INS_FLD:
case RISCV_INS_FSD:
case RISCV_INS_LB:
case RISCV_INS_LBU:
case RISCV_INS_LD:
case RISCV_INS_LH:
case RISCV_INS_LHU:
case RISCV_INS_LW:
case RISCV_INS_LWU:
case RISCV_INS_SB:
case RISCV_INS_SD:
case RISCV_INS_SH:
case RISCV_INS_SW: {
CS_ASSERT(3 == MI->flat_insn->detail->riscv.op_count);
CS_ASSERT(RISCV_OP_REG == RISCV_get_detail_op(MI, -3)->type);
CS_ASSERT(RISCV_OP_IMM == RISCV_get_detail_op(MI, -2)->type);
CS_ASSERT(RISCV_OP_REG == RISCV_get_detail_op(MI, -1)->type);

imm = RISCV_get_detail_op(MI, -2)->imm;
reg = RISCV_get_detail_op(MI, -1)->reg;
access = RISCV_get_detail_op(MI, -1)->access;

RISCV_get_detail_op(MI, -2)->type = RISCV_OP_MEM;
RISCV_get_detail_op(MI, -2)->mem.base = reg;
RISCV_get_detail_op(MI, -2)->mem.disp = imm;
RISCV_get_detail_op(MI, -2)->access = access;

RISCV_dec_op_count(MI);

break;
}
case RISCV_INS_LR_W:
case RISCV_INS_LR_W_AQ:
case RISCV_INS_LR_W_AQ_RL:
case RISCV_INS_LR_W_RL:
case RISCV_INS_LR_D:
case RISCV_INS_LR_D_AQ:
case RISCV_INS_LR_D_AQ_RL:
case RISCV_INS_LR_D_RL: {
CS_ASSERT(2 == MI->flat_insn->detail->riscv.op_count);
CS_ASSERT(RISCV_OP_REG == RISCV_get_detail_op(MI, -1)->type);
CS_ASSERT(RISCV_OP_REG == RISCV_get_detail_op(MI, -2)->type);

reg = RISCV_get_detail_op(MI, -1)->reg;

RISCV_get_detail_op(MI, -1)->type = RISCV_OP_MEM;
RISCV_get_detail_op(MI, -1)->mem.base = reg;
RISCV_get_detail_op(MI, -1)->mem.disp = 0;

break;
}
case RISCV_INS_SC_W:
case RISCV_INS_SC_W_AQ:
case RISCV_INS_SC_W_AQ_RL:
case RISCV_INS_SC_W_RL:
case RISCV_INS_SC_D:
case RISCV_INS_SC_D_AQ:
case RISCV_INS_SC_D_AQ_RL:
case RISCV_INS_SC_D_RL:
case RISCV_INS_AMOADD_D:
case RISCV_INS_AMOADD_D_AQ:
case RISCV_INS_AMOADD_D_AQ_RL:
case RISCV_INS_AMOADD_D_RL:
case RISCV_INS_AMOADD_W:
case RISCV_INS_AMOADD_W_AQ:
case RISCV_INS_AMOADD_W_AQ_RL:
case RISCV_INS_AMOADD_W_RL:
case RISCV_INS_AMOAND_D:
case RISCV_INS_AMOAND_D_AQ:
case RISCV_INS_AMOAND_D_AQ_RL:
case RISCV_INS_AMOAND_D_RL:
case RISCV_INS_AMOAND_W:
case RISCV_INS_AMOAND_W_AQ:
case RISCV_INS_AMOAND_W_AQ_RL:
case RISCV_INS_AMOAND_W_RL:
case RISCV_INS_AMOMAXU_D:
case RISCV_INS_AMOMAXU_D_AQ:
case RISCV_INS_AMOMAXU_D_AQ_RL:
case RISCV_INS_AMOMAXU_D_RL:
case RISCV_INS_AMOMAXU_W:
case RISCV_INS_AMOMAXU_W_AQ:
case RISCV_INS_AMOMAXU_W_AQ_RL:
case RISCV_INS_AMOMAXU_W_RL:
case RISCV_INS_AMOMAX_D:
case RISCV_INS_AMOMAX_D_AQ:
case RISCV_INS_AMOMAX_D_AQ_RL:
case RISCV_INS_AMOMAX_D_RL:
case RISCV_INS_AMOMAX_W:
case RISCV_INS_AMOMAX_W_AQ:
case RISCV_INS_AMOMAX_W_AQ_RL:
case RISCV_INS_AMOMAX_W_RL:
case RISCV_INS_AMOMINU_D:
case RISCV_INS_AMOMINU_D_AQ:
case RISCV_INS_AMOMINU_D_AQ_RL:
case RISCV_INS_AMOMINU_D_RL:
case RISCV_INS_AMOMINU_W:
case RISCV_INS_AMOMINU_W_AQ:
case RISCV_INS_AMOMINU_W_AQ_RL:
case RISCV_INS_AMOMINU_W_RL:
case RISCV_INS_AMOMIN_D:
case RISCV_INS_AMOMIN_D_AQ:
case RISCV_INS_AMOMIN_D_AQ_RL:
case RISCV_INS_AMOMIN_D_RL:
case RISCV_INS_AMOMIN_W:
case RISCV_INS_AMOMIN_W_AQ:
case RISCV_INS_AMOMIN_W_AQ_RL:
case RISCV_INS_AMOMIN_W_RL:
case RISCV_INS_AMOOR_D:
case RISCV_INS_AMOOR_D_AQ:
case RISCV_INS_AMOOR_D_AQ_RL:
case RISCV_INS_AMOOR_D_RL:
case RISCV_INS_AMOOR_W:
case RISCV_INS_AMOOR_W_AQ:
case RISCV_INS_AMOOR_W_AQ_RL:
case RISCV_INS_AMOOR_W_RL:
case RISCV_INS_AMOSWAP_D:
case RISCV_INS_AMOSWAP_D_AQ:
case RISCV_INS_AMOSWAP_D_AQ_RL:
case RISCV_INS_AMOSWAP_D_RL:
case RISCV_INS_AMOSWAP_W:
case RISCV_INS_AMOSWAP_W_AQ:
case RISCV_INS_AMOSWAP_W_AQ_RL:
case RISCV_INS_AMOSWAP_W_RL:
case RISCV_INS_AMOXOR_D:
case RISCV_INS_AMOXOR_D_AQ:
case RISCV_INS_AMOXOR_D_AQ_RL:
case RISCV_INS_AMOXOR_D_RL:
case RISCV_INS_AMOXOR_W:
case RISCV_INS_AMOXOR_W_AQ:
case RISCV_INS_AMOXOR_W_AQ_RL:
case RISCV_INS_AMOXOR_W_RL: {
CS_ASSERT(3 == MI->flat_insn->detail->riscv.op_count);
CS_ASSERT(RISCV_OP_REG == RISCV_get_detail_op(MI, -3)->type);
CS_ASSERT(RISCV_OP_REG == RISCV_get_detail_op(MI, -2)->type);
CS_ASSERT(RISCV_OP_REG == RISCV_get_detail_op(MI, -1)->type);

reg = RISCV_get_detail_op(MI, -1)->reg;

RISCV_get_detail_op(MI, -1)->type = RISCV_OP_MEM;
RISCV_get_detail_op(MI, -1)->mem.base = reg;
RISCV_get_detail_op(MI, -1)->mem.disp = 0;

break;
}
default: {
CS_ASSERT(0 && "id is not a RISC-V memory instruction");
break;
}
}

// set up effective address.
MI->flat_insn->detail->riscv.operands[1].type = RISCV_OP_MEM;
MI->flat_insn->detail->riscv.op_count--;
MI->flat_insn->detail->riscv.operands[1].mem.base = reg;
MI->flat_insn->detail->riscv.operands[1].mem.disp = imm;

return;
}

Expand Down Expand Up @@ -118,16 +271,13 @@ static void printOperand(MCInst *MI, unsigned OpNo, SStream *O)
unsigned reg;
int64_t Imm = 0;

RISCV_add_cs_detail(MI, OpNo);

MCOperand *MO = MCInst_getOperand(MI, OpNo);

if (MCOperand_isReg(MO)) {
reg = MCOperand_getReg(MO);
printRegName(O, reg);
if (MI->csh->detail_opt) {
MI->flat_insn->detail->riscv.operands[MI->flat_insn->detail->riscv.op_count].type = RISCV_OP_REG;
MI->flat_insn->detail->riscv.operands[MI->flat_insn->detail->riscv.op_count].reg = reg;
MI->flat_insn->detail->riscv.op_count++;
}
} else {
CS_ASSERT(MCOperand_isImm(MO) && "Unknown operand kind in printOperand");
Imm = MCOperand_getImm(MO);
Expand All @@ -142,12 +292,6 @@ static void printOperand(MCInst *MI, unsigned OpNo, SStream *O)
else
SStream_concat(O, "-%" PRIu64, -Imm);
}

if (MI->csh->detail_opt) {
MI->flat_insn->detail->riscv.operands[MI->flat_insn->detail->riscv.op_count].type = RISCV_OP_IMM;
MI->flat_insn->detail->riscv.operands[MI->flat_insn->detail->riscv.op_count].imm = Imm;
MI->flat_insn->detail->riscv.op_count++;
}
}

//CS_ASSERT(MO.isExpr() && "Unknown operand kind in printOperand");
Expand Down
32 changes: 32 additions & 0 deletions arch/RISCV/RISCVMapping.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include "../../Mapping.h"
#include "../../utils.h"
#include "../../cs_simple_types.h"

#include "RISCVMapping.h"
#include "RISCVInstPrinter.h"
Expand Down Expand Up @@ -140,6 +141,37 @@ static const insn_map insns[] = {
#include "RISCVMappingInsn.inc"
};

#ifndef CAPSTONE_DIET

static const map_insn_ops insn_operands[] = {
#include "RISCVMappingInsnOp.inc"
};

#endif

void RISCV_add_cs_detail(MCInst *MI, unsigned OpNum) {
if (!detail_is_set(MI))
return;

cs_op_type op_type = map_get_op_type(MI, OpNum);

if (op_type == CS_OP_IMM) {
RISCV_get_detail_op(MI, 0)->type = RISCV_OP_IMM;
RISCV_get_detail_op(MI, 0)->imm = MCInst_getOpVal(MI, OpNum);
RISCV_get_detail_op(MI, 0)->access = map_get_op_access(MI, OpNum);
RISCV_inc_op_count(MI);
}
else if (op_type == CS_OP_REG) {
RISCV_get_detail_op(MI, 0)->type = RISCV_OP_REG;
RISCV_get_detail_op(MI, 0)->reg = MCInst_getOpVal(MI, OpNum);
RISCV_get_detail_op(MI, 0)->access = map_get_op_access(MI, OpNum);
RISCV_inc_op_count(MI);
}
else {
CS_ASSERT(0 && "Op type not handled.");
}
}

// given internal insn id, return public instruction info
void RISCV_get_insn_id(cs_struct * h, cs_insn * insn, unsigned int id)
{
Expand Down
Loading

0 comments on commit 404912f

Please sign in to comment.