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