1//===-- ProfiledBinary.h - 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#ifndef LLVM_TOOLS_LLVM_PROFGEN_PROFILEDBINARY_H
10#define LLVM_TOOLS_LLVM_PROFGEN_PROFILEDBINARY_H
11
12#include "CallContext.h"
13#include "ErrorHandling.h"
14#include "llvm/ADT/DenseMap.h"
15#include "llvm/ADT/DenseSet.h"
16#include "llvm/ADT/SmallPtrSet.h"
17#include "llvm/ADT/StringRef.h"
18#include "llvm/ADT/StringSet.h"
19#include "llvm/DebugInfo/DWARF/DWARFContext.h"
20#include "llvm/DebugInfo/Symbolize/Symbolize.h"
21#include "llvm/MC/MCAsmInfo.h"
22#include "llvm/MC/MCContext.h"
23#include "llvm/MC/MCDisassembler/MCDisassembler.h"
24#include "llvm/MC/MCInst.h"
25#include "llvm/MC/MCInstPrinter.h"
26#include "llvm/MC/MCInstrAnalysis.h"
27#include "llvm/MC/MCInstrInfo.h"
28#include "llvm/MC/MCObjectFileInfo.h"
29#include "llvm/MC/MCPseudoProbe.h"
30#include "llvm/MC/MCRegisterInfo.h"
31#include "llvm/MC/MCSubtargetInfo.h"
32#include "llvm/MC/MCTargetOptions.h"
33#include "llvm/Object/BuildID.h"
34#include "llvm/Object/ELFObjectFile.h"
35#include "llvm/ProfileData/SampleProf.h"
36#include "llvm/Support/CommandLine.h"
37#include "llvm/Support/Path.h"
38#include "llvm/Transforms/IPO/SampleContextTracker.h"
39#include <map>
40#include <set>
41#include <sstream>
42#include <string>
43#include <unordered_map>
44#include <unordered_set>
45#include <vector>
46
47namespace llvm {
48namespace sampleprof {
49
50class ProfiledBinary;
51class MissingFrameInferrer;
52
53struct InstructionPointer {
54 const ProfiledBinary *Binary;
55 // Address of the executable segment of the binary.
56 uint64_t Address;
57 // Index to the sorted code address array of the binary.
58 uint64_t Index = 0;
59 InstructionPointer(const ProfiledBinary *Binary, uint64_t Address,
60 bool RoundToNext = false);
61 bool advance();
62 bool backward();
63 void update(uint64_t Addr);
64};
65
66// The special frame addresses.
67enum SpecialFrameAddr {
68 // Dummy root of frame trie.
69 DummyRoot = 0,
70 // Represent all the addresses outside of current binary.
71 // This's also used to indicate the call stack should be truncated since this
72 // isn't a real call context the compiler will see.
73 ExternalAddr = 1,
74};
75
76using RangesTy = std::vector<std::pair<uint64_t, uint64_t>>;
77
78enum DwarfNameStatus {
79 // Dwarf name matches with the symbol table (or symbol table just doesn't have
80 // this entry)
81 Matched = 0,
82 // Dwarf name is missing, but we fixed it with the name from symbol table
83 Missing = 1,
84 // Symbol table has different names on this. Log these GUIDs in
85 // AlternativeFunctionGUIDs
86 Mismatch = 2,
87};
88
89struct BinaryFunction {
90 StringRef FuncName;
91 // End of range is an exclusive bound.
92 RangesTy Ranges;
93 DwarfNameStatus NameStatus = DwarfNameStatus::Matched;
94
95 uint64_t getFuncSize() {
96 uint64_t Sum = 0;
97 for (auto &R : Ranges) {
98 Sum += R.second - R.first;
99 }
100 return Sum;
101 }
102};
103
104// Info about function range. A function can be split into multiple
105// non-continuous ranges, each range corresponds to one FuncRange.
106struct FuncRange {
107 uint64_t StartAddress;
108 // EndAddress is an exclusive bound.
109 uint64_t EndAddress;
110 // Function the range belongs to
111 BinaryFunction *Func;
112 // Whether the start address is the real entry of the function.
113 bool IsFuncEntry = false;
114
115 StringRef getFuncName() { return Func->FuncName; }
116};
117
118// PrologEpilog address tracker, used to filter out broken stack samples
119// Currently we use a heuristic size (two) to infer prolog and epilog
120// based on the start address and return address. In the future,
121// we will switch to Dwarf CFI based tracker
122struct PrologEpilogTracker {
123 // A set of prolog and epilog addresses. Used by virtual unwinding.
124 DenseSet<uint64_t> PrologEpilogSet;
125 ProfiledBinary *Binary;
126 PrologEpilogTracker(ProfiledBinary *Bin) : Binary(Bin){};
127
128 // Take the two addresses from the start of function as prolog
129 void
130 inferPrologAddresses(std::map<uint64_t, FuncRange> &FuncStartAddressMap) {
131 for (auto I : FuncStartAddressMap) {
132 PrologEpilogSet.insert(V: I.first);
133 InstructionPointer IP(Binary, I.first);
134 if (!IP.advance())
135 continue;
136 PrologEpilogSet.insert(V: IP.Address);
137 }
138 }
139
140 // Take the last two addresses before the return address as epilog
141 void inferEpilogAddresses(DenseSet<uint64_t> &RetAddrs) {
142 for (auto Addr : RetAddrs) {
143 PrologEpilogSet.insert(V: Addr);
144 InstructionPointer IP(Binary, Addr);
145 if (!IP.backward())
146 continue;
147 PrologEpilogSet.insert(V: IP.Address);
148 }
149 }
150};
151
152// Track function byte size under different context (outlined version as well as
153// various inlined versions). It also provides query support to get function
154// size with the best matching context, which is used to help pre-inliner use
155// accurate post-optimization size to make decisions.
156// TODO: If an inlinee is completely optimized away, ideally we should have zero
157// for its context size, currently we would misss such context since it doesn't
158// have instructions. To fix this, we need to mark all inlinee with entry probe
159// but without instructions as having zero size.
160class BinarySizeContextTracker {
161public:
162 // Add instruction with given size to a context
163 void addInstructionForContext(const SampleContextFrameVector &Context,
164 uint32_t InstrSize);
165
166 // Get function size with a specific context. When there's no exact match
167 // for the given context, try to retrieve the size of that function from
168 // closest matching context.
169 uint32_t getFuncSizeForContext(const ContextTrieNode *Context);
170
171 // For inlinees that are full optimized away, we can establish zero size using
172 // their remaining probes.
173 void trackInlineesOptimizedAway(MCPseudoProbeDecoder &ProbeDecoder);
174
175 using ProbeFrameStack = SmallVector<std::pair<StringRef, uint32_t>>;
176 void
177 trackInlineesOptimizedAway(MCPseudoProbeDecoder &ProbeDecoder,
178 const MCDecodedPseudoProbeInlineTree &ProbeNode,
179 ProbeFrameStack &Context);
180
181 void dump() { RootContext.dumpTree(); }
182
183private:
184 // Root node for context trie tree, node that this is a reverse context trie
185 // with callee as parent and caller as child. This way we can traverse from
186 // root to find the best/longest matching context if an exact match does not
187 // exist. It gives us the best possible estimate for function's post-inline,
188 // post-optimization byte size.
189 ContextTrieNode RootContext;
190};
191
192using AddressRange = std::pair<uint64_t, uint64_t>;
193
194// The parsed MMap event
195struct MMapEvent {
196 int64_t PID = 0;
197 uint64_t Address = 0;
198 uint64_t Size = 0;
199 uint64_t Offset = 0;
200 StringRef MemProtectionFlag;
201 StringRef BinaryPath;
202};
203
204class ProfiledBinary {
205 // The executable binary file.
206 object::OwningBinary<object::Binary> OBinary;
207 // Absolute path of the executable binary.
208 std::string Path;
209 // Path of the debug info binary.
210 std::string DebugBinaryPath;
211 // Path of the pseudo probe binary, either Path or DebugBinaryPath if present.
212 StringRef PseudoProbeBinPath;
213 // The target triple.
214 Triple TheTriple;
215 // Path of symbolizer path which should be pointed to binary with debug info.
216 StringRef SymbolizerPath;
217 // Options used to configure the symbolizer
218 symbolize::LLVMSymbolizer::Options SymbolizerOpts;
219 // The runtime base address that the first executable segment is loaded at.
220 uint64_t BaseAddress = 0;
221 // The runtime base address that the first loadabe segment is loaded at.
222 uint64_t FirstLoadableAddress = 0;
223 // The preferred load address of each executable segment.
224 std::vector<uint64_t> PreferredTextSegmentAddresses;
225 // The file offset of each executable segment.
226 std::vector<uint64_t> TextSegmentOffsets;
227
228 // Mutiple MC component info
229 std::unique_ptr<const MCRegisterInfo> MRI;
230 std::unique_ptr<const MCAsmInfo> AsmInfo;
231 std::unique_ptr<const MCSubtargetInfo> STI;
232 std::unique_ptr<const MCInstrInfo> MII;
233 std::unique_ptr<MCDisassembler> DisAsm;
234 std::unique_ptr<const MCInstrAnalysis> MIA;
235 std::unique_ptr<MCInstPrinter> IPrinter;
236 // A list of text sections sorted by start RVA and size. Used to check
237 // if a given RVA is a valid code address.
238 std::set<std::pair<uint64_t, uint64_t>> TextSections;
239
240 // A map of mapping function name to BinaryFunction info.
241 StringMap<BinaryFunction> BinaryFunctions;
242
243 // Lookup BinaryFunctions using the function name's MD5 hash. Needed if the
244 // profile is using MD5.
245 DenseMap<uint64_t, BinaryFunction *> HashBinaryFunctions;
246
247 // A list of binary functions that have samples.
248 SmallPtrSet<const BinaryFunction *, 0> ProfiledFunctions;
249
250 // GUID to symbol start address map
251 DenseMap<uint64_t, uint64_t> SymbolStartAddrs;
252
253 // Binary function to GUID mapping that stores the alternative names in symbol
254 // table, despite the original name from DWARF info
255 std::unordered_multimap<const BinaryFunction *, uint64_t>
256 AlternativeFunctionGUIDs;
257
258 // Mapping of profiled binary function to its pseudo probe name
259 DenseMap<const BinaryFunction *, StringRef> PseudoProbeNames;
260
261 // These maps are for temporary use of warning diagnosis.
262 DenseSet<int64_t> AddrsWithMultipleSymbols;
263 DenseSet<std::pair<uint64_t, uint64_t>> AddrsWithInvalidInstruction;
264
265 // Start address to symbol GUID map
266 std::unordered_multimap<uint64_t, uint64_t> StartAddrToSymMap;
267
268 // An ordered map of mapping function's start address to function range
269 // relevant info. Currently to determine if the offset of ELF/COFF is the
270 // start of a real function, we leverage the function range info from DWARF.
271 std::map<uint64_t, FuncRange> StartAddrToFuncRangeMap;
272
273 // Address to context location map. Used to expand the context.
274 // getCachedFrameLocationStack returns references to the mapped values while
275 // later queries insert, so the values' addresses must be stable: keep
276 // std::unordered_map.
277 std::unordered_map<uint64_t, SampleContextFrameVector> AddressToLocStackMap;
278
279 // Address to instruction size map. Also used for quick Address lookup.
280 DenseMap<uint64_t, uint64_t> AddressToInstSizeMap;
281
282 // An array of Addresses of all instructions sorted in increasing order. The
283 // sorting is needed to fast advance to the next forward/backward instruction.
284 std::vector<uint64_t> CodeAddressVec;
285 // A set of call instruction addresses. Used by virtual unwinding.
286 DenseSet<uint64_t> CallAddressSet;
287 // A set of return instruction addresses. Used by virtual unwinding.
288 DenseSet<uint64_t> RetAddressSet;
289 // An ordered set of unconditional branch instruction addresses.
290 std::set<uint64_t> UncondBranchAddrSet;
291 // A set of branch instruction addresses.
292 DenseSet<uint64_t> BranchAddressSet;
293 // A set of indirect branch instruction addresses.
294 DenseSet<uint64_t> IndirectBranchAddressSet;
295 // A set of branch target addresses (destinations of branches/calls).
296 DenseSet<uint64_t> BranchTargetAddressSet;
297
298 // Estimate and track function prolog and epilog ranges.
299 PrologEpilogTracker ProEpilogTracker;
300
301 // Infer missing frames due to compiler optimizations such as tail call
302 // elimination.
303 std::unique_ptr<MissingFrameInferrer> MissingContextInferrer;
304
305 // Track function sizes under different context
306 BinarySizeContextTracker FuncSizeTracker;
307
308 // The symbolizer used to get inline context for an instruction.
309 std::unique_ptr<symbolize::LLVMSymbolizer> Symbolizer;
310
311 // String table owning function name strings created from the symbolizer.
312 StringSet<> NameStrings;
313
314 // MMap events for PT_LOAD segments without 'x' memory protection flag.
315 std::map<uint64_t, MMapEvent, std::greater<uint64_t>> NonTextMMapEvents;
316
317 // Records the file offset, file size and virtual address of program headers.
318 struct PhdrInfo {
319 uint64_t FileOffset;
320 uint64_t FileSz;
321 uint64_t VirtualAddr;
322 };
323
324 // Program header information for non-text PT_LOAD segments.
325 SmallVector<PhdrInfo> NonTextPhdrInfo;
326
327 // A collection of functions to print disassembly for.
328 StringSet<> DisassembleFunctionSet;
329
330 // Pseudo probe decoder
331 MCPseudoProbeDecoder ProbeDecoder;
332
333 // Function name to probe frame map for top-level outlined functions.
334 StringMap<MCDecodedPseudoProbeInlineTree *> TopLevelProbeFrameMap;
335
336 bool UseFSDiscriminator = false;
337
338 // Whether we need to symbolize all instructions to get function context size.
339 bool TrackFuncContextSize = false;
340
341 // Whether this is a kernel image;
342 bool IsKernel = false;
343
344 // Indicate if the base loading address is parsed from the mmap event or uses
345 // the preferred address
346 bool IsLoadedByMMap = false;
347 // Use to avoid redundant warning.
348 bool MissingMMapWarned = false;
349
350 bool IsCOFF = false;
351
352 // Whether the binary has a PT_INTERP program header (PIE executables do,
353 // true shared libraries don't). Used to distinguish PIE from .so since
354 // both are ET_DYN.
355 bool HasInterp = false;
356
357 // Build ID used to filter perfscript addresses in [buildid:]addr format.
358 // For shared libraries, set to the binary's build ID.
359 // For main executables, kept empty (addresses have no buildid prefix).
360 std::string FilterBuildID;
361
362 void setPreferredTextSegmentAddresses(const object::ObjectFile *O);
363
364 // LLVMSymbolizer's symbolize{Code, Data} interfaces requires a section index
365 // for each address to be symbolized. This is a helper function to
366 // construct a SectionedAddress object with the given address and section
367 // index. The section index is set to UndefSection by default.
368 static object::SectionedAddress getSectionedAddress(
369 uint64_t Address,
370 uint64_t SectionIndex = object::SectionedAddress::UndefSection) {
371 return object::SectionedAddress{.Address: Address, .SectionIndex: SectionIndex};
372 }
373
374 template <class ELFT>
375 void setPreferredTextSegmentAddresses(const object::ELFFile<ELFT> &Obj,
376 StringRef FileName);
377 void setPreferredTextSegmentAddresses(const object::COFFObjectFile *Obj,
378 StringRef FileName);
379
380 // Return true if pseudo probe in Obj is usable.
381 bool checkPseudoProbe(const object::ObjectFile *Obj, StringRef ObjPath);
382
383 void decodePseudoProbe(const object::ObjectFile *Obj);
384
385 void checkUseFSDiscriminator(
386 const object::ObjectFile *Obj,
387 std::map<object::SectionRef, SectionSymbolsTy> &AllSymbols);
388
389 // Set up disassembler and related components.
390 void setUpDisassembler(const object::ObjectFile *Obj);
391 symbolize::LLVMSymbolizer::Options getSymbolizerOpts() const;
392
393 // Load debug info of subprograms from DWARF section.
394 void loadSymbolsFromDWARF(object::ObjectFile &Obj);
395
396 // Load debug info from DWARF unit.
397 void loadSymbolsFromDWARFUnit(DWARFUnit &CompilationUnit);
398
399 // Create symbol to its start address mapping.
400 void populateSymbolAddressList(const object::ObjectFile *O);
401
402 // Load functions from its symbol table (when DWARF info is missing).
403 void loadSymbolsFromSymtab(const object::ObjectFile *O);
404
405 // A function may be spilt into multiple non-continuous address ranges. We use
406 // this to set whether start a function range is the real entry of the
407 // function and also set false to the non-function label.
408 void setIsFuncEntry(FuncRange *FRange, StringRef RangeSymName);
409
410 // Warn if no entry range exists in the function.
411 void warnNoFuncEntry();
412
413 /// Dissassemble the text section and build various address maps.
414 void disassemble(const object::ObjectFile *O);
415
416 /// Helper function to dissassemble the symbol and extract info for unwinding
417 bool dissassembleSymbol(std::size_t SI, ArrayRef<uint8_t> Bytes,
418 SectionSymbolsTy &Symbols,
419 const object::SectionRef &Section);
420 /// Symbolize a given instruction pointer and return a full call context.
421 SampleContextFrameVector symbolize(const InstructionPointer &IP,
422 bool UseCanonicalFnName = false,
423 bool UseProbeDiscriminator = false);
424
425public:
426 ProfiledBinary(const StringRef ExeBinPath, const StringRef DebugBinPath);
427 ~ProfiledBinary();
428
429 /// Decode the interesting parts of the binary and build internal data
430 /// structures. On high level, the parts of interest are:
431 /// 1. Text sections, including the main code section and the PLT
432 /// entries that will be used to handle cross-module call transitions.
433 /// 2. The .debug_line section, used by Dwarf-based profile generation.
434 /// 3. Pseudo probe related sections, used by probe-based profile
435 /// generation.
436 void load(StringRef TripleStr = "");
437
438 /// Symbolize an address and return the symbol name. The returned StringRef is
439 /// owned by this ProfiledBinary object.
440 StringRef symbolizeDataAddress(uint64_t Address);
441
442 void decodePseudoProbe();
443
444 StringRef getPath() const { return Path; }
445 StringRef getName() const { return llvm::sys::path::filename(path: Path); }
446 const Triple &getTriple() const { return TheTriple; }
447 const object::Binary &getBinary() const { return *OBinary.getBinary(); }
448 uint64_t getBaseAddress() const { return BaseAddress; }
449 void setBaseAddress(uint64_t Address) { BaseAddress = Address; }
450
451 bool isCOFF() const { return IsCOFF; }
452
453 // Return the build ID used for filtering perfscript addresses.
454 StringRef getFilterBuildID() const { return FilterBuildID; }
455
456 // Canonicalize to use preferred load address as base address.
457 uint64_t canonicalizeVirtualAddress(uint64_t Address) {
458 return Address - BaseAddress + getPreferredBaseAddress();
459 }
460 // Return the preferred load address for the first executable segment.
461 uint64_t getPreferredBaseAddress() const {
462 return PreferredTextSegmentAddresses[0];
463 }
464 // Return the preferred load address for the first loadable segment.
465 uint64_t getFirstLoadableAddress() const { return FirstLoadableAddress; }
466 // Return the file offset for the first executable segment.
467 uint64_t getTextSegmentOffset() const { return TextSegmentOffsets[0]; }
468 const std::vector<uint64_t> &getPreferredTextSegmentAddresses() const {
469 return PreferredTextSegmentAddresses;
470 }
471 const std::vector<uint64_t> &getTextSegmentOffsets() const {
472 return TextSegmentOffsets;
473 }
474
475 uint64_t getInstSize(uint64_t Address) const {
476 auto I = AddressToInstSizeMap.find(Val: Address);
477 if (I == AddressToInstSizeMap.end())
478 return 0;
479 return I->second;
480 }
481
482 bool addressIsCode(uint64_t Address) const {
483 return AddressToInstSizeMap.find(Val: Address) != AddressToInstSizeMap.end();
484 }
485
486 bool addressIsCall(uint64_t Address) const {
487 return CallAddressSet.count(V: Address);
488 }
489 bool addressIsReturn(uint64_t Address) const {
490 return RetAddressSet.count(V: Address);
491 }
492 bool addressInPrologEpilog(uint64_t Address) const {
493 return ProEpilogTracker.PrologEpilogSet.count(V: Address);
494 }
495
496 bool addressIsBranchTarget(uint64_t Address) const {
497 return BranchTargetAddressSet.count(V: Address);
498 }
499 bool addressIsIndirectBranch(uint64_t Address) const {
500 return IndirectBranchAddressSet.count(V: Address);
501 }
502 bool addressIsTransfer(uint64_t Address) {
503 return BranchAddressSet.count(V: Address) || RetAddressSet.count(V: Address) ||
504 CallAddressSet.count(V: Address);
505 }
506
507 bool rangeCrossUncondBranch(uint64_t Start, uint64_t End) {
508 if (Start >= End)
509 return false;
510 auto R = UncondBranchAddrSet.lower_bound(x: Start);
511 return R != UncondBranchAddrSet.end() && *R < End;
512 }
513
514 uint64_t getAddressforIndex(uint64_t Index) const {
515 return CodeAddressVec[Index];
516 }
517
518 size_t getCodeAddrVecSize() const { return CodeAddressVec.size(); }
519
520 bool usePseudoProbes() const { return !PseudoProbeBinPath.empty(); }
521 bool useFSDiscriminator() const { return UseFSDiscriminator; }
522 bool isKernel() const { return IsKernel; }
523
524 static bool isKernelImageName(StringRef BinaryName) {
525 return BinaryName == "[kernel.kallsyms]" ||
526 BinaryName == "[kernel.kallsyms]_stext" ||
527 BinaryName == "[kernel.kallsyms]_text";
528 }
529
530 // Get the index in CodeAddressVec for the address
531 // As we might get an address which is not the code
532 // here it would round to the next valid code address by
533 // using lower bound operation
534 uint32_t getIndexForAddr(uint64_t Address) const {
535 auto Low = llvm::lower_bound(Range: CodeAddressVec, Value&: Address);
536 return Low - CodeAddressVec.begin();
537 }
538
539 uint64_t getCallAddrFromFrameAddr(uint64_t FrameAddr) const {
540 if (FrameAddr == ExternalAddr)
541 return ExternalAddr;
542 auto I = getIndexForAddr(Address: FrameAddr);
543 FrameAddr = I ? getAddressforIndex(Index: I - 1) : 0;
544 if (FrameAddr && addressIsCall(Address: FrameAddr))
545 return FrameAddr;
546 return 0;
547 }
548
549 FuncRange *findFuncRangeForStartAddr(uint64_t Address) {
550 auto I = StartAddrToFuncRangeMap.find(x: Address);
551 if (I == StartAddrToFuncRangeMap.end())
552 return nullptr;
553 return &I->second;
554 }
555
556 // Binary search the function range which includes the input address.
557 FuncRange *findFuncRange(uint64_t Address) {
558 auto I = StartAddrToFuncRangeMap.upper_bound(x: Address);
559 if (I == StartAddrToFuncRangeMap.begin())
560 return nullptr;
561 I--;
562
563 if (Address >= I->second.EndAddress)
564 return nullptr;
565
566 return &I->second;
567 }
568
569 // Get all ranges of one function.
570 RangesTy getRanges(uint64_t Address) {
571 auto *FRange = findFuncRange(Address);
572 // Ignore the range which falls into plt section or system lib.
573 if (!FRange)
574 return RangesTy();
575
576 return FRange->Func->Ranges;
577 }
578
579 const StringMap<BinaryFunction> &getAllBinaryFunctions() {
580 return BinaryFunctions;
581 }
582
583 SmallPtrSetImpl<const BinaryFunction *> &getProfiledFunctions() {
584 return ProfiledFunctions;
585 }
586
587 void setProfiledFunctions(SmallPtrSetImpl<const BinaryFunction *> &Funcs) {
588 ProfiledFunctions.clear();
589 ProfiledFunctions.insert_range(R&: Funcs);
590 }
591
592 BinaryFunction *getBinaryFunction(FunctionId FName) {
593 if (FName.isStringRef()) {
594 auto I = BinaryFunctions.find(Key: FName.stringRef());
595 if (I == BinaryFunctions.end())
596 return nullptr;
597 return &I->second;
598 }
599 auto I = HashBinaryFunctions.find(Val: FName.getHashCode());
600 if (I == HashBinaryFunctions.end())
601 return nullptr;
602 return I->second;
603 }
604
605 uint32_t getFuncSizeForContext(const ContextTrieNode *ContextNode) {
606 return FuncSizeTracker.getFuncSizeForContext(Context: ContextNode);
607 }
608
609 void inferMissingFrames(const SmallVectorImpl<uint64_t> &Context,
610 SmallVectorImpl<uint64_t> &NewContext);
611
612 // Load the symbols from debug table and populate into symbol list.
613 void populateSymbolListFromDWARF(ProfileSymbolList &SymbolList);
614
615 SampleContextFrameVector
616 getFrameLocationStack(uint64_t Address, bool UseProbeDiscriminator = false) {
617 InstructionPointer IP(this, Address);
618 return symbolize(IP, UseCanonicalFnName: SymbolizerOpts.UseSymbolTable, UseProbeDiscriminator);
619 }
620
621 const SampleContextFrameVector &
622 getCachedFrameLocationStack(uint64_t Address,
623 bool UseProbeDiscriminator = false) {
624 auto I = AddressToLocStackMap.emplace(args&: Address, args: SampleContextFrameVector());
625 if (I.second) {
626 I.first->second = getFrameLocationStack(Address, UseProbeDiscriminator);
627 }
628 return I.first->second;
629 }
630
631 std::optional<SampleContextFrame> getInlineLeafFrameLoc(uint64_t Address) {
632 const auto &Stack = getCachedFrameLocationStack(Address);
633 if (Stack.empty())
634 return {};
635 return Stack.back();
636 }
637
638 void flushSymbolizer() { Symbolizer.reset(); }
639
640 MissingFrameInferrer *getMissingContextInferrer() {
641 return MissingContextInferrer.get();
642 }
643
644 // Compare two addresses' inline context
645 bool inlineContextEqual(uint64_t Add1, uint64_t Add2);
646
647 // Get the full context of the current stack with inline context filled in.
648 // It will search the disassembling info stored in AddressToLocStackMap. This
649 // is used as the key of function sample map
650 SampleContextFrameVector
651 getExpandedContext(const SmallVectorImpl<uint64_t> &Stack,
652 bool &WasLeafInlined);
653 // Go through instructions among the given range and record its size for the
654 // inline context.
655 void computeInlinedContextSizeForRange(uint64_t StartAddress,
656 uint64_t EndAddress);
657
658 void computeInlinedContextSizeForFunc(const BinaryFunction *Func);
659
660 void loadSymbolsFromPseudoProbe();
661
662 StringRef findPseudoProbeName(const BinaryFunction *Func);
663
664 const MCDecodedPseudoProbe *getCallProbeForAddr(uint64_t Address) const {
665 return ProbeDecoder.getCallProbeForAddr(Address);
666 }
667
668 void getInlineContextForProbe(const MCDecodedPseudoProbe *Probe,
669 SampleContextFrameVector &InlineContextStack,
670 bool IncludeLeaf = false) const {
671 SmallVector<MCPseudoProbeFrameLocation, 16> ProbeInlineContext;
672 ProbeDecoder.getInlineContextForProbe(Probe, InlineContextStack&: ProbeInlineContext,
673 IncludeLeaf);
674 for (uint32_t I = 0; I < ProbeInlineContext.size(); I++) {
675 auto &Callsite = ProbeInlineContext[I];
676 // Clear the current context for an unknown probe.
677 if (Callsite.second == 0 && I != ProbeInlineContext.size() - 1) {
678 InlineContextStack.clear();
679 continue;
680 }
681 InlineContextStack.emplace_back(Args: FunctionId(Callsite.first),
682 Args: LineLocation(Callsite.second, 0));
683 }
684 }
685 const AddressProbesMap &getAddress2ProbesMap() const {
686 return ProbeDecoder.getAddress2ProbesMap();
687 }
688 const MCPseudoProbeFuncDesc *getFuncDescForGUID(uint64_t GUID) {
689 return ProbeDecoder.getFuncDescForGUID(GUID);
690 }
691
692 const MCPseudoProbeFuncDesc *
693 getInlinerDescForProbe(const MCDecodedPseudoProbe *Probe) {
694 return ProbeDecoder.getInlinerDescForProbe(Probe);
695 }
696
697 bool isNonOverlappingAddressInterval(std::pair<uint64_t, uint64_t> LHS,
698 std::pair<uint64_t, uint64_t> RHS) {
699 if (LHS.second <= RHS.first || RHS.second <= LHS.first)
700 return true;
701 return false;
702 }
703
704 Error addMMapNonTextEvent(MMapEvent Event) {
705 // Given the mmap events of the profiled binary, the virtual address
706 // intervals of mmaps most often doesn't overlap with each other. The
707 // implementation validates so, and runtime data address is mapped to
708 // a mmap event using look-up. With this implementation, data addresses
709 // from dynamic shared libraries (not the profiled binary) are not mapped or
710 // symbolized. To map runtime address to binary address in case of
711 // overlapping mmap events, the implementation could store all the mmap
712 // events in a vector and in the order they are added and reverse iterate
713 // the vector to find the mmap events. We opt'ed for the non-overlapping
714 // implementation for simplicity.
715 for (const auto &ExistingMMap : NonTextMMapEvents) {
716 if (isNonOverlappingAddressInterval(
717 LHS: {ExistingMMap.second.Address,
718 ExistingMMap.second.Address + ExistingMMap.second.Size},
719 RHS: {Event.Address, Event.Address + Event.Size})) {
720 continue;
721 }
722 return createStringError(
723 EC: inconvertibleErrorCode(),
724 Fmt: "Non-text mmap event overlaps with existing event at address: %lx",
725 Vals: Event.Address);
726 }
727 NonTextMMapEvents[Event.Address] = Event;
728 return Error::success();
729 }
730
731 // Given a non-text runtime address, canonicalize it to the virtual address in
732 // the binary.
733 // TODO: Consider unifying the canonicalization of text and non-text addresses
734 // in the ProfiledBinary class.
735 uint64_t CanonicalizeNonTextAddress(uint64_t Address);
736
737 bool getTrackFuncContextSize() { return TrackFuncContextSize; }
738
739 bool getIsLoadedByMMap() { return IsLoadedByMMap; }
740
741 void setIsLoadedByMMap(bool Value) { IsLoadedByMMap = Value; }
742
743 bool getMissingMMapWarned() { return MissingMMapWarned; }
744
745 void setMissingMMapWarned(bool Value) { MissingMMapWarned = Value; }
746};
747
748} // end namespace sampleprof
749} // end namespace llvm
750
751#endif
752