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