Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Mapping.c
Original file line number Diff line number Diff line change
Expand Up @@ -414,7 +414,8 @@ bool map_use_alias_details(const MCInst *MI)
{
assert(MI);
return (MI->csh->detail_opt & CS_OPT_ON) &&
!(MI->csh->detail_opt & CS_OPT_DETAIL_REAL);
!(MI->csh->detail_opt & CS_OPT_DETAIL_REAL) &&
!(MI->csh->detail_opt & CS_OPT_DETAIL_ALIAS_REAL);
}

/// Sets the setDetailOps flag to @p Val.
Expand Down
49 changes: 33 additions & 16 deletions arch/RISCV/RISCVInstPrinter.c
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,7 @@ void RISCV_LLVM_printInstruction(MCInst *MI, SStream *O,
MI->MRI = (MCRegisterInfo *)info;

MCInst_setIsAlias(MI, false);
MI->flat_insn->uncompressed_id = 0;
bool usesAliasDetails = map_use_alias_details(MI);
MI->flat_insn->usesAliasDetails = usesAliasDetails;

Expand All @@ -392,40 +393,56 @@ void RISCV_LLVM_printInstruction(MCInst *MI, SStream *O,
Uncompressed.csh = MI->csh;
Uncompressed.flat_insn = MI->flat_insn;
is_uncompressed = true;
const insn_map *umap = lookup_insn_map(MI->csh,
MCInst_getOpcode(&Uncompressed));
if (umap)
MI->flat_insn->uncompressed_id = umap->mapid;
}

// print the exact instruction text and done
bool print_exact_text =
(MI->csh->syntax & CS_OPT_SYNTAX_NO_ALIAS_TEXT) ||
(is_uncompressed &&
MI->csh->syntax & CS_OPT_SYNTAX_NO_ALIAS_TEXT_COMPRESSED);

// if alias suppression is on, print the original instruction no matter what
if (print_exact_text) {
printInstruction(MI, MI->address, O);
} else {
// side-effectful check for alias instructions that prints to the SStream if true
if (printAliasInstr(McInstr, MI->address, O)) {
MCInst_setIsAlias(MI, true);
// do we still want the exact details even if the text is alias ?
if (!usesAliasDetails && detail_is_set(MI)) {
// disable actual printing
SStream_Close(O);
// discard the alias operands
memset(MI->flat_insn->detail->riscv.operands, 0,
sizeof(MI->flat_insn->detail->riscv
.operands));
MI->flat_insn->detail->riscv.op_count = 0;
// re-disassemble again with no printing in order to obtain the full details
// including the whole operands array
printInstruction(MI, MI->address, O);
// re-open the stream to restore the usual state
SStream_Open(O);
}
} else // the instruction is not an alias
} else {
printInstruction(McInstr, MI->address, O);
}
}

bool real = MI->csh->detail_opt & CS_OPT_DETAIL_REAL;
// CS_OPT_DETAIL_REAL takes priority: if enabled, then real details for both aliases and compressed instructions
// CS_OPT_DETAIL_ALIAS_REAL applies when CS_OPT_DETAIL_REAL is absent: real details for aliases only
bool replaceWithRealDetails = real ? (MCInst_isAlias(MI) || is_uncompressed) : MCInst_isAlias(MI);

// do we still want the exact details (regardless of if the text is alias or not) ?
if (replaceWithRealDetails && !usesAliasDetails && detail_is_set(MI)) {
// disable actual printing
SStream_Close(O);
// discard the alias operands
memset(MI->flat_insn->detail->riscv.operands, 0,
sizeof(MI->flat_insn->detail->riscv.operands));
MI->flat_insn->detail->riscv.op_count = 0;
// re-disassemble again with no printing in order to obtain the full details
// including the whole operands array
printInstruction(McInstr, MI->address, O);
// re-open the stream to restore the usual state
SStream_Open(O);
}
RISCV_add_groups(MI);

// HACKS (TODO: INVESTIGATE later)
RISCV_add_missing_write_access(MI);
RISCV_compact_operands(MI);
// END HACKS

