371 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			371 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===- ARCDisassembler.cpp - Disassembler for ARC ---------------*- C++ -*-===//
 | |
| //
 | |
| // 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
 | |
| //
 | |
| //===----------------------------------------------------------------------===//
 | |
| ///
 | |
| /// \file
 | |
| /// This file is part of the ARC Disassembler.
 | |
| ///
 | |
| //===----------------------------------------------------------------------===//
 | |
| 
 | |
| #include "ARC.h"
 | |
| #include "ARCRegisterInfo.h"
 | |
| #include "MCTargetDesc/ARCMCTargetDesc.h"
 | |
| #include "TargetInfo/ARCTargetInfo.h"
 | |
| #include "llvm/MC/MCContext.h"
 | |
| #include "llvm/MC/MCDisassembler/MCDisassembler.h"
 | |
| #include "llvm/MC/MCFixedLenDisassembler.h"
 | |
| #include "llvm/MC/MCInst.h"
 | |
| #include "llvm/MC/MCInstrInfo.h"
 | |
| #include "llvm/MC/MCSubtargetInfo.h"
 | |
| #include "llvm/Support/TargetRegistry.h"
 | |
| 
 | |
| using namespace llvm;
 | |
| 
 | |
| #define DEBUG_TYPE "arc-disassembler"
 | |
| 
 | |
| using DecodeStatus = MCDisassembler::DecodeStatus;
 | |
| 
 | |
| namespace {
 | |
| 
 | |
| /// A disassembler class for ARC.
 | |
| class ARCDisassembler : public MCDisassembler {
 | |
| public:
 | |
|   std::unique_ptr<MCInstrInfo const> const MCII;
 | |
| 
 | |
|   ARCDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx,
 | |
|                   MCInstrInfo const *MCII)
 | |
|       : MCDisassembler(STI, Ctx), MCII(MCII) {}
 | |
| 
 | |
|   DecodeStatus getInstruction(MCInst &Instr, uint64_t &Size,
 | |
|                               ArrayRef<uint8_t> Bytes, uint64_t Address,
 | |
|                               raw_ostream &CStream) const override;
 | |
| };
 | |
| 
 | |
| } // end anonymous namespace
 | |
| 
 | |
