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