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