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