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