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/Demangle/Demangle.h"
14 #include "llvm/IR/DebugInfoMetadata.h"
15 #include "llvm/Support/CommandLine.h"
16 #include "llvm/Support/Format.h"
17 #include "llvm/Support/TargetRegistry.h"
18 #include "llvm/Support/TargetSelect.h"
19 
20 #define DEBUG_TYPE "load-binary"
21 
22 using namespace llvm;
23 using namespace sampleprof;
24 
25 cl::opt<bool> ShowDisassemblyOnly("show-disassembly-only", cl::ReallyHidden,
26                                   cl::init(false), cl::ZeroOrMore,
27                                   cl::desc("Print disassembled code."));
28 
29 cl::opt<bool> ShowSourceLocations("show-source-locations", cl::ReallyHidden,
30                                   cl::init(false), cl::ZeroOrMore,
31                                   cl::desc("Print source locations."));
32 
33 cl::opt<bool> ShowCanonicalFnName("show-canonical-fname", cl::ReallyHidden,
34                                   cl::init(false), cl::ZeroOrMore,
35                                   cl::desc("Print canonical function name."));
36 
37 cl::opt<bool> ShowPseudoProbe(
38     "show-pseudo-probe", cl::ReallyHidden, cl::init(false), cl::ZeroOrMore,
39     cl::desc("Print pseudo probe section and disassembled info."));
40 
41 static cl::list<std::string> DisassembleFunctions(
42     "disassemble-functions", cl::CommaSeparated,
43     cl::desc("List of functions to print disassembly for. Accept demangled "
44              "names only. Only work with show-disassembly-only"));
45 
46 namespace llvm {
47 namespace sampleprof {
48 
49 static const Target *getTarget(const ObjectFile *Obj) {
50   Triple TheTriple = Obj->makeTriple();
51   std::string Error;
52   std::string ArchName;
53   const Target *TheTarget =
54       TargetRegistry::lookupTarget(ArchName, TheTriple, Error);
55   if (!TheTarget)
56     exitWithError(Error, Obj->getFileName());
57   return TheTarget;
58 }
59 
60 void BinarySizeContextTracker::addInstructionForContext(
61     const SampleContextFrameVector &Context, uint32_t InstrSize) {
62   ContextTrieNode *CurNode = &RootContext;
63   bool IsLeaf = true;
64   for (const auto &Callsite : reverse(Context)) {
65     StringRef CallerName = Callsite.CallerName;
66     LineLocation CallsiteLoc = IsLeaf ? LineLocation(0, 0) : Callsite.Callsite;
67     CurNode = CurNode->getOrCreateChildContext(CallsiteLoc, CallerName);
68     IsLeaf = false;
69   }
70 
71   CurNode->addFunctionSize(InstrSize);
72 }
73 
74 uint32_t
75 BinarySizeContextTracker::getFuncSizeForContext(const SampleContext &Context) {
76   ContextTrieNode *CurrNode = &RootContext;
77   ContextTrieNode *PrevNode = nullptr;
78   SampleContextFrames Frames = Context.getContextFrames();
79   int32_t I = Frames.size() - 1;
80   Optional<uint32_t> Size;
81 
82   // Start from top-level context-less function, traverse down the reverse
83   // context trie to find the best/longest match for given context, then
84   // retrieve the size.
85 
86   while (CurrNode && I >= 0) {
87     // Process from leaf function to callers (added to context).
88     const auto &ChildFrame = Frames[I--];
89     PrevNode = CurrNode;
90     CurrNode =
91         CurrNode->getChildContext(ChildFrame.Callsite, ChildFrame.CallerName);
92     if (CurrNode && CurrNode->getFunctionSize().hasValue())
93       Size = CurrNode->getFunctionSize().getValue();
94   }
95 
96   // If we traversed all nodes along the path of the context and haven't
97   // found a size yet, pivot to look for size from sibling nodes, i.e size
98   // of inlinee under different context.
99   if (!Size.hasValue()) {
100     if (!CurrNode)
101       CurrNode = PrevNode;
102     while (!Size.hasValue() && CurrNode &&
103            !CurrNode->getAllChildContext().empty()) {
104       CurrNode = &CurrNode->getAllChildContext().begin()->second;
105       if (CurrNode->getFunctionSize().hasValue())
106         Size = CurrNode->getFunctionSize().getValue();
107     }
108   }
109 
110   assert(Size.hasValue() && "We should at least find one context size.");
111   return Size.getValue();
112 }
113 
114 void BinarySizeContextTracker::trackInlineesOptimizedAway(
115     MCPseudoProbeDecoder &ProbeDecoder) {
116   ProbeFrameStack ProbeContext;
117   for (const auto &Child : ProbeDecoder.getDummyInlineRoot().getChildren())
118     trackInlineesOptimizedAway(ProbeDecoder, *Child.second.get(), ProbeContext);
119 }
120 
121 void BinarySizeContextTracker::trackInlineesOptimizedAway(
122     MCPseudoProbeDecoder &ProbeDecoder,
123     MCDecodedPseudoProbeInlineTree &ProbeNode, ProbeFrameStack &ProbeContext) {
124   StringRef FuncName =
125       ProbeDecoder.getFuncDescForGUID(ProbeNode.Guid)->FuncName;
126   ProbeContext.emplace_back(FuncName, 0);
127 
128   // This ProbeContext has a probe, so it has code before inlining and
129   // optimization. Make sure we mark its size as known.
130   if (!ProbeNode.getProbes().empty()) {
131     ContextTrieNode *SizeContext = &RootContext;
132     for (auto &ProbeFrame : reverse(ProbeContext)) {
133       StringRef CallerName = ProbeFrame.first;
134       LineLocation CallsiteLoc(ProbeFrame.second, 0);
135       SizeContext =
136           SizeContext->getOrCreateChildContext(CallsiteLoc, CallerName);
137     }
138     // Add 0 size to make known.
139     SizeContext->addFunctionSize(0);
140   }
141 
142   // DFS down the probe inline tree
143   for (const auto &ChildNode : ProbeNode.getChildren()) {
144     InlineSite Location = ChildNode.first;
145     ProbeContext.back().second = std::get<1>(Location);
146     trackInlineesOptimizedAway(ProbeDecoder, *ChildNode.second.get(), ProbeContext);
147   }
148 
149   ProbeContext.pop_back();
150 }
151 
152 void ProfiledBinary::load() {
153   // Attempt to open the binary.
154   OwningBinary<Binary> OBinary = unwrapOrError(createBinary(Path), Path);
155   Binary &Binary = *OBinary.getBinary();
156 
157   auto *Obj = dyn_cast<ELFObjectFileBase>(&Binary);
158   if (!Obj)
159     exitWithError("not a valid Elf image", Path);
160 
161   TheTriple = Obj->makeTriple();
162   // Current only support X86
163   if (!TheTriple.isX86())
164     exitWithError("unsupported target", TheTriple.getTriple());
165   LLVM_DEBUG(dbgs() << "Loading " << Path << "\n");
166 
167   // Find the preferred load address for text sections.
168   setPreferredTextSegmentAddresses(Obj);
169 
170   // Decode pseudo probe related section
171   decodePseudoProbe(Obj);
172 
173   // Disassemble the text sections.
174   disassemble(Obj);
175 
176   // Track size for optimized inlinees when probe is available
177   if (UsePseudoProbes && TrackFuncContextSize)
178     FuncSizeTracker.trackInlineesOptimizedAway(ProbeDecoder);
179 
180   // Use function start and return address to infer prolog and epilog
181   ProEpilogTracker.inferPrologOffsets(FuncStartOffsetMap);
182   ProEpilogTracker.inferEpilogOffsets(RetAddrs);
183 
184   // TODO: decode other sections.
185 }
186 
187 bool ProfiledBinary::inlineContextEqual(uint64_t Address1, uint64_t Address2) {
188   uint64_t Offset1 = virtualAddrToOffset(Address1);
189   uint64_t Offset2 = virtualAddrToOffset(Address2);
190   const SampleContextFrameVector &Context1 = getFrameLocationStack(Offset1);
191   const SampleContextFrameVector &Context2 = getFrameLocationStack(Offset2);
192   if (Context1.size() != Context2.size())
193     return false;
194   if (Context1.empty())
195     return false;
196   // The leaf frame contains location within the leaf, and it
197   // needs to be remove that as it's not part of the calling context
198   return std::equal(Context1.begin(), Context1.begin() + Context1.size() - 1,
199                     Context2.begin(), Context2.begin() + Context2.size() - 1);
200 }
201 
202 SampleContextFrameVector
203 ProfiledBinary::getExpandedContext(const SmallVectorImpl<uint64_t> &Stack,
204                                    bool &WasLeafInlined) {
205   SampleContextFrameVector ContextVec;
206   // Process from frame root to leaf
207   for (auto Address : Stack) {
208     uint64_t Offset = virtualAddrToOffset(Address);
209     const SampleContextFrameVector &ExpandedContext =
210         getFrameLocationStack(Offset);
211     // An instruction without a valid debug line will be ignored by sample
212     // processing
213     if (ExpandedContext.empty())
214       return SampleContextFrameVector();
215     // Set WasLeafInlined to the size of inlined frame count for the last
216     // address which is leaf
217     WasLeafInlined = (ExpandedContext.size() > 1);
218     ContextVec.append(ExpandedContext);
219   }
220 
221   assert(ContextVec.size() && "Context length should be at least 1");
222 
223   // Compress the context string except for the leaf frame
224   auto LeafFrame = ContextVec.back();
225   LeafFrame.Callsite = LineLocation(0, 0);
226   ContextVec.pop_back();
227   CSProfileGenerator::compressRecursionContext(ContextVec);
228   CSProfileGenerator::trimContext(ContextVec);
229   ContextVec.push_back(LeafFrame);
230   return ContextVec;
231 }
232 
233 template <class ELFT>
234 void ProfiledBinary::setPreferredTextSegmentAddresses(const ELFFile<ELFT> &Obj, StringRef FileName) {
235   const auto &PhdrRange = unwrapOrError(Obj.program_headers(), FileName);
236   // FIXME: This should be the page size of the system running profiling.
237   // However such info isn't available at post-processing time, assuming
238   // 4K page now. Note that we don't use EXEC_PAGESIZE from <linux/param.h>
239   // because we may build the tools on non-linux.
240   uint32_t PageSize = 0x1000;
241   for (const typename ELFT::Phdr &Phdr : PhdrRange) {
242     if ((Phdr.p_type == ELF::PT_LOAD) && (Phdr.p_flags & ELF::PF_X)) {
243         // Segments will always be loaded at a page boundary.
244         PreferredTextSegmentAddresses.push_back(Phdr.p_vaddr &
245                                                 ~(PageSize - 1U));
246         TextSegmentOffsets.push_back(Phdr.p_offset & ~(PageSize - 1U));
247       }
248   }
249 
250   if (PreferredTextSegmentAddresses.empty())
251     exitWithError("no executable segment found", FileName);
252 }
253 
254 void ProfiledBinary::setPreferredTextSegmentAddresses(const ELFObjectFileBase *Obj) {
255   if (const auto *ELFObj = dyn_cast<ELF32LEObjectFile>(Obj))
256     setPreferredTextSegmentAddresses(ELFObj->getELFFile(), Obj->getFileName());
257   else if (const auto *ELFObj = dyn_cast<ELF32BEObjectFile>(Obj))
258     setPreferredTextSegmentAddresses(ELFObj->getELFFile(), Obj->getFileName());
259   else if (const auto *ELFObj = dyn_cast<ELF64LEObjectFile>(Obj))
260     setPreferredTextSegmentAddresses(ELFObj->getELFFile(), Obj->getFileName());
261   else if (const auto *ELFObj = cast<ELF64BEObjectFile>(Obj))
262     setPreferredTextSegmentAddresses(ELFObj->getELFFile(), Obj->getFileName());
263   else
264     llvm_unreachable("invalid ELF object format");
265 }
266 
267 void ProfiledBinary::decodePseudoProbe(const ELFObjectFileBase *Obj) {
268   StringRef FileName = Obj->getFileName();
269   for (section_iterator SI = Obj->section_begin(), SE = Obj->section_end();
270        SI != SE; ++SI) {
271     const SectionRef &Section = *SI;
272     StringRef SectionName = unwrapOrError(Section.getName(), FileName);
273 
274     if (SectionName == ".pseudo_probe_desc") {
275       StringRef Contents = unwrapOrError(Section.getContents(), FileName);
276       if (!ProbeDecoder.buildGUID2FuncDescMap(
277               reinterpret_cast<const uint8_t *>(Contents.data()),
278               Contents.size()))
279         exitWithError("Pseudo Probe decoder fail in .pseudo_probe_desc section");
280     } else if (SectionName == ".pseudo_probe") {
281       StringRef Contents = unwrapOrError(Section.getContents(), FileName);
282       if (!ProbeDecoder.buildAddress2ProbeMap(
283               reinterpret_cast<const uint8_t *>(Contents.data()),
284               Contents.size()))
285         exitWithError("Pseudo Probe decoder fail in .pseudo_probe section");
286       // set UsePseudoProbes flag, used for PerfReader
287       UsePseudoProbes = true;
288     }
289   }
290 
291   if (ShowPseudoProbe)
292     ProbeDecoder.printGUID2FuncDescMap(outs());
293 }
294 
295 bool ProfiledBinary::dissassembleSymbol(std::size_t SI, ArrayRef<uint8_t> Bytes,
296                                         SectionSymbolsTy &Symbols,
297                                         const SectionRef &Section) {
298   std::size_t SE = Symbols.size();
299   uint64_t SectionOffset = Section.getAddress() - getPreferredBaseAddress();
300   uint64_t SectSize = Section.getSize();
301   uint64_t StartOffset = Symbols[SI].Addr - getPreferredBaseAddress();
302   uint64_t NextStartOffset =
303       (SI + 1 < SE) ? Symbols[SI + 1].Addr - getPreferredBaseAddress()
304                     : SectionOffset + SectSize;
305   if (StartOffset >= NextStartOffset)
306     return true;
307 
308   StringRef SymbolName =
309       ShowCanonicalFnName
310           ? FunctionSamples::getCanonicalFnName(Symbols[SI].Name)
311           : Symbols[SI].Name;
312   bool ShowDisassembly =
313       ShowDisassemblyOnly && (DisassembleFunctionSet.empty() ||
314                               DisassembleFunctionSet.count(SymbolName));
315   if (ShowDisassembly)
316     outs() << '<' << SymbolName << ">:\n";
317 
318   auto WarnInvalidInsts = [](uint64_t Start, uint64_t End) {
319     WithColor::warning() << "Invalid instructions at "
320                          << format("%8" PRIx64, Start) << " - "
321                          << format("%8" PRIx64, End) << "\n";
322   };
323 
324   uint64_t Offset = StartOffset;
325   uint64_t EndOffset = 0;
326   // Size of a consecutive invalid instruction range starting from Offset -1
327   // backwards.
328   uint64_t InvalidInstLength = 0;
329   while (Offset < NextStartOffset) {
330     MCInst Inst;
331     uint64_t Size;
332     // Disassemble an instruction.
333     bool Disassembled =
334         DisAsm->getInstruction(Inst, Size, Bytes.slice(Offset - SectionOffset),
335                                Offset + getPreferredBaseAddress(), nulls());
336     if (Size == 0)
337       Size = 1;
338 
339     if (ShowDisassembly) {
340       if (ShowPseudoProbe) {
341         ProbeDecoder.printProbeForAddress(outs(),
342                                           Offset + getPreferredBaseAddress());
343       }
344       outs() << format("%8" PRIx64 ":", Offset + getPreferredBaseAddress());
345       size_t Start = outs().tell();
346       if (Disassembled)
347         IPrinter->printInst(&Inst, Offset + Size, "", *STI.get(), outs());
348       else
349         outs() << "\t<unknown>";
350       if (ShowSourceLocations) {
351         unsigned Cur = outs().tell() - Start;
352         if (Cur < 40)
353           outs().indent(40 - Cur);
354         InstructionPointer IP(this, Offset);
355         outs() << getReversedLocWithContext(
356             symbolize(IP, ShowCanonicalFnName, ShowPseudoProbe));
357       }
358       outs() << "\n";
359     }
360 
361     if (Disassembled) {
362       const MCInstrDesc &MCDesc = MII->get(Inst.getOpcode());
363 
364       // Record instruction size.
365       Offset2InstSizeMap[Offset] = Size;
366 
367       // Populate address maps.
368       CodeAddrOffsets.push_back(Offset);
369       if (MCDesc.isCall())
370         CallAddrs.insert(Offset);
371       else if (MCDesc.isReturn())
372         RetAddrs.insert(Offset);
373 
374       EndOffset = Offset;
375 
376       if (InvalidInstLength) {
377         WarnInvalidInsts(Offset - InvalidInstLength, Offset - 1);
378         InvalidInstLength = 0;
379       }
380     } else {
381       InvalidInstLength += Size;
382     }
383 
384     Offset += Size;
385   }
386 
387   if (InvalidInstLength)
388     WarnInvalidInsts(Offset - InvalidInstLength, Offset - 1);
389 
390   if (ShowDisassembly)
391     outs() << "\n";
392 
393   FuncStartOffsetMap.emplace(StartOffset,
394                              std::make_pair(Symbols[SI].Name.str(), EndOffset));
395   return true;
396 }
397 
398 void ProfiledBinary::setUpDisassembler(const ELFObjectFileBase *Obj) {
399   const Target *TheTarget = getTarget(Obj);
400   std::string TripleName = TheTriple.getTriple();
401   StringRef FileName = Obj->getFileName();
402 
403   MRI.reset(TheTarget->createMCRegInfo(TripleName));
404   if (!MRI)
405     exitWithError("no register info for target " + TripleName, FileName);
406 
407   MCTargetOptions MCOptions;
408   AsmInfo.reset(TheTarget->createMCAsmInfo(*MRI, TripleName, MCOptions));
409   if (!AsmInfo)
410     exitWithError("no assembly info for target " + TripleName, FileName);
411 
412   SubtargetFeatures Features = Obj->getFeatures();
413   STI.reset(
414       TheTarget->createMCSubtargetInfo(TripleName, "", Features.getString()));
415   if (!STI)
416     exitWithError("no subtarget info for target " + TripleName, FileName);
417 
418   MII.reset(TheTarget->createMCInstrInfo());
419   if (!MII)
420     exitWithError("no instruction info for target " + TripleName, FileName);
421 
422   MCContext Ctx(Triple(TripleName), AsmInfo.get(), MRI.get(), STI.get());
423   std::unique_ptr<MCObjectFileInfo> MOFI(
424       TheTarget->createMCObjectFileInfo(Ctx, /*PIC=*/false));
425   Ctx.setObjectFileInfo(MOFI.get());
426   DisAsm.reset(TheTarget->createMCDisassembler(*STI, Ctx));
427   if (!DisAsm)
428     exitWithError("no disassembler for target " + TripleName, FileName);
429 
430   MIA.reset(TheTarget->createMCInstrAnalysis(MII.get()));
431 
432   int AsmPrinterVariant = AsmInfo->getAssemblerDialect();
433   IPrinter.reset(TheTarget->createMCInstPrinter(
434       Triple(TripleName), AsmPrinterVariant, *AsmInfo, *MII, *MRI));
435   IPrinter->setPrintBranchImmAsAddress(true);
436 }
437 
438 void ProfiledBinary::disassemble(const ELFObjectFileBase *Obj) {
439   // Set up disassembler and related components.
440   setUpDisassembler(Obj);
441 
442   // Create a mapping from virtual address to symbol name. The symbols in text
443   // sections are the candidates to dissassemble.
444   std::map<SectionRef, SectionSymbolsTy> AllSymbols;
445   StringRef FileName = Obj->getFileName();
446   for (const SymbolRef &Symbol : Obj->symbols()) {
447     const uint64_t Addr = unwrapOrError(Symbol.getAddress(), FileName);
448     const StringRef Name = unwrapOrError(Symbol.getName(), FileName);
449     section_iterator SecI = unwrapOrError(Symbol.getSection(), FileName);
450     if (SecI != Obj->section_end())
451       AllSymbols[*SecI].push_back(SymbolInfoTy(Addr, Name, ELF::STT_NOTYPE));
452   }
453 
454   // Sort all the symbols. Use a stable sort to stabilize the output.
455   for (std::pair<const SectionRef, SectionSymbolsTy> &SecSyms : AllSymbols)
456     stable_sort(SecSyms.second);
457 
458   DisassembleFunctionSet.insert(DisassembleFunctions.begin(),
459                                 DisassembleFunctions.end());
460   assert((DisassembleFunctionSet.empty() || ShowDisassemblyOnly) &&
461          "Functions to disassemble should be only specified together with "
462          "--show-disassembly-only");
463 
464   if (ShowDisassemblyOnly)
465     outs() << "\nDisassembly of " << FileName << ":\n";
466 
467   // Dissassemble a text section.
468   for (section_iterator SI = Obj->section_begin(), SE = Obj->section_end();
469        SI != SE; ++SI) {
470     const SectionRef &Section = *SI;
471     if (!Section.isText())
472       continue;
473 
474     uint64_t ImageLoadAddr = getPreferredBaseAddress();
475     uint64_t SectionOffset = Section.getAddress() - ImageLoadAddr;
476     uint64_t SectSize = Section.getSize();
477     if (!SectSize)
478       continue;
479 
480     // Register the text section.
481     TextSections.insert({SectionOffset, SectSize});
482 
483     if (ShowDisassemblyOnly) {
484       StringRef SectionName = unwrapOrError(Section.getName(), FileName);
485       outs() << "\nDisassembly of section " << SectionName;
486       outs() << " [" << format("0x%" PRIx64, Section.getAddress()) << ", "
487              << format("0x%" PRIx64, Section.getAddress() + SectSize)
488              << "]:\n\n";
489     }
490 
491     // Get the section data.
492     ArrayRef<uint8_t> Bytes =
493         arrayRefFromStringRef(unwrapOrError(Section.getContents(), FileName));
494 
495     // Get the list of all the symbols in this section.
496     SectionSymbolsTy &Symbols = AllSymbols[Section];
497 
498     // Disassemble symbol by symbol.
499     for (std::size_t SI = 0, SE = Symbols.size(); SI != SE; ++SI) {
500       if (!dissassembleSymbol(SI, Bytes, Symbols, Section))
501         exitWithError("disassembling error", FileName);
502     }
503   }
504 }
505 
506 void ProfiledBinary::setupSymbolizer() {
507   symbolize::LLVMSymbolizer::Options SymbolizerOpts;
508   SymbolizerOpts.PrintFunctions =
509       DILineInfoSpecifier::FunctionNameKind::LinkageName;
510   SymbolizerOpts.Demangle = false;
511   SymbolizerOpts.DefaultArch = TheTriple.getArchName().str();
512   SymbolizerOpts.UseSymbolTable = false;
513   SymbolizerOpts.RelativeAddresses = false;
514   Symbolizer = std::make_unique<symbolize::LLVMSymbolizer>(SymbolizerOpts);
515 }
516 
517 SampleContextFrameVector ProfiledBinary::symbolize(const InstructionPointer &IP,
518                                                    bool UseCanonicalFnName,
519                                                    bool UseProbeDiscriminator) {
520   assert(this == IP.Binary &&
521          "Binary should only symbolize its own instruction");
522   auto Addr = object::SectionedAddress{IP.Offset + getPreferredBaseAddress(),
523                                        object::SectionedAddress::UndefSection};
524   DIInliningInfo InlineStack =
525       unwrapOrError(Symbolizer->symbolizeInlinedCode(Path, Addr), getName());
526 
527   SampleContextFrameVector CallStack;
528   for (int32_t I = InlineStack.getNumberOfFrames() - 1; I >= 0; I--) {
529     const auto &CallerFrame = InlineStack.getFrame(I);
530     if (CallerFrame.FunctionName == "<invalid>")
531       break;
532 
533     StringRef FunctionName(CallerFrame.FunctionName);
534     if (UseCanonicalFnName)
535       FunctionName = FunctionSamples::getCanonicalFnName(FunctionName);
536 
537     uint32_t Discriminator = CallerFrame.Discriminator;
538     uint32_t LineOffset = CallerFrame.Line - CallerFrame.StartLine;
539     if (UseProbeDiscriminator) {
540       LineOffset =
541           PseudoProbeDwarfDiscriminator::extractProbeIndex(Discriminator);
542       Discriminator = 0;
543     } else {
544       Discriminator = DILocation::getBaseDiscriminatorFromDiscriminator(
545           CallerFrame.Discriminator,
546           /* IsFSDiscriminator */ false);
547     }
548 
549     LineLocation Line(LineOffset, Discriminator);
550     auto It = NameStrings.insert(FunctionName.str());
551     CallStack.emplace_back(*It.first, Line);
552   }
553 
554   return CallStack;
555 }
556 
557 void ProfiledBinary::computeInlinedContextSizeForRange(uint64_t StartOffset,
558                                                        uint64_t EndOffset) {
559   uint32_t Index = getIndexForOffset(StartOffset);
560   if (CodeAddrOffsets[Index] != StartOffset)
561     WithColor::warning() << "Invalid start instruction at "
562                          << format("%8" PRIx64, StartOffset) << "\n";
563 
564   uint64_t Offset = CodeAddrOffsets[Index];
565   while (Offset <= EndOffset) {
566     const SampleContextFrameVector &SymbolizedCallStack =
567         getFrameLocationStack(Offset, UsePseudoProbes);
568     uint64_t Size = Offset2InstSizeMap[Offset];
569 
570     // Record instruction size for the corresponding context
571     FuncSizeTracker.addInstructionForContext(SymbolizedCallStack, Size);
572 
573     Offset = CodeAddrOffsets[++Index];
574   }
575 }
576 
577 InstructionPointer::InstructionPointer(const ProfiledBinary *Binary,
578                                        uint64_t Address, bool RoundToNext)
579     : Binary(Binary), Address(Address) {
580   Index = Binary->getIndexForAddr(Address);
581   if (RoundToNext) {
582     // we might get address which is not the code
583     // it should round to the next valid address
584     this->Address = Binary->getAddressforIndex(Index);
585   }
586 }
587 
588 void InstructionPointer::advance() {
589   Index++;
590   Address = Binary->getAddressforIndex(Index);
591 }
592 
593 void InstructionPointer::backward() {
594   Index--;
595   Address = Binary->getAddressforIndex(Index);
596 }
597 
598 void InstructionPointer::update(uint64_t Addr) {
599   Address = Addr;
600   Index = Binary->getIndexForAddr(Address);
601 }
602 
603 } // end namespace sampleprof
604 } // end namespace llvm
605