Skip to content
Open
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_UNCOMPRESSED_REAL);
}

/// Sets the setDetailOps flag to @p Val.
Expand Down
140 changes: 103 additions & 37 deletions arch/RISCV/RISCVInstPrinter.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
//
//===----------------------------------------------------------------------===//

#include <capstone/capstone.h>
#include <capstone/platform.h>
#include "../../MathExtras.h"

Expand Down Expand Up @@ -68,6 +69,38 @@ static inline void printOperand(MCInst *MI, unsigned OpNo, SStream *O);
// member.
static bool ArchRegNames;

static bool isRealSyntax(const MCInst *MI)
{
return MI->csh->syntax & CS_OPT_SYNTAX_REAL;
}

static bool isUncompressedRealSyntax(const MCInst *MI)
{
return MI->csh->syntax & CS_OPT_SYNTAX_UNCOMPRESSED_REAL;
}

static bool isAliasSyntax(const MCInst *MI)
{
return MI->csh->syntax & CS_OPT_SYNTAX_ALIAS;
}

static bool isRealDetail(const MCInst *MI)
{
return MI->csh->detail_opt & CS_OPT_DETAIL_REAL;
}

static bool isUncompressedRealDetail(const MCInst *MI)
{
return detail_is_set(MI) &&
!(MI->csh->detail_opt &
(CS_OPT_DETAIL_REAL | CS_OPT_DETAIL_ALIAS));
}

static bool isAliasDetail(const MCInst *MI)
{
return MI->csh->detail_opt & CS_OPT_DETAIL_ALIAS;
}

