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