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