capstone
/
MCInstPrinter.c
257 строк · 7.7 Кб
1/* Capstone Disassembly Engine */
2/* By Rot127 <unisono@quyllur.org>, 2023 */
3
4#include "MCInstPrinter.h"5#include "cs_priv.h"6#include <capstone/platform.h>7
8extern bool ARM_getFeatureBits(unsigned int mode, unsigned int feature);9extern bool PPC_getFeatureBits(unsigned int mode, unsigned int feature);10extern bool AArch64_getFeatureBits(unsigned int mode, unsigned int feature);11extern bool TriCore_getFeatureBits(unsigned int mode, unsigned int feature);12
13static bool testFeatureBits(const MCInst *MI, uint32_t Value)14{
15assert(MI && MI->csh);16switch (MI->csh->arch) {17default:18assert(0 && "Not implemented for current arch.");19return false;20#ifdef CAPSTONE_HAS_ARM21case CS_ARCH_ARM:22return ARM_getFeatureBits(MI->csh->mode, Value);23#endif24#ifdef CAPSTONE_HAS_POWERPC25case CS_ARCH_PPC:26return PPC_getFeatureBits(MI->csh->mode, Value);27#endif28#ifdef CAPSTONE_HAS_AARCH6429case CS_ARCH_AARCH64:30return AArch64_getFeatureBits(MI->csh->mode, Value);31#endif32#ifdef CAPSTONE_HAS_TRICORE33case CS_ARCH_TRICORE:34return TriCore_getFeatureBits(MI->csh->mode, Value);35#endif36}37}
38
39static bool matchAliasCondition(MCInst *MI, const MCRegisterInfo *MRI,40unsigned *OpIdx, const AliasMatchingData *M,41const AliasPatternCond *C,42bool *OrPredicateResult)43{
44// Feature tests are special, they don't consume operands.45if (C->Kind == AliasPatternCond_K_Feature)46return testFeatureBits(MI, C->Value);47if (C->Kind == AliasPatternCond_K_NegFeature)48return !testFeatureBits(MI, C->Value);49// For feature tests where just one feature is required in a list, set the50// predicate result bit to whether the expression will return true, and only51// return the real result at the end of list marker.52if (C->Kind == AliasPatternCond_K_OrFeature) {53*OrPredicateResult |= testFeatureBits(MI, C->Value);54return true;55}56if (C->Kind == AliasPatternCond_K_OrNegFeature) {57*OrPredicateResult |= !(testFeatureBits(MI, C->Value));58return true;59}60if (C->Kind == AliasPatternCond_K_EndOrFeatures) {61bool Res = *OrPredicateResult;62*OrPredicateResult = false;63return Res;64}65
66// Get and consume an operand.67MCOperand *Opnd = MCInst_getOperand(MI, *OpIdx);68++(*OpIdx);69
70// Check the specific condition for the operand.71switch (C->Kind) {72default:73assert(0 && "invalid kind");74case AliasPatternCond_K_Imm:75// Operand must be a specific immediate.76return MCOperand_isImm(Opnd) &&77MCOperand_getImm(Opnd) == (int32_t)C->Value;78case AliasPatternCond_K_Reg:79// Operand must be a specific register.80return MCOperand_isReg(Opnd) && MCOperand_getReg(Opnd) == C->Value;81case AliasPatternCond_K_TiedReg:82// Operand must match the register of another operand.83return MCOperand_isReg(Opnd) &&84MCOperand_getReg(Opnd) ==85MCOperand_getReg(MCInst_getOperand(MI, C->Value));86case AliasPatternCond_K_RegClass:87// Operand must be a register in this class. Value is a register class88// id.89return MCOperand_isReg(Opnd) &&90MCRegisterClass_contains(91MCRegisterInfo_getRegClass(MRI, C->Value),92MCOperand_getReg(Opnd));93case AliasPatternCond_K_Custom:94// Operand must match some custom criteria.95assert(M->ValidateMCOperand && "A custom validator should be set but isn't.");96return M->ValidateMCOperand(Opnd, C->Value);97case AliasPatternCond_K_Ignore:98// Operand can be anything.99return true;100case AliasPatternCond_K_Feature:101case AliasPatternCond_K_NegFeature:102case AliasPatternCond_K_OrFeature:103case AliasPatternCond_K_OrNegFeature:104case AliasPatternCond_K_EndOrFeatures:105assert(0 && "handled earlier");106}107return false;108}
109
110/// Check if PatternsForOpcode is all zero.
111static inline bool validOpToPatter(const PatternsForOpcode *P)112{
113return !(P->Opcode == 0 && P->PatternStart == 0 && P->NumPatterns == 0);114}
115
116const char *matchAliasPatterns(MCInst *MI, const AliasMatchingData *M)117{
118// TODO Rewrite to C119
120// auto It = lower_bound(M.OpToPatterns, MI->getOpcode(),121// [](const PatternsForOpcode &L, unsigned Opcode) {122// return L.Opcode < Opcode;123// });124// if (It == M.OpToPatterns.end() || It->Opcode != MI->getOpcode())125// return nullptr;126
127// Binary search by opcode. Return false if there are no aliases for this128// opcode.129unsigned MIOpcode = MI->Opcode;130size_t i = 0;131uint32_t PatternOpcode = M->OpToPatterns[i].Opcode;132while (PatternOpcode < MIOpcode && validOpToPatter(&M->OpToPatterns[i]))133PatternOpcode = M->OpToPatterns[++i].Opcode;134if (PatternOpcode != MI->Opcode || !validOpToPatter(&M->OpToPatterns[i]))135return NULL;136
137// // Try all patterns for this opcode.138uint32_t AsmStrOffset = ~0U;139const AliasPattern *Patterns = M->Patterns + M->OpToPatterns[i].PatternStart;140for (const AliasPattern *P = Patterns;141P != Patterns + M->OpToPatterns[i].NumPatterns; ++P) {142// Check operand count first.143if (MCInst_getNumOperands(MI) != P->NumOperands)144return NULL;145
146// Test all conditions for this pattern.147const AliasPatternCond *Conds = M->PatternConds + P->AliasCondStart;148unsigned OpIdx = 0;149bool OrPredicateResult = false;150bool allMatch = true;151for (const AliasPatternCond *C = Conds; C != Conds + P->NumConds; ++C) {152if (!matchAliasCondition(MI, MI->MRI, &OpIdx, M, C, &OrPredicateResult)) {153allMatch = false;154break;155}156}157if (allMatch) {158AsmStrOffset = P->AsmStrOffset;159break;160}161}162// If no alias matched, don't print an alias.163if (AsmStrOffset == ~0U)164return NULL;165
166// Go to offset AsmStrOffset and use the null terminated string there. The167// offset should point to the beginning of an alias string, so it should168// either be zero or be preceded by a null byte.169return M->AsmStrings + AsmStrOffset;170}
171
172// TODO Add functionality to toggle the flag.
173bool getUseMarkup(void) { return false; }174
175/// Utility functions to make adding mark ups simpler.
176const char *markup(const char *s)177{
178static const char *no_markup = "";179if (getUseMarkup())180return s;181else182return no_markup;183}
184
185// binary search for encoding in IndexType array
186// return -1 if not found, or index if found
187unsigned int binsearch_IndexTypeEncoding(const struct IndexType *index, size_t size, uint16_t encoding)188{
189// binary searching since the index is sorted in encoding order190size_t left, right, m;191
192right = size - 1;193
194if (encoding < index[0].encoding || encoding > index[right].encoding)195// not found196return -1;197
198left = 0;199
200while(left <= right) {201m = (left + right) / 2;202if (encoding == index[m].encoding) {203// LLVM actually uses lower_bound for the index table search204// Here we need to check if a previous entry is of the same encoding205// and return the first one.206while (m > 0 && encoding == index[m - 1].encoding)207--m;208return m;209}210
211if (encoding < index[m].encoding)212right = m - 1;213else214left = m + 1;215}216
217// not found218return -1;219}
220
221// binary search for encoding in IndexTypeStr array
222// return -1 if not found, or index if found
223unsigned int binsearch_IndexTypeStrEncoding(const struct IndexTypeStr *index, size_t size, const char *name)224{
225// binary searching since the index is sorted in encoding order226size_t left, right, m;227
228right = size - 1;229
230size_t str_left_cmp = strcmp(name, index[0].name);231size_t str_right_cmp = strcmp(name, index[right].name);232if (str_left_cmp < 0 || str_right_cmp > 0)233// not found234return -1;235
236left = 0;237
238while(left <= right) {239m = (left + right) / 2;240if (strcmp(name, index[m].name) == 0) {241// LLVM actually uses lower_bound for the index table search242// Here we need to check if a previous entry is of the same encoding243// and return the first one.244while (m > 0 && (strcmp(name, index[m - 1].name) == 0))245--m;246return m;247}248
249if (strcmp(name, index[m].name) < 0)250right = m - 1;251else252left = m + 1;253}254
255// not found256return -1;257}
258