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