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 uint64_t Offset = StartOffset; 221 while (Offset < EndOffset) { 222 MCInst Inst; 223 uint64_t Size; 224 // Disassemble an instruction. 225 if (!DisAsm->getInstruction(Inst, Size, Bytes.slice(Offset - SectionOffset), 226 Offset + PreferredBaseAddress, nulls())) 227 return false; 228 229 if (ShowDisassemblyOnly) { 230 if (ShowPseudoProbe) { 231 ProbeDecoder.printProbeForAddress(outs(), 232 Offset + PreferredBaseAddress); 233 } 234 outs() << format("%8" PRIx64 ":", Offset); 235 size_t Start = outs().tell(); 236 IPrinter->printInst(&Inst, Offset + Size, "", *STI.get(), outs()); 237 if (ShowSourceLocations) { 238 unsigned Cur = outs().tell() - Start; 239 if (Cur < 40) 240 outs().indent(40 - Cur); 241 InstructionPointer Inst(this, Offset); 242 outs() << getReversedLocWithContext(symbolize(Inst)); 243 } 244 outs() << "\n"; 245 } 246 247 const MCInstrDesc &MCDesc = MII->get(Inst.getOpcode()); 248 249 // Populate a vector of the symbolized callsite at this location 250 // We don't need symbolized info for probe-based profile, just use an empty 251 // stack as an entry to indicate a valid binary offset 252 FrameLocationStack SymbolizedCallStack; 253 if (!UsePseudoProbes) { 254 InstructionPointer IP(this, Offset); 255 SymbolizedCallStack = symbolize(IP, true); 256 } 257 Offset2LocStackMap[Offset] = SymbolizedCallStack; 258 // Populate address maps. 259 CodeAddrs.push_back(Offset); 260 if (MCDesc.isCall()) 261 CallAddrs.insert(Offset); 262 else if (MCDesc.isReturn()) 263 RetAddrs.insert(Offset); 264 265 Offset += Size; 266 } 267 268 if (ShowDisassemblyOnly) 269 outs() << "\n"; 270 271 FuncStartAddrMap[StartOffset] = Symbols[SI].Name.str(); 272 return true; 273 } 274 275 void ProfiledBinary::setUpDisassembler(const ELFObjectFileBase *Obj) { 276 const Target *TheTarget = getTarget(Obj); 277 std::string TripleName = TheTriple.getTriple(); 278 StringRef FileName = Obj->getFileName(); 279 280 MRI.reset(TheTarget->createMCRegInfo(TripleName)); 281 if (!MRI) 282 exitWithError("no register info for target " + TripleName, FileName); 283 284 MCTargetOptions MCOptions; 285 AsmInfo.reset(TheTarget->createMCAsmInfo(*MRI, TripleName, MCOptions)); 286 if (!AsmInfo) 287 exitWithError("no assembly info for target " + TripleName, FileName); 288 289 SubtargetFeatures Features = Obj->getFeatures(); 290 STI.reset( 291 TheTarget->createMCSubtargetInfo(TripleName, "", Features.getString())); 292 if (!STI) 293 exitWithError("no subtarget info for target " + TripleName, FileName); 294 295 MII.reset(TheTarget->createMCInstrInfo()); 296 if (!MII) 297 exitWithError("no instruction info for target " + TripleName, FileName); 298 299 MCObjectFileInfo MOFI; 300 MCContext Ctx(AsmInfo.get(), MRI.get(), &MOFI); 301 MOFI.InitMCObjectFileInfo(Triple(TripleName), false, Ctx); 302 DisAsm.reset(TheTarget->createMCDisassembler(*STI, Ctx)); 303 if (!DisAsm) 304 exitWithError("no disassembler for target " + TripleName, FileName); 305 306 MIA.reset(TheTarget->createMCInstrAnalysis(MII.get())); 307 308 int AsmPrinterVariant = AsmInfo->getAssemblerDialect(); 309 IPrinter.reset(TheTarget->createMCInstPrinter( 310 Triple(TripleName), AsmPrinterVariant, *AsmInfo, *MII, *MRI)); 311 IPrinter->setPrintBranchImmAsAddress(true); 312 } 313 314 void ProfiledBinary::disassemble(const ELFObjectFileBase *Obj) { 315 // Set up disassembler and related components. 316 setUpDisassembler(Obj); 317 318 // Create a mapping from virtual address to symbol name. The symbols in text 319 // sections are the candidates to dissassemble. 320 std::map<SectionRef, SectionSymbolsTy> AllSymbols; 321 StringRef FileName = Obj->getFileName(); 322 for (const SymbolRef &Symbol : Obj->symbols()) { 323 const uint64_t Addr = unwrapOrError(Symbol.getAddress(), FileName); 324 const StringRef Name = unwrapOrError(Symbol.getName(), FileName); 325 section_iterator SecI = unwrapOrError(Symbol.getSection(), FileName); 326 if (SecI != Obj->section_end()) 327 AllSymbols[*SecI].push_back(SymbolInfoTy(Addr, Name, ELF::STT_NOTYPE)); 328 } 329 330 // Sort all the symbols. Use a stable sort to stabilize the output. 331 for (std::pair<const SectionRef, SectionSymbolsTy> &SecSyms : AllSymbols) 332 stable_sort(SecSyms.second); 333 334 if (ShowDisassemblyOnly) 335 outs() << "\nDisassembly of " << FileName << ":\n"; 336 337 // Dissassemble a text section. 338 for (section_iterator SI = Obj->section_begin(), SE = Obj->section_end(); 339 SI != SE; ++SI) { 340 const SectionRef &Section = *SI; 341 if (!Section.isText()) 342 continue; 343 344 uint64_t ImageLoadAddr = PreferredBaseAddress; 345 uint64_t SectionOffset = Section.getAddress() - ImageLoadAddr; 346 uint64_t SectSize = Section.getSize(); 347 if (!SectSize) 348 continue; 349 350 // Register the text section. 351 TextSections.insert({SectionOffset, SectSize}); 352 353 if (ShowDisassemblyOnly) { 354 StringRef SectionName = unwrapOrError(Section.getName(), FileName); 355 outs() << "\nDisassembly of section " << SectionName; 356 outs() << " [" << format("0x%" PRIx64, SectionOffset) << ", " 357 << format("0x%" PRIx64, SectionOffset + SectSize) << "]:\n\n"; 358 } 359 360 // Get the section data. 361 ArrayRef<uint8_t> Bytes = 362 arrayRefFromStringRef(unwrapOrError(Section.getContents(), FileName)); 363 364 // Get the list of all the symbols in this section. 365 SectionSymbolsTy &Symbols = AllSymbols[Section]; 366 367 // Disassemble symbol by symbol. 368 for (std::size_t SI = 0, SE = Symbols.size(); SI != SE; ++SI) { 369 if (!dissassembleSymbol(SI, Bytes, Symbols, Section)) 370 exitWithError("disassembling error", FileName); 371 } 372 } 373 } 374 375 void ProfiledBinary::setupSymbolizer() { 376 symbolize::LLVMSymbolizer::Options SymbolizerOpts; 377 SymbolizerOpts.PrintFunctions = 378 DILineInfoSpecifier::FunctionNameKind::LinkageName; 379 SymbolizerOpts.Demangle = false; 380 SymbolizerOpts.DefaultArch = TheTriple.getArchName().str(); 381 SymbolizerOpts.UseSymbolTable = false; 382 SymbolizerOpts.RelativeAddresses = false; 383 Symbolizer = std::make_unique<symbolize::LLVMSymbolizer>(SymbolizerOpts); 384 } 385 386 FrameLocationStack ProfiledBinary::symbolize(const InstructionPointer &IP, 387 bool UseCanonicalFnName) { 388 assert(this == IP.Binary && 389 "Binary should only symbolize its own instruction"); 390 auto Addr = object::SectionedAddress{IP.Offset + PreferredBaseAddress, 391 object::SectionedAddress::UndefSection}; 392 DIInliningInfo InlineStack = 393 unwrapOrError(Symbolizer->symbolizeInlinedCode(Path, Addr), getName()); 394 395 FrameLocationStack CallStack; 396 397 for (int32_t I = InlineStack.getNumberOfFrames() - 1; I >= 0; I--) { 398 const auto &CallerFrame = InlineStack.getFrame(I); 399 if (CallerFrame.FunctionName == "<invalid>") 400 break; 401 StringRef FunctionName(CallerFrame.FunctionName); 402 if (UseCanonicalFnName) 403 FunctionName = FunctionSamples::getCanonicalFnName(FunctionName); 404 LineLocation Line(CallerFrame.Line - CallerFrame.StartLine, 405 DILocation::getBaseDiscriminatorFromDiscriminator( 406 CallerFrame.Discriminator)); 407 FrameLocation Callsite(FunctionName.str(), Line); 408 CallStack.push_back(Callsite); 409 } 410 411 return CallStack; 412 } 413 414 InstructionPointer::InstructionPointer(ProfiledBinary *Binary, uint64_t Address, 415 bool RoundToNext) 416 : Binary(Binary), Address(Address) { 417 Index = Binary->getIndexForAddr(Address); 418 if (RoundToNext) { 419 // we might get address which is not the code 420 // it should round to the next valid address 421 this->Address = Binary->getAddressforIndex(Index); 422 } 423 } 424 425 void InstructionPointer::advance() { 426 Index++; 427 Address = Binary->getAddressforIndex(Index); 428 } 429 430 void InstructionPointer::backward() { 431 Index--; 432 Address = Binary->getAddressforIndex(Index); 433 } 434 435 void InstructionPointer::update(uint64_t Addr) { 436 Address = Addr; 437 Index = Binary->getIndexForAddr(Address); 438 } 439 440 } // end namespace sampleprof 441 } // end namespace llvm 442