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