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