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