const char *doGetRegisterName(MCRegister Reg)
{
return getRegisterName(Reg, ArchRegNames ? RISCV_NoRegAltName :
Expand Down Expand Up @@ -166,7 +199,7 @@ void printFRMArg(MCInst *MI, unsigned OpNo, SStream *O)
{
RISCV_add_cs_detail_0(MI, RISCV_OP_GROUP_FRMArg, OpNo);
unsigned FRMArg = MCOperand_getImm(MCInst_getOperand(MI, (OpNo)));
if (!(MI->csh->syntax & CS_OPT_SYNTAX_NO_ALIAS_TEXT) &&
if (!isRealSyntax(MI) && !isUncompressedRealSyntax(MI) &&
FRMArg == RISCVFPRndMode_DYN)
return;
SStream_concat(O, "%s", ", ");
Expand Down Expand Up @@ -377,52 +410,85 @@ void RISCV_LLVM_printInstruction(MCInst *MI, SStream *O,
bool usesAliasDetails = map_use_alias_details(MI);
MI->flat_insn->usesAliasDetails = usesAliasDetails;

/* check for a non-compressed instruction */
MCInst Uncompressed;
MCInst_Init(&Uncompressed, MI->csh->arch);

MCInst *McInstr = MI;
MCInst *MIUncompressed = MI;
bool is_uncompressed = false;
// side-effectful check for compressed instructions that creates the equivalent uncompressed instruction in case of true
// (LLVM doesn't generate an API for doing a pure check)
if (uncompressInst(&Uncompressed, MI)) {
McInstr = &Uncompressed;
Uncompressed.address = MI->address;
Uncompressed.MRI = MI->MRI;
Uncompressed.csh = MI->csh;
Uncompressed.flat_insn = MI->flat_insn;
is_uncompressed = true;

bool textReal = isRealSyntax(MI);
bool detailReal = isRealDetail(MI);

if (!textReal || (detail_is_set(MI) && !detailReal)) {
// Side-effectful check for compressed instructions that also creates the equivalent
// uncompressed instruction in case of returning true
// False means no side effect happened
// (LLVM doesn't have an API for doing a pure check)
if (uncompressInst(&Uncompressed, MI)) {
MIUncompressed = &Uncompressed;
Uncompressed.address = MI->address;
Uncompressed.MRI = MI->MRI;
Uncompressed.csh = MI->csh;
Uncompressed.flat_insn = MI->flat_insn;
is_uncompressed = true;
}
}

// 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 (print_exact_text) {
if (isRealSyntax(MI)) {
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
if (isUncompressedRealSyntax(MI)) {
printInstruction(MIUncompressed, MIUncompressed->address, O);
} else {
// Side-effectful check for alias instructions that prints to the SStream if it returns true
// False means no printing to stream happened
if (printAliasInstr(MI, MI->address, O)) {
MCInst_setIsAlias(MI, true);
} else { // the instruction is not an alias
if (!is_uncompressed) {
printInstruction(MI, MI->address, O);
} else if (printAliasInstr(MIUncompressed,
MIUncompressed->address,
O)) {
MCInst_setIsAlias(MI, true);
} else {
printInstruction(MIUncompressed,
MIUncompressed->address, O);
}
}
}
}

bool textAndDetailModesMatch = (isRealSyntax(MI) && isRealDetail(MI)) ||
(isUncompressedRealSyntax(MI) &&
isUncompressedRealDetail(MI)) ||
(isAliasSyntax(MI) && isAliasDetail(MI));

if (detail_is_set(MI) && !textAndDetailModesMatch) {
SStream_Close(O);
// discard the text 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 requested details
// including the whole operands array
if (isRealDetail(MI)) {
printInstruction(MI, MI->address, O);
} else if (isUncompressedRealDetail(MI)) {
printInstruction(MIUncompressed, MIUncompressed->address, O);
} else if (!printAliasInstr(MI, MI->address, O)) {
if (!is_uncompressed) {
printInstruction(MI, MI->address, O);
// re-open the stream to restore the usual state
SStream_Open(O);
} else if (!printAliasInstr(MIUncompressed, MIUncompressed->address,
O)) {
printInstruction(MIUncompressed, MIUncompressed->address, O);
}
} else // the instruction is not an alias
printInstruction(McInstr, MI->address, O);
}
Comment thread
moste00 marked this conversation as resolved.

// re-open the stream to restore the usual state
SStream_Open(O);
}

RISCV_add_groups(MI);
RISCV_compact_operands(MI);
RISCV_set_alias_id(MI, O);
Expand Down
26 changes: 19 additions & 7 deletions bindings/python/capstone/__init__.py
Comment thread
Rot127 marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -230,11 +230,14 @@
"CS_OPT_SYNTAX_MOTOROLA",
"CS_OPT_SYNTAX_CS_REG_ALIAS",
"CS_OPT_SYNTAX_NO_DOLLAR",
"CS_OPT_SYNTAX_NO_ALIAS_TEXT",
"CS_OPT_SYNTAX_NO_ALIAS_TEXT_COMPRESSED",
"CS_OPT_SYNTAX_REAL",
"CS_OPT_SYNTAX_UNCOMPRESSED_REAL",
"CS_OPT_SYNTAX_AARCH64_EXPLICIT_WIDE_IMM",
"CS_OPT_SYNTAX_ALIAS",
"CS_OPT_DETAIL",
"CS_OPT_DETAIL_REAL",
"CS_OPT_DETAIL_UNCOMPRESSED_REAL",
"CS_OPT_DETAIL_ALIAS",
"CS_OPT_MODE",
"CS_OPT_ON",
"CS_OPT_OFF",
Expand Down Expand Up @@ -651,18 +654,27 @@
CS_OPT_SYNTAX_NO_DOLLAR = (
1 << 9
) # Does not print the $ in front of Mips, LoongArch registers.
CS_OPT_SYNTAX_NO_ALIAS_TEXT = (
CS_OPT_SYNTAX_REAL = (
1 << 10
) # Does not print an instruction's alias test if the instruction is an alias
CS_OPT_SYNTAX_NO_ALIAS_TEXT_COMPRESSED = (
) # Prints the original decoded instruction without aliases or uncompression.
CS_OPT_SYNTAX_UNCOMPRESSED_REAL = (
1 << 11
) # Like the one above it, but only supresses compressed instruction aliases
) # Prints the uncompressed real instruction when possible, without aliases.
CS_OPT_SYNTAX_AARCH64_EXPLICIT_WIDE_IMM = (
1 << 12
) # Prints shifted AArch64 MOVN and MOVZ instructions without MOV aliases
CS_OPT_SYNTAX_ALIAS = (
1 << 13
) # Prints aliases when available.
CS_OPT_DETAIL_REAL = (
1 << 1
) # If enabled, always sets the real instruction detail.Even if the instruction is an alias.
) # If enabled, always sets the real instruction detail. Even if the instruction is an alias.
CS_OPT_DETAIL_UNCOMPRESSED_REAL = (
1 << 2
) # If enabled, sets uncompressed real instruction detail when possible.
CS_OPT_DETAIL_ALIAS = (
1 << 3
) # If enabled, sets alias instruction detail when possible.

# Capstone error type
CS_ERR_OK = 0 # No error: everything was fine
Expand Down
20 changes: 16 additions & 4 deletions bindings/python/cstest_py/src/cstest_py/cs_modes.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@
"type": cs.CS_OPT_DETAIL,
"val": cs.CS_OPT_DETAIL_REAL | cs.CS_OPT_ON,
},
"CS_OPT_DETAIL_UNCOMPRESSED_REAL": {
"type": cs.CS_OPT_DETAIL,
"val": cs.CS_OPT_DETAIL_UNCOMPRESSED_REAL | cs.CS_OPT_ON,
},
"CS_OPT_DETAIL_ALIAS": {
"type": cs.CS_OPT_DETAIL,
"val": cs.CS_OPT_DETAIL_ALIAS | cs.CS_OPT_ON,
},
"CS_OPT_SKIPDATA": {"type": cs.CS_OPT_SKIPDATA, "val": cs.CS_OPT_ON},
"CS_OPT_UNSIGNED": {"type": cs.CS_OPT_UNSIGNED, "val": cs.CS_OPT_ON},
"CS_OPT_ONLY_OFFSET_BRANCH": {
Expand Down Expand Up @@ -42,13 +50,17 @@
"type": cs.CS_OPT_SYNTAX,
"val": cs.CS_OPT_SYNTAX_NO_DOLLAR,
},
"CS_OPT_SYNTAX_NO_ALIAS_TEXT": {
"CS_OPT_SYNTAX_REAL": {
"type": cs.CS_OPT_SYNTAX,
"val": cs.CS_OPT_SYNTAX_REAL
},
"CS_OPT_SYNTAX_UNCOMPRESSED_REAL": {
"type": cs.CS_OPT_SYNTAX,
"val": cs.CS_OPT_SYNTAX_NO_ALIAS_TEXT
"val": cs.CS_OPT_SYNTAX_UNCOMPRESSED_REAL
},
"CS_OPT_SYNTAX_NO_ALIAS_TEXT_COMPRESSED": {
"CS_OPT_SYNTAX_ALIAS": {
"type": cs.CS_OPT_SYNTAX,
"val": cs.CS_OPT_SYNTAX_NO_ALIAS_TEXT_COMPRESSED
"val": cs.CS_OPT_SYNTAX_ALIAS
},
"CS_OPT_SYNTAX_AARCH64_EXPLICIT_WIDE_IMM": {
"type": cs.CS_OPT_SYNTAX,
Expand Down
7 changes: 7 additions & 0 deletions bindings/python/tests/test_riscv_reg_access.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@
import unittest

class TestRiscvRegAccess(unittest.TestCase):
def test_riscv_syntax_detail_constants(self):
self.assertEqual(CS_OPT_SYNTAX_REAL, 1 << 10)
self.assertEqual(CS_OPT_SYNTAX_UNCOMPRESSED_REAL, 1 << 11)
self.assertEqual(CS_OPT_SYNTAX_ALIAS, 1 << 13)
self.assertEqual(CS_OPT_DETAIL_UNCOMPRESSED_REAL, 1 << 2)
self.assertEqual(CS_OPT_DETAIL_ALIAS, 1 << 3)

def setUp(self):
self.cs = Cs(CS_ARCH_RISCV, CS_MODE_RISCV64)
self.cs.option(CS_OPT_DETAIL, CS_OPT_DETAIL_REAL | CS_OPT_ON)
Expand Down
47 changes: 36 additions & 11 deletions cstool/cstool.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ static struct {
cs_arch archs[CS_ARCH_MAX];
cs_opt_value opt;
cs_mode mode;
cs_opt_type opt_type;
} all_opts[] = {
// cs_opt_value only
{ "+att",
Expand Down Expand Up @@ -64,18 +65,39 @@ static struct {
{ CS_ARCH_LOONGARCH, CS_ARCH_MIPS, CS_ARCH_MAX },
CS_OPT_SYNTAX_NO_DOLLAR,
0 },
{ "+noalias",
"Does not print the text alias of an alias instruction",
{ "+real-text",
"Prints the original decoded instruction without aliases or uncompression",
{ CS_ARCH_RISCV, CS_ARCH_MAX },
CS_OPT_SYNTAX_NO_ALIAS_TEXT,
CS_OPT_SYNTAX_REAL,
0 },
{ "+noaliascompressed",
"Does not print the text alias of compressed RISC-V instructions, "
"but still prints the text alias of non-compressed RISC-V instructions "
"if +noalias is not given",
{ "+uncompressed-text",
"Prints the uncompressed real instruction when possible, without aliases",
{ CS_ARCH_RISCV, CS_ARCH_MAX },
CS_OPT_SYNTAX_NO_ALIAS_TEXT_COMPRESSED,
CS_OPT_SYNTAX_UNCOMPRESSED_REAL,
0 },
{ "+alias-text",
"Prints aliases when available (default RISC-V text mode)",
{ CS_ARCH_RISCV, CS_ARCH_MAX },
CS_OPT_SYNTAX_ALIAS,
0 },
{ "+real-details",
"Fills RISC-V details from the original decoded instruction",
{ CS_ARCH_RISCV, CS_ARCH_MAX },
CS_OPT_DETAIL_REAL | CS_OPT_ON,
0,
CS_OPT_DETAIL },
{ "+uncompressed-details",
"Fills RISC-V details from the uncompressed real instruction when possible",
{ CS_ARCH_RISCV, CS_ARCH_MAX },
CS_OPT_DETAIL_UNCOMPRESSED_REAL | CS_OPT_ON,
0,
CS_OPT_DETAIL },
{ "+alias-details",
"Fills RISC-V details from aliases when available (default with -d)",
{ CS_ARCH_RISCV, CS_ARCH_MAX },
CS_OPT_DETAIL_ALIAS | CS_OPT_ON,
0,
CS_OPT_DETAIL },
{ "+explicitwideimm",
"Prints shifted MOVN and MOVZ instructions without MOV aliases",
{ CS_ARCH_AARCH64, CS_ARCH_MAX },
Expand Down Expand Up @@ -708,7 +730,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 uncompressed real instructions when possible\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 Down Expand Up @@ -893,7 +915,9 @@ static void enable_additional_options(csh handle, const char *input,
}
for (j = 0; j < CS_ARCH_MAX; j++) {
if (arch == all_opts[i].archs[j]) {
cs_option(handle, CS_OPT_SYNTAX,
cs_option(handle,
all_opts[i].opt_type ? all_opts[i].opt_type :
CS_OPT_SYNTAX,
all_opts[i].opt);
break;
}
Expand Down Expand Up @@ -927,6 +951,7 @@ int main(int argc, char **argv)
break;
case 'r':
set_real_detail = true;
detail_flag = true;
break;
case 's':
skipdata = true;
Expand Down Expand Up @@ -1139,7 +1164,7 @@ int main(int argc, char **argv)

if (set_real_detail) {
cs_option(handle, CS_OPT_DETAIL,
(CS_OPT_DETAIL_REAL | CS_OPT_ON));
(CS_OPT_DETAIL_UNCOMPRESSED_REAL | CS_OPT_ON));
}

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