File: | lib/MC/MCDisassembler/Disassembler.cpp |
Warning: | line 82, column 12 Potential leak of memory pointed to by 'Ctx' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 | /// 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 | /// 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 | /// 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 | int16_t 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 | /// 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_PrintLatency16) | |||
279 | emitLatency(DC, Inst); | |||
280 | ||||
281 | emitComments(DC, FormattedOS); | |||
282 | ||||
283 | assert(OutStringSize != 0 && "Output buffer cannot be zero size")((OutStringSize != 0 && "Output buffer cannot be zero size" ) ? static_cast<void> (0) : __assert_fail ("OutStringSize != 0 && \"Output buffer cannot be zero size\"" , "/build/llvm-toolchain-snapshot-8~svn350071/lib/MC/MCDisassembler/Disassembler.cpp" , 283, __PRETTY_FUNCTION__)); | |||
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!")::llvm::llvm_unreachable_internal("Invalid DecodeStatus!", "/build/llvm-toolchain-snapshot-8~svn350071/lib/MC/MCDisassembler/Disassembler.cpp" , 291); | |||
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_UseMarkup1){ | |||
300 | LLVMDisasmContext *DC = static_cast<LLVMDisasmContext *>(DCR); | |||
301 | MCInstPrinter *IP = DC->getIP(); | |||
302 | IP->setUseMarkup(true); | |||
303 | DC->addOptions(LLVMDisassembler_Option_UseMarkup1); | |||
304 | Options &= ~LLVMDisassembler_Option_UseMarkup1; | |||
305 | } | |||
306 | if (Options & LLVMDisassembler_Option_PrintImmHex2){ | |||
307 | LLVMDisasmContext *DC = static_cast<LLVMDisasmContext *>(DCR); | |||
308 | MCInstPrinter *IP = DC->getIP(); | |||
309 | IP->setPrintImmHex(true); | |||
310 | DC->addOptions(LLVMDisassembler_Option_PrintImmHex2); | |||
311 | Options &= ~LLVMDisassembler_Option_PrintImmHex2; | |||
312 | } | |||
313 | if (Options & LLVMDisassembler_Option_AsmPrinterVariant4){ | |||
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_AsmPrinterVariant4); | |||
326 | Options &= ~LLVMDisassembler_Option_AsmPrinterVariant4; | |||
327 | } | |||
328 | } | |||
329 | if (Options & LLVMDisassembler_Option_SetInstrComments8) { | |||
330 | LLVMDisasmContext *DC = static_cast<LLVMDisasmContext *>(DCR); | |||
331 | MCInstPrinter *IP = DC->getIP(); | |||
332 | IP->setCommentStream(DC->CommentStream); | |||
333 | DC->addOptions(LLVMDisassembler_Option_SetInstrComments8); | |||
334 | Options &= ~LLVMDisassembler_Option_SetInstrComments8; | |||
335 | } | |||
336 | if (Options & LLVMDisassembler_Option_PrintLatency16) { | |||
337 | LLVMDisasmContext *DC = static_cast<LLVMDisasmContext *>(DCR); | |||
338 | DC->addOptions(LLVMDisassembler_Option_PrintLatency16); | |||
339 | Options &= ~LLVMDisassembler_Option_PrintLatency16; | |||
340 | } | |||
341 | return (Options == 0); | |||
342 | } |