2160 lines
66 KiB
C
2160 lines
66 KiB
C
/* 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;
|
|
}
|