1//===-- lib/MC/Disassembler.cpp - Disassembler Public C Interface ---------===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9 10#include "Disassembler.h" 11#include "llvm-c/Disassembler.h" 12#include "llvm/MC/MCAsmInfo.h" 13#include "llvm/MC/MCContext.h" 14#include "llvm/MC/MCDisassembler.h" 15#include "llvm/MC/MCInst.h" 16#include "llvm/MC/MCInstPrinter.h" 17#include "llvm/MC/MCInstrInfo.h" 18#include "llvm/MC/MCRegisterInfo.h" 19#include "llvm/MC/MCSubtargetInfo.h" 20#include "llvm/Support/ErrorHandling.h" 21#include "llvm/Support/MemoryObject.h" 22#include "llvm/Support/TargetRegistry.h" 23 24namespace llvm { 25class Target; 26} // namespace llvm 27using namespace llvm; 28 29// LLVMCreateDisasm() creates a disassembler for the TripleName. Symbolic 30// disassembly is supported by passing a block of information in the DisInfo 31// parameter and specifying the TagType and callback functions as described in 32// the header llvm-c/Disassembler.h . The pointer to the block and the 33// functions can all be passed as NULL. If successful, this returns a 34// disassembler context. If not, it returns NULL. 35// 36LLVMDisasmContextRef LLVMCreateDisasmCPU(const char *Triple, const char *CPU, 37 void *DisInfo, int TagType, 38 LLVMOpInfoCallback GetOpInfo, 39 LLVMSymbolLookupCallback SymbolLookUp){ 40 // Get the target. 41 std::string Error; 42 const Target *TheTarget = TargetRegistry::lookupTarget(Triple, Error); 43 assert(TheTarget && "Unable to create target!"); 44 45 // Get the assembler info needed to setup the MCContext. 46 const MCAsmInfo *MAI = TheTarget->createMCAsmInfo(Triple); 47 if (!MAI) 48 return 0; 49 50 const MCInstrInfo *MII = TheTarget->createMCInstrInfo(); 51 if (!MII) 52 return 0; 53 54 const MCRegisterInfo *MRI = TheTarget->createMCRegInfo(Triple); 55 if (!MRI) 56 return 0; 57 58 // Package up features to be passed to target/subtarget 59 std::string FeaturesStr; 60 61 const MCSubtargetInfo *STI = TheTarget->createMCSubtargetInfo(Triple, CPU, 62 FeaturesStr); 63 if (!STI) 64 return 0; 65 66 // Set up the MCContext for creating symbols and MCExpr's. 67 MCContext *Ctx = new MCContext(*MAI, *MRI, 0); 68 if (!Ctx) 69 return 0; 70 71 // Set up disassembler. 72 MCDisassembler *DisAsm = TheTarget->createMCDisassembler(*STI); 73 if (!DisAsm) 74 return 0; 75 DisAsm->setupForSymbolicDisassembly(GetOpInfo, SymbolLookUp, DisInfo, Ctx); 76 77 // Set up the instruction printer. 78 int AsmPrinterVariant = MAI->getAssemblerDialect(); 79 MCInstPrinter *IP = TheTarget->createMCInstPrinter(AsmPrinterVariant, 80 *MAI, *MII, *MRI, *STI); 81 if (!IP) 82 return 0; 83 84 LLVMDisasmContext *DC = new LLVMDisasmContext(Triple, DisInfo, TagType, 85 GetOpInfo, SymbolLookUp, 86 TheTarget, MAI, MRI, 87 STI, MII, Ctx, DisAsm, IP); 88 if (!DC) 89 return 0; 90 91 return DC; 92} 93 94LLVMDisasmContextRef LLVMCreateDisasm(const char *Triple, void *DisInfo, 95 int TagType, LLVMOpInfoCallback GetOpInfo, 96 LLVMSymbolLookupCallback SymbolLookUp) { 97 return LLVMCreateDisasmCPU(Triple, "", DisInfo, TagType, GetOpInfo, 98 SymbolLookUp); 99} 100 101// 102// LLVMDisasmDispose() disposes of the disassembler specified by the context. 103// 104void LLVMDisasmDispose(LLVMDisasmContextRef DCR){ 105 LLVMDisasmContext *DC = (LLVMDisasmContext *)DCR; 106 delete DC; 107} 108 109namespace { 110// 111// The memory object created by LLVMDisasmInstruction(). 112// 113class DisasmMemoryObject : public MemoryObject { 114 uint8_t *Bytes; 115 uint64_t Size; 116 uint64_t BasePC; 117public: 118 DisasmMemoryObject(uint8_t *bytes, uint64_t size, uint64_t basePC) : 119 Bytes(bytes), Size(size), BasePC(basePC) {} 120 121 uint64_t getBase() const { return BasePC; } 122 uint64_t getExtent() const { return Size; } 123 124 int readByte(uint64_t Addr, uint8_t *Byte) const { 125 if (Addr - BasePC >= Size) 126 return -1; 127 *Byte = Bytes[Addr - BasePC]; 128 return 0; 129 } 130}; 131} // end anonymous namespace 132 133// 134// LLVMDisasmInstruction() disassembles a single instruction using the 135// disassembler context specified in the parameter DC. The bytes of the 136// instruction are specified in the parameter Bytes, and contains at least 137// BytesSize number of bytes. The instruction is at the address specified by 138// the PC parameter. If a valid instruction can be disassembled its string is 139// returned indirectly in OutString which whos size is specified in the 140// parameter OutStringSize. This function returns the number of bytes in the 141// instruction or zero if there was no valid instruction. If this function 142// returns zero the caller will have to pick how many bytes they want to step 143// over by printing a .byte, .long etc. to continue. 144// 145size_t LLVMDisasmInstruction(LLVMDisasmContextRef DCR, uint8_t *Bytes, 146 uint64_t BytesSize, uint64_t PC, char *OutString, 147 size_t OutStringSize){ 148 LLVMDisasmContext *DC = (LLVMDisasmContext *)DCR; 149 // Wrap the pointer to the Bytes, BytesSize and PC in a MemoryObject. 150 DisasmMemoryObject MemoryObject(Bytes, BytesSize, PC); 151 152 uint64_t Size; 153 MCInst Inst; 154 const MCDisassembler *DisAsm = DC->getDisAsm(); 155 MCInstPrinter *IP = DC->getIP(); 156 MCDisassembler::DecodeStatus S; 157 S = DisAsm->getInstruction(Inst, Size, MemoryObject, PC, 158 /*REMOVE*/ nulls(), DC->CommentStream); 159 switch (S) { 160 case MCDisassembler::Fail: 161 case MCDisassembler::SoftFail: 162 // FIXME: Do something different for soft failure modes? 163 return 0; 164 165 case MCDisassembler::Success: { 166 DC->CommentStream.flush(); 167 StringRef Comments = DC->CommentsToEmit.str(); 168 169 SmallVector<char, 64> InsnStr; 170 raw_svector_ostream OS(InsnStr); 171 IP->printInst(&Inst, OS, Comments); 172 OS.flush(); 173 174 // Tell the comment stream that the vector changed underneath it. 175 DC->CommentsToEmit.clear(); 176 DC->CommentStream.resync(); 177 178 assert(OutStringSize != 0 && "Output buffer cannot be zero size"); 179 size_t OutputSize = std::min(OutStringSize-1, InsnStr.size()); 180 std::memcpy(OutString, InsnStr.data(), OutputSize); 181 OutString[OutputSize] = '\0'; // Terminate string. 182 183 return Size; 184 } 185 } 186 llvm_unreachable("Invalid DecodeStatus!"); 187} 188 189// 190// LLVMSetDisasmOptions() sets the disassembler's options. It returns 1 if it 191// can set all the Options and 0 otherwise. 192// 193int LLVMSetDisasmOptions(LLVMDisasmContextRef DCR, uint64_t Options){ 194 if (Options & LLVMDisassembler_Option_UseMarkup){ 195 LLVMDisasmContext *DC = (LLVMDisasmContext *)DCR; 196 MCInstPrinter *IP = DC->getIP(); 197 IP->setUseMarkup(1); 198 Options &= ~LLVMDisassembler_Option_UseMarkup; 199 } 200 if (Options & LLVMDisassembler_Option_PrintImmHex){ 201 LLVMDisasmContext *DC = (LLVMDisasmContext *)DCR; 202 MCInstPrinter *IP = DC->getIP(); 203 IP->setPrintImmHex(1); 204 Options &= ~LLVMDisassembler_Option_PrintImmHex; 205 } 206 if (Options & LLVMDisassembler_Option_AsmPrinterVariant){ 207 LLVMDisasmContext *DC = (LLVMDisasmContext *)DCR; 208 // Try to set up the new instruction printer. 209 const MCAsmInfo *MAI = DC->getAsmInfo(); 210 const MCInstrInfo *MII = DC->getInstrInfo(); 211 const MCRegisterInfo *MRI = DC->getRegisterInfo(); 212 const MCSubtargetInfo *STI = DC->getSubtargetInfo(); 213 int AsmPrinterVariant = MAI->getAssemblerDialect(); 214 AsmPrinterVariant = AsmPrinterVariant == 0 ? 1 : 0; 215 MCInstPrinter *IP = DC->getTarget()->createMCInstPrinter( 216 AsmPrinterVariant, *MAI, *MII, *MRI, *STI); 217 if (IP) { 218 DC->setIP(IP); 219 Options &= ~LLVMDisassembler_Option_AsmPrinterVariant; 220 } 221 } 222 return (Options == 0); 223} 224