| /* Capstone Disassembly Engine, http://www.capstone-engine.org */ |
| /* By Nguyen Anh Quynh <aquynh@gmail.com>, 2013-2022, */ |
| /* Rot127 <unisono@quyllur.org> 2022-2023 */ |
| /* Automatically translated source file from LLVM. */ |
| |
| /* LLVM-commit: <commit> */ |
| /* LLVM-tag: <tag> */ |
| |
| /* Only small edits allowed. */ |
| /* For multiple similar edits, please create a Patch for the translator. */ |
| |
| /* Capstone's C++ file translator: */ |
| /* https://github.com/capstone-engine/capstone/tree/next/suite/auto-sync */ |
| |
| //===- AArch64Disassembler.cpp - Disassembler for AArch64 -----------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include <capstone/platform.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| |
| #include "../../LEB128.h" |
| #include "../../MCDisassembler.h" |
| #include "../../MCFixedLenDisassembler.h" |
| #include "../../MCInst.h" |
| #include "../../MCInstrDesc.h" |
| #include "../../MCRegisterInfo.h" |
| #include "../../cs_priv.h" |
| #include "../../utils.h" |
| #include "AArch64AddressingModes.h" |
| #include "AArch64BaseInfo.h" |
| #include "AArch64DisassemblerExtension.h" |
| #include "AArch64Linkage.h" |
| #include "AArch64Mapping.h" |
| |
| #define GET_INSTRINFO_MC_DESC |
| #include "AArch64GenInstrInfo.inc" |
| |
| #define CONCAT(a, b) CONCAT_(a, b) |
| #define CONCAT_(a, b) a##_##b |
| |
| #define DEBUG_TYPE "aarch64-disassembler" |
| |
| static 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; |
| } |
| } |
| |
| // Pull DecodeStatus and its enum values into the global namespace. |
| |
| // Forward declare these because the autogenerated code will reference them. |
| // Definitions are further down. |
| static DecodeStatus DecodeFPR128RegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Address, |
| const void *Decoder); |
| static DecodeStatus DecodeFPR128_loRegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Address, |
| const void *Decoder); |
| static DecodeStatus DecodeFPR64RegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Address, |
| const void *Decoder); |
| static DecodeStatus DecodeFPR32RegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Address, |
| const void *Decoder); |
| static DecodeStatus DecodeFPR16RegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Address, |
| const void *Decoder); |
| static DecodeStatus DecodeFPR8RegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Address, |
| const void *Decoder); |
| static DecodeStatus DecodeGPR64commonRegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Address, |
| const void *Decoder); |
| static DecodeStatus DecodeGPR64RegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Address, |
| const void *Decoder); |
| static DecodeStatus DecodeGPR64x8ClassRegisterClass(MCInst *Inst, |
| unsigned RegNo, |
| uint64_t Address, |
| const void *Decoder); |
| static DecodeStatus DecodeGPR64spRegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Address, |
| const void *Decoder); |
| static DecodeStatus |
| DecodeMatrixIndexGPR32_8_11RegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Address, const void *Decoder); |
| static DecodeStatus DecodeMatrixIndexGPR32_12_15RegisterClass( |
| MCInst *Inst, unsigned RegNo, uint64_t Address, const void *Decoder); |
| static DecodeStatus DecodeGPR32RegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Address, |
| const void *Decoder); |
| static DecodeStatus DecodeGPR32spRegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Address, |
| const void *Decoder); |
| static DecodeStatus DecodeQQRegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Address, |
| const void *Decoder); |
| static DecodeStatus DecodeQQQRegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Address, |
| const void *Decoder); |
| static DecodeStatus DecodeQQQQRegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Address, |
| const void *Decoder); |
| static DecodeStatus DecodeDDRegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Address, |
| const void *Decoder); |
| static DecodeStatus DecodeDDDRegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Address, |
| const void *Decoder); |
| static DecodeStatus DecodeDDDDRegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Address, |
| const void *Decoder); |
| static DecodeStatus DecodeZPRRegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Address, |
| const void *Decoder); |
| static DecodeStatus DecodeZPR_4bRegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Address, |
| const void *Decoder); |
| static DecodeStatus DecodeZPR_3bRegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Address, |
| const void *Decoder); |
| static DecodeStatus DecodeZPR2RegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Address, |
| const void *Decoder); |
| static DecodeStatus DecodeZPR3RegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Address, |
| const void *Decoder); |
| static DecodeStatus DecodeZPR4RegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Address, |
| const void *Decoder); |
| static DecodeStatus DecodeZPR2Mul2RegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Address, |
| const void *Decoder); |
| static DecodeStatus DecodeZPR4Mul4RegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Address, |
| const void *Decoder); |
| static DecodeStatus DecodeZPR2StridedRegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Address, |
| const void *Decoder); |
| static DecodeStatus DecodeZPR4StridedRegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Address, |
| const void *Decoder); |
| #define DECLARE_DecodeMatrixTile(NumBitsForTile) \ |
| static DecodeStatus CONCAT(DecodeMatrixTile, NumBitsForTile)( \ |
| MCInst * Inst, unsigned RegNo, uint64_t Address, const void *Decoder); |
| DECLARE_DecodeMatrixTile(2); |
| DECLARE_DecodeMatrixTile(3); |
| DECLARE_DecodeMatrixTile(1); |
| DECLARE_DecodeMatrixTile(4); |
| |
| static DecodeStatus DecodeMatrixTileListRegisterClass(MCInst *Inst, |
| unsigned RegMask, |
| uint64_t Address, |
| const void *Decoder); |
| static DecodeStatus DecodePPRRegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Address, |
| const void *Decoder); |
| static DecodeStatus DecodePPR_3bRegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Address, |
| const void *Decoder); |
| static DecodeStatus DecodePPR_p8to15RegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Address, |
| const void *Decoder); |
| static DecodeStatus DecodePPR2RegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Address, |
| const void *Decoder); |
| static DecodeStatus DecodePPR2Mul2RegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Address, |
| const void *Decoder); |
| |
| static DecodeStatus DecodeFixedPointScaleImm32(MCInst *Inst, unsigned Imm, |
| uint64_t Address, |
| const void *Decoder); |
| static DecodeStatus DecodeFixedPointScaleImm64(MCInst *Inst, unsigned Imm, |
| uint64_t Address, |
| const void *Decoder); |
| static DecodeStatus DecodePCRelLabel19(MCInst *Inst, unsigned Imm, |
| uint64_t Address, const void *Decoder); |
| static DecodeStatus DecodeMemExtend(MCInst *Inst, unsigned Imm, |
| uint64_t Address, const void *Decoder); |
| static DecodeStatus DecodeMRSSystemRegister(MCInst *Inst, unsigned Imm, |
| uint64_t Address, |
| const void *Decoder); |
| static DecodeStatus DecodeMSRSystemRegister(MCInst *Inst, unsigned Imm, |
| uint64_t Address, |
| const void *Decoder); |
| static DecodeStatus DecodeThreeAddrSRegInstruction(MCInst *Inst, uint32_t insn, |
| uint64_t Address, |
| const void *Decoder); |
| static DecodeStatus DecodeMoveImmInstruction(MCInst *Inst, uint32_t insn, |
| uint64_t Address, |
| const void *Decoder); |
| static DecodeStatus DecodeUnsignedLdStInstruction(MCInst *Inst, uint32_t insn, |
| uint64_t Address, |
| const void *Decoder); |
| static DecodeStatus DecodeSignedLdStInstruction(MCInst *Inst, uint32_t insn, |
| uint64_t Address, |
| const void *Decoder); |
| static DecodeStatus DecodeExclusiveLdStInstruction(MCInst *Inst, uint32_t insn, |
| uint64_t Address, |
| const void *Decoder); |
| static DecodeStatus DecodePairLdStInstruction(MCInst *Inst, uint32_t insn, |
| uint64_t Address, |
| const void *Decoder); |
| static DecodeStatus DecodeAuthLoadInstruction(MCInst *Inst, uint32_t insn, |
| uint64_t Address, |
| const void *Decoder); |
| static DecodeStatus DecodeAddSubERegInstruction(MCInst *Inst, uint32_t insn, |
| uint64_t Address, |
| const void *Decoder); |
| static DecodeStatus DecodeLogicalImmInstruction(MCInst *Inst, uint32_t insn, |
| uint64_t Address, |
| const void *Decoder); |
| static DecodeStatus DecodeModImmInstruction(MCInst *Inst, uint32_t insn, |
| uint64_t Address, |
| const void *Decoder); |
| static DecodeStatus DecodeModImmTiedInstruction(MCInst *Inst, uint32_t insn, |
| uint64_t Address, |
| const void *Decoder); |
| static DecodeStatus DecodeAdrInstruction(MCInst *Inst, uint32_t insn, |
| uint64_t Address, const void *Decoder); |
| static DecodeStatus DecodeAddSubImmShift(MCInst *Inst, uint32_t insn, |
| uint64_t Address, const void *Decoder); |
| static DecodeStatus DecodeUnconditionalBranch(MCInst *Inst, uint32_t insn, |
| uint64_t Address, |
| const void *Decoder); |
| static DecodeStatus DecodeSystemPStateImm0_15Instruction(MCInst *Inst, |
| uint32_t insn, |
| uint64_t Address, |
| const void *Decoder); |
| static DecodeStatus DecodeSystemPStateImm0_1Instruction(MCInst *Inst, |
| uint32_t insn, |
| uint64_t Address, |
| const void *Decoder); |
| static DecodeStatus DecodeTestAndBranch(MCInst *Inst, uint32_t insn, |
| uint64_t Address, const void *Decoder); |
| |
| static DecodeStatus DecodeFMOVLaneInstruction(MCInst *Inst, unsigned Insn, |
| uint64_t Address, |
| const void *Decoder); |
| static DecodeStatus DecodeVecShiftR64Imm(MCInst *Inst, unsigned Imm, |
| uint64_t Addr, const void *Decoder); |
| static DecodeStatus DecodeVecShiftR64ImmNarrow(MCInst *Inst, unsigned Imm, |
| uint64_t Addr, |
| const void *Decoder); |
| static DecodeStatus DecodeVecShiftR32Imm(MCInst *Inst, unsigned Imm, |
| uint64_t Addr, const void *Decoder); |
| static DecodeStatus DecodeVecShiftR32ImmNarrow(MCInst *Inst, unsigned Imm, |
| uint64_t Addr, |
| const void *Decoder); |
| static DecodeStatus DecodeVecShiftR16Imm(MCInst *Inst, unsigned Imm, |
| uint64_t Addr, const void *Decoder); |
| static DecodeStatus DecodeVecShiftR16ImmNarrow(MCInst *Inst, unsigned Imm, |
| uint64_t Addr, |
| const void *Decoder); |
| static DecodeStatus DecodeVecShiftR8Imm(MCInst *Inst, unsigned Imm, |
| uint64_t Addr, const void *Decoder); |
| static DecodeStatus DecodeVecShiftL64Imm(MCInst *Inst, unsigned Imm, |
| uint64_t Addr, const void *Decoder); |
| static DecodeStatus DecodeVecShiftL32Imm(MCInst *Inst, unsigned Imm, |
| uint64_t Addr, const void *Decoder); |
| static DecodeStatus DecodeVecShiftL16Imm(MCInst *Inst, unsigned Imm, |
| uint64_t Addr, const void *Decoder); |
| static DecodeStatus DecodeVecShiftL8Imm(MCInst *Inst, unsigned Imm, |
| uint64_t Addr, const void *Decoder); |
| static DecodeStatus DecodeWSeqPairsClassRegisterClass(MCInst *Inst, |
| unsigned RegNo, |
| uint64_t Addr, |
| const void *Decoder); |
| static DecodeStatus DecodeXSeqPairsClassRegisterClass(MCInst *Inst, |
| unsigned RegNo, |
| uint64_t Addr, |
| const void *Decoder); |
| static DecodeStatus DecodeSyspXzrInstruction(MCInst *Inst, uint32_t insn, |
| uint64_t Addr, |
| const void *Decoder); |
| static DecodeStatus DecodeSVELogicalImmInstruction(MCInst *Inst, uint32_t insn, |
| uint64_t Address, |
| const void *Decoder); |
| #define DECLARE_DecodeSImm(Bits) \ |
| static DecodeStatus CONCAT(DecodeSImm, Bits)( \ |
| MCInst * Inst, uint64_t Imm, uint64_t Address, const void *Decoder); |
| DECLARE_DecodeSImm(4); |
| DECLARE_DecodeSImm(5); |
| DECLARE_DecodeSImm(6); |
| DECLARE_DecodeSImm(8); |
| DECLARE_DecodeSImm(9); |
| DECLARE_DecodeSImm(10); |
| |
| #define DECLARE_DecodeImm8OptLsl(ElementWidth) \ |
| static DecodeStatus CONCAT(DecodeImm8OptLsl, ElementWidth)( \ |
| MCInst * Inst, unsigned Imm, uint64_t Addr, const void *Decoder); |
| DECLARE_DecodeImm8OptLsl(8); |
| DECLARE_DecodeImm8OptLsl(16); |
| DECLARE_DecodeImm8OptLsl(32); |
| DECLARE_DecodeImm8OptLsl(64); |
| |
| static DecodeStatus DecodeSVEIncDecImm(MCInst *Inst, unsigned Imm, |
| uint64_t Addr, const void *Decoder); |
| static DecodeStatus DecodeSVCROp(MCInst *Inst, unsigned Imm, uint64_t Address, |
| const void *Decoder); |
| static DecodeStatus DecodeCPYMemOpInstruction(MCInst *Inst, uint32_t insn, |
| uint64_t Addr, |
| const void *Decoder); |
| static DecodeStatus DecodeSETMemOpInstruction(MCInst *Inst, uint32_t insn, |
| uint64_t Addr, |
| const void *Decoder); |
| static DecodeStatus DecodePRFMRegInstruction(MCInst *Inst, uint32_t insn, |
| uint64_t Address, |
| const void *Decoder); |
| |
| #include "AArch64GenDisassemblerTables.inc" |
| |
| #define Success MCDisassembler_Success |
| #define Fail MCDisassembler_Fail |
| #define SoftFail MCDisassembler_SoftFail |
| |
| static DecodeStatus getInstruction(csh handle, const uint8_t *Bytes, size_t ByteLen, |
| MCInst *MI, uint16_t *Size, uint64_t Address, |
| void *Info) |
| { |
| *Size = 0; |
| // We want to read exactly 4 bytes of data. |
| if (ByteLen < 4) |
| return Fail; |
| *Size = 4; |
| |
| // Encoded as a small-endian 32-bit word in the stream. |
| uint32_t Insn = readBytes32(MI, Bytes); |
| |
| const uint8_t *Tables[] = {DecoderTable32, DecoderTableFallback32}; |
| |
| for (int i = 0; i < (sizeof(Tables) / sizeof(Tables[0])); ++i) { |
| void *Decoder = NULL; |
| DecodeStatus Result = decodeInstruction_4(Tables[i], MI, Insn, Address, Decoder); |
| |
| const MCInstrDesc Desc = AArch64Insts[MCInst_getOpcode(MI)]; |
| |
| // For Scalable Matrix Extension (SME) instructions that have an |
| // implicit operand for the accumulator (ZA) or implicit immediate zero |
| // which isn't encoded, manually insert operand. |
| for (unsigned j = 0; j < Desc.NumOperands; j++) { |
| if (Desc.OpInfo[j].OperandType == MCOI_OPERAND_REGISTER) { |
| switch (Desc.OpInfo[j].RegClass) { |
| default: |
| break; |
| case AArch64_MPRRegClassID: |
| MCInst_insert0(MI, j, MCOperand_CreateReg1(MI, AArch64_ZA)); |
| break; |
| case AArch64_MPR8RegClassID: |
| MCInst_insert0(MI, j, |
| MCOperand_CreateReg1(MI, AArch64_ZAB0)); |
| break; |
| case AArch64_ZTRRegClassID: |
| MCInst_insert0(MI, j, MCOperand_CreateReg1(MI, AArch64_ZT0)); |
| break; |
| } |
| } else if (Desc.OpInfo[j].OperandType == |
| AArch64_OP_IMPLICIT_IMM_0) { |
| MCInst_insert0(MI, j, MCOperand_CreateImm1(MI, 0)); |
| } |
| } |
| |
| if (MCInst_getOpcode(MI) == AArch64_LDR_ZA || |
| MCInst_getOpcode(MI) == AArch64_STR_ZA) { |
| // Spill and fill instructions have a single immediate used for both |
| // the vector select offset and optional memory offset. Replicate |
| // the decoded immediate. |
| MCOperand *Imm4Op = MCInst_getOperand(MI, (2)); |
| |
| MCInst_addOperand2(MI, (Imm4Op)); |
| } |
| |
| if (Result != MCDisassembler_Fail) |
| return Result; |
| } |
| |
| return MCDisassembler_Fail; |
| } |
| |
| DecodeStatus AArch64_LLVM_getInstruction(csh handle, const uint8_t *Bytes, |
| size_t ByteLen, MCInst *MI, uint16_t *Size, uint64_t Address, |
| void *Info) { |
| DecodeStatus Result = MCDisassembler_Fail; |
| Result = getInstruction(handle, Bytes, ByteLen, MI, Size, Address, Info); |
| MCInst_handleWriteback(MI, AArch64Insts); |
| return Result; |
| } |
| |
| uint64_t suggestBytesToSkip(const uint8_t *Bytes, uint64_t Address) |
| { |
| // AArch64 instructions are always 4 bytes wide, so there's no point |
| // in skipping any smaller number of bytes if an instruction can't |
| // be decoded. |
| return 4; |
| } |
| |
| static DecodeStatus DecodeFPR128RegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Addr, |
| const void *Decoder) |
| { |
| if (RegNo > 31) |
| return Fail; |
| |
| unsigned Register = |
| AArch64MCRegisterClasses[AArch64_FPR128RegClassID].RegsBegin[RegNo]; |
| MCOperand_CreateReg0(Inst, (Register)); |
| return Success; |
| } |
| |
| static DecodeStatus DecodeFPR128_loRegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Addr, |
| const void *Decoder) |
| { |
| if (RegNo > 15) |
| return Fail; |
| return DecodeFPR128RegisterClass(Inst, RegNo, Addr, Decoder); |
| } |
| |
| static DecodeStatus DecodeFPR64RegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Addr, const void *Decoder) |
| { |
| if (RegNo > 31) |
| return Fail; |
| |
| unsigned Register = |
| AArch64MCRegisterClasses[AArch64_FPR64RegClassID].RegsBegin[RegNo]; |
| MCOperand_CreateReg0(Inst, (Register)); |
| return Success; |
| } |
| |
| static DecodeStatus DecodeFPR32RegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Addr, const void *Decoder) |
| { |
| if (RegNo > 31) |
| return Fail; |
| |
| unsigned Register = |
| AArch64MCRegisterClasses[AArch64_FPR32RegClassID].RegsBegin[RegNo]; |
| MCOperand_CreateReg0(Inst, (Register)); |
| return Success; |
| } |
| |
| static DecodeStatus DecodeFPR16RegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Addr, const void *Decoder) |
| { |
| if (RegNo > 31) |
| return Fail; |
| |
| unsigned Register = |
| AArch64MCRegisterClasses[AArch64_FPR16RegClassID].RegsBegin[RegNo]; |
| MCOperand_CreateReg0(Inst, (Register)); |
| return Success; |
| } |
| |
| static DecodeStatus DecodeFPR8RegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Addr, const void *Decoder) |
| { |
| if (RegNo > 31) |
| return Fail; |
| |
| unsigned Register = |
| AArch64MCRegisterClasses[AArch64_FPR8RegClassID].RegsBegin[RegNo]; |
| MCOperand_CreateReg0(Inst, (Register)); |
| return Success; |
| } |
| |
| static DecodeStatus DecodeGPR64commonRegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Addr, |
| const void *Decoder) |
| { |
| if (RegNo > 30) |
| return Fail; |
| |
| unsigned Register = AArch64MCRegisterClasses[AArch64_GPR64commonRegClassID] |
| .RegsBegin[RegNo]; |
| MCOperand_CreateReg0(Inst, (Register)); |
| return Success; |
| } |
| |
| static DecodeStatus DecodeGPR64RegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Addr, const void *Decoder) |
| { |
| if (RegNo > 31) |
| return Fail; |
| |
| unsigned Register = |
| AArch64MCRegisterClasses[AArch64_GPR64RegClassID].RegsBegin[RegNo]; |
| MCOperand_CreateReg0(Inst, (Register)); |
| return Success; |
| } |
| |
| static DecodeStatus DecodeGPR64x8ClassRegisterClass(MCInst *Inst, |
| unsigned RegNo, |
| uint64_t Address, |
| const void *Decoder) |
| { |
| if (RegNo > 22) |
| return Fail; |
| if (RegNo & 1) |
| return Fail; |
| |
| unsigned Register = AArch64MCRegisterClasses[AArch64_GPR64x8ClassRegClassID] |
| .RegsBegin[RegNo >> 1]; |
| MCOperand_CreateReg0(Inst, (Register)); |
| return Success; |
| } |
| |
| static DecodeStatus DecodeGPR64spRegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Addr, |
| const void *Decoder) |
| { |
| if (RegNo > 31) |
| return Fail; |
| unsigned Register = |
| AArch64MCRegisterClasses[AArch64_GPR64spRegClassID].RegsBegin[RegNo]; |
| MCOperand_CreateReg0(Inst, (Register)); |
| return Success; |
| } |
| |
| static DecodeStatus |
| DecodeMatrixIndexGPR32_8_11RegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Addr, const void *Decoder) |
| { |
| if (RegNo > 3) |
| return Fail; |
| |
| unsigned Register = |
| AArch64MCRegisterClasses[AArch64_MatrixIndexGPR32_8_11RegClassID] |
| .RegsBegin[RegNo]; |
| MCOperand_CreateReg0(Inst, (Register)); |
| return Success; |
| } |
| |
| static DecodeStatus |
| DecodeMatrixIndexGPR32_12_15RegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Addr, const void *Decoder) |
| { |
| if (RegNo > 3) |
| return Fail; |
| |
| unsigned Register = |
| AArch64MCRegisterClasses[AArch64_MatrixIndexGPR32_12_15RegClassID] |
| .RegsBegin[RegNo]; |
| MCOperand_CreateReg0(Inst, (Register)); |
| return Success; |
| } |
| |
| static DecodeStatus DecodeGPR32RegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Addr, const void *Decoder) |
| { |
| if (RegNo > 31) |
| return Fail; |
| |
| unsigned Register = |
| AArch64MCRegisterClasses[AArch64_GPR32RegClassID].RegsBegin[RegNo]; |
| MCOperand_CreateReg0(Inst, (Register)); |
| return Success; |
| } |
| |
| static DecodeStatus DecodeGPR32spRegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Addr, |
| const void *Decoder) |
| { |
| if (RegNo > 31) |
| return Fail; |
| |
| unsigned Register = |
| AArch64MCRegisterClasses[AArch64_GPR32spRegClassID].RegsBegin[RegNo]; |
| MCOperand_CreateReg0(Inst, (Register)); |
| return Success; |
| } |
| |
| static DecodeStatus DecodeZPRRegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Address, |
| const void *Decoder) |
| { |
| if (RegNo > 31) |
| return Fail; |
| |
| unsigned Register = |
| AArch64MCRegisterClasses[AArch64_ZPRRegClassID].RegsBegin[RegNo]; |
| MCOperand_CreateReg0(Inst, (Register)); |
| return Success; |
| } |
| |
| static DecodeStatus DecodeZPR_4bRegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Address, |
| const void *Decoder) |
| { |
| if (RegNo > 15) |
| return Fail; |
| return DecodeZPRRegisterClass(Inst, RegNo, Address, Decoder); |
| } |
| |
| static DecodeStatus DecodeZPR_3bRegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Address, |
| const void *Decoder) |
| { |
| if (RegNo > 7) |
| return Fail; |
| return DecodeZPRRegisterClass(Inst, RegNo, Address, Decoder); |
| } |
| |
| static DecodeStatus DecodeZPR2RegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Address, |
| const void *Decoder) |
| { |
| if (RegNo > 31) |
| return Fail; |
| unsigned Register = |
| AArch64MCRegisterClasses[AArch64_ZPR2RegClassID].RegsBegin[RegNo]; |
| MCOperand_CreateReg0(Inst, (Register)); |
| return Success; |
| } |
| |
| static DecodeStatus DecodeZPR3RegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Address, |
| const void *Decoder) |
| { |
| if (RegNo > 31) |
| return Fail; |
| unsigned Register = |
| AArch64MCRegisterClasses[AArch64_ZPR3RegClassID].RegsBegin[RegNo]; |
| MCOperand_CreateReg0(Inst, (Register)); |
| return Success; |
| } |
| |
| static DecodeStatus DecodeZPR4RegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Address, |
| const void *Decoder) |
| { |
| if (RegNo > 31) |
| return Fail; |
| unsigned Register = |
| AArch64MCRegisterClasses[AArch64_ZPR4RegClassID].RegsBegin[RegNo]; |
| MCOperand_CreateReg0(Inst, (Register)); |
| return Success; |
| } |
| |
| static DecodeStatus DecodeZPR2Mul2RegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Address, |
| const void *Decoder) |
| { |
| if (RegNo * 2 > 30) |
| return Fail; |
| unsigned Register = |
| AArch64MCRegisterClasses[AArch64_ZPR2RegClassID].RegsBegin[RegNo * 2]; |
| MCOperand_CreateReg0(Inst, (Register)); |
| return Success; |
| } |
| |
| static DecodeStatus DecodeZPR4Mul4RegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Address, |
| const void *Decoder) |
| { |
| if (RegNo * 4 > 28) |
| return Fail; |
| unsigned Register = |
| AArch64MCRegisterClasses[AArch64_ZPR4RegClassID].RegsBegin[RegNo * 4]; |
| MCOperand_CreateReg0(Inst, (Register)); |
| return Success; |
| } |
| |
| static DecodeStatus DecodeZPR2StridedRegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Address, |
| const void *Decoder) |
| { |
| if (RegNo > 15) |
| return Fail; |
| unsigned Register = AArch64MCRegisterClasses[AArch64_ZPR2StridedRegClassID] |
| .RegsBegin[RegNo]; |
| MCOperand_CreateReg0(Inst, (Register)); |
| return Success; |
| } |
| |
| static DecodeStatus DecodeZPR4StridedRegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Address, |
| const void *Decoder) |
| { |
| if (RegNo > 7) |
| return Fail; |
| unsigned Register = AArch64MCRegisterClasses[AArch64_ZPR4StridedRegClassID] |
| .RegsBegin[RegNo]; |
| MCOperand_CreateReg0(Inst, (Register)); |
| return Success; |
| } |
| |
| static DecodeStatus DecodeMatrixTileListRegisterClass(MCInst *Inst, |
| unsigned RegMask, |
| uint64_t Address, |
| const void *Decoder) |
| { |
| if (RegMask > 0xFF) |
| return Fail; |
| MCOperand_CreateImm0(Inst, (RegMask)); |
| return Success; |
| } |
| |
| static const unsigned |
| MatrixZATileDecoderTable[5][16] = { |
| {AArch64_ZAB0}, |
| {AArch64_ZAH0, AArch64_ZAH1}, |
| {AArch64_ZAS0, AArch64_ZAS1, AArch64_ZAS2, AArch64_ZAS3}, |
| {AArch64_ZAD0, AArch64_ZAD1, AArch64_ZAD2, AArch64_ZAD3, AArch64_ZAD4, |
| AArch64_ZAD5, AArch64_ZAD6, AArch64_ZAD7}, |
| {AArch64_ZAQ0, AArch64_ZAQ1, AArch64_ZAQ2, AArch64_ZAQ3, AArch64_ZAQ4, |
| AArch64_ZAQ5, AArch64_ZAQ6, AArch64_ZAQ7, AArch64_ZAQ8, AArch64_ZAQ9, |
| AArch64_ZAQ10, AArch64_ZAQ11, AArch64_ZAQ12, AArch64_ZAQ13, |
| AArch64_ZAQ14, AArch64_ZAQ15}}; |
| |
| #define DEFINE_DecodeMatrixTile(NumBitsForTile) \ |
| static DecodeStatus CONCAT(DecodeMatrixTile, NumBitsForTile)( \ |
| MCInst * Inst, unsigned RegNo, uint64_t Address, const void *Decoder) \ |
| { \ |
| unsigned LastReg = (1 << NumBitsForTile) - 1; \ |
| if (RegNo > LastReg) \ |
| return Fail; \ |
| MCOperand_CreateReg0( \ |
| Inst, (MatrixZATileDecoderTable[NumBitsForTile][RegNo])); \ |
| return Success; \ |
| } |
| DEFINE_DecodeMatrixTile(2); |
| DEFINE_DecodeMatrixTile(3); |
| DEFINE_DecodeMatrixTile(1); |
| DEFINE_DecodeMatrixTile(4); |
| |
| static DecodeStatus DecodePPRRegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Addr, const void *Decoder) |
| { |
| if (RegNo > 15) |
| return Fail; |
| |
| unsigned Register = |
| AArch64MCRegisterClasses[AArch64_PPRRegClassID].RegsBegin[RegNo]; |
| MCOperand_CreateReg0(Inst, (Register)); |
| return Success; |
| } |
| |
| static DecodeStatus DecodePPR_3bRegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Addr, |
| const void *Decoder) |
| { |
| if (RegNo > 7) |
| return Fail; |
| |
| // Just reuse the PPR decode table |
| return DecodePPRRegisterClass(Inst, RegNo, Addr, Decoder); |
| } |
| |
| static DecodeStatus DecodePPR_p8to15RegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Addr, |
| const void *Decoder) |
| { |
| if (RegNo > 7) |
| return Fail; |
| |
| // Just reuse the PPR decode table |
| return DecodePPRRegisterClass(Inst, RegNo + 8, Addr, Decoder); |
| } |
| |
| static DecodeStatus DecodePPR2RegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Address, |
| const void *Decoder) |
| { |
| if (RegNo > 15) |
| return Fail; |
| |
| unsigned Register = |
| AArch64MCRegisterClasses[AArch64_PPR2RegClassID].RegsBegin[RegNo]; |
| MCOperand_CreateReg0(Inst, (Register)); |
| return Success; |
| } |
| |
| static DecodeStatus DecodePPR2Mul2RegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Address, |
| const void *Decoder) |
| { |
| if ((RegNo * 2) > 14) |
| return Fail; |
| unsigned Register = |
| AArch64MCRegisterClasses[AArch64_PPR2RegClassID].RegsBegin[RegNo * 2]; |
| MCOperand_CreateReg0(Inst, (Register)); |
| return Success; |
| } |
| |
| static DecodeStatus DecodeQQRegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Addr, const void *Decoder) |
| { |
| if (RegNo > 31) |
| return Fail; |
| unsigned Register = |
| AArch64MCRegisterClasses[AArch64_QQRegClassID].RegsBegin[RegNo]; |
| MCOperand_CreateReg0(Inst, (Register)); |
| return Success; |
| } |
| |
| static DecodeStatus DecodeQQQRegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Addr, const void *Decoder) |
| { |
| if (RegNo > 31) |
| return Fail; |
| unsigned Register = |
| AArch64MCRegisterClasses[AArch64_QQQRegClassID].RegsBegin[RegNo]; |
| MCOperand_CreateReg0(Inst, (Register)); |
| return Success; |
| } |
| |
| static DecodeStatus DecodeQQQQRegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Addr, const void *Decoder) |
| { |
| if (RegNo > 31) |
| return Fail; |
| unsigned Register = |
| AArch64MCRegisterClasses[AArch64_QQQQRegClassID].RegsBegin[RegNo]; |
| MCOperand_CreateReg0(Inst, (Register)); |
| return Success; |
| } |
| |
| static DecodeStatus DecodeDDRegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Addr, const void *Decoder) |
| { |
| if (RegNo > 31) |
| return Fail; |
| unsigned Register = |
| AArch64MCRegisterClasses[AArch64_DDRegClassID].RegsBegin[RegNo]; |
| MCOperand_CreateReg0(Inst, (Register)); |
| return Success; |
| } |
| |
| static DecodeStatus DecodeDDDRegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Addr, const void *Decoder) |
| { |
| if (RegNo > 31) |
| return Fail; |
| unsigned Register = |
| AArch64MCRegisterClasses[AArch64_DDDRegClassID].RegsBegin[RegNo]; |
| MCOperand_CreateReg0(Inst, (Register)); |
| return Success; |
| } |
| |
| static DecodeStatus DecodeDDDDRegisterClass(MCInst *Inst, unsigned RegNo, |
| uint64_t Addr, const void *Decoder) |
| { |
| if (RegNo > 31) |
| return Fail; |
| unsigned Register = |
| AArch64MCRegisterClasses[AArch64_DDDDRegClassID].RegsBegin[RegNo]; |
| MCOperand_CreateReg0(Inst, (Register)); |
| return Success; |
| } |
| |
| static DecodeStatus DecodeFixedPointScaleImm32(MCInst *Inst, unsigned Imm, |
| uint64_t Addr, |
| const void *Decoder) |
| { |
| // scale{5} is asserted as 1 in tblgen. |
| Imm |= 0x20; |
| MCOperand_CreateImm0(Inst, (64 - Imm)); |
| return Success; |
| } |
| |
| static DecodeStatus DecodeFixedPointScaleImm64(MCInst *Inst, unsigned Imm, |
| uint64_t Addr, |
| const void *Decoder) |
| { |
| MCOperand_CreateImm0(Inst, (64 - Imm)); |
| return Success; |
| } |
| |
| static DecodeStatus DecodePCRelLabel19(MCInst *Inst, unsigned Imm, |
| uint64_t Addr, const void *Decoder) |
| { |
| int64_t ImmVal = Imm; |
| |
| // Sign-extend 19-bit immediate. |
| if (ImmVal & (1 << (19 - 1))) |
| ImmVal |= ~((1LL << 19) - 1); |
| |
| // No symbols supported in Capstone |
| // if (!Decoder->tryAddingSymbolicOperand( |
| // Inst, ImmVal * 4, Addr, MCInst_getOpcode(Inst) != AArch64_LDRXl, 0, |
| // 0, 4)) |
| MCOperand_CreateImm0(Inst, (ImmVal)); |
| return Success; |
| } |
| |
| static DecodeStatus DecodeMemExtend(MCInst *Inst, unsigned Imm, |
| uint64_t Address, const void *Decoder) |
| { |
| MCOperand_CreateImm0(Inst, ((Imm >> 1) & 1)); |
| MCOperand_CreateImm0(Inst, (Imm & 1)); |
| return Success; |
| } |
| |
| static DecodeStatus DecodeMRSSystemRegister(MCInst *Inst, unsigned Imm, |
| uint64_t Address, |
| const void *Decoder) |
| { |
| MCOperand_CreateImm0(Inst, (Imm)); |
| |
| // Every system register in the encoding space is valid with the syntax |
| // S<op0>_<op1>_<Cn>_<Cm>_<op2>, so decoding system registers always |
| // succeeds. |
| return Success; |
| } |
| |
| static DecodeStatus DecodeMSRSystemRegister(MCInst *Inst, unsigned Imm, |
| uint64_t Address, |
| const void *Decoder) |
| { |
| MCOperand_CreateImm0(Inst, (Imm)); |
| |
| return Success; |
| } |
| |
| static DecodeStatus DecodeFMOVLaneInstruction(MCInst *Inst, unsigned Insn, |
| uint64_t Address, |
| const void *Decoder) |
| { |
| // This decoder exists to add the dummy Lane operand to the MCInst, which |
| // must be 1 in assembly but has no other real manifestation. |
| unsigned Rd = fieldFromInstruction_4(Insn, 0, 5); |
| unsigned Rn = fieldFromInstruction_4(Insn, 5, 5); |
| unsigned IsToVec = fieldFromInstruction_4(Insn, 16, 1); |
| |
| if (IsToVec) { |
| DecodeFPR128RegisterClass(Inst, Rd, Address, Decoder); |
| DecodeGPR64RegisterClass(Inst, Rn, Address, Decoder); |
| } else { |
| DecodeGPR64RegisterClass(Inst, Rd, Address, Decoder); |
| DecodeFPR128RegisterClass(Inst, Rn, Address, Decoder); |
| } |
| |
| // Add the lane |
| MCOperand_CreateImm0(Inst, (1)); |
| |
| return Success; |
| } |
| |
| static DecodeStatus DecodeVecShiftRImm(MCInst *Inst, unsigned Imm, unsigned Add) |
| { |
| MCOperand_CreateImm0(Inst, (Add - Imm)); |
| return Success; |
| } |
| |
| static DecodeStatus DecodeVecShiftLImm(MCInst *Inst, unsigned Imm, unsigned Add) |
| { |
| MCOperand_CreateImm0(Inst, ((Imm + Add) & (Add - 1))); |
| return Success; |
| } |
| |
| static DecodeStatus DecodeVecShiftR64Imm(MCInst *Inst, unsigned Imm, |
| uint64_t Addr, const void *Decoder) |
| { |
| return DecodeVecShiftRImm(Inst, Imm, 64); |
| } |
| |
| static DecodeStatus DecodeVecShiftR64ImmNarrow(MCInst *Inst, unsigned Imm, |
| uint64_t Addr, |
| const void *Decoder) |
| { |
| return DecodeVecShiftRImm(Inst, Imm | 0x20, 64); |
| } |
| |
| static DecodeStatus DecodeVecShiftR32Imm(MCInst *Inst, unsigned Imm, |
| uint64_t Addr, const void *Decoder) |
| { |
| return DecodeVecShiftRImm(Inst, Imm, 32); |
| } |
| |
| static DecodeStatus DecodeVecShiftR32ImmNarrow(MCInst *Inst, unsigned Imm, |
| uint64_t Addr, |
| const void *Decoder) |
| { |
| return DecodeVecShiftRImm(Inst, Imm | 0x10, 32); |
| } |
| |
| static DecodeStatus DecodeVecShiftR16Imm(MCInst *Inst, unsigned Imm, |
| uint64_t Addr, const void *Decoder) |
| { |
| return DecodeVecShiftRImm(Inst, Imm, 16); |
| } |
| |
| static DecodeStatus DecodeVecShiftR16ImmNarrow(MCInst *Inst, unsigned Imm, |
| uint64_t Addr, |
| const void *Decoder) |
| { |
| return DecodeVecShiftRImm(Inst, Imm | 0x8, 16); |
| } |
| |
| static DecodeStatus DecodeVecShiftR8Imm(MCInst *Inst, unsigned Imm, |
| uint64_t Addr, const void *Decoder) |
| { |
| return DecodeVecShiftRImm(Inst, Imm, 8); |
| } |
| |
| static DecodeStatus DecodeVecShiftL64Imm(MCInst *Inst, unsigned Imm, |
| uint64_t Addr, const void *Decoder) |
| { |
| return DecodeVecShiftLImm(Inst, Imm, 64); |
| } |
| |
| static DecodeStatus DecodeVecShiftL32Imm(MCInst *Inst, unsigned Imm, |
| uint64_t Addr, const void *Decoder) |
| { |
| return DecodeVecShiftLImm(Inst, Imm, 32); |
| } |
| |
| static DecodeStatus DecodeVecShiftL16Imm(MCInst *Inst, unsigned Imm, |
| uint64_t Addr, const void *Decoder) |
| { |
| return DecodeVecShiftLImm(Inst, Imm, 16); |
| } |
| |
| static DecodeStatus DecodeVecShiftL8Imm(MCInst *Inst, unsigned Imm, |
| uint64_t Addr, const void *Decoder) |
| { |
| return DecodeVecShiftLImm(Inst, Imm, 8); |
| } |
| |
| static DecodeStatus DecodeThreeAddrSRegInstruction(MCInst *Inst, uint32_t insn, |
| uint64_t Addr, |
| const void *Decoder) |
| { |
| unsigned Rd = fieldFromInstruction_4(insn, 0, 5); |
| unsigned Rn = fieldFromInstruction_4(insn, 5, 5); |
| unsigned Rm = fieldFromInstruction_4(insn, 16, 5); |
| unsigned shiftHi = fieldFromInstruction_4(insn, 22, 2); |
| unsigned shiftLo = fieldFromInstruction_4(insn, 10, 6); |
| unsigned shift = (shiftHi << 6) | shiftLo; |
| switch (MCInst_getOpcode(Inst)) { |
| default: |
| return Fail; |
| case AArch64_ADDWrs: |
| case AArch64_ADDSWrs: |
| case AArch64_SUBWrs: |
| case AArch64_SUBSWrs: |
| // if shift == '11' then ReservedValue() |
| if (shiftHi == 0x3) |
| return Fail; |
| // fall through |
| case AArch64_ANDWrs: |
| case AArch64_ANDSWrs: |
| case AArch64_BICWrs: |
| case AArch64_BICSWrs: |
| case AArch64_ORRWrs: |
| case AArch64_ORNWrs: |
| case AArch64_EORWrs: |
| case AArch64_EONWrs: { |
| // if sf == '0' and imm6<5> == '1' then ReservedValue() |
| if (shiftLo >> 5 == 1) |
| return Fail; |
| DecodeGPR32RegisterClass(Inst, Rd, Addr, Decoder); |
| DecodeGPR32RegisterClass(Inst, Rn, Addr, Decoder); |
| DecodeGPR32RegisterClass(Inst, Rm, Addr, Decoder); |
| break; |
| } |
| case AArch64_ADDXrs: |
| case AArch64_ADDSXrs: |
| case AArch64_SUBXrs: |
| case AArch64_SUBSXrs: |
| // if shift == '11' then ReservedValue() |
| if (shiftHi == 0x3) |
| return Fail; |
| // fall through |
| case AArch64_ANDXrs: |
| case AArch64_ANDSXrs: |
| case AArch64_BICXrs: |
| case AArch64_BICSXrs: |
| case AArch64_ORRXrs: |
| case AArch64_ORNXrs: |
| case AArch64_EORXrs: |
| case AArch64_EONXrs: |
| DecodeGPR64RegisterClass(Inst, Rd, Addr, Decoder); |
| DecodeGPR64RegisterClass(Inst, Rn, Addr, Decoder); |
| DecodeGPR64RegisterClass(Inst, Rm, Addr, Decoder); |
| break; |
| } |
| |
| MCOperand_CreateImm0(Inst, (shift)); |
| return Success; |
| } |
| |
| static DecodeStatus DecodeMoveImmInstruction(MCInst *Inst, uint32_t insn, |
| uint64_t Addr, const void *Decoder) |
| { |
| unsigned Rd = fieldFromInstruction_4(insn, 0, 5); |
| unsigned imm = fieldFromInstruction_4(insn, 5, 16); |
| unsigned shift = fieldFromInstruction_4(insn, 21, 2); |
| shift <<= 4; |
| switch (MCInst_getOpcode(Inst)) { |
| default: |
| return Fail; |
| case AArch64_MOVZWi: |
| case AArch64_MOVNWi: |
| case AArch64_MOVKWi: |
| if (shift & (1U << 5)) |
| return Fail; |
| DecodeGPR32RegisterClass(Inst, Rd, Addr, Decoder); |
| break; |
| case AArch64_MOVZXi: |
| case AArch64_MOVNXi: |
| case AArch64_MOVKXi: |
| DecodeGPR64RegisterClass(Inst, Rd, Addr, Decoder); |
| break; |
| } |
| |
| if (MCInst_getOpcode(Inst) == AArch64_MOVKWi || |
| MCInst_getOpcode(Inst) == AArch64_MOVKXi) |
| MCInst_addOperand2(Inst, (MCInst_getOperand(Inst, (0)))); |
| |
| MCOperand_CreateImm0(Inst, (imm)); |
| MCOperand_CreateImm0(Inst, (shift)); |
| return Success; |
| } |
| |
| static DecodeStatus DecodeUnsignedLdStInstruction(MCInst *Inst, uint32_t insn, |
| uint64_t Addr, |
| const void *Decoder) |
| { |
| unsigned Rt = fieldFromInstruction_4(insn, 0, 5); |
| unsigned Rn = fieldFromInstruction_4(insn, 5, 5); |
| unsigned offset = fieldFromInstruction_4(insn, 10, 12); |
| |
| switch (MCInst_getOpcode(Inst)) { |
| default: |
| return Fail; |
| case AArch64_PRFMui: |
| // Rt is an immediate in prefetch. |
| MCOperand_CreateImm0(Inst, (Rt)); |
| break; |
| case AArch64_STRBBui: |
| case AArch64_LDRBBui: |
| case AArch64_LDRSBWui: |
| case AArch64_STRHHui: |
| case AArch64_LDRHHui: |
| case AArch64_LDRSHWui: |
| case AArch64_STRWui: |
| case AArch64_LDRWui: |
| DecodeGPR32RegisterClass(Inst, Rt, Addr, Decoder); |
| break; |
| case AArch64_LDRSBXui: |
| case AArch64_LDRSHXui: |
| case AArch64_LDRSWui: |
| case AArch64_STRXui: |
| case AArch64_LDRXui: |
| DecodeGPR64RegisterClass(Inst, Rt, Addr, Decoder); |
| break; |
| case AArch64_LDRQui: |
| case AArch64_STRQui: |
| DecodeFPR128RegisterClass(Inst, Rt, Addr, Decoder); |
| break; |
| case AArch64_LDRDui: |
| case AArch64_STRDui: |
| DecodeFPR64RegisterClass(Inst, Rt, Addr, Decoder); |
| break; |
| case AArch64_LDRSui: |
| case AArch64_STRSui: |
| DecodeFPR32RegisterClass(Inst, Rt, Addr, Decoder); |
| break; |
| case AArch64_LDRHui: |
| case AArch64_STRHui: |
| DecodeFPR16RegisterClass(Inst, Rt, Addr, Decoder); |
| break; |
| case AArch64_LDRBui: |
| case AArch64_STRBui: |
| DecodeFPR8RegisterClass(Inst, Rt, Addr, Decoder); |
| break; |
| } |
| |
| DecodeGPR64spRegisterClass(Inst, Rn, Addr, Decoder); |
| // No symbols supported in Capstone |
| // if (!Decoder->tryAddingSymbolicOperand(Inst, offset, Addr, Fail, 0, 0, 4)) |
| MCOperand_CreateImm0(Inst, (offset)); |
| return Success; |
| } |
| |
| static DecodeStatus DecodeSignedLdStInstruction(MCInst *Inst, uint32_t insn, |
| uint64_t Addr, |
| const void *Decoder) |
| { |
| unsigned Rt = fieldFromInstruction_4(insn, 0, 5); |
| unsigned Rn = fieldFromInstruction_4(insn, 5, 5); |
| int64_t offset = fieldFromInstruction_4(insn, 12, 9); |
| |
| // offset is a 9-bit signed immediate, so sign extend it to |
| // fill the unsigned. |
| if (offset & (1 << (9 - 1))) |
| offset |= ~((1LL << 9) - 1); |
| |
| // First operand is always the writeback to the address register, if needed. |
| switch (MCInst_getOpcode(Inst)) { |
| default: |
| break; |
| case AArch64_LDRSBWpre: |
| case AArch64_LDRSHWpre: |
| case AArch64_STRBBpre: |
| case AArch64_LDRBBpre: |
| case AArch64_STRHHpre: |
| case AArch64_LDRHHpre: |
| case AArch64_STRWpre: |
| case AArch64_LDRWpre: |
| case AArch64_LDRSBWpost: |
| case AArch64_LDRSHWpost: |
| case AArch64_STRBBpost: |
| case AArch64_LDRBBpost: |
| case AArch64_STRHHpost: |
| case AArch64_LDRHHpost: |
| case AArch64_STRWpost: |
| case AArch64_LDRWpost: |
| case AArch64_LDRSBXpre: |
| case AArch64_LDRSHXpre: |
| case AArch64_STRXpre: |
| case AArch64_LDRSWpre: |
| case AArch64_LDRXpre: |
| case AArch64_LDRSBXpost: |
| case AArch64_LDRSHXpost: |
| case AArch64_STRXpost: |
| case AArch64_LDRSWpost: |
| case AArch64_LDRXpost: |
| case AArch64_LDRQpre: |
| case AArch64_STRQpre: |
| case AArch64_LDRQpost: |
| case AArch64_STRQpost: |
| case AArch64_LDRDpre: |
| case AArch64_STRDpre: |
| case AArch64_LDRDpost: |
| case AArch64_STRDpost: |
| case AArch64_LDRSpre: |
| case AArch64_STRSpre: |
| case AArch64_LDRSpost: |
| case AArch64_STRSpost: |
| case AArch64_LDRHpre: |
| case AArch64_STRHpre: |
| case AArch64_LDRHpost: |
| case AArch64_STRHpost: |
| case AArch64_LDRBpre: |
| case AArch64_STRBpre: |
| case AArch64_LDRBpost: |
| case AArch64_STRBpost: |
| DecodeGPR64spRegisterClass(Inst, Rn, Addr, Decoder); |
| break; |
| } |
| |
| switch (MCInst_getOpcode(Inst)) { |
| default: |
| return Fail; |
| case AArch64_PRFUMi: |
| // Rt is an immediate in prefetch. |
| MCOperand_CreateImm0(Inst, (Rt)); |
| break; |
| case AArch64_STURBBi: |
| case AArch64_LDURBBi: |
| case AArch64_LDURSBWi: |
| case AArch64_STURHHi: |
| case AArch64_LDURHHi: |
| case AArch64_LDURSHWi: |
| case AArch64_STURWi: |
| case AArch64_LDURWi: |
| case AArch64_LDTRSBWi: |
| case AArch64_LDTRSHWi: |
| case AArch64_STTRWi: |
| case AArch64_LDTRWi: |
| case AArch64_STTRHi: |
| case AArch64_LDTRHi: |
| case AArch64_LDTRBi: |
| case AArch64_STTRBi: |
| case AArch64_LDRSBWpre: |
| case AArch64_LDRSHWpre: |
| case AArch64_STRBBpre: |
| case AArch64_LDRBBpre: |
| case AArch64_STRHHpre: |
| case AArch64_LDRHHpre: |
| case AArch64_STRWpre: |
| case AArch64_LDRWpre: |
| case AArch64_LDRSBWpost: |
| case AArch64_LDRSHWpost: |
| case AArch64_STRBBpost: |
| case AArch64_LDRBBpost: |
| case AArch64_STRHHpost: |
| case AArch64_LDRHHpost: |
| case AArch64_STRWpost: |
| case AArch64_LDRWpost: |
| case AArch64_STLURBi: |
| case AArch64_STLURHi: |
| case AArch64_STLURWi: |
| case AArch64_LDAPURBi: |
| case AArch64_LDAPURSBWi: |
| case AArch64_LDAPURHi: |
| case AArch64_LDAPURSHWi: |
| case AArch64_LDAPURi: |
| DecodeGPR32RegisterClass(Inst, Rt, Addr, Decoder); |
| break; |
| case AArch64_LDURSBXi: |
| case AArch64_LDURSHXi: |
| case AArch64_LDURSWi: |
| case AArch64_STURXi: |
| case AArch64_LDURXi: |
| case AArch64_LDTRSBXi: |
| case AArch64_LDTRSHXi: |
| case AArch64_LDTRSWi: |
| case AArch64_STTRXi: |
| case AArch64_LDTRXi: |
| case AArch64_LDRSBXpre: |
| case AArch64_LDRSHXpre: |
| case AArch64_STRXpre: |
| case AArch64_LDRSWpre: |
| case AArch64_LDRXpre: |
| case AArch64_LDRSBXpost: |
| case AArch64_LDRSHXpost: |
| case AArch64_STRXpost: |
| case AArch64_LDRSWpost: |
| case AArch64_LDRXpost: |
| case AArch64_LDAPURSWi: |
| case AArch64_LDAPURSHXi: |
| case AArch64_LDAPURSBXi: |
| case AArch64_STLURXi: |
| case AArch64_LDAPURXi: |
| DecodeGPR64RegisterClass(Inst, Rt, Addr, Decoder); |
| break; |
| case AArch64_LDURQi: |
| case AArch64_STURQi: |
| case AArch64_LDRQpre: |
| case AArch64_STRQpre: |
| case AArch64_LDRQpost: |
| case AArch64_STRQpost: |
| DecodeFPR128RegisterClass(Inst, Rt, Addr, Decoder); |
| break; |
| case AArch64_LDURDi: |
| case AArch64_STURDi: |
| case AArch64_LDRDpre: |
| case AArch64_STRDpre: |
| case AArch64_LDRDpost: |
| case AArch64_STRDpost: |
| DecodeFPR64RegisterClass(Inst, Rt, Addr, Decoder); |
| break; |
| case AArch64_LDURSi: |
| case AArch64_STURSi: |
| case AArch64_LDRSpre: |
| case AArch64_STRSpre: |
| case AArch64_LDRSpost: |
| case AArch64_STRSpost: |
| DecodeFPR32RegisterClass(Inst, Rt, Addr, Decoder); |
| break; |
| case AArch64_LDURHi: |
| case AArch64_STURHi: |
| case AArch64_LDRHpre: |
| case AArch64_STRHpre: |
| case AArch64_LDRHpost: |
| case AArch64_STRHpost: |
| DecodeFPR16RegisterClass(Inst, Rt, Addr, Decoder); |
| break; |
| case AArch64_LDURBi: |
| case AArch64_STURBi: |
| case AArch64_LDRBpre: |
| case AArch64_STRBpre: |
| case AArch64_LDRBpost: |
| case AArch64_STRBpost: |
| DecodeFPR8RegisterClass(Inst, Rt, Addr, Decoder); |
| break; |
| } |
| |
| DecodeGPR64spRegisterClass(Inst, Rn, Addr, Decoder); |
| MCOperand_CreateImm0(Inst, (offset)); |
| |
| bool IsLoad = fieldFromInstruction_4(insn, 22, 1); |
| bool IsIndexed = fieldFromInstruction_4(insn, 10, 2) != 0; |
| bool IsFP = fieldFromInstruction_4(insn, 26, 1); |
| |
| // Cannot write back to a transfer register (but xzr != sp). |
| if (IsLoad && IsIndexed && !IsFP && Rn != 31 && Rt == Rn) |
| return SoftFail; |
| |
| return Success; |
| } |
| |
| static DecodeStatus DecodeExclusiveLdStInstruction(MCInst *Inst, uint32_t insn, |
| uint64_t Addr, |
| const void *Decoder) |
| { |
| unsigned Rt = fieldFromInstruction_4(insn, 0, 5); |
| unsigned Rn = fieldFromInstruction_4(insn, 5, 5); |
| unsigned Rt2 = fieldFromInstruction_4(insn, 10, 5); |
| unsigned Rs = fieldFromInstruction_4(insn, 16, 5); |
| |
| unsigned Opcode = MCInst_getOpcode(Inst); |
| switch (Opcode) { |
| default: |
| return Fail; |
| case AArch64_STLXRW: |
| case AArch64_STLXRB: |
| case AArch64_STLXRH: |
| case AArch64_STXRW: |
| case AArch64_STXRB: |
| case AArch64_STXRH: |
| DecodeGPR32RegisterClass(Inst, Rs, Addr, Decoder); |
| // fall through |
| case AArch64_LDARW: |
| case AArch64_LDARB: |
| case AArch64_LDARH: |
| case AArch64_LDAXRW: |
| case AArch64_LDAXRB: |
| case AArch64_LDAXRH: |
| case AArch64_LDXRW: |
| case AArch64_LDXRB: |
| case AArch64_LDXRH: |
| case AArch64_STLRW: |
| case AArch64_STLRB: |
| case AArch64_STLRH: |
| case AArch64_STLLRW: |
| case AArch64_STLLRB: |
| case AArch64_STLLRH: |
| case AArch64_LDLARW: |
| case AArch64_LDLARB: |
| case AArch64_LDLARH: |
| DecodeGPR32RegisterClass(Inst, Rt, Addr, Decoder); |
| break; |
| case AArch64_STLXRX: |
| case AArch64_STXRX: |
| DecodeGPR32RegisterClass(Inst, Rs, Addr, Decoder); |
| // fall through |
| case AArch64_LDARX: |
| case AArch64_LDAXRX: |
| case AArch64_LDXRX: |
| case AArch64_STLRX: |
| case AArch64_LDLARX: |
| case AArch64_STLLRX: |
| DecodeGPR64RegisterClass(Inst, Rt, Addr, Decoder); |
| break; |
| case AArch64_STLXPW: |
| case AArch64_STXPW: |
| DecodeGPR32RegisterClass(Inst, Rs, Addr, Decoder); |
| // fall through |
| case AArch64_LDAXPW: |
| case AArch64_LDXPW: |
| DecodeGPR32RegisterClass(Inst, Rt, Addr, Decoder); |
| DecodeGPR32RegisterClass(Inst, Rt2, Addr, Decoder); |
| break; |
| case AArch64_STLXPX: |
| case AArch64_STXPX: |
| DecodeGPR32RegisterClass(Inst, Rs, Addr, Decoder); |
| // fall through |
| case AArch64_LDAXPX: |
| case AArch64_LDXPX: |
| DecodeGPR64RegisterClass(Inst, Rt, Addr, Decoder); |
| DecodeGPR64RegisterClass(Inst, Rt2, Addr, Decoder); |
| break; |
| } |
| |
| DecodeGPR64spRegisterClass(Inst, Rn, Addr, Decoder); |
| |
| // You shouldn't load to the same register twice in an instruction... |
| if ((Opcode == AArch64_LDAXPW || Opcode == AArch64_LDXPW || |
| Opcode == AArch64_LDAXPX || Opcode == AArch64_LDXPX) && |
| Rt == Rt2) |
| return SoftFail; |
| |
| return Success; |
| } |
| |
| static DecodeStatus DecodePairLdStInstruction(MCInst *Inst, uint32_t insn, |
| uint64_t Addr, |
| const void *Decoder) |
| { |
| unsigned Rt = fieldFromInstruction_4(insn, 0, 5); |
| unsigned Rn = fieldFromInstruction_4(insn, 5, 5); |
| unsigned Rt2 = fieldFromInstruction_4(insn, 10, 5); |
| int64_t offset = fieldFromInstruction_4(insn, 15, 7); |
| bool IsLoad = fieldFromInstruction_4(insn, 22, 1); |
| |
| // offset is a 7-bit signed immediate, so sign extend it to |
| // fill the unsigned. |
| if (offset & (1 << (7 - 1))) |
| offset |= ~((1LL << 7) - 1); |
| |
| unsigned Opcode = MCInst_getOpcode(Inst); |
| bool NeedsDisjointWritebackTransfer = false; |
| |
| // First operand is always writeback of base register. |
| switch (Opcode) { |
| default: |
| break; |
| case AArch64_LDPXpost: |
| case AArch64_STPXpost: |
| case AArch64_LDPSWpost: |
| case AArch64_LDPXpre: |
| case AArch64_STPXpre: |
| case AArch64_LDPSWpre: |
| case AArch64_LDPWpost: |
| case AArch64_STPWpost: |
| case AArch64_LDPWpre: |
| case AArch64_STPWpre: |
| case AArch64_LDPQpost: |
| case AArch64_STPQpost: |
| case AArch64_LDPQpre: |
| case AArch64_STPQpre: |
| case AArch64_LDPDpost: |
| case AArch64_STPDpost: |
| case AArch64_LDPDpre: |
| case AArch64_STPDpre: |
| case AArch64_LDPSpost: |
| case AArch64_STPSpost: |
| case AArch64_LDPSpre: |
| case AArch64_STPSpre: |
| case AArch64_STGPpre: |
| case AArch64_STGPpost: |
| DecodeGPR64spRegisterClass(Inst, Rn, Addr, Decoder); |
| break; |
| } |
| |
| switch (Opcode) { |
| default: |
| return Fail; |
| case AArch64_LDPXpost: |
| case AArch64_STPXpost: |
| case AArch64_LDPSWpost: |
| case AArch64_LDPXpre: |
| case AArch64_STPXpre: |
| case AArch64_LDPSWpre: |
| case AArch64_STGPpre: |
| case AArch64_STGPpost: |
| NeedsDisjointWritebackTransfer = true; |
| // fall through |
| case AArch64_LDNPXi: |
| case AArch64_STNPXi: |
| case AArch64_LDPXi: |
| case AArch64_STPXi: |
| case AArch64_LDPSWi: |
| case AArch64_STGPi: |
| DecodeGPR64RegisterClass(Inst, Rt, Addr, Decoder); |
| DecodeGPR64RegisterClass(Inst, Rt2, Addr, Decoder); |
| break; |
| case AArch64_LDPWpost: |
| case AArch64_STPWpost: |
| case AArch64_LDPWpre: |
| case AArch64_STPWpre: |
| NeedsDisjointWritebackTransfer = true; |
| // fall through |
| case AArch64_LDNPWi: |
| case AArch64_STNPWi: |
| case AArch64_LDPWi: |
| case AArch64_STPWi: |
| DecodeGPR32RegisterClass(Inst, Rt, Addr, Decoder); |
| DecodeGPR32RegisterClass(Inst, Rt2, Addr, Decoder); |
| break; |
| case AArch64_LDNPQi: |
| case AArch64_STNPQi: |
| case AArch64_LDPQpost: |
| case AArch64_STPQpost: |
| case AArch64_LDPQi: |
| case AArch64_STPQi: |
| case AArch64_LDPQpre: |
| case AArch64_STPQpre: |
| DecodeFPR128RegisterClass(Inst, Rt, Addr, Decoder); |
| DecodeFPR128RegisterClass(Inst, Rt2, Addr, Decoder); |
| break; |
| case AArch64_LDNPDi: |
| case AArch64_STNPDi: |
| case AArch64_LDPDpost: |
| case AArch64_STPDpost: |
| case AArch64_LDPDi: |
| case AArch64_STPDi: |
| case AArch64_LDPDpre: |
| case AArch64_STPDpre: |
| DecodeFPR64RegisterClass(Inst, Rt, Addr, Decoder); |
| DecodeFPR64RegisterClass(Inst, Rt2, Addr, Decoder); |
| break; |
| case AArch64_LDNPSi: |
| case AArch64_STNPSi: |
| case AArch64_LDPSpost: |
| case AArch64_STPSpost: |
| case AArch64_LDPSi: |
| case AArch64_STPSi: |
| case AArch64_LDPSpre: |
| case AArch64_STPSpre: |
| DecodeFPR32RegisterClass(Inst, Rt, Addr, Decoder); |
| DecodeFPR32RegisterClass(Inst, Rt2, Addr, Decoder); |
| break; |
| } |
| |
| DecodeGPR64spRegisterClass(Inst, Rn, Addr, Decoder); |
| MCOperand_CreateImm0(Inst, (offset)); |
| |
| // You shouldn't load to the same register twice in an instruction... |
| if (IsLoad && Rt == Rt2) |
| return SoftFail; |
| |
| // ... or do any operation that writes-back to a transfer register. But note |
| // that "stp xzr, xzr, [sp], #4" is fine because xzr and sp are different. |
| if (NeedsDisjointWritebackTransfer && Rn != 31 && (Rt == Rn || Rt2 == Rn)) |
| return SoftFail; |
| |
| return Success; |
| } |
| |
| static DecodeStatus DecodeAuthLoadInstruction(MCInst *Inst, uint32_t insn, |
| uint64_t Addr, |
| const void *Decoder) |
| { |
| unsigned Rt = fieldFromInstruction_4(insn, 0, 5); |
| unsigned Rn = fieldFromInstruction_4(insn, 5, 5); |
| uint64_t offset = fieldFromInstruction_4(insn, 22, 1) << 9 | |
| fieldFromInstruction_4(insn, 12, 9); |
| unsigned writeback = fieldFromInstruction_4(insn, 11, 1); |
| |
| switch (MCInst_getOpcode(Inst)) { |
| default: |
| return Fail; |
| case AArch64_LDRAAwriteback: |
| case AArch64_LDRABwriteback: |
| DecodeGPR64spRegisterClass(Inst, Rn /* writeback register */, Addr, |
| Decoder); |
| break; |
| case AArch64_LDRAAindexed: |
| case AArch64_LDRABindexed: |
| break; |
| } |
| |
| DecodeGPR64RegisterClass(Inst, Rt, Addr, Decoder); |
| DecodeGPR64spRegisterClass(Inst, Rn, Addr, Decoder); |
| CONCAT(DecodeSImm, 10)(Inst, offset, Addr, Decoder); |
| |
| if (writeback && Rt == Rn && Rn != 31) { |
| return SoftFail; |
| } |
| |
| return Success; |
| } |
| |
| static DecodeStatus DecodeAddSubERegInstruction(MCInst *Inst, uint32_t insn, |
| uint64_t Addr, |
| const void *Decoder) |
| { |
| unsigned Rd = fieldFromInstruction_4(insn, 0, 5); |
| unsigned Rn = fieldFromInstruction_4(insn, 5, 5); |
| unsigned Rm = fieldFromInstruction_4(insn, 16, 5); |
| unsigned extend = fieldFromInstruction_4(insn, 10, 6); |
| |
| unsigned shift = extend & 0x7; |
| if (shift > 4) |
| return Fail; |
| |
| switch (MCInst_getOpcode(Inst)) { |
| default: |
| return Fail; |
| case AArch64_ADDWrx: |
| case AArch64_SUBWrx: |
| DecodeGPR32spRegisterClass(Inst, Rd, Addr, Decoder); |
| DecodeGPR32spRegisterClass(Inst, Rn, Addr, Decoder); |
| DecodeGPR32RegisterClass(Inst, Rm, Addr, Decoder); |
| break; |
| case AArch64_ADDSWrx: |
| case AArch64_SUBSWrx: |
| DecodeGPR32RegisterClass(Inst, Rd, Addr, Decoder); |
| DecodeGPR32spRegisterClass(Inst, Rn, Addr, Decoder); |
| DecodeGPR32RegisterClass(Inst, Rm, Addr, Decoder); |
| break; |
| case AArch64_ADDXrx: |
| case AArch64_SUBXrx: |
| DecodeGPR64spRegisterClass(Inst, Rd, Addr, Decoder); |
| DecodeGPR64spRegisterClass(Inst, Rn, Addr, Decoder); |
| DecodeGPR32RegisterClass(Inst, Rm, Addr, Decoder); |
| break; |
| case AArch64_ADDSXrx: |
| case AArch64_SUBSXrx: |
| DecodeGPR64RegisterClass(Inst, Rd, Addr, Decoder); |
| DecodeGPR64spRegisterClass(Inst, Rn, Addr, Decoder); |
| DecodeGPR32RegisterClass(Inst, Rm, Addr, Decoder); |
| break; |
| case AArch64_ADDXrx64: |
| case AArch64_SUBXrx64: |
| DecodeGPR64spRegisterClass(Inst, Rd, Addr, Decoder); |
| DecodeGPR64spRegisterClass(Inst, Rn, Addr, Decoder); |
| DecodeGPR64RegisterClass(Inst, Rm, Addr, Decoder); |
| break; |
| case AArch64_SUBSXrx64: |
| case AArch64_ADDSXrx64: |
| DecodeGPR64RegisterClass(Inst, Rd, Addr, Decoder); |
| DecodeGPR64spRegisterClass(Inst, Rn, Addr, Decoder); |
| DecodeGPR64RegisterClass(Inst, Rm, Addr, Decoder); |
| break; |
| } |
| |
| MCOperand_CreateImm0(Inst, (extend)); |
| return Success; |
| } |
| |
| static DecodeStatus DecodeLogicalImmInstruction(MCInst *Inst, uint32_t insn, |
| uint64_t Addr, |
| const void *Decoder) |
| { |
| unsigned Rd = fieldFromInstruction_4(insn, 0, 5); |
| unsigned Rn = fieldFromInstruction_4(insn, 5, 5); |
| unsigned Datasize = fieldFromInstruction_4(insn, 31, 1); |
| unsigned imm; |
| |
| if (Datasize) { |
| if (MCInst_getOpcode(Inst) == AArch64_ANDSXri) |
| DecodeGPR64RegisterClass(Inst, Rd, Addr, Decoder); |
| else |
| DecodeGPR64spRegisterClass(Inst, Rd, Addr, Decoder); |
| DecodeGPR64RegisterClass(Inst, Rn, Addr, Decoder); |
| imm = fieldFromInstruction_4(insn, 10, 13); |
| if (!AArch64_AM_isValidDecodeLogicalImmediate(imm, 64)) |
| return Fail; |
| } else { |
| if (MCInst_getOpcode(Inst) == AArch64_ANDSWri) |
| DecodeGPR32RegisterClass(Inst, Rd, Addr, Decoder); |
| else |
| DecodeGPR32spRegisterClass(Inst, Rd, Addr, Decoder); |
| DecodeGPR32RegisterClass(Inst, Rn, Addr, Decoder); |
| imm = fieldFromInstruction_4(insn, 10, 12); |
| if (!AArch64_AM_isValidDecodeLogicalImmediate(imm, 32)) |
| return Fail; |
| } |
| MCOperand_CreateImm0(Inst, (imm)); |
| return Success; |
| } |
| |
| static DecodeStatus DecodeModImmInstruction(MCInst *Inst, uint32_t insn, |
| uint64_t Addr, const void *Decoder) |
| { |
| unsigned Rd = fieldFromInstruction_4(insn, 0, 5); |
| unsigned cmode = fieldFromInstruction_4(insn, 12, 4); |
| unsigned imm = fieldFromInstruction_4(insn, 16, 3) << 5; |
| imm |= fieldFromInstruction_4(insn, 5, 5); |
| |
| if (MCInst_getOpcode(Inst) == AArch64_MOVID) |
| DecodeFPR64RegisterClass(Inst, Rd, Addr, Decoder); |
| else |
| DecodeFPR128RegisterClass(Inst, Rd, Addr, Decoder); |
| |
| MCOperand_CreateImm0(Inst, (imm)); |
| |
| switch (MCInst_getOpcode(Inst)) { |
| default: |
| break; |
| case AArch64_MOVIv4i16: |
| case AArch64_MOVIv8i16: |
| case AArch64_MVNIv4i16: |
| case AArch64_MVNIv8i16: |
| case AArch64_MOVIv2i32: |
| case AArch64_MOVIv4i32: |
| case AArch64_MVNIv2i32: |
| case AArch64_MVNIv4i32: |
| MCOperand_CreateImm0(Inst, ((cmode & 6) << 2)); |
| break; |
| case AArch64_MOVIv2s_msl: |
| case AArch64_MOVIv4s_msl: |
| case AArch64_MVNIv2s_msl: |
| case AArch64_MVNIv4s_msl: |
| MCOperand_CreateImm0(Inst, ((cmode & 1) ? 0x110 : 0x108)); |
| break; |
| } |
| |
| return Success; |
| } |
| |
| static DecodeStatus DecodeModImmTiedInstruction(MCInst *Inst, uint32_t insn, |
| uint64_t Addr, |
| const void *Decoder) |
| { |
| unsigned Rd = fieldFromInstruction_4(insn, 0, 5); |
| unsigned cmode = fieldFromInstruction_4(insn, 12, 4); |
| unsigned imm = fieldFromInstruction_4(insn, 16, 3) << 5; |
| imm |= fieldFromInstruction_4(insn, 5, 5); |
| |
| // Tied operands added twice. |
| DecodeFPR128RegisterClass(Inst, Rd, Addr, Decoder); |
| DecodeFPR128RegisterClass(Inst, Rd, Addr, Decoder); |
| |
| MCOperand_CreateImm0(Inst, (imm)); |
| MCOperand_CreateImm0(Inst, ((cmode & 6) << 2)); |
| |
| return Success; |
| } |
| |
| static DecodeStatus DecodeAdrInstruction(MCInst *Inst, uint32_t insn, |
| uint64_t Addr, const void *Decoder) |
| { |
| unsigned Rd = fieldFromInstruction_4(insn, 0, 5); |
| int64_t imm = fieldFromInstruction_4(insn, 5, 19) << 2; |
| imm |= fieldFromInstruction_4(insn, 29, 2); |
| |
| // Sign-extend the 21-bit immediate. |
| if (imm & (1 << (21 - 1))) |
| imm |= ~((1LL << 21) - 1); |
| |
| DecodeGPR64RegisterClass(Inst, Rd, Addr, Decoder); |
| // No symbols supported in Capstone |
| // if (!Decoder->tryAddingSymbolicOperand(Inst, imm, Addr, Fail, 0, 0, 4)) |
| MCOperand_CreateImm0(Inst, (imm)); |
| |
| return Success; |
| } |
| |
| static DecodeStatus DecodeAddSubImmShift(MCInst *Inst, uint32_t insn, |
| uint64_t Addr, const void *Decoder) |
| { |
| unsigned Rd = fieldFromInstruction_4(insn, 0, 5); |
| unsigned Rn = fieldFromInstruction_4(insn, 5, 5); |
| unsigned Imm = fieldFromInstruction_4(insn, 10, 14); |
| unsigned S = fieldFromInstruction_4(insn, 29, 1); |
| unsigned Datasize = fieldFromInstruction_4(insn, 31, 1); |
| |
| unsigned ShifterVal = (Imm >> 12) & 3; |
| unsigned ImmVal = Imm & 0xFFF; |
| |
| if (ShifterVal != 0 && ShifterVal != 1) |
| return Fail; |
| |
| if (Datasize) { |
| if (Rd == 31 && !S) |
| DecodeGPR64spRegisterClass(Inst, Rd, Addr, Decoder); |
| else |
| DecodeGPR64RegisterClass(Inst, Rd, Addr, Decoder); |
| DecodeGPR64spRegisterClass(Inst, Rn, Addr, Decoder); |
| } else { |
| if (Rd == 31 && !S) |
| DecodeGPR32spRegisterClass(Inst, Rd, Addr, Decoder); |
| else |
| DecodeGPR32RegisterClass(Inst, Rd, Addr, Decoder); |
| DecodeGPR32spRegisterClass(Inst, Rn, Addr, Decoder); |
| } |
| |
| // No symbols supported in Capstone |
| // if (!Decoder->tryAddingSymbolicOperand(Inst, Imm, Addr, Fail, 0, 0, 4)) |
| MCOperand_CreateImm0(Inst, (ImmVal)); |
| MCOperand_CreateImm0(Inst, (12 * ShifterVal)); |
| return Success; |
| } |
| |
| static DecodeStatus DecodeUnconditionalBranch(MCInst *Inst, uint32_t insn, |
| uint64_t Addr, |
| const void *Decoder) |
| { |
| int64_t imm = fieldFromInstruction_4(insn, 0, 26); |
| |
| // Sign-extend the 26-bit immediate. |
| if (imm & (1 << (26 - 1))) |
| imm |= ~((1LL << 26) - 1); |
| |
| // No symbols supported in Capstone |
| // if (!Decoder->tryAddingSymbolicOperand(Inst, imm * 4, Addr, true, 0, 0, 4)) |
| MCOperand_CreateImm0(Inst, (imm)); |
| |
| return Success; |
| } |
| |
| static bool isInvalidPState(uint64_t Op1, uint64_t Op2) |
| { |
| return Op1 == 0 && (Op2 == 0 || // CFINV |
| Op2 == 1 || // XAFlag |
| Op2 == 2); // AXFlag |
| } |
| |
| static DecodeStatus DecodeSystemPStateImm0_15Instruction(MCInst *Inst, |
| uint32_t insn, |
| uint64_t Addr, |
| const void *Decoder) |
| { |
| uint64_t op1 = fieldFromInstruction_4(insn, 16, 3); |
| uint64_t op2 = fieldFromInstruction_4(insn, 5, 3); |
| uint64_t imm = fieldFromInstruction_4(insn, 8, 4); |
| uint64_t pstate_field = (op1 << 3) | op2; |
| |
| if (isInvalidPState(op1, op2)) |
| return Fail; |
| |
| MCOperand_CreateImm0(Inst, (pstate_field)); |
| MCOperand_CreateImm0(Inst, (imm)); |
| |
| const AArch64PState_PStateImm0_15 *PState = AArch64PState_lookupPStateImm0_15ByEncoding(pstate_field); |
| if (PState && |
| AArch64_testFeatureList(Inst->csh->mode, PState->FeaturesRequired)) |
| return Success; |
| return Fail; |
| } |
| |
| static DecodeStatus DecodeSystemPStateImm0_1Instruction(MCInst *Inst, |
| uint32_t insn, |
| uint64_t Addr, |
| const void *Decoder) |
| { |
| uint64_t op1 = fieldFromInstruction_4(insn, 16, 3); |
| uint64_t op2 = fieldFromInstruction_4(insn, 5, 3); |
| uint64_t crm_high = fieldFromInstruction_4(insn, 9, 3); |
| uint64_t imm = fieldFromInstruction_4(insn, 8, 1); |
| uint64_t pstate_field = (crm_high << 6) | (op1 << 3) | op2; |
| |
| if (isInvalidPState(op1, op2)) |
| return Fail; |
| |
| MCOperand_CreateImm0(Inst, (pstate_field)); |
| MCOperand_CreateImm0(Inst, (imm)); |
| |
| const AArch64PState_PStateImm0_1 *PState = AArch64PState_lookupPStateImm0_1ByEncoding(pstate_field); |
| if (PState && |
| AArch64_testFeatureList(Inst->csh->mode, PState->FeaturesRequired)) |
| return Success; |
| return Fail; |
| } |
| |
| static DecodeStatus DecodeTestAndBranch(MCInst *Inst, uint32_t insn, |
| uint64_t Addr, const void *Decoder) |
| { |
| uint64_t Rt = fieldFromInstruction_4(insn, 0, 5); |
| uint64_t bit = fieldFromInstruction_4(insn, 31, 1) << 5; |
| bit |= fieldFromInstruction_4(insn, 19, 5); |
| int64_t dst = fieldFromInstruction_4(insn, 5, 14); |
| |
| // Sign-extend 14-bit immediate. |
| if (dst & (1 << (14 - 1))) |
| dst |= ~((1LL << 14) - 1); |
| |
| if (fieldFromInstruction_4(insn, 31, 1) == 0) |
| DecodeGPR32RegisterClass(Inst, Rt, Addr, Decoder); |
| else |
| DecodeGPR64RegisterClass(Inst, Rt, Addr, Decoder); |
| MCOperand_CreateImm0(Inst, (bit)); |
| // No symbols supported in Capstone |
| // if (!Decoder->tryAddingSymbolicOperand(Inst, dst * 4, Addr, true, 0, 0, 4)) |
| MCOperand_CreateImm0(Inst, (dst)); |
| |
| return Success; |
| } |
| |
| static DecodeStatus DecodeGPRSeqPairsClassRegisterClass(MCInst *Inst, |
| unsigned RegClassID, |
| unsigned RegNo, |
| uint64_t Addr, |
| const void *Decoder) |
| { |
| // Register number must be even (see CASP instruction) |
| if (RegNo & 0x1) |
| return Fail; |
| |
| unsigned Reg = AArch64MCRegisterClasses[RegClassID].RegsBegin[RegNo / 2]; |
| MCOperand_CreateReg0(Inst, (Reg)); |
| return Success; |
| } |
| |
| static DecodeStatus DecodeWSeqPairsClassRegisterClass(MCInst *Inst, |
| unsigned RegNo, |
| uint64_t Addr, |
| const void *Decoder) |
| { |
| return DecodeGPRSeqPairsClassRegisterClass( |
| Inst, AArch64_WSeqPairsClassRegClassID, RegNo, Addr, Decoder); |
| } |
| |
| static DecodeStatus DecodeXSeqPairsClassRegisterClass(MCInst *Inst, |
| unsigned RegNo, |
| uint64_t Addr, |
| const void *Decoder) |
| { |
| return DecodeGPRSeqPairsClassRegisterClass( |
| Inst, AArch64_XSeqPairsClassRegClassID, RegNo, Addr, Decoder); |
| } |
| |
| static DecodeStatus DecodeSyspXzrInstruction(MCInst *Inst, uint32_t insn, |
| uint64_t Addr, const void *Decoder) |
| { |
| unsigned op1 = fieldFromInstruction_4(insn, 16, 3); |
| unsigned CRn = fieldFromInstruction_4(insn, 12, 4); |
| unsigned CRm = fieldFromInstruction_4(insn, 8, 4); |
| unsigned op2 = fieldFromInstruction_4(insn, 5, 3); |
| unsigned Rt = fieldFromInstruction_4(insn, 0, 5); |
| if (Rt != 0x1f) |
| return Fail; |
| |
| MCOperand_CreateImm0(Inst, (op1)); |
| MCOperand_CreateImm0(Inst, (CRn)); |
| MCOperand_CreateImm0(Inst, (CRm)); |
| MCOperand_CreateImm0(Inst, (op2)); |
| DecodeGPR64RegisterClass(Inst, Rt, Addr, Decoder); |
| |
| return Success; |
| } |
| |
| static DecodeStatus DecodeSVELogicalImmInstruction(MCInst *Inst, uint32_t insn, |
| uint64_t Addr, |
| const void *Decoder) |
| { |
| unsigned Zdn = fieldFromInstruction_4(insn, 0, 5); |
| unsigned imm = fieldFromInstruction_4(insn, 5, 13); |
| if (!AArch64_AM_isValidDecodeLogicalImmediate(imm, 64)) |
| return Fail; |
| |
| // The same (tied) operand is added twice to the instruction. |
| DecodeZPRRegisterClass(Inst, Zdn, Addr, Decoder); |
| if (MCInst_getOpcode(Inst) != AArch64_DUPM_ZI) |
| DecodeZPRRegisterClass(Inst, Zdn, Addr, Decoder); |
| MCOperand_CreateImm0(Inst, (imm)); |
| return Success; |
| } |
| |
| #define DEFINE_DecodeSImm(Bits) \ |
| static DecodeStatus CONCAT(DecodeSImm, Bits)( \ |
| MCInst * Inst, uint64_t Imm, uint64_t Address, const void *Decoder) \ |
| { \ |
| if (Imm & ~((1LL << Bits) - 1)) \ |
| return Fail; \ |
| \ |
| if (Imm & (1 << (Bits - 1))) \ |
| Imm |= ~((1LL << Bits) - 1); \ |
| \ |
| MCOperand_CreateImm0(Inst, (Imm)); \ |
| return Success; \ |
| } |
| DEFINE_DecodeSImm(4); |
| DEFINE_DecodeSImm(5); |
| DEFINE_DecodeSImm(6); |
| DEFINE_DecodeSImm(8); |
| DEFINE_DecodeSImm(9); |
| DEFINE_DecodeSImm(10); |
| |
| // Decode 8-bit signed/unsigned immediate for a given element width. |
| #define DEFINE_DecodeImm8OptLsl(ElementWidth) \ |
| static DecodeStatus CONCAT(DecodeImm8OptLsl, ElementWidth)( \ |
| MCInst * Inst, unsigned Imm, uint64_t Addr, const void *Decoder) \ |
| { \ |
| unsigned Val = (uint8_t)Imm; \ |
| unsigned Shift = (Imm & 0x100) ? 8 : 0; \ |
| if (ElementWidth == 8 && Shift) \ |
| return Fail; \ |
| MCOperand_CreateImm0(Inst, (Val)); \ |
| MCOperand_CreateImm0(Inst, (Shift)); \ |
| return Success; \ |
| } |
| DEFINE_DecodeImm8OptLsl(8); |
| DEFINE_DecodeImm8OptLsl(16); |
| DEFINE_DecodeImm8OptLsl(32); |
| DEFINE_DecodeImm8OptLsl(64); |
| |
| // Decode uimm4 ranged from 1-16. |
| static DecodeStatus DecodeSVEIncDecImm(MCInst *Inst, unsigned Imm, |
| uint64_t Addr, const void *Decoder) |
| { |
| MCOperand_CreateImm0(Inst, (Imm + 1)); |
| return Success; |
| } |
| |
| static DecodeStatus DecodeSVCROp(MCInst *Inst, unsigned Imm, uint64_t Address, |
| const void *Decoder) |
| { |
| if (AArch64SVCR_lookupSVCRByEncoding(Imm)) { |
| MCOperand_CreateImm0(Inst, (Imm)); |
| return Success; |
| } |
| return Fail; |
| } |
| |
| static DecodeStatus DecodeCPYMemOpInstruction(MCInst *Inst, uint32_t insn, |
| uint64_t Addr, |
| const void *Decoder) |
| { |
| unsigned Rd = fieldFromInstruction_4(insn, 0, 5); |
| unsigned Rs = fieldFromInstruction_4(insn, 16, 5); |
| unsigned Rn = fieldFromInstruction_4(insn, 5, 5); |
| |
| // None of the registers may alias: if they do, then the instruction is not |
| // merely unpredictable but actually entirely unallocated. |
| if (Rd == Rs || Rs == Rn || Rd == Rn) |
| return MCDisassembler_Fail; |
| |
| // All three register operands are written back, so they all appear |
| // twice in the operand list, once as outputs and once as inputs. |
| if (!DecodeGPR64commonRegisterClass(Inst, Rd, Addr, Decoder) || |
| !DecodeGPR64commonRegisterClass(Inst, Rs, Addr, Decoder) || |
| !DecodeGPR64RegisterClass(Inst, Rn, Addr, Decoder) || |
| !DecodeGPR64commonRegisterClass(Inst, Rd, Addr, Decoder) || |
| !DecodeGPR64commonRegisterClass(Inst, Rs, Addr, Decoder) || |
| !DecodeGPR64RegisterClass(Inst, Rn, Addr, Decoder)) |
| return MCDisassembler_Fail; |
| |
| return MCDisassembler_Success; |
| } |
| |
| static DecodeStatus DecodeSETMemOpInstruction(MCInst *Inst, uint32_t insn, |
| uint64_t Addr, |
| const void *Decoder) |
| { |
| unsigned Rd = fieldFromInstruction_4(insn, 0, 5); |
| unsigned Rm = fieldFromInstruction_4(insn, 16, 5); |
| unsigned Rn = fieldFromInstruction_4(insn, 5, 5); |
| |
| // None of the registers may alias: if they do, then the instruction is not |
| // merely unpredictable but actually entirely unallocated. |
| if (Rd == Rm || Rm == Rn || Rd == Rn) |
| return MCDisassembler_Fail; |
| |
| // Rd and Rn (not Rm) register operands are written back, so they appear |
| // twice in the operand list, once as outputs and once as inputs. |
| if (!DecodeGPR64commonRegisterClass(Inst, Rd, Addr, Decoder) || |
| !DecodeGPR64RegisterClass(Inst, Rn, Addr, Decoder) || |
| !DecodeGPR64commonRegisterClass(Inst, Rd, Addr, Decoder) || |
| !DecodeGPR64RegisterClass(Inst, Rn, Addr, Decoder) || |
| !DecodeGPR64RegisterClass(Inst, Rm, Addr, Decoder)) |
| return MCDisassembler_Fail; |
| |
| return MCDisassembler_Success; |
| } |
| |
| static DecodeStatus DecodePRFMRegInstruction(MCInst *Inst, uint32_t insn, |
| uint64_t Addr, const void *Decoder) |
| { |
| // PRFM with Rt = '11xxx' should be decoded as RPRFM. |
| // Fail to decode and defer to fallback decoder table to decode RPRFM. |
| unsigned Mask = 0x18; |
| uint64_t Rt = fieldFromInstruction_4(insn, 0, 5); |
| if ((Rt & Mask) == Mask) |
| return Fail; |
| |
| uint64_t Rn = fieldFromInstruction_4(insn, 5, 5); |
| uint64_t Shift = fieldFromInstruction_4(insn, 12, 1); |
| uint64_t Extend = fieldFromInstruction_4(insn, 15, 1); |
| uint64_t Rm = fieldFromInstruction_4(insn, 16, 5); |
| |
| MCOperand_CreateImm0(Inst, (Rt)); |
| DecodeGPR64spRegisterClass(Inst, Rn, Addr, Decoder); |
| |
| switch (MCInst_getOpcode(Inst)) { |
| default: |
| return Fail; |
| case AArch64_PRFMroW: |
| DecodeGPR32RegisterClass(Inst, Rm, Addr, Decoder); |
| break; |
| case AArch64_PRFMroX: |
| DecodeGPR64RegisterClass(Inst, Rm, Addr, Decoder); |
| break; |
| } |
| |
| DecodeMemExtend(Inst, (Extend << 1) | Shift, Addr, Decoder); |
| |
| return Success; |
| } |