Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 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;
}
Comment thread
Rot127 marked this conversation as resolved.

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));
Comment thread
moste00 marked this conversation as resolved.
Outdated
}

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