400 lines
9.4 KiB
C
400 lines
9.4 KiB
C
|
|
#ifdef CAPSTONE_HAS_RISCV
|
|
|
|
#include <stdio.h> // debug
|
|
#include <string.h>
|
|
|
|
#include "../../Mapping.h"
|
|
#include "../../utils.h"
|
|
#include "../../cs_simple_types.h"
|
|
|
|
#include "RISCVMapping.h"
|
|
#include "RISCVInstPrinter.h"
|
|
|
|
#define GET_INSTRINFO_ENUM
|
|
#include "RISCVGenInstrInfo.inc"
|
|
|
|
#ifndef CAPSTONE_DIET
|
|
static const name_map reg_name_maps[] = {
|
|
{ RISCV_REG_INVALID, NULL },
|
|
|
|
{ RISCV_REG_X0, "zero" },
|
|
{ RISCV_REG_X1, "ra" },
|
|
{ RISCV_REG_X2, "sp" },
|
|
{ RISCV_REG_X3, "gp" },
|
|
{ RISCV_REG_X4, "tp" },
|
|
{ RISCV_REG_X5, "t0" },
|
|
{ RISCV_REG_X6, "t1" },
|
|
{ RISCV_REG_X7, "t2" },
|
|
{ RISCV_REG_X8, "s0" },
|
|
{ RISCV_REG_X9, "s1" },
|
|
{ RISCV_REG_X10, "a0" },
|
|
{ RISCV_REG_X11, "a1" },
|
|
{ RISCV_REG_X12, "a2" },
|
|
{ RISCV_REG_X13, "a3" },
|
|
{ RISCV_REG_X14, "a4" },
|
|
{ RISCV_REG_X15, "a5" },
|
|
{ RISCV_REG_X16, "a6" },
|
|
{ RISCV_REG_X17, "a7" },
|
|
{ RISCV_REG_X18, "s2" },
|
|
{ RISCV_REG_X19, "s3" },
|
|
{ RISCV_REG_X20, "s4" },
|
|
{ RISCV_REG_X21, "s5" },
|
|
{ RISCV_REG_X22, "s6" },
|
|
{ RISCV_REG_X23, "s7" },
|
|
{ RISCV_REG_X24, "s8" },
|
|
{ RISCV_REG_X25, "s9" },
|
|
{ RISCV_REG_X26, "s10" },
|
|
{ RISCV_REG_X27, "s11" },
|
|
{ RISCV_REG_X28, "t3" },
|
|
{ RISCV_REG_X29, "t4" },
|
|
{ RISCV_REG_X30, "t5" },
|
|
{ RISCV_REG_X31, "t6" },
|
|
|
|
{ RISCV_REG_F0_32, "ft0" },
|
|
{ RISCV_REG_F0_64, "ft0" },
|
|
{ RISCV_REG_F1_32, "ft1" },
|
|
{ RISCV_REG_F1_64, "ft1" },
|
|
{ RISCV_REG_F2_32, "ft2" },
|
|
{ RISCV_REG_F2_64, "ft2" },
|
|
{ RISCV_REG_F3_32, "ft3" },
|
|
{ RISCV_REG_F3_64, "ft3" },
|
|
{ RISCV_REG_F4_32, "ft4" },
|
|
{ RISCV_REG_F4_64, "ft4" },
|
|
{ RISCV_REG_F5_32, "ft5" },
|
|
{ RISCV_REG_F5_64, "ft5" },
|
|
{ RISCV_REG_F6_32, "ft6" },
|
|
{ RISCV_REG_F6_64, "ft6" },
|
|
{ RISCV_REG_F7_32, "ft7" },
|
|
{ RISCV_REG_F7_64, "ft7" },
|
|
{ RISCV_REG_F8_32, "fs0" },
|
|
{ RISCV_REG_F8_64, "fs0" },
|
|
{ RISCV_REG_F9_32, "fs1" },
|
|
{ RISCV_REG_F9_64, "fs1" },
|
|
{ RISCV_REG_F10_32, "fa0" },
|
|
{ RISCV_REG_F10_64, "fa0" },
|
|
{ RISCV_REG_F11_32, "fa1" },
|
|
{ RISCV_REG_F11_64, "fa1" },
|
|
{ RISCV_REG_F12_32, "fa2" },
|
|
{ RISCV_REG_F12_64, "fa2" },
|
|
{ RISCV_REG_F13_32, "fa3" },
|
|
{ RISCV_REG_F13_64, "fa3" },
|
|
{ RISCV_REG_F14_32, "fa4" },
|
|
{ RISCV_REG_F14_64, "fa4" },
|
|
{ RISCV_REG_F15_32, "fa5" },
|
|
{ RISCV_REG_F15_64, "fa5" },
|
|
{ RISCV_REG_F16_32, "fa6" },
|
|
{ RISCV_REG_F16_64, "fa6" },
|
|
{ RISCV_REG_F17_32, "fa7" },
|
|
{ RISCV_REG_F17_64, "fa7" },
|
|
{ RISCV_REG_F18_32, "fs2" },
|
|
{ RISCV_REG_F18_64, "fs2" },
|
|
{ RISCV_REG_F19_32, "fs3" },
|
|
{ RISCV_REG_F19_64, "fs3" },
|
|
{ RISCV_REG_F20_32, "fs4" },
|
|
{ RISCV_REG_F20_64, "fs4" },
|
|
{ RISCV_REG_F21_32, "fs5" },
|
|
{ RISCV_REG_F21_64, "fs5" },
|
|
{ RISCV_REG_F22_32, "fs6" },
|
|
{ RISCV_REG_F22_64, "fs6" },
|
|
{ RISCV_REG_F23_32, "fs7" },
|
|
{ RISCV_REG_F23_64, "fs7" },
|
|
{ RISCV_REG_F24_32, "fs8" },
|
|
{ RISCV_REG_F24_64, "fs8" },
|
|
{ RISCV_REG_F25_32, "fs9" },
|
|
{ RISCV_REG_F25_64, "fs9" },
|
|
{ RISCV_REG_F26_32, "fs10" },
|
|
{ RISCV_REG_F26_64, "fs10" },
|
|
{ RISCV_REG_F27_32, "fs11" },
|
|
{ RISCV_REG_F27_64, "fs11" },
|
|
{ RISCV_REG_F28_32, "ft8" },
|
|
{ RISCV_REG_F28_64, "ft8" },
|
|
{ RISCV_REG_F29_32, "ft9" },
|
|
{ RISCV_REG_F29_64, "ft9" },
|
|
{ RISCV_REG_F30_32, "ft10" },
|
|
{ RISCV_REG_F30_64, "ft10" },
|
|
{ RISCV_REG_F31_32, "ft11" },
|
|
{ RISCV_REG_F31_64, "ft11" },
|
|
};
|
|
#endif
|
|
|
|
const char *RISCV_reg_name(csh handle, unsigned int reg)
|
|
{
|
|
#ifndef CAPSTONE_DIET
|
|
if (reg >= RISCV_REG_ENDING)
|
|
return NULL;
|
|
return reg_name_maps[reg].name;
|
|
#else
|
|
return NULL;
|
|
#endif
|
|
}
|
|
|
|
static const insn_map insns[] = {
|
|
// dummy item
|
|
{
|
|
0, 0,
|
|
#ifndef CAPSTONE_DIET
|
|
{0}, {0}, {0}, 0, 0
|
|
#endif
|
|
},
|
|
|
|
#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)
|
|
{
|
|
unsigned int i;
|
|
|
|
i = insn_find(insns, ARR_SIZE(insns), id, &h->insn_cache);
|
|
if (i != 0) {
|
|
insn->id = insns[i].mapid;
|
|
|
|
if (h->detail_opt) {
|
|
#ifndef CAPSTONE_DIET
|
|
memcpy(insn->detail->regs_read,
|
|
insns[i].regs_use, sizeof(insns[i].regs_use));
|
|
insn->detail->regs_read_count = (uint8_t)count_positive(insns[i].regs_use);
|
|
|
|
memcpy(insn->detail->regs_write, insns[i].regs_mod, sizeof(insns[i].regs_mod));
|
|
insn->detail->regs_write_count = (uint8_t)count_positive(insns[i].regs_mod);
|
|
|
|
memcpy(insn->detail->groups, insns[i].groups, sizeof(insns[i].groups));
|
|
insn->detail->groups_count = (uint8_t)count_positive8(insns[i].groups);
|
|
|
|
if (insns[i].branch || insns[i].indirect_branch) {
|
|
// this insn also belongs to JUMP group. add JUMP group
|
|
insn->detail->groups[insn->detail->groups_count] = RISCV_GRP_JUMP;
|
|
insn->detail->groups_count++;
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
static const name_map insn_name_maps[] = {
|
|
{RISCV_INS_INVALID, NULL},
|
|
|
|
#include "RISCVGenInsnNameMaps.inc"
|
|
};
|
|
|
|
const char *RISCV_insn_name(csh handle, unsigned int id)
|
|
{
|
|
#ifndef CAPSTONE_DIET
|
|
if (id >= RISCV_INS_ENDING)
|
|
return NULL;
|
|
|
|
return insn_name_maps[id].name;
|
|
#else
|
|
return NULL;
|
|
#endif
|
|
}
|
|
|
|
#ifndef CAPSTONE_DIET
|
|
static const name_map group_name_maps[] = {
|
|
// generic groups
|
|
{ RISCV_GRP_INVALID, NULL },
|
|
{ RISCV_GRP_JUMP, "jump" },
|
|
{ RISCV_GRP_CALL, "call" },
|
|
{ RISCV_GRP_RET, "ret" },
|
|
{ RISCV_GRP_INT, "int" },
|
|
{ RISCV_GRP_IRET, "iret" },
|
|
{ RISCV_GRP_PRIVILEGE, "privileged" },
|
|
{ RISCV_GRP_BRANCH_RELATIVE, "branch_relative" },
|
|
|
|
// architecture specific
|
|
{ RISCV_GRP_ISRV32, "isrv32" },
|
|
{ RISCV_GRP_ISRV64, "isrv64" },
|
|
{ RISCV_GRP_HASSTDEXTA, "hasStdExtA" },
|
|
{ RISCV_GRP_HASSTDEXTC, "hasStdExtC" },
|
|
{ RISCV_GRP_HASSTDEXTD, "hasStdExtD" },
|
|
{ RISCV_GRP_HASSTDEXTF, "hasStdExtF" },
|
|
{ RISCV_GRP_HASSTDEXTM, "hasStdExtM" },
|
|
|
|
/*
|
|
{ RISCV_GRP_ISRVA, "isrva" },
|
|
{ RISCV_GRP_ISRVC, "isrvc" },
|
|
{ RISCV_GRP_ISRVD, "isrvd" },
|
|
{ RISCV_GRP_ISRVCD, "isrvcd" },
|
|
{ RISCV_GRP_ISRVF, "isrvf" },
|
|
{ RISCV_GRP_ISRV32C, "isrv32c" },
|
|
{ RISCV_GRP_ISRV32CF, "isrv32cf" },
|
|
{ RISCV_GRP_ISRVM, "isrvm" },
|
|
{ RISCV_GRP_ISRV64A, "isrv64a" },
|
|
{ RISCV_GRP_ISRV64C, "isrv64c" },
|
|
{ RISCV_GRP_ISRV64D, "isrv64d" },
|
|
{ RISCV_GRP_ISRV64F, "isrv64f" },
|
|
{ RISCV_GRP_ISRV64M, "isrv64m" }
|
|
*/
|
|
{ RISCV_GRP_ENDING, NULL }
|
|
};
|
|
#endif
|
|
|
|
const char *RISCV_group_name(csh handle, unsigned int id)
|
|
{
|
|
#ifndef CAPSTONE_DIET
|
|
// verify group id
|
|
if (id >= RISCV_GRP_ENDING ||
|
|
(id > RISCV_GRP_BRANCH_RELATIVE && id < RISCV_GRP_ISRV32))
|
|
return NULL;
|
|
return id2name(group_name_maps, ARR_SIZE(group_name_maps), id);
|
|
#else
|
|
return NULL;
|
|
#endif
|
|
}
|
|
|
|
// map instruction name to public instruction ID
|
|
riscv_reg RISCV_map_insn(const char *name)
|
|
{
|
|
// handle special alias first
|
|
unsigned int i;
|
|
|
|
// NOTE: skip first NULL name in insn_name_maps
|
|
i = name2id(&insn_name_maps[1], ARR_SIZE(insn_name_maps) - 1, name);
|
|
|
|
return (i != -1) ? i : RISCV_REG_INVALID;
|
|
}
|
|
|
|
// map internal raw register to 'public' register
|
|
riscv_reg RISCV_map_register(unsigned int r)
|
|
{
|
|
static const unsigned int map[] = { 0,
|
|
RISCV_REG_X0,
|
|
RISCV_REG_X1,
|
|
RISCV_REG_X2,
|
|
RISCV_REG_X3,
|
|
RISCV_REG_X4,
|
|
RISCV_REG_X5,
|
|
RISCV_REG_X6,
|
|
RISCV_REG_X7,
|
|
RISCV_REG_X8,
|
|
RISCV_REG_X9,
|
|
RISCV_REG_X10,
|
|
RISCV_REG_X11,
|
|
RISCV_REG_X12,
|
|
RISCV_REG_X13,
|
|
RISCV_REG_X14,
|
|
RISCV_REG_X15,
|
|
RISCV_REG_X16,
|
|
RISCV_REG_X17,
|
|
RISCV_REG_X18,
|
|
RISCV_REG_X19,
|
|
RISCV_REG_X20,
|
|
RISCV_REG_X21,
|
|
RISCV_REG_X22,
|
|
RISCV_REG_X23,
|
|
RISCV_REG_X24,
|
|
RISCV_REG_X25,
|
|
RISCV_REG_X26,
|
|
RISCV_REG_X27,
|
|
RISCV_REG_X28,
|
|
RISCV_REG_X29,
|
|
RISCV_REG_X30,
|
|
RISCV_REG_X31,
|
|
|
|
RISCV_REG_F0_32,
|
|
RISCV_REG_F0_64,
|
|
RISCV_REG_F1_32,
|
|
RISCV_REG_F1_64,
|
|
RISCV_REG_F2_32,
|
|
RISCV_REG_F2_64,
|
|
RISCV_REG_F3_32,
|
|
RISCV_REG_F3_64,
|
|
RISCV_REG_F4_32,
|
|
RISCV_REG_F4_64,
|
|
RISCV_REG_F5_32,
|
|
RISCV_REG_F5_64,
|
|
RISCV_REG_F6_32,
|
|
RISCV_REG_F6_64,
|
|
RISCV_REG_F7_32,
|
|
RISCV_REG_F7_64,
|
|
RISCV_REG_F8_32,
|
|
RISCV_REG_F8_64,
|
|
RISCV_REG_F9_32,
|
|
RISCV_REG_F9_64,
|
|
RISCV_REG_F10_32,
|
|
RISCV_REG_F10_64,
|
|
RISCV_REG_F11_32,
|
|
RISCV_REG_F11_64,
|
|
RISCV_REG_F12_32,
|
|
RISCV_REG_F12_64,
|
|
RISCV_REG_F13_32,
|
|
RISCV_REG_F13_64,
|
|
RISCV_REG_F14_32,
|
|
RISCV_REG_F14_64,
|
|
RISCV_REG_F15_32,
|
|
RISCV_REG_F15_64,
|
|
RISCV_REG_F16_32,
|
|
RISCV_REG_F16_64,
|
|
RISCV_REG_F17_32,
|
|
RISCV_REG_F17_64,
|
|
RISCV_REG_F18_32,
|
|
RISCV_REG_F18_64,
|
|
RISCV_REG_F19_32,
|
|
RISCV_REG_F19_64,
|
|
RISCV_REG_F20_32,
|
|
RISCV_REG_F20_64,
|
|
RISCV_REG_F21_32,
|
|
RISCV_REG_F21_64,
|
|
RISCV_REG_F22_32,
|
|
RISCV_REG_F22_64,
|
|
RISCV_REG_F23_32,
|
|
RISCV_REG_F23_64,
|
|
RISCV_REG_F24_32,
|
|
RISCV_REG_F24_64,
|
|
RISCV_REG_F25_32,
|
|
RISCV_REG_F25_64,
|
|
RISCV_REG_F26_32,
|
|
RISCV_REG_F26_64,
|
|
RISCV_REG_F27_32,
|
|
RISCV_REG_F27_64,
|
|
RISCV_REG_F28_32,
|
|
RISCV_REG_F28_64,
|
|
RISCV_REG_F29_32,
|
|
RISCV_REG_F29_64,
|
|
RISCV_REG_F30_32,
|
|
RISCV_REG_F30_64,
|
|
RISCV_REG_F31_32,
|
|
RISCV_REG_F31_64,
|
|
};
|
|
|
|
if (r < ARR_SIZE(map))
|
|
return map[r];
|
|
|
|
// cannot find this register
|
|
return 0;
|
|
}
|
|
|
|
#endif
|