1 //===-- ProfiledBinary.cpp - Binary decoder ---------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "ProfiledBinary.h" 10 #include "ErrorHandling.h" 11 #include "ProfileGenerator.h" 12 #include "llvm/ADT/Triple.h" 13 #include "llvm/Demangle/Demangle.h" 14 #include "llvm/IR/DebugInfoMetadata.h" 15 #include "llvm/Support/CommandLine.h" 16 #include "llvm/Support/Format.h" 17 #include "llvm/Support/TargetRegistry.h" 18 #include "llvm/Support/TargetSelect.h" 19 20 #define DEBUG_TYPE "load-binary" 21 22 using namespace llvm; 23 using namespace sampleprof; 24 25 cl::opt<bool> ShowDisassemblyOnly("show-disassembly-only", cl::ReallyHidden, 26 cl::init(false), cl::ZeroOrMore, 27 cl::desc("Print disassembled code.")); 28 29 cl::opt<bool> ShowSourceLocations("show-source-locations", cl::ReallyHidden, 30 cl::init(false), cl::ZeroOrMore, 31 cl::desc("Print source locations.")); 32 33 cl::opt<bool> ShowCanonicalFnName("show-canonical-fname", cl::ReallyHidden, 34 cl::init(false), cl::ZeroOrMore, 35 cl::desc("Print canonical function name.")); 36 37 cl::opt<bool> ShowPseudoProbe( 38 "show-pseudo-probe", cl::ReallyHidden, cl::init(false), cl::ZeroOrMore, 39 cl::desc("Print pseudo probe section and disassembled info.")); 40 41 namespace llvm { 42 namespace sampleprof { 43 44 static const Target *getTarget(const ObjectFile *Obj) { 45 Triple TheTriple = Obj->makeTriple(); 46 std::string Error; 47 std::string ArchName; 48 const Target *TheTarget = 49 TargetRegistry::lookupTarget(ArchName, TheTriple, Error); 50 if (!TheTarget) 51 exitWithError(Error, Obj->getFileName()); 52 return TheTarget; 53 } 54 55 template <class ELFT> 56 static uint64_t getELFImageLMAForSec(const ELFFile<ELFT> &Obj, 57 const object::ELFSectionRef &Sec, 58 StringRef FileName) { 59 // Search for a PT_LOAD segment containing the requested section. Return this 60 // segment's p_addr as the image load address for the section. 61 const auto &PhdrRange = unwrapOrError(Obj.program_headers(), FileName); 62 for (const typename ELFT::Phdr &Phdr : PhdrRange) 63 if ((Phdr.p_type == ELF::PT_LOAD) && (Phdr.p_vaddr <= Sec.getAddress()) && 64 (Phdr.p_vaddr + Phdr.p_memsz > Sec.getAddress())) 65 // Segments will always be loaded at a page boundary. 66 return Phdr.p_paddr & ~(Phdr.p_align - 1U); 67 return 0; 68 } 69 70 // Get the image load address for a specific section. Note that an image is 71 // loaded by segments (a group of sections) and segments may not be consecutive 72 // in memory. 73 static uint64_t getELFImageLMAForSec(const object::ELFSectionRef &Sec) { 74 if (const auto *ELFObj = dyn_cast<ELF32LEObjectFile>(Sec.getObject())) 75 return getELFImageLMAForSec(ELFObj->getELFFile(), Sec, 76 ELFObj->getFileName()); 77 else if (const auto *ELFObj = dyn_cast<ELF32BEObjectFile>(Sec.getObject())) 78 return getELFImageLMAForSec(ELFObj->getELFFile(), Sec, 79 ELFObj->getFileName()); 80 else if (const auto *ELFObj = dyn_cast<ELF64LEObjectFile>(Sec.getObject())) 81 return getELFImageLMAForSec(ELFObj->getELFFile(), Sec, 82 ELFObj->getFileName()); 83 const auto *ELFObj = cast<ELF64BEObjectFile>(Sec.getObject()); 84 return getELFImageLMAForSec(ELFObj->getELFFile(), Sec, ELFObj->getFileName()); 85 } 86 87 void ProfiledBinary::load() { 88 // Attempt to open the binary. 89 OwningBinary<Binary> OBinary = unwrapOrError(createBinary(Path), Path); 90 Binary &Binary = *OBinary.getBinary(); 91 92 auto *Obj = dyn_cast<ELFObjectFileBase>(&Binary); 93 if (!Obj) 94 exitWithError("not a valid Elf image", Path); 95 96 TheTriple = Obj->makeTriple(); 97 // Current only support X86 98 if (!TheTriple.isX86()) 99 exitWithError("unsupported target", TheTriple.getTriple()); 100 LLVM_DEBUG(dbgs() << "Loading " << Path << "\n"); 101 102 // Find the preferred base address for text sections. 103 setPreferredBaseAddress(Obj); 104 105 // Decode pseudo probe related section 106 decodePseudoProbe(Obj); 107 108 // Disassemble the text sections. 109 disassemble(Obj); 110 111 // Use function start and return address to infer prolog and epilog 112 ProEpilogTracker.inferPrologOffsets(FuncStartAddrMap); 113 ProEpilogTracker.inferEpilogOffsets(RetAddrs); 114 115 // TODO: decode other sections. 116 } 117 118 bool ProfiledBinary::inlineContextEqual(uint64_t Address1, 119 uint64_t Address2) const { 120 uint64_t Offset1 = virtualAddrToOffset(Address1); 121 uint64_t Offset2 = virtualAddrToOffset(Address2); 122 const FrameLocationStack &Context1 = getFrameLocationStack(Offset1); 123 const FrameLocationStack &Context2 = getFrameLocationStack(Offset2); 124 if (Context1.size() != Context2.size()) 125 return false; 126 if (Context1.empty()) 127 return false; 128 // The leaf frame contains location within the leaf, and it 129 // needs to be remove that as it's not part of the calling context 130 return std::equal(Context1.begin(), Context1.begin() + Context1.size() - 1, 131 Context2.begin(), Context2.begin() + Context2.size() - 1); 132 } 133 134 std::string 135 ProfiledBinary::getExpandedContextStr(const SmallVectorImpl<uint64_t> &Stack, 136 bool &WasLeafInlined) const { 137 std::string ContextStr; 138 SmallVector<std::string, 16> ContextVec; 139 // Process from frame root to leaf 140 for (auto Address : Stack) { 141 uint64_t Offset = virtualAddrToOffset(Address); 142 const FrameLocationStack &ExpandedContext = getFrameLocationStack(Offset); 143 // An instruction without a valid debug line will be ignored by sample 144 // processing 145 if (ExpandedContext.empty()) 146 return std::string(); 147 // Set WasLeafInlined to the size of inlined frame count for the last 148 // address which is leaf 149 WasLeafInlined = (ExpandedContext.size() > 1); 150 for (const auto &Loc : ExpandedContext) { 151 ContextVec.push_back(getCallSite(Loc)); 152 } 153 } 154 155 assert(ContextVec.size() && "Context length should be at least 1"); 156 // Compress the context string except for the leaf frame 157 std::string LeafFrame = ContextVec.back(); 158 ContextVec.pop_back(); 159 CSProfileGenerator::compressRecursionContext<std::string>(ContextVec); 160 161 std::ostringstream OContextStr; 162 for (uint32_t I = 0; I < (uint32_t)ContextVec.size(); I++) { 163 if (OContextStr.str().size()) { 164 OContextStr << " @ "; 165 } 166 OContextStr << ContextVec[I]; 167 } 168 // Only keep the function name for the leaf frame 169 if (OContextStr.str().size()) 170 OContextStr << " @ "; 171 OContextStr << StringRef(LeafFrame).split(":").first.str(); 172 return OContextStr.str(); 173 } 174 175 void ProfiledBinary::setPreferredBaseAddress(const ELFObjectFileBase *Obj) { 176 for (section_iterator SI = Obj->section_begin(), SE = Obj->section_end(); 177 SI != SE; ++SI) { 178 const SectionRef &Section = *SI; 179 if (Section.isText()) { 180 PreferredBaseAddress = getELFImageLMAForSec(Section); 181 return; 182 } 183 } 184 exitWithError("no text section found", Obj->getFileName()); 185 } 186 187 void ProfiledBinary::decodePseudoProbe(const ELFObjectFileBase *Obj) { 188 StringRef FileName = Obj->getFileName(); 189 for (section_iterator SI = Obj->section_begin(), SE = Obj->section_end(); 190 SI != SE; ++SI) { 191 const SectionRef &Section = *SI; 192 StringRef SectionName = unwrapOrError(Section.getName(), FileName); 193 194 if (SectionName == ".pseudo_probe_desc") { 195 StringRef Contents = unwrapOrError(Section.getContents(), FileName); 196 ProbeDecoder.buildGUID2FuncDescMap( 197 reinterpret_cast<const uint8_t *>(Contents.data()), Contents.size()); 198 } else if (SectionName == ".pseudo_probe") { 199 StringRef Contents = unwrapOrError(Section.getContents(), FileName); 200 ProbeDecoder.buildAddress2ProbeMap( 201 reinterpret_cast<const uint8_t *>(Contents.data()), Contents.size()); 202 // set UsePseudoProbes flag, used for PerfReader 203 UsePseudoProbes = true; 204 } 205 } 206 207 if (ShowPseudoProbe) 208 ProbeDecoder.printGUID2FuncDescMap(outs()); 209 } 210 211 bool ProfiledBinary::dissassembleSymbol(std::size_t SI, ArrayRef<uint8_t> Bytes, 212 SectionSymbolsTy &Symbols, 213 const SectionRef &Section) { 214 std::size_t SE = Symbols.size(); 215 uint64_t SectionOffset = Section.getAddress() - PreferredBaseAddress; 216 uint64_t SectSize = Section.getSize(); 217 uint64_t StartOffset = Symbols[SI].Addr - PreferredBaseAddress; 218 uint64_t EndOffset = (SI + 1 < SE) 219 ? Symbols[SI + 1].Addr - PreferredBaseAddress 220 : SectionOffset + SectSize; 221 if (StartOffset >= EndOffset) 222 return true; 223 224 StringRef SymbolName = 225 ShowCanonicalFnName 226 ? FunctionSamples::getCanonicalFnName(Symbols[SI].Name) 227 : Symbols[SI].Name; 228 if (ShowDisassemblyOnly) 229 outs() << '<' << SymbolName << ">:\n"; 230 231 auto WarnInvalidInsts = [](uint64_t Start, uint64_t End) { 232 WithColor::warning() << "Invalid instructions at " 233 << format("%8" PRIx64, Start) << " - " 234 << format("%8" PRIx64, End) << "\n"; 235 }; 236 237 uint64_t Offset = StartOffset; 238 // Size of a consecutive invalid instruction range starting from Offset -1 239 // backwards. 240 uint64_t InvalidInstLength = 0; 241 while (Offset < EndOffset) { 242 MCInst Inst; 243 uint64_t Size; 244 // Disassemble an instruction. 245 bool Disassembled = 246 DisAsm->getInstruction(Inst, Size, Bytes.slice(Offset - SectionOffset), 247 Offset + PreferredBaseAddress, nulls()); 248 if (Size == 0) 249 Size = 1; 250 251 if (ShowDisassemblyOnly) { 252 if (ShowPseudoProbe) { 253 ProbeDecoder.printProbeForAddress(outs(), 254 Offset + PreferredBaseAddress); 255 } 256 outs() << format("%8" PRIx64 ":", Offset); 257 size_t Start = outs().tell(); 258 if (Disassembled) 259 IPrinter->printInst(&Inst, Offset + Size, "", *STI.get(), outs()); 260 else 261 outs() << "\t<unknown>"; 262 if (ShowSourceLocations) { 263 unsigned Cur = outs().tell() - Start; 264 if (Cur < 40) 265 outs().indent(40 - Cur); 266 InstructionPointer IP(this, Offset); 267 outs() << getReversedLocWithContext(symbolize(IP, ShowCanonicalFnName)); 268 } 269 outs() << "\n"; 270 } 271 272 if (Disassembled) { 273 const MCInstrDesc &MCDesc = MII->get(Inst.getOpcode()); 274 // Populate a vector of the symbolized callsite at this location 275 // We don't need symbolized info for probe-based profile, just use an 276 // empty stack as an entry to indicate a valid binary offset 277 FrameLocationStack SymbolizedCallStack; 278 if (!UsePseudoProbes) { 279 InstructionPointer IP(this, Offset); 280 SymbolizedCallStack = symbolize(IP, true); 281 } 282 Offset2LocStackMap[Offset] = SymbolizedCallStack; 283 // Populate address maps. 284 CodeAddrs.push_back(Offset); 285 if (MCDesc.isCall()) 286 CallAddrs.insert(Offset); 287 else if (MCDesc.isReturn()) 288 RetAddrs.insert(Offset); 289 290 if (InvalidInstLength) { 291 WarnInvalidInsts(Offset - InvalidInstLength, Offset - 1); 292 InvalidInstLength = 0; 293 } 294 } else { 295 InvalidInstLength += Size; 296 } 297 298 Offset += Size; 299 } 300 301 if (InvalidInstLength) 302 WarnInvalidInsts(Offset - InvalidInstLength, Offset - 1); 303 304 if (ShowDisassemblyOnly) 305 outs() << "\n"; 306 307 FuncStartAddrMap[StartOffset] = Symbols[SI].Name.str(); 308 return true; 309 } 310 311 void ProfiledBinary::setUpDisassembler(const ELFObjectFileBase *Obj) { 312 const Target *TheTarget = getTarget(Obj); 313 std::string TripleName = TheTriple.getTriple(); 314 StringRef FileName = Obj->getFileName(); 315 316 MRI.reset(TheTarget->createMCRegInfo(TripleName)); 317 if (!MRI) 318 exitWithError("no register info for target " + TripleName, FileName); 319 320 MCTargetOptions MCOptions; 321 AsmInfo.reset(TheTarget->createMCAsmInfo(*MRI, TripleName, MCOptions)); 322 if (!AsmInfo) 323 exitWithError("no assembly info for target " + TripleName, FileName); 324 325 SubtargetFeatures Features = Obj->getFeatures(); 326 STI.reset( 327 TheTarget->createMCSubtargetInfo(TripleName, "", Features.getString())); 328 if (!STI) 329 exitWithError("no subtarget info for target " + TripleName, FileName); 330 331 MII.reset(TheTarget->createMCInstrInfo()); 332 if (!MII) 333 exitWithError("no instruction info for target " + TripleName, FileName); 334 335 MCContext Ctx(Triple(TripleName), AsmInfo.get(), MRI.get(), STI.get()); 336 std::unique_ptr<MCObjectFileInfo> MOFI( 337 TheTarget->createMCObjectFileInfo(Ctx, /*PIC=*/false)); 338 Ctx.setObjectFileInfo(MOFI.get()); 339 DisAsm.reset(TheTarget->createMCDisassembler(*STI, Ctx)); 340 if (!DisAsm) 341 exitWithError("no disassembler for target " + TripleName, FileName); 342 343 MIA.reset(TheTarget->createMCInstrAnalysis(MII.get())); 344 345 int AsmPrinterVariant = AsmInfo->getAssemblerDialect(); 346 IPrinter.reset(TheTarget->createMCInstPrinter( 347 Triple(TripleName), AsmPrinterVariant, *AsmInfo, *MII, *MRI)); 348 IPrinter->setPrintBranchImmAsAddress(true); 349 } 350 351 void ProfiledBinary::disassemble(const ELFObjectFileBase *Obj) { 352 // Set up disassembler and related components. 353 setUpDisassembler(Obj); 354 355 // Create a mapping from virtual address to symbol name. The symbols in text 356 // sections are the candidates to dissassemble. 357 std::map<SectionRef, SectionSymbolsTy> AllSymbols; 358 StringRef FileName = Obj->getFileName(); 359 for (const SymbolRef &Symbol : Obj->symbols()) { 360 const uint64_t Addr = unwrapOrError(Symbol.getAddress(), FileName); 361 const StringRef Name = unwrapOrError(Symbol.getName(), FileName); 362 section_iterator SecI = unwrapOrError(Symbol.getSection(), FileName); 363 if (SecI != Obj->section_end()) 364 AllSymbols[*SecI].push_back(SymbolInfoTy(Addr, Name, ELF::STT_NOTYPE)); 365 } 366 367 // Sort all the symbols. Use a stable sort to stabilize the output. 368 for (std::pair<const SectionRef, SectionSymbolsTy> &SecSyms : AllSymbols) 369 stable_sort(SecSyms.second); 370 371 if (ShowDisassemblyOnly) 372 outs() << "\nDisassembly of " << FileName << ":\n"; 373 374 // Dissassemble a text section. 375 for (section_iterator SI = Obj->section_begin(), SE = Obj->section_end(); 376 SI != SE; ++SI) { 377 const SectionRef &Section = *SI; 378 if (!Section.isText()) 379 continue; 380 381 uint64_t ImageLoadAddr = PreferredBaseAddress; 382 uint64_t SectionOffset = Section.getAddress() - ImageLoadAddr; 383 uint64_t SectSize = Section.getSize(); 384 if (!SectSize) 385 continue; 386 387 // Register the text section. 388 TextSections.insert({SectionOffset, SectSize}); 389 390 if (ShowDisassemblyOnly) { 391 StringRef SectionName = unwrapOrError(Section.getName(), FileName); 392 outs() << "\nDisassembly of section " << SectionName; 393 outs() << " [" << format("0x%" PRIx64, SectionOffset) << ", " 394 << format("0x%" PRIx64, SectionOffset + SectSize) << "]:\n\n"; 395 } 396 397 // Get the section data. 398 ArrayRef<uint8_t> Bytes = 399 arrayRefFromStringRef(unwrapOrError(Section.getContents(), FileName)); 400 401 // Get the list of all the symbols in this section. 402 SectionSymbolsTy &Symbols = AllSymbols[Section]; 403 404 // Disassemble symbol by symbol. 405 for (std::size_t SI = 0, SE = Symbols.size(); SI != SE; ++SI) { 406 if (!dissassembleSymbol(SI, Bytes, Symbols, Section)) 407 exitWithError("disassembling error", FileName); 408 } 409 } 410 } 411 412 void ProfiledBinary::setupSymbolizer() { 413 symbolize::LLVMSymbolizer::Options SymbolizerOpts; 414 SymbolizerOpts.PrintFunctions = 415 DILineInfoSpecifier::FunctionNameKind::LinkageName; 416 SymbolizerOpts.Demangle = false; 417 SymbolizerOpts.DefaultArch = TheTriple.getArchName().str(); 418 SymbolizerOpts.UseSymbolTable = false; 419 SymbolizerOpts.RelativeAddresses = false; 420 Symbolizer = std::make_unique<symbolize::LLVMSymbolizer>(SymbolizerOpts); 421 } 422 423 FrameLocationStack ProfiledBinary::symbolize(const InstructionPointer &IP, 424 bool UseCanonicalFnName) { 425 assert(this == IP.Binary && 426 "Binary should only symbolize its own instruction"); 427 auto Addr = object::SectionedAddress{IP.Offset + PreferredBaseAddress, 428 object::SectionedAddress::UndefSection}; 429 DIInliningInfo InlineStack = 430 unwrapOrError(Symbolizer->symbolizeInlinedCode(Path, Addr), getName()); 431 432 FrameLocationStack CallStack; 433 434 for (int32_t I = InlineStack.getNumberOfFrames() - 1; I >= 0; I--) { 435 const auto &CallerFrame = InlineStack.getFrame(I); 436 if (CallerFrame.FunctionName == "<invalid>") 437 break; 438 StringRef FunctionName(CallerFrame.FunctionName); 439 if (UseCanonicalFnName) 440 FunctionName = FunctionSamples::getCanonicalFnName(FunctionName); 441 LineLocation Line(CallerFrame.Line - CallerFrame.StartLine, 442 DILocation::getBaseDiscriminatorFromDiscriminator( 443 CallerFrame.Discriminator)); 444 FrameLocation Callsite(FunctionName.str(), Line); 445 CallStack.push_back(Callsite); 446 } 447 448 return CallStack; 449 } 450 451 InstructionPointer::InstructionPointer(ProfiledBinary *Binary, uint64_t Address, 452 bool RoundToNext) 453 : Binary(Binary), Address(Address) { 454 Index = Binary->getIndexForAddr(Address); 455 if (RoundToNext) { 456 // we might get address which is not the code 457 // it should round to the next valid address 458 this->Address = Binary->getAddressforIndex(Index); 459 } 460 } 461 462 void InstructionPointer::advance() { 463 Index++; 464 Address = Binary->getAddressforIndex(Index); 465 } 466 467 void InstructionPointer::backward() { 468 Index--; 469 Address = Binary->getAddressforIndex(Index); 470 } 471 472 void InstructionPointer::update(uint64_t Addr) { 473 Address = Addr; 474 Index = Binary->getIndexForAddr(Address); 475 } 476 477 } // end namespace sampleprof 478 } // end namespace llvm 479