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(new MCPseudoProbeAddrFragment(AddrDelta
));
86 // Emit the GUID of the split function that the sentinel probe represents.
87 MCOS
->emitInt64(Guid
);
91 MCOS
->emitULEB128IntValue(Discriminator
);
94 dbgs().indent(MCPseudoProbeTable::DdgPrintIndent
);
95 dbgs() << "Probe: " << Index
<< "\n";
99 void MCPseudoProbeInlineTree::addPseudoProbe(
100 const MCPseudoProbe
&Probe
, const MCPseudoProbeInlineStack
&InlineStack
) {
101 // The function should not be called on the root.
102 assert(isRoot() && "Should only be called on root");
104 // When it comes here, the input look like:
105 // Probe: GUID of C, ...
106 // InlineStack: [88, A], [66, B]
107 // which means, Function A inlines function B at call site with a probe id of
108 // 88, and B inlines C at probe 66. The tri-tree expects a tree path like {[0,
109 // A], [88, B], [66, C]} to locate the tree node where the probe should be
110 // added. Note that the edge [0, A] means A is the top-level function we are
111 // emitting probes for.
113 // Make a [0, A] edge.
114 // An empty inline stack means the function that the probe originates from
115 // is a top-level function.
117 if (InlineStack
.empty()) {
118 Top
= InlineSite(Probe
.getGuid(), 0);
120 Top
= InlineSite(std::get
<0>(InlineStack
.front()), 0);
123 auto *Cur
= getOrAddNode(Top
);
125 // Make interior edges by walking the inline stack. Once it's done, Cur should
126 // point to the node that the probe originates from.
127 if (!InlineStack
.empty()) {
128 auto Iter
= InlineStack
.begin();
129 auto Index
= std::get
<1>(*Iter
);
131 for (; Iter
!= InlineStack
.end(); Iter
++) {
132 // Make an edge by using the previous probe id and current GUID.
133 Cur
= Cur
->getOrAddNode(InlineSite(std::get
<0>(*Iter
), Index
));
134 Index
= std::get
<1>(*Iter
);
136 Cur
= Cur
->getOrAddNode(InlineSite(Probe
.getGuid(), Index
));
139 Cur
->Probes
.push_back(Probe
);
142 void MCPseudoProbeInlineTree::emit(MCObjectStreamer
*MCOS
,
143 const MCPseudoProbe
*&LastProbe
) {
145 dbgs().indent(MCPseudoProbeTable::DdgPrintIndent
);
146 dbgs() << "Group [\n";
147 MCPseudoProbeTable::DdgPrintIndent
+= 2;
149 assert(!isRoot() && "Root should be handled seperately");
151 // Emit probes grouped by GUID.
153 dbgs().indent(MCPseudoProbeTable::DdgPrintIndent
);
154 dbgs() << "GUID: " << Guid
<< "\n";
157 MCOS
->emitInt64(Guid
);
158 // Emit number of probes in this node, including a sentinel probe for
159 // top-level functions if needed.
160 bool NeedSentinel
= false;
161 if (Parent
->isRoot()) {
162 assert(isSentinelProbe(LastProbe
->getAttributes()) &&
163 "Starting probe of a top-level function should be a sentinel probe");
164 // The main body of a split function doesn't need a sentinel probe.
165 if (LastProbe
->getGuid() != Guid
)
169 MCOS
->emitULEB128IntValue(Probes
.size() + NeedSentinel
);
170 // Emit number of direct inlinees
171 MCOS
->emitULEB128IntValue(Children
.size());
172 // Emit sentinel probe for top-level functions
174 LastProbe
->emit(MCOS
, nullptr);
176 // Emit probes in this group
177 for (const auto &Probe
: Probes
) {
178 Probe
.emit(MCOS
, LastProbe
);
182 // Emit sorted descendant. InlineSite is unique for each pair, so there will
183 // be no ordering of Inlinee based on MCPseudoProbeInlineTree*
184 using InlineeType
= std::pair
<InlineSite
, MCPseudoProbeInlineTree
*>;
185 auto Comparer
= [](const InlineeType
&A
, const InlineeType
&B
) {
186 return A
.first
< B
.first
;
188 std::vector
<InlineeType
> Inlinees
;
189 for (const auto &Child
: Children
)
190 Inlinees
.emplace_back(Child
.first
, Child
.second
.get());
191 std::sort(Inlinees
.begin(), Inlinees
.end(), Comparer
);
193 for (const auto &Inlinee
: Inlinees
) {
195 MCOS
->emitULEB128IntValue(std::get
<1>(Inlinee
.first
));
197 dbgs().indent(MCPseudoProbeTable::DdgPrintIndent
);
198 dbgs() << "InlineSite: " << std::get
<1>(Inlinee
.first
) << "\n";
201 Inlinee
.second
->emit(MCOS
, LastProbe
);
205 MCPseudoProbeTable::DdgPrintIndent
-= 2;
206 dbgs().indent(MCPseudoProbeTable::DdgPrintIndent
);
211 void MCPseudoProbeSections::emit(MCObjectStreamer
*MCOS
) {
212 MCContext
&Ctx
= MCOS
->getContext();
213 SmallVector
<std::pair
<MCSymbol
*, MCPseudoProbeInlineTree
*>> Vec
;
214 Vec
.reserve(MCProbeDivisions
.size());
215 for (auto &ProbeSec
: MCProbeDivisions
)
216 Vec
.emplace_back(ProbeSec
.first
, &ProbeSec
.second
);
217 for (auto I
: llvm::enumerate(MCOS
->getAssembler()))
218 I
.value().setOrdinal(I
.index());
219 llvm::sort(Vec
, [](auto A
, auto B
) {
220 return A
.first
->getSection().getOrdinal() <
221 B
.first
->getSection().getOrdinal();
223 for (auto [FuncSym
, RootPtr
] : Vec
) {
224 const auto &Root
= *RootPtr
;
225 if (auto *S
= Ctx
.getObjectFileInfo()->getPseudoProbeSection(
226 FuncSym
->getSection())) {
227 // Switch to the .pseudoprobe section or a comdat group.
228 MCOS
->switchSection(S
);
229 // Emit probes grouped by GUID.
230 // Emit sorted descendant. InlineSite is unique for each pair, so there
231 // will be no ordering of Inlinee based on MCPseudoProbeInlineTree*
232 using InlineeType
= std::pair
<InlineSite
, MCPseudoProbeInlineTree
*>;
233 auto Comparer
= [](const InlineeType
&A
, const InlineeType
&B
) {
234 return A
.first
< B
.first
;
236 std::vector
<InlineeType
> Inlinees
;
237 for (const auto &Child
: Root
.getChildren())
238 Inlinees
.emplace_back(Child
.first
, Child
.second
.get());
239 std::sort(Inlinees
.begin(), Inlinees
.end(), Comparer
);
241 for (const auto &Inlinee
: Inlinees
) {
242 // Emit the group guarded by a sentinel probe.
243 MCPseudoProbe
SentinelProbe(
244 const_cast<MCSymbol
*>(FuncSym
), MD5Hash(FuncSym
->getName()),
245 (uint32_t)PseudoProbeReservedId::Invalid
,
246 (uint32_t)PseudoProbeType::Block
,
247 (uint32_t)PseudoProbeAttributes::Sentinel
, 0);
248 const MCPseudoProbe
*Probe
= &SentinelProbe
;
249 Inlinee
.second
->emit(MCOS
, Probe
);
256 // This emits the pseudo probe tables.
258 void MCPseudoProbeTable::emit(MCObjectStreamer
*MCOS
) {
259 MCContext
&Ctx
= MCOS
->getContext();
260 auto &ProbeTable
= Ctx
.getMCPseudoProbeTable();
262 // Bail out early so we don't switch to the pseudo_probe section needlessly
263 // and in doing so create an unnecessary (if empty) section.
264 auto &ProbeSections
= ProbeTable
.getProbeSections();
265 if (ProbeSections
.empty())
268 LLVM_DEBUG(MCPseudoProbeTable::DdgPrintIndent
= 0);
270 // Put out the probe.
271 ProbeSections
.emit(MCOS
);
274 static StringRef
getProbeFNameForGUID(const GUIDProbeFunctionMap
&GUID2FuncMAP
,
276 auto It
= GUID2FuncMAP
.find(GUID
);
277 assert(It
!= GUID2FuncMAP
.end() &&
278 "Probe function must exist for a valid GUID");
279 return It
->second
.FuncName
;
282 void MCPseudoProbeFuncDesc::print(raw_ostream
&OS
) {
283 OS
<< "GUID: " << FuncGUID
<< " Name: " << FuncName
<< "\n";
284 OS
<< "Hash: " << FuncHash
<< "\n";
287 void MCDecodedPseudoProbe::getInlineContext(
288 SmallVectorImpl
<MCPseduoProbeFrameLocation
> &ContextStack
,
289 const GUIDProbeFunctionMap
&GUID2FuncMAP
) const {
290 uint32_t Begin
= ContextStack
.size();
291 MCDecodedPseudoProbeInlineTree
*Cur
= InlineTree
;
292 // It will add the string of each node's inline site during iteration.
293 // Note that it won't include the probe's belonging function(leaf location)
294 while (Cur
->hasInlineSite()) {
295 StringRef FuncName
= getProbeFNameForGUID(GUID2FuncMAP
, Cur
->Parent
->Guid
);
296 ContextStack
.emplace_back(
297 MCPseduoProbeFrameLocation(FuncName
, std::get
<1>(Cur
->ISite
)));
298 Cur
= static_cast<MCDecodedPseudoProbeInlineTree
*>(Cur
->Parent
);
300 // Make the ContextStack in caller-callee order
301 std::reverse(ContextStack
.begin() + Begin
, ContextStack
.end());
304 std::string
MCDecodedPseudoProbe::getInlineContextStr(
305 const GUIDProbeFunctionMap
&GUID2FuncMAP
) const {
306 std::ostringstream OContextStr
;
307 SmallVector
<MCPseduoProbeFrameLocation
, 16> ContextStack
;
308 getInlineContext(ContextStack
, GUID2FuncMAP
);
309 for (auto &Cxt
: ContextStack
) {
310 if (OContextStr
.str().size())
311 OContextStr
<< " @ ";
312 OContextStr
<< Cxt
.first
.str() << ":" << Cxt
.second
;
314 return OContextStr
.str();
317 static const char *PseudoProbeTypeStr
[3] = {"Block", "IndirectCall",
320 void MCDecodedPseudoProbe::print(raw_ostream
&OS
,
321 const GUIDProbeFunctionMap
&GUID2FuncMAP
,
322 bool ShowName
) const {
325 StringRef FuncName
= getProbeFNameForGUID(GUID2FuncMAP
, Guid
);
326 OS
<< FuncName
.str() << " ";
330 OS
<< "Index: " << Index
<< " ";
332 OS
<< "Discriminator: " << Discriminator
<< " ";
333 OS
<< "Type: " << PseudoProbeTypeStr
[static_cast<uint8_t>(Type
)] << " ";
334 std::string InlineContextStr
= getInlineContextStr(GUID2FuncMAP
);
335 if (InlineContextStr
.size()) {
337 OS
<< InlineContextStr
;
342 template <typename T
> ErrorOr
<T
> MCPseudoProbeDecoder::readUnencodedNumber() {
343 if (Data
+ sizeof(T
) > End
) {
344 return std::error_code();
346 T Val
= endian::readNext
<T
, llvm::endianness::little
, unaligned
>(Data
);
347 return ErrorOr
<T
>(Val
);
350 template <typename T
> ErrorOr
<T
> MCPseudoProbeDecoder::readUnsignedNumber() {
351 unsigned NumBytesRead
= 0;
352 uint64_t Val
= decodeULEB128(Data
, &NumBytesRead
);
353 if (Val
> std::numeric_limits
<T
>::max() || (Data
+ NumBytesRead
> End
)) {
354 return std::error_code();
356 Data
+= NumBytesRead
;
357 return ErrorOr
<T
>(static_cast<T
>(Val
));
360 template <typename T
> ErrorOr
<T
> MCPseudoProbeDecoder::readSignedNumber() {
361 unsigned NumBytesRead
= 0;
362 int64_t Val
= decodeSLEB128(Data
, &NumBytesRead
);
363 if (Val
> std::numeric_limits
<T
>::max() || (Data
+ NumBytesRead
> End
)) {
364 return std::error_code();
366 Data
+= NumBytesRead
;
367 return ErrorOr
<T
>(static_cast<T
>(Val
));
370 ErrorOr
<StringRef
> MCPseudoProbeDecoder::readString(uint32_t Size
) {
371 StringRef
Str(reinterpret_cast<const char *>(Data
), Size
);
372 if (Data
+ Size
> End
) {
373 return std::error_code();
376 return ErrorOr
<StringRef
>(Str
);
379 bool MCPseudoProbeDecoder::buildGUID2FuncDescMap(const uint8_t *Start
,
381 // The pseudo_probe_desc section has a format like:
382 // .section .pseudo_probe_desc,"",@progbits
383 // .quad -5182264717993193164 // GUID
384 // .quad 4294967295 // Hash
385 // .uleb 3 // Name size
386 // .ascii "foo" // Name
387 // .quad -2624081020897602054
388 // .quad 174696971957
396 auto ErrorOrGUID
= readUnencodedNumber
<uint64_t>();
400 auto ErrorOrHash
= readUnencodedNumber
<uint64_t>();
404 auto ErrorOrNameSize
= readUnsignedNumber
<uint32_t>();
405 if (!ErrorOrNameSize
)
407 uint32_t NameSize
= std::move(*ErrorOrNameSize
);
409 auto ErrorOrName
= readString(NameSize
);
413 uint64_t GUID
= std::move(*ErrorOrGUID
);
414 uint64_t Hash
= std::move(*ErrorOrHash
);
415 StringRef Name
= std::move(*ErrorOrName
);
417 // Initialize PseudoProbeFuncDesc and populate it into GUID2FuncDescMap
418 GUID2FuncDescMap
.emplace(GUID
, MCPseudoProbeFuncDesc(GUID
, Hash
, Name
));
420 assert(Data
== End
&& "Have unprocessed data in pseudo_probe_desc section");
424 bool MCPseudoProbeDecoder::buildAddress2ProbeMap(
425 MCDecodedPseudoProbeInlineTree
*Cur
, uint64_t &LastAddr
,
426 const Uint64Set
&GuidFilter
, const Uint64Map
&FuncStartAddrs
) {
427 // The pseudo_probe section encodes an inline forest and each tree has a
428 // format defined in MCPseudoProbe.h
431 bool IsTopLevelFunc
= Cur
== &DummyInlineRoot
;
432 if (IsTopLevelFunc
) {
433 // Use a sequential id for top level inliner.
434 Index
= Cur
->getChildren().size();
436 // Read inline site for inlinees
437 auto ErrorOrIndex
= readUnsignedNumber
<uint32_t>();
440 Index
= std::move(*ErrorOrIndex
);
444 auto ErrorOrCurGuid
= readUnencodedNumber
<uint64_t>();
447 uint64_t Guid
= std::move(*ErrorOrCurGuid
);
449 // Decide if top-level node should be disgarded.
450 if (IsTopLevelFunc
&& !GuidFilter
.empty() && !GuidFilter
.count(Guid
))
453 // If the incoming node is null, all its children nodes should be disgarded.
455 // Switch/add to a new tree node(inlinee)
456 Cur
= Cur
->getOrAddNode(std::make_tuple(Guid
, Index
));
458 if (IsTopLevelFunc
&& !EncodingIsAddrBased
) {
459 if (auto V
= FuncStartAddrs
.lookup(Guid
))
464 // Read number of probes in the current node.
465 auto ErrorOrNodeCount
= readUnsignedNumber
<uint32_t>();
466 if (!ErrorOrNodeCount
)
468 uint32_t NodeCount
= std::move(*ErrorOrNodeCount
);
469 // Read number of direct inlinees
470 auto ErrorOrCurChildrenToProcess
= readUnsignedNumber
<uint32_t>();
471 if (!ErrorOrCurChildrenToProcess
)
473 // Read all probes in this node
474 for (std::size_t I
= 0; I
< NodeCount
; I
++) {
476 auto ErrorOrIndex
= readUnsignedNumber
<uint32_t>();
479 uint32_t Index
= std::move(*ErrorOrIndex
);
481 auto ErrorOrValue
= readUnencodedNumber
<uint8_t>();
484 uint8_t Value
= std::move(*ErrorOrValue
);
485 uint8_t Kind
= Value
& 0xf;
486 uint8_t Attr
= (Value
& 0x70) >> 4;
490 auto ErrorOrOffset
= readSignedNumber
<int64_t>();
493 int64_t Offset
= std::move(*ErrorOrOffset
);
494 Addr
= LastAddr
+ Offset
;
496 auto ErrorOrAddr
= readUnencodedNumber
<int64_t>();
499 Addr
= std::move(*ErrorOrAddr
);
500 if (isSentinelProbe(Attr
)) {
501 // For sentinel probe, the addr field actually stores the GUID of the
502 // split function. Convert it to the real address.
503 if (auto V
= FuncStartAddrs
.lookup(Addr
))
506 // For now we assume all probe encoding should be either based on
507 // leading probe address or function start address.
508 // The scheme is for downwards compatibility.
509 // TODO: retire this scheme once compatibility is no longer an issue.
510 EncodingIsAddrBased
= true;
514 uint32_t Discriminator
= 0;
515 if (hasDiscriminator(Attr
)) {
516 auto ErrorOrDiscriminator
= readUnsignedNumber
<uint32_t>();
517 if (!ErrorOrDiscriminator
)
519 Discriminator
= std::move(*ErrorOrDiscriminator
);
522 if (Cur
&& !isSentinelProbe(Attr
)) {
523 // Populate Address2ProbesMap
524 auto &Probes
= Address2ProbesMap
[Addr
];
525 Probes
.emplace_back(Addr
, Cur
->Guid
, Index
, PseudoProbeType(Kind
), Attr
,
527 Cur
->addProbes(&Probes
.back());
532 uint32_t ChildrenToProcess
= std::move(*ErrorOrCurChildrenToProcess
);
533 for (uint32_t I
= 0; I
< ChildrenToProcess
; I
++) {
534 buildAddress2ProbeMap(Cur
, LastAddr
, GuidFilter
, FuncStartAddrs
);
540 bool MCPseudoProbeDecoder::buildAddress2ProbeMap(
541 const uint8_t *Start
, std::size_t Size
, const Uint64Set
&GuidFilter
,
542 const Uint64Map
&FuncStartAddrs
) {
545 uint64_t LastAddr
= 0;
547 buildAddress2ProbeMap(&DummyInlineRoot
, LastAddr
, GuidFilter
,
549 assert(Data
== End
&& "Have unprocessed data in pseudo_probe section");
553 void MCPseudoProbeDecoder::printGUID2FuncDescMap(raw_ostream
&OS
) {
554 OS
<< "Pseudo Probe Desc:\n";
555 // Make the output deterministic
556 std::map
<uint64_t, MCPseudoProbeFuncDesc
> OrderedMap(GUID2FuncDescMap
.begin(),
557 GUID2FuncDescMap
.end());
558 for (auto &I
: OrderedMap
) {
563 void MCPseudoProbeDecoder::printProbeForAddress(raw_ostream
&OS
,
565 auto It
= Address2ProbesMap
.find(Address
);
566 if (It
!= Address2ProbesMap
.end()) {
567 for (auto &Probe
: It
->second
) {
569 Probe
.print(OS
, GUID2FuncDescMap
, true);
574 void MCPseudoProbeDecoder::printProbesForAllAddresses(raw_ostream
&OS
) {
575 auto Entries
= make_first_range(Address2ProbesMap
);
576 SmallVector
<uint64_t, 0> Addresses(Entries
.begin(), Entries
.end());
577 llvm::sort(Addresses
);
578 for (auto K
: Addresses
) {
582 printProbeForAddress(OS
, K
);
586 const MCDecodedPseudoProbe
*
587 MCPseudoProbeDecoder::getCallProbeForAddr(uint64_t Address
) const {
588 auto It
= Address2ProbesMap
.find(Address
);
589 if (It
== Address2ProbesMap
.end())
591 const auto &Probes
= It
->second
;
593 const MCDecodedPseudoProbe
*CallProbe
= nullptr;
594 for (const auto &Probe
: Probes
) {
595 if (Probe
.isCall()) {
596 // Disabling the assert and returning first call probe seen so far.
597 // Subsequent call probes, if any, are ignored. Due to the the way
598 // .pseudo_probe section is decoded, probes of the same-named independent
599 // static functions are merged thus multiple call probes may be seen for a
600 // callsite. This should only happen to compiler-generated statics, with
601 // -funique-internal-linkage-names where user statics get unique names.
603 // TODO: re-enable or narrow down the assert to static functions only.
605 // assert(!CallProbe &&
606 // "There should be only one call probe corresponding to address "
607 // "which is a callsite.");
615 const MCPseudoProbeFuncDesc
*
616 MCPseudoProbeDecoder::getFuncDescForGUID(uint64_t GUID
) const {
617 auto It
= GUID2FuncDescMap
.find(GUID
);
618 assert(It
!= GUID2FuncDescMap
.end() && "Function descriptor doesn't exist");
622 void MCPseudoProbeDecoder::getInlineContextForProbe(
623 const MCDecodedPseudoProbe
*Probe
,
624 SmallVectorImpl
<MCPseduoProbeFrameLocation
> &InlineContextStack
,
625 bool IncludeLeaf
) const {
626 Probe
->getInlineContext(InlineContextStack
, GUID2FuncDescMap
);
629 // Note that the context from probe doesn't include leaf frame,
630 // hence we need to retrieve and prepend leaf if requested.
631 const auto *FuncDesc
= getFuncDescForGUID(Probe
->getGuid());
632 InlineContextStack
.emplace_back(
633 MCPseduoProbeFrameLocation(FuncDesc
->FuncName
, Probe
->getIndex()));
636 const MCPseudoProbeFuncDesc
*MCPseudoProbeDecoder::getInlinerDescForProbe(
637 const MCDecodedPseudoProbe
*Probe
) const {
638 MCDecodedPseudoProbeInlineTree
*InlinerNode
= Probe
->getInlineTreeNode();
639 if (!InlinerNode
->hasInlineSite())
641 return getFuncDescForGUID(InlinerNode
->Parent
->Guid
);