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 ProfiledBinary::getExpandedContextStr( 135 const SmallVectorImpl<uint64_t> &Stack) const { 136 std::string ContextStr; 137 SmallVector<std::string, 16> ContextVec; 138 // Process from frame root to leaf 139 for (auto Address : Stack) { 140 uint64_t Offset = virtualAddrToOffset(Address); 141 const FrameLocationStack &ExpandedContext = getFrameLocationStack(Offset); 142 // An instruction without a valid debug line will be ignored by sample 143 // processing 144 if (ExpandedContext.empty()) 145 return std::string(); 146 for (const auto &Loc : ExpandedContext) { 147 ContextVec.push_back(getCallSite(Loc)); 148 } 149 } 150 151 assert(ContextVec.size() && "Context length should be at least 1"); 152 // Compress the context string except for the leaf frame 153 std::string LeafFrame = ContextVec.back(); 154 ContextVec.pop_back(); 155 CSProfileGenerator::compressRecursionContext<std::string>(ContextVec); 156 157 std::ostringstream OContextStr; 158 for (uint32_t I = 0; I < (uint32_t)ContextVec.size(); I++) { 159 if (OContextStr.str().size()) { 160 OContextStr << " @ "; 161 } 162 OContextStr << ContextVec[I]; 163 } 164 // Only keep the function name for the leaf frame 165 if (OContextStr.str().size()) 166 OContextStr << " @ "; 167 OContextStr << StringRef(LeafFrame).split(":").first.str(); 168 return OContextStr.str(); 169 } 170 171 void ProfiledBinary::setPreferredBaseAddress(const ELFObjectFileBase *Obj) { 172 for (section_iterator SI = Obj->section_begin(), SE = Obj->section_end(); 173 SI != SE; ++SI) { 174 const SectionRef &Section = *SI; 175 if (Section.isText()) { 176 PreferredBaseAddress = getELFImageLMAForSec(Section); 177 return; 178 } 179 } 180 exitWithError("no text section found", Obj->getFileName()); 181 } 182 183 void ProfiledBinary::decodePseudoProbe(const ELFObjectFileBase *Obj) { 184 StringRef FileName = Obj->getFileName(); 185 for (section_iterator SI = Obj->section_begin(), SE = Obj->section_end(); 186 SI != SE; ++SI) { 187 const SectionRef &Section = *SI; 188 StringRef SectionName = unwrapOrError(Section.getName(), FileName); 189 190 if (SectionName == ".pseudo_probe_desc") { 191 StringRef Contents = unwrapOrError(Section.getContents(), FileName); 192 ProbeDecoder.buildGUID2FuncDescMap( 193 reinterpret_cast<const uint8_t *>(Contents.data()), Contents.size()); 194 } else if (SectionName == ".pseudo_probe") { 195 StringRef Contents = unwrapOrError(Section.getContents(), FileName); 196 ProbeDecoder.buildAddress2ProbeMap( 197 reinterpret_cast<const uint8_t *>(Contents.data()), Contents.size()); 198 // set UsePseudoProbes flag, used for PerfReader 199 UsePseudoProbes = true; 200 } 201 } 202 203 if (ShowPseudoProbe) 204 ProbeDecoder.printGUID2FuncDescMap(outs()); 205 } 206 207 bool ProfiledBinary::dissassembleSymbol(std::size_t SI, ArrayRef<uint8_t> Bytes, 208 SectionSymbolsTy &Symbols, 209 const SectionRef &Section) { 210 std::size_t SE = Symbols.size(); 211 uint64_t SectionOffset = Section.getAddress() - PreferredBaseAddress; 212 uint64_t SectSize = Section.getSize(); 213 uint64_t StartOffset = Symbols[SI].Addr - PreferredBaseAddress; 214 uint64_t EndOffset = (SI + 1 < SE) 215 ? Symbols[SI + 1].Addr - PreferredBaseAddress 216 : SectionOffset + SectSize; 217 if (StartOffset >= EndOffset) 218 return true; 219 220 StringRef SymbolName = 221 ShowCanonicalFnName 222 ? FunctionSamples::getCanonicalFnName(Symbols[SI].Name) 223 : Symbols[SI].Name; 224 if (ShowDisassemblyOnly) 225 outs() << '<' << SymbolName << ">:\n"; 226 227 auto WarnInvalidInsts = [](uint64_t Start, uint64_t End) { 228 WithColor::warning() << "Invalid instructions at " 229 << format("%8" PRIx64, Start) << " - " 230 << format("%8" PRIx64, End) << "\n"; 231 }; 232 233 uint64_t Offset = StartOffset; 234 // Size of a consecutive invalid instruction range starting from Offset -1 235 // backwards. 236 uint64_t InvalidInstLength = 0; 237 while (Offset < EndOffset) { 238 MCInst Inst; 239 uint64_t Size; 240 // Disassemble an instruction. 241 bool Disassembled = 242 DisAsm->getInstruction(Inst, Size, Bytes.slice(Offset - SectionOffset), 243 Offset + PreferredBaseAddress, nulls()); 244 if (Size == 0) 245 Size = 1; 246 247 if (ShowDisassemblyOnly) { 248 if (ShowPseudoProbe) { 249 ProbeDecoder.printProbeForAddress(outs(), 250 Offset + PreferredBaseAddress); 251 } 252 outs() << format("%8" PRIx64 ":", Offset); 253 size_t Start = outs().tell(); 254 if (Disassembled) 255 IPrinter->printInst(&Inst, Offset + Size, "", *STI.get(), outs()); 256 else 257 outs() << "\t<unknown>"; 258 if (ShowSourceLocations) { 259 unsigned Cur = outs().tell() - Start; 260 if (Cur < 40) 261 outs().indent(40 - Cur); 262 InstructionPointer IP(this, Offset); 263 outs() << getReversedLocWithContext(symbolize(IP, ShowCanonicalFnName)); 264 } 265 outs() << "\n"; 266 } 267 268 if (Disassembled) { 269 const MCInstrDesc &MCDesc = MII->get(Inst.getOpcode()); 270 // Populate a vector of the symbolized callsite at this location 271 // We don't need symbolized info for probe-based profile, just use an 272 // empty stack as an entry to indicate a valid binary offset 273 FrameLocationStack SymbolizedCallStack; 274 if (!UsePseudoProbes) { 275 InstructionPointer IP(this, Offset); 276 SymbolizedCallStack = symbolize(IP, true); 277 } 278 Offset2LocStackMap[Offset] = SymbolizedCallStack; 279 // Populate address maps. 280 CodeAddrs.push_back(Offset); 281 if (MCDesc.isCall()) 282 CallAddrs.insert(Offset); 283 else if (MCDesc.isReturn()) 284 RetAddrs.insert(Offset); 285 286 if (InvalidInstLength) { 287 WarnInvalidInsts(Offset - InvalidInstLength, Offset - 1); 288 InvalidInstLength = 0; 289 } 290 } else { 291 InvalidInstLength += Size; 292 } 293 294 Offset += Size; 295 } 296 297 if (InvalidInstLength) 298 WarnInvalidInsts(Offset - InvalidInstLength, Offset - 1); 299 300 if (ShowDisassemblyOnly) 301 outs() << "\n"; 302 303 FuncStartAddrMap[StartOffset] = Symbols[SI].Name.str(); 304 return true; 305 } 306 307 void ProfiledBinary::setUpDisassembler(const ELFObjectFileBase *Obj) { 308 const Target *TheTarget = getTarget(Obj); 309 std::string TripleName = TheTriple.getTriple(); 310 StringRef FileName = Obj->getFileName(); 311 312 MRI.reset(TheTarget->createMCRegInfo(TripleName)); 313 if (!MRI) 314 exitWithError("no register info for target " + TripleName, FileName); 315 316 MCTargetOptions MCOptions; 317 AsmInfo.reset(TheTarget->createMCAsmInfo(*MRI, TripleName, MCOptions)); 318 if (!AsmInfo) 319 exitWithError("no assembly info for target " + TripleName, FileName); 320 321 SubtargetFeatures Features = Obj->getFeatures(); 322 STI.reset( 323 TheTarget->createMCSubtargetInfo(TripleName, "", Features.getString())); 324 if (!STI) 325 exitWithError("no subtarget info for target " + TripleName, FileName); 326 327 MII.reset(TheTarget->createMCInstrInfo()); 328 if (!MII) 329 exitWithError("no instruction info for target " + TripleName, FileName); 330 331 MCObjectFileInfo MOFI; 332 MCContext Ctx(AsmInfo.get(), MRI.get(), &MOFI); 333 MOFI.InitMCObjectFileInfo(Triple(TripleName), false, Ctx); 334 DisAsm.reset(TheTarget->createMCDisassembler(*STI, Ctx)); 335 if (!DisAsm) 336 exitWithError("no disassembler for target " + TripleName, FileName); 337 338 MIA.reset(TheTarget->createMCInstrAnalysis(MII.get())); 339 340 int AsmPrinterVariant = AsmInfo->getAssemblerDialect(); 341 IPrinter.reset(TheTarget->createMCInstPrinter( 342 Triple(TripleName), AsmPrinterVariant, *AsmInfo, *MII, *MRI)); 343 IPrinter->setPrintBranchImmAsAddress(true); 344 } 345 346 void ProfiledBinary::disassemble(const ELFObjectFileBase *Obj) { 347 // Set up disassembler and related components. 348 setUpDisassembler(Obj); 349 350 // Create a mapping from virtual address to symbol name. The symbols in text 351 // sections are the candidates to dissassemble. 352 std::map<SectionRef, SectionSymbolsTy> AllSymbols; 353 StringRef FileName = Obj->getFileName(); 354 for (const SymbolRef &Symbol : Obj->symbols()) { 355 const uint64_t Addr = unwrapOrError(Symbol.getAddress(), FileName); 356 const StringRef Name = unwrapOrError(Symbol.getName(), FileName); 357 section_iterator SecI = unwrapOrError(Symbol.getSection(), FileName); 358 if (SecI != Obj->section_end()) 359 AllSymbols[*SecI].push_back(SymbolInfoTy(Addr, Name, ELF::STT_NOTYPE)); 360 } 361 362 // Sort all the symbols. Use a stable sort to stabilize the output. 363 for (std::pair<const SectionRef, SectionSymbolsTy> &SecSyms : AllSymbols) 364 stable_sort(SecSyms.second); 365 366 if (ShowDisassemblyOnly) 367 outs() << "\nDisassembly of " << FileName << ":\n"; 368 369 // Dissassemble a text section. 370 for (section_iterator SI = Obj->section_begin(), SE = Obj->section_end(); 371 SI != SE; ++SI) { 372 const SectionRef &Section = *SI; 373 if (!Section.isText()) 374 continue; 375 376 uint64_t ImageLoadAddr = PreferredBaseAddress; 377 uint64_t SectionOffset = Section.getAddress() - ImageLoadAddr; 378 uint64_t SectSize = Section.getSize(); 379 if (!SectSize) 380 continue; 381 382 // Register the text section. 383 TextSections.insert({SectionOffset, SectSize}); 384 385 if (ShowDisassemblyOnly) { 386 StringRef SectionName = unwrapOrError(Section.getName(), FileName); 387 outs() << "\nDisassembly of section " << SectionName; 388 outs() << " [" << format("0x%" PRIx64, SectionOffset) << ", " 389 << format("0x%" PRIx64, SectionOffset + SectSize) << "]:\n\n"; 390 } 391 392 // Get the section data. 393 ArrayRef<uint8_t> Bytes = 394 arrayRefFromStringRef(unwrapOrError(Section.getContents(), FileName)); 395 396 // Get the list of all the symbols in this section. 397 SectionSymbolsTy &Symbols = AllSymbols[Section]; 398 399 // Disassemble symbol by symbol. 400 for (std::size_t SI = 0, SE = Symbols.size(); SI != SE; ++SI) { 401 if (!dissassembleSymbol(SI, Bytes, Symbols, Section)) 402 exitWithError("disassembling error", FileName); 403 } 404 } 405 } 406 407 void ProfiledBinary::setupSymbolizer() { 408 symbolize::LLVMSymbolizer::Options SymbolizerOpts; 409 SymbolizerOpts.PrintFunctions = 410 DILineInfoSpecifier::FunctionNameKind::LinkageName; 411 SymbolizerOpts.Demangle = false; 412 SymbolizerOpts.DefaultArch = TheTriple.getArchName().str(); 413 SymbolizerOpts.UseSymbolTable = false; 414 SymbolizerOpts.RelativeAddresses = false; 415 Symbolizer = std::make_unique<symbolize::LLVMSymbolizer>(SymbolizerOpts); 416 } 417 418 FrameLocationStack ProfiledBinary::symbolize(const InstructionPointer &IP, 419 bool UseCanonicalFnName) { 420 assert(this == IP.Binary && 421 "Binary should only symbolize its own instruction"); 422 auto Addr = object::SectionedAddress{IP.Offset + PreferredBaseAddress, 423 object::SectionedAddress::UndefSection}; 424 DIInliningInfo InlineStack = 425 unwrapOrError(Symbolizer->symbolizeInlinedCode(Path, Addr), getName()); 426 427 FrameLocationStack CallStack; 428 429 for (int32_t I = InlineStack.getNumberOfFrames() - 1; I >= 0; I--) { 430 const auto &CallerFrame = InlineStack.getFrame(I); 431 if (CallerFrame.FunctionName == "<invalid>") 432 break; 433 StringRef FunctionName(CallerFrame.FunctionName); 434 if (UseCanonicalFnName) 435 FunctionName = FunctionSamples::getCanonicalFnName(FunctionName); 436 LineLocation Line(CallerFrame.Line - CallerFrame.StartLine, 437 DILocation::getBaseDiscriminatorFromDiscriminator( 438 CallerFrame.Discriminator)); 439 FrameLocation Callsite(FunctionName.str(), Line); 440 CallStack.push_back(Callsite); 441 } 442 443 return CallStack; 444 } 445 446 InstructionPointer::InstructionPointer(ProfiledBinary *Binary, uint64_t Address, 447 bool RoundToNext) 448 : Binary(Binary), Address(Address) { 449 Index = Binary->getIndexForAddr(Address); 450 if (RoundToNext) { 451 // we might get address which is not the code 452 // it should round to the next valid address 453 this->Address = Binary->getAddressforIndex(Index); 454 } 455 } 456 457 void InstructionPointer::advance() { 458 Index++; 459 Address = Binary->getAddressforIndex(Index); 460 } 461 462 void InstructionPointer::backward() { 463 Index--; 464 Address = Binary->getAddressforIndex(Index); 465 } 466 467 void InstructionPointer::update(uint64_t Addr) { 468 Address = Addr; 469 Index = Binary->getIndexForAddr(Address); 470 } 471 472 } // end namespace sampleprof 473 } // end namespace llvm 474