mirror of
https://github.com/hedge-dev/XenonRecomp.git
synced 2025-06-06 18:31:03 +00:00
239 lines
6.7 KiB
C
239 lines
6.7 KiB
C
![]() |
/* Capstone Disassembly Engine */
|
||
|
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2013-2019 */
|
||
|
/* Rot127 <unisono@quyllur.org>, 2022-2023 */
|
||
|
|
||
|
#include "ARMDisassemblerExtension.h"
|
||
|
#include "ARMBaseInfo.h"
|
||
|
|
||
|
bool ITBlock_push_back(ARM_ITBlock *it, char v)
|
||
|
{
|
||
|
if (it->size >= sizeof(it->ITStates)) {
|
||
|
// TODO: consider warning user.
|
||
|
it->size = 0;
|
||
|
}
|
||
|
it->ITStates[it->size] = v;
|
||
|
it->size++;
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
// Returns true if the current instruction is in an IT block
|
||
|
bool ITBlock_instrInITBlock(ARM_ITBlock *it)
|
||
|
{
|
||
|
return (it->size > 0);
|
||
|
}
|
||
|
|
||
|
// Returns true if current instruction is the last instruction in an IT block
|
||
|
bool ITBlock_instrLastInITBlock(ARM_ITBlock *it)
|
||
|
{
|
||
|
return (it->size == 1);
|
||
|
}
|
||
|
|
||
|
// Returns the condition code for instruction in IT block
|
||
|
unsigned ITBlock_getITCC(ARM_ITBlock *it)
|
||
|
{
|
||
|
unsigned CC = ARMCC_AL;
|
||
|
|
||
|
if (ITBlock_instrInITBlock(it))
|
||
|
CC = it->ITStates[it->size - 1];
|
||
|
|
||
|
return CC;
|
||
|
}
|
||
|
|
||
|
// Advances the IT block state to the next T or E
|
||
|
void ITBlock_advanceITState(ARM_ITBlock *it)
|
||
|
{
|
||
|
it->size--;
|
||
|
}
|
||
|
|
||
|
// Called when decoding an IT instruction. Sets the IT state for the following
|
||
|
// instructions that for the IT block. Firstcond and Mask correspond to the
|
||
|
// fields in the IT instruction encoding.
|
||
|
void ITBlock_setITState(ARM_ITBlock *it, char Firstcond, char Mask)
|
||
|
{
|
||
|
// (3 - the number of trailing zeros) is the number of then / else.
|
||
|
unsigned NumTZ = CountTrailingZeros_8(Mask);
|
||
|
unsigned char CCBits = (unsigned char)(Firstcond & 0xf);
|
||
|
assert(NumTZ <= 3 && "Invalid IT mask!");
|
||
|
// push condition codes onto the stack the correct order for the pops
|
||
|
for (unsigned Pos = NumTZ + 1; Pos <= 3; ++Pos) {
|
||
|
unsigned Else = (Mask >> Pos) & 1;
|
||
|
ITBlock_push_back(it, CCBits ^ Else);
|
||
|
}
|
||
|
ITBlock_push_back(it, CCBits);
|
||
|
}
|
||
|
|
||
|
bool VPTBlock_push_back(ARM_VPTBlock *it, char v)
|
||
|
{
|
||
|
if (it->size >= sizeof(it->VPTStates)) {
|
||
|
// TODO: consider warning user.
|
||
|
it->size = 0;
|
||
|
}
|
||
|
it->VPTStates[it->size] = v;
|
||
|
it->size++;
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool VPTBlock_instrInVPTBlock(ARM_VPTBlock *VPT)
|
||
|
{
|
||
|
return VPT->size > 0;
|
||
|
}
|
||
|
|
||
|
unsigned VPTBlock_getVPTPred(ARM_VPTBlock *VPT)
|
||
|
{
|
||
|
unsigned Pred = ARMVCC_None;
|
||
|
if (VPTBlock_instrInVPTBlock(VPT))
|
||
|
Pred = VPT->VPTStates[VPT->size - 1];
|
||
|
return Pred;
|
||
|
}
|
||
|
|
||
|
void VPTBlock_advanceVPTState(ARM_VPTBlock *VPT)
|
||
|
{
|
||
|
VPT->size--;
|
||
|
}
|
||
|
|
||
|
void VPTBlock_setVPTState(ARM_VPTBlock *VPT, char Mask)
|
||
|
{
|
||
|
// (3 - the number of trailing zeros) is the number of then / else.
|
||
|
unsigned NumTZ = CountTrailingZeros_8(Mask);
|
||
|
assert(NumTZ <= 3 && "Invalid VPT mask!");
|
||
|
// push predicates onto the stack the correct order for the pops
|
||
|
for (unsigned Pos = NumTZ + 1; Pos <= 3; ++Pos) {
|
||
|
bool T = ((Mask >> Pos) & 1) == 0;
|
||
|
if (T)
|
||
|
VPTBlock_push_back(VPT, ARMVCC_Then);
|
||
|
else
|
||
|
VPTBlock_push_back(VPT, ARMVCC_Else);
|
||
|
}
|
||
|
VPTBlock_push_back(VPT, ARMVCC_Then);
|
||
|
}
|
||
|
|
||
|
/// ThumbDisassembler - Thumb disassembler for all Thumb platforms.
|
||
|
|
||
|
bool Check(DecodeStatus *Out, DecodeStatus In)
|
||
|
{
|
||
|
switch (In) {
|
||
|
case MCDisassembler_Success:
|
||
|
// Out stays the same.
|
||
|
return true;
|
||
|
case MCDisassembler_SoftFail:
|
||
|
*Out = In;
|
||
|
return true;
|
||
|
case MCDisassembler_Fail:
|
||
|
*Out = In;
|
||
|
return false;
|
||
|
default: // never reached
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Imported from ARMBaseInstrInfo.h
|
||
|
//
|
||
|
/// isValidCoprocessorNumber - decide whether an explicit coprocessor
|
||
|
/// number is legal in generic instructions like CDP. The answer can
|
||
|
/// vary with the subtarget.
|
||
|
bool isValidCoprocessorNumber(MCInst *Inst, unsigned Num)
|
||
|
{
|
||
|
// In Armv7 and Armv8-M CP10 and CP11 clash with VFP/NEON, however, the
|
||
|
// coprocessor is still valid for CDP/MCR/MRC and friends. Allowing it is
|
||
|
// useful for code which is shared with older architectures which do not
|
||
|
// know the new VFP/NEON mnemonics.
|
||
|
|
||
|
// Armv8-A disallows everything *other* than 111x (CP14 and CP15).
|
||
|
if (ARM_getFeatureBits(Inst->csh->mode, ARM_HasV8Ops) &&
|
||
|
(Num & 0xE) != 0xE)
|
||
|
return false;
|
||
|
|
||
|
// Armv8.1-M disallows 100x (CP8,CP9) and 111x (CP14,CP15)
|
||
|
// which clash with MVE.
|
||
|
if (ARM_getFeatureBits(Inst->csh->mode, ARM_HasV8_1MMainlineOps) &&
|
||
|
((Num & 0xE) == 0x8 || (Num & 0xE) == 0xE))
|
||
|
return false;
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
// Imported from ARMMCTargetDesc.h
|
||
|
bool ARM_isVpred(arm_op_type op)
|
||
|
{
|
||
|
return op == ARM_OP_VPRED_R || op == ARM_OP_VPRED_N;
|
||
|
}
|
||
|
|
||
|
// Imported from ARMBaseInstrInfo.h
|
||
|
//
|
||
|
// This table shows the VPT instruction variants, i.e. the different
|
||
|
// mask field encodings, see also B5.6. Predication/conditional execution in
|
||
|
// the ArmARM.
|
||
|
bool isVPTOpcode(int Opc)
|
||
|
{
|
||
|
return Opc == ARM_MVE_VPTv16i8 || Opc == ARM_MVE_VPTv16u8 ||
|
||
|
Opc == ARM_MVE_VPTv16s8 || Opc == ARM_MVE_VPTv8i16 ||
|
||
|
Opc == ARM_MVE_VPTv8u16 || Opc == ARM_MVE_VPTv8s16 ||
|
||
|
Opc == ARM_MVE_VPTv4i32 || Opc == ARM_MVE_VPTv4u32 ||
|
||
|
Opc == ARM_MVE_VPTv4s32 || Opc == ARM_MVE_VPTv4f32 ||
|
||
|
Opc == ARM_MVE_VPTv8f16 || Opc == ARM_MVE_VPTv16i8r ||
|
||
|
Opc == ARM_MVE_VPTv16u8r || Opc == ARM_MVE_VPTv16s8r ||
|
||
|
Opc == ARM_MVE_VPTv8i16r || Opc == ARM_MVE_VPTv8u16r ||
|
||
|
Opc == ARM_MVE_VPTv8s16r || Opc == ARM_MVE_VPTv4i32r ||
|
||
|
Opc == ARM_MVE_VPTv4u32r || Opc == ARM_MVE_VPTv4s32r ||
|
||
|
Opc == ARM_MVE_VPTv4f32r || Opc == ARM_MVE_VPTv8f16r ||
|
||
|
Opc == ARM_MVE_VPST;
|
||
|
}
|
||
|
|
||
|
// Imported from ARMMCTargetDesc.cpp
|
||
|
bool ARM_isCDECoproc(size_t Coproc, const MCInst *MI)
|
||
|
{
|
||
|
// Unfortunately we don't have ARMTargetInfo in the disassembler, so we have
|
||
|
// to rely on feature bits.
|
||
|
if (Coproc >= 8)
|
||
|
return false;
|
||
|
|
||
|
return ARM_getFeatureBits(MI->csh->mode,
|
||
|
ARM_FeatureCoprocCDE0 + Coproc);
|
||
|
}
|
||
|
|
||
|
// Hacky: enable all features for disassembler
|
||
|
bool ARM_getFeatureBits(unsigned int mode, unsigned int feature)
|
||
|
{
|
||
|
if (feature == ARM_ModeThumb) {
|
||
|
if (mode & CS_MODE_THUMB)
|
||
|
return true;
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if (feature == ARM_FeatureDFB)
|
||
|
return false;
|
||
|
|
||
|
if (feature == ARM_FeatureRAS)
|
||
|
return false;
|
||
|
|
||
|
if (feature == ARM_FeatureMClass && (mode & CS_MODE_MCLASS) == 0)
|
||
|
return false;
|
||
|
|
||
|
if ((feature == ARM_HasMVEIntegerOps || feature == ARM_HasMVEFloatOps ||
|
||
|
feature == ARM_FeatureMVEVectorCostFactor1 ||
|
||
|
feature == ARM_FeatureMVEVectorCostFactor2 ||
|
||
|
feature == ARM_FeatureMVEVectorCostFactor4) &&
|
||
|
(mode & CS_MODE_MCLASS) == 0)
|
||
|
return false;
|
||
|
|
||
|
if ((feature == ARM_HasV8Ops || feature == ARM_HasV8_1MMainlineOps ||
|
||
|
feature == ARM_HasV8_1aOps || feature == ARM_HasV8_2aOps ||
|
||
|
feature == ARM_HasV8_3aOps || feature == ARM_HasV8_4aOps ||
|
||
|
feature == ARM_HasV8_5aOps || feature == ARM_HasV8_6aOps ||
|
||
|
feature == ARM_HasV8_7aOps || feature == ARM_HasV8_8aOps ||
|
||
|
feature == ARM_HasV8_9aOps) &&
|
||
|
(mode & CS_MODE_V8) == 0)
|
||
|
return false;
|
||
|
|
||
|
if (feature >= ARM_FeatureCoprocCDE0 &&
|
||
|
feature <= ARM_FeatureCoprocCDE7)
|
||
|
// We currently have no way to detect CDE (Custom-Datapath-Extension)
|
||
|
// coprocessors.
|
||
|
return false;
|
||
|
|
||
|
// we support everything
|
||
|
return true;
|
||
|
}
|