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