Branch data Line data Source code
1 : : //===------------- Disassembler for in-memory function --------------------===//
2 : : //
3 : : // Modified for use in The Julia Language from code in the llvm-mc project:
4 : : // llvm-mc.cpp and Disassembler.cpp
5 : : //
6 : : // Original copyright:
7 : : //
8 : : // University of Illinois/NCSA
9 : : // Open Source License
10 : : // Copyright (c) 2003-2016 University of Illinois at Urbana-Champaign.
11 : : // All rights reserved.
12 : : //
13 : : // Developed by:
14 : : //
15 : : // LLVM Team
16 : : //
17 : : // University of Illinois at Urbana-Champaign
18 : : //
19 : : // http://llvm.org
20 : : //
21 : : // Permission is hereby granted, free of charge, to any person obtaining a copy of
22 : : // this software and associated documentation files (the "Software"), to deal with
23 : : // the Software without restriction, including without limitation the rights to
24 : : // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
25 : : // of the Software, and to permit persons to whom the Software is furnished to do
26 : : // so, subject to the following conditions:
27 : : //
28 : : // * Redistributions of source code must retain the above copyright notice,
29 : : // this list of conditions and the following disclaimers.
30 : : //
31 : : // * Redistributions in binary form must reproduce the above copyright notice,
32 : : // this list of conditions and the following disclaimers in the
33 : : // documentation and/or other materials provided with the distribution.
34 : : //
35 : : // * Neither the names of the LLVM Team, University of Illinois at
36 : : // Urbana-Champaign, nor the names of its contributors may be used to
37 : : // endorse or promote products derived from this Software without specific
38 : : // prior written permission.
39 : : //
40 : : // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
41 : : // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
42 : : // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
43 : : // CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
44 : : // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
45 : : // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
46 : : // SOFTWARE.
47 : : //===----------------------------------------------------------------------===//
48 : : //
49 : : // This class implements a disassembler of a memory block, given a function
50 : : // pointer and size.
51 : : //
52 : : //===----------------------------------------------------------------------===//
53 : :
54 : : #include <map>
55 : : #include <set>
56 : : #include <string>
57 : :
58 : : #include "llvm-version.h"
59 : :
60 : : // for outputting disassembly
61 : : #include <llvm/ADT/Triple.h>
62 : : #include <llvm/AsmParser/Parser.h>
63 : : #include <llvm/Analysis/TargetTransformInfo.h>
64 : : #include <llvm/BinaryFormat/COFF.h>
65 : : #include <llvm/BinaryFormat/MachO.h>
66 : : #include <llvm/DebugInfo/DIContext.h>
67 : : #include <llvm/DebugInfo/DWARF/DWARFContext.h>
68 : : #include <llvm/IR/AssemblyAnnotationWriter.h>
69 : : #include <llvm/IR/DebugInfo.h>
70 : : #include <llvm/IR/Function.h>
71 : : #include <llvm/IR/IntrinsicInst.h>
72 : : #include <llvm/IR/LLVMContext.h>
73 : : #include <llvm/IR/Module.h>
74 : : #include <llvm/MC/MCAsmBackend.h>
75 : : #include <llvm/MC/MCAsmInfo.h>
76 : : #include <llvm/MC/MCCodeEmitter.h>
77 : : #include <llvm/MC/MCContext.h>
78 : : #include <llvm/MC/MCDisassembler/MCDisassembler.h>
79 : : #include <llvm/MC/MCDisassembler/MCExternalSymbolizer.h>
80 : : #include <llvm/MC/MCExpr.h>
81 : : #include <llvm/MC/MCInst.h>
82 : : #include <llvm/MC/MCInstPrinter.h>
83 : : #include <llvm/MC/MCInstrAnalysis.h>
84 : : #include <llvm/MC/MCInstrInfo.h>
85 : : #include <llvm/MC/MCObjectFileInfo.h>
86 : : #include <llvm/MC/MCRegisterInfo.h>
87 : : #include <llvm/MC/MCStreamer.h>
88 : : #include <llvm/MC/MCSubtargetInfo.h>
89 : : #include <llvm/MC/MCSymbol.h>
90 : : #include <llvm/Object/ObjectFile.h>
91 : : #include <llvm/Support/FormattedStream.h>
92 : : #include <llvm/Support/MemoryBuffer.h>
93 : : #include <llvm/Support/NativeFormatting.h>
94 : : #include <llvm/Support/SourceMgr.h>
95 : : #if JL_LLVM_VERSION >= 140000
96 : : #include <llvm/MC/TargetRegistry.h>
97 : : #else
98 : : #include <llvm/Support/TargetRegistry.h>
99 : : #endif
100 : : #include <llvm/Support/TargetSelect.h>
101 : : #include <llvm/Support/raw_ostream.h>
102 : :
103 : : // for outputting assembly
104 : : #include <llvm/CodeGen/AsmPrinter.h>
105 : : #include <llvm/CodeGen/AsmPrinterHandler.h>
106 : : #include <llvm/CodeGen/MachineModuleInfo.h>
107 : : #include <llvm/CodeGen/Passes.h>
108 : : #include <llvm/CodeGen/TargetPassConfig.h>
109 : : #include <llvm/Support/CodeGen.h>
110 : : #include <llvm/IR/LegacyPassManager.h>
111 : :
112 : : #include <llvm-c/Disassembler.h>
113 : :
114 : : #include "julia.h"
115 : : #include "julia_internal.h"
116 : : #include "jitlayers.h"
117 : : #include "processor.h"
118 : :
119 : : using namespace llvm;
120 : : #include "debuginfo.h"
121 : : #include "julia_assert.h"
122 : :
123 : : // helper class for tracking inlining context while printing debug info
124 : : class DILineInfoPrinter {
125 : : // internal state:
126 : : std::vector<DILineInfo> context;
127 : : uint32_t inline_depth = 0;
128 : : // configuration options:
129 : : const char* LineStart = "; ";
130 : : bool bracket_outer = false;
131 : : bool collapse_recursive = true;
132 : :
133 : : enum {
134 : : output_none = 0,
135 : : output_source = 1,
136 : : } verbosity = output_source;
137 : : public:
138 : 112 : DILineInfoPrinter(const char *LineStart, bool bracket_outer)
139 : 112 : : LineStart(LineStart),
140 : 112 : bracket_outer(bracket_outer) {};
141 : 112 : void SetVerbosity(const char *c)
142 : : {
143 [ - + ]: 112 : if (StringRef("default") == c) {
144 : 0 : verbosity = output_source;
145 : : }
146 [ + + ]: 112 : else if (StringRef("source") == c) {
147 : 109 : verbosity = output_source;
148 : : }
149 [ + - ]: 3 : else if (StringRef("none") == c) {
150 : 3 : verbosity = output_none;
151 : : }
152 : 112 : }
153 : :
154 : : void emit_finish(raw_ostream &Out);
155 : : void emit_lineinfo(raw_ostream &Out, std::vector<DILineInfo> &DI);
156 : :
157 : : struct repeat {
158 : : size_t times;
159 : : const char *c;
160 : : };
161 : 10089 : struct repeat inlining_indent(const char *c)
162 : : {
163 : : return repeat{
164 : 10089 : std::max(inline_depth + bracket_outer, (uint32_t)1) - 1,
165 : 10089 : c };
166 : : }
167 : :
168 : : template<class T>
169 : 6 : void emit_lineinfo(std::string &Out, T &DI)
170 : : {
171 : 12 : raw_string_ostream OS(Out);
172 : 6 : emit_lineinfo(OS, DI);
173 : 6 : }
174 : :
175 : 3 : void emit_lineinfo(raw_ostream &Out, DILineInfo &DI)
176 : : {
177 : 6 : std::vector<DILineInfo> DIvec(1);
178 : 3 : DIvec[0] = DI;
179 : 3 : emit_lineinfo(Out, DIvec);
180 : 3 : }
181 : :
182 : 3 : void emit_lineinfo(raw_ostream &Out, DIInliningInfo &DI)
183 : : {
184 : 3 : uint32_t nframes = DI.getNumberOfFrames();
185 : 6 : std::vector<DILineInfo> DIvec(nframes);
186 [ + + ]: 6 : for (uint32_t i = 0; i < DI.getNumberOfFrames(); i++) {
187 : 3 : DIvec[i] = DI.getFrame(i);
188 : : }
189 : 3 : emit_lineinfo(Out, DIvec);
190 : 3 : }
191 : :
192 : 3 : void emit_finish(std::string &Out)
193 : : {
194 : 6 : raw_string_ostream OS(Out);
195 : 3 : emit_finish(OS);
196 : 3 : }
197 : : };
198 : :
199 : 20769 : static raw_ostream &operator<<(raw_ostream &Out, struct DILineInfoPrinter::repeat i)
200 : : {
201 [ + + ]: 20769 : while (i.times-- > 0)
202 : 10112 : Out << i.c;
203 : 10657 : return Out;
204 : : }
205 : :
206 : 115 : void DILineInfoPrinter::emit_finish(raw_ostream &Out)
207 : : {
208 : 115 : auto pops = inlining_indent("└");
209 [ + + ]: 115 : if (pops.times > 0)
210 : 31 : Out << LineStart << pops << '\n';
211 : 115 : context.clear();
212 : 115 : this->inline_depth = 0;
213 : 115 : }
214 : :
215 : 1227 : void DILineInfoPrinter::emit_lineinfo(raw_ostream &Out, std::vector<DILineInfo> &DI)
216 : : {
217 [ + + ]: 1227 : if (verbosity == output_none)
218 : 6 : return;
219 : 1221 : uint32_t nframes = DI.size();
220 [ - + ]: 1221 : if (nframes == 0)
221 : 0 : return; // just skip over lines with no debug info at all
222 : : // compute the size of the matching prefix in the inlining information stack
223 : : uint32_t nctx;
224 [ + + + + : 2654 : for (nctx = 0; nctx < context.size() && nctx < nframes; nctx++) {
+ + ]
225 : 2188 : const DILineInfo &CtxLine = context.at(nctx);
226 : 2188 : const DILineInfo &FrameLine = DI.at(nframes - 1 - nctx);
227 [ + + ]: 2188 : if (CtxLine != FrameLine) {
228 : 755 : break;
229 : : }
230 : : }
231 : 1221 : bool update_line_only = false;
232 [ + - ]: 1221 : if (collapse_recursive) {
233 [ + + ]: 1221 : if (nctx > 0) {
234 : : // check if we're adding more frames with the same method name,
235 : : // if so, drop all existing calls to it from the top of the context
236 : : // AND check if instead the context was previously printed that way
237 : : // but now has removed the recursive frames
238 : 601 : StringRef method = StringRef(context.at(nctx - 1).FunctionName).rtrim(';'); // last matching frame
239 [ + + + + : 1497 : if ((nctx < nframes && StringRef(DI.at(nframes - nctx - 1).FunctionName).rtrim(';') == method) ||
+ + ]
240 [ + + + + ]: 1497 : (nctx < context.size() && StringRef(context.at(nctx).FunctionName).rtrim(';') == method)) {
241 : 85 : update_line_only = true;
242 : : // transform nctx to exclude the combined frames
243 [ + + + + : 236 : while (nctx > 0 && StringRef(context.at(nctx - 1).FunctionName).rtrim(';') == method)
+ + ]
244 : 151 : nctx -= 1;
245 : : }
246 : : }
247 [ + + + + : 1221 : if (!update_line_only && nctx < context.size() && nctx < nframes) {
+ + + + ]
248 : : // look at the first non-matching element to see if we are only changing the line number
249 : 679 : const DILineInfo &CtxLine = context.at(nctx);
250 : 679 : const DILineInfo &FrameLine = DI.at(nframes - 1 - nctx);
251 [ + + ]: 679 : if (StringRef(CtxLine.FunctionName).rtrim(';') == StringRef(FrameLine.FunctionName).rtrim(';'))
252 : 526 : update_line_only = true;
253 : : }
254 : : }
255 [ # # # # : 0 : else if (nctx < context.size() && nctx < nframes) {
# # ]
256 : : // look at the first non-matching element to see if we are only changing the line number
257 : 0 : const DILineInfo &CtxLine = context.at(nctx);
258 : 0 : const DILineInfo &FrameLine = DI.at(nframes - 1 - nctx);
259 [ # # # # ]: 0 : if (CtxLine.FileName == FrameLine.FileName &&
260 [ # # ]: 0 : StringRef(CtxLine.FunctionName).rtrim(';') == StringRef(FrameLine.FunctionName).rtrim(';')) {
261 : 0 : update_line_only = true;
262 : : }
263 : : }
264 : : // examine how many frames we're returning from
265 [ + + ]: 1221 : if (nctx < context.size()) {
266 : : // compute the new inlining depth
267 : : uint32_t npops;
268 [ + - ]: 964 : if (collapse_recursive) {
269 : 964 : npops = 1;
270 : 964 : StringRef Prev = StringRef(context.at(nctx).FunctionName).rtrim(';');
271 [ + + ]: 1667 : for (uint32_t i = nctx + 1; i < context.size(); i++) {
272 : 703 : StringRef Next = StringRef(context.at(i).FunctionName).rtrim(';');
273 [ + + ]: 703 : if (Prev != Next)
274 : 412 : npops += 1;
275 : 703 : Prev = Next;
276 : : }
277 : : }
278 : : else {
279 : 0 : npops = context.size() - nctx;
280 : : }
281 : 964 : context.resize(nctx);
282 [ + + + + ]: 964 : update_line_only && (npops -= 1);
283 [ + + ]: 964 : if (npops > 0) {
284 : 652 : this->inline_depth -= npops;
285 : 652 : Out << LineStart << inlining_indent("│") << repeat{npops, "└"} << '\n';
286 : : }
287 : : }
288 : : // print the new frames
289 [ + + ]: 2712 : while (nctx < nframes) {
290 : 1491 : const DILineInfo &frame = DI.at(nframes - 1 - nctx);
291 : 1491 : Out << LineStart << inlining_indent("│");
292 : 1491 : nctx += 1;
293 : 1491 : context.push_back(frame);
294 [ + + ]: 1491 : if (update_line_only) {
295 : 611 : update_line_only = false;
296 : : }
297 : : else {
298 : 880 : this->inline_depth += 1;
299 [ + + + + ]: 880 : if (bracket_outer || nctx != 1)
300 : 800 : Out << "┌";
301 : : }
302 : 1491 : Out << " @ " << frame.FileName;
303 [ + - + + ]: 1491 : if (frame.Line != UINT_MAX && frame.Line != 0)
304 : 1444 : Out << ":" << frame.Line;
305 : 1491 : StringRef method = StringRef(frame.FunctionName).rtrim(';');
306 : 1491 : Out << " within `" << method << "`";
307 [ + - ]: 1491 : if (collapse_recursive) {
308 [ + + ]: 1783 : while (nctx < nframes) {
309 : 796 : const DILineInfo &frame = DI.at(nframes - 1 - nctx);
310 [ + + ]: 796 : if (StringRef(frame.FunctionName).rtrim(';') != method)
311 : 504 : break;
312 : 292 : nctx += 1;
313 : 292 : context.push_back(frame);
314 : 292 : Out << " @ " << frame.FileName
315 : 292 : << ":" << frame.Line;
316 : : }
317 : : }
318 : 1491 : Out << "\n";
319 : : }
320 : : #ifndef JL_NDEBUG
321 : 1221 : StringRef Prev = StringRef(context.at(0).FunctionName).rtrim(';');
322 : 1221 : uint32_t depth2 = 1;
323 [ + + ]: 3065 : for (uint32_t i = 1; i < nctx; i++) {
324 : 1844 : StringRef Next = StringRef(context.at(i).FunctionName).rtrim(';');
325 [ + - + + : 1844 : if (!collapse_recursive || Prev != Next)
+ + ]
326 : 1488 : depth2 += 1;
327 : 1844 : Prev = Next;
328 : : }
329 [ - + ]: 1221 : assert(this->inline_depth == depth2);
330 : : #endif
331 : : }
332 : :
333 : :
334 : : // adaptor class for printing line numbers before llvm IR lines
335 : : class LineNumberAnnotatedWriter : public AssemblyAnnotationWriter {
336 : : const DILocation *InstrLoc = nullptr;
337 : : DILineInfoPrinter LinePrinter;
338 : : DenseMap<const Instruction *, DILocation *> DebugLoc;
339 : : DenseMap<const Function *, DISubprogram *> Subprogram;
340 : : public:
341 : 106 : LineNumberAnnotatedWriter(const char *LineStart, bool bracket_outer, const char *debuginfo)
342 : 106 : : LinePrinter(LineStart, bracket_outer) {
343 : 106 : LinePrinter.SetVerbosity(debuginfo);
344 : 106 : }
345 : : virtual void emitFunctionAnnot(const Function *, formatted_raw_ostream &);
346 : : virtual void emitInstructionAnnot(const Instruction *, formatted_raw_ostream &);
347 : : virtual void emitInstructionAnnot(const DILocation *, formatted_raw_ostream &);
348 : : virtual void emitBasicBlockEndAnnot(const BasicBlock *, formatted_raw_ostream &);
349 : : // virtual void printInfoComment(const Value &, formatted_raw_ostream &) {}
350 : :
351 : 112 : void emitEnd(formatted_raw_ostream &Out) {
352 : 112 : LinePrinter.emit_finish(Out);
353 : 112 : InstrLoc = nullptr;
354 : 112 : }
355 : :
356 : 775 : void addSubprogram(const Function *F, DISubprogram *SP)
357 : : {
358 : 775 : Subprogram[F] = SP;
359 : 775 : }
360 : :
361 : 8184 : void addDebugLoc(const Instruction *I, DILocation *Loc)
362 : : {
363 : 8184 : DebugLoc[I] = Loc;
364 : 8184 : }
365 : : };
366 : :
367 : 145 : void LineNumberAnnotatedWriter::emitFunctionAnnot(
368 : : const Function *F, formatted_raw_ostream &Out)
369 : : {
370 : 145 : InstrLoc = nullptr;
371 : 145 : DISubprogram *FuncLoc = F->getSubprogram();
372 [ + + ]: 145 : if (!FuncLoc) {
373 : 89 : auto SP = Subprogram.find(F);
374 [ + + ]: 89 : if (SP != Subprogram.end())
375 : 49 : FuncLoc = SP->second;
376 : : }
377 [ + + ]: 145 : if (FuncLoc) {
378 : 210 : std::vector<DILineInfo> DIvec(1);
379 : 105 : DILineInfo &DI = DIvec.back();
380 : 105 : DI.FunctionName = FuncLoc->getName().str();
381 : 105 : DI.FileName = FuncLoc->getFilename().str();
382 : 105 : DI.Line = FuncLoc->getLine();
383 : 105 : LinePrinter.emit_lineinfo(Out, DIvec);
384 : : }
385 : 145 : }
386 : :
387 : 7831 : void LineNumberAnnotatedWriter::emitInstructionAnnot(
388 : : const Instruction *I, formatted_raw_ostream &Out)
389 : : {
390 : 7831 : const DILocation *NewInstrLoc = I->getDebugLoc();
391 [ + + ]: 7831 : if (!NewInstrLoc) {
392 : 7277 : auto Loc = DebugLoc.find(I);
393 [ + + ]: 7277 : if (Loc != DebugLoc.end())
394 : 7098 : NewInstrLoc = Loc->second;
395 : : }
396 : 7831 : emitInstructionAnnot(NewInstrLoc, Out);
397 : 7831 : Out << LinePrinter.inlining_indent(" ");
398 : 7831 : }
399 : :
400 : 8386 : void LineNumberAnnotatedWriter::emitInstructionAnnot(
401 : : const DILocation *NewInstrLoc, formatted_raw_ostream &Out)
402 : : {
403 [ + + + + ]: 8386 : if (NewInstrLoc && NewInstrLoc != InstrLoc) {
404 : 1116 : InstrLoc = NewInstrLoc;
405 : 2232 : std::vector<DILineInfo> DIvec;
406 : 1844 : do {
407 : 2960 : DIvec.emplace_back();
408 : 2960 : DILineInfo &DI = DIvec.back();
409 : 2960 : DIScope *scope = NewInstrLoc->getScope();
410 [ + - ]: 2960 : if (scope)
411 : 2960 : DI.FunctionName = scope->getName().str();
412 : 2960 : DI.FileName = NewInstrLoc->getFilename().str();
413 : 2960 : DI.Line = NewInstrLoc->getLine();
414 : 2960 : NewInstrLoc = NewInstrLoc->getInlinedAt();
415 [ + + ]: 2960 : } while (NewInstrLoc);
416 : 1116 : LinePrinter.emit_lineinfo(Out, DIvec);
417 : : }
418 : 8386 : }
419 : :
420 : 555 : void LineNumberAnnotatedWriter::emitBasicBlockEndAnnot(
421 : : const BasicBlock *BB, formatted_raw_ostream &Out)
422 : : {
423 [ + + ]: 555 : if (BB == &BB->getParent()->back())
424 : 88 : emitEnd(Out);
425 : 555 : }
426 : :
427 : 49 : static void jl_strip_llvm_debug(Module *m, bool all_meta, LineNumberAnnotatedWriter *AAW)
428 : : {
429 : : // strip metadata from all instructions in all functions in the module
430 : 49 : Instruction *deletelast = nullptr; // can't actually delete until the iterator advances
431 [ + + ]: 824 : for (Function &f : m->functions()) {
432 [ + - ]: 775 : if (AAW)
433 : 775 : AAW->addSubprogram(&f, f.getSubprogram());
434 [ + + ]: 1339 : for (BasicBlock &f_bb : f) {
435 [ + + ]: 8829 : for (Instruction &inst : f_bb) {
436 [ + + ]: 8265 : if (deletelast) {
437 : 81 : deletelast->eraseFromParent();
438 : 81 : deletelast = nullptr;
439 : : }
440 : : // remove dbg.declare and dbg.value calls
441 [ + + + + : 8265 : if (isa<DbgDeclareInst>(inst) || isa<DbgValueInst>(inst)) {
+ + ]
442 : 81 : deletelast = &inst;
443 : 81 : continue;
444 : : }
445 : :
446 : : // iterate over all metadata kinds and set to NULL to remove
447 [ + - ]: 8184 : if (all_meta) {
448 : 16368 : SmallVector<std::pair<unsigned, MDNode*>, 4> MDForInst;
449 : 8184 : inst.getAllMetadataOtherThanDebugLoc(MDForInst);
450 [ + + ]: 9653 : for (const auto &md_iter : MDForInst) {
451 : 1469 : inst.setMetadata(md_iter.first, NULL);
452 : : }
453 : : }
454 : : // record debug location before erasing it
455 [ + - ]: 8184 : if (AAW)
456 : 8184 : AAW->addDebugLoc(&inst, inst.getDebugLoc());
457 : 8184 : inst.setDebugLoc(DebugLoc());
458 : : }
459 [ - + ]: 564 : if (deletelast) {
460 : 0 : deletelast->eraseFromParent();
461 : 0 : deletelast = nullptr;
462 : : }
463 : : }
464 : 775 : f.setSubprogram(NULL);
465 : : }
466 [ + - ]: 49 : if (all_meta) {
467 [ + + ]: 846 : for (GlobalObject &g : m->global_objects()) {
468 : 797 : g.clearMetadata();
469 : : }
470 : : }
471 : : // now that the subprogram is not referenced, we can delete it too
472 [ + - ]: 49 : if (NamedMDNode *md = m->getNamedMetadata("llvm.dbg.cu"))
473 : 49 : m->eraseNamedMetadata(md);
474 : : //if (NamedMDNode *md = m->getNamedMetadata("llvm.module.flags"))
475 : : // m->eraseNamedMetadata(md);
476 : 49 : }
477 : :
478 : 0 : void jl_strip_llvm_debug(Module *m)
479 : : {
480 : 0 : jl_strip_llvm_debug(m, false, NULL);
481 : 0 : }
482 : :
483 : 49 : void jl_strip_llvm_addrspaces(Module *m)
484 : : {
485 : 98 : legacy::PassManager PM;
486 : 49 : PM.add(createRemoveJuliaAddrspacesPass());
487 : 49 : PM.run(*m);
488 : 49 : }
489 : :
490 : : // print an llvm IR acquired from jl_get_llvmf
491 : : // warning: this takes ownership of, and destroys, dump->TSM
492 : : extern "C" JL_DLLEXPORT
493 : 82 : jl_value_t *jl_dump_function_ir_impl(jl_llvmf_dump_t *dump, char strip_ir_metadata, char dump_module, const char *debuginfo)
494 : : {
495 : 164 : std::string code;
496 : 164 : raw_string_ostream stream(code);
497 : :
498 : : {
499 : : //RAII will release the module
500 : 164 : auto TSM = std::unique_ptr<orc::ThreadSafeModule>(unwrap(dump->TSM));
501 : : //If TSM is not passed in, then the context MUST be locked externally.
502 : : //RAII will release the lock
503 : 82 : Optional<orc::ThreadSafeContext::Lock> lock;
504 [ + - ]: 82 : if (TSM) {
505 : 82 : lock.emplace(TSM->getContext().getLock());
506 : : }
507 : 82 : Function *llvmf = cast<Function>(unwrap(dump->F));
508 [ + - + - : 82 : if (!llvmf || (!llvmf->isDeclaration() && !llvmf->getParent()))
- + - + ]
509 : 0 : jl_error("jl_dump_function_ir: Expected Function* in a temporary Module");
510 : :
511 : 164 : LineNumberAnnotatedWriter AAW{"; ", false, debuginfo};
512 [ - + ]: 82 : if (!llvmf->getParent()) {
513 : : // print the function declaration as-is
514 : 0 : llvmf->print(stream, &AAW);
515 [ # # ]: 0 : delete llvmf;
516 : : }
517 : : else {
518 [ + - + - ]: 82 : assert(TSM && TSM->getModuleUnlocked() == llvmf->getParent() && "Passed module was not the same as function parent!");
519 : 82 : auto m = TSM->getModuleUnlocked();
520 [ + + ]: 82 : if (strip_ir_metadata) {
521 : 49 : std::string llvmfn(llvmf->getName());
522 : 49 : jl_strip_llvm_addrspaces(m);
523 : 49 : jl_strip_llvm_debug(m, true, &AAW);
524 : : // rewriting the function type creates a new function, so look it up again
525 : 49 : llvmf = m->getFunction(llvmfn);
526 : : }
527 [ + + ]: 82 : if (dump_module) {
528 : 6 : m->print(stream, &AAW);
529 : : }
530 : : else {
531 : 76 : llvmf->print(stream, &AAW);
532 : : }
533 : : }
534 : : }
535 : :
536 : 82 : return jl_pchar_to_string(stream.str().data(), stream.str().size());
537 : : }
538 : :
539 : : static void jl_dump_asm_internal(
540 : : uintptr_t Fptr, size_t Fsize, int64_t slide,
541 : : object::SectionRef Section,
542 : : DIContext *di_ctx,
543 : : raw_ostream &rstream,
544 : : const char* asm_variant,
545 : : const char* debuginfo,
546 : : bool binary);
547 : :
548 : : // This isn't particularly fast, but neither is printing assembly, and they're only used for interactive mode
549 : 3 : static uint64_t compute_obj_symsize(object::SectionRef Section, uint64_t offset)
550 : : {
551 : : // Scan the object file for the closest symbols above and below offset in the given section
552 : 3 : uint64_t lo = 0;
553 : 3 : uint64_t hi = 0;
554 : 3 : bool setlo = false;
555 : 3 : uint64_t SAddr = Section.getAddress();
556 : 3 : uint64_t SSize = Section.getSize();
557 [ + - - + ]: 3 : if (offset < SAddr || offset >= SAddr + SSize)
558 : 0 : return 0;
559 : : // test for lower and upper symbol bounds relative to other symbols
560 : 3 : hi = SAddr + SSize;
561 [ + + ]: 30 : for (const object::SymbolRef &Sym : Section.getObject()->symbols()) {
562 [ + + ]: 27 : if (!Section.containsSymbol(Sym))
563 : 18 : continue;
564 : 9 : uint64_t Addr = cantFail(Sym.getAddress());
565 [ + + + - ]: 9 : if (Addr <= offset && Addr >= lo) {
566 : : // test for lower bound on symbol
567 : 6 : lo = Addr;
568 : 6 : setlo = true;
569 : : }
570 [ + + + - ]: 9 : if (Addr > offset && Addr < hi) {
571 : : // test for upper bound on symbol
572 : 3 : hi = Addr;
573 : : }
574 : : }
575 [ + - ]: 3 : if (setlo)
576 : 3 : return hi - lo;
577 : 0 : return 0;
578 : : }
579 : :
580 : : // print a native disassembly for the function starting at fptr
581 : : extern "C" JL_DLLEXPORT
582 : 3 : jl_value_t *jl_dump_fptr_asm_impl(uint64_t fptr, char raw_mc, const char* asm_variant, const char *debuginfo, char binary)
583 : : {
584 [ - + ]: 3 : assert(fptr != 0);
585 : 6 : std::string code;
586 : 6 : raw_string_ostream stream(code);
587 : :
588 : : // Find debug info (line numbers) to print alongside
589 : 3 : object::SectionRef Section;
590 : 3 : int64_t slide = 0;
591 : 3 : uint64_t symsize = 0;
592 : 3 : llvm::DIContext *context = NULL;
593 [ - + ]: 3 : if (!jl_DI_for_fptr(fptr, &symsize, &slide, &Section, &context)) {
594 [ # # ]: 0 : if (!jl_dylib_DI_for_fptr(fptr, &Section, &slide, &context,
595 : : false, NULL, NULL, NULL, NULL)) {
596 : 0 : jl_printf(JL_STDERR, "WARNING: Unable to find function pointer\n");
597 : 0 : return jl_pchar_to_string("", 0);
598 : : }
599 : : }
600 [ + - + - : 3 : if (symsize == 0 && Section.getObject())
+ - ]
601 : 3 : symsize = compute_obj_symsize(Section, fptr + slide);
602 [ - + ]: 3 : if (symsize == 0) {
603 : 0 : jl_printf(JL_STDERR, "WARNING: Could not determine size of symbol\n");
604 : 0 : return jl_pchar_to_string("", 0);
605 : : }
606 : :
607 [ - + ]: 3 : if (raw_mc) {
608 : 0 : return (jl_value_t*)jl_pchar_to_array((char*)fptr, symsize);
609 : : }
610 : :
611 : : // Dump assembly code
612 : 3 : jl_ptls_t ptls = jl_current_task->ptls;
613 : 3 : int8_t gc_state = jl_gc_safe_enter(ptls);
614 : 3 : jl_dump_asm_internal(
615 : : fptr, symsize, slide,
616 : : Section, context,
617 : : stream,
618 : : asm_variant,
619 : : debuginfo,
620 : : binary);
621 : 3 : jl_gc_safe_leave(ptls, gc_state);
622 : :
623 : 3 : return jl_pchar_to_string(stream.str().data(), stream.str().size());
624 : : }
625 : :
626 : :
627 : : namespace {
628 : : #define FuncMCView ArrayRef<uint8_t>
629 : :
630 : : // Look up a symbol, and return a const char* to its name when the
631 : : // address matches. We currently just use "L<address>" as name for the
632 : : // symbol. We could easily get more fancy, e.g. numbering symbols
633 : : // sequentially or encoding the line number, but that doesn't seem
634 : : // necessary.
635 : : class SymbolTable {
636 : : typedef std::map<uint64_t, std::string> TableType;
637 : : TableType Table;
638 : : MCContext& Ctx;
639 : : const FuncMCView &MemObj;
640 : : int Pass;
641 : : const object::ObjectFile *object;
642 : : uint64_t ip; // virtual instruction pointer of the current instruction
643 : : int64_t slide;
644 : : public:
645 : 3 : SymbolTable(MCContext &Ctx, const object::ObjectFile *object, int64_t slide, const FuncMCView &MemObj):
646 : 3 : Ctx(Ctx), MemObj(MemObj), object(object), ip(0), slide(slide) {}
647 : 6 : const FuncMCView &getMemoryObject() const { return MemObj; }
648 : 6 : void setPass(int Pass) { this->Pass = Pass; }
649 : 6 : int getPass() const { return Pass; }
650 : : void insertAddress(uint64_t addr);
651 : : // void createSymbol(const char *name, uint64_t addr);
652 : : void createSymbols();
653 : : const char *lookupSymbolName(uint64_t addr);
654 : : MCSymbol *lookupSymbol(uint64_t addr);
655 : : StringRef getSymbolNameAt(uint64_t offset) const;
656 : : const char *lookupLocalPC(size_t addr);
657 : : void setIP(uint64_t addr);
658 : : uint64_t getIP() const;
659 : : };
660 : :
661 : 24 : void SymbolTable::setIP(uint64_t addr)
662 : : {
663 : 24 : ip = addr;
664 : 24 : }
665 : 6 : uint64_t SymbolTable::getIP() const
666 : : {
667 : 6 : return ip;
668 : : }
669 : :
670 : 9 : const char *SymbolTable::lookupLocalPC(size_t addr) {
671 : 9 : jl_frame_t *frame = NULL;
672 : 9 : jl_getFunctionInfo(&frame,
673 : : addr,
674 : : /*skipC*/0,
675 : : /*noInline*/1/* the entry pointer shouldn't have inlining */);
676 : 9 : char *name = frame->func_name; // TODO: free me
677 : 9 : free(frame->file_name);
678 : 9 : free(frame);
679 : 9 : return name;
680 : : }
681 : :
682 : 9 : StringRef SymbolTable::getSymbolNameAt(uint64_t offset) const
683 : : {
684 [ - + ]: 9 : if (object == NULL)
685 : 0 : return StringRef();
686 : 9 : object::section_iterator ESection = object->section_end();
687 [ + + ]: 90 : for (const object::SymbolRef &Sym : object->symbols()) {
688 : 81 : auto Sect = cantFail(Sym.getSection());
689 [ + + ]: 81 : if (Sect == ESection)
690 : 54 : continue;
691 [ + + ]: 63 : if (Sect->getAddress() == 0)
692 : 36 : continue;
693 : 27 : uint64_t Addr = cantFail(Sym.getAddress());
694 [ - + ]: 27 : if (Addr == offset) {
695 : 0 : auto sNameOrError = Sym.getName();
696 [ # # ]: 0 : if (sNameOrError)
697 : 0 : return sNameOrError.get();
698 : : }
699 : : }
700 : 9 : return StringRef();
701 : : }
702 : :
703 : : // Insert an address
704 : 0 : void SymbolTable::insertAddress(uint64_t addr)
705 : : {
706 : 0 : Table[addr] = "";
707 : 0 : }
708 : : // Create symbols for all addresses
709 : 3 : void SymbolTable::createSymbols()
710 : : {
711 : 3 : uintptr_t Fptr = (uintptr_t)MemObj.data();
712 : 3 : uintptr_t Fsize = MemObj.size();
713 : 3 : for (TableType::iterator isymb = Table.begin(), esymb = Table.end();
714 [ - + ]: 3 : isymb != esymb; ++isymb) {
715 : 0 : uintptr_t rel = isymb->first - ip;
716 : 0 : uintptr_t addr = isymb->first;
717 [ # # # # ]: 0 : if (Fptr <= addr && addr < Fptr + Fsize) {
718 : 0 : std::string name;
719 : 0 : raw_string_ostream(name) << "L" << rel;
720 : 0 : isymb->second = name;
721 : : }
722 : : else {
723 : 0 : const char *global = lookupLocalPC(addr);
724 [ # # # # ]: 0 : if (global && global[0])
725 : 0 : isymb->second = global;
726 : : // TODO: free(global)?
727 : : }
728 : : }
729 : 3 : }
730 : :
731 : 15 : const char *SymbolTable::lookupSymbolName(uint64_t addr)
732 : : {
733 : 15 : TableType::iterator Sym;
734 : : bool insertion;
735 : 15 : std::tie(Sym, insertion) = Table.insert(std::make_pair(addr, std::string()));
736 [ + + ]: 15 : if (insertion) {
737 : : // First time we've seen addr: try to look it up
738 : 9 : StringRef local_name = getSymbolNameAt(addr + slide);
739 [ + - ]: 9 : if (local_name.empty()) {
740 : 9 : const char *global = lookupLocalPC(addr);
741 [ - + ]: 9 : if (global) {
742 : : //std::string name;
743 : : //raw_string_ostream(name) << global << "@0x" << std::hex
744 : : // << std::setfill('0') << std::setw(2 * sizeof(void*))
745 : : // << addr;
746 : : //Sym->second = name.str();
747 : 0 : Sym->second = global;
748 : : }
749 : : }
750 : : else {
751 : 0 : Sym->second = local_name.str();
752 : : }
753 : : }
754 [ + - ]: 15 : return Sym->second.empty() ? NULL : Sym->second.c_str();
755 : : }
756 : :
757 : 9 : MCSymbol *SymbolTable::lookupSymbol(uint64_t addr)
758 : : {
759 : 9 : TableType::iterator Sym = Table.find(addr);
760 [ - + - - : 9 : if (Sym == Table.end() || Sym->second.empty())
+ - ]
761 : 9 : return NULL;
762 : 0 : MCSymbol *symb = Ctx.getOrCreateSymbol(Sym->second);
763 [ # # ]: 0 : assert(symb->isUndefined());
764 : 0 : return symb;
765 : : }
766 : :
767 : 6 : static const char *SymbolLookup(void *DisInfo, uint64_t ReferenceValue, uint64_t *ReferenceType,
768 : : uint64_t ReferencePC, const char **ReferenceName)
769 : : {
770 : 6 : uint64_t RTypeIn = *ReferenceType;
771 : 6 : SymbolTable *SymTab = (SymbolTable*)DisInfo;
772 : 6 : *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;
773 : 6 : *ReferenceName = NULL;
774 [ + - ]: 6 : if (SymTab->getPass() != 0) {
775 [ - + ]: 6 : if (RTypeIn == LLVMDisassembler_ReferenceType_In_Branch) {
776 : 0 : uint64_t addr = ReferenceValue + SymTab->getIP(); // probably pc-rel
777 : 0 : const char *symbolName = SymTab->lookupSymbolName(addr);
778 : 0 : return symbolName;
779 : : }
780 [ - + ]: 6 : else if (RTypeIn == LLVMDisassembler_ReferenceType_In_PCrel_Load) {
781 : 0 : uint64_t addr = ReferenceValue + SymTab->getIP();
782 : 0 : const char *symbolName = SymTab->lookupSymbolName(addr);
783 [ # # ]: 0 : if (symbolName) {
784 : 0 : *ReferenceType = LLVMDisassembler_ReferenceType_Out_LitPool_SymAddr;
785 : 0 : *ReferenceName = symbolName;
786 : : }
787 : : }
788 [ + - ]: 6 : else if (RTypeIn == LLVMDisassembler_ReferenceType_InOut_None) {
789 : 6 : uint64_t addr = ReferenceValue; // probably not pc-rel
790 : 6 : const char *symbolName = SymTab->lookupSymbolName(addr);
791 : 6 : return symbolName;
792 : : }
793 : : }
794 : 0 : return NULL;
795 : : }
796 : :
797 : 6 : static int OpInfoLookup(void *DisInfo, uint64_t PC, uint64_t Offset, uint64_t Size,
798 : : int TagType, void *TagBuf)
799 : : {
800 : 6 : SymbolTable *SymTab = (SymbolTable*)DisInfo;
801 : 6 : LLVMOpInfo1 *info = (LLVMOpInfo1*)TagBuf;
802 : 6 : memset(info, 0, sizeof(*info));
803 [ - + ]: 6 : if (TagType != 1)
804 : 0 : return 0; // Unknown data format
805 : 6 : PC += SymTab->getIP() - (uint64_t)(uintptr_t)SymTab->getMemoryObject().data(); // add offset from MemoryObject base
806 : : // TODO: see if we knew of a relocation applied at PC
807 : : // info->AddSymbol.Present = 1;
808 : : // info->AddSymbol.Name = name;
809 : : // info->AddSymbol.Value = pointer; // unused by LLVM
810 : : // info->Value = 0; // offset
811 : : // return 1; // Success
812 : 6 : return 0;
813 : : }
814 : : } // namespace
815 : :
816 : : // Stringify raw bytes as a comment string.
817 : 3 : std::string rawCodeComment(const llvm::ArrayRef<uint8_t>& Memory, const llvm::Triple& Triple)
818 : : {
819 : 6 : std::string Buffer{"; "};
820 : 6 : llvm::raw_string_ostream Stream{Buffer};
821 : 3 : auto Address = reinterpret_cast<uintptr_t>(Memory.data());
822 : : // write abbreviated address
823 : 3 : llvm::write_hex(Stream, Address & 0xffff, HexPrintStyle::Lower, 4);
824 : 3 : Stream << ":";
825 : 3 : auto Arch = Triple.getArch();
826 [ + - - + ]: 3 : bool FixedLength = !(Arch == Triple::x86 || Arch == Triple::x86_64);
827 [ - + ]: 3 : if (FixedLength)
828 : 0 : Stream << " ";
829 [ - + - - : 3 : if (FixedLength && Triple.isLittleEndian()) {
- + ]
830 [ # # ]: 0 : for (auto Iter = Memory.rbegin(); Iter != Memory.rend(); ++Iter)
831 : 0 : llvm::write_hex(Stream, *Iter, HexPrintStyle::Lower, 2);
832 : : }
833 : : else {
834 : : // variable-length or (fixed-length) big-endian format
835 [ + + ]: 19 : for (auto Byte : Memory) {
836 [ + - ]: 16 : if (!FixedLength)
837 : 16 : Stream << " ";
838 : 16 : llvm::write_hex(Stream, Byte, HexPrintStyle::Lower, 2);
839 : : }
840 : : }
841 : 3 : return Stream.str();
842 : : }
843 : :
844 : 3 : static void jl_dump_asm_internal(
845 : : uintptr_t Fptr, size_t Fsize, int64_t slide,
846 : : object::SectionRef Section,
847 : : DIContext *di_ctx,
848 : : raw_ostream &rstream,
849 : : const char* asm_variant,
850 : : const char* debuginfo,
851 : : bool binary)
852 : : {
853 : : // GC safe
854 : : // Get the host information
855 : 3 : Triple TheTriple(sys::getProcessTriple());
856 : :
857 : 3 : const auto &target = jl_get_llvm_disasm_target();
858 : 3 : const auto &cpu = target.first;
859 : 3 : const auto &features = target.second;
860 : :
861 : 3 : std::string err;
862 : 3 : const Target *TheTarget = TargetRegistry::lookupTarget(TheTriple.str(), err);
863 : :
864 : : // Set up required helpers and streamer
865 : 3 : SourceMgr SrcMgr;
866 : :
867 : 3 : MCTargetOptions Options;
868 : : std::unique_ptr<MCAsmInfo> MAI(
869 : 3 : TheTarget->createMCAsmInfo(*TheTarget->createMCRegInfo(TheTriple.str()), TheTriple.str(), Options));
870 [ + - ]: 3 : assert(MAI && "Unable to create target asm info!");
871 : :
872 : 3 : std::unique_ptr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TheTriple.str()));
873 [ + - ]: 3 : assert(MRI && "Unable to create target register info!");
874 : :
875 : : std::unique_ptr<llvm::MCSubtargetInfo> STI(
876 : 3 : TheTarget->createMCSubtargetInfo(TheTriple.str(), cpu, features));
877 [ + - ]: 3 : assert(STI && "Unable to create subtarget info!");
878 : :
879 : : #if JL_LLVM_VERSION >= 130000
880 : 3 : MCContext Ctx(TheTriple, MAI.get(), MRI.get(), STI.get(), &SrcMgr);
881 : : std::unique_ptr<MCObjectFileInfo> MOFI(
882 : 3 : TheTarget->createMCObjectFileInfo(Ctx, /*PIC=*/false, /*LargeCodeModel=*/ false));
883 : 3 : Ctx.setObjectFileInfo(MOFI.get());
884 : : #else
885 : : std::unique_ptr<MCObjectFileInfo> MOFI(new MCObjectFileInfo());
886 : : MCContext Ctx(MAI.get(), MRI.get(), MOFI.get(), &SrcMgr);
887 : : MOFI->InitMCObjectFileInfo(TheTriple, /* PIC */ false, Ctx);
888 : : #endif
889 : :
890 : 3 : std::unique_ptr<MCDisassembler> DisAsm(TheTarget->createMCDisassembler(*STI, Ctx));
891 [ - + ]: 3 : if (!DisAsm) {
892 : 0 : rstream << "ERROR: no disassembler for target " << TheTriple.str();
893 : 0 : return;
894 : : }
895 : 3 : unsigned OutputAsmVariant = 0; // ATT or Intel-style assembly
896 : :
897 [ - + ]: 3 : if (strcmp(asm_variant, "intel") == 0) {
898 : 0 : OutputAsmVariant = 1;
899 : : }
900 : 3 : bool ShowEncoding = false;
901 : :
902 : : std::unique_ptr<MCInstrInfo> MCII(
903 : 6 : TheTarget->createMCInstrInfo());
904 : : std::unique_ptr<MCInstrAnalysis> MCIA(
905 : 6 : TheTarget->createMCInstrAnalysis(MCII.get()));
906 : : std::unique_ptr<MCInstPrinter> IP(
907 : 6 : TheTarget->createMCInstPrinter(TheTriple, OutputAsmVariant, *MAI, *MCII, *MRI));
908 : : //IP->setPrintImmHex(true); // prefer hex or decimal immediates
909 : 3 : std::unique_ptr<MCCodeEmitter> CE;
910 : 3 : std::unique_ptr<MCAsmBackend> MAB;
911 [ - + ]: 3 : if (ShowEncoding) {
912 : : #if JL_LLVM_VERSION >= 150000
913 : : CE.reset(TheTarget->createMCCodeEmitter(*MCII, Ctx));
914 : : #else
915 : 0 : CE.reset(TheTarget->createMCCodeEmitter(*MCII, *MRI, Ctx));
916 : : #endif
917 : 0 : MAB.reset(TheTarget->createMCAsmBackend(*STI, *MRI, Options));
918 : : }
919 : :
920 : : // createAsmStreamer expects a unique_ptr to a formatted stream, which means
921 : : // it will destruct the stream when it is done. We cannot have this, so we
922 : : // start out with a raw stream, and create formatted stream from it here.
923 : : // LLVM will destroy the formatted stream, and we keep the raw stream.
924 : 6 : std::unique_ptr<formatted_raw_ostream> ustream(new formatted_raw_ostream(rstream));
925 : : std::unique_ptr<MCStreamer> Streamer(
926 : 3 : TheTarget->createAsmStreamer(Ctx, std::move(ustream), /*asmverbose*/true,
927 : : /*useDwarfDirectory*/ true,
928 : : IP.release(),
929 : 3 : std::move(CE), std::move(MAB),
930 : 9 : /*ShowInst*/ false));
931 : : #if JL_LLVM_VERSION >= 140000
932 : 3 : Streamer->initSections(true, *STI);
933 : : #else
934 : : Streamer->InitSections(true);
935 : : #endif
936 : :
937 : : // Make the MemoryObject wrapper
938 : 3 : ArrayRef<uint8_t> memoryObject(const_cast<uint8_t*>((const uint8_t*)Fptr),Fsize);
939 : 6 : SymbolTable DisInfo(Ctx, Section.getObject(), slide, memoryObject);
940 : :
941 : 6 : DILineInfoTable di_lineinfo;
942 [ + - ]: 3 : if (di_ctx)
943 : 3 : di_lineinfo = di_ctx->getLineInfoForAddressRange(makeAddress(Section, Fptr + slide), Fsize);
944 [ + - ]: 3 : if (!di_lineinfo.empty()) {
945 : 3 : auto cur_addr = di_lineinfo[0].first;
946 : 3 : auto nlineinfo = di_lineinfo.size();
947 : : // filter out line infos that doesn't contain any instructions
948 : 3 : unsigned j = 0;
949 [ + + ]: 6 : for (unsigned i = 1; i < nlineinfo; i++) {
950 : 3 : auto &info = di_lineinfo[i];
951 [ + - ]: 3 : if (info.first != cur_addr)
952 : 3 : j++;
953 : 3 : cur_addr = info.first;
954 [ - + ]: 3 : if (i != j) {
955 : 0 : di_lineinfo[j] = std::move(info);
956 : : }
957 : : }
958 [ - + ]: 3 : if (j + 1 < nlineinfo) {
959 : 0 : di_lineinfo.resize(j + 1);
960 : : }
961 : : }
962 : :
963 [ + + ]: 3 : if (binary) {
964 : : // Print the complete address and the size at the top (instruction addresses are abbreviated)
965 : 2 : std::string Buffer{"; code origin: "};
966 : 1 : llvm::raw_string_ostream Stream{Buffer};
967 : 1 : auto Address = reinterpret_cast<uintptr_t>(memoryObject.data());
968 : 1 : llvm::write_hex(Stream, Address, HexPrintStyle::Lower, 16);
969 : 1 : Stream << ", code size: " << memoryObject.size();
970 : 1 : Streamer->emitRawText(Stream.str());
971 : : }
972 : :
973 : : // Take two passes: In the first pass we record all branch labels,
974 : : // in the second we actually perform the output
975 [ + + ]: 9 : for (int pass = 0; pass < 2; ++ pass) {
976 : 6 : DisInfo.setPass(pass);
977 [ + + ]: 6 : if (pass != 0) {
978 : : // Switch to symbolic disassembly. We cannot do this
979 : : // before the first pass, because this changes branch
980 : : // targets from immediate values (constants) to
981 : : // expressions, which are not handled correctly by
982 : : // MCIA->evaluateBranch. (It should be possible to rewrite
983 : : // this routine to handle this case correctly as well.)
984 : : // Could add OpInfoLookup here
985 : 6 : DisAsm->setSymbolizer(std::unique_ptr<MCSymbolizer>(new MCExternalSymbolizer(
986 : : Ctx,
987 : 6 : std::unique_ptr<MCRelocationInfo>(new MCRelocationInfo(Ctx)),
988 : : OpInfoLookup,
989 : : SymbolLookup,
990 : 3 : &DisInfo)));
991 : : }
992 : :
993 : 6 : uint64_t nextLineAddr = -1;
994 : 6 : DILineInfoTable::iterator di_lineIter = di_lineinfo.begin();
995 : 6 : DILineInfoTable::iterator di_lineEnd = di_lineinfo.end();
996 : 12 : DILineInfoPrinter dbgctx{"; ", true};
997 : 6 : dbgctx.SetVerbosity(debuginfo);
998 [ + + ]: 6 : if (pass != 0) {
999 [ + - + - ]: 3 : if (di_ctx && di_lineIter != di_lineEnd) {
1000 : : // Set up the line info
1001 : 3 : nextLineAddr = di_lineIter->first;
1002 [ - + ]: 3 : if (nextLineAddr != (uint64_t)(Fptr + slide)) {
1003 : 0 : std::string buf;
1004 : 0 : dbgctx.emit_lineinfo(buf, di_lineIter->second);
1005 [ # # ]: 0 : if (!buf.empty()) {
1006 : 0 : Streamer->emitRawText(buf);
1007 : : }
1008 : : }
1009 : : }
1010 : : }
1011 : :
1012 : 6 : uint64_t Index = 0;
1013 : 6 : uint64_t insSize = 0;
1014 : :
1015 : : // Do the disassembly
1016 [ + + ]: 24 : for (Index = 0; Index < Fsize; Index += insSize) {
1017 : :
1018 [ + + + - : 18 : if (pass != 0 && nextLineAddr != (uint64_t)-1 && Index + Fptr + slide == nextLineAddr) {
+ + ]
1019 [ + - ]: 6 : if (di_ctx) {
1020 : 12 : std::string buf;
1021 : : DILineInfoSpecifier infoSpec(
1022 : : DILineInfoSpecifier::FileLineInfoKind::RawValue,
1023 : 6 : DILineInfoSpecifier::FunctionNameKind::ShortName);
1024 : 6 : DIInliningInfo dbg = di_ctx->getInliningInfoForAddress(makeAddress(Section, Index + Fptr + slide), infoSpec);
1025 [ + + ]: 6 : if (dbg.getNumberOfFrames()) {
1026 : 3 : dbgctx.emit_lineinfo(buf, dbg);
1027 : : }
1028 : : else {
1029 : 3 : dbgctx.emit_lineinfo(buf, di_lineIter->second);
1030 : : }
1031 [ + - ]: 6 : if (!buf.empty()) {
1032 : 6 : Streamer->emitRawText(buf);
1033 : : }
1034 : 6 : nextLineAddr = (++di_lineIter)->first;
1035 : : }
1036 : : }
1037 : :
1038 : 18 : DisInfo.setIP(Fptr+Index);
1039 [ + + ]: 18 : if (pass != 0) {
1040 : : // Uncomment this to output addresses for all instructions
1041 : : // stream << Index << ": ";
1042 : 9 : MCSymbol *symbol = DisInfo.lookupSymbol(Fptr+Index);
1043 [ - + ]: 9 : if (symbol) {
1044 : 0 : Streamer->emitLabel(symbol);
1045 : : }
1046 : : }
1047 : :
1048 : 36 : MCInst Inst;
1049 : : MCDisassembler::DecodeStatus S;
1050 : 18 : FuncMCView view = memoryObject.slice(Index);
1051 : 36 : S = DisAsm->getInstruction(Inst, insSize, view, 0,
1052 [ + + ]: 18 : /*CStream*/ pass != 0 ? Streamer->GetCommentOS() : nulls());
1053 [ + + - + : 18 : if (pass != 0 && Streamer->GetCommentOS().tell() > 0)
- + ]
1054 : 0 : Streamer->GetCommentOS() << '\n';
1055 [ - - + - ]: 18 : switch (S) {
1056 : 0 : case MCDisassembler::Fail:
1057 [ # # ]: 0 : if (insSize == 0) // skip illegible bytes
1058 : : #if defined(_CPU_PPC_) || defined(_CPU_PPC64_) || defined(_CPU_ARM_) || defined(_CPU_AARCH64_)
1059 : : insSize = 4; // instructions are always 4 bytes
1060 : : #else
1061 : 0 : insSize = 1; // attempt to slide 1 byte forward
1062 : : #endif
1063 [ # # ]: 0 : if (pass != 0) {
1064 : 0 : std::string _buf;
1065 : 0 : raw_string_ostream buf(_buf);
1066 [ # # ]: 0 : if (insSize == 4) {
1067 : 0 : buf << "\t.long\t";
1068 : 0 : llvm::write_hex(buf, *(uint32_t*)(Fptr + Index), HexPrintStyle::PrefixLower, 8);
1069 : : }
1070 : : else {
1071 [ # # ]: 0 : for (uint64_t i = 0; i < insSize; ++i) {
1072 : 0 : buf << "\t.byte\t";
1073 : 0 : llvm::write_hex(buf, *(uint8_t*)(Fptr + Index + i), HexPrintStyle::PrefixLower, 2);
1074 : : }
1075 : : }
1076 : 0 : Streamer->emitRawText(StringRef(buf.str()));
1077 : : }
1078 : 0 : break;
1079 : :
1080 : 0 : case MCDisassembler::SoftFail:
1081 [ # # ]: 0 : if (pass != 0) {
1082 : 0 : Streamer->emitRawText(StringRef("potentially undefined instruction encoding:"));
1083 : : }
1084 : : // Fall through
1085 : :
1086 : : case MCDisassembler::Success:
1087 [ + + ]: 18 : if (pass == 0) {
1088 : : // Pass 0: Record all branch target references
1089 [ + - ]: 9 : if (MCIA) {
1090 : 9 : const MCInstrDesc &opcode = MCII->get(Inst.getOpcode());
1091 [ + - - + : 9 : if (opcode.isBranch() || opcode.isCall()) {
- + ]
1092 : : uint64_t addr;
1093 [ # # ]: 0 : if (MCIA->evaluateBranch(Inst, Fptr + Index, insSize, addr))
1094 : 0 : DisInfo.insertAddress(addr);
1095 : : }
1096 : : }
1097 : : }
1098 : : else {
1099 : : // Pass 1: Output instruction
1100 [ + - ]: 9 : if (pass != 0) {
1101 : : // attempt to symbolicate any immediate operands
1102 : 9 : const MCInstrDesc &opinfo = MCII->get(Inst.getOpcode());
1103 [ + + ]: 30 : for (unsigned Op = 0; Op < opinfo.NumOperands; Op++) {
1104 : 21 : const MCOperand &OpI = Inst.getOperand(Op);
1105 [ + + ]: 21 : if (OpI.isImm()) {
1106 : 9 : int64_t imm = OpI.getImm();
1107 [ - + ]: 9 : if (opinfo.OpInfo[Op].OperandType == MCOI::OPERAND_PCREL)
1108 : 0 : imm += Fptr + Index;
1109 : 9 : const char *name = DisInfo.lookupSymbolName(imm);
1110 [ - + ]: 9 : if (name)
1111 : 0 : Streamer->AddComment(name);
1112 : : }
1113 : : }
1114 : : }
1115 [ + + ]: 9 : if (binary)
1116 : 3 : Streamer->emitRawText(rawCodeComment(memoryObject.slice(Index, insSize), TheTriple));
1117 : 9 : Streamer->emitInstruction(Inst, *STI);
1118 : : }
1119 : 18 : break;
1120 : : }
1121 : : }
1122 : :
1123 : 6 : DisInfo.setIP(Fptr);
1124 [ + + ]: 6 : if (pass == 0)
1125 : 3 : DisInfo.createSymbols();
1126 : :
1127 [ + + + - ]: 6 : if (pass != 0 && di_ctx) {
1128 : 6 : std::string buf;
1129 : 3 : dbgctx.emit_finish(buf);
1130 [ + - ]: 3 : if (!buf.empty()) {
1131 : 3 : Streamer->emitRawText(buf);
1132 : : }
1133 : : }
1134 : : }
1135 : : }
1136 : :
1137 : : /// addPassesToX helper drives creation and initialization of TargetPassConfig.
1138 : : static MCContext *
1139 : 24 : addPassesToGenerateCode(LLVMTargetMachine *TM, PassManagerBase &PM) {
1140 : 24 : TargetPassConfig *PassConfig = TM->createPassConfig(PM);
1141 : 24 : PassConfig->setDisableVerify(false);
1142 : 24 : PM.add(PassConfig);
1143 : : MachineModuleInfoWrapperPass *MMIWP =
1144 : 24 : new MachineModuleInfoWrapperPass(TM);
1145 : 24 : PM.add(MMIWP);
1146 [ - + ]: 24 : if (PassConfig->addISelPasses())
1147 : 0 : return NULL;
1148 : 24 : PassConfig->addMachinePasses();
1149 : 24 : PassConfig->setInitialized();
1150 : 24 : return &MMIWP->getMMI().getContext();
1151 : : }
1152 : :
1153 : : class LineNumberPrinterHandler : public AsmPrinterHandler {
1154 : : MCStreamer &S;
1155 : : LineNumberAnnotatedWriter LinePrinter;
1156 : : std::string Buffer;
1157 : : llvm::raw_string_ostream RawStream;
1158 : : llvm::formatted_raw_ostream Stream;
1159 : :
1160 : : public:
1161 : 24 : LineNumberPrinterHandler(AsmPrinter &Printer, const char *debuginfo)
1162 : 48 : : S(*Printer.OutStreamer),
1163 : : LinePrinter("; ", true, debuginfo),
1164 : 24 : RawStream(Buffer),
1165 : 24 : Stream(RawStream) {}
1166 : :
1167 : 603 : void emitAndReset() {
1168 : 603 : Stream.flush();
1169 : 603 : RawStream.flush();
1170 [ + + ]: 603 : if (Buffer.empty())
1171 : 518 : return;
1172 : 85 : S.emitRawText(Buffer);
1173 : 85 : Buffer.clear();
1174 : : }
1175 : :
1176 : 0 : virtual void setSymbolSize(const MCSymbol *Sym, uint64_t Size) override {}
1177 : : //virtual void beginModule(Module *M) override {}
1178 : 24 : virtual void endModule() override {}
1179 : : /// note that some AsmPrinter implementations may not call beginFunction at all
1180 : 24 : virtual void beginFunction(const MachineFunction *MF) override {
1181 : 24 : LinePrinter.emitFunctionAnnot(&MF->getFunction(), Stream);
1182 : 24 : emitAndReset();
1183 : 24 : }
1184 : : //virtual void markFunctionEnd() override {}
1185 : 24 : virtual void endFunction(const MachineFunction *MF) override {
1186 : 24 : LinePrinter.emitEnd(Stream);
1187 : 24 : emitAndReset();
1188 : 24 : }
1189 : : //virtual void beginFragment(const MachineBasicBlock *MBB,
1190 : : // ExceptionSymbolProvider ESP) override {}
1191 : : //virtual void endFragment() override {}
1192 : : //virtual void beginFunclet(const MachineBasicBlock &MBB,
1193 : : // MCSymbol *Sym = nullptr) override {}
1194 : : //virtual void endFunclet() override {}
1195 : 555 : virtual void beginInstruction(const MachineInstr *MI) override {
1196 : 555 : LinePrinter.emitInstructionAnnot(MI->getDebugLoc(), Stream);
1197 : 555 : emitAndReset();
1198 : 555 : }
1199 : 555 : virtual void endInstruction() override {}
1200 : : };
1201 : :
1202 : : // get a native assembly for llvm::Function
1203 : : extern "C" JL_DLLEXPORT
1204 : 24 : jl_value_t *jl_dump_function_asm_impl(jl_llvmf_dump_t* dump, char raw_mc, const char* asm_variant, const char *debuginfo, char binary)
1205 : : {
1206 : : // precise printing via IR assembler
1207 : 48 : SmallVector<char, 4096> ObjBufferSV;
1208 : : { // scope block
1209 : 24 : auto TSM = std::unique_ptr<orc::ThreadSafeModule>(unwrap(dump->TSM));
1210 : 24 : llvm::raw_svector_ostream asmfile(ObjBufferSV);
1211 : 24 : TSM->withModuleDo([&](Module &m) {
1212 : 24 : Function *f = cast<Function>(unwrap(dump->F));
1213 [ - + ]: 24 : assert(!f->isDeclaration());
1214 [ + + ]: 281 : for (auto &f2 : m.functions()) {
1215 [ + + + - : 257 : if (f != &f2 && !f->isDeclaration())
+ + ]
1216 : 233 : f2.deleteBody();
1217 : : }
1218 : 24 : });
1219 : 24 : auto TMBase = jl_ExecutionEngine->cloneTargetMachine();
1220 : 24 : LLVMTargetMachine *TM = static_cast<LLVMTargetMachine*>(TMBase.get());
1221 : 24 : legacy::PassManager PM;
1222 : 24 : addTargetPasses(&PM, TM->getTargetTriple(), TM->getTargetIRAnalysis());
1223 [ - + ]: 24 : if (raw_mc) {
1224 : 0 : raw_svector_ostream obj_OS(ObjBufferSV);
1225 [ # # ]: 0 : if (TM->addPassesToEmitFile(PM, obj_OS, nullptr, CGFT_ObjectFile, false, nullptr))
1226 : 0 : return jl_an_empty_string;
1227 : 0 : TSM->withModuleDo([&](Module &m) { PM.run(m); });
1228 : : }
1229 : : else {
1230 : 24 : MCContext *Context = addPassesToGenerateCode(TM, PM);
1231 [ - + ]: 24 : if (!Context)
1232 : 0 : return jl_an_empty_string;
1233 : 24 : Context->setGenDwarfForAssembly(false);
1234 : : // Duplicate LLVMTargetMachine::addAsmPrinter here so we can set the asm dialect and add the custom annotation printer
1235 : 24 : const MCSubtargetInfo &STI = *TM->getMCSubtargetInfo();
1236 : 24 : const MCAsmInfo &MAI = *TM->getMCAsmInfo();
1237 : 24 : const MCRegisterInfo &MRI = *TM->getMCRegisterInfo();
1238 : 24 : const MCInstrInfo &MII = *TM->getMCInstrInfo();
1239 : 24 : unsigned OutputAsmDialect = MAI.getAssemblerDialect();
1240 [ + + ]: 24 : if (!strcmp(asm_variant, "att"))
1241 : 23 : OutputAsmDialect = 0;
1242 [ + + ]: 24 : if (!strcmp(asm_variant, "intel"))
1243 : 1 : OutputAsmDialect = 1;
1244 : 24 : MCInstPrinter *InstPrinter = TM->getTarget().createMCInstPrinter(
1245 : : jl_ExecutionEngine->getTargetTriple(), OutputAsmDialect, MAI, MII, MRI);
1246 : 24 : std::unique_ptr<MCAsmBackend> MAB(TM->getTarget().createMCAsmBackend(
1247 : 24 : STI, MRI, TM->Options.MCOptions));
1248 : 24 : std::unique_ptr<MCCodeEmitter> MCE;
1249 [ - + ]: 24 : if (binary) { // enable MCAsmStreamer::AddEncodingComment printing
1250 : : #if JL_LLVM_VERSION >= 150000
1251 : : MCE.reset(TM->getTarget().createMCCodeEmitter(MII, *Context));
1252 : : #else
1253 : 0 : MCE.reset(TM->getTarget().createMCCodeEmitter(MII, MRI, *Context));
1254 : : #endif
1255 : : }
1256 : 24 : auto FOut = std::make_unique<formatted_raw_ostream>(asmfile);
1257 : 24 : std::unique_ptr<MCStreamer> S(TM->getTarget().createAsmStreamer(
1258 : 24 : *Context, std::move(FOut), true,
1259 : : true, InstPrinter,
1260 : 24 : std::move(MCE), std::move(MAB),
1261 : 24 : false));
1262 : : std::unique_ptr<AsmPrinter> Printer(
1263 : 24 : TM->getTarget().createAsmPrinter(*TM, std::move(S)));
1264 : 48 : Printer->addAsmPrinterHandler(AsmPrinter::HandlerInfo(
1265 : 48 : std::unique_ptr<AsmPrinterHandler>(new LineNumberPrinterHandler(*Printer, debuginfo)),
1266 : : "emit", "Debug Info Emission", "Julia", "Julia::LineNumberPrinterHandler Markup"));
1267 [ - + ]: 24 : if (!Printer)
1268 : 0 : return jl_an_empty_string;
1269 : 24 : PM.add(Printer.release());
1270 : 24 : PM.add(createFreeMachineFunctionPass());
1271 : 48 : TSM->withModuleDo([&](Module &m){ PM.run(m); });
1272 : : }
1273 : : }
1274 : 24 : return jl_pchar_to_string(ObjBufferSV.data(), ObjBufferSV.size());
1275 : : }
1276 : :
1277 : : extern "C" JL_DLLEXPORT
1278 : 0 : LLVMDisasmContextRef jl_LLVMCreateDisasm_impl(
1279 : : const char *TripleName, void *DisInfo, int TagType,
1280 : : LLVMOpInfoCallback GetOpInfo, LLVMSymbolLookupCallback SymbolLookUp)
1281 : : {
1282 : 0 : return LLVMCreateDisasm(TripleName, DisInfo, TagType, GetOpInfo, SymbolLookUp);
1283 : : }
1284 : :
1285 : : extern "C" JL_DLLEXPORT
1286 : 0 : JL_DLLEXPORT size_t jl_LLVMDisasmInstruction_impl(
1287 : : LLVMDisasmContextRef DC, uint8_t *Bytes, uint64_t BytesSize,
1288 : : uint64_t PC, char *OutString, size_t OutStringSize)
1289 : : {
1290 : 0 : return LLVMDisasmInstruction(DC, Bytes, BytesSize, PC, OutString, OutStringSize);
1291 : : }
|