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/MCRelocationInfo.h" 20 #include "llvm/MC/MCSubtargetInfo.h" 21 #include "llvm/MC/MCSymbolizer.h" 22 #include "llvm/Support/ErrorHandling.h" 23 #include "llvm/Support/FormattedStream.h" 24 #include "llvm/Support/MemoryObject.h" 25 #include "llvm/Support/TargetRegistry.h" 26 27 using 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 // 36 LLVMDisasmContextRef 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 if (!TheTarget) 44 return nullptr; 45 46 const MCRegisterInfo *MRI = TheTarget->createMCRegInfo(Triple); 47 if (!MRI) 48 return nullptr; 49 50 // Get the assembler info needed to setup the MCContext. 51 const MCAsmInfo *MAI = TheTarget->createMCAsmInfo(*MRI, Triple); 52 if (!MAI) 53 return nullptr; 54 55 const MCInstrInfo *MII = TheTarget->createMCInstrInfo(); 56 if (!MII) 57 return nullptr; 58 59 // Package up features to be passed to target/subtarget 60 std::string FeaturesStr; 61 62 const MCSubtargetInfo *STI = TheTarget->createMCSubtargetInfo(Triple, CPU, 63 FeaturesStr); 64 if (!STI) 65 return nullptr; 66 67 // Set up the MCContext for creating symbols and MCExpr's. 68 MCContext *Ctx = new MCContext(MAI, MRI, nullptr); 69 if (!Ctx) 70 return nullptr; 71 72 // Set up disassembler. 73 MCDisassembler *DisAsm = TheTarget->createMCDisassembler(*STI, *Ctx); 74 if (!DisAsm) 75 return nullptr; 76 77 std::unique_ptr<MCRelocationInfo> RelInfo( 78 TheTarget->createMCRelocationInfo(Triple, *Ctx)); 79 if (!RelInfo) 80 return nullptr; 81 82 std::unique_ptr<MCSymbolizer> Symbolizer(TheTarget->createMCSymbolizer( 83 Triple, GetOpInfo, SymbolLookUp, DisInfo, Ctx, RelInfo.release())); 84 DisAsm->setSymbolizer(std::move(Symbolizer)); 85 86 // Set up the instruction printer. 87 int AsmPrinterVariant = MAI->getAssemblerDialect(); 88 MCInstPrinter *IP = TheTarget->createMCInstPrinter(AsmPrinterVariant, 89 *MAI, *MII, *MRI, *STI); 90 if (!IP) 91 return nullptr; 92 93 LLVMDisasmContext *DC = new LLVMDisasmContext(Triple, DisInfo, TagType, 94 GetOpInfo, SymbolLookUp, 95 TheTarget, MAI, MRI, 96 STI, MII, Ctx, DisAsm, IP); 97 if (!DC) 98 return nullptr; 99 100 DC->setCPU(CPU); 101 return DC; 102 } 103 104 LLVMDisasmContextRef LLVMCreateDisasm(const char *Triple, void *DisInfo, 105 int TagType, LLVMOpInfoCallback GetOpInfo, 106 LLVMSymbolLookupCallback SymbolLookUp) { 107 return LLVMCreateDisasmCPU(Triple, "", DisInfo, TagType, GetOpInfo, 108 SymbolLookUp); 109 } 110 111 // 112 // LLVMDisasmDispose() disposes of the disassembler specified by the context. 113 // 114 void LLVMDisasmDispose(LLVMDisasmContextRef DCR){ 115 LLVMDisasmContext *DC = (LLVMDisasmContext *)DCR; 116 delete DC; 117 } 118 119 namespace { 120 // 121 // The memory object created by LLVMDisasmInstruction(). 122 // 123 class DisasmMemoryObject : public MemoryObject { 124 uint8_t *Bytes; 125 uint64_t Size; 126 uint64_t BasePC; 127 public: 128 DisasmMemoryObject(uint8_t *bytes, uint64_t size, uint64_t basePC) : 129 Bytes(bytes), Size(size), BasePC(basePC) {} 130 131 uint64_t getBase() const override { return BasePC; } 132 uint64_t getExtent() const override { return Size; } 133 134 int readByte(uint64_t Addr, uint8_t *Byte) const override { 135 if (Addr - BasePC >= Size) 136 return -1; 137 *Byte = Bytes[Addr - BasePC]; 138 return 0; 139 } 140 }; 141 } // end anonymous namespace 142 143 /// \brief Emits the comments that are stored in \p DC comment stream. 144 /// Each comment in the comment stream must end with a newline. 145 static void emitComments(LLVMDisasmContext *DC, 146 formatted_raw_ostream &FormattedOS) { 147 // Flush the stream before taking its content. 148 DC->CommentStream.flush(); 149 StringRef Comments = DC->CommentsToEmit.str(); 150 // Get the default information for printing a comment. 151 const MCAsmInfo *MAI = DC->getAsmInfo(); 152 const char *CommentBegin = MAI->getCommentString(); 153 unsigned CommentColumn = MAI->getCommentColumn(); 154 bool IsFirst = true; 155 while (!Comments.empty()) { 156 if (!IsFirst) 157 FormattedOS << '\n'; 158 // Emit a line of comments. 159 FormattedOS.PadToColumn(CommentColumn); 160 size_t Position = Comments.find('\n'); 161 FormattedOS << CommentBegin << ' ' << Comments.substr(0, Position); 162 // Move after the newline character. 163 Comments = Comments.substr(Position+1); 164 IsFirst = false; 165 } 166 FormattedOS.flush(); 167 168 // Tell the comment stream that the vector changed underneath it. 169 DC->CommentsToEmit.clear(); 170 DC->CommentStream.resync(); 171 } 172 173 /// \brief Gets latency information for \p Inst form the itinerary 174 /// scheduling model, based on \p DC information. 175 /// \return The maximum expected latency over all the operands or -1 176 /// if no information are available. 177 static int getItineraryLatency(LLVMDisasmContext *DC, const MCInst &Inst) { 178 const int NoInformationAvailable = -1; 179 180 // Check if we have a CPU to get the itinerary information. 181 if (DC->getCPU().empty()) 182 return NoInformationAvailable; 183 184 // Get itinerary information. 185 const MCSubtargetInfo *STI = DC->getSubtargetInfo(); 186 InstrItineraryData IID = STI->getInstrItineraryForCPU(DC->getCPU()); 187 // Get the scheduling class of the requested instruction. 188 const MCInstrDesc& Desc = DC->getInstrInfo()->get(Inst.getOpcode()); 189 unsigned SCClass = Desc.getSchedClass(); 190 191 int Latency = 0; 192 for (unsigned OpIdx = 0, OpIdxEnd = Inst.getNumOperands(); OpIdx != OpIdxEnd; 193 ++OpIdx) 194 Latency = std::max(Latency, IID.getOperandCycle(SCClass, OpIdx)); 195 196 return Latency; 197 } 198 199 /// \brief Gets latency information for \p Inst, based on \p DC information. 200 /// \return The maximum expected latency over all the definitions or -1 201 /// if no information are available. 202 static int getLatency(LLVMDisasmContext *DC, const MCInst &Inst) { 203 // Try to compute scheduling information. 204 const MCSubtargetInfo *STI = DC->getSubtargetInfo(); 205 const MCSchedModel *SCModel = STI->getSchedModel(); 206 const int NoInformationAvailable = -1; 207 208 // Check if we have a scheduling model for instructions. 209 if (!SCModel || !SCModel->hasInstrSchedModel()) 210 // Try to fall back to the itinerary model if we do not have a 211 // scheduling model. 212 return getItineraryLatency(DC, Inst); 213 214 // Get the scheduling class of the requested instruction. 215 const MCInstrDesc& Desc = DC->getInstrInfo()->get(Inst.getOpcode()); 216 unsigned SCClass = Desc.getSchedClass(); 217 const MCSchedClassDesc *SCDesc = SCModel->getSchedClassDesc(SCClass); 218 // Resolving the variant SchedClass requires an MI to pass to 219 // SubTargetInfo::resolveSchedClass. 220 if (!SCDesc || !SCDesc->isValid() || SCDesc->isVariant()) 221 return NoInformationAvailable; 222 223 // Compute output latency. 224 int Latency = 0; 225 for (unsigned DefIdx = 0, DefEnd = SCDesc->NumWriteLatencyEntries; 226 DefIdx != DefEnd; ++DefIdx) { 227 // Lookup the definition's write latency in SubtargetInfo. 228 const MCWriteLatencyEntry *WLEntry = STI->getWriteLatencyEntry(SCDesc, 229 DefIdx); 230 Latency = std::max(Latency, WLEntry->Cycles); 231 } 232 233 return Latency; 234 } 235 236 237 /// \brief Emits latency information in DC->CommentStream for \p Inst, based 238 /// on the information available in \p DC. 239 static void emitLatency(LLVMDisasmContext *DC, const MCInst &Inst) { 240 int Latency = getLatency(DC, Inst); 241 242 // Report only interesting latency. 243 if (Latency < 2) 244 return; 245 246 DC->CommentStream << "Latency: " << Latency << '\n'; 247 } 248 249 // 250 // LLVMDisasmInstruction() disassembles a single instruction using the 251 // disassembler context specified in the parameter DC. The bytes of the 252 // instruction are specified in the parameter Bytes, and contains at least 253 // BytesSize number of bytes. The instruction is at the address specified by 254 // the PC parameter. If a valid instruction can be disassembled its string is 255 // returned indirectly in OutString which whos size is specified in the 256 // parameter OutStringSize. This function returns the number of bytes in the 257 // instruction or zero if there was no valid instruction. If this function 258 // returns zero the caller will have to pick how many bytes they want to step 259 // over by printing a .byte, .long etc. to continue. 260 // 261 size_t LLVMDisasmInstruction(LLVMDisasmContextRef DCR, uint8_t *Bytes, 262 uint64_t BytesSize, uint64_t PC, char *OutString, 263 size_t OutStringSize){ 264 LLVMDisasmContext *DC = (LLVMDisasmContext *)DCR; 265 // Wrap the pointer to the Bytes, BytesSize and PC in a MemoryObject. 266 DisasmMemoryObject MemoryObject(Bytes, BytesSize, PC); 267 268 uint64_t Size; 269 MCInst Inst; 270 const MCDisassembler *DisAsm = DC->getDisAsm(); 271 MCInstPrinter *IP = DC->getIP(); 272 MCDisassembler::DecodeStatus S; 273 SmallVector<char, 64> InsnStr; 274 raw_svector_ostream Annotations(InsnStr); 275 S = DisAsm->getInstruction(Inst, Size, MemoryObject, PC, 276 /*REMOVE*/ nulls(), Annotations); 277 switch (S) { 278 case MCDisassembler::Fail: 279 case MCDisassembler::SoftFail: 280 // FIXME: Do something different for soft failure modes? 281 return 0; 282 283 case MCDisassembler::Success: { 284 Annotations.flush(); 285 StringRef AnnotationsStr = Annotations.str(); 286 287 SmallVector<char, 64> InsnStr; 288 raw_svector_ostream OS(InsnStr); 289 formatted_raw_ostream FormattedOS(OS); 290 IP->printInst(&Inst, FormattedOS, AnnotationsStr); 291 292 if (DC->getOptions() & LLVMDisassembler_Option_PrintLatency) 293 emitLatency(DC, Inst); 294 295 emitComments(DC, FormattedOS); 296 OS.flush(); 297 298 assert(OutStringSize != 0 && "Output buffer cannot be zero size"); 299 size_t OutputSize = std::min(OutStringSize-1, InsnStr.size()); 300 std::memcpy(OutString, InsnStr.data(), OutputSize); 301 OutString[OutputSize] = '\0'; // Terminate string. 302 303 return Size; 304 } 305 } 306 llvm_unreachable("Invalid DecodeStatus!"); 307 } 308 309 // 310 // LLVMSetDisasmOptions() sets the disassembler's options. It returns 1 if it 311 // can set all the Options and 0 otherwise. 312 // 313 int LLVMSetDisasmOptions(LLVMDisasmContextRef DCR, uint64_t Options){ 314 if (Options & LLVMDisassembler_Option_UseMarkup){ 315 LLVMDisasmContext *DC = (LLVMDisasmContext *)DCR; 316 MCInstPrinter *IP = DC->getIP(); 317 IP->setUseMarkup(1); 318 DC->addOptions(LLVMDisassembler_Option_UseMarkup); 319 Options &= ~LLVMDisassembler_Option_UseMarkup; 320 } 321 if (Options & LLVMDisassembler_Option_PrintImmHex){ 322 LLVMDisasmContext *DC = (LLVMDisasmContext *)DCR; 323 MCInstPrinter *IP = DC->getIP(); 324 IP->setPrintImmHex(1); 325 DC->addOptions(LLVMDisassembler_Option_PrintImmHex); 326 Options &= ~LLVMDisassembler_Option_PrintImmHex; 327 } 328 if (Options & LLVMDisassembler_Option_AsmPrinterVariant){ 329 LLVMDisasmContext *DC = (LLVMDisasmContext *)DCR; 330 // Try to set up the new instruction printer. 331 const MCAsmInfo *MAI = DC->getAsmInfo(); 332 const MCInstrInfo *MII = DC->getInstrInfo(); 333 const MCRegisterInfo *MRI = DC->getRegisterInfo(); 334 const MCSubtargetInfo *STI = DC->getSubtargetInfo(); 335 int AsmPrinterVariant = MAI->getAssemblerDialect(); 336 AsmPrinterVariant = AsmPrinterVariant == 0 ? 1 : 0; 337 MCInstPrinter *IP = DC->getTarget()->createMCInstPrinter( 338 AsmPrinterVariant, *MAI, *MII, *MRI, *STI); 339 if (IP) { 340 DC->setIP(IP); 341 DC->addOptions(LLVMDisassembler_Option_AsmPrinterVariant); 342 Options &= ~LLVMDisassembler_Option_AsmPrinterVariant; 343 } 344 } 345 if (Options & LLVMDisassembler_Option_SetInstrComments) { 346 LLVMDisasmContext *DC = (LLVMDisasmContext *)DCR; 347 MCInstPrinter *IP = DC->getIP(); 348 IP->setCommentStream(DC->CommentStream); 349 DC->addOptions(LLVMDisassembler_Option_SetInstrComments); 350 Options &= ~LLVMDisassembler_Option_SetInstrComments; 351 } 352 if (Options & LLVMDisassembler_Option_PrintLatency) { 353 LLVMDisasmContext *DC = (LLVMDisasmContext *)DCR; 354 DC->addOptions(LLVMDisassembler_Option_PrintLatency); 355 Options &= ~LLVMDisassembler_Option_PrintLatency; 356 } 357 return (Options == 0); 358 } 359