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::init(false), 26 cl::ZeroOrMore, 27 cl::desc("Print disassembled code.")); 28 29 cl::opt<bool> ShowSourceLocations("show-source-locations", cl::init(false), 30 cl::ZeroOrMore, 31 cl::desc("Print source locations.")); 32 33 static cl::opt<bool> 34 ShowCanonicalFnName("show-canonical-fname", cl::init(false), cl::ZeroOrMore, 35 cl::desc("Print canonical function name.")); 36 37 static cl::opt<bool> ShowPseudoProbe( 38 "show-pseudo-probe", cl::init(false), cl::ZeroOrMore, 39 cl::desc("Print pseudo probe section and disassembled info.")); 40 41 static cl::opt<bool> UseDwarfCorrelation( 42 "use-dwarf-correlation", cl::init(false), cl::ZeroOrMore, 43 cl::desc("Use dwarf for profile correlation even when binary contains " 44 "pseudo probe.")); 45 46 static cl::list<std::string> DisassembleFunctions( 47 "disassemble-functions", cl::CommaSeparated, 48 cl::desc("List of functions to print disassembly for. Accept demangled " 49 "names only. Only work with show-disassembly-only")); 50 51 extern cl::opt<bool> ShowDetailedWarning; 52 53 namespace llvm { 54 namespace sampleprof { 55 56 static const Target *getTarget(const ObjectFile *Obj) { 57 Triple TheTriple = Obj->makeTriple(); 58 std::string Error; 59 std::string ArchName; 60 const Target *TheTarget = 61 TargetRegistry::lookupTarget(ArchName, TheTriple, Error); 62 if (!TheTarget) 63 exitWithError(Error, Obj->getFileName()); 64 return TheTarget; 65 } 66 67 void BinarySizeContextTracker::addInstructionForContext( 68 const SampleContextFrameVector &Context, uint32_t InstrSize) { 69 ContextTrieNode *CurNode = &RootContext; 70 bool IsLeaf = true; 71 for (const auto &Callsite : reverse(Context)) { 72 StringRef CallerName = Callsite.FuncName; 73 LineLocation CallsiteLoc = IsLeaf ? LineLocation(0, 0) : Callsite.Location; 74 CurNode = CurNode->getOrCreateChildContext(CallsiteLoc, CallerName); 75 IsLeaf = false; 76 } 77 78 CurNode->addFunctionSize(InstrSize); 79 } 80 81 uint32_t 82 BinarySizeContextTracker::getFuncSizeForContext(const SampleContext &Context) { 83 ContextTrieNode *CurrNode = &RootContext; 84 ContextTrieNode *PrevNode = nullptr; 85 SampleContextFrames Frames = Context.getContextFrames(); 86 int32_t I = Frames.size() - 1; 87 Optional<uint32_t> Size; 88 89 // Start from top-level context-less function, traverse down the reverse 90 // context trie to find the best/longest match for given context, then 91 // retrieve the size. 92 93 while (CurrNode && I >= 0) { 94 // Process from leaf function to callers (added to context). 95 const auto &ChildFrame = Frames[I--]; 96 PrevNode = CurrNode; 97 CurrNode = 98 CurrNode->getChildContext(ChildFrame.Location, ChildFrame.FuncName); 99 if (CurrNode && CurrNode->getFunctionSize().hasValue()) 100 Size = CurrNode->getFunctionSize().getValue(); 101 } 102 103 // If we traversed all nodes along the path of the context and haven't 104 // found a size yet, pivot to look for size from sibling nodes, i.e size 105 // of inlinee under different context. 106 if (!Size.hasValue()) { 107 if (!CurrNode) 108 CurrNode = PrevNode; 109 while (!Size.hasValue() && CurrNode && 110 !CurrNode->getAllChildContext().empty()) { 111 CurrNode = &CurrNode->getAllChildContext().begin()->second; 112 if (CurrNode->getFunctionSize().hasValue()) 113 Size = CurrNode->getFunctionSize().getValue(); 114 } 115 } 116 117 assert(Size.hasValue() && "We should at least find one context size."); 118 return Size.getValue(); 119 } 120 121 void BinarySizeContextTracker::trackInlineesOptimizedAway( 122 MCPseudoProbeDecoder &ProbeDecoder) { 123 ProbeFrameStack ProbeContext; 124 for (const auto &Child : ProbeDecoder.getDummyInlineRoot().getChildren()) 125 trackInlineesOptimizedAway(ProbeDecoder, *Child.second.get(), ProbeContext); 126 } 127 128 void BinarySizeContextTracker::trackInlineesOptimizedAway( 129 MCPseudoProbeDecoder &ProbeDecoder, 130 MCDecodedPseudoProbeInlineTree &ProbeNode, ProbeFrameStack &ProbeContext) { 131 StringRef FuncName = 132 ProbeDecoder.getFuncDescForGUID(ProbeNode.Guid)->FuncName; 133 ProbeContext.emplace_back(FuncName, 0); 134 135 // This ProbeContext has a probe, so it has code before inlining and 136 // optimization. Make sure we mark its size as known. 137 if (!ProbeNode.getProbes().empty()) { 138 ContextTrieNode *SizeContext = &RootContext; 139 for (auto &ProbeFrame : reverse(ProbeContext)) { 140 StringRef CallerName = ProbeFrame.first; 141 LineLocation CallsiteLoc(ProbeFrame.second, 0); 142 SizeContext = 143 SizeContext->getOrCreateChildContext(CallsiteLoc, CallerName); 144 } 145 // Add 0 size to make known. 146 SizeContext->addFunctionSize(0); 147 } 148 149 // DFS down the probe inline tree 150 for (const auto &ChildNode : ProbeNode.getChildren()) { 151 InlineSite Location = ChildNode.first; 152 ProbeContext.back().second = std::get<1>(Location); 153 trackInlineesOptimizedAway(ProbeDecoder, *ChildNode.second.get(), ProbeContext); 154 } 155 156 ProbeContext.pop_back(); 157 } 158 159 void ProfiledBinary::warnNoFuncEntry() { 160 uint64_t NoFuncEntryNum = 0; 161 for (auto &F : BinaryFunctions) { 162 if (F.second.Ranges.empty()) 163 continue; 164 bool hasFuncEntry = false; 165 for (auto &R : F.second.Ranges) { 166 if (FuncRange *FR = findFuncRangeForStartOffset(R.first)) { 167 if (FR->IsFuncEntry) { 168 hasFuncEntry = true; 169 break; 170 } 171 } 172 } 173 174 if (!hasFuncEntry) { 175 NoFuncEntryNum++; 176 if (ShowDetailedWarning) 177 WithColor::warning() 178 << "Failed to determine function entry for " << F.first 179 << " due to inconsistent name from symbol table and dwarf info.\n"; 180 } 181 } 182 emitWarningSummary(NoFuncEntryNum, BinaryFunctions.size(), 183 "of functions failed to determine function entry due to " 184 "inconsistent name from symbol table and dwarf info."); 185 } 186 187 void ProfiledBinary::load() { 188 // Attempt to open the binary. 189 OwningBinary<Binary> OBinary = unwrapOrError(createBinary(Path), Path); 190 Binary &ExeBinary = *OBinary.getBinary(); 191 192 auto *Obj = dyn_cast<ELFObjectFileBase>(&ExeBinary); 193 if (!Obj) 194 exitWithError("not a valid Elf image", Path); 195 196 TheTriple = Obj->makeTriple(); 197 // Current only support X86 198 if (!TheTriple.isX86()) 199 exitWithError("unsupported target", TheTriple.getTriple()); 200 LLVM_DEBUG(dbgs() << "Loading " << Path << "\n"); 201 202 // Find the preferred load address for text sections. 203 setPreferredTextSegmentAddresses(Obj); 204 205 // Decode pseudo probe related section 206 decodePseudoProbe(Obj); 207 208 // Load debug info of subprograms from DWARF section. 209 // If path of debug info binary is specified, use the debug info from it, 210 // otherwise use the debug info from the executable binary. 211 if (!DebugBinaryPath.empty()) { 212 OwningBinary<Binary> DebugPath = 213 unwrapOrError(createBinary(DebugBinaryPath), DebugBinaryPath); 214 loadSymbolsFromDWARF(*cast<ObjectFile>(DebugPath.getBinary())); 215 } else { 216 loadSymbolsFromDWARF(*cast<ObjectFile>(&ExeBinary)); 217 } 218 219 // Disassemble the text sections. 220 disassemble(Obj); 221 222 // Use function start and return address to infer prolog and epilog 223 ProEpilogTracker.inferPrologOffsets(StartOffset2FuncRangeMap); 224 ProEpilogTracker.inferEpilogOffsets(RetOffsets); 225 226 warnNoFuncEntry(); 227 228 // TODO: decode other sections. 229 } 230 231 bool ProfiledBinary::inlineContextEqual(uint64_t Address1, uint64_t Address2) { 232 uint64_t Offset1 = virtualAddrToOffset(Address1); 233 uint64_t Offset2 = virtualAddrToOffset(Address2); 234 const SampleContextFrameVector &Context1 = getFrameLocationStack(Offset1); 235 const SampleContextFrameVector &Context2 = getFrameLocationStack(Offset2); 236 if (Context1.size() != Context2.size()) 237 return false; 238 if (Context1.empty()) 239 return false; 240 // The leaf frame contains location within the leaf, and it 241 // needs to be remove that as it's not part of the calling context 242 return std::equal(Context1.begin(), Context1.begin() + Context1.size() - 1, 243 Context2.begin(), Context2.begin() + Context2.size() - 1); 244 } 245 246 SampleContextFrameVector 247 ProfiledBinary::getExpandedContext(const SmallVectorImpl<uint64_t> &Stack, 248 bool &WasLeafInlined) { 249 SampleContextFrameVector ContextVec; 250 // Process from frame root to leaf 251 for (auto Address : Stack) { 252 uint64_t Offset = virtualAddrToOffset(Address); 253 const SampleContextFrameVector &ExpandedContext = 254 getFrameLocationStack(Offset); 255 // An instruction without a valid debug line will be ignored by sample 256 // processing 257 if (ExpandedContext.empty()) 258 return SampleContextFrameVector(); 259 // Set WasLeafInlined to the size of inlined frame count for the last 260 // address which is leaf 261 WasLeafInlined = (ExpandedContext.size() > 1); 262 ContextVec.append(ExpandedContext); 263 } 264 265 // Replace with decoded base discriminator 266 for (auto &Frame : ContextVec) { 267 Frame.Location.Discriminator = ProfileGeneratorBase::getBaseDiscriminator( 268 Frame.Location.Discriminator, UseFSDiscriminator); 269 } 270 271 assert(ContextVec.size() && "Context length should be at least 1"); 272 273 // Compress the context string except for the leaf frame 274 auto LeafFrame = ContextVec.back(); 275 LeafFrame.Location = LineLocation(0, 0); 276 ContextVec.pop_back(); 277 CSProfileGenerator::compressRecursionContext(ContextVec); 278 CSProfileGenerator::trimContext(ContextVec); 279 ContextVec.push_back(LeafFrame); 280 return ContextVec; 281 } 282 283 template <class ELFT> 284 void ProfiledBinary::setPreferredTextSegmentAddresses(const ELFFile<ELFT> &Obj, StringRef FileName) { 285 const auto &PhdrRange = unwrapOrError(Obj.program_headers(), FileName); 286 // FIXME: This should be the page size of the system running profiling. 287 // However such info isn't available at post-processing time, assuming 288 // 4K page now. Note that we don't use EXEC_PAGESIZE from <linux/param.h> 289 // because we may build the tools on non-linux. 290 uint32_t PageSize = 0x1000; 291 for (const typename ELFT::Phdr &Phdr : PhdrRange) { 292 if (Phdr.p_type == ELF::PT_LOAD) { 293 if (!FirstLoadableAddress) 294 FirstLoadableAddress = Phdr.p_vaddr & ~(PageSize - 1U); 295 if (Phdr.p_flags & ELF::PF_X) { 296 // Segments will always be loaded at a page boundary. 297 PreferredTextSegmentAddresses.push_back(Phdr.p_vaddr & 298 ~(PageSize - 1U)); 299 TextSegmentOffsets.push_back(Phdr.p_offset & ~(PageSize - 1U)); 300 } 301 } 302 } 303 304 if (PreferredTextSegmentAddresses.empty()) 305 exitWithError("no executable segment found", FileName); 306 } 307 308 void ProfiledBinary::setPreferredTextSegmentAddresses(const ELFObjectFileBase *Obj) { 309 if (const auto *ELFObj = dyn_cast<ELF32LEObjectFile>(Obj)) 310 setPreferredTextSegmentAddresses(ELFObj->getELFFile(), Obj->getFileName()); 311 else if (const auto *ELFObj = dyn_cast<ELF32BEObjectFile>(Obj)) 312 setPreferredTextSegmentAddresses(ELFObj->getELFFile(), Obj->getFileName()); 313 else if (const auto *ELFObj = dyn_cast<ELF64LEObjectFile>(Obj)) 314 setPreferredTextSegmentAddresses(ELFObj->getELFFile(), Obj->getFileName()); 315 else if (const auto *ELFObj = cast<ELF64BEObjectFile>(Obj)) 316 setPreferredTextSegmentAddresses(ELFObj->getELFFile(), Obj->getFileName()); 317 else 318 llvm_unreachable("invalid ELF object format"); 319 } 320 321 void ProfiledBinary::decodePseudoProbe(const ELFObjectFileBase *Obj) { 322 if (UseDwarfCorrelation) 323 return; 324 325 StringRef FileName = Obj->getFileName(); 326 for (section_iterator SI = Obj->section_begin(), SE = Obj->section_end(); 327 SI != SE; ++SI) { 328 const SectionRef &Section = *SI; 329 StringRef SectionName = unwrapOrError(Section.getName(), FileName); 330 331 if (SectionName == ".pseudo_probe_desc") { 332 StringRef Contents = unwrapOrError(Section.getContents(), FileName); 333 if (!ProbeDecoder.buildGUID2FuncDescMap( 334 reinterpret_cast<const uint8_t *>(Contents.data()), 335 Contents.size())) 336 exitWithError("Pseudo Probe decoder fail in .pseudo_probe_desc section"); 337 } else if (SectionName == ".pseudo_probe") { 338 StringRef Contents = unwrapOrError(Section.getContents(), FileName); 339 if (!ProbeDecoder.buildAddress2ProbeMap( 340 reinterpret_cast<const uint8_t *>(Contents.data()), 341 Contents.size())) 342 exitWithError("Pseudo Probe decoder fail in .pseudo_probe section"); 343 // set UsePseudoProbes flag, used for PerfReader 344 UsePseudoProbes = true; 345 } 346 } 347 348 // Build TopLevelProbeFrameMap to track size for optimized inlinees when probe 349 // is available 350 if (UsePseudoProbes && TrackFuncContextSize) { 351 for (const auto &Child : ProbeDecoder.getDummyInlineRoot().getChildren()) { 352 auto *Frame = Child.second.get(); 353 StringRef FuncName = 354 ProbeDecoder.getFuncDescForGUID(Frame->Guid)->FuncName; 355 TopLevelProbeFrameMap[FuncName] = Frame; 356 } 357 } 358 359 if (ShowPseudoProbe) 360 ProbeDecoder.printGUID2FuncDescMap(outs()); 361 } 362 363 void ProfiledBinary::setIsFuncEntry(uint64_t Offset, StringRef RangeSymName) { 364 // Note that the start offset of each ELF section can be a non-function 365 // symbol, we need to binary search for the start of a real function range. 366 auto *FuncRange = findFuncRangeForOffset(Offset); 367 // Skip external function symbol. 368 if (!FuncRange) 369 return; 370 371 // Set IsFuncEntry to ture if there is only one range in the function or the 372 // RangeSymName from ELF is equal to its DWARF-based function name. 373 if (FuncRange->Func->Ranges.size() == 1 || 374 (!FuncRange->IsFuncEntry && FuncRange->getFuncName() == RangeSymName)) 375 FuncRange->IsFuncEntry = true; 376 } 377 378 bool ProfiledBinary::dissassembleSymbol(std::size_t SI, ArrayRef<uint8_t> Bytes, 379 SectionSymbolsTy &Symbols, 380 const SectionRef &Section) { 381 std::size_t SE = Symbols.size(); 382 uint64_t SectionOffset = Section.getAddress() - getPreferredBaseAddress(); 383 uint64_t SectSize = Section.getSize(); 384 uint64_t StartOffset = Symbols[SI].Addr - getPreferredBaseAddress(); 385 uint64_t NextStartOffset = 386 (SI + 1 < SE) ? Symbols[SI + 1].Addr - getPreferredBaseAddress() 387 : SectionOffset + SectSize; 388 setIsFuncEntry(StartOffset, 389 FunctionSamples::getCanonicalFnName(Symbols[SI].Name)); 390 391 StringRef SymbolName = 392 ShowCanonicalFnName 393 ? FunctionSamples::getCanonicalFnName(Symbols[SI].Name) 394 : Symbols[SI].Name; 395 bool ShowDisassembly = 396 ShowDisassemblyOnly && (DisassembleFunctionSet.empty() || 397 DisassembleFunctionSet.count(SymbolName)); 398 if (ShowDisassembly) 399 outs() << '<' << SymbolName << ">:\n"; 400 401 auto WarnInvalidInsts = [](uint64_t Start, uint64_t End) { 402 WithColor::warning() << "Invalid instructions at " 403 << format("%8" PRIx64, Start) << " - " 404 << format("%8" PRIx64, End) << "\n"; 405 }; 406 407 uint64_t Offset = StartOffset; 408 // Size of a consecutive invalid instruction range starting from Offset -1 409 // backwards. 410 uint64_t InvalidInstLength = 0; 411 while (Offset < NextStartOffset) { 412 MCInst Inst; 413 uint64_t Size; 414 // Disassemble an instruction. 415 bool Disassembled = 416 DisAsm->getInstruction(Inst, Size, Bytes.slice(Offset - SectionOffset), 417 Offset + getPreferredBaseAddress(), nulls()); 418 if (Size == 0) 419 Size = 1; 420 421 if (ShowDisassembly) { 422 if (ShowPseudoProbe) { 423 ProbeDecoder.printProbeForAddress(outs(), 424 Offset + getPreferredBaseAddress()); 425 } 426 outs() << format("%8" PRIx64 ":", Offset + getPreferredBaseAddress()); 427 size_t Start = outs().tell(); 428 if (Disassembled) 429 IPrinter->printInst(&Inst, Offset + Size, "", *STI.get(), outs()); 430 else 431 outs() << "\t<unknown>"; 432 if (ShowSourceLocations) { 433 unsigned Cur = outs().tell() - Start; 434 if (Cur < 40) 435 outs().indent(40 - Cur); 436 InstructionPointer IP(this, Offset); 437 outs() << getReversedLocWithContext( 438 symbolize(IP, ShowCanonicalFnName, ShowPseudoProbe)); 439 } 440 outs() << "\n"; 441 } 442 443 if (Disassembled) { 444 const MCInstrDesc &MCDesc = MII->get(Inst.getOpcode()); 445 446 // Record instruction size. 447 Offset2InstSizeMap[Offset] = Size; 448 449 // Populate address maps. 450 CodeAddrOffsets.push_back(Offset); 451 if (MCDesc.isCall()) 452 CallOffsets.insert(Offset); 453 else if (MCDesc.isReturn()) 454 RetOffsets.insert(Offset); 455 else if (MCDesc.isBranch()) 456 BranchOffsets.insert(Offset); 457 458 if (InvalidInstLength) { 459 WarnInvalidInsts(Offset - InvalidInstLength, Offset - 1); 460 InvalidInstLength = 0; 461 } 462 } else { 463 InvalidInstLength += Size; 464 } 465 466 Offset += Size; 467 } 468 469 if (InvalidInstLength) 470 WarnInvalidInsts(Offset - InvalidInstLength, Offset - 1); 471 472 if (ShowDisassembly) 473 outs() << "\n"; 474 475 return true; 476 } 477 478 void ProfiledBinary::setUpDisassembler(const ELFObjectFileBase *Obj) { 479 const Target *TheTarget = getTarget(Obj); 480 std::string TripleName = TheTriple.getTriple(); 481 StringRef FileName = Obj->getFileName(); 482 483 MRI.reset(TheTarget->createMCRegInfo(TripleName)); 484 if (!MRI) 485 exitWithError("no register info for target " + TripleName, FileName); 486 487 MCTargetOptions MCOptions; 488 AsmInfo.reset(TheTarget->createMCAsmInfo(*MRI, TripleName, MCOptions)); 489 if (!AsmInfo) 490 exitWithError("no assembly info for target " + TripleName, FileName); 491 492 SubtargetFeatures Features = Obj->getFeatures(); 493 STI.reset( 494 TheTarget->createMCSubtargetInfo(TripleName, "", Features.getString())); 495 if (!STI) 496 exitWithError("no subtarget info for target " + TripleName, FileName); 497 498 MII.reset(TheTarget->createMCInstrInfo()); 499 if (!MII) 500 exitWithError("no instruction info for target " + TripleName, FileName); 501 502 MCContext Ctx(Triple(TripleName), AsmInfo.get(), MRI.get(), STI.get()); 503 std::unique_ptr<MCObjectFileInfo> MOFI( 504 TheTarget->createMCObjectFileInfo(Ctx, /*PIC=*/false)); 505 Ctx.setObjectFileInfo(MOFI.get()); 506 DisAsm.reset(TheTarget->createMCDisassembler(*STI, Ctx)); 507 if (!DisAsm) 508 exitWithError("no disassembler for target " + TripleName, FileName); 509 510 MIA.reset(TheTarget->createMCInstrAnalysis(MII.get())); 511 512 int AsmPrinterVariant = AsmInfo->getAssemblerDialect(); 513 IPrinter.reset(TheTarget->createMCInstPrinter( 514 Triple(TripleName), AsmPrinterVariant, *AsmInfo, *MII, *MRI)); 515 IPrinter->setPrintBranchImmAsAddress(true); 516 } 517 518 void ProfiledBinary::disassemble(const ELFObjectFileBase *Obj) { 519 // Set up disassembler and related components. 520 setUpDisassembler(Obj); 521 522 // Create a mapping from virtual address to symbol name. The symbols in text 523 // sections are the candidates to dissassemble. 524 std::map<SectionRef, SectionSymbolsTy> AllSymbols; 525 StringRef FileName = Obj->getFileName(); 526 for (const SymbolRef &Symbol : Obj->symbols()) { 527 const uint64_t Addr = unwrapOrError(Symbol.getAddress(), FileName); 528 const StringRef Name = unwrapOrError(Symbol.getName(), FileName); 529 section_iterator SecI = unwrapOrError(Symbol.getSection(), FileName); 530 if (SecI != Obj->section_end()) 531 AllSymbols[*SecI].push_back(SymbolInfoTy(Addr, Name, ELF::STT_NOTYPE)); 532 } 533 534 // Sort all the symbols. Use a stable sort to stabilize the output. 535 for (std::pair<const SectionRef, SectionSymbolsTy> &SecSyms : AllSymbols) 536 stable_sort(SecSyms.second); 537 538 DisassembleFunctionSet.insert(DisassembleFunctions.begin(), 539 DisassembleFunctions.end()); 540 assert((DisassembleFunctionSet.empty() || ShowDisassemblyOnly) && 541 "Functions to disassemble should be only specified together with " 542 "--show-disassembly-only"); 543 544 if (ShowDisassemblyOnly) 545 outs() << "\nDisassembly of " << FileName << ":\n"; 546 547 // Dissassemble a text section. 548 for (section_iterator SI = Obj->section_begin(), SE = Obj->section_end(); 549 SI != SE; ++SI) { 550 const SectionRef &Section = *SI; 551 if (!Section.isText()) 552 continue; 553 554 uint64_t ImageLoadAddr = getPreferredBaseAddress(); 555 uint64_t SectionOffset = Section.getAddress() - ImageLoadAddr; 556 uint64_t SectSize = Section.getSize(); 557 if (!SectSize) 558 continue; 559 560 // Register the text section. 561 TextSections.insert({SectionOffset, SectSize}); 562 563 StringRef SectionName = unwrapOrError(Section.getName(), FileName); 564 565 if (ShowDisassemblyOnly) { 566 outs() << "\nDisassembly of section " << SectionName; 567 outs() << " [" << format("0x%" PRIx64, Section.getAddress()) << ", " 568 << format("0x%" PRIx64, Section.getAddress() + SectSize) 569 << "]:\n\n"; 570 } 571 572 if (SectionName == ".plt") 573 continue; 574 575 // Get the section data. 576 ArrayRef<uint8_t> Bytes = 577 arrayRefFromStringRef(unwrapOrError(Section.getContents(), FileName)); 578 579 // Get the list of all the symbols in this section. 580 SectionSymbolsTy &Symbols = AllSymbols[Section]; 581 582 // Disassemble symbol by symbol. 583 for (std::size_t SI = 0, SE = Symbols.size(); SI != SE; ++SI) { 584 if (!dissassembleSymbol(SI, Bytes, Symbols, Section)) 585 exitWithError("disassembling error", FileName); 586 } 587 } 588 589 // Dissassemble rodata section to check if FS discriminator symbol exists. 590 checkUseFSDiscriminator(Obj, AllSymbols); 591 } 592 593 void ProfiledBinary::checkUseFSDiscriminator( 594 const ELFObjectFileBase *Obj, 595 std::map<SectionRef, SectionSymbolsTy> &AllSymbols) { 596 const char *FSDiscriminatorVar = "__llvm_fs_discriminator__"; 597 for (section_iterator SI = Obj->section_begin(), SE = Obj->section_end(); 598 SI != SE; ++SI) { 599 const SectionRef &Section = *SI; 600 if (!Section.isData() || Section.getSize() == 0) 601 continue; 602 SectionSymbolsTy &Symbols = AllSymbols[Section]; 603 604 for (std::size_t SI = 0, SE = Symbols.size(); SI != SE; ++SI) { 605 if (Symbols[SI].Name == FSDiscriminatorVar) { 606 UseFSDiscriminator = true; 607 return; 608 } 609 } 610 } 611 } 612 613 void ProfiledBinary::loadSymbolsFromDWARF(ObjectFile &Obj) { 614 auto DebugContext = llvm::DWARFContext::create(Obj); 615 if (!DebugContext) 616 exitWithError("Misssing debug info.", Path); 617 618 for (const auto &CompilationUnit : DebugContext->compile_units()) { 619 for (const auto &DieInfo : CompilationUnit->dies()) { 620 llvm::DWARFDie Die(CompilationUnit.get(), &DieInfo); 621 622 if (!Die.isSubprogramDIE()) 623 continue; 624 auto Name = Die.getName(llvm::DINameKind::LinkageName); 625 if (!Name) 626 Name = Die.getName(llvm::DINameKind::ShortName); 627 if (!Name) 628 continue; 629 630 auto RangesOrError = Die.getAddressRanges(); 631 if (!RangesOrError) 632 continue; 633 const DWARFAddressRangesVector &Ranges = RangesOrError.get(); 634 635 if (Ranges.empty()) 636 continue; 637 638 // Different DWARF symbols can have same function name, search or create 639 // BinaryFunction indexed by the name. 640 auto Ret = BinaryFunctions.emplace(Name, BinaryFunction()); 641 auto &Func = Ret.first->second; 642 if (Ret.second) 643 Func.FuncName = Ret.first->first; 644 645 for (const auto &Range : Ranges) { 646 uint64_t FuncStart = Range.LowPC; 647 uint64_t FuncSize = Range.HighPC - FuncStart; 648 649 if (FuncSize == 0 || FuncStart < getPreferredBaseAddress()) 650 continue; 651 652 uint64_t StartOffset = FuncStart - getPreferredBaseAddress(); 653 uint64_t EndOffset = Range.HighPC - getPreferredBaseAddress(); 654 655 // We may want to know all ranges for one function. Here group the 656 // ranges and store them into BinaryFunction. 657 Func.Ranges.emplace_back(StartOffset, EndOffset); 658 659 auto R = StartOffset2FuncRangeMap.emplace(StartOffset, FuncRange()); 660 if (R.second) { 661 FuncRange &FRange = R.first->second; 662 FRange.Func = &Func; 663 FRange.StartOffset = StartOffset; 664 FRange.EndOffset = EndOffset; 665 } else { 666 WithColor::warning() 667 << "Duplicated symbol start address at " 668 << format("%8" PRIx64, StartOffset + getPreferredBaseAddress()) 669 << " " << R.first->second.getFuncName() << " and " << Name 670 << "\n"; 671 } 672 } 673 } 674 } 675 assert(!StartOffset2FuncRangeMap.empty() && "Misssing debug info."); 676 } 677 678 void ProfiledBinary::populateSymbolListFromDWARF( 679 ProfileSymbolList &SymbolList) { 680 for (auto &I : StartOffset2FuncRangeMap) 681 SymbolList.add(I.second.getFuncName()); 682 } 683 684 void ProfiledBinary::setupSymbolizer() { 685 symbolize::LLVMSymbolizer::Options SymbolizerOpts; 686 SymbolizerOpts.PrintFunctions = 687 DILineInfoSpecifier::FunctionNameKind::LinkageName; 688 SymbolizerOpts.Demangle = false; 689 SymbolizerOpts.DefaultArch = TheTriple.getArchName().str(); 690 SymbolizerOpts.UseSymbolTable = false; 691 SymbolizerOpts.RelativeAddresses = false; 692 Symbolizer = std::make_unique<symbolize::LLVMSymbolizer>(SymbolizerOpts); 693 } 694 695 SampleContextFrameVector ProfiledBinary::symbolize(const InstructionPointer &IP, 696 bool UseCanonicalFnName, 697 bool UseProbeDiscriminator) { 698 assert(this == IP.Binary && 699 "Binary should only symbolize its own instruction"); 700 auto Addr = object::SectionedAddress{IP.Offset + getPreferredBaseAddress(), 701 object::SectionedAddress::UndefSection}; 702 DIInliningInfo InlineStack = unwrapOrError( 703 Symbolizer->symbolizeInlinedCode(SymbolizerPath.str(), Addr), 704 SymbolizerPath); 705 706 SampleContextFrameVector CallStack; 707 for (int32_t I = InlineStack.getNumberOfFrames() - 1; I >= 0; I--) { 708 const auto &CallerFrame = InlineStack.getFrame(I); 709 if (CallerFrame.FunctionName == "<invalid>") 710 break; 711 712 StringRef FunctionName(CallerFrame.FunctionName); 713 if (UseCanonicalFnName) 714 FunctionName = FunctionSamples::getCanonicalFnName(FunctionName); 715 716 uint32_t Discriminator = CallerFrame.Discriminator; 717 uint32_t LineOffset = (CallerFrame.Line - CallerFrame.StartLine) & 0xffff; 718 if (UseProbeDiscriminator) { 719 LineOffset = 720 PseudoProbeDwarfDiscriminator::extractProbeIndex(Discriminator); 721 Discriminator = 0; 722 } 723 724 LineLocation Line(LineOffset, Discriminator); 725 auto It = NameStrings.insert(FunctionName.str()); 726 CallStack.emplace_back(*It.first, Line); 727 } 728 729 return CallStack; 730 } 731 732 void ProfiledBinary::computeInlinedContextSizeForRange(uint64_t StartOffset, 733 uint64_t EndOffset) { 734 uint64_t RangeBegin = offsetToVirtualAddr(StartOffset); 735 uint64_t RangeEnd = offsetToVirtualAddr(EndOffset); 736 InstructionPointer IP(this, RangeBegin, true); 737 738 if (IP.Address != RangeBegin) 739 WithColor::warning() << "Invalid start instruction at " 740 << format("%8" PRIx64, RangeBegin) << "\n"; 741 742 if (IP.Address >= RangeEnd) 743 return; 744 745 do { 746 uint64_t Offset = virtualAddrToOffset(IP.Address); 747 const SampleContextFrameVector &SymbolizedCallStack = 748 getFrameLocationStack(Offset, UsePseudoProbes); 749 uint64_t Size = Offset2InstSizeMap[Offset]; 750 751 // Record instruction size for the corresponding context 752 FuncSizeTracker.addInstructionForContext(SymbolizedCallStack, Size); 753 754 } while (IP.advance() && IP.Address < RangeEnd); 755 } 756 757 void ProfiledBinary::computeInlinedContextSizeForFunc( 758 const BinaryFunction *Func) { 759 // Note that a function can be spilt into multiple ranges, so compute for all 760 // ranges of the function. 761 for (const auto &Range : Func->Ranges) 762 computeInlinedContextSizeForRange(Range.first, Range.second); 763 764 // Track optimized-away inlinee for probed binary. A function inlined and then 765 // optimized away should still have their probes left over in places. 766 if (usePseudoProbes()) { 767 auto I = TopLevelProbeFrameMap.find(Func->FuncName); 768 if (I != TopLevelProbeFrameMap.end()) { 769 BinarySizeContextTracker::ProbeFrameStack ProbeContext; 770 FuncSizeTracker.trackInlineesOptimizedAway(ProbeDecoder, *I->second, 771 ProbeContext); 772 } 773 } 774 } 775 776 InstructionPointer::InstructionPointer(const ProfiledBinary *Binary, 777 uint64_t Address, bool RoundToNext) 778 : Binary(Binary), Address(Address) { 779 Index = Binary->getIndexForAddr(Address); 780 if (RoundToNext) { 781 // we might get address which is not the code 782 // it should round to the next valid address 783 if (Index >= Binary->getCodeOffsetsSize()) 784 this->Address = UINT64_MAX; 785 else 786 this->Address = Binary->getAddressforIndex(Index); 787 } 788 } 789 790 bool InstructionPointer::advance() { 791 Index++; 792 if (Index >= Binary->getCodeOffsetsSize()) { 793 Address = UINT64_MAX; 794 return false; 795 } 796 Address = Binary->getAddressforIndex(Index); 797 return true; 798 } 799 800 bool InstructionPointer::backward() { 801 if (Index == 0) { 802 Address = 0; 803 return false; 804 } 805 Index--; 806 Address = Binary->getAddressforIndex(Index); 807 return true; 808 } 809 810 void InstructionPointer::update(uint64_t Addr) { 811 Address = Addr; 812 Index = Binary->getIndexForAddr(Address); 813 } 814 815 } // end namespace sampleprof 816 } // end namespace llvm 817