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