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