1 //===-- ProfiledBinary.cpp - 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 #include "ProfiledBinary.h" 10 #include "ErrorHandling.h" 11 #include "ProfileGenerator.h" 12 #include "llvm/ADT/Triple.h" 13 #include "llvm/Demangle/Demangle.h" 14 #include "llvm/IR/DebugInfoMetadata.h" 15 #include "llvm/Support/CommandLine.h" 16 #include "llvm/Support/Format.h" 17 #include "llvm/Support/TargetRegistry.h" 18 #include "llvm/Support/TargetSelect.h" 19 20 #define DEBUG_TYPE "load-binary" 21 22 using namespace llvm; 23 using namespace sampleprof; 24 25 cl::opt<bool> ShowDisassemblyOnly("show-disassembly-only", cl::ReallyHidden, 26 cl::init(false), cl::ZeroOrMore, 27 cl::desc("Print disassembled code.")); 28 29 cl::opt<bool> ShowSourceLocations("show-source-locations", cl::ReallyHidden, 30 cl::init(false), cl::ZeroOrMore, 31 cl::desc("Print source locations.")); 32 33 cl::opt<bool> ShowCanonicalFnName("show-canonical-fname", cl::ReallyHidden, 34 cl::init(false), cl::ZeroOrMore, 35 cl::desc("Print canonical function name.")); 36 37 cl::opt<bool> ShowPseudoProbe( 38 "show-pseudo-probe", cl::ReallyHidden, cl::init(false), cl::ZeroOrMore, 39 cl::desc("Print pseudo probe section and disassembled info.")); 40 41 namespace llvm { 42 namespace sampleprof { 43 44 static const Target *getTarget(const ObjectFile *Obj) { 45 Triple TheTriple = Obj->makeTriple(); 46 std::string Error; 47 std::string ArchName; 48 const Target *TheTarget = 49 TargetRegistry::lookupTarget(ArchName, TheTriple, Error); 50 if (!TheTarget) 51 exitWithError(Error, Obj->getFileName()); 52 return TheTarget; 53 } 54 55 void BinarySizeContextTracker::addInstructionForContext( 56 const SampleContextFrameVector &Context, uint32_t InstrSize) { 57 ContextTrieNode *CurNode = &RootContext; 58 bool IsLeaf = true; 59 for (const auto &Callsite : reverse(Context)) { 60 StringRef CallerName = Callsite.CallerName; 61 LineLocation CallsiteLoc = IsLeaf ? LineLocation(0, 0) : Callsite.Callsite; 62 CurNode = CurNode->getOrCreateChildContext(CallsiteLoc, CallerName); 63 IsLeaf = false; 64 } 65 66 CurNode->addFunctionSize(InstrSize); 67 } 68 69 uint32_t 70 BinarySizeContextTracker::getFuncSizeForContext(const SampleContext &Context) { 71 ContextTrieNode *CurrNode = &RootContext; 72 ContextTrieNode *PrevNode = nullptr; 73 SampleContextFrames Frames = Context.getContextFrames(); 74 int32_t I = Frames.size() - 1; 75 Optional<uint32_t> Size; 76 77 // Start from top-level context-less function, traverse down the reverse 78 // context trie to find the best/longest match for given context, then 79 // retrieve the size. 80 81 while (CurrNode && I >= 0) { 82 // Process from leaf function to callers (added to context). 83 const auto &ChildFrame = Frames[I--]; 84 PrevNode = CurrNode; 85 CurrNode = 86 CurrNode->getChildContext(ChildFrame.Callsite, ChildFrame.CallerName); 87 if (CurrNode && CurrNode->getFunctionSize().hasValue()) 88 Size = CurrNode->getFunctionSize().getValue(); 89 } 90 91 // If we traversed all nodes along the path of the context and haven't 92 // found a size yet, pivot to look for size from sibling nodes, i.e size 93 // of inlinee under different context. 94 if (!Size.hasValue()) { 95 if (!CurrNode) 96 CurrNode = PrevNode; 97 while (!Size.hasValue() && CurrNode && 98 !CurrNode->getAllChildContext().empty()) { 99 CurrNode = &CurrNode->getAllChildContext().begin()->second; 100 if (CurrNode->getFunctionSize().hasValue()) 101 Size = CurrNode->getFunctionSize().getValue(); 102 } 103 } 104 105 assert(Size.hasValue() && "We should at least find one context size."); 106 return Size.getValue(); 107 } 108 109 void BinarySizeContextTracker::trackInlineesOptimizedAway( 110 MCPseudoProbeDecoder &ProbeDecoder) { 111 ProbeFrameStack ProbeContext; 112 for (const auto &Child : ProbeDecoder.getDummyInlineRoot().getChildren()) 113 trackInlineesOptimizedAway(ProbeDecoder, *Child.second.get(), ProbeContext); 114 } 115 116 void BinarySizeContextTracker::trackInlineesOptimizedAway( 117 MCPseudoProbeDecoder &ProbeDecoder, 118 MCDecodedPseudoProbeInlineTree &ProbeNode, ProbeFrameStack &ProbeContext) { 119 StringRef FuncName = 120 ProbeDecoder.getFuncDescForGUID(ProbeNode.Guid)->FuncName; 121 ProbeContext.emplace_back(FuncName, 0); 122 123 // This ProbeContext has a probe, so it has code before inlining and 124 // optimization. Make sure we mark its size as known. 125 if (!ProbeNode.getProbes().empty()) { 126 ContextTrieNode *SizeContext = &RootContext; 127 for (auto &ProbeFrame : reverse(ProbeContext)) { 128 StringRef CallerName = ProbeFrame.first; 129 LineLocation CallsiteLoc(ProbeFrame.second, 0); 130 SizeContext = 131 SizeContext->getOrCreateChildContext(CallsiteLoc, CallerName); 132 } 133 // Add 0 size to make known. 134 SizeContext->addFunctionSize(0); 135 } 136 137 // DFS down the probe inline tree 138 for (const auto &ChildNode : ProbeNode.getChildren()) { 139 InlineSite Location = ChildNode.first; 140 ProbeContext.back().second = std::get<1>(Location); 141 trackInlineesOptimizedAway(ProbeDecoder, *ChildNode.second.get(), ProbeContext); 142 } 143 144 ProbeContext.pop_back(); 145 } 146 147 void ProfiledBinary::load() { 148 // Attempt to open the binary. 149 OwningBinary<Binary> OBinary = unwrapOrError(createBinary(Path), Path); 150 Binary &Binary = *OBinary.getBinary(); 151 152 auto *Obj = dyn_cast<ELFObjectFileBase>(&Binary); 153 if (!Obj) 154 exitWithError("not a valid Elf image", Path); 155 156 TheTriple = Obj->makeTriple(); 157 // Current only support X86 158 if (!TheTriple.isX86()) 159 exitWithError("unsupported target", TheTriple.getTriple()); 160 LLVM_DEBUG(dbgs() << "Loading " << Path << "\n"); 161 162 // Find the preferred load address for text sections. 163 setPreferredTextSegmentAddresses(Obj); 164 165 // Decode pseudo probe related section 166 decodePseudoProbe(Obj); 167 168 // Disassemble the text sections. 169 disassemble(Obj); 170 171 // Track size for optimized inlinees when probe is available 172 if (UsePseudoProbes && TrackFuncContextSize) 173 FuncSizeTracker.trackInlineesOptimizedAway(ProbeDecoder); 174 175 // Use function start and return address to infer prolog and epilog 176 ProEpilogTracker.inferPrologOffsets(FuncStartAddrMap); 177 ProEpilogTracker.inferEpilogOffsets(RetAddrs); 178 179 // TODO: decode other sections. 180 } 181 182 bool ProfiledBinary::inlineContextEqual(uint64_t Address1, 183 uint64_t Address2) const { 184 uint64_t Offset1 = virtualAddrToOffset(Address1); 185 uint64_t Offset2 = virtualAddrToOffset(Address2); 186 const SampleContextFrameVector &Context1 = getFrameLocationStack(Offset1); 187 const SampleContextFrameVector &Context2 = getFrameLocationStack(Offset2); 188 if (Context1.size() != Context2.size()) 189 return false; 190 if (Context1.empty()) 191 return false; 192 // The leaf frame contains location within the leaf, and it 193 // needs to be remove that as it's not part of the calling context 194 return std::equal(Context1.begin(), Context1.begin() + Context1.size() - 1, 195 Context2.begin(), Context2.begin() + Context2.size() - 1); 196 } 197 198 SampleContextFrameVector 199 ProfiledBinary::getExpandedContext(const SmallVectorImpl<uint64_t> &Stack, 200 bool &WasLeafInlined) const { 201 SampleContextFrameVector ContextVec; 202 // Process from frame root to leaf 203 for (auto Address : Stack) { 204 uint64_t Offset = virtualAddrToOffset(Address); 205 const SampleContextFrameVector &ExpandedContext = 206 getFrameLocationStack(Offset); 207 // An instruction without a valid debug line will be ignored by sample 208 // processing 209 if (ExpandedContext.empty()) 210 return SampleContextFrameVector(); 211 // Set WasLeafInlined to the size of inlined frame count for the last 212 // address which is leaf 213 WasLeafInlined = (ExpandedContext.size() > 1); 214 ContextVec.append(ExpandedContext); 215 } 216 217 // Compress the context string except for the leaf frame 218 auto LeafFrame = ContextVec.back(); 219 LeafFrame.Callsite = LineLocation(0, 0); 220 ContextVec.pop_back(); 221 assert(ContextVec.size() && "Context length should be at least 1"); 222 CSProfileGenerator::compressRecursionContext(ContextVec); 223 CSProfileGenerator::trimContext(ContextVec); 224 ContextVec.push_back(LeafFrame); 225 return ContextVec; 226 } 227 228 template <class ELFT> 229 void ProfiledBinary::setPreferredTextSegmentAddresses(const ELFFile<ELFT> &Obj, StringRef FileName) { 230 const auto &PhdrRange = unwrapOrError(Obj.program_headers(), FileName); 231 for (const typename ELFT::Phdr &Phdr : PhdrRange) { 232 if ((Phdr.p_type == ELF::PT_LOAD) && (Phdr.p_flags & ELF::PF_X)) { 233 // Segments will always be loaded at a page boundary. 234 PreferredTextSegmentAddresses.push_back(Phdr.p_vaddr & ~(Phdr.p_align - 1U)); 235 TextSegmentOffsets.push_back(Phdr.p_offset & ~(Phdr.p_align - 1U)); 236 } 237 } 238 239 if (PreferredTextSegmentAddresses.empty()) 240 exitWithError("no executable segment found", FileName); 241 } 242 243 void ProfiledBinary::setPreferredTextSegmentAddresses(const ELFObjectFileBase *Obj) { 244 if (const auto *ELFObj = dyn_cast<ELF32LEObjectFile>(Obj)) 245 setPreferredTextSegmentAddresses(ELFObj->getELFFile(), Obj->getFileName()); 246 else if (const auto *ELFObj = dyn_cast<ELF32BEObjectFile>(Obj)) 247 setPreferredTextSegmentAddresses(ELFObj->getELFFile(), Obj->getFileName()); 248 else if (const auto *ELFObj = dyn_cast<ELF64LEObjectFile>(Obj)) 249 setPreferredTextSegmentAddresses(ELFObj->getELFFile(), Obj->getFileName()); 250 else if (const auto *ELFObj = cast<ELF64BEObjectFile>(Obj)) 251 setPreferredTextSegmentAddresses(ELFObj->getELFFile(), Obj->getFileName()); 252 else 253 llvm_unreachable("invalid ELF object format"); 254 } 255 256 void ProfiledBinary::decodePseudoProbe(const ELFObjectFileBase *Obj) { 257 StringRef FileName = Obj->getFileName(); 258 for (section_iterator SI = Obj->section_begin(), SE = Obj->section_end(); 259 SI != SE; ++SI) { 260 const SectionRef &Section = *SI; 261 StringRef SectionName = unwrapOrError(Section.getName(), FileName); 262 263 if (SectionName == ".pseudo_probe_desc") { 264 StringRef Contents = unwrapOrError(Section.getContents(), FileName); 265 if (!ProbeDecoder.buildGUID2FuncDescMap( 266 reinterpret_cast<const uint8_t *>(Contents.data()), 267 Contents.size())) 268 exitWithError("Pseudo Probe decoder fail in .pseudo_probe_desc section"); 269 } else if (SectionName == ".pseudo_probe") { 270 StringRef Contents = unwrapOrError(Section.getContents(), FileName); 271 if (!ProbeDecoder.buildAddress2ProbeMap( 272 reinterpret_cast<const uint8_t *>(Contents.data()), 273 Contents.size())) 274 exitWithError("Pseudo Probe decoder fail in .pseudo_probe section"); 275 // set UsePseudoProbes flag, used for PerfReader 276 UsePseudoProbes = true; 277 } 278 } 279 280 if (ShowPseudoProbe) 281 ProbeDecoder.printGUID2FuncDescMap(outs()); 282 } 283 284 bool ProfiledBinary::dissassembleSymbol(std::size_t SI, ArrayRef<uint8_t> Bytes, 285 SectionSymbolsTy &Symbols, 286 const SectionRef &Section) { 287 std::size_t SE = Symbols.size(); 288 uint64_t SectionOffset = Section.getAddress() - getPreferredBaseAddress(); 289 uint64_t SectSize = Section.getSize(); 290 uint64_t StartOffset = Symbols[SI].Addr - getPreferredBaseAddress(); 291 uint64_t EndOffset = (SI + 1 < SE) 292 ? Symbols[SI + 1].Addr - getPreferredBaseAddress() 293 : SectionOffset + SectSize; 294 if (StartOffset >= EndOffset) 295 return true; 296 297 StringRef SymbolName = 298 ShowCanonicalFnName 299 ? FunctionSamples::getCanonicalFnName(Symbols[SI].Name) 300 : Symbols[SI].Name; 301 if (ShowDisassemblyOnly) 302 outs() << '<' << SymbolName << ">:\n"; 303 304 auto WarnInvalidInsts = [](uint64_t Start, uint64_t End) { 305 WithColor::warning() << "Invalid instructions at " 306 << format("%8" PRIx64, Start) << " - " 307 << format("%8" PRIx64, End) << "\n"; 308 }; 309 310 uint64_t Offset = StartOffset; 311 // Size of a consecutive invalid instruction range starting from Offset -1 312 // backwards. 313 uint64_t InvalidInstLength = 0; 314 while (Offset < EndOffset) { 315 MCInst Inst; 316 uint64_t Size; 317 // Disassemble an instruction. 318 bool Disassembled = 319 DisAsm->getInstruction(Inst, Size, Bytes.slice(Offset - SectionOffset), 320 Offset + getPreferredBaseAddress(), nulls()); 321 if (Size == 0) 322 Size = 1; 323 324 if (ShowDisassemblyOnly) { 325 if (ShowPseudoProbe) { 326 ProbeDecoder.printProbeForAddress(outs(), 327 Offset + getPreferredBaseAddress()); 328 } 329 outs() << format("%8" PRIx64 ":", Offset + getPreferredBaseAddress()); 330 size_t Start = outs().tell(); 331 if (Disassembled) 332 IPrinter->printInst(&Inst, Offset + Size, "", *STI.get(), outs()); 333 else 334 outs() << "\t<unknown>"; 335 if (ShowSourceLocations) { 336 unsigned Cur = outs().tell() - Start; 337 if (Cur < 40) 338 outs().indent(40 - Cur); 339 InstructionPointer IP(this, Offset); 340 outs() << getReversedLocWithContext( 341 symbolize(IP, ShowCanonicalFnName, ShowPseudoProbe)); 342 } 343 outs() << "\n"; 344 } 345 346 if (Disassembled) { 347 const MCInstrDesc &MCDesc = MII->get(Inst.getOpcode()); 348 // Populate a vector of the symbolized callsite at this location 349 // We don't need symbolized info for probe-based profile, just use an 350 // empty stack as an entry to indicate a valid binary offset 351 SampleContextFrameVector SymbolizedCallStack; 352 if (!UsePseudoProbes || TrackFuncContextSize) { 353 InstructionPointer IP(this, Offset); 354 // TODO: reallocation of Offset2LocStackMap will lead to dangling 355 // strings We need ProfiledBinary to owned these string. 356 Offset2LocStackMap[Offset] = symbolize(IP, true, UsePseudoProbes); 357 SampleContextFrameVector &SymbolizedCallStack = 358 Offset2LocStackMap[Offset]; 359 // Record instruction size for the corresponding context 360 if (TrackFuncContextSize && !SymbolizedCallStack.empty()) 361 FuncSizeTracker.addInstructionForContext(Offset2LocStackMap[Offset], 362 Size); 363 } else { 364 Offset2LocStackMap[Offset] = SampleContextFrameVector(); 365 } 366 367 // Populate address maps. 368 CodeAddrs.push_back(Offset); 369 if (MCDesc.isCall()) 370 CallAddrs.insert(Offset); 371 else if (MCDesc.isReturn()) 372 RetAddrs.insert(Offset); 373 374 if (InvalidInstLength) { 375 WarnInvalidInsts(Offset - InvalidInstLength, Offset - 1); 376 InvalidInstLength = 0; 377 } 378 } else { 379 InvalidInstLength += Size; 380 } 381 382 Offset += Size; 383 } 384 385 if (InvalidInstLength) 386 WarnInvalidInsts(Offset - InvalidInstLength, Offset - 1); 387 388 if (ShowDisassemblyOnly) 389 outs() << "\n"; 390 391 FuncStartAddrMap[StartOffset] = Symbols[SI].Name.str(); 392 return true; 393 } 394 395 void ProfiledBinary::setUpDisassembler(const ELFObjectFileBase *Obj) { 396 const Target *TheTarget = getTarget(Obj); 397 std::string TripleName = TheTriple.getTriple(); 398 StringRef FileName = Obj->getFileName(); 399 400 MRI.reset(TheTarget->createMCRegInfo(TripleName)); 401 if (!MRI) 402 exitWithError("no register info for target " + TripleName, FileName); 403 404 MCTargetOptions MCOptions; 405 AsmInfo.reset(TheTarget->createMCAsmInfo(*MRI, TripleName, MCOptions)); 406 if (!AsmInfo) 407 exitWithError("no assembly info for target " + TripleName, FileName); 408 409 SubtargetFeatures Features = Obj->getFeatures(); 410 STI.reset( 411 TheTarget->createMCSubtargetInfo(TripleName, "", Features.getString())); 412 if (!STI) 413 exitWithError("no subtarget info for target " + TripleName, FileName); 414 415 MII.reset(TheTarget->createMCInstrInfo()); 416 if (!MII) 417 exitWithError("no instruction info for target " + TripleName, FileName); 418 419 MCContext Ctx(Triple(TripleName), AsmInfo.get(), MRI.get(), STI.get()); 420 std::unique_ptr<MCObjectFileInfo> MOFI( 421 TheTarget->createMCObjectFileInfo(Ctx, /*PIC=*/false)); 422 Ctx.setObjectFileInfo(MOFI.get()); 423 DisAsm.reset(TheTarget->createMCDisassembler(*STI, Ctx)); 424 if (!DisAsm) 425 exitWithError("no disassembler for target " + TripleName, FileName); 426 427 MIA.reset(TheTarget->createMCInstrAnalysis(MII.get())); 428 429 int AsmPrinterVariant = AsmInfo->getAssemblerDialect(); 430 IPrinter.reset(TheTarget->createMCInstPrinter( 431 Triple(TripleName), AsmPrinterVariant, *AsmInfo, *MII, *MRI)); 432 IPrinter->setPrintBranchImmAsAddress(true); 433 } 434 435 void ProfiledBinary::disassemble(const ELFObjectFileBase *Obj) { 436 // Set up disassembler and related components. 437 setUpDisassembler(Obj); 438 439 // Create a mapping from virtual address to symbol name. The symbols in text 440 // sections are the candidates to dissassemble. 441 std::map<SectionRef, SectionSymbolsTy> AllSymbols; 442 StringRef FileName = Obj->getFileName(); 443 for (const SymbolRef &Symbol : Obj->symbols()) { 444 const uint64_t Addr = unwrapOrError(Symbol.getAddress(), FileName); 445 const StringRef Name = unwrapOrError(Symbol.getName(), FileName); 446 section_iterator SecI = unwrapOrError(Symbol.getSection(), FileName); 447 if (SecI != Obj->section_end()) 448 AllSymbols[*SecI].push_back(SymbolInfoTy(Addr, Name, ELF::STT_NOTYPE)); 449 } 450 451 // Sort all the symbols. Use a stable sort to stabilize the output. 452 for (std::pair<const SectionRef, SectionSymbolsTy> &SecSyms : AllSymbols) 453 stable_sort(SecSyms.second); 454 455 if (ShowDisassemblyOnly) 456 outs() << "\nDisassembly of " << FileName << ":\n"; 457 458 // Dissassemble a text section. 459 for (section_iterator SI = Obj->section_begin(), SE = Obj->section_end(); 460 SI != SE; ++SI) { 461 const SectionRef &Section = *SI; 462 if (!Section.isText()) 463 continue; 464 465 uint64_t ImageLoadAddr = getPreferredBaseAddress(); 466 uint64_t SectionOffset = Section.getAddress() - ImageLoadAddr; 467 uint64_t SectSize = Section.getSize(); 468 if (!SectSize) 469 continue; 470 471 // Register the text section. 472 TextSections.insert({SectionOffset, SectSize}); 473 474 if (ShowDisassemblyOnly) { 475 StringRef SectionName = unwrapOrError(Section.getName(), FileName); 476 outs() << "\nDisassembly of section " << SectionName; 477 outs() << " [" << format("0x%" PRIx64, Section.getAddress()) << ", " 478 << format("0x%" PRIx64, Section.getAddress() + SectSize) 479 << "]:\n\n"; 480 } 481 482 // Get the section data. 483 ArrayRef<uint8_t> Bytes = 484 arrayRefFromStringRef(unwrapOrError(Section.getContents(), FileName)); 485 486 // Get the list of all the symbols in this section. 487 SectionSymbolsTy &Symbols = AllSymbols[Section]; 488 489 // Disassemble symbol by symbol. 490 for (std::size_t SI = 0, SE = Symbols.size(); SI != SE; ++SI) { 491 if (!dissassembleSymbol(SI, Bytes, Symbols, Section)) 492 exitWithError("disassembling error", FileName); 493 } 494 } 495 } 496 497 void ProfiledBinary::setupSymbolizer() { 498 symbolize::LLVMSymbolizer::Options SymbolizerOpts; 499 SymbolizerOpts.PrintFunctions = 500 DILineInfoSpecifier::FunctionNameKind::LinkageName; 501 SymbolizerOpts.Demangle = false; 502 SymbolizerOpts.DefaultArch = TheTriple.getArchName().str(); 503 SymbolizerOpts.UseSymbolTable = false; 504 SymbolizerOpts.RelativeAddresses = false; 505 Symbolizer = std::make_unique<symbolize::LLVMSymbolizer>(SymbolizerOpts); 506 } 507 508 SampleContextFrameVector ProfiledBinary::symbolize(const InstructionPointer &IP, 509 bool UseCanonicalFnName, 510 bool UseProbeDiscriminator) { 511 assert(this == IP.Binary && 512 "Binary should only symbolize its own instruction"); 513 auto Addr = object::SectionedAddress{IP.Offset + getPreferredBaseAddress(), 514 object::SectionedAddress::UndefSection}; 515 DIInliningInfo InlineStack = 516 unwrapOrError(Symbolizer->symbolizeInlinedCode(Path, Addr), getName()); 517 518 SampleContextFrameVector CallStack; 519 for (int32_t I = InlineStack.getNumberOfFrames() - 1; I >= 0; I--) { 520 const auto &CallerFrame = InlineStack.getFrame(I); 521 if (CallerFrame.FunctionName == "<invalid>") 522 break; 523 524 StringRef FunctionName(CallerFrame.FunctionName); 525 if (UseCanonicalFnName) 526 FunctionName = FunctionSamples::getCanonicalFnName(FunctionName); 527 528 uint32_t Discriminator = CallerFrame.Discriminator; 529 uint32_t LineOffset = CallerFrame.Line - CallerFrame.StartLine; 530 if (UseProbeDiscriminator) { 531 LineOffset = 532 PseudoProbeDwarfDiscriminator::extractProbeIndex(Discriminator); 533 Discriminator = 0; 534 } else { 535 Discriminator = DILocation::getBaseDiscriminatorFromDiscriminator( 536 CallerFrame.Discriminator, 537 /* IsFSDiscriminator */ false); 538 } 539 540 LineLocation Line(LineOffset, Discriminator); 541 auto It = NameStrings.insert(FunctionName.str()); 542 CallStack.emplace_back(*It.first, Line); 543 } 544 545 return CallStack; 546 } 547 548 InstructionPointer::InstructionPointer(const ProfiledBinary *Binary, 549 uint64_t Address, bool RoundToNext) 550 : Binary(Binary), Address(Address) { 551 Index = Binary->getIndexForAddr(Address); 552 if (RoundToNext) { 553 // we might get address which is not the code 554 // it should round to the next valid address 555 this->Address = Binary->getAddressforIndex(Index); 556 } 557 } 558 559 void InstructionPointer::advance() { 560 Index++; 561 Address = Binary->getAddressforIndex(Index); 562 } 563 564 void InstructionPointer::backward() { 565 Index--; 566 Address = Binary->getAddressforIndex(Index); 567 } 568 569 void InstructionPointer::update(uint64_t Addr) { 570 Address = Addr; 571 Index = Binary->getIndexForAddr(Address); 572 } 573 574 } // end namespace sampleprof 575 } // end namespace llvm 576