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