1 //===-- ProfiledBinary.cpp - Binary decoder ---------------------*- C++ -*-===//
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 "ProfiledBinary.h"
10 #include "ErrorHandling.h"
11 #include "ProfileGenerator.h"
12 #include "llvm/ADT/Triple.h"
13 #include "llvm/DebugInfo/Symbolize/SymbolizableModule.h"
14 #include "llvm/Demangle/Demangle.h"
15 #include "llvm/IR/DebugInfoMetadata.h"
16 #include "llvm/MC/TargetRegistry.h"
17 #include "llvm/Support/CommandLine.h"
18 #include "llvm/Support/Format.h"
19 #include "llvm/Support/TargetSelect.h"
20 
21 #define DEBUG_TYPE "load-binary"
22 
23 using namespace llvm;
24 using namespace sampleprof;
25 
26 cl::opt<bool> ShowDisassemblyOnly("show-disassembly-only",
27                                   cl::desc("Print disassembled code."));
28 
29 cl::opt<bool> ShowSourceLocations("show-source-locations",
30                                   cl::desc("Print source locations."));
31 
32 static cl::opt<bool>
33     ShowCanonicalFnName("show-canonical-fname",
34                         cl::desc("Print canonical function name."));
35 
36 static cl::opt<bool> ShowPseudoProbe(
37     "show-pseudo-probe",
38     cl::desc("Print pseudo probe section and disassembled info."));
39 
40 static cl::opt<bool> UseDwarfCorrelation(
41     "use-dwarf-correlation",
42     cl::desc("Use dwarf for profile correlation even when binary contains "
43              "pseudo probe."));
44 
45 static cl::opt<std::string>
46     DWPPath("dwp", cl::init(""),
47             cl::desc("Path of .dwp file. When not specified, it will be "
48                      "<binary>.dwp in the same directory as the main binary."));
49 
50 static cl::list<std::string> DisassembleFunctions(
51     "disassemble-functions", cl::CommaSeparated,
52     cl::desc("List of functions to print disassembly for. Accept demangled "
53              "names only. Only work with show-disassembly-only"));
54 
55 extern cl::opt<bool> ShowDetailedWarning;
56 
57 namespace llvm {
58 namespace sampleprof {
59 
getTarget(const ObjectFile * Obj)60 static const Target *getTarget(const ObjectFile *Obj) {
61   Triple TheTriple = Obj->makeTriple();
62   std::string Error;
63   std::string ArchName;
64   const Target *TheTarget =
65       TargetRegistry::lookupTarget(ArchName, TheTriple, Error);
66   if (!TheTarget)
67     exitWithError(Error, Obj->getFileName());
68   return TheTarget;
69 }
70 
addInstructionForContext(const SampleContextFrameVector & Context,uint32_t InstrSize)71 void BinarySizeContextTracker::addInstructionForContext(
72     const SampleContextFrameVector &Context, uint32_t InstrSize) {
73   ContextTrieNode *CurNode = &RootContext;
74   bool IsLeaf = true;
75   for (const auto &Callsite : reverse(Context)) {
76     StringRef CallerName = Callsite.FuncName;
77     LineLocation CallsiteLoc = IsLeaf ? LineLocation(0, 0) : Callsite.Location;
78     CurNode = CurNode->getOrCreateChildContext(CallsiteLoc, CallerName);
79     IsLeaf = false;
80   }
81 
82   CurNode->addFunctionSize(InstrSize);
83 }
84 
85 uint32_t
getFuncSizeForContext(const ContextTrieNode * Node)86 BinarySizeContextTracker::getFuncSizeForContext(const ContextTrieNode *Node) {
87   ContextTrieNode *CurrNode = &RootContext;
88   ContextTrieNode *PrevNode = nullptr;
89 
90   Optional<uint32_t> Size;
91 
92   // Start from top-level context-less function, traverse down the reverse
93   // context trie to find the best/longest match for given context, then
94   // retrieve the size.
95   LineLocation CallSiteLoc(0, 0);
96   while (CurrNode && Node->getParentContext() != nullptr) {
97     PrevNode = CurrNode;
98     CurrNode = CurrNode->getChildContext(CallSiteLoc, Node->getFuncName());
99     if (CurrNode && CurrNode->getFunctionSize())
100       Size = CurrNode->getFunctionSize().value();
101     CallSiteLoc = Node->getCallSiteLoc();
102     Node = Node->getParentContext();
103   }
104 
105   // If we traversed all nodes along the path of the context and haven't
106   // found a size yet, pivot to look for size from sibling nodes, i.e size
107   // of inlinee under different context.
108   if (!Size) {
109     if (!CurrNode)
110       CurrNode = PrevNode;
111     while (!Size && CurrNode && !CurrNode->getAllChildContext().empty()) {
112       CurrNode = &CurrNode->getAllChildContext().begin()->second;
113       if (CurrNode->getFunctionSize())
114         Size = CurrNode->getFunctionSize().value();
115     }
116   }
117 
118   assert(Size && "We should at least find one context size.");
119   return Size.value();
120 }
121 
trackInlineesOptimizedAway(MCPseudoProbeDecoder & ProbeDecoder)122 void BinarySizeContextTracker::trackInlineesOptimizedAway(
123     MCPseudoProbeDecoder &ProbeDecoder) {
124   ProbeFrameStack ProbeContext;
125   for (const auto &Child : ProbeDecoder.getDummyInlineRoot().getChildren())
126     trackInlineesOptimizedAway(ProbeDecoder, *Child.second.get(), ProbeContext);
127 }
128 
trackInlineesOptimizedAway(MCPseudoProbeDecoder & ProbeDecoder,MCDecodedPseudoProbeInlineTree & ProbeNode,ProbeFrameStack & ProbeContext)129 void BinarySizeContextTracker::trackInlineesOptimizedAway(
130     MCPseudoProbeDecoder &ProbeDecoder,
131     MCDecodedPseudoProbeInlineTree &ProbeNode, ProbeFrameStack &ProbeContext) {
132   StringRef FuncName =
133       ProbeDecoder.getFuncDescForGUID(ProbeNode.Guid)->FuncName;
134   ProbeContext.emplace_back(FuncName, 0);
135 
136   // This ProbeContext has a probe, so it has code before inlining and
137   // optimization. Make sure we mark its size as known.
138   if (!ProbeNode.getProbes().empty()) {
139     ContextTrieNode *SizeContext = &RootContext;
140     for (auto &ProbeFrame : reverse(ProbeContext)) {
141       StringRef CallerName = ProbeFrame.first;
142       LineLocation CallsiteLoc(ProbeFrame.second, 0);
143       SizeContext =
144           SizeContext->getOrCreateChildContext(CallsiteLoc, CallerName);
145     }
146     // Add 0 size to make known.
147     SizeContext->addFunctionSize(0);
148   }
149 
150   // DFS down the probe inline tree
151   for (const auto &ChildNode : ProbeNode.getChildren()) {
152     InlineSite Location = ChildNode.first;
153     ProbeContext.back().second = std::get<1>(Location);
154     trackInlineesOptimizedAway(ProbeDecoder, *ChildNode.second.get(),
155                                ProbeContext);
156   }
157 
158   ProbeContext.pop_back();
159 }
160 
warnNoFuncEntry()161 void ProfiledBinary::warnNoFuncEntry() {
162   uint64_t NoFuncEntryNum = 0;
163   for (auto &F : BinaryFunctions) {
164     if (F.second.Ranges.empty())
165       continue;
166     bool hasFuncEntry = false;
167     for (auto &R : F.second.Ranges) {
168       if (FuncRange *FR = findFuncRangeForStartOffset(R.first)) {
169         if (FR->IsFuncEntry) {
170           hasFuncEntry = true;
171           break;
172         }
173       }
174     }
175 
176     if (!hasFuncEntry) {
177       NoFuncEntryNum++;
178       if (ShowDetailedWarning)
179         WithColor::warning()
180             << "Failed to determine function entry for " << F.first
181             << " due to inconsistent name from symbol table and dwarf info.\n";
182     }
183   }
184   emitWarningSummary(NoFuncEntryNum, BinaryFunctions.size(),
185                      "of functions failed to determine function entry due to "
186                      "inconsistent name from symbol table and dwarf info.");
187 }
188 
load()189 void ProfiledBinary::load() {
190   // Attempt to open the binary.
191   OwningBinary<Binary> OBinary = unwrapOrError(createBinary(Path), Path);
192   Binary &ExeBinary = *OBinary.getBinary();
193 
194   auto *Obj = dyn_cast<ELFObjectFileBase>(&ExeBinary);
195   if (!Obj)
196     exitWithError("not a valid Elf image", Path);
197 
198   TheTriple = Obj->makeTriple();
199   // Current only support X86
200   if (!TheTriple.isX86())
201     exitWithError("unsupported target", TheTriple.getTriple());
202   LLVM_DEBUG(dbgs() << "Loading " << Path << "\n");
203 
204   // Find the preferred load address for text sections.
205   setPreferredTextSegmentAddresses(Obj);
206 
207   checkPseudoProbe(Obj);
208 
209   if (ShowDisassemblyOnly)
210     decodePseudoProbe(Obj);
211 
212   // Load debug info of subprograms from DWARF section.
213   // If path of debug info binary is specified, use the debug info from it,
214   // otherwise use the debug info from the executable binary.
215   if (!DebugBinaryPath.empty()) {
216     OwningBinary<Binary> DebugPath =
217         unwrapOrError(createBinary(DebugBinaryPath), DebugBinaryPath);
218     loadSymbolsFromDWARF(*cast<ObjectFile>(DebugPath.getBinary()));
219   } else {
220     loadSymbolsFromDWARF(*cast<ObjectFile>(&ExeBinary));
221   }
222 
223   // Disassemble the text sections.
224   disassemble(Obj);
225 
226   // Use function start and return address to infer prolog and epilog
227   ProEpilogTracker.inferPrologOffsets(StartOffset2FuncRangeMap);
228   ProEpilogTracker.inferEpilogOffsets(RetOffsets);
229 
230   warnNoFuncEntry();
231 
232   // TODO: decode other sections.
233 }
234 
inlineContextEqual(uint64_t Address1,uint64_t Address2)235 bool ProfiledBinary::inlineContextEqual(uint64_t Address1, uint64_t Address2) {
236   uint64_t Offset1 = virtualAddrToOffset(Address1);
237   uint64_t Offset2 = virtualAddrToOffset(Address2);
238   const SampleContextFrameVector &Context1 = getFrameLocationStack(Offset1);
239   const SampleContextFrameVector &Context2 = getFrameLocationStack(Offset2);
240   if (Context1.size() != Context2.size())
241     return false;
242   if (Context1.empty())
243     return false;
244   // The leaf frame contains location within the leaf, and it
245   // needs to be remove that as it's not part of the calling context
246   return std::equal(Context1.begin(), Context1.begin() + Context1.size() - 1,
247                     Context2.begin(), Context2.begin() + Context2.size() - 1);
248 }
249 
250 SampleContextFrameVector
getExpandedContext(const SmallVectorImpl<uint64_t> & Stack,bool & WasLeafInlined)251 ProfiledBinary::getExpandedContext(const SmallVectorImpl<uint64_t> &Stack,
252                                    bool &WasLeafInlined) {
253   SampleContextFrameVector ContextVec;
254   if (Stack.empty())
255     return ContextVec;
256   // Process from frame root to leaf
257   for (auto Address : Stack) {
258     uint64_t Offset = virtualAddrToOffset(Address);
259     const SampleContextFrameVector &ExpandedContext =
260         getFrameLocationStack(Offset);
261     // An instruction without a valid debug line will be ignored by sample
262     // processing
263     if (ExpandedContext.empty())
264       return SampleContextFrameVector();
265     // Set WasLeafInlined to the size of inlined frame count for the last
266     // address which is leaf
267     WasLeafInlined = (ExpandedContext.size() > 1);
268     ContextVec.append(ExpandedContext);
269   }
270 
271   // Replace with decoded base discriminator
272   for (auto &Frame : ContextVec) {
273     Frame.Location.Discriminator = ProfileGeneratorBase::getBaseDiscriminator(
274         Frame.Location.Discriminator, UseFSDiscriminator);
275   }
276 
277   assert(ContextVec.size() && "Context length should be at least 1");
278 
279   // Compress the context string except for the leaf frame
280   auto LeafFrame = ContextVec.back();
281   LeafFrame.Location = LineLocation(0, 0);
282   ContextVec.pop_back();
283   CSProfileGenerator::compressRecursionContext(ContextVec);
284   CSProfileGenerator::trimContext(ContextVec);
285   ContextVec.push_back(LeafFrame);
286   return ContextVec;
287 }
288 
289 template <class ELFT>
setPreferredTextSegmentAddresses(const ELFFile<ELFT> & Obj,StringRef FileName)290 void ProfiledBinary::setPreferredTextSegmentAddresses(const ELFFile<ELFT> &Obj,
291                                                       StringRef FileName) {
292   const auto &PhdrRange = unwrapOrError(Obj.program_headers(), FileName);
293   // FIXME: This should be the page size of the system running profiling.
294   // However such info isn't available at post-processing time, assuming
295   // 4K page now. Note that we don't use EXEC_PAGESIZE from <linux/param.h>
296   // because we may build the tools on non-linux.
297   uint32_t PageSize = 0x1000;
298   for (const typename ELFT::Phdr &Phdr : PhdrRange) {
299     if (Phdr.p_type == ELF::PT_LOAD) {
300       if (!FirstLoadableAddress)
301         FirstLoadableAddress = Phdr.p_vaddr & ~(PageSize - 1U);
302       if (Phdr.p_flags & ELF::PF_X) {
303         // Segments will always be loaded at a page boundary.
304         PreferredTextSegmentAddresses.push_back(Phdr.p_vaddr &
305                                                 ~(PageSize - 1U));
306         TextSegmentOffsets.push_back(Phdr.p_offset & ~(PageSize - 1U));
307       }
308     }
309   }
310 
311   if (PreferredTextSegmentAddresses.empty())
312     exitWithError("no executable segment found", FileName);
313 }
314 
setPreferredTextSegmentAddresses(const ELFObjectFileBase * Obj)315 void ProfiledBinary::setPreferredTextSegmentAddresses(
316     const ELFObjectFileBase *Obj) {
317   if (const auto *ELFObj = dyn_cast<ELF32LEObjectFile>(Obj))
318     setPreferredTextSegmentAddresses(ELFObj->getELFFile(), Obj->getFileName());
319   else if (const auto *ELFObj = dyn_cast<ELF32BEObjectFile>(Obj))
320     setPreferredTextSegmentAddresses(ELFObj->getELFFile(), Obj->getFileName());
321   else if (const auto *ELFObj = dyn_cast<ELF64LEObjectFile>(Obj))
322     setPreferredTextSegmentAddresses(ELFObj->getELFFile(), Obj->getFileName());
323   else if (const auto *ELFObj = cast<ELF64BEObjectFile>(Obj))
324     setPreferredTextSegmentAddresses(ELFObj->getELFFile(), Obj->getFileName());
325   else
326     llvm_unreachable("invalid ELF object format");
327 }
328 
checkPseudoProbe(const ELFObjectFileBase * Obj)329 void ProfiledBinary::checkPseudoProbe(const ELFObjectFileBase *Obj) {
330   if (UseDwarfCorrelation)
331     return;
332 
333   bool HasProbeDescSection = false;
334   bool HasPseudoProbeSection = false;
335 
336   StringRef FileName = Obj->getFileName();
337   for (section_iterator SI = Obj->section_begin(), SE = Obj->section_end();
338        SI != SE; ++SI) {
339     const SectionRef &Section = *SI;
340     StringRef SectionName = unwrapOrError(Section.getName(), FileName);
341     if (SectionName == ".pseudo_probe_desc") {
342       HasProbeDescSection = true;
343     } else if (SectionName == ".pseudo_probe") {
344       HasPseudoProbeSection = true;
345     }
346   }
347 
348   // set UsePseudoProbes flag, used for PerfReader
349   UsePseudoProbes = HasProbeDescSection && HasPseudoProbeSection;
350 }
351 
decodePseudoProbe(const ELFObjectFileBase * Obj)352 void ProfiledBinary::decodePseudoProbe(const ELFObjectFileBase *Obj) {
353   if (!UsePseudoProbes)
354     return;
355 
356   std::unordered_set<uint64_t> ProfiledGuids;
357   if (!ShowDisassemblyOnly)
358     for (auto *F : ProfiledFunctions)
359       ProfiledGuids.insert(Function::getGUID(F->FuncName));
360 
361   StringRef FileName = Obj->getFileName();
362   for (section_iterator SI = Obj->section_begin(), SE = Obj->section_end();
363        SI != SE; ++SI) {
364     const SectionRef &Section = *SI;
365     StringRef SectionName = unwrapOrError(Section.getName(), FileName);
366 
367     if (SectionName == ".pseudo_probe_desc") {
368       StringRef Contents = unwrapOrError(Section.getContents(), FileName);
369       if (!ProbeDecoder.buildGUID2FuncDescMap(
370               reinterpret_cast<const uint8_t *>(Contents.data()),
371               Contents.size()))
372         exitWithError(
373             "Pseudo Probe decoder fail in .pseudo_probe_desc section");
374     } else if (SectionName == ".pseudo_probe") {
375       StringRef Contents = unwrapOrError(Section.getContents(), FileName);
376       if (!ProbeDecoder.buildAddress2ProbeMap(
377               reinterpret_cast<const uint8_t *>(Contents.data()),
378               Contents.size(), ProfiledGuids))
379         exitWithError("Pseudo Probe decoder fail in .pseudo_probe section");
380     }
381   }
382 
383   // Build TopLevelProbeFrameMap to track size for optimized inlinees when probe
384   // is available
385   if (TrackFuncContextSize) {
386     for (const auto &Child : ProbeDecoder.getDummyInlineRoot().getChildren()) {
387       auto *Frame = Child.second.get();
388       StringRef FuncName =
389           ProbeDecoder.getFuncDescForGUID(Frame->Guid)->FuncName;
390       TopLevelProbeFrameMap[FuncName] = Frame;
391     }
392   }
393 
394   if (ShowPseudoProbe)
395     ProbeDecoder.printGUID2FuncDescMap(outs());
396 }
397 
decodePseudoProbe()398 void ProfiledBinary::decodePseudoProbe() {
399   OwningBinary<Binary> OBinary = unwrapOrError(createBinary(Path), Path);
400   Binary &ExeBinary = *OBinary.getBinary();
401   auto *Obj = dyn_cast<ELFObjectFileBase>(&ExeBinary);
402   decodePseudoProbe(Obj);
403 }
404 
setIsFuncEntry(uint64_t Offset,StringRef RangeSymName)405 void ProfiledBinary::setIsFuncEntry(uint64_t Offset, StringRef RangeSymName) {
406   // Note that the start offset of each ELF section can be a non-function
407   // symbol, we need to binary search for the start of a real function range.
408   auto *FuncRange = findFuncRangeForOffset(Offset);
409   // Skip external function symbol.
410   if (!FuncRange)
411     return;
412 
413   // Set IsFuncEntry to ture if there is only one range in the function or the
414   // RangeSymName from ELF is equal to its DWARF-based function name.
415   if (FuncRange->Func->Ranges.size() == 1 ||
416       (!FuncRange->IsFuncEntry && FuncRange->getFuncName() == RangeSymName))
417     FuncRange->IsFuncEntry = true;
418 }
419 
dissassembleSymbol(std::size_t SI,ArrayRef<uint8_t> Bytes,SectionSymbolsTy & Symbols,const SectionRef & Section)420 bool ProfiledBinary::dissassembleSymbol(std::size_t SI, ArrayRef<uint8_t> Bytes,
421                                         SectionSymbolsTy &Symbols,
422                                         const SectionRef &Section) {
423   std::size_t SE = Symbols.size();
424   uint64_t SectionOffset = Section.getAddress() - getPreferredBaseAddress();
425   uint64_t SectSize = Section.getSize();
426   uint64_t StartOffset = Symbols[SI].Addr - getPreferredBaseAddress();
427   uint64_t NextStartOffset =
428       (SI + 1 < SE) ? Symbols[SI + 1].Addr - getPreferredBaseAddress()
429                     : SectionOffset + SectSize;
430   setIsFuncEntry(StartOffset,
431                  FunctionSamples::getCanonicalFnName(Symbols[SI].Name));
432 
433   StringRef SymbolName =
434       ShowCanonicalFnName
435           ? FunctionSamples::getCanonicalFnName(Symbols[SI].Name)
436           : Symbols[SI].Name;
437   bool ShowDisassembly =
438       ShowDisassemblyOnly && (DisassembleFunctionSet.empty() ||
439                               DisassembleFunctionSet.count(SymbolName));
440   if (ShowDisassembly)
441     outs() << '<' << SymbolName << ">:\n";
442 
443   auto WarnInvalidInsts = [](uint64_t Start, uint64_t End) {
444     WithColor::warning() << "Invalid instructions at "
445                          << format("%8" PRIx64, Start) << " - "
446                          << format("%8" PRIx64, End) << "\n";
447   };
448 
449   uint64_t Offset = StartOffset;
450   // Size of a consecutive invalid instruction range starting from Offset -1
451   // backwards.
452   uint64_t InvalidInstLength = 0;
453   while (Offset < NextStartOffset) {
454     MCInst Inst;
455     uint64_t Size;
456     // Disassemble an instruction.
457     bool Disassembled =
458         DisAsm->getInstruction(Inst, Size, Bytes.slice(Offset - SectionOffset),
459                                Offset + getPreferredBaseAddress(), nulls());
460     if (Size == 0)
461       Size = 1;
462 
463     if (ShowDisassembly) {
464       if (ShowPseudoProbe) {
465         ProbeDecoder.printProbeForAddress(outs(),
466                                           Offset + getPreferredBaseAddress());
467       }
468       outs() << format("%8" PRIx64 ":", Offset + getPreferredBaseAddress());
469       size_t Start = outs().tell();
470       if (Disassembled)
471         IPrinter->printInst(&Inst, Offset + Size, "", *STI.get(), outs());
472       else
473         outs() << "\t<unknown>";
474       if (ShowSourceLocations) {
475         unsigned Cur = outs().tell() - Start;
476         if (Cur < 40)
477           outs().indent(40 - Cur);
478         InstructionPointer IP(this, Offset);
479         outs() << getReversedLocWithContext(
480             symbolize(IP, ShowCanonicalFnName, ShowPseudoProbe));
481       }
482       outs() << "\n";
483     }
484 
485     if (Disassembled) {
486       const MCInstrDesc &MCDesc = MII->get(Inst.getOpcode());
487 
488       // Record instruction size.
489       Offset2InstSizeMap[Offset] = Size;
490 
491       // Populate address maps.
492       CodeAddrOffsets.push_back(Offset);
493       if (MCDesc.isCall()) {
494         CallOffsets.insert(Offset);
495         UncondBranchOffsets.insert(Offset);
496       } else if (MCDesc.isReturn()) {
497         RetOffsets.insert(Offset);
498         UncondBranchOffsets.insert(Offset);
499       } else if (MCDesc.isBranch()) {
500         if (MCDesc.isUnconditionalBranch())
501           UncondBranchOffsets.insert(Offset);
502         BranchOffsets.insert(Offset);
503       }
504 
505       if (InvalidInstLength) {
506         WarnInvalidInsts(Offset - InvalidInstLength, Offset - 1);
507         InvalidInstLength = 0;
508       }
509     } else {
510       InvalidInstLength += Size;
511     }
512 
513     Offset += Size;
514   }
515 
516   if (InvalidInstLength)
517     WarnInvalidInsts(Offset - InvalidInstLength, Offset - 1);
518 
519   if (ShowDisassembly)
520     outs() << "\n";
521 
522   return true;
523 }
524 
setUpDisassembler(const ELFObjectFileBase * Obj)525 void ProfiledBinary::setUpDisassembler(const ELFObjectFileBase *Obj) {
526   const Target *TheTarget = getTarget(Obj);
527   std::string TripleName = TheTriple.getTriple();
528   StringRef FileName = Obj->getFileName();
529 
530   MRI.reset(TheTarget->createMCRegInfo(TripleName));
531   if (!MRI)
532     exitWithError("no register info for target " + TripleName, FileName);
533 
534   MCTargetOptions MCOptions;
535   AsmInfo.reset(TheTarget->createMCAsmInfo(*MRI, TripleName, MCOptions));
536   if (!AsmInfo)
537     exitWithError("no assembly info for target " + TripleName, FileName);
538 
539   SubtargetFeatures Features = Obj->getFeatures();
540   STI.reset(
541       TheTarget->createMCSubtargetInfo(TripleName, "", Features.getString()));
542   if (!STI)
543     exitWithError("no subtarget info for target " + TripleName, FileName);
544 
545   MII.reset(TheTarget->createMCInstrInfo());
546   if (!MII)
547     exitWithError("no instruction info for target " + TripleName, FileName);
548 
549   MCContext Ctx(Triple(TripleName), AsmInfo.get(), MRI.get(), STI.get());
550   std::unique_ptr<MCObjectFileInfo> MOFI(
551       TheTarget->createMCObjectFileInfo(Ctx, /*PIC=*/false));
552   Ctx.setObjectFileInfo(MOFI.get());
553   DisAsm.reset(TheTarget->createMCDisassembler(*STI, Ctx));
554   if (!DisAsm)
555     exitWithError("no disassembler for target " + TripleName, FileName);
556 
557   MIA.reset(TheTarget->createMCInstrAnalysis(MII.get()));
558 
559   int AsmPrinterVariant = AsmInfo->getAssemblerDialect();
560   IPrinter.reset(TheTarget->createMCInstPrinter(
561       Triple(TripleName), AsmPrinterVariant, *AsmInfo, *MII, *MRI));
562   IPrinter->setPrintBranchImmAsAddress(true);
563 }
564 
disassemble(const ELFObjectFileBase * Obj)565 void ProfiledBinary::disassemble(const ELFObjectFileBase *Obj) {
566   // Set up disassembler and related components.
567   setUpDisassembler(Obj);
568 
569   // Create a mapping from virtual address to symbol name. The symbols in text
570   // sections are the candidates to dissassemble.
571   std::map<SectionRef, SectionSymbolsTy> AllSymbols;
572   StringRef FileName = Obj->getFileName();
573   for (const SymbolRef &Symbol : Obj->symbols()) {
574     const uint64_t Addr = unwrapOrError(Symbol.getAddress(), FileName);
575     const StringRef Name = unwrapOrError(Symbol.getName(), FileName);
576     section_iterator SecI = unwrapOrError(Symbol.getSection(), FileName);
577     if (SecI != Obj->section_end())
578       AllSymbols[*SecI].push_back(SymbolInfoTy(Addr, Name, ELF::STT_NOTYPE));
579   }
580 
581   // Sort all the symbols. Use a stable sort to stabilize the output.
582   for (std::pair<const SectionRef, SectionSymbolsTy> &SecSyms : AllSymbols)
583     stable_sort(SecSyms.second);
584 
585   DisassembleFunctionSet.insert(DisassembleFunctions.begin(),
586                                 DisassembleFunctions.end());
587   assert((DisassembleFunctionSet.empty() || ShowDisassemblyOnly) &&
588          "Functions to disassemble should be only specified together with "
589          "--show-disassembly-only");
590 
591   if (ShowDisassemblyOnly)
592     outs() << "\nDisassembly of " << FileName << ":\n";
593 
594   // Dissassemble a text section.
595   for (section_iterator SI = Obj->section_begin(), SE = Obj->section_end();
596        SI != SE; ++SI) {
597     const SectionRef &Section = *SI;
598     if (!Section.isText())
599       continue;
600 
601     uint64_t ImageLoadAddr = getPreferredBaseAddress();
602     uint64_t SectionOffset = Section.getAddress() - ImageLoadAddr;
603     uint64_t SectSize = Section.getSize();
604     if (!SectSize)
605       continue;
606 
607     // Register the text section.
608     TextSections.insert({SectionOffset, SectSize});
609 
610     StringRef SectionName = unwrapOrError(Section.getName(), FileName);
611 
612     if (ShowDisassemblyOnly) {
613       outs() << "\nDisassembly of section " << SectionName;
614       outs() << " [" << format("0x%" PRIx64, Section.getAddress()) << ", "
615              << format("0x%" PRIx64, Section.getAddress() + SectSize)
616              << "]:\n\n";
617     }
618 
619     if (SectionName == ".plt")
620       continue;
621 
622     // Get the section data.
623     ArrayRef<uint8_t> Bytes =
624         arrayRefFromStringRef(unwrapOrError(Section.getContents(), FileName));
625 
626     // Get the list of all the symbols in this section.
627     SectionSymbolsTy &Symbols = AllSymbols[Section];
628 
629     // Disassemble symbol by symbol.
630     for (std::size_t SI = 0, SE = Symbols.size(); SI != SE; ++SI) {
631       if (!dissassembleSymbol(SI, Bytes, Symbols, Section))
632         exitWithError("disassembling error", FileName);
633     }
634   }
635 
636   // Dissassemble rodata section to check if FS discriminator symbol exists.
637   checkUseFSDiscriminator(Obj, AllSymbols);
638 }
639 
checkUseFSDiscriminator(const ELFObjectFileBase * Obj,std::map<SectionRef,SectionSymbolsTy> & AllSymbols)640 void ProfiledBinary::checkUseFSDiscriminator(
641     const ELFObjectFileBase *Obj,
642     std::map<SectionRef, SectionSymbolsTy> &AllSymbols) {
643   const char *FSDiscriminatorVar = "__llvm_fs_discriminator__";
644   for (section_iterator SI = Obj->section_begin(), SE = Obj->section_end();
645        SI != SE; ++SI) {
646     const SectionRef &Section = *SI;
647     if (!Section.isData() || Section.getSize() == 0)
648       continue;
649     SectionSymbolsTy &Symbols = AllSymbols[Section];
650 
651     for (std::size_t SI = 0, SE = Symbols.size(); SI != SE; ++SI) {
652       if (Symbols[SI].Name == FSDiscriminatorVar) {
653         UseFSDiscriminator = true;
654         return;
655       }
656     }
657   }
658 }
659 
loadSymbolsFromDWARFUnit(DWARFUnit & CompilationUnit)660 void ProfiledBinary::loadSymbolsFromDWARFUnit(DWARFUnit &CompilationUnit) {
661   for (const auto &DieInfo : CompilationUnit.dies()) {
662     llvm::DWARFDie Die(&CompilationUnit, &DieInfo);
663 
664     if (!Die.isSubprogramDIE())
665       continue;
666     auto Name = Die.getName(llvm::DINameKind::LinkageName);
667     if (!Name)
668       Name = Die.getName(llvm::DINameKind::ShortName);
669     if (!Name)
670       continue;
671 
672     auto RangesOrError = Die.getAddressRanges();
673     if (!RangesOrError)
674       continue;
675     const DWARFAddressRangesVector &Ranges = RangesOrError.get();
676 
677     if (Ranges.empty())
678       continue;
679 
680     // Different DWARF symbols can have same function name, search or create
681     // BinaryFunction indexed by the name.
682     auto Ret = BinaryFunctions.emplace(Name, BinaryFunction());
683     auto &Func = Ret.first->second;
684     if (Ret.second)
685       Func.FuncName = Ret.first->first;
686 
687     for (const auto &Range : Ranges) {
688       uint64_t FuncStart = Range.LowPC;
689       uint64_t FuncSize = Range.HighPC - FuncStart;
690 
691       if (FuncSize == 0 || FuncStart < getPreferredBaseAddress())
692         continue;
693 
694       uint64_t StartOffset = FuncStart - getPreferredBaseAddress();
695       uint64_t EndOffset = Range.HighPC - getPreferredBaseAddress();
696 
697       // We may want to know all ranges for one function. Here group the
698       // ranges and store them into BinaryFunction.
699       Func.Ranges.emplace_back(StartOffset, EndOffset);
700 
701       auto R = StartOffset2FuncRangeMap.emplace(StartOffset, FuncRange());
702       if (R.second) {
703         FuncRange &FRange = R.first->second;
704         FRange.Func = &Func;
705         FRange.StartOffset = StartOffset;
706         FRange.EndOffset = EndOffset;
707       } else {
708         WithColor::warning()
709             << "Duplicated symbol start address at "
710             << format("%8" PRIx64, StartOffset + getPreferredBaseAddress())
711             << " " << R.first->second.getFuncName() << " and " << Name << "\n";
712       }
713     }
714   }
715 }
716 
loadSymbolsFromDWARF(ObjectFile & Obj)717 void ProfiledBinary::loadSymbolsFromDWARF(ObjectFile &Obj) {
718   auto DebugContext = llvm::DWARFContext::create(
719       Obj, DWARFContext::ProcessDebugRelocations::Process, nullptr, DWPPath);
720   if (!DebugContext)
721     exitWithError("Error creating the debug info context", Path);
722 
723   for (const auto &CompilationUnit : DebugContext->compile_units())
724     loadSymbolsFromDWARFUnit(*CompilationUnit.get());
725 
726   // Handles DWO sections that can either be in .o, .dwo or .dwp files.
727   for (const auto &CompilationUnit : DebugContext->compile_units()) {
728     DWARFUnit *const DwarfUnit = CompilationUnit.get();
729     if (llvm::Optional<uint64_t> DWOId = DwarfUnit->getDWOId()) {
730       DWARFUnit *DWOCU = DwarfUnit->getNonSkeletonUnitDIE(false).getDwarfUnit();
731       if (!DWOCU->isDWOUnit()) {
732         std::string DWOName = dwarf::toString(
733             DwarfUnit->getUnitDIE().find(
734                 {dwarf::DW_AT_dwo_name, dwarf::DW_AT_GNU_dwo_name}),
735             "");
736         WithColor::warning()
737             << "DWO debug information for " << DWOName
738             << " was not loaded. Please check the .o, .dwo or .dwp path.\n";
739         continue;
740       }
741       loadSymbolsFromDWARFUnit(*DWOCU);
742     }
743   }
744 
745   if (BinaryFunctions.empty())
746     WithColor::warning() << "Loading of DWARF info completed, but no binary "
747                             "functions have been retrieved.\n";
748 }
749 
populateSymbolListFromDWARF(ProfileSymbolList & SymbolList)750 void ProfiledBinary::populateSymbolListFromDWARF(
751     ProfileSymbolList &SymbolList) {
752   for (auto &I : StartOffset2FuncRangeMap)
753     SymbolList.add(I.second.getFuncName());
754 }
755 
setupSymbolizer()756 void ProfiledBinary::setupSymbolizer() {
757   symbolize::LLVMSymbolizer::Options SymbolizerOpts;
758   SymbolizerOpts.PrintFunctions =
759       DILineInfoSpecifier::FunctionNameKind::LinkageName;
760   SymbolizerOpts.Demangle = false;
761   SymbolizerOpts.DefaultArch = TheTriple.getArchName().str();
762   SymbolizerOpts.UseSymbolTable = false;
763   SymbolizerOpts.RelativeAddresses = false;
764   SymbolizerOpts.DWPName = DWPPath;
765   Symbolizer = std::make_unique<symbolize::LLVMSymbolizer>(SymbolizerOpts);
766 }
767 
symbolize(const InstructionPointer & IP,bool UseCanonicalFnName,bool UseProbeDiscriminator)768 SampleContextFrameVector ProfiledBinary::symbolize(const InstructionPointer &IP,
769                                                    bool UseCanonicalFnName,
770                                                    bool UseProbeDiscriminator) {
771   assert(this == IP.Binary &&
772          "Binary should only symbolize its own instruction");
773   auto Addr = object::SectionedAddress{IP.Offset + getPreferredBaseAddress(),
774                                        object::SectionedAddress::UndefSection};
775   DIInliningInfo InlineStack = unwrapOrError(
776       Symbolizer->symbolizeInlinedCode(SymbolizerPath.str(), Addr),
777       SymbolizerPath);
778 
779   SampleContextFrameVector CallStack;
780   for (int32_t I = InlineStack.getNumberOfFrames() - 1; I >= 0; I--) {
781     const auto &CallerFrame = InlineStack.getFrame(I);
782     if (CallerFrame.FunctionName == "<invalid>")
783       break;
784 
785     StringRef FunctionName(CallerFrame.FunctionName);
786     if (UseCanonicalFnName)
787       FunctionName = FunctionSamples::getCanonicalFnName(FunctionName);
788 
789     uint32_t Discriminator = CallerFrame.Discriminator;
790     uint32_t LineOffset = (CallerFrame.Line - CallerFrame.StartLine) & 0xffff;
791     if (UseProbeDiscriminator) {
792       LineOffset =
793           PseudoProbeDwarfDiscriminator::extractProbeIndex(Discriminator);
794       Discriminator = 0;
795     }
796 
797     LineLocation Line(LineOffset, Discriminator);
798     auto It = NameStrings.insert(FunctionName.str());
799     CallStack.emplace_back(*It.first, Line);
800   }
801 
802   return CallStack;
803 }
804 
computeInlinedContextSizeForRange(uint64_t StartOffset,uint64_t EndOffset)805 void ProfiledBinary::computeInlinedContextSizeForRange(uint64_t StartOffset,
806                                                        uint64_t EndOffset) {
807   uint64_t RangeBegin = offsetToVirtualAddr(StartOffset);
808   uint64_t RangeEnd = offsetToVirtualAddr(EndOffset);
809   InstructionPointer IP(this, RangeBegin, true);
810 
811   if (IP.Address != RangeBegin)
812     WithColor::warning() << "Invalid start instruction at "
813                          << format("%8" PRIx64, RangeBegin) << "\n";
814 
815   if (IP.Address >= RangeEnd)
816     return;
817 
818   do {
819     uint64_t Offset = virtualAddrToOffset(IP.Address);
820     const SampleContextFrameVector &SymbolizedCallStack =
821         getFrameLocationStack(Offset, UsePseudoProbes);
822     uint64_t Size = Offset2InstSizeMap[Offset];
823 
824     // Record instruction size for the corresponding context
825     FuncSizeTracker.addInstructionForContext(SymbolizedCallStack, Size);
826 
827   } while (IP.advance() && IP.Address < RangeEnd);
828 }
829 
computeInlinedContextSizeForFunc(const BinaryFunction * Func)830 void ProfiledBinary::computeInlinedContextSizeForFunc(
831     const BinaryFunction *Func) {
832   // Note that a function can be spilt into multiple ranges, so compute for all
833   // ranges of the function.
834   for (const auto &Range : Func->Ranges)
835     computeInlinedContextSizeForRange(Range.first, Range.second);
836 
837   // Track optimized-away inlinee for probed binary. A function inlined and then
838   // optimized away should still have their probes left over in places.
839   if (usePseudoProbes()) {
840     auto I = TopLevelProbeFrameMap.find(Func->FuncName);
841     if (I != TopLevelProbeFrameMap.end()) {
842       BinarySizeContextTracker::ProbeFrameStack ProbeContext;
843       FuncSizeTracker.trackInlineesOptimizedAway(ProbeDecoder, *I->second,
844                                                  ProbeContext);
845     }
846   }
847 }
848 
InstructionPointer(const ProfiledBinary * Binary,uint64_t Address,bool RoundToNext)849 InstructionPointer::InstructionPointer(const ProfiledBinary *Binary,
850                                        uint64_t Address, bool RoundToNext)
851     : Binary(Binary), Address(Address) {
852   Index = Binary->getIndexForAddr(Address);
853   if (RoundToNext) {
854     // we might get address which is not the code
855     // it should round to the next valid address
856     if (Index >= Binary->getCodeOffsetsSize())
857       this->Address = UINT64_MAX;
858     else
859       this->Address = Binary->getAddressforIndex(Index);
860   }
861 }
862 
advance()863 bool InstructionPointer::advance() {
864   Index++;
865   if (Index >= Binary->getCodeOffsetsSize()) {
866     Address = UINT64_MAX;
867     return false;
868   }
869   Address = Binary->getAddressforIndex(Index);
870   return true;
871 }
872 
backward()873 bool InstructionPointer::backward() {
874   if (Index == 0) {
875     Address = 0;
876     return false;
877   }
878   Index--;
879   Address = Binary->getAddressforIndex(Index);
880   return true;
881 }
882 
update(uint64_t Addr)883 void InstructionPointer::update(uint64_t Addr) {
884   Address = Addr;
885   Index = Binary->getIndexForAddr(Address);
886 }
887 
888 } // end namespace sampleprof
889 } // end namespace llvm
890