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