aboutsummaryrefslogtreecommitdiffstats
path: root/capstone/arch/RISCV/RISCVDisassembler.c
diff options
context:
space:
mode:
Diffstat (limited to 'capstone/arch/RISCV/RISCVDisassembler.c')
-rw-r--r--capstone/arch/RISCV/RISCVDisassembler.c434
1 files changed, 434 insertions, 0 deletions
diff --git a/capstone/arch/RISCV/RISCVDisassembler.c b/capstone/arch/RISCV/RISCVDisassembler.c
new file mode 100644
index 000000000..9b0c089df
--- /dev/null
+++ b/capstone/arch/RISCV/RISCVDisassembler.c
@@ -0,0 +1,434 @@
+//===-- RISCVDisassembler.cpp - Disassembler for RISCV --------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+/* Capstone Disassembly Engine */
+/* RISC-V Backend By Rodrigo Cortes Porto <porto703@gmail.com> &
+ Shawn Chang <citypw@gmail.com>, HardenedLinux@2018 */
+
+#ifdef CAPSTONE_HAS_RISCV
+
+#include <stdio.h> // DEBUG
+#include <stdlib.h>
+#include <string.h>
+
+#include "../../cs_priv.h"
+#include "../../utils.h"
+
+#include "../../MCInst.h"
+#include "../../MCInstrDesc.h"
+#include "../../MCFixedLenDisassembler.h"
+#include "../../MCRegisterInfo.h"
+#include "../../MCDisassembler.h"
+#include "../../MathExtras.h"
+#include "RISCVBaseInfo.h"
+#include "RISCVDisassembler.h"
+
+
+/* Need the feature infos define in
+ RISCVGenSubtargetInfo.inc. */
+#define GET_SUBTARGETINFO_ENUM
+#include "RISCVGenSubtargetInfo.inc"
+
+/* When we specify the RISCV64 mode, It means It is RV64IMAFD.
+ Similar, RISCV32 means RV32IMAFD.
+*/
+static uint64_t getFeatureBits(int mode)
+{
+ if (mode == CS_MODE_RISCV32)
+ // return b11110
+ return RISCV_FeatureStdExtM | RISCV_FeatureStdExtA |
+ RISCV_FeatureStdExtF | RISCV_FeatureStdExtD ;
+ else
+
+ // CS_MODE_RISCV64, return b11111
+ return RISCV_Feature64Bit | RISCV_FeatureStdExtM |
+ RISCV_FeatureStdExtA | RISCV_FeatureStdExtF |
+ RISCV_FeatureStdExtD ;
+}
+
+#define GET_REGINFO_ENUM
+#define GET_REGINFO_MC_DESC
+#include "RISCVGenRegisterInfo.inc"
+#define GET_INSTRINFO_ENUM
+#include "RISCVGenInstrInfo.inc"
+
+static const unsigned GPRDecoderTable[] = {
+ RISCV_X0, RISCV_X1, RISCV_X2, RISCV_X3,
+ RISCV_X4, RISCV_X5, RISCV_X6, RISCV_X7,
+ RISCV_X8, RISCV_X9, RISCV_X10, RISCV_X11,
+ RISCV_X12, RISCV_X13, RISCV_X14, RISCV_X15,
+ RISCV_X16, RISCV_X17, RISCV_X18, RISCV_X19,
+ RISCV_X20, RISCV_X21, RISCV_X22, RISCV_X23,
+ RISCV_X24, RISCV_X25, RISCV_X26, RISCV_X27,
+ RISCV_X28, RISCV_X29, RISCV_X30, RISCV_X31
+};
+
+static DecodeStatus DecodeGPRRegisterClass(MCInst *Inst, uint64_t RegNo,
+ uint64_t Address, const void *Decoder)
+{
+ unsigned Reg = 0;
+
+ if (RegNo > sizeof(GPRDecoderTable))
+ return MCDisassembler_Fail;
+
+ // We must define our own mapping from RegNo to register identifier.
+ // Accessing index RegNo in the register class will work in the case that
+ // registers were added in ascending order, but not in general.
+ Reg = GPRDecoderTable[RegNo];
+ //Inst.addOperand(MCOperand::createReg(Reg));
+ MCOperand_CreateReg0(Inst, Reg);
+ return MCDisassembler_Success;
+}
+
+static const unsigned FPR32DecoderTable[] = {
+ RISCV_F0_32, RISCV_F1_32, RISCV_F2_32, RISCV_F3_32,
+ RISCV_F4_32, RISCV_F5_32, RISCV_F6_32, RISCV_F7_32,
+ RISCV_F8_32, RISCV_F9_32, RISCV_F10_32, RISCV_F11_32,
+ RISCV_F12_32, RISCV_F13_32, RISCV_F14_32, RISCV_F15_32,
+ RISCV_F16_32, RISCV_F17_32, RISCV_F18_32, RISCV_F19_32,
+ RISCV_F20_32, RISCV_F21_32, RISCV_F22_32, RISCV_F23_32,
+ RISCV_F24_32, RISCV_F25_32, RISCV_F26_32, RISCV_F27_32,
+ RISCV_F28_32, RISCV_F29_32, RISCV_F30_32, RISCV_F31_32
+};
+
+static DecodeStatus DecodeFPR32RegisterClass(MCInst *Inst, uint64_t RegNo,
+ uint64_t Address, const void *Decoder)
+{
+ unsigned Reg = 0;
+
+ if (RegNo > sizeof(FPR32DecoderTable))
+ return MCDisassembler_Fail;
+
+ // We must define our own mapping from RegNo to register identifier.
+ // Accessing index RegNo in the register class will work in the case that
+ // registers were added in ascending order, but not in general.
+ Reg = FPR32DecoderTable[RegNo];
+ MCOperand_CreateReg0(Inst, Reg);
+ return MCDisassembler_Success;
+}
+
+static DecodeStatus DecodeFPR32CRegisterClass(MCInst *Inst, uint64_t RegNo,
+ uint64_t Address,
+ const void *Decoder)
+{
+ unsigned Reg = 0;
+
+ if (RegNo > 8)
+ return MCDisassembler_Fail;
+ Reg = FPR32DecoderTable[RegNo + 8];
+ MCOperand_CreateReg0(Inst, Reg);
+ return MCDisassembler_Success;
+}
+
+static const unsigned FPR64DecoderTable[] = {
+ RISCV_F0_64, RISCV_F1_64, RISCV_F2_64, RISCV_F3_64,
+ RISCV_F4_64, RISCV_F5_64, RISCV_F6_64, RISCV_F7_64,
+ RISCV_F8_64, RISCV_F9_64, RISCV_F10_64, RISCV_F11_64,
+ RISCV_F12_64, RISCV_F13_64, RISCV_F14_64, RISCV_F15_64,
+ RISCV_F16_64, RISCV_F17_64, RISCV_F18_64, RISCV_F19_64,
+ RISCV_F20_64, RISCV_F21_64, RISCV_F22_64, RISCV_F23_64,
+ RISCV_F24_64, RISCV_F25_64, RISCV_F26_64, RISCV_F27_64,
+ RISCV_F28_64, RISCV_F29_64, RISCV_F30_64, RISCV_F31_64
+};
+
+static DecodeStatus DecodeFPR64RegisterClass(MCInst *Inst, uint64_t RegNo,
+ uint64_t Address, const void *Decoder)
+{
+ unsigned Reg = 0;
+
+ if (RegNo > sizeof(FPR64DecoderTable))
+ return MCDisassembler_Fail;
+
+ // We must define our own mapping from RegNo to register identifier.
+ // Accessing index RegNo in the register class will work in the case that
+ // registers were added in ascending order, but not in general.
+ Reg = FPR64DecoderTable[RegNo];
+ MCOperand_CreateReg0(Inst, Reg);
+ return MCDisassembler_Success;
+}
+
+static DecodeStatus DecodeFPR64CRegisterClass(MCInst *Inst, uint64_t RegNo,
+ uint64_t Address,
+ const void *Decoder)
+{
+ unsigned Reg = 0;
+
+ if (RegNo > 8)
+ return MCDisassembler_Fail;
+ Reg = FPR64DecoderTable[RegNo + 8];
+ MCOperand_CreateReg0(Inst, Reg);
+ return MCDisassembler_Success;
+}
+
+static DecodeStatus DecodeGPRNoX0RegisterClass(MCInst *Inst, uint64_t RegNo,
+ uint64_t Address,
+ const void *Decoder)
+{
+ if (RegNo == 0)
+ return MCDisassembler_Fail;
+ return DecodeGPRRegisterClass(Inst, RegNo, Address, Decoder);
+}
+
+static DecodeStatus DecodeGPRNoX0X2RegisterClass(MCInst *Inst, uint64_t RegNo,
+ uint64_t Address,
+ const void *Decoder)
+{
+ if (RegNo == 2)
+ return MCDisassembler_Fail;
+ return DecodeGPRNoX0RegisterClass(Inst, RegNo, Address, Decoder);
+}
+
+static DecodeStatus DecodeGPRCRegisterClass(MCInst *Inst, uint64_t RegNo,
+ uint64_t Address,
+ const void *Decoder)
+{
+ unsigned Reg = 0;
+
+ if (RegNo > 8)
+ return MCDisassembler_Fail;
+
+ Reg = GPRDecoderTable[RegNo + 8];
+ MCOperand_CreateReg0(Inst, Reg);
+ return MCDisassembler_Success;
+}
+
+// Add implied SP operand for instructions *SP compressed instructions. The SP
+// operand isn't explicitly encoded in the instruction.
+static void addImplySP(MCInst *Inst, int64_t Address, const void *Decoder)
+{
+ if (MCInst_getOpcode(Inst) == RISCV_C_LWSP ||
+ MCInst_getOpcode(Inst) == RISCV_C_SWSP ||
+ MCInst_getOpcode(Inst) == RISCV_C_LDSP ||
+ MCInst_getOpcode(Inst) == RISCV_C_SDSP ||
+ MCInst_getOpcode(Inst) == RISCV_C_FLWSP ||
+ MCInst_getOpcode(Inst) == RISCV_C_FSWSP ||
+ MCInst_getOpcode(Inst) == RISCV_C_FLDSP ||
+ MCInst_getOpcode(Inst) == RISCV_C_FSDSP ||
+ MCInst_getOpcode(Inst) == RISCV_C_ADDI4SPN) {
+ DecodeGPRRegisterClass(Inst, 2, Address, Decoder);
+ }
+
+ if (MCInst_getOpcode(Inst) == RISCV_C_ADDI16SP) {
+ DecodeGPRRegisterClass(Inst, 2, Address, Decoder);
+ DecodeGPRRegisterClass(Inst, 2, Address, Decoder);
+ }
+}
+
+static DecodeStatus decodeUImmOperand(MCInst *Inst, uint64_t Imm,
+ int64_t Address, const void *Decoder,
+ unsigned N)
+{
+ //CS_ASSERT(isUInt<N>(Imm) && "Invalid immediate");
+ addImplySP(Inst, Address, Decoder);
+ //Inst.addOperand(MCOperand::createImm(Imm));
+ MCOperand_CreateImm0(Inst, Imm);
+ return MCDisassembler_Success;
+}
+
+static DecodeStatus decodeUImmNonZeroOperand(MCInst *Inst, uint64_t Imm,
+ int64_t Address,
+ const void *Decoder,
+ unsigned N)
+{
+ if (Imm == 0)
+ return MCDisassembler_Fail;
+ return decodeUImmOperand(Inst, Imm, Address, Decoder, N);
+}
+
+static DecodeStatus decodeSImmOperand(MCInst *Inst, uint64_t Imm,
+ int64_t Address, const void *Decoder,
+ unsigned N)
+{
+ //CS_ASSERT(isUInt<N>(Imm) && "Invalid immediate");
+ addImplySP(Inst, Address, Decoder);
+ // Sign-extend the number in the bottom N bits of Imm
+ //Inst.addOperand(MCOperand::createImm(SignExtend64<N>(Imm)));
+ MCOperand_CreateImm0(Inst, SignExtend64(Imm, N));
+ return MCDisassembler_Success;
+}
+
+static DecodeStatus decodeSImmNonZeroOperand(MCInst *Inst, uint64_t Imm,
+ int64_t Address,
+ const void *Decoder,
+ unsigned N)
+{
+ if (Imm == 0)
+ return MCDisassembler_Fail;
+ return decodeSImmOperand(Inst, Imm, Address, Decoder, N);
+}
+
+static DecodeStatus decodeSImmOperandAndLsl1(MCInst *Inst, uint64_t Imm,
+ int64_t Address,
+ const void *Decoder,
+ unsigned N)
+{
+ //CS_ASSERT(isUInt<N>(Imm) && "Invalid immediate");
+ // Sign-extend the number in the bottom N bits of Imm after accounting for
+ // the fact that the N bit immediate is stored in N-1 bits (the LSB is
+ // always zero)
+ //Inst.addOperand(MCOperand::createImm(SignExtend64<N>(Imm << 1)));
+ MCOperand_CreateImm0(Inst, SignExtend64(Imm << 1, N));
+ return MCDisassembler_Success;
+}
+
+static DecodeStatus decodeCLUIImmOperand(MCInst *Inst, uint64_t Imm,
+ int64_t Address,
+ const void *Decoder)
+{
+ //CS_ASSERT(isUInt<6>(Imm) && "Invalid immediate");
+ if (Imm > 31) {
+ Imm = (SignExtend64(Imm, 6) & 0xfffff);
+ }
+ //Inst.addOperand(MCOperand::createImm(Imm));
+ MCOperand_CreateImm0(Inst, Imm);
+ return MCDisassembler_Success;
+}
+
+static DecodeStatus decodeFRMArg(MCInst *Inst, uint64_t Imm,
+ int64_t Address,
+ const void *Decoder)
+{
+ //CS_ASSERT(isUInt<3>(Imm) && "Invalid immediate");
+ if (!RISCVFPRndMode_isValidRoundingMode(Imm))
+ return MCDisassembler_Fail;
+
+ //Inst.addOperand(MCOperand::createImm(Imm));
+ MCOperand_CreateImm0(Inst, Imm);
+ return MCDisassembler_Success;
+}
+
+
+#include "RISCVGenDisassemblerTables.inc"
+
+static void init_MI_insn_detail(MCInst *MI)
+{
+ if (MI->flat_insn->detail) {
+ memset(MI->flat_insn->detail, 0, sizeof(cs_detail));
+ }
+
+ return;
+}
+
+// mark the load/store instructions through the opcode.
+static void markLSInsn(MCInst *MI, uint32_t in)
+{
+ /*
+ I ld 0000011 = 0x03
+ st 0100011 = 0x23
+ F/D ld 0000111 = 0x07
+ st 0100111 = 0x27
+ */
+#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))
+ MI->flat_insn->detail->riscv.need_effective_addr = true;
+#undef MASK_LS_INSN
+ return;
+}
+
+static DecodeStatus RISCVDisassembler_getInstruction(int mode, MCInst *MI,
+ const uint8_t *code, size_t code_len,
+ uint16_t *Size, uint64_t Address,
+ MCRegisterInfo *MRI)
+{
+ // TODO: This will need modification when supporting instruction set
+ // extensions with instructions > 32-bits (up to 176 bits wide).
+ uint32_t Inst = 0;
+ DecodeStatus Result;
+
+ // It's a 32 bit instruction if bit 0 and 1 are 1.
+ if ((code[0] & 0x3) == 0x3) {
+ if (code_len < 4) {
+ *Size = 0;
+ return MCDisassembler_Fail;
+ }
+
+ *Size = 4;
+ // Get the four bytes of the instruction.
+ //Encoded as little endian 32 bits.
+ Inst = code[0] | (code[1] << 8) | (code[2] << 16) | ((uint32_t)code[3] << 24);
+ init_MI_insn_detail(MI);
+ // Now we need mark what instruction need fix effective address output.
+ if (MI->csh->detail)
+ markLSInsn(MI, Inst);
+ Result = decodeInstruction(DecoderTable32, MI, Inst, Address, MRI, mode);
+ } else {
+ if (code_len < 2) {
+ *Size = 0;
+ return MCDisassembler_Fail;
+ }
+
+ // If not b4bit.
+ if (! (getFeatureBits(mode) & ((uint64_t)RISCV_Feature64Bit))) {
+ // Trying RISCV32Only_16 table (16-bit Instruction)
+ Inst = code[0] | (code[1] << 8);
+ init_MI_insn_detail(MI);
+ Result = decodeInstruction(DecoderTableRISCV32Only_16, MI, Inst, Address,
+ MRI, mode);
+ if (Result != MCDisassembler_Fail) {
+ *Size = 2;
+ return Result;
+ }
+ }
+
+ // Trying RISCV_C table (16-bit Instruction)
+ Inst = code[0] | (code[1] << 8);
+ init_MI_insn_detail(MI);
+ // Calling the auto-generated decoder function.
+ Result = decodeInstruction(DecoderTable16, MI, Inst, Address, MRI, mode);
+ *Size = 2;
+ }
+
+ return Result;
+}
+
+bool RISCV_getInstruction(csh ud, const uint8_t *code, size_t code_len,
+ MCInst *instr, uint16_t *size, uint64_t address,
+ void *info)
+{
+ cs_struct *handle = (cs_struct *)(uintptr_t)ud;
+
+ return MCDisassembler_Success ==
+ RISCVDisassembler_getInstruction(handle->mode, instr,
+ code, code_len,
+ size, address,
+ (MCRegisterInfo *)info);
+
+}
+
+void RISCV_init(MCRegisterInfo * MRI)
+{
+ /*
+ InitMCRegisterInfo(RISCVRegDesc, 97, RA, PC,
+ RISCVMCRegisterClasses, 11,
+ RISCVRegUnitRoots,
+ 64,
+ RISCVRegDiffLists,
+ RISCVLaneMaskLists,
+ RISCVRegStrings,
+ RISCVRegClassStrings,
+ RISCVSubRegIdxLists,
+ 2,
+ RISCVSubRegIdxRanges,
+ RISCVRegEncodingTable);
+ */
+
+ MCRegisterInfo_InitMCRegisterInfo(MRI, RISCVRegDesc, 97, 0, 0,
+ RISCVMCRegisterClasses, 11,
+ 0,
+ 0,
+ RISCVRegDiffLists,
+ 0,
+ RISCVSubRegIdxLists,
+ 2,
+ 0);
+}
+
+#endif