| static bool readInstruction32(ArrayRef<uint8_t> Bytes, uint64_t Address,
 | |
|                               uint64_t &Size, uint32_t &Insn) {
 | |
|   Size = 4;
 | |
|   // Read 2 16-bit values, but swap hi/lo parts.
 | |
|   Insn =
 | |
|       (Bytes[0] << 16) | (Bytes[1] << 24) | (Bytes[2] << 0) | (Bytes[3] << 8);
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| static bool readInstruction64(ArrayRef<uint8_t> Bytes, uint64_t Address,
 | |
|                               uint64_t &Size, uint64_t &Insn) {
 | |
|   Size = 8;
 | |
|   Insn = ((uint64_t)Bytes[0] << 16) | ((uint64_t)Bytes[1] << 24) |
 | |
|          ((uint64_t)Bytes[2] << 0) | ((uint64_t)Bytes[3] << 8) |
 | |
|          ((uint64_t)Bytes[4] << 48) | ((uint64_t)Bytes[5] << 56) |
 | |
|          ((uint64_t)Bytes[6] << 32) | ((uint64_t)Bytes[7] << 40);
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| static bool readInstruction48(ArrayRef<uint8_t> Bytes, uint64_t Address,
 | |
|                               uint64_t &Size, uint64_t &Insn) {
 | |
|   Size = 6;
 | |
|   Insn = ((uint64_t)Bytes[0] << 0) | ((uint64_t)Bytes[1] << 8) |
 | |
|          ((uint64_t)Bytes[2] << 32) | ((uint64_t)Bytes[3] << 40) |
 | |
|          ((uint64_t)Bytes[4] << 16) | ((uint64_t)Bytes[5] << 24);
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| static bool readInstruction16(ArrayRef<uint8_t> Bytes, uint64_t Address,
 | |
|                               uint64_t &Size, uint32_t &Insn) {
 | |
|   Size = 2;
 | |
|   Insn = (Bytes[0] << 0) | (Bytes[1] << 8);
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| template <unsigned B>
 | |
| static DecodeStatus DecodeSignedOperand(MCInst &Inst, unsigned InsnS,
 | |
|                                         uint64_t Address = 0,
 | |
|                                         const void *Decoder = nullptr);
 | |
| 
 | |
| template <unsigned B>
 | |
| static DecodeStatus DecodeFromCyclicRange(MCInst &Inst, unsigned InsnS,
 | |
|                                         uint64_t Address = 0,
 | |
|                                         const void *Decoder = nullptr);
 | |
| 
 | |
| template <unsigned B>
 | |
| static DecodeStatus DecodeBranchTargetS(MCInst &Inst, unsigned InsnS,
 | |
|                                         uint64_t Address, const void *Decoder);
 | |
| 
 | |
| static DecodeStatus DecodeMEMrs9(MCInst &, unsigned, uint64_t, const void *);
 | |
| 
 | |
| static DecodeStatus DecodeLdLImmInstruction(MCInst &, uint64_t, uint64_t,
 | |
|                                             const void *);
 | |
| 
 | |
| static DecodeStatus DecodeStLImmInstruction(MCInst &, uint64_t, uint64_t,
 | |
|                                             const void *);
 | |
| 
 | |
| static DecodeStatus DecodeLdRLImmInstruction(MCInst &, uint64_t, uint64_t,
 | |
|                                              const void *);
 | |
| 
 | |
| static DecodeStatus DecodeMoveHRegInstruction(MCInst &Inst, uint64_t, uint64_t,
 | |
|                                               const void *);
 | |
| 
 | |
| static const uint16_t GPR32DecoderTable[] = {
 | |
|     ARC::R0,  ARC::R1,    ARC::R2,  ARC::R3,   ARC::R4,  ARC::R5,  ARC::R6,
 | |
|     ARC::R7,  ARC::R8,    ARC::R9,  ARC::R10,  ARC::R11, ARC::R12, ARC::R13,
 | |
|     ARC::R14, ARC::R15,   ARC::R16, ARC::R17,  ARC::R18, ARC::R19, ARC::R20,
 | |
|     ARC::R21, ARC::R22,   ARC::R23, ARC::R24,  ARC::R25, ARC::GP,  ARC::FP,
 | |
|     ARC::SP,  ARC::ILINK, ARC::R30, ARC::BLINK};
 | |
| 
 | |
| static DecodeStatus DecodeGPR32RegisterClass(MCInst &Inst, unsigned RegNo,
 | |
|                                              uint64_t Address,
 | |
|                                              const void *Decoder) {
 | |
|   if (RegNo >= 32) {
 | |
|     LLVM_DEBUG(dbgs() << "Not a GPR32 register.");
 | |
|     return MCDisassembler::Fail;
 | |
|   }
 | |
| 
 | |
|   unsigned Reg = GPR32DecoderTable[RegNo];
 | |
|   Inst.addOperand(MCOperand::createReg(Reg));
 | |
|   return MCDisassembler::Success;
 | |
| }
 | |
| 
 | |
| static DecodeStatus DecodeGBR32ShortRegister(MCInst &Inst, unsigned RegNo,
 | |
|                                                uint64_t Address,
 | |
|                                                const void *Decoder) {
 | |
|   // Enumerates registers from ranges [r0-r3],[r12-r15].
 | |
|   if (RegNo > 3)
 | |
|     RegNo += 8; // 4 for r12, etc...
 | |
| 
 | |
|   return DecodeGPR32RegisterClass(Inst, RegNo, Address, Decoder);
 | |
| }
 | |
| 
 | |
| #include "ARCGenDisassemblerTables.inc"
 | |
| 
 | |
| static unsigned decodeCField(unsigned Insn) {
 | |
|   return fieldFromInstruction(Insn, 6, 6);
 | |
| }
 | |
| 
 | |
| static unsigned decodeBField(unsigned Insn) {
 | |
|   return (fieldFromInstruction(Insn, 12, 3) << 3) |
 | |
|          fieldFromInstruction(Insn, 24, 3);
 | |
| }
 | |
| 
 | |
| static unsigned decodeAField(unsigned Insn) {
 | |
|   return fieldFromInstruction(Insn, 0, 6);
 | |
| }
 | |
| 
 | |
| static DecodeStatus DecodeMEMrs9(MCInst &Inst, unsigned Insn, uint64_t Address,
 | |
|                                  const void *Dec) {
 | |
|   // We have the 9-bit immediate in the low bits, 6-bit register in high bits.
 | |
|   unsigned S9 = Insn & 0x1ff;
 | |
|   unsigned R = (Insn & (0x7fff & ~0x1ff)) >> 9;
 | |
|   DecodeGPR32RegisterClass(Inst, R, Address, Dec);
 | |
|   Inst.addOperand(MCOperand::createImm(SignExtend32<9>(S9)));
 | |
|   return MCDisassembler::Success;
 | |
| }
 | |
| 
 | |
| static bool DecodeSymbolicOperand(MCInst &Inst, uint64_t Address,
 | |
|                                   uint64_t Value, const void *Decoder) {
 | |
|   static const uint64_t atLeast = 2;
 | |
|   // TODO: Try to force emitter to use MCDisassembler* instead of void*.
 | |
|   auto Disassembler = static_cast<const MCDisassembler *>(Decoder);
 | |
|   return (nullptr != Disassembler &&
 | |
|           Disassembler->tryAddingSymbolicOperand(Inst, Value, Address, true, 0,
 | |
|                                                  atLeast));
 | |
| }
 | |
| 
 | |
| static void DecodeSymbolicOperandOff(MCInst &Inst, uint64_t Address,
 | |
|                                      uint64_t Offset, const void *Decoder) {
 | |
|   uint64_t nextAddress = Address + Offset;
 | |
| 
 | |
|   if (!DecodeSymbolicOperand(Inst, Address, nextAddress, Decoder))
 | |
|     Inst.addOperand(MCOperand::createImm(Offset));
 | |
| }
 | |
| 
 | |
| template <unsigned B>
 | |
| static DecodeStatus DecodeBranchTargetS(MCInst &Inst, unsigned InsnS,
 | |
|                                         uint64_t Address, const void *Decoder) {
 | |
| 
 | |
|   static_assert(B > 0, "field is empty");
 | |
|   DecodeSymbolicOperandOff(Inst, Address, SignExtend32<B>(InsnS), Decoder);
 | |
|   return MCDisassembler::Success;
 | |
| }
 | |
| 
 | |
| template <unsigned B>
 | |
| static DecodeStatus DecodeSignedOperand(MCInst &Inst, unsigned InsnS,
 | |
|                                         uint64_t /*Address*/,
 | |
|                                         const void * /*Decoder*/) {
 | |
| 
 | |
|   static_assert(B > 0, "field is empty");
 | |
|   Inst.addOperand(MCOperand::createImm(
 | |
|       SignExtend32<B>(maskTrailingOnes<decltype(InsnS)>(B) & InsnS)));
 | |
|   return MCDisassembler::Success;
 | |
| }
 | |
| 
 | |
| template <unsigned B>
 | |
| static DecodeStatus DecodeFromCyclicRange(MCInst &Inst, unsigned InsnS,
 | |
|                                           uint64_t /*Address*/,
 | |
|                                           const void * /*Decoder*/) {
 | |
| 
 | |
|   static_assert(B > 0, "field is empty");
 | |
|   const unsigned max = (1u << B) - 1;
 | |
|   Inst.addOperand(
 | |
|       MCOperand::createImm(InsnS < max ? static_cast<int>(InsnS) : -1));
 | |
|   return MCDisassembler::Success;
 | |
| }
 | |
| 
 | |
| static DecodeStatus DecodeStLImmInstruction(MCInst &Inst, uint64_t Insn,
 | |
|                                             uint64_t Address,
 | |
|                                             const void *Decoder) {
 | |
|   unsigned SrcC, DstB, LImm;
 | |
|   DstB = decodeBField(Insn);
 | |
|   if (DstB != 62) {
 | |
|     LLVM_DEBUG(dbgs() << "Decoding StLImm found non-limm register.");
 | |
|     return MCDisassembler::Fail;
 | |
|   }
 | |
|   SrcC = decodeCField(Insn);
 | |
|   DecodeGPR32RegisterClass(Inst, SrcC, Address, Decoder);
 | |
|   LImm = (Insn >> 32);
 | |
|   Inst.addOperand(MCOperand::createImm(LImm));
 | |
|   Inst.addOperand(MCOperand::createImm(0));
 | |
|   return MCDisassembler::Success;
 | |
| }
 | |
| 
 | |
| static DecodeStatus DecodeLdLImmInstruction(MCInst &Inst, uint64_t Insn,
 | |
|                                             uint64_t Address,
 | |
|                                             const void *Decoder) {
 | |
|   unsigned DstA, SrcB, LImm;
 | |
|   LLVM_DEBUG(dbgs() << "Decoding LdLImm:\n");
 | |
|   SrcB = decodeBField(Insn);
 | |
|   if (SrcB != 62) {
 | |
|     LLVM_DEBUG(dbgs() << "Decoding LdLImm found non-limm register.");
 | |
|     return MCDisassembler::Fail;
 | |
|   }
 | |
|   DstA = decodeAField(Insn);
 | |
|   DecodeGPR32RegisterClass(Inst, DstA, Address, Decoder);
 | |
|   LImm = (Insn >> 32);
 | |
|   Inst.addOperand(MCOperand::createImm(LImm));
 | |
|   Inst.addOperand(MCOperand::createImm(0));
 | |
|   return MCDisassembler::Success;
 | |
| }
 | |
| 
 | |
| static DecodeStatus DecodeLdRLImmInstruction(MCInst &Inst, uint64_t Insn,
 | |
|                                              uint64_t Address,
 | |
|                                              const void *Decoder) {
 | |
|   unsigned DstA, SrcB;
 | |
|   LLVM_DEBUG(dbgs() << "Decoding LdRLimm\n");
 | |
|   DstA = decodeAField(Insn);
 | |
|   DecodeGPR32RegisterClass(Inst, DstA, Address, Decoder);
 | |
|   SrcB = decodeBField(Insn);
 | |
|   DecodeGPR32RegisterClass(Inst, SrcB, Address, Decoder);
 | |
|   if (decodeCField(Insn) != 62) {
 | |
|     LLVM_DEBUG(dbgs() << "Decoding LdRLimm found non-limm register.");
 | |
|     return MCDisassembler::Fail;
 | |
|   }
 | |
|   Inst.addOperand(MCOperand::createImm((uint32_t)(Insn >> 32)));
 | |
|   return MCDisassembler::Success;
 | |
| }
 | |
| 
 | |
| static DecodeStatus DecodeMoveHRegInstruction(MCInst &Inst, uint64_t Insn,
 | |
|                                               uint64_t Address,
 | |
|                                               const void *Decoder) {
 | |
|   LLVM_DEBUG(dbgs() << "Decoding MOV_S h-register\n");
 | |
|   using Field = decltype(Insn);
 | |
|   Field h = fieldFromInstruction(Insn, 5, 3) |
 | |
|             (fieldFromInstruction(Insn, 0, 2) << 3);
 | |
|   Field g = fieldFromInstruction(Insn, 8, 3) |
 | |
|             (fieldFromInstruction(Insn, 3, 2) << 3);
 | |
| 
 | |
|   auto DecodeRegisterOrImm = [&Inst, Address, Decoder](Field RegNum,
 | |
|                                                        Field Value) {
 | |
|     if (30 == RegNum) {
 | |
|       Inst.addOperand(MCOperand::createImm(Value));
 | |
|       return MCDisassembler::Success;
 | |
|     }
 | |
| 
 | |
|     return DecodeGPR32RegisterClass(Inst, RegNum, Address, Decoder);
 | |
|   };
 | |
| 
 | |
|   if (MCDisassembler::Success != DecodeRegisterOrImm(g, 0))
 | |
|     return MCDisassembler::Fail;
 | |
| 
 | |
|   return DecodeRegisterOrImm(h, Insn >> 16u);
 | |
| }
 | |
| 
 | |
| DecodeStatus ARCDisassembler::getInstruction(MCInst &Instr, uint64_t &Size,
 | |
|                                              ArrayRef<uint8_t> Bytes,
 | |
|                                              uint64_t Address,
 | |
|                                              raw_ostream &cStream) const {
 | |
|   MCDisassembler::DecodeStatus Result;
 | |
|   if (Bytes.size() < 2) {
 | |
|     Size = 0;
 | |
|     return Fail;
 | |
|   }
 | |
|   uint8_t DecodeByte = (Bytes[1] & 0xF7) >> 3;
 | |
|   // 0x00 -> 0x07 are 32-bit instructions.
 | |
|   // 0x08 -> 0x1F are 16-bit instructions.
 | |
|   if (DecodeByte < 0x08) {
 | |
|     // 32-bit instruction.
 | |
|     if (Bytes.size() < 4) {
 | |
|       // Did we decode garbage?
 | |
|       Size = 0;
 | |
|       return Fail;
 | |
|     }
 | |
|     if (Bytes.size() >= 8) {
 | |
|       // Attempt to decode 64-bit instruction.
 | |
|       uint64_t Insn64;
 | |
|       if (!readInstruction64(Bytes, Address, Size, Insn64))
 | |
|         return Fail;
 | |
|       Result =
 | |
|           decodeInstruction(DecoderTable64, Instr, Insn64, Address, this, STI);
 | |
|       if (Success == Result) {
 | |
|         LLVM_DEBUG(dbgs() << "Successfully decoded 64-bit instruction.");
 | |
|         return Result;
 | |
|       }
 | |
|       LLVM_DEBUG(dbgs() << "Not a 64-bit instruction, falling back to 32-bit.");
 | |
|     }
 | |
|     uint32_t Insn32;
 | |
|     if (!readInstruction32(Bytes, Address, Size, Insn32)) {
 | |
|       return Fail;
 | |
|     }
 | |
|     // Calling the auto-generated decoder function.
 | |
|     return decodeInstruction(DecoderTable32, Instr, Insn32, Address, this, STI);
 | |
|   } else {
 | |
|     if (Bytes.size() >= 6) {
 | |
|       // Attempt to treat as instr. with limm data.
 | |
|       uint64_t Insn48;
 | |
|       if (!readInstruction48(Bytes, Address, Size, Insn48))
 | |
|         return Fail;
 | |
|       Result =
 | |
|           decodeInstruction(DecoderTable48, Instr, Insn48, Address, this, STI);
 | |
|       if (Success == Result) {
 | |
|         LLVM_DEBUG(
 | |
|             dbgs() << "Successfully decoded 16-bit instruction with limm.");
 | |
|         return Result;
 | |
|       }
 | |
|       LLVM_DEBUG(
 | |
|           dbgs() << "Not a 16-bit instruction with limm, try without it.");
 | |
|     }
 | |
| 
 | |
|     uint32_t Insn16;
 | |
|     if (!readInstruction16(Bytes, Address, Size, Insn16))
 | |
|       return Fail;
 | |
| 
 | |
|     // Calling the auto-generated decoder function.
 | |
|     return decodeInstruction(DecoderTable16, Instr, Insn16, Address, this, STI);
 | |
|   }
 | |
| }
 | |
| 
 | |
| static MCDisassembler *createARCDisassembler(const Target &T,
 | |
|                                              const MCSubtargetInfo &STI,
 | |
|                                              MCContext &Ctx) {
 | |
|   return new ARCDisassembler(STI, Ctx, T.createMCInstrInfo());
 | |
| }
 | |
| 
 | |
| extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeARCDisassembler() {
 | |
|   // Register the disassembler.
 | |
|   TargetRegistry::RegisterMCDisassembler(getTheARCTarget(),
 | |
|                                          createARCDisassembler);
 | |
| }
 |