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