ProfiledBinary.h 9.7 KB

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