1 //===- lib/MC/MCPseudoProbe.cpp - Pseudo probe encoding support ----------===//
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 "llvm/MC/MCPseudoProbe.h"
10 #include "llvm/MC/MCAsmInfo.h"
11 #include "llvm/MC/MCContext.h"
12 #include "llvm/MC/MCObjectFileInfo.h"
13 #include "llvm/MC/MCObjectStreamer.h"
14 #include "llvm/MC/MCStreamer.h"
15 #include "llvm/Support/Endian.h"
16 #include "llvm/Support/LEB128.h"
17 #include "llvm/Support/raw_ostream.h"
18 #include <limits>
19 #include <memory>
20 #include <sstream>
21
22 #define DEBUG_TYPE "mcpseudoprobe"
23
24 using namespace llvm;
25 using namespace support;
26
27 #ifndef NDEBUG
28 int MCPseudoProbeTable::DdgPrintIndent = 0;
29 #endif
30
buildSymbolDiff(MCObjectStreamer * MCOS,const MCSymbol * A,const MCSymbol * B)31 static const MCExpr *buildSymbolDiff(MCObjectStreamer *MCOS, const MCSymbol *A,
32 const MCSymbol *B) {
33 MCContext &Context = MCOS->getContext();
34 MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None;
35 const MCExpr *ARef = MCSymbolRefExpr::create(A, Variant, Context);
36 const MCExpr *BRef = MCSymbolRefExpr::create(B, Variant, Context);
37 const MCExpr *AddrDelta =
38 MCBinaryExpr::create(MCBinaryExpr::Sub, ARef, BRef, Context);
39 return AddrDelta;
40 }
41
emit(MCObjectStreamer * MCOS,const MCPseudoProbe * LastProbe) const42 void MCPseudoProbe::emit(MCObjectStreamer *MCOS,
43 const MCPseudoProbe *LastProbe) const {
44 // Emit Index
45 MCOS->emitULEB128IntValue(Index);
46 // Emit Type and the flag:
47 // Type (bit 0 to 3), with bit 4 to 6 for attributes.
48 // Flag (bit 7, 0 - code address, 1 - address delta). This indicates whether
49 // the following field is a symbolic code address or an address delta.
50 assert(Type <= 0xF && "Probe type too big to encode, exceeding 15");
51 assert(Attributes <= 0x7 &&
52 "Probe attributes too big to encode, exceeding 7");
53 uint8_t PackedType = Type | (Attributes << 4);
54 uint8_t Flag = LastProbe ? ((int8_t)MCPseudoProbeFlag::AddressDelta << 7) : 0;
55 MCOS->emitInt8(Flag | PackedType);
56
57 if (LastProbe) {
58 // Emit the delta between the address label and LastProbe.
59 const MCExpr *AddrDelta =
60 buildSymbolDiff(MCOS, Label, LastProbe->getLabel());
61 int64_t Delta;
62 if (AddrDelta->evaluateAsAbsolute(Delta, MCOS->getAssemblerPtr())) {
63 MCOS->emitSLEB128IntValue(Delta);
64 } else {
65 MCOS->insert(new MCPseudoProbeAddrFragment(AddrDelta));
66 }
67 } else {
68 // Emit label as a symbolic code address.
69 MCOS->emitSymbolValue(
70 Label, MCOS->getContext().getAsmInfo()->getCodePointerSize());
71 }
72
73 LLVM_DEBUG({
74 dbgs().indent(MCPseudoProbeTable::DdgPrintIndent);
75 dbgs() << "Probe: " << Index << "\n";
76 });
77 }
78
addPseudoProbe(const MCPseudoProbe & Probe,const MCPseudoProbeInlineStack & InlineStack)79 void MCPseudoProbeInlineTree::addPseudoProbe(
80 const MCPseudoProbe &Probe, const MCPseudoProbeInlineStack &InlineStack) {
81 // The function should not be called on the root.
82 assert(isRoot() && "Should not be called on root");
83
84 // When it comes here, the input look like:
85 // Probe: GUID of C, ...
86 // InlineStack: [88, A], [66, B]
87 // which means, Function A inlines function B at call site with a probe id of
88 // 88, and B inlines C at probe 66. The tri-tree expects a tree path like {[0,
89 // A], [88, B], [66, C]} to locate the tree node where the probe should be
90 // added. Note that the edge [0, A] means A is the top-level function we are
91 // emitting probes for.
92
93 // Make a [0, A] edge.
94 // An empty inline stack means the function that the probe originates from
95 // is a top-level function.
96 InlineSite Top;
97 if (InlineStack.empty()) {
98 Top = InlineSite(Probe.getGuid(), 0);
99 } else {
100 Top = InlineSite(std::get<0>(InlineStack.front()), 0);
101 }
102
103 auto *Cur = getOrAddNode(Top);
104
105 // Make interior edges by walking the inline stack. Once it's done, Cur should
106 // point to the node that the probe originates from.
107 if (!InlineStack.empty()) {
108 auto Iter = InlineStack.begin();
109 auto Index = std::get<1>(*Iter);
110 Iter++;
111 for (; Iter != InlineStack.end(); Iter++) {
112 // Make an edge by using the previous probe id and current GUID.
113 Cur = Cur->getOrAddNode(InlineSite(std::get<0>(*Iter), Index));
114 Index = std::get<1>(*Iter);
115 }
116 Cur = Cur->getOrAddNode(InlineSite(Probe.getGuid(), Index));
117 }
118
119 Cur->Probes.push_back(Probe);
120 }
121
emit(MCObjectStreamer * MCOS,const MCPseudoProbe * & LastProbe)122 void MCPseudoProbeInlineTree::emit(MCObjectStreamer *MCOS,
123 const MCPseudoProbe *&LastProbe) {
124 LLVM_DEBUG({
125 dbgs().indent(MCPseudoProbeTable::DdgPrintIndent);
126 dbgs() << "Group [\n";
127 MCPseudoProbeTable::DdgPrintIndent += 2;
128 });
129 // Emit probes grouped by GUID.
130 if (Guid != 0) {
131 LLVM_DEBUG({
132 dbgs().indent(MCPseudoProbeTable::DdgPrintIndent);
133 dbgs() << "GUID: " << Guid << "\n";
134 });
135 // Emit Guid
136 MCOS->emitInt64(Guid);
137 // Emit number of probes in this node
138 MCOS->emitULEB128IntValue(Probes.size());
139 // Emit number of direct inlinees
140 MCOS->emitULEB128IntValue(Children.size());
141 // Emit probes in this group
142 for (const auto &Probe : Probes) {
143 Probe.emit(MCOS, LastProbe);
144 LastProbe = &Probe;
145 }
146 } else {
147 assert(Probes.empty() && "Root should not have probes");
148 }
149
150 // Emit sorted descendant
151 // InlineSite is unique for each pair,
152 // so there will be no ordering of Inlinee based on MCPseudoProbeInlineTree*
153 std::map<InlineSite, MCPseudoProbeInlineTree *> Inlinees;
154 for (auto Child = Children.begin(); Child != Children.end(); ++Child)
155 Inlinees[Child->first] = Child->second.get();
156
157 for (const auto &Inlinee : Inlinees) {
158 if (Guid) {
159 // Emit probe index
160 MCOS->emitULEB128IntValue(std::get<1>(Inlinee.first));
161 LLVM_DEBUG({
162 dbgs().indent(MCPseudoProbeTable::DdgPrintIndent);
163 dbgs() << "InlineSite: " << std::get<1>(Inlinee.first) << "\n";
164 });
165 }
166 // Emit the group
167 Inlinee.second->emit(MCOS, LastProbe);
168 }
169
170 LLVM_DEBUG({
171 MCPseudoProbeTable::DdgPrintIndent -= 2;
172 dbgs().indent(MCPseudoProbeTable::DdgPrintIndent);
173 dbgs() << "]\n";
174 });
175 }
176
emit(MCObjectStreamer * MCOS)177 void MCPseudoProbeSection::emit(MCObjectStreamer *MCOS) {
178 MCContext &Ctx = MCOS->getContext();
179
180 for (auto &ProbeSec : MCProbeDivisions) {
181 const MCPseudoProbe *LastProbe = nullptr;
182 if (auto *S =
183 Ctx.getObjectFileInfo()->getPseudoProbeSection(ProbeSec.first)) {
184 // Switch to the .pseudoprobe section or a comdat group.
185 MCOS->SwitchSection(S);
186 // Emit probes grouped by GUID.
187 ProbeSec.second.emit(MCOS, LastProbe);
188 }
189 }
190 }
191
192 //
193 // This emits the pseudo probe tables.
194 //
emit(MCObjectStreamer * MCOS)195 void MCPseudoProbeTable::emit(MCObjectStreamer *MCOS) {
196 MCContext &Ctx = MCOS->getContext();
197 auto &ProbeTable = Ctx.getMCPseudoProbeTable();
198
199 // Bail out early so we don't switch to the pseudo_probe section needlessly
200 // and in doing so create an unnecessary (if empty) section.
201 auto &ProbeSections = ProbeTable.getProbeSections();
202 if (ProbeSections.empty())
203 return;
204
205 LLVM_DEBUG(MCPseudoProbeTable::DdgPrintIndent = 0);
206
207 // Put out the probe.
208 ProbeSections.emit(MCOS);
209 }
210
getProbeFNameForGUID(const GUIDProbeFunctionMap & GUID2FuncMAP,uint64_t GUID)211 static StringRef getProbeFNameForGUID(const GUIDProbeFunctionMap &GUID2FuncMAP,
212 uint64_t GUID) {
213 auto It = GUID2FuncMAP.find(GUID);
214 assert(It != GUID2FuncMAP.end() &&
215 "Probe function must exist for a valid GUID");
216 return It->second.FuncName;
217 }
218
print(raw_ostream & OS)219 void MCPseudoProbeFuncDesc::print(raw_ostream &OS) {
220 OS << "GUID: " << FuncGUID << " Name: " << FuncName << "\n";
221 OS << "Hash: " << FuncHash << "\n";
222 }
223
getInlineContext(SmallVectorImpl<MCPseduoProbeFrameLocation> & ContextStack,const GUIDProbeFunctionMap & GUID2FuncMAP) const224 void MCDecodedPseudoProbe::getInlineContext(
225 SmallVectorImpl<MCPseduoProbeFrameLocation> &ContextStack,
226 const GUIDProbeFunctionMap &GUID2FuncMAP) const {
227 uint32_t Begin = ContextStack.size();
228 MCDecodedPseudoProbeInlineTree *Cur = InlineTree;
229 // It will add the string of each node's inline site during iteration.
230 // Note that it won't include the probe's belonging function(leaf location)
231 while (Cur->hasInlineSite()) {
232 StringRef FuncName =
233 getProbeFNameForGUID(GUID2FuncMAP, std::get<0>(Cur->ISite));
234 ContextStack.emplace_back(
235 MCPseduoProbeFrameLocation(FuncName, std::get<1>(Cur->ISite)));
236 Cur = static_cast<MCDecodedPseudoProbeInlineTree *>(Cur->Parent);
237 }
238 // Make the ContextStack in caller-callee order
239 std::reverse(ContextStack.begin() + Begin, ContextStack.end());
240 }
241
getInlineContextStr(const GUIDProbeFunctionMap & GUID2FuncMAP) const242 std::string MCDecodedPseudoProbe::getInlineContextStr(
243 const GUIDProbeFunctionMap &GUID2FuncMAP) const {
244 std::ostringstream OContextStr;
245 SmallVector<MCPseduoProbeFrameLocation, 16> ContextStack;
246 getInlineContext(ContextStack, GUID2FuncMAP);
247 for (auto &Cxt : ContextStack) {
248 if (OContextStr.str().size())
249 OContextStr << " @ ";
250 OContextStr << Cxt.first.str() << ":" << Cxt.second;
251 }
252 return OContextStr.str();
253 }
254
255 static const char *PseudoProbeTypeStr[3] = {"Block", "IndirectCall",
256 "DirectCall"};
257
print(raw_ostream & OS,const GUIDProbeFunctionMap & GUID2FuncMAP,bool ShowName) const258 void MCDecodedPseudoProbe::print(raw_ostream &OS,
259 const GUIDProbeFunctionMap &GUID2FuncMAP,
260 bool ShowName) const {
261 OS << "FUNC: ";
262 if (ShowName) {
263 StringRef FuncName = getProbeFNameForGUID(GUID2FuncMAP, Guid);
264 OS << FuncName.str() << " ";
265 } else {
266 OS << Guid << " ";
267 }
268 OS << "Index: " << Index << " ";
269 OS << "Type: " << PseudoProbeTypeStr[static_cast<uint8_t>(Type)] << " ";
270 std::string InlineContextStr = getInlineContextStr(GUID2FuncMAP);
271 if (InlineContextStr.size()) {
272 OS << "Inlined: @ ";
273 OS << InlineContextStr;
274 }
275 OS << "\n";
276 }
277
readUnencodedNumber()278 template <typename T> ErrorOr<T> MCPseudoProbeDecoder::readUnencodedNumber() {
279 if (Data + sizeof(T) > End) {
280 return std::error_code();
281 }
282 T Val = endian::readNext<T, little, unaligned>(Data);
283 return ErrorOr<T>(Val);
284 }
285
readUnsignedNumber()286 template <typename T> ErrorOr<T> MCPseudoProbeDecoder::readUnsignedNumber() {
287 unsigned NumBytesRead = 0;
288 uint64_t Val = decodeULEB128(Data, &NumBytesRead);
289 if (Val > std::numeric_limits<T>::max() || (Data + NumBytesRead > End)) {
290 return std::error_code();
291 }
292 Data += NumBytesRead;
293 return ErrorOr<T>(static_cast<T>(Val));
294 }
295
readSignedNumber()296 template <typename T> ErrorOr<T> MCPseudoProbeDecoder::readSignedNumber() {
297 unsigned NumBytesRead = 0;
298 int64_t Val = decodeSLEB128(Data, &NumBytesRead);
299 if (Val > std::numeric_limits<T>::max() || (Data + NumBytesRead > End)) {
300 return std::error_code();
301 }
302 Data += NumBytesRead;
303 return ErrorOr<T>(static_cast<T>(Val));
304 }
305
readString(uint32_t Size)306 ErrorOr<StringRef> MCPseudoProbeDecoder::readString(uint32_t Size) {
307 StringRef Str(reinterpret_cast<const char *>(Data), Size);
308 if (Data + Size > End) {
309 return std::error_code();
310 }
311 Data += Size;
312 return ErrorOr<StringRef>(Str);
313 }
314
buildGUID2FuncDescMap(const uint8_t * Start,std::size_t Size)315 bool MCPseudoProbeDecoder::buildGUID2FuncDescMap(const uint8_t *Start,
316 std::size_t Size) {
317 // The pseudo_probe_desc section has a format like:
318 // .section .pseudo_probe_desc,"",@progbits
319 // .quad -5182264717993193164 // GUID
320 // .quad 4294967295 // Hash
321 // .uleb 3 // Name size
322 // .ascii "foo" // Name
323 // .quad -2624081020897602054
324 // .quad 174696971957
325 // .uleb 34
326 // .ascii "main"
327
328 Data = Start;
329 End = Data + Size;
330
331 while (Data < End) {
332 auto ErrorOrGUID = readUnencodedNumber<uint64_t>();
333 if (!ErrorOrGUID)
334 return false;
335
336 auto ErrorOrHash = readUnencodedNumber<uint64_t>();
337 if (!ErrorOrHash)
338 return false;
339
340 auto ErrorOrNameSize = readUnsignedNumber<uint32_t>();
341 if (!ErrorOrNameSize)
342 return false;
343 uint32_t NameSize = std::move(*ErrorOrNameSize);
344
345 auto ErrorOrName = readString(NameSize);
346 if (!ErrorOrName)
347 return false;
348
349 uint64_t GUID = std::move(*ErrorOrGUID);
350 uint64_t Hash = std::move(*ErrorOrHash);
351 StringRef Name = std::move(*ErrorOrName);
352
353 // Initialize PseudoProbeFuncDesc and populate it into GUID2FuncDescMap
354 GUID2FuncDescMap.emplace(GUID, MCPseudoProbeFuncDesc(GUID, Hash, Name));
355 }
356 assert(Data == End && "Have unprocessed data in pseudo_probe_desc section");
357 return true;
358 }
359
buildAddress2ProbeMap(const uint8_t * Start,std::size_t Size)360 bool MCPseudoProbeDecoder::buildAddress2ProbeMap(const uint8_t *Start,
361 std::size_t Size) {
362 // The pseudo_probe section encodes an inline forest and each tree has a
363 // format like:
364 // FUNCTION BODY (one for each uninlined function present in the text
365 // section)
366 // GUID (uint64)
367 // GUID of the function
368 // NPROBES (ULEB128)
369 // Number of probes originating from this function.
370 // NUM_INLINED_FUNCTIONS (ULEB128)
371 // Number of callees inlined into this function, aka number of
372 // first-level inlinees
373 // PROBE RECORDS
374 // A list of NPROBES entries. Each entry contains:
375 // INDEX (ULEB128)
376 // TYPE (uint4)
377 // 0 - block probe, 1 - indirect call, 2 - direct call
378 // ATTRIBUTE (uint3)
379 // 1 - tail call, 2 - dangling
380 // ADDRESS_TYPE (uint1)
381 // 0 - code address, 1 - address delta
382 // CODE_ADDRESS (uint64 or ULEB128)
383 // code address or address delta, depending on Flag
384 // INLINED FUNCTION RECORDS
385 // A list of NUM_INLINED_FUNCTIONS entries describing each of the
386 // inlined callees. Each record contains:
387 // INLINE SITE
388 // Index of the callsite probe (ULEB128)
389 // FUNCTION BODY
390 // A FUNCTION BODY entry describing the inlined function.
391
392 Data = Start;
393 End = Data + Size;
394
395 MCDecodedPseudoProbeInlineTree *Root = &DummyInlineRoot;
396 MCDecodedPseudoProbeInlineTree *Cur = &DummyInlineRoot;
397 uint64_t LastAddr = 0;
398 uint32_t Index = 0;
399 // A DFS-based decoding
400 while (Data < End) {
401 if (Root == Cur) {
402 // Use a sequential id for top level inliner.
403 Index = Root->getChildren().size();
404 } else {
405 // Read inline site for inlinees
406 auto ErrorOrIndex = readUnsignedNumber<uint32_t>();
407 if (!ErrorOrIndex)
408 return false;
409 Index = std::move(*ErrorOrIndex);
410 }
411 // Switch/add to a new tree node(inlinee)
412 Cur = Cur->getOrAddNode(std::make_tuple(Cur->Guid, Index));
413 // Read guid
414 auto ErrorOrCurGuid = readUnencodedNumber<uint64_t>();
415 if (!ErrorOrCurGuid)
416 return false;
417 Cur->Guid = std::move(*ErrorOrCurGuid);
418 // Read number of probes in the current node.
419 auto ErrorOrNodeCount = readUnsignedNumber<uint32_t>();
420 if (!ErrorOrNodeCount)
421 return false;
422 uint32_t NodeCount = std::move(*ErrorOrNodeCount);
423 // Read number of direct inlinees
424 auto ErrorOrCurChildrenToProcess = readUnsignedNumber<uint32_t>();
425 if (!ErrorOrCurChildrenToProcess)
426 return false;
427 Cur->ChildrenToProcess = std::move(*ErrorOrCurChildrenToProcess);
428 // Read all probes in this node
429 for (std::size_t I = 0; I < NodeCount; I++) {
430 // Read index
431 auto ErrorOrIndex = readUnsignedNumber<uint32_t>();
432 if (!ErrorOrIndex)
433 return false;
434 uint32_t Index = std::move(*ErrorOrIndex);
435 // Read type | flag.
436 auto ErrorOrValue = readUnencodedNumber<uint8_t>();
437 if (!ErrorOrValue)
438 return false;
439 uint8_t Value = std::move(*ErrorOrValue);
440 uint8_t Kind = Value & 0xf;
441 uint8_t Attr = (Value & 0x70) >> 4;
442 // Read address
443 uint64_t Addr = 0;
444 if (Value & 0x80) {
445 auto ErrorOrOffset = readSignedNumber<int64_t>();
446 if (!ErrorOrOffset)
447 return false;
448 int64_t Offset = std::move(*ErrorOrOffset);
449 Addr = LastAddr + Offset;
450 } else {
451 auto ErrorOrAddr = readUnencodedNumber<int64_t>();
452 if (!ErrorOrAddr)
453 return false;
454 Addr = std::move(*ErrorOrAddr);
455 }
456 // Populate Address2ProbesMap
457 auto &Probes = Address2ProbesMap[Addr];
458 Probes.emplace_back(Addr, Cur->Guid, Index, PseudoProbeType(Kind), Attr,
459 Cur);
460 Cur->addProbes(&Probes.back());
461 LastAddr = Addr;
462 }
463
464 // Look for the parent for the next node by subtracting the current
465 // node count from tree counts along the parent chain. The first node
466 // in the chain that has a non-zero tree count is the target.
467 while (Cur != Root) {
468 if (Cur->ChildrenToProcess == 0) {
469 Cur = static_cast<MCDecodedPseudoProbeInlineTree *>(Cur->Parent);
470 if (Cur != Root) {
471 assert(Cur->ChildrenToProcess > 0 &&
472 "Should have some unprocessed nodes");
473 Cur->ChildrenToProcess -= 1;
474 }
475 } else {
476 break;
477 }
478 }
479 }
480
481 assert(Data == End && "Have unprocessed data in pseudo_probe section");
482 assert(Cur == Root &&
483 " Cur should point to root when the forest is fully built up");
484 return true;
485 }
486
printGUID2FuncDescMap(raw_ostream & OS)487 void MCPseudoProbeDecoder::printGUID2FuncDescMap(raw_ostream &OS) {
488 OS << "Pseudo Probe Desc:\n";
489 // Make the output deterministic
490 std::map<uint64_t, MCPseudoProbeFuncDesc> OrderedMap(GUID2FuncDescMap.begin(),
491 GUID2FuncDescMap.end());
492 for (auto &I : OrderedMap) {
493 I.second.print(OS);
494 }
495 }
496
printProbeForAddress(raw_ostream & OS,uint64_t Address)497 void MCPseudoProbeDecoder::printProbeForAddress(raw_ostream &OS,
498 uint64_t Address) {
499 auto It = Address2ProbesMap.find(Address);
500 if (It != Address2ProbesMap.end()) {
501 for (auto &Probe : It->second) {
502 OS << " [Probe]:\t";
503 Probe.print(OS, GUID2FuncDescMap, true);
504 }
505 }
506 }
507
printProbesForAllAddresses(raw_ostream & OS)508 void MCPseudoProbeDecoder::printProbesForAllAddresses(raw_ostream &OS) {
509 std::vector<uint64_t> Addresses;
510 for (auto Entry : Address2ProbesMap)
511 Addresses.push_back(Entry.first);
512 std::sort(Addresses.begin(), Addresses.end());
513 for (auto K : Addresses) {
514 OS << "Address:\t";
515 OS << K;
516 OS << "\n";
517 printProbeForAddress(OS, K);
518 }
519 }
520
521 const MCDecodedPseudoProbe *
getCallProbeForAddr(uint64_t Address) const522 MCPseudoProbeDecoder::getCallProbeForAddr(uint64_t Address) const {
523 auto It = Address2ProbesMap.find(Address);
524 if (It == Address2ProbesMap.end())
525 return nullptr;
526 const auto &Probes = It->second;
527
528 const MCDecodedPseudoProbe *CallProbe = nullptr;
529 for (const auto &Probe : Probes) {
530 if (Probe.isCall()) {
531 assert(!CallProbe &&
532 "There should be only one call probe corresponding to address "
533 "which is a callsite.");
534 CallProbe = &Probe;
535 }
536 }
537 return CallProbe;
538 }
539
540 const MCPseudoProbeFuncDesc *
getFuncDescForGUID(uint64_t GUID) const541 MCPseudoProbeDecoder::getFuncDescForGUID(uint64_t GUID) const {
542 auto It = GUID2FuncDescMap.find(GUID);
543 assert(It != GUID2FuncDescMap.end() && "Function descriptor doesn't exist");
544 return &It->second;
545 }
546
getInlineContextForProbe(const MCDecodedPseudoProbe * Probe,SmallVectorImpl<MCPseduoProbeFrameLocation> & InlineContextStack,bool IncludeLeaf) const547 void MCPseudoProbeDecoder::getInlineContextForProbe(
548 const MCDecodedPseudoProbe *Probe,
549 SmallVectorImpl<MCPseduoProbeFrameLocation> &InlineContextStack,
550 bool IncludeLeaf) const {
551 Probe->getInlineContext(InlineContextStack, GUID2FuncDescMap);
552 if (!IncludeLeaf)
553 return;
554 // Note that the context from probe doesn't include leaf frame,
555 // hence we need to retrieve and prepend leaf if requested.
556 const auto *FuncDesc = getFuncDescForGUID(Probe->getGuid());
557 InlineContextStack.emplace_back(
558 MCPseduoProbeFrameLocation(FuncDesc->FuncName, Probe->getIndex()));
559 }
560
getInlinerDescForProbe(const MCDecodedPseudoProbe * Probe) const561 const MCPseudoProbeFuncDesc *MCPseudoProbeDecoder::getInlinerDescForProbe(
562 const MCDecodedPseudoProbe *Probe) const {
563 MCDecodedPseudoProbeInlineTree *InlinerNode = Probe->getInlineTreeNode();
564 if (!InlinerNode->hasInlineSite())
565 return nullptr;
566 return getFuncDescForGUID(std::get<0>(InlinerNode->ISite));
567 }
568