capstone/MCInstPrinter.c
Rot127 3a2cd3c331
Coverity defects (#2469)
* Fix CID 508418 - Uninitialized struct

* Fix CID 509089 - Fix OOB read and write

* Fix CID 509088 - OOB.

Also adds tests and to ensure no OOB access.

* Fix CID 509085 - Resource leak.

* Fix CID 508414 and companions - Using undefined values.

* Fix CID 508405 - Use of uninitialized value

* Remove unnecessary and badly implemented dev fuzz code.

* Fix CID 508396 - Uninitialzied variable.

* Fix CID 508393, 508365 -- OOB read.

* Fix CID 432207 - OVerlapping memory access.

* Remove unused functions

* Fix CID 432170 - Overlapping memory access.

* Fix CID 166022 - Check for negative index

* Let strncat not depend n src operand.

* Fix 509083 and 509084 - NULL dereference

* Remove duplicated code.

* Initialize sysop

* Fix resource leak

* Remove unreachable code.

* Remove duplicate code.

* Add assert to check return value of cmoack

* Fixed: d should be a signed value, since it is checked against < 0

* Add missing break.

* Add NULL check

* Fix signs of binary search comparisons.

* Add explicit cast of or result

* Fix correct scope of case.

* Handle invalid integer type.

* Return UINT_MAX instead of implicitly casted -1

* Remove dead code

* Fix type of im

* Fix type of d

* Remove duplicated code.

* Add returns after CS_ASSERTS

* Check for len == 0 case.

* Ensure shift operates on uint64

* Replace strcpy with strncpy.

* Handle edge cases for 32bit rotate

* Fix some out of enum warnings

* Replace a strcpy with strncpy.

* Fix increment of address

* Skip some linting

* Fix: set instruction id

* Remove unused enum

* Replace the last usages of strcpy with SStream functions.

* Increase number of allowed AArch64 operands.

* Check safety of incrementing t the next operand.

* Fix naming of operand

* Update python constants

* Fix option setup of CS_OPT_DETAIL_REAL

* Document DETAIL_REAL has to be used with CS_OPT_ON.

* Run Coverity scan every Monday.

* Remove dead code

* Fix OOB read

* Rename macro to reflect it is only used with sstreams

* Fix rebase issues
2024-09-18 21:19:42 +08:00

263 lines
7.9 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);
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
}
}
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;
}