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