| //===-EDDisassembler.cpp - LLVM Enhanced Disassembler ---------------------===// | |
| // | |
| // The LLVM Compiler Infrastructure | |
| // | |
| // This file is distributed under the University of Illinois Open Source | |
| // License. See LICENSE.TXT for details. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| // | |
| // This file implements the Enhanced Disassembly library's disassembler class. | |
| // The disassembler is responsible for vending individual instructions according | |
| // to a given architecture and disassembly syntax. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "EDDisassembler.h" | |
| #include "EDInst.h" | |
| #include "llvm/MC/EDInstInfo.h" | |
| #include "llvm/MC/MCAsmInfo.h" | |
| #include "llvm/MC/MCContext.h" | |
| #include "llvm/MC/MCDisassembler.h" | |
| #include "llvm/MC/MCExpr.h" | |
| #include "llvm/MC/MCInst.h" | |
| #include "llvm/MC/MCInstPrinter.h" | |
| #include "llvm/MC/MCRegisterInfo.h" | |
| #include "llvm/MC/MCStreamer.h" | |
| #include "llvm/MC/MCSubtargetInfo.h" | |
| #include "llvm/MC/MCParser/AsmLexer.h" | |
| #include "llvm/MC/MCParser/MCAsmParser.h" | |
| #include "llvm/MC/MCParser/MCParsedAsmOperand.h" | |
| #include "llvm/MC/MCTargetAsmLexer.h" | |
| #include "llvm/MC/MCTargetAsmParser.h" | |
| #include "llvm/Support/MemoryBuffer.h" | |
| #include "llvm/Support/MemoryObject.h" | |
| #include "llvm/Support/SourceMgr.h" | |
| #include "llvm/Support/TargetRegistry.h" | |
| #include "llvm/Support/TargetSelect.h" | |
| using namespace llvm; | |
| bool EDDisassembler::sInitialized = false; | |
| EDDisassembler::DisassemblerMap_t EDDisassembler::sDisassemblers; | |
| struct TripleMap { | |
| Triple::ArchType Arch; | |
| const char *String; | |
| }; | |
| static struct TripleMap triplemap[] = { | |
| { Triple::x86, "i386-unknown-unknown" }, | |
| { Triple::x86_64, "x86_64-unknown-unknown" }, | |
| { Triple::arm, "arm-unknown-unknown" }, | |
| { Triple::thumb, "thumb-unknown-unknown" }, | |
| { Triple::InvalidArch, NULL, } | |
| }; | |
| /// infoFromArch - Returns the TripleMap corresponding to a given architecture, | |
| /// or NULL if there is an error | |
| /// | |
| /// @arg arch - The Triple::ArchType for the desired architecture | |
| static const char *tripleFromArch(Triple::ArchType arch) { | |
| unsigned int infoIndex; | |
| for (infoIndex = 0; triplemap[infoIndex].String != NULL; ++infoIndex) { | |
| if (arch == triplemap[infoIndex].Arch) | |
| return triplemap[infoIndex].String; | |
| } | |
| return NULL; | |
| } | |
| /// getLLVMSyntaxVariant - gets the constant to use to get an assembly printer | |
| /// for the desired assembly syntax, suitable for passing to | |
| /// Target::createMCInstPrinter() | |
| /// | |
| /// @arg arch - The target architecture | |
| /// @arg syntax - The assembly syntax in sd form | |
| static int getLLVMSyntaxVariant(Triple::ArchType arch, | |
| EDDisassembler::AssemblySyntax syntax) { | |
| switch (syntax) { | |
| default: | |
| return -1; | |
| // Mappings below from X86AsmPrinter.cpp | |
| case EDDisassembler::kEDAssemblySyntaxX86ATT: | |
| if (arch == Triple::x86 || arch == Triple::x86_64) | |
| return 0; | |
| else | |
| return -1; | |
| case EDDisassembler::kEDAssemblySyntaxX86Intel: | |
| if (arch == Triple::x86 || arch == Triple::x86_64) | |
| return 1; | |
| else | |
| return -1; | |
| case EDDisassembler::kEDAssemblySyntaxARMUAL: | |
| if (arch == Triple::arm || arch == Triple::thumb) | |
| return 0; | |
| else | |
| return -1; | |
| } | |
| } | |
| void EDDisassembler::initialize() { | |
| if (sInitialized) | |
| return; | |
| sInitialized = true; | |
| InitializeAllTargetInfos(); | |
| InitializeAllTargetMCs(); | |
| InitializeAllAsmParsers(); | |
| InitializeAllDisassemblers(); | |
| } | |
| #undef BRINGUP_TARGET | |
| EDDisassembler *EDDisassembler::getDisassembler(Triple::ArchType arch, | |
| AssemblySyntax syntax) { | |
| CPUKey key; | |
| key.Arch = arch; | |
| key.Syntax = syntax; | |
| EDDisassembler::DisassemblerMap_t::iterator i = sDisassemblers.find(key); | |
| if (i != sDisassemblers.end()) { | |
| return i->second; | |
| } else { | |
| EDDisassembler* sdd = new EDDisassembler(key); | |
| if (!sdd->valid()) { | |
| delete sdd; | |
| return NULL; | |
| } | |
| sDisassemblers[key] = sdd; | |
| return sdd; | |
| } | |
| return NULL; | |
| } | |
| EDDisassembler *EDDisassembler::getDisassembler(StringRef str, | |
| AssemblySyntax syntax) { | |
| return getDisassembler(Triple(str).getArch(), syntax); | |
| } | |
| EDDisassembler::EDDisassembler(CPUKey &key) : | |
| Valid(false), | |
| HasSemantics(false), | |
| ErrorStream(nulls()), | |
| Key(key) { | |
| const char *triple = tripleFromArch(key.Arch); | |
| if (!triple) | |
| return; | |
| LLVMSyntaxVariant = getLLVMSyntaxVariant(key.Arch, key.Syntax); | |
| if (LLVMSyntaxVariant < 0) | |
| return; | |
| std::string tripleString(triple); | |
| std::string errorString; | |
| Tgt = TargetRegistry::lookupTarget(tripleString, | |
| errorString); | |
| if (!Tgt) | |
| return; | |
| MRI.reset(Tgt->createMCRegInfo(tripleString)); | |
| if (!MRI) | |
| return; | |
| initMaps(*MRI); | |
| AsmInfo.reset(Tgt->createMCAsmInfo(tripleString)); | |
| if (!AsmInfo) | |
| return; | |
| STI.reset(Tgt->createMCSubtargetInfo(tripleString, "", "")); | |
| if (!STI) | |
| return; | |
| Disassembler.reset(Tgt->createMCDisassembler(*STI)); | |
| if (!Disassembler) | |
| return; | |
| InstInfos = Disassembler->getEDInfo(); | |
| InstString.reset(new std::string); | |
| InstStream.reset(new raw_string_ostream(*InstString)); | |
| InstPrinter.reset(Tgt->createMCInstPrinter(LLVMSyntaxVariant, *AsmInfo, *STI)); | |
| if (!InstPrinter) | |
| return; | |
| GenericAsmLexer.reset(new AsmLexer(*AsmInfo)); | |
| SpecificAsmLexer.reset(Tgt->createMCAsmLexer(*MRI, *AsmInfo)); | |
| SpecificAsmLexer->InstallLexer(*GenericAsmLexer); | |
| initMaps(*MRI); | |
| Valid = true; | |
| } | |
| EDDisassembler::~EDDisassembler() { | |
| if (!valid()) | |
| return; | |
| } | |
| namespace { | |
| /// EDMemoryObject - a subclass of MemoryObject that allows use of a callback | |
| /// as provided by the sd interface. See MemoryObject. | |
| class EDMemoryObject : public llvm::MemoryObject { | |
| private: | |
| EDByteReaderCallback Callback; | |
| void *Arg; | |
| public: | |
| EDMemoryObject(EDByteReaderCallback callback, | |
| void *arg) : Callback(callback), Arg(arg) { } | |
| ~EDMemoryObject() { } | |
| uint64_t getBase() const { return 0x0; } | |
| uint64_t getExtent() const { return (uint64_t)-1; } | |
| int readByte(uint64_t address, uint8_t *ptr) const { | |
| if (!Callback) | |
| return -1; | |
| if (Callback(ptr, address, Arg)) | |
| return -1; | |
| return 0; | |
| } | |
| }; | |
| } | |
| EDInst *EDDisassembler::createInst(EDByteReaderCallback byteReader, | |
| uint64_t address, | |
| void *arg) { | |
| EDMemoryObject memoryObject(byteReader, arg); | |
| MCInst* inst = new MCInst; | |
| uint64_t byteSize; | |
| MCDisassembler::DecodeStatus S; | |
| S = Disassembler->getInstruction(*inst, byteSize, memoryObject, address, | |
| ErrorStream, nulls()); | |
| switch (S) { | |
| case MCDisassembler::Fail: | |
| case MCDisassembler::SoftFail: | |
| // FIXME: Do something different on soft failure mode? | |
| delete inst; | |
| return NULL; | |
| case MCDisassembler::Success: { | |
| const llvm::EDInstInfo *thisInstInfo = NULL; | |
| if (InstInfos) { | |
| thisInstInfo = &InstInfos[inst->getOpcode()]; | |
| } | |
| EDInst* sdInst = new EDInst(inst, byteSize, *this, thisInstInfo); | |
| return sdInst; | |
| } | |
| } | |
| return NULL; | |
| } | |
| void EDDisassembler::initMaps(const MCRegisterInfo ®isterInfo) { | |
| unsigned numRegisters = registerInfo.getNumRegs(); | |
| unsigned registerIndex; | |
| for (registerIndex = 0; registerIndex < numRegisters; ++registerIndex) { | |
| const char* registerName = registerInfo.get(registerIndex).Name; | |
| RegVec.push_back(registerName); | |
| RegRMap[registerName] = registerIndex; | |
| } | |
| switch (Key.Arch) { | |
| default: | |
| break; | |
| case Triple::x86: | |
| case Triple::x86_64: | |
| stackPointers.insert(registerIDWithName("SP")); | |
| stackPointers.insert(registerIDWithName("ESP")); | |
| stackPointers.insert(registerIDWithName("RSP")); | |
| programCounters.insert(registerIDWithName("IP")); | |
| programCounters.insert(registerIDWithName("EIP")); | |
| programCounters.insert(registerIDWithName("RIP")); | |
| break; | |
| case Triple::arm: | |
| case Triple::thumb: | |
| stackPointers.insert(registerIDWithName("SP")); | |
| programCounters.insert(registerIDWithName("PC")); | |
| break; | |
| } | |
| } | |
| const char *EDDisassembler::nameWithRegisterID(unsigned registerID) const { | |
| if (registerID >= RegVec.size()) | |
| return NULL; | |
| else | |
| return RegVec[registerID].c_str(); | |
| } | |
| unsigned EDDisassembler::registerIDWithName(const char *name) const { | |
| regrmap_t::const_iterator iter = RegRMap.find(std::string(name)); | |
| if (iter == RegRMap.end()) | |
| return 0; | |
| else | |
| return (*iter).second; | |
| } | |
| bool EDDisassembler::registerIsStackPointer(unsigned registerID) { | |
| return (stackPointers.find(registerID) != stackPointers.end()); | |
| } | |
| bool EDDisassembler::registerIsProgramCounter(unsigned registerID) { | |
| return (programCounters.find(registerID) != programCounters.end()); | |
| } | |
| int EDDisassembler::printInst(std::string &str, MCInst &inst) { | |
| PrinterMutex.acquire(); | |
| InstPrinter->printInst(&inst, *InstStream, ""); | |
| InstStream->flush(); | |
| str = *InstString; | |
| InstString->clear(); | |
| PrinterMutex.release(); | |
| return 0; | |
| } | |
| static void diag_handler(const SMDiagnostic &diag, | |
| void *context) | |
| { | |
| if (context) { | |
| EDDisassembler *disassembler = static_cast<EDDisassembler*>(context); | |
| diag.Print("", disassembler->ErrorStream); | |
| } | |
| } | |
| int EDDisassembler::parseInst(SmallVectorImpl<MCParsedAsmOperand*> &operands, | |
| SmallVectorImpl<AsmToken> &tokens, | |
| const std::string &str) { | |
| int ret = 0; | |
| switch (Key.Arch) { | |
| default: | |
| return -1; | |
| case Triple::x86: | |
| case Triple::x86_64: | |
| case Triple::arm: | |
| case Triple::thumb: | |
| break; | |
| } | |
| const char *cStr = str.c_str(); | |
| MemoryBuffer *buf = MemoryBuffer::getMemBuffer(cStr, cStr + strlen(cStr)); | |
| StringRef instName; | |
| SMLoc instLoc; | |
| SourceMgr sourceMgr; | |
| sourceMgr.setDiagHandler(diag_handler, static_cast<void*>(this)); | |
| sourceMgr.AddNewSourceBuffer(buf, SMLoc()); // ownership of buf handed over | |
| MCContext context(*AsmInfo, *MRI, NULL); | |
| OwningPtr<MCStreamer> streamer(createNullStreamer(context)); | |
| OwningPtr<MCAsmParser> genericParser(createMCAsmParser(sourceMgr, | |
| context, *streamer, | |
| *AsmInfo)); | |
| StringRef triple = tripleFromArch(Key.Arch); | |
| OwningPtr<MCSubtargetInfo> STI(Tgt->createMCSubtargetInfo(triple, "", "")); | |
| OwningPtr<MCTargetAsmParser> | |
| TargetParser(Tgt->createMCAsmParser(*STI, *genericParser)); | |
| AsmToken OpcodeToken = genericParser->Lex(); | |
| AsmToken NextToken = genericParser->Lex(); // consume next token, because specificParser expects us to | |
| if (OpcodeToken.is(AsmToken::Identifier)) { | |
| instName = OpcodeToken.getString(); | |
| instLoc = OpcodeToken.getLoc(); | |
| if (NextToken.isNot(AsmToken::Eof) && | |
| TargetParser->ParseInstruction(instName, instLoc, operands)) | |
| ret = -1; | |
| } else { | |
| ret = -1; | |
| } | |
| ParserMutex.acquire(); | |
| if (!ret) { | |
| GenericAsmLexer->setBuffer(buf); | |
| while (SpecificAsmLexer->Lex(), | |
| SpecificAsmLexer->isNot(AsmToken::Eof) && | |
| SpecificAsmLexer->isNot(AsmToken::EndOfStatement)) { | |
| if (SpecificAsmLexer->is(AsmToken::Error)) { | |
| ret = -1; | |
| break; | |
| } | |
| tokens.push_back(SpecificAsmLexer->getTok()); | |
| } | |
| } | |
| ParserMutex.release(); | |
| return ret; | |
| } | |
| int EDDisassembler::llvmSyntaxVariant() const { | |
| return LLVMSyntaxVariant; | |
| } |