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 22 static cl::opt<bool> ShowDisassembly("show-disassembly", cl::ReallyHidden, 23 cl::init(false), cl::ZeroOrMore, 24 cl::desc("Print disassembled code.")); 25 26 static cl::opt<bool> ShowSourceLocations("show-source-locations", 27 cl::ReallyHidden, cl::init(false), 28 cl::ZeroOrMore, 29 cl::desc("Print source locations.")); 30 31 namespace llvm { 32 namespace sampleprof { 33 34 static const Target *getTarget(const ObjectFile *Obj) { 35 Triple TheTriple = Obj->makeTriple(); 36 std::string Error; 37 std::string ArchName; 38 const Target *TheTarget = 39 TargetRegistry::lookupTarget(ArchName, TheTriple, Error); 40 if (!TheTarget) 41 exitWithError(Error, Obj->getFileName()); 42 return TheTarget; 43 } 44 45 template <class ELFT> 46 static uint64_t getELFImageLMAForSec(const ELFFile<ELFT> &Obj, 47 const object::ELFSectionRef &Sec, 48 StringRef FileName) { 49 // Search for a PT_LOAD segment containing the requested section. Return this 50 // segment's p_addr as the image load address for the section. 51 const auto &PhdrRange = unwrapOrError(Obj.program_headers(), FileName); 52 for (const typename ELFT::Phdr &Phdr : PhdrRange) 53 if ((Phdr.p_type == ELF::PT_LOAD) && (Phdr.p_vaddr <= Sec.getAddress()) && 54 (Phdr.p_vaddr + Phdr.p_memsz > Sec.getAddress())) 55 // Segments will always be loaded at a page boundary. 56 return Phdr.p_paddr & ~(Phdr.p_align - 1U); 57 return 0; 58 } 59 60 // Get the image load address for a specific section. Note that an image is 61 // loaded by segments (a group of sections) and segments may not be consecutive 62 // in memory. 63 static uint64_t getELFImageLMAForSec(const object::ELFSectionRef &Sec) { 64 if (const auto *ELFObj = dyn_cast<ELF32LEObjectFile>(Sec.getObject())) 65 return getELFImageLMAForSec(ELFObj->getELFFile(), Sec, 66 ELFObj->getFileName()); 67 else if (const auto *ELFObj = dyn_cast<ELF32BEObjectFile>(Sec.getObject())) 68 return getELFImageLMAForSec(ELFObj->getELFFile(), Sec, 69 ELFObj->getFileName()); 70 else if (const auto *ELFObj = dyn_cast<ELF64LEObjectFile>(Sec.getObject())) 71 return getELFImageLMAForSec(ELFObj->getELFFile(), Sec, 72 ELFObj->getFileName()); 73 const auto *ELFObj = cast<ELF64BEObjectFile>(Sec.getObject()); 74 return getELFImageLMAForSec(ELFObj->getELFFile(), Sec, ELFObj->getFileName()); 75 } 76 77 void ProfiledBinary::load() { 78 // Attempt to open the binary. 79 OwningBinary<Binary> OBinary = unwrapOrError(createBinary(Path), Path); 80 Binary &Binary = *OBinary.getBinary(); 81 82 auto *Obj = dyn_cast<ELFObjectFileBase>(&Binary); 83 if (!Obj) 84 exitWithError("not a valid Elf image", Path); 85 86 TheTriple = Obj->makeTriple(); 87 // Current only support X86 88 if (!TheTriple.isX86()) 89 exitWithError("unsupported target", TheTriple.getTriple()); 90 LLVM_DEBUG(dbgs() << "Loading " << Path << "\n"); 91 92 // Find the preferred base address for text sections. 93 setPreferredBaseAddress(Obj); 94 95 // Disassemble the text sections. 96 disassemble(Obj); 97 98 // TODO: decode other sections. 99 100 return; 101 } 102 103 void ProfiledBinary::setPreferredBaseAddress(const ELFObjectFileBase *Obj) { 104 for (section_iterator SI = Obj->section_begin(), SE = Obj->section_end(); 105 SI != SE; ++SI) { 106 const SectionRef &Section = *SI; 107 if (Section.isText()) { 108 PreferredBaseAddress = getELFImageLMAForSec(Section); 109 return; 110 } 111 } 112 exitWithError("no text section found", Obj->getFileName()); 113 } 114 115 bool ProfiledBinary::dissassembleSymbol(std::size_t SI, ArrayRef<uint8_t> Bytes, 116 SectionSymbolsTy &Symbols, 117 const SectionRef &Section) { 118 119 std::size_t SE = Symbols.size(); 120 uint64_t SectionOffset = Section.getAddress() - PreferredBaseAddress; 121 uint64_t SectSize = Section.getSize(); 122 uint64_t StartOffset = Symbols[SI].Addr - PreferredBaseAddress; 123 uint64_t EndOffset = (SI + 1 < SE) 124 ? Symbols[SI + 1].Addr - PreferredBaseAddress 125 : SectionOffset + SectSize; 126 if (StartOffset >= EndOffset) 127 return true; 128 129 std::string &&SymbolName = Symbols[SI].Name.str(); 130 if (ShowDisassembly) 131 outs() << '<' << SymbolName << ">:\n"; 132 133 uint64_t Offset = StartOffset; 134 while (Offset < EndOffset) { 135 MCInst Inst; 136 uint64_t Size; 137 // Disassemble an instruction. 138 if (!DisAsm->getInstruction(Inst, Size, Bytes.slice(Offset - SectionOffset), 139 Offset + PreferredBaseAddress, nulls())) 140 return false; 141 142 if (ShowDisassembly) { 143 outs() << format("%8" PRIx64 ":", Offset); 144 size_t Start = outs().tell(); 145 IP->printInst(&Inst, Offset + Size, "", *STI.get(), outs()); 146 if (ShowSourceLocations) { 147 unsigned Cur = outs().tell() - Start; 148 if (Cur < 40) 149 outs().indent(40 - Cur); 150 InstructionPointer Inst(this, Offset); 151 outs() << getReversedLocWithContext(symbolize(Inst)); 152 } 153 outs() << "\n"; 154 } 155 156 const MCInstrDesc &MCDesc = MII->get(Inst.getOpcode()); 157 158 // Populate address maps. 159 CodeAddrs.push_back(Offset); 160 if (MCDesc.isCall()) 161 CallAddrs.insert(Offset); 162 else if (MCDesc.isReturn()) 163 RetAddrs.insert(Offset); 164 165 Offset += Size; 166 } 167 168 if (ShowDisassembly) 169 outs() << "\n"; 170 171 FuncStartAddrMap[StartOffset] = Symbols[SI].Name.str(); 172 return true; 173 } 174 175 void ProfiledBinary::setUpDisassembler(const ELFObjectFileBase *Obj) { 176 const Target *TheTarget = getTarget(Obj); 177 std::string TripleName = TheTriple.getTriple(); 178 StringRef FileName = Obj->getFileName(); 179 180 MRI.reset(TheTarget->createMCRegInfo(TripleName)); 181 if (!MRI) 182 exitWithError("no register info for target " + TripleName, FileName); 183 184 MCTargetOptions MCOptions; 185 AsmInfo.reset(TheTarget->createMCAsmInfo(*MRI, TripleName, MCOptions)); 186 if (!AsmInfo) 187 exitWithError("no assembly info for target " + TripleName, FileName); 188 189 SubtargetFeatures Features = Obj->getFeatures(); 190 STI.reset( 191 TheTarget->createMCSubtargetInfo(TripleName, "", Features.getString())); 192 if (!STI) 193 exitWithError("no subtarget info for target " + TripleName, FileName); 194 195 MII.reset(TheTarget->createMCInstrInfo()); 196 if (!MII) 197 exitWithError("no instruction info for target " + TripleName, FileName); 198 199 MCObjectFileInfo MOFI; 200 MCContext Ctx(AsmInfo.get(), MRI.get(), &MOFI); 201 MOFI.InitMCObjectFileInfo(Triple(TripleName), false, Ctx); 202 DisAsm.reset(TheTarget->createMCDisassembler(*STI, Ctx)); 203 if (!DisAsm) 204 exitWithError("no disassembler for target " + TripleName, FileName); 205 206 MIA.reset(TheTarget->createMCInstrAnalysis(MII.get())); 207 208 int AsmPrinterVariant = AsmInfo->getAssemblerDialect(); 209 IP.reset(TheTarget->createMCInstPrinter(Triple(TripleName), AsmPrinterVariant, 210 *AsmInfo, *MII, *MRI)); 211 IP->setPrintBranchImmAsAddress(true); 212 } 213 214 void ProfiledBinary::disassemble(const ELFObjectFileBase *Obj) { 215 // Set up disassembler and related components. 216 setUpDisassembler(Obj); 217 218 // Create a mapping from virtual address to symbol name. The symbols in text 219 // sections are the candidates to dissassemble. 220 std::map<SectionRef, SectionSymbolsTy> AllSymbols; 221 StringRef FileName = Obj->getFileName(); 222 for (const SymbolRef &Symbol : Obj->symbols()) { 223 const uint64_t Addr = unwrapOrError(Symbol.getAddress(), FileName); 224 const StringRef Name = unwrapOrError(Symbol.getName(), FileName); 225 section_iterator SecI = unwrapOrError(Symbol.getSection(), FileName); 226 if (SecI != Obj->section_end()) 227 AllSymbols[*SecI].push_back(SymbolInfoTy(Addr, Name, ELF::STT_NOTYPE)); 228 } 229 230 // Sort all the symbols. Use a stable sort to stabilize the output. 231 for (std::pair<const SectionRef, SectionSymbolsTy> &SecSyms : AllSymbols) 232 stable_sort(SecSyms.second); 233 234 if (ShowDisassembly) 235 outs() << "\nDisassembly of " << FileName << ":\n"; 236 237 // Dissassemble a text section. 238 for (section_iterator SI = Obj->section_begin(), SE = Obj->section_end(); 239 SI != SE; ++SI) { 240 const SectionRef &Section = *SI; 241 if (!Section.isText()) 242 continue; 243 244 uint64_t ImageLoadAddr = PreferredBaseAddress; 245 uint64_t SectionOffset = Section.getAddress() - ImageLoadAddr; 246 uint64_t SectSize = Section.getSize(); 247 if (!SectSize) 248 continue; 249 250 // Register the text section. 251 TextSections.insert({SectionOffset, SectSize}); 252 253 if (ShowDisassembly) { 254 StringRef SectionName = unwrapOrError(Section.getName(), FileName); 255 outs() << "\nDisassembly of section " << SectionName; 256 outs() << " [" << format("0x%" PRIx64, SectionOffset) << ", " 257 << format("0x%" PRIx64, SectionOffset + SectSize) << "]:\n\n"; 258 } 259 260 // Get the section data. 261 ArrayRef<uint8_t> Bytes = 262 arrayRefFromStringRef(unwrapOrError(Section.getContents(), FileName)); 263 264 // Get the list of all the symbols in this section. 265 SectionSymbolsTy &Symbols = AllSymbols[Section]; 266 267 // Disassemble symbol by symbol. 268 for (std::size_t SI = 0, SE = Symbols.size(); SI != SE; ++SI) { 269 if (!dissassembleSymbol(SI, Bytes, Symbols, Section)) 270 exitWithError("disassembling error", FileName); 271 } 272 } 273 } 274 275 void ProfiledBinary::setupSymbolizer() { 276 symbolize::LLVMSymbolizer::Options SymbolizerOpts; 277 SymbolizerOpts.PrintFunctions = 278 DILineInfoSpecifier::FunctionNameKind::LinkageName; 279 SymbolizerOpts.Demangle = false; 280 SymbolizerOpts.DefaultArch = TheTriple.getArchName().str(); 281 SymbolizerOpts.UseSymbolTable = false; 282 SymbolizerOpts.RelativeAddresses = false; 283 Symbolizer = std::make_unique<symbolize::LLVMSymbolizer>(SymbolizerOpts); 284 } 285 286 FrameLocationStack ProfiledBinary::symbolize(const InstructionPointer &IP) { 287 assert(this == IP.Binary && 288 "Binary should only symbolize its own instruction"); 289 auto Addr = object::SectionedAddress{IP.Offset + PreferredBaseAddress, 290 object::SectionedAddress::UndefSection}; 291 DIInliningInfo InlineStack = 292 unwrapOrError(Symbolizer->symbolizeInlinedCode(Path, Addr), getName()); 293 294 FrameLocationStack CallStack; 295 296 for (int32_t I = InlineStack.getNumberOfFrames() - 1; I >= 0; I--) { 297 const auto &CallerFrame = InlineStack.getFrame(I); 298 if (CallerFrame.FunctionName == "<invalid>") 299 break; 300 LineLocation Line(CallerFrame.Line - CallerFrame.StartLine, 301 CallerFrame.Discriminator); 302 FrameLocation Callsite(CallerFrame.FunctionName, Line); 303 CallStack.push_back(Callsite); 304 } 305 306 return CallStack; 307 } 308 309 } // end namespace sampleprof 310 } // end namespace llvm 311