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