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 MCObjectFileInfo MOFI; 336 MCContext Ctx(AsmInfo.get(), MRI.get(), &MOFI); 337 MOFI.InitMCObjectFileInfo(Triple(TripleName), false, Ctx); 338 DisAsm.reset(TheTarget->createMCDisassembler(*STI, Ctx)); 339 if (!DisAsm) 340 exitWithError("no disassembler for target " + TripleName, FileName); 341 342 MIA.reset(TheTarget->createMCInstrAnalysis(MII.get())); 343 344 int AsmPrinterVariant = AsmInfo->getAssemblerDialect(); 345 IPrinter.reset(TheTarget->createMCInstPrinter( 346 Triple(TripleName), AsmPrinterVariant, *AsmInfo, *MII, *MRI)); 347 IPrinter->setPrintBranchImmAsAddress(true); 348 } 349 350 void ProfiledBinary::disassemble(const ELFObjectFileBase *Obj) { 351 // Set up disassembler and related components. 352 setUpDisassembler(Obj); 353 354 // Create a mapping from virtual address to symbol name. The symbols in text 355 // sections are the candidates to dissassemble. 356 std::map<SectionRef, SectionSymbolsTy> AllSymbols; 357 StringRef FileName = Obj->getFileName(); 358 for (const SymbolRef &Symbol : Obj->symbols()) { 359 const uint64_t Addr = unwrapOrError(Symbol.getAddress(), FileName); 360 const StringRef Name = unwrapOrError(Symbol.getName(), FileName); 361 section_iterator SecI = unwrapOrError(Symbol.getSection(), FileName); 362 if (SecI != Obj->section_end()) 363 AllSymbols[*SecI].push_back(SymbolInfoTy(Addr, Name, ELF::STT_NOTYPE)); 364 } 365 366 // Sort all the symbols. Use a stable sort to stabilize the output. 367 for (std::pair<const SectionRef, SectionSymbolsTy> &SecSyms : AllSymbols) 368 stable_sort(SecSyms.second); 369 370 if (ShowDisassemblyOnly) 371 outs() << "\nDisassembly of " << FileName << ":\n"; 372 373 // Dissassemble a text section. 374 for (section_iterator SI = Obj->section_begin(), SE = Obj->section_end(); 375 SI != SE; ++SI) { 376 const SectionRef &Section = *SI; 377 if (!Section.isText()) 378 continue; 379 380 uint64_t ImageLoadAddr = PreferredBaseAddress; 381 uint64_t SectionOffset = Section.getAddress() - ImageLoadAddr; 382 uint64_t SectSize = Section.getSize(); 383 if (!SectSize) 384 continue; 385 386 // Register the text section. 387 TextSections.insert({SectionOffset, SectSize}); 388 389 if (ShowDisassemblyOnly) { 390 StringRef SectionName = unwrapOrError(Section.getName(), FileName); 391 outs() << "\nDisassembly of section " << SectionName; 392 outs() << " [" << format("0x%" PRIx64, SectionOffset) << ", " 393 << format("0x%" PRIx64, SectionOffset + SectSize) << "]:\n\n"; 394 } 395 396 // Get the section data. 397 ArrayRef<uint8_t> Bytes = 398 arrayRefFromStringRef(unwrapOrError(Section.getContents(), FileName)); 399 400 // Get the list of all the symbols in this section. 401 SectionSymbolsTy &Symbols = AllSymbols[Section]; 402 403 // Disassemble symbol by symbol. 404 for (std::size_t SI = 0, SE = Symbols.size(); SI != SE; ++SI) { 405 if (!dissassembleSymbol(SI, Bytes, Symbols, Section)) 406 exitWithError("disassembling error", FileName); 407 } 408 } 409 } 410 411 void ProfiledBinary::setupSymbolizer() { 412 symbolize::LLVMSymbolizer::Options SymbolizerOpts; 413 SymbolizerOpts.PrintFunctions = 414 DILineInfoSpecifier::FunctionNameKind::LinkageName; 415 SymbolizerOpts.Demangle = false; 416 SymbolizerOpts.DefaultArch = TheTriple.getArchName().str(); 417 SymbolizerOpts.UseSymbolTable = false; 418 SymbolizerOpts.RelativeAddresses = false; 419 Symbolizer = std::make_unique<symbolize::LLVMSymbolizer>(SymbolizerOpts); 420 } 421 422 FrameLocationStack ProfiledBinary::symbolize(const InstructionPointer &IP, 423 bool UseCanonicalFnName) { 424 assert(this == IP.Binary && 425 "Binary should only symbolize its own instruction"); 426 auto Addr = object::SectionedAddress{IP.Offset + PreferredBaseAddress, 427 object::SectionedAddress::UndefSection}; 428 DIInliningInfo InlineStack = 429 unwrapOrError(Symbolizer->symbolizeInlinedCode(Path, Addr), getName()); 430 431 FrameLocationStack CallStack; 432 433 for (int32_t I = InlineStack.getNumberOfFrames() - 1; I >= 0; I--) { 434 const auto &CallerFrame = InlineStack.getFrame(I); 435 if (CallerFrame.FunctionName == "<invalid>") 436 break; 437 StringRef FunctionName(CallerFrame.FunctionName); 438 if (UseCanonicalFnName) 439 FunctionName = FunctionSamples::getCanonicalFnName(FunctionName); 440 LineLocation Line(CallerFrame.Line - CallerFrame.StartLine, 441 DILocation::getBaseDiscriminatorFromDiscriminator( 442 CallerFrame.Discriminator)); 443 FrameLocation Callsite(FunctionName.str(), Line); 444 CallStack.push_back(Callsite); 445 } 446 447 return CallStack; 448 } 449 450 InstructionPointer::InstructionPointer(ProfiledBinary *Binary, uint64_t Address, 451 bool RoundToNext) 452 : Binary(Binary), Address(Address) { 453 Index = Binary->getIndexForAddr(Address); 454 if (RoundToNext) { 455 // we might get address which is not the code 456 // it should round to the next valid address 457 this->Address = Binary->getAddressforIndex(Index); 458 } 459 } 460 461 void InstructionPointer::advance() { 462 Index++; 463 Address = Binary->getAddressforIndex(Index); 464 } 465 466 void InstructionPointer::backward() { 467 Index--; 468 Address = Binary->getAddressforIndex(Index); 469 } 470 471 void InstructionPointer::update(uint64_t Addr) { 472 Address = Addr; 473 Index = Binary->getIndexForAddr(Address); 474 } 475 476 } // end namespace sampleprof 477 } // end namespace llvm 478