Disassembler.cpp 13 KB

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