5af28808 Update Auto-Sync to Python 3.13 and tree-sitter-py 24.0 (#2705) 99f018ac Python binding: (#2742) a07baf83 Auto-Sync update Sparc LLVM-18 (#2704) 81c5c93d Enable to generate legacy MC tests for the fuzzer. (#2733) a25d4980 Add warning about naive search and replace to patch reg names. (#2728) 7ac87d17 Print immediate only memory operands for AArch64. (#2732) c34034c8 Add x30 implicit read to the RET alias. (#2739) 95a4ca3e Update source list before installing valgrind. (#2730) 6909724e Make assertion hit warnings optional in release builds. (#2729) fe6bdc6e Make SStream respect the CS_OPT_UNSIGNED flag. (#2723) 21ce3624 Use cs_ac_type for operand access mode in all arches and use cs_xtensa_op_type for Xtensa operand type (#2721) df26583f clang-format: change license to BSD-3-Clause (#2724) 280b749e Remove unused files. (#2709) 87908ece Add flag for the SoftFail case of the LLVM disassembler. (#2707) efc0ba44 Fix missing operand for smstart, due to space replaced by tab (#2720) 2ae64133 Fix missing sp register read in ret instruction (#2719) 8df252a6 Fix arm pop reg access (#2718) 14612272 ARM: fix typo, cspr -> cpsr (#2716) f2f0a3c3 Fix LoongArch ld/st instructions register info (#2701) 829be2bf LoongArch: Compute absolute address for address operand (#2699) 42fbce6c Add jump group for generic jirl (#2698) fc525c73 Apple AArch64 proprietary (#2692) 895f2f2e Build PDB for debugging on Windows (#2685) 5c3aef03 Version: Update to v6.0.0-alpha4 (#2682) 106f7d3b Update read/written registers for x87 comparison instructions (#2680) ebe3ef2a Add workflow for building on Windows (#2675) 72f7d305 Revert "Add a script to compare the inc file content with the latest generate…" (#2678) 5b5c5ed8 Fix nanomips decoding of jalrc (#2672) ae03cca4 Mips32r6_64r632 is for both mips32r6 and mips64r6 (#2673) 21178aea Add a script to compare the inc file content with the latest generated ones. (#2667) 81a6ba03 MIPS: Fix MIPS16 decoding, wrong flags and ghost registers (#2665) 98a393e3 Stringify BH fields when printing ppc details (#2663) 2607d0f3 Remove undefined constants in riscv_const.py (#2660) (#2661) 5058c634 Decode BH field in print_insn_detail_ppc (#2662) 6461ed08 Add Call group to svc, smc and hvc. (#2651) e2f1dc8d Tms32c64x Little Endian (#2648) 5464c91d Fix build for compilers requiring explicit static for inline functions.. (#2645) bb2f6579 Enhance shift value and types of shift instructions. (#2638) cd282ef5 Update operand type enums of all arch modules to the one in `capstone.h` (#2633) dc0c0909 cmake: Fix building capstone as sub-project (#2629) cd8dd20c - Added missing files for sdist archive (#2624) 9affd99b Give the user some guidance where to add missing enumeration values. (#2639) 1bea3fab Add checks for MIPS details on cstest_py (#2640) ace8056c Add aliases mapping for MIPS & test for id, alias_id (#2635) 1abe1868 Build Tarball before DEB/RPM package. (#2627) 0a012190 Switch to ubuntu-24.04-arm runner image (#2625) 4e0b8c48 Fix wrong version requirement of tricore instructions: (#2620) 8ac2843b chore(version): Update Version to 6.0.0-Alpha3 (#2616) d7ef910b Rebased #2570 (#2614) c831cd5e Fix SystemZ macro in Makefile (#2603) 30601176 Apply new EVM opcode updates (#2602) 3c4d7fc8 Add tricore tc1.8 instructions (#2595) 5f290cad Create debian and rpm package on releases (#2590) 0f09210a delete travis (#2600) 5c5f756f Downgrade labeler to v4 due to https://github.com/actions/labeler/issues/710. (#2598) git-subtree-dir: external/capstone git-subtree-split: 5af288083e9f03e32723f9708c305692f866b666
268 lines
8.0 KiB
C
268 lines
8.0 KiB
C
/* Capstone Disassembly Engine */
|
|
/* By Rot127 <unisono@quyllur.org>, 2023 */
|
|
|
|
#include "MCInstPrinter.h"
|
|
#include "cs_priv.h"
|
|
#include <capstone/platform.h>
|
|
|
|
extern bool ARM_getFeatureBits(unsigned int mode, unsigned int feature);
|
|
extern bool PPC_getFeatureBits(unsigned int mode, unsigned int feature);
|
|
extern bool Mips_getFeatureBits(unsigned int mode, unsigned int feature);
|
|
extern bool AArch64_getFeatureBits(unsigned int mode, unsigned int feature);
|
|
extern bool TriCore_getFeatureBits(unsigned int mode, unsigned int feature);
|
|
extern bool Sparc_getFeatureBits(unsigned int mode, unsigned int feature);
|
|
|
|
static bool testFeatureBits(const MCInst *MI, uint32_t Value)
|
|
{
|
|
assert(MI && MI->csh);
|
|
switch (MI->csh->arch) {
|
|
default:
|
|
assert(0 && "Not implemented for current arch.");
|
|
return false;
|
|
#ifdef CAPSTONE_HAS_ARM
|
|
case CS_ARCH_ARM:
|
|
return ARM_getFeatureBits(MI->csh->mode, Value);
|
|
#endif
|
|
#ifdef CAPSTONE_HAS_POWERPC
|
|
case CS_ARCH_PPC:
|
|
return PPC_getFeatureBits(MI->csh->mode, Value);
|
|
#endif
|
|
#ifdef CAPSTONE_HAS_MIPS
|
|
case CS_ARCH_MIPS:
|
|
return Mips_getFeatureBits(MI->csh->mode, Value);
|
|
#endif
|
|
#ifdef CAPSTONE_HAS_AARCH64
|
|
case CS_ARCH_AARCH64:
|
|
return AArch64_getFeatureBits(MI->csh->mode, Value);
|
|
#endif
|
|
#ifdef CAPSTONE_HAS_TRICORE
|
|
case CS_ARCH_TRICORE:
|
|
return TriCore_getFeatureBits(MI->csh->mode, Value);
|
|
#endif
|
|
#ifdef CAPSTONE_HAS_SPARC
|
|
case CS_ARCH_SPARC:
|
|
return Sparc_getFeatureBits(MI->csh->mode, Value);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
static bool matchAliasCondition(MCInst *MI, const MCRegisterInfo *MRI,
|
|
unsigned *OpIdx, const AliasMatchingData *M,
|
|
const AliasPatternCond *C,
|
|
bool *OrPredicateResult)
|
|
{
|
|
// Feature tests are special, they don't consume operands.
|
|
if (C->Kind == AliasPatternCond_K_Feature)
|
|
return testFeatureBits(MI, C->Value);
|
|
if (C->Kind == AliasPatternCond_K_NegFeature)
|
|
return !testFeatureBits(MI, C->Value);
|
|
// For feature tests where just one feature is required in a list, set the
|
|
// predicate result bit to whether the expression will return true, and only
|
|
// return the real result at the end of list marker.
|
|
if (C->Kind == AliasPatternCond_K_OrFeature) {
|
|
*OrPredicateResult |= testFeatureBits(MI, C->Value);
|
|
return true;
|
|
}
|
|
if (C->Kind == AliasPatternCond_K_OrNegFeature) {
|
|
*OrPredicateResult |= !(testFeatureBits(MI, C->Value));
|
|
return true;
|
|
}
|
|
if (C->Kind == AliasPatternCond_K_EndOrFeatures) {
|
|
bool Res = *OrPredicateResult;
|
|
*OrPredicateResult = false;
|
|
return Res;
|
|
}
|
|
|
|
// Get and consume an operand.
|
|
MCOperand *Opnd = MCInst_getOperand(MI, *OpIdx);
|
|
++(*OpIdx);
|
|
|
|
// Check the specific condition for the operand.
|
|
switch (C->Kind) {
|
|
default:
|
|
assert(0 && "invalid kind");
|
|
case AliasPatternCond_K_Imm:
|
|
// Operand must be a specific immediate.
|
|
return MCOperand_isImm(Opnd) &&
|
|
MCOperand_getImm(Opnd) == (int32_t)C->Value;
|
|
case AliasPatternCond_K_Reg:
|
|
// Operand must be a specific register.
|
|
return MCOperand_isReg(Opnd) && MCOperand_getReg(Opnd) == C->Value;
|
|
case AliasPatternCond_K_TiedReg:
|
|
// Operand must match the register of another operand.
|
|
return MCOperand_isReg(Opnd) &&
|
|
MCOperand_getReg(Opnd) ==
|
|
MCOperand_getReg(MCInst_getOperand(MI, C->Value));
|
|
case AliasPatternCond_K_RegClass:
|
|
// Operand must be a register in this class. Value is a register class
|
|
// id.
|
|
return MCOperand_isReg(Opnd) &&
|
|
MCRegisterClass_contains(
|
|
MCRegisterInfo_getRegClass(MRI, C->Value),
|
|
MCOperand_getReg(Opnd));
|
|
case AliasPatternCond_K_Custom:
|
|
// Operand must match some custom criteria.
|
|
assert(M->ValidateMCOperand && "A custom validator should be set but isn't.");
|
|
return M->ValidateMCOperand(Opnd, C->Value);
|
|
case AliasPatternCond_K_Ignore:
|
|
// Operand can be anything.
|
|
return true;
|
|
case AliasPatternCond_K_Feature:
|
|
case AliasPatternCond_K_NegFeature:
|
|
case AliasPatternCond_K_OrFeature:
|
|
case AliasPatternCond_K_OrNegFeature:
|
|
case AliasPatternCond_K_EndOrFeatures:
|
|
assert(0 && "handled earlier");
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/// Check if PatternsForOpcode is all zero.
|
|
static inline bool validOpToPatter(const PatternsForOpcode *P)
|
|
{
|
|
return !(P->Opcode == 0 && P->PatternStart == 0 && P->NumPatterns == 0);
|
|
}
|
|
|
|
const char *matchAliasPatterns(MCInst *MI, const AliasMatchingData *M)
|
|
{
|
|
// TODO Rewrite to C
|
|
|
|
// auto It = lower_bound(M.OpToPatterns, MI->getOpcode(),
|
|
// [](const PatternsForOpcode &L, unsigned Opcode) {
|
|
// return L.Opcode < Opcode;
|
|
// });
|
|
// if (It == M.OpToPatterns.end() || It->Opcode != MI->getOpcode())
|
|
// return nullptr;
|
|
|
|
// Binary search by opcode. Return false if there are no aliases for this
|
|
// opcode.
|
|
unsigned MIOpcode = MI->Opcode;
|
|
size_t i = 0;
|
|
uint32_t PatternOpcode = M->OpToPatterns[i].Opcode;
|
|
while (PatternOpcode < MIOpcode && validOpToPatter(&M->OpToPatterns[i]))
|
|
PatternOpcode = M->OpToPatterns[++i].Opcode;
|
|
if (PatternOpcode != MI->Opcode || !validOpToPatter(&M->OpToPatterns[i]))
|
|
return NULL;
|
|
|
|
// // Try all patterns for this opcode.
|
|
uint32_t AsmStrOffset = ~0U;
|
|
const AliasPattern *Patterns = M->Patterns + M->OpToPatterns[i].PatternStart;
|
|
for (const AliasPattern *P = Patterns;
|
|
P != Patterns + M->OpToPatterns[i].NumPatterns; ++P) {
|
|
// Check operand count first.
|
|
if (MCInst_getNumOperands(MI) != P->NumOperands)
|
|
return NULL;
|
|
|
|
// Test all conditions for this pattern.
|
|
const AliasPatternCond *Conds = M->PatternConds + P->AliasCondStart;
|
|
unsigned OpIdx = 0;
|
|
bool OrPredicateResult = false;
|
|
bool allMatch = true;
|
|
for (const AliasPatternCond *C = Conds; C != Conds + P->NumConds; ++C) {
|
|
if (!matchAliasCondition(MI, MI->MRI, &OpIdx, M, C, &OrPredicateResult)) {
|
|
allMatch = false;
|
|
break;
|
|
}
|
|
}
|
|
if (allMatch) {
|
|
AsmStrOffset = P->AsmStrOffset;
|
|
break;
|
|
}
|
|
}
|
|
// If no alias matched, don't print an alias.
|
|
if (AsmStrOffset == ~0U)
|
|
return NULL;
|
|
|
|
// Go to offset AsmStrOffset and use the null terminated string there. The
|
|
// offset should point to the beginning of an alias string, so it should
|
|
// either be zero or be preceded by a null byte.
|
|
return M->AsmStrings + AsmStrOffset;
|
|
}
|
|
|
|
// TODO Add functionality to toggle the flag.
|
|
bool getUseMarkup(void) { return false; }
|
|
|
|
/// Utility functions to make adding mark ups simpler.
|
|
const char *markup(const char *s)
|
|
{
|
|
static const char *no_markup = "";
|
|
if (getUseMarkup())
|
|
return s;
|
|
else
|
|
return no_markup;
|
|
}
|
|
|
|
// binary search for encoding in IndexType array
|
|
// return -1 if not found, or index if found
|
|
unsigned int binsearch_IndexTypeEncoding(const struct IndexType *index, size_t size, uint16_t encoding)
|
|
{
|
|
// binary searching since the index is sorted in encoding order
|
|
size_t left, right, m;
|
|
|
|
right = size - 1;
|
|
|
|
if (encoding < index[0].encoding || encoding > index[right].encoding)
|
|
// not found
|
|
return -1;
|
|
|
|
left = 0;
|
|
|
|
while(left <= right) {
|
|
m = (left + right) / 2;
|
|
if (encoding == index[m].encoding) {
|
|
// LLVM actually uses lower_bound for the index table search
|
|
// Here we need to check if a previous entry is of the same encoding
|
|
// and return the first one.
|
|
while (m > 0 && encoding == index[m - 1].encoding)
|
|
--m;
|
|
return m;
|
|
}
|
|
|
|
if (encoding < index[m].encoding)
|
|
right = m - 1;
|
|
else
|
|
left = m + 1;
|
|
}
|
|
|
|
// not found
|
|
return -1;
|
|
}
|
|
|
|
// binary search for encoding in IndexTypeStr array
|
|
// return -1 if not found, or index if found
|
|
unsigned int binsearch_IndexTypeStrEncoding(const struct IndexTypeStr *index, size_t size, const char *name)
|
|
{
|
|
// binary searching since the index is sorted in encoding order
|
|
size_t left, right, m;
|
|
|
|
right = size - 1;
|
|
|
|
int str_left_cmp = strcmp(name, index[0].name);
|
|
int str_right_cmp = strcmp(name, index[right].name);
|
|
if (str_left_cmp < 0 || str_right_cmp > 0)
|
|
// not found
|
|
return -1;
|
|
|
|
left = 0;
|
|
|
|
while(left <= right) {
|
|
m = (left + right) / 2;
|
|
if (strcmp(name, index[m].name) == 0) {
|
|
// LLVM actually uses lower_bound for the index table search
|
|
// Here we need to check if a previous entry is of the same encoding
|
|
// and return the first one.
|
|
while (m > 0 && (strcmp(name, index[m - 1].name) == 0))
|
|
--m;
|
|
return m;
|
|
}
|
|
|
|
if (strcmp(name, index[m].name) < 0)
|
|
right = m - 1;
|
|
else
|
|
left = m + 1;
|
|
}
|
|
|
|
// not found
|
|
return -1;
|
|
}
|