Home | History | Annotate | Line # | Download | only in llvm-profgen
      1 //===-- ProfiledBinary.h - 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 #ifndef LLVM_TOOLS_LLVM_PROFGEN_PROFILEDBINARY_H
     10 #define LLVM_TOOLS_LLVM_PROFGEN_PROFILEDBINARY_H
     11 
     12 #include "CallContext.h"
     13 #include "PseudoProbe.h"
     14 #include "llvm/ADT/Optional.h"
     15 #include "llvm/ADT/StringRef.h"
     16 #include "llvm/DebugInfo/Symbolize/Symbolize.h"
     17 #include "llvm/MC/MCAsmInfo.h"
     18 #include "llvm/MC/MCContext.h"
     19 #include "llvm/MC/MCDisassembler/MCDisassembler.h"
     20 #include "llvm/MC/MCInst.h"
     21 #include "llvm/MC/MCInstPrinter.h"
     22 #include "llvm/MC/MCInstrAnalysis.h"
     23 #include "llvm/MC/MCInstrInfo.h"
     24 #include "llvm/MC/MCObjectFileInfo.h"
     25 #include "llvm/MC/MCRegisterInfo.h"
     26 #include "llvm/MC/MCSubtargetInfo.h"
     27 #include "llvm/MC/MCTargetOptions.h"
     28 #include "llvm/Object/ELFObjectFile.h"
     29 #include "llvm/ProfileData/SampleProf.h"
     30 #include "llvm/Support/Path.h"
     31 #include <list>
     32 #include <set>
     33 #include <sstream>
     34 #include <string>
     35 #include <unordered_map>
     36 #include <unordered_set>
     37 #include <vector>
     38 
     39 using namespace llvm;
     40 using namespace sampleprof;
     41 using namespace llvm::object;
     42 
     43 namespace llvm {
     44 namespace sampleprof {
     45 
     46 class ProfiledBinary;
     47 
     48 struct InstructionPointer {
     49   ProfiledBinary *Binary;
     50   union {
     51     // Offset of the executable segment of the binary.
     52     uint64_t Offset = 0;
     53     // Also used as address in unwinder
     54     uint64_t Address;
     55   };
     56   // Index to the sorted code address array of the binary.
     57   uint64_t Index = 0;
     58   InstructionPointer(ProfiledBinary *Binary, uint64_t Address,
     59                      bool RoundToNext = false);
     60   void advance();
     61   void backward();
     62   void update(uint64_t Addr);
     63 };
     64 
     65 // PrologEpilog offset tracker, used to filter out broken stack samples
     66 // Currently we use a heuristic size (two) to infer prolog and epilog
     67 // based on the start address and return address. In the future,
     68 // we will switch to Dwarf CFI based tracker
     69 struct PrologEpilogTracker {
     70   // A set of prolog and epilog offsets. Used by virtual unwinding.
     71   std::unordered_set<uint64_t> PrologEpilogSet;
     72   ProfiledBinary *Binary;
     73   PrologEpilogTracker(ProfiledBinary *Bin) : Binary(Bin){};
     74 
     75   // Take the two addresses from the start of function as prolog
     76   void inferPrologOffsets(
     77       std::unordered_map<uint64_t, std::string> &FuncStartAddrMap) {
     78     for (auto I : FuncStartAddrMap) {
     79       PrologEpilogSet.insert(I.first);
     80       InstructionPointer IP(Binary, I.first);
     81       IP.advance();
     82       PrologEpilogSet.insert(IP.Offset);
     83     }
     84   }
     85 
     86   // Take the last two addresses before the return address as epilog
     87   void inferEpilogOffsets(std::unordered_set<uint64_t> &RetAddrs) {
     88     for (auto Addr : RetAddrs) {
     89       PrologEpilogSet.insert(Addr);
     90       InstructionPointer IP(Binary, Addr);
     91       IP.backward();
     92       PrologEpilogSet.insert(IP.Offset);
     93     }
     94   }
     95 };
     96 
     97 class ProfiledBinary {
     98   // Absolute path of the binary.
     99   std::string Path;
    100   // The target triple.
    101   Triple TheTriple;
    102   // The runtime base address that the executable sections are loaded at.
    103   mutable uint64_t BaseAddress = 0;
    104   // The preferred base address that the executable sections are loaded at.
    105   uint64_t PreferredBaseAddress = 0;
    106   // Mutiple MC component info
    107   std::unique_ptr<const MCRegisterInfo> MRI;
    108   std::unique_ptr<const MCAsmInfo> AsmInfo;
    109   std::unique_ptr<const MCSubtargetInfo> STI;
    110   std::unique_ptr<const MCInstrInfo> MII;
    111   std::unique_ptr<MCDisassembler> DisAsm;
    112   std::unique_ptr<const MCInstrAnalysis> MIA;
    113   std::unique_ptr<MCInstPrinter> IPrinter;
    114   // A list of text sections sorted by start RVA and size. Used to check
    115   // if a given RVA is a valid code address.
    116   std::set<std::pair<uint64_t, uint64_t>> TextSections;
    117   // Function offset to name mapping.
    118   std::unordered_map<uint64_t, std::string> FuncStartAddrMap;
    119   // Offset to context location map. Used to expand the context.
    120   std::unordered_map<uint64_t, FrameLocationStack> Offset2LocStackMap;
    121   // An array of offsets of all instructions sorted in increasing order. The
    122   // sorting is needed to fast advance to the next forward/backward instruction.
    123   std::vector<uint64_t> CodeAddrs;
    124   // A set of call instruction offsets. Used by virtual unwinding.
    125   std::unordered_set<uint64_t> CallAddrs;
    126   // A set of return instruction offsets. Used by virtual unwinding.
    127   std::unordered_set<uint64_t> RetAddrs;
    128 
    129   PrologEpilogTracker ProEpilogTracker;
    130 
    131   // The symbolizer used to get inline context for an instruction.
    132   std::unique_ptr<symbolize::LLVMSymbolizer> Symbolizer;
    133 
    134   // Pseudo probe decoder
    135   PseudoProbeDecoder ProbeDecoder;
    136 
    137   bool UsePseudoProbes = false;
    138 
    139   void setPreferredBaseAddress(const ELFObjectFileBase *O);
    140 
    141   void decodePseudoProbe(const ELFObjectFileBase *Obj);
    142 
    143   // Set up disassembler and related components.
    144   void setUpDisassembler(const ELFObjectFileBase *Obj);
    145   void setupSymbolizer();
    146 
    147   /// Dissassemble the text section and build various address maps.
    148   void disassemble(const ELFObjectFileBase *O);
    149 
    150   /// Helper function to dissassemble the symbol and extract info for unwinding
    151   bool dissassembleSymbol(std::size_t SI, ArrayRef<uint8_t> Bytes,
    152                           SectionSymbolsTy &Symbols, const SectionRef &Section);
    153   /// Symbolize a given instruction pointer and return a full call context.
    154   FrameLocationStack symbolize(const InstructionPointer &IP,
    155                                bool UseCanonicalFnName = false);
    156 
    157   /// Decode the interesting parts of the binary and build internal data
    158   /// structures. On high level, the parts of interest are:
    159   ///   1. Text sections, including the main code section and the PLT
    160   ///   entries that will be used to handle cross-module call transitions.
    161   ///   2. The .debug_line section, used by Dwarf-based profile generation.
    162   ///   3. Pseudo probe related sections, used by probe-based profile
    163   ///   generation.
    164   void load();
    165   const FrameLocationStack &getFrameLocationStack(uint64_t Offset) const {
    166     auto I = Offset2LocStackMap.find(Offset);
    167     assert(I != Offset2LocStackMap.end() &&
    168            "Can't find location for offset in the binary");
    169     return I->second;
    170   }
    171 
    172 public:
    173   ProfiledBinary(StringRef Path) : Path(Path), ProEpilogTracker(this) {
    174     setupSymbolizer();
    175     load();
    176   }
    177   uint64_t virtualAddrToOffset(uint64_t VitualAddress) const {
    178     return VitualAddress - BaseAddress;
    179   }
    180   uint64_t offsetToVirtualAddr(uint64_t Offset) const {
    181     return Offset + BaseAddress;
    182   }
    183   StringRef getPath() const { return Path; }
    184   StringRef getName() const { return llvm::sys::path::filename(Path); }
    185   uint64_t getBaseAddress() const { return BaseAddress; }
    186   void setBaseAddress(uint64_t Address) { BaseAddress = Address; }
    187   uint64_t getPreferredBaseAddress() const { return PreferredBaseAddress; }
    188 
    189   bool addressIsCode(uint64_t Address) const {
    190     uint64_t Offset = virtualAddrToOffset(Address);
    191     return Offset2LocStackMap.find(Offset) != Offset2LocStackMap.end();
    192   }
    193   bool addressIsCall(uint64_t Address) const {
    194     uint64_t Offset = virtualAddrToOffset(Address);
    195     return CallAddrs.count(Offset);
    196   }
    197   bool addressIsReturn(uint64_t Address) const {
    198     uint64_t Offset = virtualAddrToOffset(Address);
    199     return RetAddrs.count(Offset);
    200   }
    201   bool addressInPrologEpilog(uint64_t Address) const {
    202     uint64_t Offset = virtualAddrToOffset(Address);
    203     return ProEpilogTracker.PrologEpilogSet.count(Offset);
    204   }
    205 
    206   uint64_t getAddressforIndex(uint64_t Index) const {
    207     return offsetToVirtualAddr(CodeAddrs[Index]);
    208   }
    209 
    210   bool usePseudoProbes() const { return UsePseudoProbes; }
    211   // Get the index in CodeAddrs for the address
    212   // As we might get an address which is not the code
    213   // here it would round to the next valid code address by
    214   // using lower bound operation
    215   uint32_t getIndexForAddr(uint64_t Address) const {
    216     uint64_t Offset = virtualAddrToOffset(Address);
    217     auto Low = llvm::lower_bound(CodeAddrs, Offset);
    218     return Low - CodeAddrs.begin();
    219   }
    220 
    221   uint64_t getCallAddrFromFrameAddr(uint64_t FrameAddr) const {
    222     return getAddressforIndex(getIndexForAddr(FrameAddr) - 1);
    223   }
    224 
    225   StringRef getFuncFromStartOffset(uint64_t Offset) {
    226     return FuncStartAddrMap[Offset];
    227   }
    228 
    229   Optional<FrameLocation> getInlineLeafFrameLoc(uint64_t Offset) {
    230     const auto &Stack = getFrameLocationStack(Offset);
    231     if (Stack.empty())
    232       return {};
    233     return Stack.back();
    234   }
    235 
    236   // Compare two addresses' inline context
    237   bool inlineContextEqual(uint64_t Add1, uint64_t Add2) const;
    238 
    239   // Get the context string of the current stack with inline context filled in.
    240   // It will search the disassembling info stored in Offset2LocStackMap. This is
    241   // used as the key of function sample map
    242   std::string getExpandedContextStr(const SmallVectorImpl<uint64_t> &Stack,
    243                                     bool &WasLeafInlined) const;
    244 
    245   const PseudoProbe *getCallProbeForAddr(uint64_t Address) const {
    246     return ProbeDecoder.getCallProbeForAddr(Address);
    247   }
    248   void
    249   getInlineContextForProbe(const PseudoProbe *Probe,
    250                            SmallVectorImpl<std::string> &InlineContextStack,
    251                            bool IncludeLeaf = false) const {
    252     return ProbeDecoder.getInlineContextForProbe(Probe, InlineContextStack,
    253                                                  IncludeLeaf);
    254   }
    255   const AddressProbesMap &getAddress2ProbesMap() const {
    256     return ProbeDecoder.getAddress2ProbesMap();
    257   }
    258   const PseudoProbeFuncDesc *getFuncDescForGUID(uint64_t GUID) {
    259     return ProbeDecoder.getFuncDescForGUID(GUID);
    260   }
    261   const PseudoProbeFuncDesc *getInlinerDescForProbe(const PseudoProbe *Probe) {
    262     return ProbeDecoder.getInlinerDescForProbe(Probe);
    263   }
    264 };
    265 
    266 } // end namespace sampleprof
    267 } // end namespace llvm
    268 
    269 #endif
    270