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