X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FTarget%2FARM%2FDisassembler%2FARMDisassembler.cpp;h=4d5122a7620f92a763ff93fc184fb534fdceec6c;hb=765aab84d619c67a9a44d97b78c696d3d9bd4fb9;hp=39a5af9e60555c4b14a1a4beafb68298be7aa073;hpb=ce046b98ed6c351779fc43599a80d588752bc1ca;p=oota-llvm.git diff --git a/lib/Target/ARM/Disassembler/ARMDisassembler.cpp b/lib/Target/ARM/Disassembler/ARMDisassembler.cpp index 39a5af9e605..4d5122a7620 100644 --- a/lib/Target/ARM/Disassembler/ARMDisassembler.cpp +++ b/lib/Target/ARM/Disassembler/ARMDisassembler.cpp @@ -7,8 +7,6 @@ // //===----------------------------------------------------------------------===// -#define DEBUG_TYPE "arm-disassembler" - #include "llvm/MC/MCDisassembler.h" #include "MCTargetDesc/ARMAddressingModes.h" #include "MCTargetDesc/ARMBaseInfo.h" @@ -22,13 +20,14 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/LEB128.h" -#include "llvm/Support/MemoryObject.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/raw_ostream.h" #include using namespace llvm; +#define DEBUG_TYPE "arm-disassembler" + typedef MCDisassembler::DecodeStatus DecodeStatus; namespace { @@ -85,46 +84,34 @@ namespace { } namespace { -/// ARMDisassembler - ARM disassembler for all ARM platforms. +/// ARM disassembler for all ARM platforms. class ARMDisassembler : public MCDisassembler { public: - /// Constructor - Initializes the disassembler. - /// - ARMDisassembler(const MCSubtargetInfo &STI) : - MCDisassembler(STI) { + ARMDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx) : + MCDisassembler(STI, Ctx) { } - ~ARMDisassembler() { - } + ~ARMDisassembler() {} - /// getInstruction - See MCDisassembler. - DecodeStatus getInstruction(MCInst &instr, - uint64_t &size, - const MemoryObject ®ion, - uint64_t address, - raw_ostream &vStream, - raw_ostream &cStream) const; + DecodeStatus getInstruction(MCInst &Instr, uint64_t &Size, + ArrayRef Bytes, uint64_t Address, + raw_ostream &VStream, + raw_ostream &CStream) const override; }; -/// ThumbDisassembler - Thumb disassembler for all Thumb platforms. +/// Thumb disassembler for all Thumb platforms. class ThumbDisassembler : public MCDisassembler { public: - /// Constructor - Initializes the disassembler. - /// - ThumbDisassembler(const MCSubtargetInfo &STI) : - MCDisassembler(STI) { + ThumbDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx) : + MCDisassembler(STI, Ctx) { } - ~ThumbDisassembler() { - } + ~ThumbDisassembler() {} - /// getInstruction - See MCDisassembler. - DecodeStatus getInstruction(MCInst &instr, - uint64_t &size, - const MemoryObject ®ion, - uint64_t address, - raw_ostream &vStream, - raw_ostream &cStream) const; + DecodeStatus getInstruction(MCInst &Instr, uint64_t &Size, + ArrayRef Bytes, uint64_t Address, + raw_ostream &VStream, + raw_ostream &CStream) const override; private: mutable ITStatus ITBlock; @@ -189,8 +176,6 @@ static DecodeStatus DecodePredicateOperand(MCInst &Inst, unsigned Val, uint64_t Address, const void *Decoder); static DecodeStatus DecodeCCOutOperand(MCInst &Inst, unsigned Val, uint64_t Address, const void *Decoder); -static DecodeStatus DecodeSOImmOperand(MCInst &Inst, unsigned Val, - uint64_t Address, const void *Decoder); static DecodeStatus DecodeRegListOperand(MCInst &Inst, unsigned Val, uint64_t Address, const void *Decoder); static DecodeStatus DecodeSPRRegListOperand(MCInst &Inst, unsigned Val, @@ -285,6 +270,8 @@ static DecodeStatus DecodeInstSyncBarrierOption(MCInst &Inst, unsigned Insn, uint64_t Address, const void *Decoder); static DecodeStatus DecodeMSRMask(MCInst &Inst, unsigned Insn, uint64_t Address, const void *Decoder); +static DecodeStatus DecodeBankedReg(MCInst &Inst, unsigned Insn, + uint64_t Address, const void *Decoder); static DecodeStatus DecodeDoubleRegLoad(MCInst &Inst, unsigned Insn, uint64_t Address, const void *Decoder); static DecodeStatus DecodeDoubleRegStore(MCInst &Inst, unsigned Insn, @@ -323,8 +310,6 @@ static DecodeStatus DecodeVCVTD(MCInst &Inst, unsigned Insn, uint64_t Address, const void *Decoder); static DecodeStatus DecodeVCVTQ(MCInst &Inst, unsigned Insn, uint64_t Address, const void *Decoder); -static DecodeStatus DecodeImm0_4(MCInst &Inst, unsigned Insn, uint64_t Address, - const void *Decoder); static DecodeStatus DecodeThumbAddSpecialReg(MCInst &Inst, uint16_t Insn, @@ -406,93 +391,137 @@ static DecodeStatus DecodeMRRC2(llvm::MCInst &Inst, unsigned Val, uint64_t Address, const void *Decoder); #include "ARMGenDisassemblerTables.inc" -static MCDisassembler *createARMDisassembler(const Target &T, const MCSubtargetInfo &STI) { - return new ARMDisassembler(STI); +static MCDisassembler *createARMDisassembler(const Target &T, + const MCSubtargetInfo &STI, + MCContext &Ctx) { + return new ARMDisassembler(STI, Ctx); } -static MCDisassembler *createThumbDisassembler(const Target &T, const MCSubtargetInfo &STI) { - return new ThumbDisassembler(STI); +static MCDisassembler *createThumbDisassembler(const Target &T, + const MCSubtargetInfo &STI, + MCContext &Ctx) { + return new ThumbDisassembler(STI, Ctx); } -DecodeStatus ARMDisassembler::getInstruction(MCInst &MI, uint64_t &Size, - const MemoryObject &Region, - uint64_t Address, - raw_ostream &os, - raw_ostream &cs) const { - CommentStream = &cs; +// Post-decoding checks +static DecodeStatus checkDecodedInstruction(MCInst &MI, uint64_t &Size, + uint64_t Address, raw_ostream &OS, + raw_ostream &CS, + uint32_t Insn, + DecodeStatus Result) +{ + switch (MI.getOpcode()) { + case ARM::HVC: { + // HVC is undefined if condition = 0xf otherwise upredictable + // if condition != 0xe + uint32_t Cond = (Insn >> 28) & 0xF; + if (Cond == 0xF) + return MCDisassembler::Fail; + if (Cond != 0xE) + return MCDisassembler::SoftFail; + return Result; + } + default: return Result; + } +} - uint8_t bytes[4]; +DecodeStatus ARMDisassembler::getInstruction(MCInst &MI, uint64_t &Size, + ArrayRef Bytes, + uint64_t Address, raw_ostream &OS, + raw_ostream &CS) const { + CommentStream = &CS; assert(!(STI.getFeatureBits() & ARM::ModeThumb) && - "Asked to disassemble an ARM instruction but Subtarget is in Thumb mode!"); + "Asked to disassemble an ARM instruction but Subtarget is in Thumb " + "mode!"); // We want to read exactly 4 bytes of data. - if (Region.readBytes(Address, 4, bytes) == -1) { + if (Bytes.size() < 4) { Size = 0; return MCDisassembler::Fail; } // Encoded as a small-endian 32-bit word in the stream. - uint32_t insn = (bytes[3] << 24) | - (bytes[2] << 16) | - (bytes[1] << 8) | - (bytes[0] << 0); + uint32_t Insn = + (Bytes[3] << 24) | (Bytes[2] << 16) | (Bytes[1] << 8) | (Bytes[0] << 0); // Calling the auto-generated decoder function. - DecodeStatus result = decodeInstruction(DecoderTableARM32, MI, insn, - Address, this, STI); - if (result != MCDisassembler::Fail) { + DecodeStatus Result = + decodeInstruction(DecoderTableARM32, MI, Insn, Address, this, STI); + if (Result != MCDisassembler::Fail) { Size = 4; - return result; + return checkDecodedInstruction(MI, Size, Address, OS, CS, Insn, Result); } // VFP and NEON instructions, similarly, are shared between ARM // and Thumb modes. MI.clear(); - result = decodeInstruction(DecoderTableVFP32, MI, insn, Address, this, STI); - if (result != MCDisassembler::Fail) { + Result = decodeInstruction(DecoderTableVFP32, MI, Insn, Address, this, STI); + if (Result != MCDisassembler::Fail) { Size = 4; - return result; + return Result; } MI.clear(); - result = decodeInstruction(DecoderTableNEONData32, MI, insn, Address, - this, STI); - if (result != MCDisassembler::Fail) { + Result = decodeInstruction(DecoderTableVFPV832, MI, Insn, Address, this, STI); + if (Result != MCDisassembler::Fail) { + Size = 4; + return Result; + } + + MI.clear(); + Result = + decodeInstruction(DecoderTableNEONData32, MI, Insn, Address, this, STI); + if (Result != MCDisassembler::Fail) { Size = 4; // Add a fake predicate operand, because we share these instruction // definitions with Thumb2 where these instructions are predicable. if (!DecodePredicateOperand(MI, 0xE, Address, this)) return MCDisassembler::Fail; - return result; + return Result; } MI.clear(); - result = decodeInstruction(DecoderTableNEONLoadStore32, MI, insn, Address, + Result = decodeInstruction(DecoderTableNEONLoadStore32, MI, Insn, Address, this, STI); - if (result != MCDisassembler::Fail) { + if (Result != MCDisassembler::Fail) { Size = 4; // Add a fake predicate operand, because we share these instruction // definitions with Thumb2 where these instructions are predicable. if (!DecodePredicateOperand(MI, 0xE, Address, this)) return MCDisassembler::Fail; - return result; + return Result; } MI.clear(); - result = decodeInstruction(DecoderTableNEONDup32, MI, insn, Address, - this, STI); - if (result != MCDisassembler::Fail) { + Result = + decodeInstruction(DecoderTableNEONDup32, MI, Insn, Address, this, STI); + if (Result != MCDisassembler::Fail) { Size = 4; // Add a fake predicate operand, because we share these instruction // definitions with Thumb2 where these instructions are predicable. if (!DecodePredicateOperand(MI, 0xE, Address, this)) return MCDisassembler::Fail; - return result; + return Result; } MI.clear(); + Result = + decodeInstruction(DecoderTablev8NEON32, MI, Insn, Address, this, STI); + if (Result != MCDisassembler::Fail) { + Size = 4; + return Result; + } + MI.clear(); + Result = + decodeInstruction(DecoderTablev8Crypto32, MI, Insn, Address, this, STI); + if (Result != MCDisassembler::Fail) { + Size = 4; + return Result; + } + + MI.clear(); Size = 0; return MCDisassembler::Fail; } @@ -661,55 +690,53 @@ void ThumbDisassembler::UpdateThumbVFPPredicate(MCInst &MI) const { } DecodeStatus ThumbDisassembler::getInstruction(MCInst &MI, uint64_t &Size, - const MemoryObject &Region, + ArrayRef Bytes, uint64_t Address, - raw_ostream &os, - raw_ostream &cs) const { - CommentStream = &cs; - - uint8_t bytes[4]; + raw_ostream &OS, + raw_ostream &CS) const { + CommentStream = &CS; assert((STI.getFeatureBits() & ARM::ModeThumb) && "Asked to disassemble in Thumb mode but Subtarget is in ARM mode!"); // We want to read exactly 2 bytes of data. - if (Region.readBytes(Address, 2, bytes) == -1) { + if (Bytes.size() < 2) { Size = 0; return MCDisassembler::Fail; } - uint16_t insn16 = (bytes[1] << 8) | bytes[0]; - DecodeStatus result = decodeInstruction(DecoderTableThumb16, MI, insn16, - Address, this, STI); - if (result != MCDisassembler::Fail) { + uint16_t Insn16 = (Bytes[1] << 8) | Bytes[0]; + DecodeStatus Result = + decodeInstruction(DecoderTableThumb16, MI, Insn16, Address, this, STI); + if (Result != MCDisassembler::Fail) { Size = 2; - Check(result, AddThumbPredicate(MI)); - return result; + Check(Result, AddThumbPredicate(MI)); + return Result; } MI.clear(); - result = decodeInstruction(DecoderTableThumbSBit16, MI, insn16, - Address, this, STI); - if (result) { + Result = decodeInstruction(DecoderTableThumbSBit16, MI, Insn16, Address, this, + STI); + if (Result) { Size = 2; bool InITBlock = ITBlock.instrInITBlock(); - Check(result, AddThumbPredicate(MI)); + Check(Result, AddThumbPredicate(MI)); AddThumb1SBit(MI, InITBlock); - return result; + return Result; } MI.clear(); - result = decodeInstruction(DecoderTableThumb216, MI, insn16, - Address, this, STI); - if (result != MCDisassembler::Fail) { + Result = + decodeInstruction(DecoderTableThumb216, MI, Insn16, Address, this, STI); + if (Result != MCDisassembler::Fail) { Size = 2; // Nested IT blocks are UNPREDICTABLE. Must be checked before we add // the Thumb predicate. if (MI.getOpcode() == ARM::t2IT && ITBlock.instrInITBlock()) - result = MCDisassembler::SoftFail; + Result = MCDisassembler::SoftFail; - Check(result, AddThumbPredicate(MI)); + Check(Result, AddThumbPredicate(MI)); // If we find an IT instruction, we need to parse its condition // code and mask operands so that we can apply them correctly @@ -721,94 +748,132 @@ DecodeStatus ThumbDisassembler::getInstruction(MCInst &MI, uint64_t &Size, ITBlock.setITState(Firstcond, Mask); } - return result; + return Result; } // We want to read exactly 4 bytes of data. - if (Region.readBytes(Address, 4, bytes) == -1) { + if (Bytes.size() < 4) { Size = 0; return MCDisassembler::Fail; } - uint32_t insn32 = (bytes[3] << 8) | - (bytes[2] << 0) | - (bytes[1] << 24) | - (bytes[0] << 16); + uint32_t Insn32 = + (Bytes[3] << 8) | (Bytes[2] << 0) | (Bytes[1] << 24) | (Bytes[0] << 16); MI.clear(); - result = decodeInstruction(DecoderTableThumb32, MI, insn32, Address, - this, STI); - if (result != MCDisassembler::Fail) { + Result = + decodeInstruction(DecoderTableThumb32, MI, Insn32, Address, this, STI); + if (Result != MCDisassembler::Fail) { Size = 4; bool InITBlock = ITBlock.instrInITBlock(); - Check(result, AddThumbPredicate(MI)); + Check(Result, AddThumbPredicate(MI)); AddThumb1SBit(MI, InITBlock); - return result; + return Result; } MI.clear(); - result = decodeInstruction(DecoderTableThumb232, MI, insn32, Address, - this, STI); - if (result != MCDisassembler::Fail) { + Result = + decodeInstruction(DecoderTableThumb232, MI, Insn32, Address, this, STI); + if (Result != MCDisassembler::Fail) { Size = 4; - Check(result, AddThumbPredicate(MI)); - return result; + Check(Result, AddThumbPredicate(MI)); + return Result; } - MI.clear(); - result = decodeInstruction(DecoderTableVFP32, MI, insn32, Address, this, STI); - if (result != MCDisassembler::Fail) { - Size = 4; - UpdateThumbVFPPredicate(MI); - return result; + if (fieldFromInstruction(Insn32, 28, 4) == 0xE) { + MI.clear(); + Result = + decodeInstruction(DecoderTableVFP32, MI, Insn32, Address, this, STI); + if (Result != MCDisassembler::Fail) { + Size = 4; + UpdateThumbVFPPredicate(MI); + return Result; + } } MI.clear(); - result = decodeInstruction(DecoderTableNEONDup32, MI, insn32, Address, - this, STI); - if (result != MCDisassembler::Fail) { + Result = + decodeInstruction(DecoderTableVFPV832, MI, Insn32, Address, this, STI); + if (Result != MCDisassembler::Fail) { Size = 4; - Check(result, AddThumbPredicate(MI)); - return result; + return Result; + } + + if (fieldFromInstruction(Insn32, 28, 4) == 0xE) { + MI.clear(); + Result = decodeInstruction(DecoderTableNEONDup32, MI, Insn32, Address, this, + STI); + if (Result != MCDisassembler::Fail) { + Size = 4; + Check(Result, AddThumbPredicate(MI)); + return Result; + } } - if (fieldFromInstruction(insn32, 24, 8) == 0xF9) { + if (fieldFromInstruction(Insn32, 24, 8) == 0xF9) { MI.clear(); - uint32_t NEONLdStInsn = insn32; + uint32_t NEONLdStInsn = Insn32; NEONLdStInsn &= 0xF0FFFFFF; NEONLdStInsn |= 0x04000000; - result = decodeInstruction(DecoderTableNEONLoadStore32, MI, NEONLdStInsn, + Result = decodeInstruction(DecoderTableNEONLoadStore32, MI, NEONLdStInsn, Address, this, STI); - if (result != MCDisassembler::Fail) { + if (Result != MCDisassembler::Fail) { Size = 4; - Check(result, AddThumbPredicate(MI)); - return result; + Check(Result, AddThumbPredicate(MI)); + return Result; } } - if (fieldFromInstruction(insn32, 24, 4) == 0xF) { + if (fieldFromInstruction(Insn32, 24, 4) == 0xF) { MI.clear(); - uint32_t NEONDataInsn = insn32; + uint32_t NEONDataInsn = Insn32; NEONDataInsn &= 0xF0FFFFFF; // Clear bits 27-24 NEONDataInsn |= (NEONDataInsn & 0x10000000) >> 4; // Move bit 28 to bit 24 NEONDataInsn |= 0x12000000; // Set bits 28 and 25 - result = decodeInstruction(DecoderTableNEONData32, MI, NEONDataInsn, + Result = decodeInstruction(DecoderTableNEONData32, MI, NEONDataInsn, Address, this, STI); - if (result != MCDisassembler::Fail) { + if (Result != MCDisassembler::Fail) { Size = 4; - Check(result, AddThumbPredicate(MI)); - return result; + Check(Result, AddThumbPredicate(MI)); + return Result; + } + + MI.clear(); + uint32_t NEONCryptoInsn = Insn32; + NEONCryptoInsn &= 0xF0FFFFFF; // Clear bits 27-24 + NEONCryptoInsn |= (NEONCryptoInsn & 0x10000000) >> 4; // Move bit 28 to bit 24 + NEONCryptoInsn |= 0x12000000; // Set bits 28 and 25 + Result = decodeInstruction(DecoderTablev8Crypto32, MI, NEONCryptoInsn, + Address, this, STI); + if (Result != MCDisassembler::Fail) { + Size = 4; + return Result; + } + + MI.clear(); + uint32_t NEONv8Insn = Insn32; + NEONv8Insn &= 0xF3FFFFFF; // Clear bits 27-26 + Result = decodeInstruction(DecoderTablev8NEON32, MI, NEONv8Insn, Address, + this, STI); + if (Result != MCDisassembler::Fail) { + Size = 4; + return Result; } } + MI.clear(); Size = 0; return MCDisassembler::Fail; } extern "C" void LLVMInitializeARMDisassembler() { - TargetRegistry::RegisterMCDisassembler(TheARMTarget, + TargetRegistry::RegisterMCDisassembler(TheARMLETarget, + createARMDisassembler); + TargetRegistry::RegisterMCDisassembler(TheARMBETarget, createARMDisassembler); - TargetRegistry::RegisterMCDisassembler(TheThumbTarget, + TargetRegistry::RegisterMCDisassembler(TheThumbLETarget, + createThumbDisassembler); + TargetRegistry::RegisterMCDisassembler(TheThumbBETarget, createThumbDisassembler); } @@ -916,8 +981,11 @@ static DecodeStatus DecodetcGPRRegisterClass(MCInst &Inst, unsigned RegNo, static DecodeStatus DecoderGPRRegisterClass(MCInst &Inst, unsigned RegNo, uint64_t Address, const void *Decoder) { - if (RegNo == 13 || RegNo == 15) return MCDisassembler::Fail; - return DecodeGPRRegisterClass(Inst, RegNo, Address, Decoder); + DecodeStatus S = MCDisassembler::Success; + if (RegNo == 13 || RegNo == 15) + S = MCDisassembler::SoftFail; + Check(S, DecodeGPRRegisterClass(Inst, RegNo, Address, Decoder)); + return S; } static const uint16_t SPRDecoderTable[] = { @@ -954,7 +1022,11 @@ static const uint16_t DPRDecoderTable[] = { static DecodeStatus DecodeDPRRegisterClass(MCInst &Inst, unsigned RegNo, uint64_t Address, const void *Decoder) { - if (RegNo > 31) + uint64_t featureBits = ((const MCDisassembler*)Decoder)->getSubtargetInfo() + .getFeatureBits(); + bool hasD16 = featureBits & ARM::FeatureD16; + + if (RegNo > 31 || (hasD16 && RegNo > 15)) return MCDisassembler::Fail; unsigned Register = DPRDecoderTable[RegNo]; @@ -1061,15 +1133,6 @@ static DecodeStatus DecodeCCOutOperand(MCInst &Inst, unsigned Val, return MCDisassembler::Success; } -static DecodeStatus DecodeSOImmOperand(MCInst &Inst, unsigned Val, - uint64_t Address, const void *Decoder) { - uint32_t imm = Val & 0xFF; - uint32_t rot = (Val & 0xF00) >> 7; - uint32_t rot_imm = (imm >> rot) | (imm << ((32-rot) & 0x1F)); - Inst.addOperand(MCOperand::CreateImm(rot_imm)); - return MCDisassembler::Success; -} - static DecodeStatus DecodeSORegImmOperand(MCInst &Inst, unsigned Val, uint64_t Address, const void *Decoder) { DecodeStatus S = MCDisassembler::Success; @@ -1146,20 +1209,22 @@ static DecodeStatus DecodeRegListOperand(MCInst &Inst, unsigned Val, uint64_t Address, const void *Decoder) { DecodeStatus S = MCDisassembler::Success; - bool writebackLoad = false; - unsigned writebackReg = 0; + bool NeedDisjointWriteback = false; + unsigned WritebackReg = 0; switch (Inst.getOpcode()) { - default: - break; - case ARM::LDMIA_UPD: - case ARM::LDMDB_UPD: - case ARM::LDMIB_UPD: - case ARM::LDMDA_UPD: - case ARM::t2LDMIA_UPD: - case ARM::t2LDMDB_UPD: - writebackLoad = true; - writebackReg = Inst.getOperand(0).getReg(); - break; + default: + break; + case ARM::LDMIA_UPD: + case ARM::LDMDB_UPD: + case ARM::LDMIB_UPD: + case ARM::LDMDA_UPD: + case ARM::t2LDMIA_UPD: + case ARM::t2LDMDB_UPD: + case ARM::t2STMIA_UPD: + case ARM::t2STMDB_UPD: + NeedDisjointWriteback = true; + WritebackReg = Inst.getOperand(0).getReg(); + break; } // Empty register lists are not allowed. @@ -1169,7 +1234,7 @@ static DecodeStatus DecodeRegListOperand(MCInst &Inst, unsigned Val, if (!Check(S, DecodeGPRRegisterClass(Inst, i, Address, Decoder))) return MCDisassembler::Fail; // Writeback not allowed if Rn is in the target list. - if (writebackLoad && writebackReg == Inst.end()[-1].getReg()) + if (NeedDisjointWriteback && WritebackReg == Inst.end()[-1].getReg()) Check(S, MCDisassembler::SoftFail); } } @@ -1304,6 +1369,11 @@ static DecodeStatus DecodeCopMemInstruction(MCInst &Inst, unsigned Insn, break; } + uint64_t featureBits = ((const MCDisassembler*)Decoder)->getSubtargetInfo() + .getFeatureBits(); + if ((featureBits & ARM::HasV8Ops) && (coproc != 14)) + return MCDisassembler::Fail; + Inst.addOperand(MCOperand::CreateImm(coproc)); Inst.addOperand(MCOperand::CreateImm(CRd)); if (!Check(S, DecodeGPRRegisterClass(Inst, Rn, Address, Decoder))) @@ -2905,11 +2975,9 @@ static DecodeStatus DecodeVLD4DupInstruction(MCInst &Inst, unsigned Insn, if (size == 0x3) { if (align == 0) return MCDisassembler::Fail; - size = 4; align = 16; } else { if (size == 2) { - size = 1 << size; align *= 8; } else { size = 1 << size; @@ -3199,42 +3267,65 @@ static DecodeStatus DecodeT2LoadShift(MCInst &Inst, unsigned Insn, unsigned Rt = fieldFromInstruction(Insn, 12, 4); unsigned Rn = fieldFromInstruction(Insn, 16, 4); - if (Rn == 0xF) { + uint64_t featureBits = ((const MCDisassembler*)Decoder)->getSubtargetInfo() + .getFeatureBits(); + bool hasMP = featureBits & ARM::FeatureMP; + bool hasV7Ops = featureBits & ARM::HasV7Ops; + + if (Rn == 15) { switch (Inst.getOpcode()) { - case ARM::t2LDRBs: - Inst.setOpcode(ARM::t2LDRBpci); - break; - case ARM::t2LDRHs: - Inst.setOpcode(ARM::t2LDRHpci); - break; - case ARM::t2LDRSHs: - Inst.setOpcode(ARM::t2LDRSHpci); - break; - case ARM::t2LDRSBs: - Inst.setOpcode(ARM::t2LDRSBpci); - break; - case ARM::t2LDRs: - Inst.setOpcode(ARM::t2LDRpci); - break; - case ARM::t2PLDs: { - Inst.setOpcode(ARM::t2PLDi12); - Inst.addOperand(MCOperand::CreateReg(ARM::PC)); - int imm = fieldFromInstruction(Insn, 0, 12); - if (!fieldFromInstruction(Insn, 23, 1)) imm *= -1; - Inst.addOperand(MCOperand::CreateImm(imm)); - return S; - } - default: - return MCDisassembler::Fail; + case ARM::t2LDRBs: + Inst.setOpcode(ARM::t2LDRBpci); + break; + case ARM::t2LDRHs: + Inst.setOpcode(ARM::t2LDRHpci); + break; + case ARM::t2LDRSHs: + Inst.setOpcode(ARM::t2LDRSHpci); + break; + case ARM::t2LDRSBs: + Inst.setOpcode(ARM::t2LDRSBpci); + break; + case ARM::t2LDRs: + Inst.setOpcode(ARM::t2LDRpci); + break; + case ARM::t2PLDs: + Inst.setOpcode(ARM::t2PLDpci); + break; + case ARM::t2PLIs: + Inst.setOpcode(ARM::t2PLIpci); + break; + default: + return MCDisassembler::Fail; } return DecodeT2LoadLabel(Inst, Insn, Address, Decoder); } + if (Rt == 15) { + switch (Inst.getOpcode()) { + case ARM::t2LDRSHs: + return MCDisassembler::Fail; + case ARM::t2LDRHs: + Inst.setOpcode(ARM::t2PLDWs); + break; + case ARM::t2LDRSBs: + Inst.setOpcode(ARM::t2PLIs); + default: + break; + } + } + switch (Inst.getOpcode()) { case ARM::t2PLDs: - case ARM::t2PLDWs: + break; case ARM::t2PLIs: + if (!hasV7Ops) + return MCDisassembler::Fail; + break; + case ARM::t2PLDWs: + if (!hasV7Ops || !hasMP) + return MCDisassembler::Fail; break; default: if (!Check(S, DecodeGPRRegisterClass(Inst, Rt, Address, Decoder))) @@ -3260,6 +3351,12 @@ static DecodeStatus DecodeT2LoadImm8(MCInst &Inst, unsigned Insn, unsigned imm = fieldFromInstruction(Insn, 0, 8); imm |= (U << 8); imm |= (Rn << 9); + unsigned add = fieldFromInstruction(Insn, 9, 1); + + uint64_t featureBits = ((const MCDisassembler*)Decoder)->getSubtargetInfo() + .getFeatureBits(); + bool hasMP = featureBits & ARM::FeatureMP; + bool hasV7Ops = featureBits & ARM::HasV7Ops; if (Rn == 15) { switch (Inst.getOpcode()) { @@ -3278,14 +3375,50 @@ static DecodeStatus DecodeT2LoadImm8(MCInst &Inst, unsigned Insn, case ARM::t2LDRSHi8: Inst.setOpcode(ARM::t2LDRSHpci); break; + case ARM::t2PLDi8: + Inst.setOpcode(ARM::t2PLDpci); + break; + case ARM::t2PLIi8: + Inst.setOpcode(ARM::t2PLIpci); + break; default: return MCDisassembler::Fail; } return DecodeT2LoadLabel(Inst, Insn, Address, Decoder); } - if (!Check(S, DecodeGPRRegisterClass(Inst, Rt, Address, Decoder))) - return MCDisassembler::Fail; + if (Rt == 15) { + switch (Inst.getOpcode()) { + case ARM::t2LDRSHi8: + return MCDisassembler::Fail; + case ARM::t2LDRHi8: + if (!add) + Inst.setOpcode(ARM::t2PLDWi8); + break; + case ARM::t2LDRSBi8: + Inst.setOpcode(ARM::t2PLIi8); + break; + default: + break; + } + } + + switch (Inst.getOpcode()) { + case ARM::t2PLDi8: + break; + case ARM::t2PLIi8: + if (!hasV7Ops) + return MCDisassembler::Fail; + break; + case ARM::t2PLDWi8: + if (!hasV7Ops || !hasMP) + return MCDisassembler::Fail; + break; + default: + if (!Check(S, DecodeGPRRegisterClass(Inst, Rt, Address, Decoder))) + return MCDisassembler::Fail; + } + if (!Check(S, DecodeT2AddrModeImm8(Inst, imm, Address, Decoder))) return MCDisassembler::Fail; return S; @@ -3300,6 +3433,11 @@ static DecodeStatus DecodeT2LoadImm12(MCInst &Inst, unsigned Insn, unsigned imm = fieldFromInstruction(Insn, 0, 12); imm |= (Rn << 13); + uint64_t featureBits = ((const MCDisassembler*)Decoder)->getSubtargetInfo() + .getFeatureBits(); + bool hasMP = (featureBits & ARM::FeatureMP); + bool hasV7Ops = (featureBits & ARM::HasV7Ops); + if (Rn == 15) { switch (Inst.getOpcode()) { case ARM::t2LDRi12: @@ -3317,14 +3455,49 @@ static DecodeStatus DecodeT2LoadImm12(MCInst &Inst, unsigned Insn, case ARM::t2LDRSBi12: Inst.setOpcode(ARM::t2LDRSBpci); break; + case ARM::t2PLDi12: + Inst.setOpcode(ARM::t2PLDpci); + break; + case ARM::t2PLIi12: + Inst.setOpcode(ARM::t2PLIpci); + break; default: return MCDisassembler::Fail; } return DecodeT2LoadLabel(Inst, Insn, Address, Decoder); } - if (!Check(S, DecodeGPRRegisterClass(Inst, Rt, Address, Decoder))) - return MCDisassembler::Fail; + if (Rt == 15) { + switch (Inst.getOpcode()) { + case ARM::t2LDRSHi12: + return MCDisassembler::Fail; + case ARM::t2LDRHi12: + Inst.setOpcode(ARM::t2PLDWi12); + break; + case ARM::t2LDRSBi12: + Inst.setOpcode(ARM::t2PLIi12); + break; + default: + break; + } + } + + switch (Inst.getOpcode()) { + case ARM::t2PLDi12: + break; + case ARM::t2PLIi12: + if (!hasV7Ops) + return MCDisassembler::Fail; + break; + case ARM::t2PLDWi12: + if (!hasV7Ops || !hasMP) + return MCDisassembler::Fail; + break; + default: + if (!Check(S, DecodeGPRRegisterClass(Inst, Rt, Address, Decoder))) + return MCDisassembler::Fail; + } + if (!Check(S, DecodeT2AddrModeImm12(Inst, imm, Address, Decoder))) return MCDisassembler::Fail; return S; @@ -3377,11 +3550,34 @@ static DecodeStatus DecodeT2LoadLabel(MCInst &Inst, unsigned Insn, unsigned U = fieldFromInstruction(Insn, 23, 1); int imm = fieldFromInstruction(Insn, 0, 12); - // FIXME: detect and decode PLD properly - if (Inst.getOpcode() == ARM::t2LDRBpci && Rt == 15) { - Inst.setOpcode(ARM::t2PLDi12); - Inst.addOperand(MCOperand::CreateReg(ARM::PC)); - } else { + uint64_t featureBits = ((const MCDisassembler*)Decoder)->getSubtargetInfo() + .getFeatureBits(); + bool hasV7Ops = (featureBits & ARM::HasV7Ops); + + if (Rt == 15) { + switch (Inst.getOpcode()) { + case ARM::t2LDRBpci: + case ARM::t2LDRHpci: + Inst.setOpcode(ARM::t2PLDpci); + break; + case ARM::t2LDRSBpci: + Inst.setOpcode(ARM::t2PLIpci); + break; + case ARM::t2LDRSHpci: + return MCDisassembler::Fail; + default: + break; + } + } + + switch(Inst.getOpcode()) { + case ARM::t2PLDpci: + break; + case ARM::t2PLIpci: + if (!hasV7Ops) + return MCDisassembler::Fail; + break; + default: if (!Check(S, DecodeGPRRegisterClass(Inst, Rt, Address, Decoder))) return MCDisassembler::Fail; } @@ -3528,7 +3724,10 @@ static DecodeStatus DecodeT2LdStPre(MCInst &Inst, unsigned Insn, break; case ARM::t2LDRSB_PRE: case ARM::t2LDRSB_POST: - Inst.setOpcode(ARM::t2LDRSBpci); + if (Rt == 15) + Inst.setOpcode(ARM::t2PLIpci); + else + Inst.setOpcode(ARM::t2LDRSBpci); break; case ARM::t2LDRSH_PRE: case ARM::t2LDRSH_POST: @@ -3674,6 +3873,11 @@ static DecodeStatus DecodeCoprocessor(MCInst &Inst, unsigned Val, if (Val == 0xA || Val == 0xB) return MCDisassembler::Fail; + uint64_t featureBits = ((const MCDisassembler*)Decoder)->getSubtargetInfo() + .getFeatureBits(); + if ((featureBits & ARM::HasV8Ops) && !(Val == 14 || Val == 15)) + return MCDisassembler::Fail; + Inst.addOperand(MCOperand::CreateImm(Val)); return MCDisassembler::Success; } @@ -3820,7 +4024,85 @@ static DecodeStatus DecodeInstSyncBarrierOption(MCInst &Inst, unsigned Val, static DecodeStatus DecodeMSRMask(MCInst &Inst, unsigned Val, uint64_t Address, const void *Decoder) { - if (!Val) return MCDisassembler::Fail; + DecodeStatus S = MCDisassembler::Success; + uint64_t FeatureBits = ((const MCDisassembler*)Decoder)->getSubtargetInfo() + .getFeatureBits(); + if (FeatureBits & ARM::FeatureMClass) { + unsigned ValLow = Val & 0xff; + + // Validate the SYSm value first. + switch (ValLow) { + case 0: // apsr + case 1: // iapsr + case 2: // eapsr + case 3: // xpsr + case 5: // ipsr + case 6: // epsr + case 7: // iepsr + case 8: // msp + case 9: // psp + case 16: // primask + case 20: // control + break; + case 17: // basepri + case 18: // basepri_max + case 19: // faultmask + if (!(FeatureBits & ARM::HasV7Ops)) + // Values basepri, basepri_max and faultmask are only valid for v7m. + return MCDisassembler::Fail; + break; + default: + return MCDisassembler::Fail; + } + + if (Inst.getOpcode() == ARM::t2MSR_M) { + unsigned Mask = fieldFromInstruction(Val, 10, 2); + if (!(FeatureBits & ARM::HasV7Ops)) { + // The ARMv6-M MSR bits {11-10} can be only 0b10, other values are + // unpredictable. + if (Mask != 2) + S = MCDisassembler::SoftFail; + } + else { + // The ARMv7-M architecture stores an additional 2-bit mask value in + // MSR bits {11-10}. The mask is used only with apsr, iapsr, eapsr and + // xpsr, it has to be 0b10 in other cases. Bit mask{1} indicates if + // the NZCVQ bits should be moved by the instruction. Bit mask{0} + // indicates the move for the GE{3:0} bits, the mask{0} bit can be set + // only if the processor includes the DSP extension. + if (Mask == 0 || (Mask != 2 && ValLow > 3) || + (!(FeatureBits & ARM::FeatureDSPThumb2) && (Mask & 1))) + S = MCDisassembler::SoftFail; + } + } + } else { + // A/R class + if (Val == 0) + return MCDisassembler::Fail; + } + Inst.addOperand(MCOperand::CreateImm(Val)); + return S; +} + +static DecodeStatus DecodeBankedReg(MCInst &Inst, unsigned Val, + uint64_t Address, const void *Decoder) { + + unsigned R = fieldFromInstruction(Val, 5, 1); + unsigned SysM = fieldFromInstruction(Val, 0, 5); + + // The table of encodings for these banked registers comes from B9.2.3 of the + // ARM ARM. There are patterns, but nothing regular enough to make this logic + // neater. So by fiat, these values are UNPREDICTABLE: + if (!R) { + if (SysM == 0x7 || SysM == 0xf || SysM == 0x18 || SysM == 0x19 || + SysM == 0x1a || SysM == 0x1b) + return MCDisassembler::SoftFail; + } else { + if (SysM != 0xe && SysM != 0x10 && SysM != 0x12 && SysM != 0x14 && + SysM != 0x16 && SysM != 0x1c && SysM != 0x1e) + return MCDisassembler::SoftFail; + } + Inst.addOperand(MCOperand::CreateImm(Val)); return MCDisassembler::Success; } @@ -4588,10 +4870,8 @@ static DecodeStatus DecodeIT(MCInst &Inst, unsigned Insn, S = MCDisassembler::SoftFail; } - if (mask == 0x0) { - mask |= 0x8; - S = MCDisassembler::SoftFail; - } + if (mask == 0x0) + return MCDisassembler::Fail; Inst.addOperand(MCOperand::CreateImm(pred)); Inst.addOperand(MCOperand::CreateImm(mask)); @@ -4691,7 +4971,7 @@ static DecodeStatus DecodeT2ShifterImmOperand(MCInst &Inst, uint32_t Val, DecodeStatus S = MCDisassembler::Success; // Shift of "asr #32" is not allowed in Thumb2 mode. - if (Val == 0x20) S = MCDisassembler::SoftFail; + if (Val == 0x20) S = MCDisassembler::Fail; Inst.addOperand(MCOperand::CreateImm(Val)); return S; } @@ -4783,15 +5063,6 @@ static DecodeStatus DecodeVCVTQ(MCInst &Inst, unsigned Insn, return S; } -static DecodeStatus DecodeImm0_4(MCInst &Inst, unsigned Insn, uint64_t Address, - const void *Decoder) -{ - unsigned Imm = fieldFromInstruction(Insn, 0, 3); - if (Imm > 4) return MCDisassembler::Fail; - Inst.addOperand(MCOperand::CreateImm(Imm)); - return MCDisassembler::Success; -} - static DecodeStatus DecodeLDR(MCInst &Inst, unsigned Val, uint64_t Address, const void *Decoder) { DecodeStatus S = MCDisassembler::Success;