xref: /netbsd-src/external/apache2/llvm/dist/llvm/tools/llvm-profgen/ProfiledBinary.cpp (revision 82d56013d7b633d116a93943de88e08335357a7c)
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 
getTarget(const ObjectFile * Obj)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>
getELFImageLMAForSec(const ELFFile<ELFT> & Obj,const object::ELFSectionRef & Sec,StringRef FileName)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.
getELFImageLMAForSec(const object::ELFSectionRef & Sec)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 
load()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 
inlineContextEqual(uint64_t Address1,uint64_t Address2) const118 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
getExpandedContextStr(const SmallVectorImpl<uint64_t> & Stack,bool & WasLeafInlined) const135 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 
setPreferredBaseAddress(const ELFObjectFileBase * Obj)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 
decodePseudoProbe(const ELFObjectFileBase * Obj)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 
dissassembleSymbol(std::size_t SI,ArrayRef<uint8_t> Bytes,SectionSymbolsTy & Symbols,const SectionRef & Section)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 
setUpDisassembler(const ELFObjectFileBase * Obj)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 
disassemble(const ELFObjectFileBase * Obj)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 
setupSymbolizer()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 
symbolize(const InstructionPointer & IP,bool UseCanonicalFnName)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 
InstructionPointer(ProfiledBinary * Binary,uint64_t Address,bool RoundToNext)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 
advance()462 void InstructionPointer::advance() {
463   Index++;
464   Address = Binary->getAddressforIndex(Index);
465 }
466 
backward()467 void InstructionPointer::backward() {
468   Index--;
469   Address = Binary->getAddressforIndex(Index);
470 }
471 
update(uint64_t Addr)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