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