1 //===- lib/MC/MCPseudoProbe.cpp - Pseudo probe encoding support ----------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "llvm/MC/MCPseudoProbe.h"
10 #include "llvm/ADT/STLExtras.h"
11 #include "llvm/IR/PseudoProbe.h"
12 #include "llvm/MC/MCAsmInfo.h"
13 #include "llvm/MC/MCAssembler.h"
14 #include "llvm/MC/MCContext.h"
15 #include "llvm/MC/MCExpr.h"
16 #include "llvm/MC/MCFragment.h"
17 #include "llvm/MC/MCObjectFileInfo.h"
18 #include "llvm/MC/MCObjectStreamer.h"
19 #include "llvm/MC/MCSymbol.h"
20 #include "llvm/Support/Endian.h"
21 #include "llvm/Support/LEB128.h"
22 #include "llvm/Support/MD5.h"
23 #include "llvm/Support/raw_ostream.h"
31 #define DEBUG_TYPE "mcpseudoprobe"
34 using namespace support
;
37 int MCPseudoProbeTable::DdgPrintIndent
= 0;
40 static const MCExpr
*buildSymbolDiff(MCObjectStreamer
*MCOS
, const MCSymbol
*A
,
42 MCContext
&Context
= MCOS
->getContext();
43 MCSymbolRefExpr::VariantKind Variant
= MCSymbolRefExpr::VK_None
;
44 const MCExpr
*ARef
= MCSymbolRefExpr::create(A
, Variant
, Context
);
45 const MCExpr
*BRef
= MCSymbolRefExpr::create(B
, Variant
, Context
);
46 const MCExpr
*AddrDelta
=
47 MCBinaryExpr::create(MCBinaryExpr::Sub
, ARef
, BRef
, Context
);
51 void MCPseudoProbe::emit(MCObjectStreamer
*MCOS
,
52 const MCPseudoProbe
*LastProbe
) const {
53 bool IsSentinel
= isSentinelProbe(getAttributes());
54 assert((LastProbe
|| IsSentinel
) &&
55 "Last probe should not be null for non-sentinel probes");
58 MCOS
->emitULEB128IntValue(Index
);
59 // Emit Type and the flag:
60 // Type (bit 0 to 3), with bit 4 to 6 for attributes.
61 // Flag (bit 7, 0 - code address, 1 - address delta). This indicates whether
62 // the following field is a symbolic code address or an address delta.
63 // Emit FS discriminator
64 assert(Type
<= 0xF && "Probe type too big to encode, exceeding 15");
65 auto NewAttributes
= Attributes
;
67 NewAttributes
|= (uint32_t)PseudoProbeAttributes::HasDiscriminator
;
68 assert(NewAttributes
<= 0x7 &&
69 "Probe attributes too big to encode, exceeding 7");
70 uint8_t PackedType
= Type
| (NewAttributes
<< 4);
72 !IsSentinel
? ((int8_t)MCPseudoProbeFlag::AddressDelta
<< 7) : 0;
73 MCOS
->emitInt8(Flag
| PackedType
);
76 // Emit the delta between the address label and LastProbe.
77 const MCExpr
*AddrDelta
=
78 buildSymbolDiff(MCOS
, Label
, LastProbe
->getLabel());
80 if (AddrDelta
->evaluateAsAbsolute(Delta
, MCOS
->getAssemblerPtr())) {
81 MCOS
->emitSLEB128IntValue(Delta
);
83 MCOS
->insert(MCOS
->getContext().allocFragment
<MCPseudoProbeAddrFragment
>(
87 // Emit the GUID of the split function that the sentinel probe represents.
88 MCOS
->emitInt64(Guid
);
92 MCOS
->emitULEB128IntValue(Discriminator
);
95 dbgs().indent(MCPseudoProbeTable::DdgPrintIndent
);
96 dbgs() << "Probe: " << Index
<< "\n";
100 void MCPseudoProbeInlineTree::addPseudoProbe(
101 const MCPseudoProbe
&Probe
, const MCPseudoProbeInlineStack
&InlineStack
) {
102 // The function should not be called on the root.
103 assert(isRoot() && "Should only be called on root");
105 // When it comes here, the input look like:
106 // Probe: GUID of C, ...
107 // InlineStack: [88, A], [66, B]
108 // which means, Function A inlines function B at call site with a probe id of
109 // 88, and B inlines C at probe 66. The tri-tree expects a tree path like {[0,
110 // A], [88, B], [66, C]} to locate the tree node where the probe should be
111 // added. Note that the edge [0, A] means A is the top-level function we are
112 // emitting probes for.
114 // Make a [0, A] edge.
115 // An empty inline stack means the function that the probe originates from
116 // is a top-level function.
118 if (InlineStack
.empty()) {
119 Top
= InlineSite(Probe
.getGuid(), 0);
121 Top
= InlineSite(std::get
<0>(InlineStack
.front()), 0);
124 auto *Cur
= getOrAddNode(Top
);
126 // Make interior edges by walking the inline stack. Once it's done, Cur should
127 // point to the node that the probe originates from.
128 if (!InlineStack
.empty()) {
129 auto Iter
= InlineStack
.begin();
130 auto Index
= std::get
<1>(*Iter
);
132 for (; Iter
!= InlineStack
.end(); Iter
++) {
133 // Make an edge by using the previous probe id and current GUID.
134 Cur
= Cur
->getOrAddNode(InlineSite(std::get
<0>(*Iter
), Index
));
135 Index
= std::get
<1>(*Iter
);
137 Cur
= Cur
->getOrAddNode(InlineSite(Probe
.getGuid(), Index
));
140 Cur
->Probes
.push_back(Probe
);
143 void MCPseudoProbeInlineTree::emit(MCObjectStreamer
*MCOS
,
144 const MCPseudoProbe
*&LastProbe
) {
146 dbgs().indent(MCPseudoProbeTable::DdgPrintIndent
);
147 dbgs() << "Group [\n";
148 MCPseudoProbeTable::DdgPrintIndent
+= 2;
150 assert(!isRoot() && "Root should be handled separately");
152 // Emit probes grouped by GUID.
154 dbgs().indent(MCPseudoProbeTable::DdgPrintIndent
);
155 dbgs() << "GUID: " << Guid
<< "\n";
158 MCOS
->emitInt64(Guid
);
159 // Emit number of probes in this node, including a sentinel probe for
160 // top-level functions if needed.
161 bool NeedSentinel
= false;
162 if (Parent
->isRoot()) {
163 assert(isSentinelProbe(LastProbe
->getAttributes()) &&
164 "Starting probe of a top-level function should be a sentinel probe");
165 // The main body of a split function doesn't need a sentinel probe.
166 if (LastProbe
->getGuid() != Guid
)
170 MCOS
->emitULEB128IntValue(Probes
.size() + NeedSentinel
);
171 // Emit number of direct inlinees
172 MCOS
->emitULEB128IntValue(Children
.size());
173 // Emit sentinel probe for top-level functions
175 LastProbe
->emit(MCOS
, nullptr);
177 // Emit probes in this group
178 for (const auto &Probe
: Probes
) {
179 Probe
.emit(MCOS
, LastProbe
);
183 // Emit sorted descendant. InlineSite is unique for each pair, so there will
184 // be no ordering of Inlinee based on MCPseudoProbeInlineTree*
185 using InlineeType
= std::pair
<InlineSite
, MCPseudoProbeInlineTree
*>;
186 std::vector
<InlineeType
> Inlinees
;
187 for (const auto &Child
: Children
)
188 Inlinees
.emplace_back(Child
.first
, Child
.second
.get());
189 llvm::sort(Inlinees
, llvm::less_first());
191 for (const auto &Inlinee
: Inlinees
) {
193 MCOS
->emitULEB128IntValue(std::get
<1>(Inlinee
.first
));
195 dbgs().indent(MCPseudoProbeTable::DdgPrintIndent
);
196 dbgs() << "InlineSite: " << std::get
<1>(Inlinee
.first
) << "\n";
199 Inlinee
.second
->emit(MCOS
, LastProbe
);
203 MCPseudoProbeTable::DdgPrintIndent
-= 2;
204 dbgs().indent(MCPseudoProbeTable::DdgPrintIndent
);
209 void MCPseudoProbeSections::emit(MCObjectStreamer
*MCOS
) {
210 MCContext
&Ctx
= MCOS
->getContext();
211 SmallVector
<std::pair
<MCSymbol
*, MCPseudoProbeInlineTree
*>> Vec
;
212 Vec
.reserve(MCProbeDivisions
.size());
213 for (auto &ProbeSec
: MCProbeDivisions
)
214 Vec
.emplace_back(ProbeSec
.first
, &ProbeSec
.second
);
215 for (auto I
: llvm::enumerate(MCOS
->getAssembler()))
216 I
.value().setOrdinal(I
.index());
217 llvm::sort(Vec
, [](auto A
, auto B
) {
218 return A
.first
->getSection().getOrdinal() <
219 B
.first
->getSection().getOrdinal();
221 for (auto [FuncSym
, RootPtr
] : Vec
) {
222 const auto &Root
= *RootPtr
;
223 if (auto *S
= Ctx
.getObjectFileInfo()->getPseudoProbeSection(
224 FuncSym
->getSection())) {
225 // Switch to the .pseudoprobe section or a comdat group.
226 MCOS
->switchSection(S
);
227 // Emit probes grouped by GUID.
228 // Emit sorted descendant. InlineSite is unique for each pair, so there
229 // will be no ordering of Inlinee based on MCPseudoProbeInlineTree*
230 using InlineeType
= std::pair
<InlineSite
, MCPseudoProbeInlineTree
*>;
231 std::vector
<InlineeType
> Inlinees
;
232 for (const auto &Child
: Root
.getChildren())
233 Inlinees
.emplace_back(Child
.first
, Child
.second
.get());
234 llvm::sort(Inlinees
, llvm::less_first());
236 for (const auto &Inlinee
: Inlinees
) {
237 // Emit the group guarded by a sentinel probe.
238 MCPseudoProbe
SentinelProbe(
239 const_cast<MCSymbol
*>(FuncSym
), MD5Hash(FuncSym
->getName()),
240 (uint32_t)PseudoProbeReservedId::Invalid
,
241 (uint32_t)PseudoProbeType::Block
,
242 (uint32_t)PseudoProbeAttributes::Sentinel
, 0);
243 const MCPseudoProbe
*Probe
= &SentinelProbe
;
244 Inlinee
.second
->emit(MCOS
, Probe
);
251 // This emits the pseudo probe tables.
253 void MCPseudoProbeTable::emit(MCObjectStreamer
*MCOS
) {
254 MCContext
&Ctx
= MCOS
->getContext();
255 auto &ProbeTable
= Ctx
.getMCPseudoProbeTable();
257 // Bail out early so we don't switch to the pseudo_probe section needlessly
258 // and in doing so create an unnecessary (if empty) section.
259 auto &ProbeSections
= ProbeTable
.getProbeSections();
260 if (ProbeSections
.empty())
263 LLVM_DEBUG(MCPseudoProbeTable::DdgPrintIndent
= 0);
265 // Put out the probe.
266 ProbeSections
.emit(MCOS
);
269 static StringRef
getProbeFNameForGUID(const GUIDProbeFunctionMap
&GUID2FuncMAP
,
271 auto It
= GUID2FuncMAP
.find(GUID
);
272 assert(It
!= GUID2FuncMAP
.end() &&
273 "Probe function must exist for a valid GUID");
274 return It
->second
.FuncName
;
277 void MCPseudoProbeFuncDesc::print(raw_ostream
&OS
) {
278 OS
<< "GUID: " << FuncGUID
<< " Name: " << FuncName
<< "\n";
279 OS
<< "Hash: " << FuncHash
<< "\n";
282 void MCDecodedPseudoProbe::getInlineContext(
283 SmallVectorImpl
<MCPseudoProbeFrameLocation
> &ContextStack
,
284 const GUIDProbeFunctionMap
&GUID2FuncMAP
) const {
285 uint32_t Begin
= ContextStack
.size();
286 MCDecodedPseudoProbeInlineTree
*Cur
= InlineTree
;
287 // It will add the string of each node's inline site during iteration.
288 // Note that it won't include the probe's belonging function(leaf location)
289 while (Cur
->hasInlineSite()) {
290 StringRef FuncName
= getProbeFNameForGUID(GUID2FuncMAP
, Cur
->Parent
->Guid
);
291 ContextStack
.emplace_back(
292 MCPseudoProbeFrameLocation(FuncName
, std::get
<1>(Cur
->ISite
)));
293 Cur
= static_cast<MCDecodedPseudoProbeInlineTree
*>(Cur
->Parent
);
295 // Make the ContextStack in caller-callee order
296 std::reverse(ContextStack
.begin() + Begin
, ContextStack
.end());
299 std::string
MCDecodedPseudoProbe::getInlineContextStr(
300 const GUIDProbeFunctionMap
&GUID2FuncMAP
) const {
301 std::ostringstream OContextStr
;
302 SmallVector
<MCPseudoProbeFrameLocation
, 16> ContextStack
;
303 getInlineContext(ContextStack
, GUID2FuncMAP
);
304 for (auto &Cxt
: ContextStack
) {
305 if (OContextStr
.str().size())
306 OContextStr
<< " @ ";
307 OContextStr
<< Cxt
.first
.str() << ":" << Cxt
.second
;
309 return OContextStr
.str();
312 static const char *PseudoProbeTypeStr
[3] = {"Block", "IndirectCall",
315 void MCDecodedPseudoProbe::print(raw_ostream
&OS
,
316 const GUIDProbeFunctionMap
&GUID2FuncMAP
,
317 bool ShowName
) const {
320 StringRef FuncName
= getProbeFNameForGUID(GUID2FuncMAP
, Guid
);
321 OS
<< FuncName
.str() << " ";
325 OS
<< "Index: " << Index
<< " ";
327 OS
<< "Discriminator: " << Discriminator
<< " ";
328 OS
<< "Type: " << PseudoProbeTypeStr
[static_cast<uint8_t>(Type
)] << " ";
329 std::string InlineContextStr
= getInlineContextStr(GUID2FuncMAP
);
330 if (InlineContextStr
.size()) {
332 OS
<< InlineContextStr
;
337 template <typename T
> ErrorOr
<T
> MCPseudoProbeDecoder::readUnencodedNumber() {
338 if (Data
+ sizeof(T
) > End
) {
339 return std::error_code();
341 T Val
= endian::readNext
<T
, llvm::endianness::little
>(Data
);
342 return ErrorOr
<T
>(Val
);
345 template <typename T
> ErrorOr
<T
> MCPseudoProbeDecoder::readUnsignedNumber() {
346 unsigned NumBytesRead
= 0;
347 uint64_t Val
= decodeULEB128(Data
, &NumBytesRead
);
348 if (Val
> std::numeric_limits
<T
>::max() || (Data
+ NumBytesRead
> End
)) {
349 return std::error_code();
351 Data
+= NumBytesRead
;
352 return ErrorOr
<T
>(static_cast<T
>(Val
));
355 template <typename T
> ErrorOr
<T
> MCPseudoProbeDecoder::readSignedNumber() {
356 unsigned NumBytesRead
= 0;
357 int64_t Val
= decodeSLEB128(Data
, &NumBytesRead
);
358 if (Val
> std::numeric_limits
<T
>::max() || (Data
+ NumBytesRead
> End
)) {
359 return std::error_code();
361 Data
+= NumBytesRead
;
362 return ErrorOr
<T
>(static_cast<T
>(Val
));
365 ErrorOr
<StringRef
> MCPseudoProbeDecoder::readString(uint32_t Size
) {
366 StringRef
Str(reinterpret_cast<const char *>(Data
), Size
);
367 if (Data
+ Size
> End
) {
368 return std::error_code();
371 return ErrorOr
<StringRef
>(Str
);
374 bool MCPseudoProbeDecoder::buildGUID2FuncDescMap(const uint8_t *Start
,
376 // The pseudo_probe_desc section has a format like:
377 // .section .pseudo_probe_desc,"",@progbits
378 // .quad -5182264717993193164 // GUID
379 // .quad 4294967295 // Hash
380 // .uleb 3 // Name size
381 // .ascii "foo" // Name
382 // .quad -2624081020897602054
383 // .quad 174696971957
391 auto ErrorOrGUID
= readUnencodedNumber
<uint64_t>();
395 auto ErrorOrHash
= readUnencodedNumber
<uint64_t>();
399 auto ErrorOrNameSize
= readUnsignedNumber
<uint32_t>();
400 if (!ErrorOrNameSize
)
402 uint32_t NameSize
= std::move(*ErrorOrNameSize
);
404 auto ErrorOrName
= readString(NameSize
);
408 uint64_t GUID
= std::move(*ErrorOrGUID
);
409 uint64_t Hash
= std::move(*ErrorOrHash
);
410 StringRef Name
= std::move(*ErrorOrName
);
412 // Initialize PseudoProbeFuncDesc and populate it into GUID2FuncDescMap
413 GUID2FuncDescMap
.emplace(GUID
, MCPseudoProbeFuncDesc(GUID
, Hash
, Name
));
415 assert(Data
== End
&& "Have unprocessed data in pseudo_probe_desc section");
419 bool MCPseudoProbeDecoder::buildAddress2ProbeMap(
420 MCDecodedPseudoProbeInlineTree
*Cur
, uint64_t &LastAddr
,
421 const Uint64Set
&GuidFilter
, const Uint64Map
&FuncStartAddrs
) {
422 // The pseudo_probe section encodes an inline forest and each tree has a
423 // format defined in MCPseudoProbe.h
426 bool IsTopLevelFunc
= Cur
== &DummyInlineRoot
;
427 if (IsTopLevelFunc
) {
428 // Use a sequential id for top level inliner.
429 Index
= Cur
->getChildren().size();
431 // Read inline site for inlinees
432 auto ErrorOrIndex
= readUnsignedNumber
<uint32_t>();
435 Index
= std::move(*ErrorOrIndex
);
439 auto ErrorOrCurGuid
= readUnencodedNumber
<uint64_t>();
442 uint64_t Guid
= std::move(*ErrorOrCurGuid
);
444 // Decide if top-level node should be disgarded.
445 if (IsTopLevelFunc
&& !GuidFilter
.empty() && !GuidFilter
.count(Guid
))
448 // If the incoming node is null, all its children nodes should be disgarded.
450 // Switch/add to a new tree node(inlinee)
451 Cur
= Cur
->getOrAddNode(std::make_tuple(Guid
, Index
));
453 if (IsTopLevelFunc
&& !EncodingIsAddrBased
) {
454 if (auto V
= FuncStartAddrs
.lookup(Guid
))
459 // Read number of probes in the current node.
460 auto ErrorOrNodeCount
= readUnsignedNumber
<uint32_t>();
461 if (!ErrorOrNodeCount
)
463 uint32_t NodeCount
= std::move(*ErrorOrNodeCount
);
464 // Read number of direct inlinees
465 auto ErrorOrCurChildrenToProcess
= readUnsignedNumber
<uint32_t>();
466 if (!ErrorOrCurChildrenToProcess
)
468 // Read all probes in this node
469 for (std::size_t I
= 0; I
< NodeCount
; I
++) {
471 auto ErrorOrIndex
= readUnsignedNumber
<uint32_t>();
474 uint32_t Index
= std::move(*ErrorOrIndex
);
476 auto ErrorOrValue
= readUnencodedNumber
<uint8_t>();
479 uint8_t Value
= std::move(*ErrorOrValue
);
480 uint8_t Kind
= Value
& 0xf;
481 uint8_t Attr
= (Value
& 0x70) >> 4;
485 auto ErrorOrOffset
= readSignedNumber
<int64_t>();
488 int64_t Offset
= std::move(*ErrorOrOffset
);
489 Addr
= LastAddr
+ Offset
;
491 auto ErrorOrAddr
= readUnencodedNumber
<int64_t>();
494 Addr
= std::move(*ErrorOrAddr
);
495 if (isSentinelProbe(Attr
)) {
496 // For sentinel probe, the addr field actually stores the GUID of the
497 // split function. Convert it to the real address.
498 if (auto V
= FuncStartAddrs
.lookup(Addr
))
501 // For now we assume all probe encoding should be either based on
502 // leading probe address or function start address.
503 // The scheme is for downwards compatibility.
504 // TODO: retire this scheme once compatibility is no longer an issue.
505 EncodingIsAddrBased
= true;
509 uint32_t Discriminator
= 0;
510 if (hasDiscriminator(Attr
)) {
511 auto ErrorOrDiscriminator
= readUnsignedNumber
<uint32_t>();
512 if (!ErrorOrDiscriminator
)
514 Discriminator
= std::move(*ErrorOrDiscriminator
);
517 if (Cur
&& !isSentinelProbe(Attr
)) {
518 // Populate Address2ProbesMap
519 auto &Probes
= Address2ProbesMap
[Addr
];
520 Probes
.emplace_back(Addr
, Cur
->Guid
, Index
, PseudoProbeType(Kind
), Attr
,
522 Cur
->addProbes(&Probes
.back());
527 uint32_t ChildrenToProcess
= std::move(*ErrorOrCurChildrenToProcess
);
528 for (uint32_t I
= 0; I
< ChildrenToProcess
; I
++) {
529 buildAddress2ProbeMap(Cur
, LastAddr
, GuidFilter
, FuncStartAddrs
);
535 bool MCPseudoProbeDecoder::buildAddress2ProbeMap(
536 const uint8_t *Start
, std::size_t Size
, const Uint64Set
&GuidFilter
,
537 const Uint64Map
&FuncStartAddrs
) {
540 uint64_t LastAddr
= 0;
542 buildAddress2ProbeMap(&DummyInlineRoot
, LastAddr
, GuidFilter
,
544 assert(Data
== End
&& "Have unprocessed data in pseudo_probe section");
548 void MCPseudoProbeDecoder::printGUID2FuncDescMap(raw_ostream
&OS
) {
549 OS
<< "Pseudo Probe Desc:\n";
550 // Make the output deterministic
551 std::map
<uint64_t, MCPseudoProbeFuncDesc
> OrderedMap(GUID2FuncDescMap
.begin(),
552 GUID2FuncDescMap
.end());
553 for (auto &I
: OrderedMap
) {
558 void MCPseudoProbeDecoder::printProbeForAddress(raw_ostream
&OS
,
560 auto It
= Address2ProbesMap
.find(Address
);
561 if (It
!= Address2ProbesMap
.end()) {
562 for (auto &Probe
: It
->second
) {
564 Probe
.print(OS
, GUID2FuncDescMap
, true);
569 void MCPseudoProbeDecoder::printProbesForAllAddresses(raw_ostream
&OS
) {
570 auto Entries
= make_first_range(Address2ProbesMap
);
571 SmallVector
<uint64_t, 0> Addresses(Entries
.begin(), Entries
.end());
572 llvm::sort(Addresses
);
573 for (auto K
: Addresses
) {
577 printProbeForAddress(OS
, K
);
581 const MCDecodedPseudoProbe
*
582 MCPseudoProbeDecoder::getCallProbeForAddr(uint64_t Address
) const {
583 auto It
= Address2ProbesMap
.find(Address
);
584 if (It
== Address2ProbesMap
.end())
586 const auto &Probes
= It
->second
;
588 const MCDecodedPseudoProbe
*CallProbe
= nullptr;
589 for (const auto &Probe
: Probes
) {
590 if (Probe
.isCall()) {
591 // Disabling the assert and returning first call probe seen so far.
592 // Subsequent call probes, if any, are ignored. Due to the the way
593 // .pseudo_probe section is decoded, probes of the same-named independent
594 // static functions are merged thus multiple call probes may be seen for a
595 // callsite. This should only happen to compiler-generated statics, with
596 // -funique-internal-linkage-names where user statics get unique names.
598 // TODO: re-enable or narrow down the assert to static functions only.
600 // assert(!CallProbe &&
601 // "There should be only one call probe corresponding to address "
602 // "which is a callsite.");
610 const MCPseudoProbeFuncDesc
*
611 MCPseudoProbeDecoder::getFuncDescForGUID(uint64_t GUID
) const {
612 auto It
= GUID2FuncDescMap
.find(GUID
);
613 assert(It
!= GUID2FuncDescMap
.end() && "Function descriptor doesn't exist");
617 void MCPseudoProbeDecoder::getInlineContextForProbe(
618 const MCDecodedPseudoProbe
*Probe
,
619 SmallVectorImpl
<MCPseudoProbeFrameLocation
> &InlineContextStack
,
620 bool IncludeLeaf
) const {
621 Probe
->getInlineContext(InlineContextStack
, GUID2FuncDescMap
);
624 // Note that the context from probe doesn't include leaf frame,
625 // hence we need to retrieve and prepend leaf if requested.
626 const auto *FuncDesc
= getFuncDescForGUID(Probe
->getGuid());
627 InlineContextStack
.emplace_back(
628 MCPseudoProbeFrameLocation(FuncDesc
->FuncName
, Probe
->getIndex()));
631 const MCPseudoProbeFuncDesc
*MCPseudoProbeDecoder::getInlinerDescForProbe(
632 const MCDecodedPseudoProbe
*Probe
) const {
633 MCDecodedPseudoProbeInlineTree
*InlinerNode
= Probe
->getInlineTreeNode();
634 if (!InlinerNode
->hasInlineSite())
636 return getFuncDescForGUID(InlinerNode
->Parent
->Guid
);