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