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