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