ProfiledBinary.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790
  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. #include "ProfiledBinary.h"
  9. #include "ErrorHandling.h"
  10. #include "ProfileGenerator.h"
  11. #include "llvm/ADT/Triple.h"
  12. #include "llvm/Demangle/Demangle.h"
  13. #include "llvm/IR/DebugInfoMetadata.h"
  14. #include "llvm/MC/TargetRegistry.h"
  15. #include "llvm/Support/CommandLine.h"
  16. #include "llvm/Support/Format.h"
  17. #include "llvm/Support/TargetSelect.h"
  18. #define DEBUG_TYPE "load-binary"
  19. using namespace llvm;
  20. using namespace sampleprof;
  21. cl::opt<bool> ShowDisassemblyOnly("show-disassembly-only", cl::init(false),
  22. cl::ZeroOrMore,
  23. cl::desc("Print disassembled code."));
  24. cl::opt<bool> ShowSourceLocations("show-source-locations", cl::init(false),
  25. cl::ZeroOrMore,
  26. cl::desc("Print source locations."));
  27. static cl::opt<bool>
  28. ShowCanonicalFnName("show-canonical-fname", cl::init(false), cl::ZeroOrMore,
  29. cl::desc("Print canonical function name."));
  30. static cl::opt<bool> ShowPseudoProbe(
  31. "show-pseudo-probe", cl::init(false), cl::ZeroOrMore,
  32. cl::desc("Print pseudo probe section and disassembled info."));
  33. static cl::opt<bool> UseDwarfCorrelation(
  34. "use-dwarf-correlation", cl::init(false), cl::ZeroOrMore,
  35. cl::desc("Use dwarf for profile correlation even when binary contains "
  36. "pseudo probe."));
  37. static cl::list<std::string> DisassembleFunctions(
  38. "disassemble-functions", cl::CommaSeparated,
  39. cl::desc("List of functions to print disassembly for. Accept demangled "
  40. "names only. Only work with show-disassembly-only"));
  41. extern cl::opt<bool> ShowDetailedWarning;
  42. namespace llvm {
  43. namespace sampleprof {
  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. void BinarySizeContextTracker::addInstructionForContext(
  55. const SampleContextFrameVector &Context, uint32_t InstrSize) {
  56. ContextTrieNode *CurNode = &RootContext;
  57. bool IsLeaf = true;
  58. for (const auto &Callsite : reverse(Context)) {
  59. StringRef CallerName = Callsite.FuncName;
  60. LineLocation CallsiteLoc = IsLeaf ? LineLocation(0, 0) : Callsite.Location;
  61. CurNode = CurNode->getOrCreateChildContext(CallsiteLoc, CallerName);
  62. IsLeaf = false;
  63. }
  64. CurNode->addFunctionSize(InstrSize);
  65. }
  66. uint32_t
  67. BinarySizeContextTracker::getFuncSizeForContext(const SampleContext &Context) {
  68. ContextTrieNode *CurrNode = &RootContext;
  69. ContextTrieNode *PrevNode = nullptr;
  70. SampleContextFrames Frames = Context.getContextFrames();
  71. int32_t I = Frames.size() - 1;
  72. Optional<uint32_t> Size;
  73. // Start from top-level context-less function, traverse down the reverse
  74. // context trie to find the best/longest match for given context, then
  75. // retrieve the size.
  76. while (CurrNode && I >= 0) {
  77. // Process from leaf function to callers (added to context).
  78. const auto &ChildFrame = Frames[I--];
  79. PrevNode = CurrNode;
  80. CurrNode =
  81. CurrNode->getChildContext(ChildFrame.Location, ChildFrame.FuncName);
  82. if (CurrNode && CurrNode->getFunctionSize().hasValue())
  83. Size = CurrNode->getFunctionSize().getValue();
  84. }
  85. // If we traversed all nodes along the path of the context and haven't
  86. // found a size yet, pivot to look for size from sibling nodes, i.e size
  87. // of inlinee under different context.
  88. if (!Size.hasValue()) {
  89. if (!CurrNode)
  90. CurrNode = PrevNode;
  91. while (!Size.hasValue() && CurrNode &&
  92. !CurrNode->getAllChildContext().empty()) {
  93. CurrNode = &CurrNode->getAllChildContext().begin()->second;
  94. if (CurrNode->getFunctionSize().hasValue())
  95. Size = CurrNode->getFunctionSize().getValue();
  96. }
  97. }
  98. assert(Size.hasValue() && "We should at least find one context size.");
  99. return Size.getValue();
  100. }
  101. void BinarySizeContextTracker::trackInlineesOptimizedAway(
  102. MCPseudoProbeDecoder &ProbeDecoder) {
  103. ProbeFrameStack ProbeContext;
  104. for (const auto &Child : ProbeDecoder.getDummyInlineRoot().getChildren())
  105. trackInlineesOptimizedAway(ProbeDecoder, *Child.second.get(), ProbeContext);
  106. }
  107. void BinarySizeContextTracker::trackInlineesOptimizedAway(
  108. MCPseudoProbeDecoder &ProbeDecoder,
  109. MCDecodedPseudoProbeInlineTree &ProbeNode, ProbeFrameStack &ProbeContext) {
  110. StringRef FuncName =
  111. ProbeDecoder.getFuncDescForGUID(ProbeNode.Guid)->FuncName;
  112. ProbeContext.emplace_back(FuncName, 0);
  113. // This ProbeContext has a probe, so it has code before inlining and
  114. // optimization. Make sure we mark its size as known.
  115. if (!ProbeNode.getProbes().empty()) {
  116. ContextTrieNode *SizeContext = &RootContext;
  117. for (auto &ProbeFrame : reverse(ProbeContext)) {
  118. StringRef CallerName = ProbeFrame.first;
  119. LineLocation CallsiteLoc(ProbeFrame.second, 0);
  120. SizeContext =
  121. SizeContext->getOrCreateChildContext(CallsiteLoc, CallerName);
  122. }
  123. // Add 0 size to make known.
  124. SizeContext->addFunctionSize(0);
  125. }
  126. // DFS down the probe inline tree
  127. for (const auto &ChildNode : ProbeNode.getChildren()) {
  128. InlineSite Location = ChildNode.first;
  129. ProbeContext.back().second = std::get<1>(Location);
  130. trackInlineesOptimizedAway(ProbeDecoder, *ChildNode.second.get(), ProbeContext);
  131. }
  132. ProbeContext.pop_back();
  133. }
  134. void ProfiledBinary::warnNoFuncEntry() {
  135. uint64_t NoFuncEntryNum = 0;
  136. for (auto &F : BinaryFunctions) {
  137. if (F.second.Ranges.empty())
  138. continue;
  139. bool hasFuncEntry = false;
  140. for (auto &R : F.second.Ranges) {
  141. if (FuncRange *FR = findFuncRangeForStartOffset(R.first)) {
  142. if (FR->IsFuncEntry) {
  143. hasFuncEntry = true;
  144. break;
  145. }
  146. }
  147. }
  148. if (!hasFuncEntry) {
  149. NoFuncEntryNum++;
  150. if (ShowDetailedWarning)
  151. WithColor::warning()
  152. << "Failed to determine function entry for " << F.first
  153. << " due to inconsistent name from symbol table and dwarf info.\n";
  154. }
  155. }
  156. emitWarningSummary(NoFuncEntryNum, BinaryFunctions.size(),
  157. "of functions failed to determine function entry due to "
  158. "inconsistent name from symbol table and dwarf info.");
  159. }
  160. void ProfiledBinary::load() {
  161. // Attempt to open the binary.
  162. OwningBinary<Binary> OBinary = unwrapOrError(createBinary(Path), Path);
  163. Binary &ExeBinary = *OBinary.getBinary();
  164. auto *Obj = dyn_cast<ELFObjectFileBase>(&ExeBinary);
  165. if (!Obj)
  166. exitWithError("not a valid Elf image", Path);
  167. TheTriple = Obj->makeTriple();
  168. // Current only support X86
  169. if (!TheTriple.isX86())
  170. exitWithError("unsupported target", TheTriple.getTriple());
  171. LLVM_DEBUG(dbgs() << "Loading " << Path << "\n");
  172. // Find the preferred load address for text sections.
  173. setPreferredTextSegmentAddresses(Obj);
  174. // Decode pseudo probe related section
  175. decodePseudoProbe(Obj);
  176. // Load debug info of subprograms from DWARF section.
  177. // If path of debug info binary is specified, use the debug info from it,
  178. // otherwise use the debug info from the executable binary.
  179. if (!DebugBinaryPath.empty()) {
  180. OwningBinary<Binary> DebugPath =
  181. unwrapOrError(createBinary(DebugBinaryPath), DebugBinaryPath);
  182. loadSymbolsFromDWARF(*dyn_cast<ObjectFile>(DebugPath.getBinary()));
  183. } else {
  184. loadSymbolsFromDWARF(*dyn_cast<ObjectFile>(&ExeBinary));
  185. }
  186. // Disassemble the text sections.
  187. disassemble(Obj);
  188. // Track size for optimized inlinees when probe is available
  189. if (UsePseudoProbes && TrackFuncContextSize)
  190. FuncSizeTracker.trackInlineesOptimizedAway(ProbeDecoder);
  191. // Use function start and return address to infer prolog and epilog
  192. ProEpilogTracker.inferPrologOffsets(StartOffset2FuncRangeMap);
  193. ProEpilogTracker.inferEpilogOffsets(RetOffsets);
  194. warnNoFuncEntry();
  195. // TODO: decode other sections.
  196. }
  197. bool ProfiledBinary::inlineContextEqual(uint64_t Address1, uint64_t Address2) {
  198. uint64_t Offset1 = virtualAddrToOffset(Address1);
  199. uint64_t Offset2 = virtualAddrToOffset(Address2);
  200. const SampleContextFrameVector &Context1 = getFrameLocationStack(Offset1);
  201. const SampleContextFrameVector &Context2 = getFrameLocationStack(Offset2);
  202. if (Context1.size() != Context2.size())
  203. return false;
  204. if (Context1.empty())
  205. return false;
  206. // The leaf frame contains location within the leaf, and it
  207. // needs to be remove that as it's not part of the calling context
  208. return std::equal(Context1.begin(), Context1.begin() + Context1.size() - 1,
  209. Context2.begin(), Context2.begin() + Context2.size() - 1);
  210. }
  211. SampleContextFrameVector
  212. ProfiledBinary::getExpandedContext(const SmallVectorImpl<uint64_t> &Stack,
  213. bool &WasLeafInlined) {
  214. SampleContextFrameVector ContextVec;
  215. // Process from frame root to leaf
  216. for (auto Address : Stack) {
  217. uint64_t Offset = virtualAddrToOffset(Address);
  218. const SampleContextFrameVector &ExpandedContext =
  219. getFrameLocationStack(Offset);
  220. // An instruction without a valid debug line will be ignored by sample
  221. // processing
  222. if (ExpandedContext.empty())
  223. return SampleContextFrameVector();
  224. // Set WasLeafInlined to the size of inlined frame count for the last
  225. // address which is leaf
  226. WasLeafInlined = (ExpandedContext.size() > 1);
  227. ContextVec.append(ExpandedContext);
  228. }
  229. // Replace with decoded base discriminator
  230. for (auto &Frame : ContextVec) {
  231. Frame.Location.Discriminator = ProfileGeneratorBase::getBaseDiscriminator(
  232. Frame.Location.Discriminator, UseFSDiscriminator);
  233. }
  234. assert(ContextVec.size() && "Context length should be at least 1");
  235. // Compress the context string except for the leaf frame
  236. auto LeafFrame = ContextVec.back();
  237. LeafFrame.Location = LineLocation(0, 0);
  238. ContextVec.pop_back();
  239. CSProfileGenerator::compressRecursionContext(ContextVec);
  240. CSProfileGenerator::trimContext(ContextVec);
  241. ContextVec.push_back(LeafFrame);
  242. return ContextVec;
  243. }
  244. template <class ELFT>
  245. void ProfiledBinary::setPreferredTextSegmentAddresses(const ELFFile<ELFT> &Obj, StringRef FileName) {
  246. const auto &PhdrRange = unwrapOrError(Obj.program_headers(), FileName);
  247. // FIXME: This should be the page size of the system running profiling.
  248. // However such info isn't available at post-processing time, assuming
  249. // 4K page now. Note that we don't use EXEC_PAGESIZE from <linux/param.h>
  250. // because we may build the tools on non-linux.
  251. uint32_t PageSize = 0x1000;
  252. for (const typename ELFT::Phdr &Phdr : PhdrRange) {
  253. if (Phdr.p_type == ELF::PT_LOAD) {
  254. if (!FirstLoadableAddress)
  255. FirstLoadableAddress = Phdr.p_vaddr & ~(PageSize - 1U);
  256. if (Phdr.p_flags & ELF::PF_X) {
  257. // Segments will always be loaded at a page boundary.
  258. PreferredTextSegmentAddresses.push_back(Phdr.p_vaddr &
  259. ~(PageSize - 1U));
  260. TextSegmentOffsets.push_back(Phdr.p_offset & ~(PageSize - 1U));
  261. }
  262. }
  263. }
  264. if (PreferredTextSegmentAddresses.empty())
  265. exitWithError("no executable segment found", FileName);
  266. }
  267. void ProfiledBinary::setPreferredTextSegmentAddresses(const ELFObjectFileBase *Obj) {
  268. if (const auto *ELFObj = dyn_cast<ELF32LEObjectFile>(Obj))
  269. setPreferredTextSegmentAddresses(ELFObj->getELFFile(), Obj->getFileName());
  270. else if (const auto *ELFObj = dyn_cast<ELF32BEObjectFile>(Obj))
  271. setPreferredTextSegmentAddresses(ELFObj->getELFFile(), Obj->getFileName());
  272. else if (const auto *ELFObj = dyn_cast<ELF64LEObjectFile>(Obj))
  273. setPreferredTextSegmentAddresses(ELFObj->getELFFile(), Obj->getFileName());
  274. else if (const auto *ELFObj = cast<ELF64BEObjectFile>(Obj))
  275. setPreferredTextSegmentAddresses(ELFObj->getELFFile(), Obj->getFileName());
  276. else
  277. llvm_unreachable("invalid ELF object format");
  278. }
  279. void ProfiledBinary::decodePseudoProbe(const ELFObjectFileBase *Obj) {
  280. if (UseDwarfCorrelation)
  281. return;
  282. StringRef FileName = Obj->getFileName();
  283. for (section_iterator SI = Obj->section_begin(), SE = Obj->section_end();
  284. SI != SE; ++SI) {
  285. const SectionRef &Section = *SI;
  286. StringRef SectionName = unwrapOrError(Section.getName(), FileName);
  287. if (SectionName == ".pseudo_probe_desc") {
  288. StringRef Contents = unwrapOrError(Section.getContents(), FileName);
  289. if (!ProbeDecoder.buildGUID2FuncDescMap(
  290. reinterpret_cast<const uint8_t *>(Contents.data()),
  291. Contents.size()))
  292. exitWithError("Pseudo Probe decoder fail in .pseudo_probe_desc section");
  293. } else if (SectionName == ".pseudo_probe") {
  294. StringRef Contents = unwrapOrError(Section.getContents(), FileName);
  295. if (!ProbeDecoder.buildAddress2ProbeMap(
  296. reinterpret_cast<const uint8_t *>(Contents.data()),
  297. Contents.size()))
  298. exitWithError("Pseudo Probe decoder fail in .pseudo_probe section");
  299. // set UsePseudoProbes flag, used for PerfReader
  300. UsePseudoProbes = true;
  301. }
  302. }
  303. if (ShowPseudoProbe)
  304. ProbeDecoder.printGUID2FuncDescMap(outs());
  305. }
  306. void ProfiledBinary::setIsFuncEntry(uint64_t Offset, StringRef RangeSymName) {
  307. // Note that the start offset of each ELF section can be a non-function
  308. // symbol, we need to binary search for the start of a real function range.
  309. auto *FuncRange = findFuncRangeForOffset(Offset);
  310. // Skip external function symbol.
  311. if (!FuncRange)
  312. return;
  313. // Set IsFuncEntry to ture if there is only one range in the function or the
  314. // RangeSymName from ELF is equal to its DWARF-based function name.
  315. if (FuncRange->Func->Ranges.size() == 1 ||
  316. (!FuncRange->IsFuncEntry && FuncRange->getFuncName() == RangeSymName))
  317. FuncRange->IsFuncEntry = true;
  318. }
  319. bool ProfiledBinary::dissassembleSymbol(std::size_t SI, ArrayRef<uint8_t> Bytes,
  320. SectionSymbolsTy &Symbols,
  321. const SectionRef &Section) {
  322. std::size_t SE = Symbols.size();
  323. uint64_t SectionOffset = Section.getAddress() - getPreferredBaseAddress();
  324. uint64_t SectSize = Section.getSize();
  325. uint64_t StartOffset = Symbols[SI].Addr - getPreferredBaseAddress();
  326. uint64_t NextStartOffset =
  327. (SI + 1 < SE) ? Symbols[SI + 1].Addr - getPreferredBaseAddress()
  328. : SectionOffset + SectSize;
  329. setIsFuncEntry(StartOffset,
  330. FunctionSamples::getCanonicalFnName(Symbols[SI].Name));
  331. StringRef SymbolName =
  332. ShowCanonicalFnName
  333. ? FunctionSamples::getCanonicalFnName(Symbols[SI].Name)
  334. : Symbols[SI].Name;
  335. bool ShowDisassembly =
  336. ShowDisassemblyOnly && (DisassembleFunctionSet.empty() ||
  337. DisassembleFunctionSet.count(SymbolName));
  338. if (ShowDisassembly)
  339. outs() << '<' << SymbolName << ">:\n";
  340. auto WarnInvalidInsts = [](uint64_t Start, uint64_t End) {
  341. WithColor::warning() << "Invalid instructions at "
  342. << format("%8" PRIx64, Start) << " - "
  343. << format("%8" PRIx64, End) << "\n";
  344. };
  345. uint64_t Offset = StartOffset;
  346. // Size of a consecutive invalid instruction range starting from Offset -1
  347. // backwards.
  348. uint64_t InvalidInstLength = 0;
  349. while (Offset < NextStartOffset) {
  350. MCInst Inst;
  351. uint64_t Size;
  352. // Disassemble an instruction.
  353. bool Disassembled =
  354. DisAsm->getInstruction(Inst, Size, Bytes.slice(Offset - SectionOffset),
  355. Offset + getPreferredBaseAddress(), nulls());
  356. if (Size == 0)
  357. Size = 1;
  358. if (ShowDisassembly) {
  359. if (ShowPseudoProbe) {
  360. ProbeDecoder.printProbeForAddress(outs(),
  361. Offset + getPreferredBaseAddress());
  362. }
  363. outs() << format("%8" PRIx64 ":", Offset + getPreferredBaseAddress());
  364. size_t Start = outs().tell();
  365. if (Disassembled)
  366. IPrinter->printInst(&Inst, Offset + Size, "", *STI.get(), outs());
  367. else
  368. outs() << "\t<unknown>";
  369. if (ShowSourceLocations) {
  370. unsigned Cur = outs().tell() - Start;
  371. if (Cur < 40)
  372. outs().indent(40 - Cur);
  373. InstructionPointer IP(this, Offset);
  374. outs() << getReversedLocWithContext(
  375. symbolize(IP, ShowCanonicalFnName, ShowPseudoProbe));
  376. }
  377. outs() << "\n";
  378. }
  379. if (Disassembled) {
  380. const MCInstrDesc &MCDesc = MII->get(Inst.getOpcode());
  381. // Record instruction size.
  382. Offset2InstSizeMap[Offset] = Size;
  383. // Populate address maps.
  384. CodeAddrOffsets.push_back(Offset);
  385. if (MCDesc.isCall())
  386. CallOffsets.insert(Offset);
  387. else if (MCDesc.isReturn())
  388. RetOffsets.insert(Offset);
  389. else if (MCDesc.isBranch())
  390. BranchOffsets.insert(Offset);
  391. if (InvalidInstLength) {
  392. WarnInvalidInsts(Offset - InvalidInstLength, Offset - 1);
  393. InvalidInstLength = 0;
  394. }
  395. } else {
  396. InvalidInstLength += Size;
  397. }
  398. Offset += Size;
  399. }
  400. if (InvalidInstLength)
  401. WarnInvalidInsts(Offset - InvalidInstLength, Offset - 1);
  402. if (ShowDisassembly)
  403. outs() << "\n";
  404. return true;
  405. }
  406. void ProfiledBinary::setUpDisassembler(const ELFObjectFileBase *Obj) {
  407. const Target *TheTarget = getTarget(Obj);
  408. std::string TripleName = TheTriple.getTriple();
  409. StringRef FileName = Obj->getFileName();
  410. MRI.reset(TheTarget->createMCRegInfo(TripleName));
  411. if (!MRI)
  412. exitWithError("no register info for target " + TripleName, FileName);
  413. MCTargetOptions MCOptions;
  414. AsmInfo.reset(TheTarget->createMCAsmInfo(*MRI, TripleName, MCOptions));
  415. if (!AsmInfo)
  416. exitWithError("no assembly info for target " + TripleName, FileName);
  417. SubtargetFeatures Features = Obj->getFeatures();
  418. STI.reset(
  419. TheTarget->createMCSubtargetInfo(TripleName, "", Features.getString()));
  420. if (!STI)
  421. exitWithError("no subtarget info for target " + TripleName, FileName);
  422. MII.reset(TheTarget->createMCInstrInfo());
  423. if (!MII)
  424. exitWithError("no instruction info for target " + TripleName, FileName);
  425. MCContext Ctx(Triple(TripleName), AsmInfo.get(), MRI.get(), STI.get());
  426. std::unique_ptr<MCObjectFileInfo> MOFI(
  427. TheTarget->createMCObjectFileInfo(Ctx, /*PIC=*/false));
  428. Ctx.setObjectFileInfo(MOFI.get());
  429. DisAsm.reset(TheTarget->createMCDisassembler(*STI, Ctx));
  430. if (!DisAsm)
  431. exitWithError("no disassembler for target " + TripleName, FileName);
  432. MIA.reset(TheTarget->createMCInstrAnalysis(MII.get()));
  433. int AsmPrinterVariant = AsmInfo->getAssemblerDialect();
  434. IPrinter.reset(TheTarget->createMCInstPrinter(
  435. Triple(TripleName), AsmPrinterVariant, *AsmInfo, *MII, *MRI));
  436. IPrinter->setPrintBranchImmAsAddress(true);
  437. }
  438. void ProfiledBinary::disassemble(const ELFObjectFileBase *Obj) {
  439. // Set up disassembler and related components.
  440. setUpDisassembler(Obj);
  441. // Create a mapping from virtual address to symbol name. The symbols in text
  442. // sections are the candidates to dissassemble.
  443. std::map<SectionRef, SectionSymbolsTy> AllSymbols;
  444. StringRef FileName = Obj->getFileName();
  445. for (const SymbolRef &Symbol : Obj->symbols()) {
  446. const uint64_t Addr = unwrapOrError(Symbol.getAddress(), FileName);
  447. const StringRef Name = unwrapOrError(Symbol.getName(), FileName);
  448. section_iterator SecI = unwrapOrError(Symbol.getSection(), FileName);
  449. if (SecI != Obj->section_end())
  450. AllSymbols[*SecI].push_back(SymbolInfoTy(Addr, Name, ELF::STT_NOTYPE));
  451. }
  452. // Sort all the symbols. Use a stable sort to stabilize the output.
  453. for (std::pair<const SectionRef, SectionSymbolsTy> &SecSyms : AllSymbols)
  454. stable_sort(SecSyms.second);
  455. DisassembleFunctionSet.insert(DisassembleFunctions.begin(),
  456. DisassembleFunctions.end());
  457. assert((DisassembleFunctionSet.empty() || ShowDisassemblyOnly) &&
  458. "Functions to disassemble should be only specified together with "
  459. "--show-disassembly-only");
  460. if (ShowDisassemblyOnly)
  461. outs() << "\nDisassembly of " << FileName << ":\n";
  462. // Dissassemble a text section.
  463. for (section_iterator SI = Obj->section_begin(), SE = Obj->section_end();
  464. SI != SE; ++SI) {
  465. const SectionRef &Section = *SI;
  466. if (!Section.isText())
  467. continue;
  468. uint64_t ImageLoadAddr = getPreferredBaseAddress();
  469. uint64_t SectionOffset = Section.getAddress() - ImageLoadAddr;
  470. uint64_t SectSize = Section.getSize();
  471. if (!SectSize)
  472. continue;
  473. // Register the text section.
  474. TextSections.insert({SectionOffset, SectSize});
  475. StringRef SectionName = unwrapOrError(Section.getName(), FileName);
  476. if (ShowDisassemblyOnly) {
  477. outs() << "\nDisassembly of section " << SectionName;
  478. outs() << " [" << format("0x%" PRIx64, Section.getAddress()) << ", "
  479. << format("0x%" PRIx64, Section.getAddress() + SectSize)
  480. << "]:\n\n";
  481. }
  482. if (SectionName == ".plt")
  483. continue;
  484. // Get the section data.
  485. ArrayRef<uint8_t> Bytes =
  486. arrayRefFromStringRef(unwrapOrError(Section.getContents(), FileName));
  487. // Get the list of all the symbols in this section.
  488. SectionSymbolsTy &Symbols = AllSymbols[Section];
  489. // Disassemble symbol by symbol.
  490. for (std::size_t SI = 0, SE = Symbols.size(); SI != SE; ++SI) {
  491. if (!dissassembleSymbol(SI, Bytes, Symbols, Section))
  492. exitWithError("disassembling error", FileName);
  493. }
  494. }
  495. // Dissassemble rodata section to check if FS discriminator symbol exists.
  496. checkUseFSDiscriminator(Obj, AllSymbols);
  497. }
  498. void ProfiledBinary::checkUseFSDiscriminator(
  499. const ELFObjectFileBase *Obj,
  500. std::map<SectionRef, SectionSymbolsTy> &AllSymbols) {
  501. const char *FSDiscriminatorVar = "__llvm_fs_discriminator__";
  502. for (section_iterator SI = Obj->section_begin(), SE = Obj->section_end();
  503. SI != SE; ++SI) {
  504. const SectionRef &Section = *SI;
  505. if (!Section.isData() || Section.getSize() == 0)
  506. continue;
  507. SectionSymbolsTy &Symbols = AllSymbols[Section];
  508. for (std::size_t SI = 0, SE = Symbols.size(); SI != SE; ++SI) {
  509. if (Symbols[SI].Name == FSDiscriminatorVar) {
  510. UseFSDiscriminator = true;
  511. return;
  512. }
  513. }
  514. }
  515. }
  516. void ProfiledBinary::loadSymbolsFromDWARF(ObjectFile &Obj) {
  517. auto DebugContext = llvm::DWARFContext::create(Obj);
  518. if (!DebugContext)
  519. exitWithError("Misssing debug info.", Path);
  520. for (const auto &CompilationUnit : DebugContext->compile_units()) {
  521. for (const auto &DieInfo : CompilationUnit->dies()) {
  522. llvm::DWARFDie Die(CompilationUnit.get(), &DieInfo);
  523. if (!Die.isSubprogramDIE())
  524. continue;
  525. auto Name = Die.getName(llvm::DINameKind::LinkageName);
  526. if (!Name)
  527. Name = Die.getName(llvm::DINameKind::ShortName);
  528. if (!Name)
  529. continue;
  530. auto RangesOrError = Die.getAddressRanges();
  531. if (!RangesOrError)
  532. continue;
  533. const DWARFAddressRangesVector &Ranges = RangesOrError.get();
  534. if (Ranges.empty())
  535. continue;
  536. // Different DWARF symbols can have same function name, search or create
  537. // BinaryFunction indexed by the name.
  538. auto Ret = BinaryFunctions.emplace(Name, BinaryFunction());
  539. auto &Func = Ret.first->second;
  540. if (Ret.second)
  541. Func.FuncName = Ret.first->first;
  542. for (const auto &Range : Ranges) {
  543. uint64_t FuncStart = Range.LowPC;
  544. uint64_t FuncSize = Range.HighPC - FuncStart;
  545. if (FuncSize == 0 || FuncStart < getPreferredBaseAddress())
  546. continue;
  547. uint64_t StartOffset = FuncStart - getPreferredBaseAddress();
  548. uint64_t EndOffset = Range.HighPC - getPreferredBaseAddress();
  549. // We may want to know all ranges for one function. Here group the
  550. // ranges and store them into BinaryFunction.
  551. Func.Ranges.emplace_back(StartOffset, EndOffset);
  552. auto R = StartOffset2FuncRangeMap.emplace(StartOffset, FuncRange());
  553. if (R.second) {
  554. FuncRange &FRange = R.first->second;
  555. FRange.Func = &Func;
  556. FRange.StartOffset = StartOffset;
  557. FRange.EndOffset = EndOffset;
  558. } else {
  559. WithColor::warning()
  560. << "Duplicated symbol start address at "
  561. << format("%8" PRIx64, StartOffset + getPreferredBaseAddress())
  562. << " " << R.first->second.getFuncName() << " and " << Name
  563. << "\n";
  564. }
  565. }
  566. }
  567. }
  568. assert(!StartOffset2FuncRangeMap.empty() && "Misssing debug info.");
  569. }
  570. void ProfiledBinary::populateSymbolListFromDWARF(
  571. ProfileSymbolList &SymbolList) {
  572. for (auto &I : StartOffset2FuncRangeMap)
  573. SymbolList.add(I.second.getFuncName());
  574. }
  575. void ProfiledBinary::setupSymbolizer() {
  576. symbolize::LLVMSymbolizer::Options SymbolizerOpts;
  577. SymbolizerOpts.PrintFunctions =
  578. DILineInfoSpecifier::FunctionNameKind::LinkageName;
  579. SymbolizerOpts.Demangle = false;
  580. SymbolizerOpts.DefaultArch = TheTriple.getArchName().str();
  581. SymbolizerOpts.UseSymbolTable = false;
  582. SymbolizerOpts.RelativeAddresses = false;
  583. Symbolizer = std::make_unique<symbolize::LLVMSymbolizer>(SymbolizerOpts);
  584. }
  585. SampleContextFrameVector ProfiledBinary::symbolize(const InstructionPointer &IP,
  586. bool UseCanonicalFnName,
  587. bool UseProbeDiscriminator) {
  588. assert(this == IP.Binary &&
  589. "Binary should only symbolize its own instruction");
  590. auto Addr = object::SectionedAddress{IP.Offset + getPreferredBaseAddress(),
  591. object::SectionedAddress::UndefSection};
  592. DIInliningInfo InlineStack = unwrapOrError(
  593. Symbolizer->symbolizeInlinedCode(SymbolizerPath.str(), Addr),
  594. SymbolizerPath);
  595. SampleContextFrameVector CallStack;
  596. for (int32_t I = InlineStack.getNumberOfFrames() - 1; I >= 0; I--) {
  597. const auto &CallerFrame = InlineStack.getFrame(I);
  598. if (CallerFrame.FunctionName == "<invalid>")
  599. break;
  600. StringRef FunctionName(CallerFrame.FunctionName);
  601. if (UseCanonicalFnName)
  602. FunctionName = FunctionSamples::getCanonicalFnName(FunctionName);
  603. uint32_t Discriminator = CallerFrame.Discriminator;
  604. uint32_t LineOffset = (CallerFrame.Line - CallerFrame.StartLine) & 0xffff;
  605. if (UseProbeDiscriminator) {
  606. LineOffset =
  607. PseudoProbeDwarfDiscriminator::extractProbeIndex(Discriminator);
  608. Discriminator = 0;
  609. }
  610. LineLocation Line(LineOffset, Discriminator);
  611. auto It = NameStrings.insert(FunctionName.str());
  612. CallStack.emplace_back(*It.first, Line);
  613. }
  614. return CallStack;
  615. }
  616. void ProfiledBinary::computeInlinedContextSizeForRange(uint64_t StartOffset,
  617. uint64_t EndOffset) {
  618. uint64_t RangeBegin = offsetToVirtualAddr(StartOffset);
  619. uint64_t RangeEnd = offsetToVirtualAddr(EndOffset);
  620. InstructionPointer IP(this, RangeBegin, true);
  621. if (IP.Address != RangeBegin)
  622. WithColor::warning() << "Invalid start instruction at "
  623. << format("%8" PRIx64, RangeBegin) << "\n";
  624. if (IP.Address >= RangeEnd)
  625. return;
  626. do {
  627. uint64_t Offset = virtualAddrToOffset(IP.Address);
  628. const SampleContextFrameVector &SymbolizedCallStack =
  629. getFrameLocationStack(Offset, UsePseudoProbes);
  630. uint64_t Size = Offset2InstSizeMap[Offset];
  631. // Record instruction size for the corresponding context
  632. FuncSizeTracker.addInstructionForContext(SymbolizedCallStack, Size);
  633. } while (IP.advance() && IP.Address < RangeEnd);
  634. }
  635. InstructionPointer::InstructionPointer(const ProfiledBinary *Binary,
  636. uint64_t Address, bool RoundToNext)
  637. : Binary(Binary), Address(Address) {
  638. Index = Binary->getIndexForAddr(Address);
  639. if (RoundToNext) {
  640. // we might get address which is not the code
  641. // it should round to the next valid address
  642. if (Index >= Binary->getCodeOffsetsSize())
  643. this->Address = UINT64_MAX;
  644. else
  645. this->Address = Binary->getAddressforIndex(Index);
  646. }
  647. }
  648. bool InstructionPointer::advance() {
  649. Index++;
  650. if (Index >= Binary->getCodeOffsetsSize()) {
  651. Address = UINT64_MAX;
  652. return false;
  653. }
  654. Address = Binary->getAddressforIndex(Index);
  655. return true;
  656. }
  657. bool InstructionPointer::backward() {
  658. if (Index == 0) {
  659. Address = 0;
  660. return false;
  661. }
  662. Index--;
  663. Address = Binary->getAddressforIndex(Index);
  664. return true;
  665. }
  666. void InstructionPointer::update(uint64_t Addr) {
  667. Address = Addr;
  668. Index = Binary->getIndexForAddr(Address);
  669. }
  670. } // end namespace sampleprof
  671. } // end namespace llvm