RISCV_set_alias_id(MI, O);
}

Expand Down
18 changes: 16 additions & 2 deletions arch/RISCV/RISCVMapping.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "RISCVGenRegisterInfo.inc"

#include "RISCVInstPrinter.h"
#include "RISCVBaseInfo.h"

const char *RISCV_reg_name(csh handle, unsigned int reg)
{
Expand Down Expand Up @@ -53,10 +54,23 @@ void RISCV_add_cs_detail_0(MCInst *MI, riscv_op_group opgroup, unsigned OpNum)
{
if (!detail_is_set(MI))
return;
// are not "true" arguments and has no Capstone equivalent
// rounding mode: store in detail, not as a regular operand
if (opgroup == RISCV_OP_GROUP_FRMArg ||
opgroup == RISCV_OP_GROUP_FRMArgLegacy)
opgroup == RISCV_OP_GROUP_FRMArgLegacy) {
unsigned frm = (unsigned)MCInst_getOperand(MI, OpNum)->ImmVal;
riscv_rounding_mode rm;
switch (frm) {
case RISCVFPRndMode_RNE: rm = RISCV_RM_RNE; break;
case RISCVFPRndMode_RTZ: rm = RISCV_RM_RTZ; break;
case RISCVFPRndMode_RDN: rm = RISCV_RM_RDN; break;
case RISCVFPRndMode_RUP: rm = RISCV_RM_RUP; break;
case RISCVFPRndMode_RMM: rm = RISCV_RM_RMM; break;
case RISCVFPRndMode_DYN: rm = RISCV_RM_DYN; break;
default: rm = RISCV_RM_INVALID; break;
}
RISCV_get_detail(MI)->rounding_mode = rm;
return;
}

if (opgroup == RISCV_OP_GROUP_FPImmOperand) {
unsigned Imm = (unsigned)MCInst_getOperand(MI, OpNum)->ImmVal;
Expand Down
18 changes: 16 additions & 2 deletions cstool/cstool.c
Original file line number Diff line number Diff line change
Expand Up @@ -643,7 +643,7 @@ static void usage(char *prog)
int i, j;
printf("Cstool for Capstone Disassembler Engine v%u.%u.%u\n\n",
CS_VERSION_MAJOR, CS_VERSION_MINOR, CS_VERSION_EXTRA);
printf("Syntax: %s [-d|-a|-r|-s|-u|-v] <arch+opts> <assembly-hexstring> [start-address-in-hex-format]\n",
printf("Syntax: %s [-d|-a|-r|-R|-s|-u|-v] <arch+opts> <assembly-hexstring> [start-address-in-hex-format]\n",
prog);
printf("\nThe following <arch+opts> options are supported:\n");

Expand Down Expand Up @@ -676,6 +676,7 @@ static void usage(char *prog)
printf("\nExtra options:\n");
printf(" -d show detailed information of the instructions\n");
printf(" -r show detailed information of the real instructions (even for alias)\n");
printf(" -R show detailed information of the real instructions for aliases only (not for compressed)\n");
printf(" -a Print Capstone register alias (if any). Otherwise LLVM register names are emitted.\n");
printf(" -s decode in SKIPDATA mode\n");
printf(" -u show immediates as unsigned\n");
Expand All @@ -691,6 +692,10 @@ static void print_details(csh handle, cs_arch arch, cs_mode md, cs_insn *ins)
printf("with %s operand set\n",
ins->usesAliasDetails ? "ALIAS" : "REAL");
}
if (ins->uncompressed_id) {
printf("\tUncompressed: %" PRIu64 " (%s)\n", ins->uncompressed_id,
cs_insn_name(handle, ins->uncompressed_id));
}

switch (arch) {
case CS_ARCH_X86:
Expand Down Expand Up @@ -839,16 +844,20 @@ int main(int argc, char **argv)
bool skipdata = false;
bool custom_reg_alias = false;
bool set_real_detail = false;
bool set_alias_real_detail = false;
int args_left;

while ((c = getopt(argc, argv, "rasudhvf")) != -1) {
while ((c = getopt(argc, argv, "rRasudhvf")) != -1) {
switch (c) {
case 'a':
custom_reg_alias = true;
break;
case 'r':
set_real_detail = true;
break;
case 'R':
set_alias_real_detail = true;
break;
case 's':
skipdata = true;
break;
Expand Down Expand Up @@ -1063,6 +1072,11 @@ int main(int argc, char **argv)
(CS_OPT_DETAIL_REAL | CS_OPT_ON));
}

if (set_alias_real_detail) {
cs_option(handle, CS_OPT_DETAIL,
(CS_OPT_DETAIL_ALIAS_REAL | CS_OPT_ON));
}

count = cs_disasm(handle, assembly, size, address, 0, &insn);

if (count > 0) {
Expand Down
9 changes: 9 additions & 0 deletions cstool/cstool_riscv.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,5 +68,14 @@ void print_insn_detail_riscv(csh handle, cs_insn *ins)
}
}

if (riscv->rounding_mode != RISCV_RM_INVALID) {
static const char *const rm_str[] = {
[RISCV_RM_RNE] = "rne", [RISCV_RM_RTZ] = "rtz",
[RISCV_RM_RDN] = "rdn", [RISCV_RM_RUP] = "rup",
[RISCV_RM_RMM] = "rmm", [RISCV_RM_DYN] = "dyn",
};
printf("\trounding_mode: %s\n", rm_str[riscv->rounding_mode]);
}

printf("\n");
}
9 changes: 9 additions & 0 deletions include/capstone/capstone.h
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,9 @@ typedef enum cs_opt_value {
CS_OPT_DETAIL_REAL =
1
<< 1, ///< If enabled, always sets the real instruction detail. Even if the instruction is an alias.
CS_OPT_DETAIL_ALIAS_REAL =
1
<< 2, ///< Like CS_OPT_DETAIL_REAL but only for alias instructions. Compressed instructions that are uncompressed keep alias details.
} cs_opt_value;

/// An option
Expand Down Expand Up @@ -551,6 +554,12 @@ typedef struct cs_insn {
/// -- Only supported by auto-sync archs --
uint64_t alias_id;

/// If this instruction is a compressed instruction (RISCV only),
/// this member is set with the ID of its non-compressed equivalent.
/// Otherwise 0 (i.e. <ARCH>_INS_INVALID).
/// -- Only supported by RISCV --
uint64_t uncompressed_id;

/// Address (EIP) of this instruction
/// This information is available even when CS_OPT_DETAIL = CS_OPT_OFF
uint64_t address;
Expand Down
12 changes: 12 additions & 0 deletions include/capstone/riscv.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,17 @@ extern "C" {
#pragma warning(disable : 4201)
#endif

//> Floating-point rounding mode for RISC-V FP instructions
typedef enum riscv_rounding_mode {
RISCV_RM_INVALID = 0, ///< not applicable (no rounding mode)
RISCV_RM_RNE, ///< round to nearest, ties to even
RISCV_RM_RTZ, ///< round towards zero
RISCV_RM_RDN, ///< round down (towards -infinity)
RISCV_RM_RUP, ///< round up (towards +infinity)
RISCV_RM_RMM, ///< round to nearest, ties to max magnitude
RISCV_RM_DYN, ///< dynamic rounding mode (use frm CSR)
} riscv_rounding_mode;

//> Operand type for instruction's operands
typedef enum riscv_op_type {
RISCV_OP_INVALID = CS_OP_INVALID, ///< = CS_OP_INVALID (Uninitialized).
Expand Down Expand Up @@ -65,6 +76,7 @@ typedef struct cs_riscv {
// or 0 when instruction has no operand.
uint8_t op_count;
cs_riscv_op operands[NUM_RISCV_OPS]; // operands for this instruction.
riscv_rounding_mode rounding_mode; // FP rounding mode, or RISCV_RM_INVALID
} cs_riscv;

//> RISCV registers
Expand Down
3 changes: 3 additions & 0 deletions suite/cstest/include/test_mapping.h
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,9 @@ static const TestOptionMapEntry test_option_map[] = {
{ .str = "CS_OPT_DETAIL_REAL",
.opt = { .type = CS_OPT_DETAIL,
.val = CS_OPT_DETAIL_REAL | CS_OPT_ON } },
{ .str = "CS_OPT_DETAIL_ALIAS_REAL",
.opt = { .type = CS_OPT_DETAIL,
.val = CS_OPT_DETAIL_ALIAS_REAL | CS_OPT_ON } },
{ .str = "CS_OPT_SKIPDATA",
.opt = { .type = CS_OPT_SKIPDATA, .val = CS_OPT_ON } },
{ .str = "CS_OPT_UNSIGNED",
Expand Down
80 changes: 79 additions & 1 deletion tests/details/riscv.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6224,4 +6224,82 @@ test_cases:
expected:
insns:
- asm_text: "addi a0, a1, 0"
- asm_text: "c.li a0, 0x15"

# CS_OPT_DETAIL_ALIAS_REAL: alias (mv) gets real details; compressed (c.add) is NOT an alias
# so is_alias stays false and its details are the uncompressed form's operands unchanged.
- input:
bytes: [0x2e, 0x95, 0x13, 0x85, 0x05, 0x00]
arch: "CS_ARCH_RISCV"
options: [CS_MODE_RISCV32, CS_MODE_RISCV_C, CS_OPT_DETAIL_ALIAS_REAL]
address: 0x0
expected:
insns:
- asm_text: "add a0, a0, a1"
is_alias: -1
details:
riscv:
operands:
- type: RISCV_OP_REG
reg: a0
access: CS_AC_WRITE
- type: RISCV_OP_REG
reg: a0
access: CS_AC_READ
- type: RISCV_OP_REG
reg: a1
access: CS_AC_READ
- asm_text: "mv a0, a1"
is_alias: 1
uses_alias_details: -1
details:
riscv:
operands:
- type: RISCV_OP_REG
reg: a0
access: CS_AC_WRITE
- type: RISCV_OP_REG
reg: a1
access: CS_AC_READ
- type: RISCV_OP_IMM
imm: 0x0
access: CS_AC_READ

# Both CS_OPT_DETAIL_REAL and CS_OPT_DETAIL_ALIAS_REAL: CS_OPT_DETAIL_REAL takes priority.
# Compressed (c.add) now also gets real details via re-disassembly (is_uncompressed path).
# Alias (mv) is unchanged — real details in both cases.
- input:
bytes: [0x2e, 0x95, 0x13, 0x85, 0x05, 0x00]
arch: "CS_ARCH_RISCV"
options: [CS_MODE_RISCV32, CS_MODE_RISCV_C, CS_OPT_DETAIL_REAL, CS_OPT_DETAIL_ALIAS_REAL]
address: 0x0
expected:
insns:
- asm_text: "add a0, a0, a1"
is_alias: -1
details:
riscv:
operands:
- type: RISCV_OP_REG
reg: a0
access: CS_AC_WRITE
- type: RISCV_OP_REG
reg: a0
access: CS_AC_READ
- type: RISCV_OP_REG
reg: a1
access: CS_AC_READ
- asm_text: "mv a0, a1"
is_alias: 1
uses_alias_details: -1
details:
riscv:
operands:
- type: RISCV_OP_REG
reg: a0
access: CS_AC_WRITE
- type: RISCV_OP_REG
reg: a1
access: CS_AC_READ
- type: RISCV_OP_IMM
imm: 0x0
access: CS_AC_READ
4 changes: 4 additions & 0 deletions tests/issues/issues.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6334,6 +6334,8 @@ test_cases:
details:
riscv:
operands:
- type: "RISCV_OP_REG"
reg: "sp"
- type: "RISCV_OP_REG"
reg: "sp"
- type: "RISCV_OP_IMM"
Expand All @@ -6354,6 +6356,8 @@ test_cases:
details:
riscv:
operands:
- type: "RISCV_OP_REG"
reg: "sp"
- type: "RISCV_OP_REG"
reg: "sp"
- type: "RISCV_OP_IMM"
Expand Down
Loading