1e8d8bef9SDimitry Andric //===- lib/MC/MCPseudoProbe.cpp - Pseudo probe encoding support ----------===//
2e8d8bef9SDimitry Andric //
3e8d8bef9SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e8d8bef9SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5e8d8bef9SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e8d8bef9SDimitry Andric //
7e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===//
8e8d8bef9SDimitry Andric
9e8d8bef9SDimitry Andric #include "llvm/MC/MCPseudoProbe.h"
10fcaf7f86SDimitry Andric #include "llvm/ADT/STLExtras.h"
1106c3fb27SDimitry Andric #include "llvm/IR/PseudoProbe.h"
12e8d8bef9SDimitry Andric #include "llvm/MC/MCAsmInfo.h"
13*5f757f3fSDimitry Andric #include "llvm/MC/MCAssembler.h"
14e8d8bef9SDimitry Andric #include "llvm/MC/MCContext.h"
1581ad6265SDimitry Andric #include "llvm/MC/MCExpr.h"
1681ad6265SDimitry Andric #include "llvm/MC/MCFragment.h"
17e8d8bef9SDimitry Andric #include "llvm/MC/MCObjectFileInfo.h"
18e8d8bef9SDimitry Andric #include "llvm/MC/MCObjectStreamer.h"
19bdd1243dSDimitry Andric #include "llvm/MC/MCSymbol.h"
20349cc55cSDimitry Andric #include "llvm/Support/Endian.h"
21349cc55cSDimitry Andric #include "llvm/Support/LEB128.h"
22bdd1243dSDimitry Andric #include "llvm/Support/MD5.h"
23349cc55cSDimitry Andric #include "llvm/Support/raw_ostream.h"
24bdd1243dSDimitry Andric #include <algorithm>
25bdd1243dSDimitry Andric #include <cassert>
26349cc55cSDimitry Andric #include <limits>
27349cc55cSDimitry Andric #include <memory>
28349cc55cSDimitry Andric #include <sstream>
29bdd1243dSDimitry Andric #include <vector>
30e8d8bef9SDimitry Andric
31e8d8bef9SDimitry Andric #define DEBUG_TYPE "mcpseudoprobe"
32e8d8bef9SDimitry Andric
33e8d8bef9SDimitry Andric using namespace llvm;
34349cc55cSDimitry Andric using namespace support;
35e8d8bef9SDimitry Andric
36e8d8bef9SDimitry Andric #ifndef NDEBUG
37e8d8bef9SDimitry Andric int MCPseudoProbeTable::DdgPrintIndent = 0;
38e8d8bef9SDimitry Andric #endif
39e8d8bef9SDimitry Andric
buildSymbolDiff(MCObjectStreamer * MCOS,const MCSymbol * A,const MCSymbol * B)40e8d8bef9SDimitry Andric static const MCExpr *buildSymbolDiff(MCObjectStreamer *MCOS, const MCSymbol *A,
41e8d8bef9SDimitry Andric const MCSymbol *B) {
42e8d8bef9SDimitry Andric MCContext &Context = MCOS->getContext();
43e8d8bef9SDimitry Andric MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None;
44e8d8bef9SDimitry Andric const MCExpr *ARef = MCSymbolRefExpr::create(A, Variant, Context);
45e8d8bef9SDimitry Andric const MCExpr *BRef = MCSymbolRefExpr::create(B, Variant, Context);
46e8d8bef9SDimitry Andric const MCExpr *AddrDelta =
47e8d8bef9SDimitry Andric MCBinaryExpr::create(MCBinaryExpr::Sub, ARef, BRef, Context);
48e8d8bef9SDimitry Andric return AddrDelta;
49e8d8bef9SDimitry Andric }
50e8d8bef9SDimitry Andric
emit(MCObjectStreamer * MCOS,const MCPseudoProbe * LastProbe) const51e8d8bef9SDimitry Andric void MCPseudoProbe::emit(MCObjectStreamer *MCOS,
52e8d8bef9SDimitry Andric const MCPseudoProbe *LastProbe) const {
53bdd1243dSDimitry Andric bool IsSentinel = isSentinelProbe(getAttributes());
54bdd1243dSDimitry Andric assert((LastProbe || IsSentinel) &&
55bdd1243dSDimitry Andric "Last probe should not be null for non-sentinel probes");
56bdd1243dSDimitry Andric
57e8d8bef9SDimitry Andric // Emit Index
58e8d8bef9SDimitry Andric MCOS->emitULEB128IntValue(Index);
59e8d8bef9SDimitry Andric // Emit Type and the flag:
60e8d8bef9SDimitry Andric // Type (bit 0 to 3), with bit 4 to 6 for attributes.
61e8d8bef9SDimitry Andric // Flag (bit 7, 0 - code address, 1 - address delta). This indicates whether
62e8d8bef9SDimitry Andric // the following field is a symbolic code address or an address delta.
6306c3fb27SDimitry Andric // Emit FS discriminator
64e8d8bef9SDimitry Andric assert(Type <= 0xF && "Probe type too big to encode, exceeding 15");
6506c3fb27SDimitry Andric auto NewAttributes = Attributes;
6606c3fb27SDimitry Andric if (Discriminator)
6706c3fb27SDimitry Andric NewAttributes |= (uint32_t)PseudoProbeAttributes::HasDiscriminator;
6806c3fb27SDimitry Andric assert(NewAttributes <= 0x7 &&
69e8d8bef9SDimitry Andric "Probe attributes too big to encode, exceeding 7");
7006c3fb27SDimitry Andric uint8_t PackedType = Type | (NewAttributes << 4);
71bdd1243dSDimitry Andric uint8_t Flag =
72bdd1243dSDimitry Andric !IsSentinel ? ((int8_t)MCPseudoProbeFlag::AddressDelta << 7) : 0;
73e8d8bef9SDimitry Andric MCOS->emitInt8(Flag | PackedType);
74e8d8bef9SDimitry Andric
75bdd1243dSDimitry Andric if (!IsSentinel) {
76e8d8bef9SDimitry Andric // Emit the delta between the address label and LastProbe.
77e8d8bef9SDimitry Andric const MCExpr *AddrDelta =
78e8d8bef9SDimitry Andric buildSymbolDiff(MCOS, Label, LastProbe->getLabel());
79e8d8bef9SDimitry Andric int64_t Delta;
80e8d8bef9SDimitry Andric if (AddrDelta->evaluateAsAbsolute(Delta, MCOS->getAssemblerPtr())) {
81e8d8bef9SDimitry Andric MCOS->emitSLEB128IntValue(Delta);
82e8d8bef9SDimitry Andric } else {
83e8d8bef9SDimitry Andric MCOS->insert(new MCPseudoProbeAddrFragment(AddrDelta));
84e8d8bef9SDimitry Andric }
85e8d8bef9SDimitry Andric } else {
86bdd1243dSDimitry Andric // Emit the GUID of the split function that the sentinel probe represents.
87bdd1243dSDimitry Andric MCOS->emitInt64(Guid);
88e8d8bef9SDimitry Andric }
89e8d8bef9SDimitry Andric
9006c3fb27SDimitry Andric if (Discriminator)
9106c3fb27SDimitry Andric MCOS->emitULEB128IntValue(Discriminator);
9206c3fb27SDimitry Andric
93e8d8bef9SDimitry Andric LLVM_DEBUG({
94e8d8bef9SDimitry Andric dbgs().indent(MCPseudoProbeTable::DdgPrintIndent);
95e8d8bef9SDimitry Andric dbgs() << "Probe: " << Index << "\n";
96e8d8bef9SDimitry Andric });
97e8d8bef9SDimitry Andric }
98e8d8bef9SDimitry Andric
addPseudoProbe(const MCPseudoProbe & Probe,const MCPseudoProbeInlineStack & InlineStack)99e8d8bef9SDimitry Andric void MCPseudoProbeInlineTree::addPseudoProbe(
100e8d8bef9SDimitry Andric const MCPseudoProbe &Probe, const MCPseudoProbeInlineStack &InlineStack) {
101e8d8bef9SDimitry Andric // The function should not be called on the root.
102bdd1243dSDimitry Andric assert(isRoot() && "Should only be called on root");
103e8d8bef9SDimitry Andric
104e8d8bef9SDimitry Andric // When it comes here, the input look like:
105e8d8bef9SDimitry Andric // Probe: GUID of C, ...
106e8d8bef9SDimitry Andric // InlineStack: [88, A], [66, B]
107e8d8bef9SDimitry Andric // which means, Function A inlines function B at call site with a probe id of
108e8d8bef9SDimitry Andric // 88, and B inlines C at probe 66. The tri-tree expects a tree path like {[0,
109e8d8bef9SDimitry Andric // A], [88, B], [66, C]} to locate the tree node where the probe should be
110e8d8bef9SDimitry Andric // added. Note that the edge [0, A] means A is the top-level function we are
111e8d8bef9SDimitry Andric // emitting probes for.
112e8d8bef9SDimitry Andric
113e8d8bef9SDimitry Andric // Make a [0, A] edge.
114e8d8bef9SDimitry Andric // An empty inline stack means the function that the probe originates from
115e8d8bef9SDimitry Andric // is a top-level function.
116e8d8bef9SDimitry Andric InlineSite Top;
117e8d8bef9SDimitry Andric if (InlineStack.empty()) {
118e8d8bef9SDimitry Andric Top = InlineSite(Probe.getGuid(), 0);
119e8d8bef9SDimitry Andric } else {
120e8d8bef9SDimitry Andric Top = InlineSite(std::get<0>(InlineStack.front()), 0);
121e8d8bef9SDimitry Andric }
122e8d8bef9SDimitry Andric
123e8d8bef9SDimitry Andric auto *Cur = getOrAddNode(Top);
124e8d8bef9SDimitry Andric
125e8d8bef9SDimitry Andric // Make interior edges by walking the inline stack. Once it's done, Cur should
126e8d8bef9SDimitry Andric // point to the node that the probe originates from.
127e8d8bef9SDimitry Andric if (!InlineStack.empty()) {
128e8d8bef9SDimitry Andric auto Iter = InlineStack.begin();
129e8d8bef9SDimitry Andric auto Index = std::get<1>(*Iter);
130e8d8bef9SDimitry Andric Iter++;
131e8d8bef9SDimitry Andric for (; Iter != InlineStack.end(); Iter++) {
132e8d8bef9SDimitry Andric // Make an edge by using the previous probe id and current GUID.
133e8d8bef9SDimitry Andric Cur = Cur->getOrAddNode(InlineSite(std::get<0>(*Iter), Index));
134e8d8bef9SDimitry Andric Index = std::get<1>(*Iter);
135e8d8bef9SDimitry Andric }
136e8d8bef9SDimitry Andric Cur = Cur->getOrAddNode(InlineSite(Probe.getGuid(), Index));
137e8d8bef9SDimitry Andric }
138e8d8bef9SDimitry Andric
139e8d8bef9SDimitry Andric Cur->Probes.push_back(Probe);
140e8d8bef9SDimitry Andric }
141e8d8bef9SDimitry Andric
emit(MCObjectStreamer * MCOS,const MCPseudoProbe * & LastProbe)142e8d8bef9SDimitry Andric void MCPseudoProbeInlineTree::emit(MCObjectStreamer *MCOS,
143e8d8bef9SDimitry Andric const MCPseudoProbe *&LastProbe) {
144e8d8bef9SDimitry Andric LLVM_DEBUG({
145e8d8bef9SDimitry Andric dbgs().indent(MCPseudoProbeTable::DdgPrintIndent);
146e8d8bef9SDimitry Andric dbgs() << "Group [\n";
147e8d8bef9SDimitry Andric MCPseudoProbeTable::DdgPrintIndent += 2;
148e8d8bef9SDimitry Andric });
149bdd1243dSDimitry Andric assert(!isRoot() && "Root should be handled seperately");
150bdd1243dSDimitry Andric
151e8d8bef9SDimitry Andric // Emit probes grouped by GUID.
152e8d8bef9SDimitry Andric LLVM_DEBUG({
153e8d8bef9SDimitry Andric dbgs().indent(MCPseudoProbeTable::DdgPrintIndent);
154e8d8bef9SDimitry Andric dbgs() << "GUID: " << Guid << "\n";
155e8d8bef9SDimitry Andric });
156e8d8bef9SDimitry Andric // Emit Guid
157e8d8bef9SDimitry Andric MCOS->emitInt64(Guid);
158bdd1243dSDimitry Andric // Emit number of probes in this node, including a sentinel probe for
159bdd1243dSDimitry Andric // top-level functions if needed.
160bdd1243dSDimitry Andric bool NeedSentinel = false;
161bdd1243dSDimitry Andric if (Parent->isRoot()) {
162bdd1243dSDimitry Andric assert(isSentinelProbe(LastProbe->getAttributes()) &&
163bdd1243dSDimitry Andric "Starting probe of a top-level function should be a sentinel probe");
164bdd1243dSDimitry Andric // The main body of a split function doesn't need a sentinel probe.
165bdd1243dSDimitry Andric if (LastProbe->getGuid() != Guid)
166bdd1243dSDimitry Andric NeedSentinel = true;
167bdd1243dSDimitry Andric }
168bdd1243dSDimitry Andric
169bdd1243dSDimitry Andric MCOS->emitULEB128IntValue(Probes.size() + NeedSentinel);
170e8d8bef9SDimitry Andric // Emit number of direct inlinees
171349cc55cSDimitry Andric MCOS->emitULEB128IntValue(Children.size());
172bdd1243dSDimitry Andric // Emit sentinel probe for top-level functions
173bdd1243dSDimitry Andric if (NeedSentinel)
174bdd1243dSDimitry Andric LastProbe->emit(MCOS, nullptr);
175bdd1243dSDimitry Andric
176e8d8bef9SDimitry Andric // Emit probes in this group
177e8d8bef9SDimitry Andric for (const auto &Probe : Probes) {
178e8d8bef9SDimitry Andric Probe.emit(MCOS, LastProbe);
179e8d8bef9SDimitry Andric LastProbe = &Probe;
180e8d8bef9SDimitry Andric }
181e8d8bef9SDimitry Andric
182bdd1243dSDimitry Andric // Emit sorted descendant. InlineSite is unique for each pair, so there will
183bdd1243dSDimitry Andric // be no ordering of Inlinee based on MCPseudoProbeInlineTree*
184bdd1243dSDimitry Andric using InlineeType = std::pair<InlineSite, MCPseudoProbeInlineTree *>;
185bdd1243dSDimitry Andric auto Comparer = [](const InlineeType &A, const InlineeType &B) {
186bdd1243dSDimitry Andric return A.first < B.first;
187bdd1243dSDimitry Andric };
188bdd1243dSDimitry Andric std::vector<InlineeType> Inlinees;
189bdd1243dSDimitry Andric for (const auto &Child : Children)
190bdd1243dSDimitry Andric Inlinees.emplace_back(Child.first, Child.second.get());
191bdd1243dSDimitry Andric std::sort(Inlinees.begin(), Inlinees.end(), Comparer);
192349cc55cSDimitry Andric
193e8d8bef9SDimitry Andric for (const auto &Inlinee : Inlinees) {
194e8d8bef9SDimitry Andric // Emit probe index
195e8d8bef9SDimitry Andric MCOS->emitULEB128IntValue(std::get<1>(Inlinee.first));
196e8d8bef9SDimitry Andric LLVM_DEBUG({
197e8d8bef9SDimitry Andric dbgs().indent(MCPseudoProbeTable::DdgPrintIndent);
198e8d8bef9SDimitry Andric dbgs() << "InlineSite: " << std::get<1>(Inlinee.first) << "\n";
199e8d8bef9SDimitry Andric });
200e8d8bef9SDimitry Andric // Emit the group
201e8d8bef9SDimitry Andric Inlinee.second->emit(MCOS, LastProbe);
202e8d8bef9SDimitry Andric }
203e8d8bef9SDimitry Andric
204e8d8bef9SDimitry Andric LLVM_DEBUG({
205e8d8bef9SDimitry Andric MCPseudoProbeTable::DdgPrintIndent -= 2;
206e8d8bef9SDimitry Andric dbgs().indent(MCPseudoProbeTable::DdgPrintIndent);
207e8d8bef9SDimitry Andric dbgs() << "]\n";
208e8d8bef9SDimitry Andric });
209e8d8bef9SDimitry Andric }
210e8d8bef9SDimitry Andric
emit(MCObjectStreamer * MCOS)211bdd1243dSDimitry Andric void MCPseudoProbeSections::emit(MCObjectStreamer *MCOS) {
212e8d8bef9SDimitry Andric MCContext &Ctx = MCOS->getContext();
213*5f757f3fSDimitry Andric SmallVector<std::pair<MCSymbol *, MCPseudoProbeInlineTree *>> Vec;
214*5f757f3fSDimitry Andric Vec.reserve(MCProbeDivisions.size());
215*5f757f3fSDimitry Andric for (auto &ProbeSec : MCProbeDivisions)
216*5f757f3fSDimitry Andric Vec.emplace_back(ProbeSec.first, &ProbeSec.second);
217*5f757f3fSDimitry Andric for (auto I : llvm::enumerate(MCOS->getAssembler()))
218*5f757f3fSDimitry Andric I.value().setOrdinal(I.index());
219*5f757f3fSDimitry Andric llvm::sort(Vec, [](auto A, auto B) {
220*5f757f3fSDimitry Andric return A.first->getSection().getOrdinal() <
221*5f757f3fSDimitry Andric B.first->getSection().getOrdinal();
222*5f757f3fSDimitry Andric });
223*5f757f3fSDimitry Andric for (auto [FuncSym, RootPtr] : Vec) {
224*5f757f3fSDimitry Andric const auto &Root = *RootPtr;
225bdd1243dSDimitry Andric if (auto *S = Ctx.getObjectFileInfo()->getPseudoProbeSection(
226bdd1243dSDimitry Andric FuncSym->getSection())) {
227e8d8bef9SDimitry Andric // Switch to the .pseudoprobe section or a comdat group.
22881ad6265SDimitry Andric MCOS->switchSection(S);
229e8d8bef9SDimitry Andric // Emit probes grouped by GUID.
230bdd1243dSDimitry Andric // Emit sorted descendant. InlineSite is unique for each pair, so there
231bdd1243dSDimitry Andric // will be no ordering of Inlinee based on MCPseudoProbeInlineTree*
232bdd1243dSDimitry Andric using InlineeType = std::pair<InlineSite, MCPseudoProbeInlineTree *>;
233bdd1243dSDimitry Andric auto Comparer = [](const InlineeType &A, const InlineeType &B) {
234bdd1243dSDimitry Andric return A.first < B.first;
235bdd1243dSDimitry Andric };
236bdd1243dSDimitry Andric std::vector<InlineeType> Inlinees;
237bdd1243dSDimitry Andric for (const auto &Child : Root.getChildren())
238bdd1243dSDimitry Andric Inlinees.emplace_back(Child.first, Child.second.get());
239bdd1243dSDimitry Andric std::sort(Inlinees.begin(), Inlinees.end(), Comparer);
240bdd1243dSDimitry Andric
241bdd1243dSDimitry Andric for (const auto &Inlinee : Inlinees) {
242bdd1243dSDimitry Andric // Emit the group guarded by a sentinel probe.
24306c3fb27SDimitry Andric MCPseudoProbe SentinelProbe(
24406c3fb27SDimitry Andric const_cast<MCSymbol *>(FuncSym), MD5Hash(FuncSym->getName()),
245bdd1243dSDimitry Andric (uint32_t)PseudoProbeReservedId::Invalid,
246bdd1243dSDimitry Andric (uint32_t)PseudoProbeType::Block,
24706c3fb27SDimitry Andric (uint32_t)PseudoProbeAttributes::Sentinel, 0);
248bdd1243dSDimitry Andric const MCPseudoProbe *Probe = &SentinelProbe;
249bdd1243dSDimitry Andric Inlinee.second->emit(MCOS, Probe);
250bdd1243dSDimitry Andric }
251e8d8bef9SDimitry Andric }
252e8d8bef9SDimitry Andric }
253e8d8bef9SDimitry Andric }
254e8d8bef9SDimitry Andric
255e8d8bef9SDimitry Andric //
256e8d8bef9SDimitry Andric // This emits the pseudo probe tables.
257e8d8bef9SDimitry Andric //
emit(MCObjectStreamer * MCOS)258e8d8bef9SDimitry Andric void MCPseudoProbeTable::emit(MCObjectStreamer *MCOS) {
259e8d8bef9SDimitry Andric MCContext &Ctx = MCOS->getContext();
260e8d8bef9SDimitry Andric auto &ProbeTable = Ctx.getMCPseudoProbeTable();
261e8d8bef9SDimitry Andric
262e8d8bef9SDimitry Andric // Bail out early so we don't switch to the pseudo_probe section needlessly
263e8d8bef9SDimitry Andric // and in doing so create an unnecessary (if empty) section.
264e8d8bef9SDimitry Andric auto &ProbeSections = ProbeTable.getProbeSections();
265e8d8bef9SDimitry Andric if (ProbeSections.empty())
266e8d8bef9SDimitry Andric return;
267e8d8bef9SDimitry Andric
268e8d8bef9SDimitry Andric LLVM_DEBUG(MCPseudoProbeTable::DdgPrintIndent = 0);
269e8d8bef9SDimitry Andric
270e8d8bef9SDimitry Andric // Put out the probe.
271e8d8bef9SDimitry Andric ProbeSections.emit(MCOS);
272e8d8bef9SDimitry Andric }
273349cc55cSDimitry Andric
getProbeFNameForGUID(const GUIDProbeFunctionMap & GUID2FuncMAP,uint64_t GUID)274349cc55cSDimitry Andric static StringRef getProbeFNameForGUID(const GUIDProbeFunctionMap &GUID2FuncMAP,
275349cc55cSDimitry Andric uint64_t GUID) {
276349cc55cSDimitry Andric auto It = GUID2FuncMAP.find(GUID);
277349cc55cSDimitry Andric assert(It != GUID2FuncMAP.end() &&
278349cc55cSDimitry Andric "Probe function must exist for a valid GUID");
279349cc55cSDimitry Andric return It->second.FuncName;
280349cc55cSDimitry Andric }
281349cc55cSDimitry Andric
print(raw_ostream & OS)282349cc55cSDimitry Andric void MCPseudoProbeFuncDesc::print(raw_ostream &OS) {
283349cc55cSDimitry Andric OS << "GUID: " << FuncGUID << " Name: " << FuncName << "\n";
284349cc55cSDimitry Andric OS << "Hash: " << FuncHash << "\n";
285349cc55cSDimitry Andric }
286349cc55cSDimitry Andric
getInlineContext(SmallVectorImpl<MCPseduoProbeFrameLocation> & ContextStack,const GUIDProbeFunctionMap & GUID2FuncMAP) const287349cc55cSDimitry Andric void MCDecodedPseudoProbe::getInlineContext(
288349cc55cSDimitry Andric SmallVectorImpl<MCPseduoProbeFrameLocation> &ContextStack,
289349cc55cSDimitry Andric const GUIDProbeFunctionMap &GUID2FuncMAP) const {
290349cc55cSDimitry Andric uint32_t Begin = ContextStack.size();
291349cc55cSDimitry Andric MCDecodedPseudoProbeInlineTree *Cur = InlineTree;
292349cc55cSDimitry Andric // It will add the string of each node's inline site during iteration.
293349cc55cSDimitry Andric // Note that it won't include the probe's belonging function(leaf location)
294349cc55cSDimitry Andric while (Cur->hasInlineSite()) {
29581ad6265SDimitry Andric StringRef FuncName = getProbeFNameForGUID(GUID2FuncMAP, Cur->Parent->Guid);
296349cc55cSDimitry Andric ContextStack.emplace_back(
297349cc55cSDimitry Andric MCPseduoProbeFrameLocation(FuncName, std::get<1>(Cur->ISite)));
298349cc55cSDimitry Andric Cur = static_cast<MCDecodedPseudoProbeInlineTree *>(Cur->Parent);
299349cc55cSDimitry Andric }
300349cc55cSDimitry Andric // Make the ContextStack in caller-callee order
301349cc55cSDimitry Andric std::reverse(ContextStack.begin() + Begin, ContextStack.end());
302349cc55cSDimitry Andric }
303349cc55cSDimitry Andric
getInlineContextStr(const GUIDProbeFunctionMap & GUID2FuncMAP) const304349cc55cSDimitry Andric std::string MCDecodedPseudoProbe::getInlineContextStr(
305349cc55cSDimitry Andric const GUIDProbeFunctionMap &GUID2FuncMAP) const {
306349cc55cSDimitry Andric std::ostringstream OContextStr;
307349cc55cSDimitry Andric SmallVector<MCPseduoProbeFrameLocation, 16> ContextStack;
308349cc55cSDimitry Andric getInlineContext(ContextStack, GUID2FuncMAP);
309349cc55cSDimitry Andric for (auto &Cxt : ContextStack) {
310349cc55cSDimitry Andric if (OContextStr.str().size())
311349cc55cSDimitry Andric OContextStr << " @ ";
312349cc55cSDimitry Andric OContextStr << Cxt.first.str() << ":" << Cxt.second;
313349cc55cSDimitry Andric }
314349cc55cSDimitry Andric return OContextStr.str();
315349cc55cSDimitry Andric }
316349cc55cSDimitry Andric
317349cc55cSDimitry Andric static const char *PseudoProbeTypeStr[3] = {"Block", "IndirectCall",
318349cc55cSDimitry Andric "DirectCall"};
319349cc55cSDimitry Andric
print(raw_ostream & OS,const GUIDProbeFunctionMap & GUID2FuncMAP,bool ShowName) const320349cc55cSDimitry Andric void MCDecodedPseudoProbe::print(raw_ostream &OS,
321349cc55cSDimitry Andric const GUIDProbeFunctionMap &GUID2FuncMAP,
322349cc55cSDimitry Andric bool ShowName) const {
323349cc55cSDimitry Andric OS << "FUNC: ";
324349cc55cSDimitry Andric if (ShowName) {
325349cc55cSDimitry Andric StringRef FuncName = getProbeFNameForGUID(GUID2FuncMAP, Guid);
326349cc55cSDimitry Andric OS << FuncName.str() << " ";
327349cc55cSDimitry Andric } else {
328349cc55cSDimitry Andric OS << Guid << " ";
329349cc55cSDimitry Andric }
330349cc55cSDimitry Andric OS << "Index: " << Index << " ";
33106c3fb27SDimitry Andric if (Discriminator)
33206c3fb27SDimitry Andric OS << "Discriminator: " << Discriminator << " ";
333349cc55cSDimitry Andric OS << "Type: " << PseudoProbeTypeStr[static_cast<uint8_t>(Type)] << " ";
334349cc55cSDimitry Andric std::string InlineContextStr = getInlineContextStr(GUID2FuncMAP);
335349cc55cSDimitry Andric if (InlineContextStr.size()) {
336349cc55cSDimitry Andric OS << "Inlined: @ ";
337349cc55cSDimitry Andric OS << InlineContextStr;
338349cc55cSDimitry Andric }
339349cc55cSDimitry Andric OS << "\n";
340349cc55cSDimitry Andric }
341349cc55cSDimitry Andric
readUnencodedNumber()342349cc55cSDimitry Andric template <typename T> ErrorOr<T> MCPseudoProbeDecoder::readUnencodedNumber() {
343349cc55cSDimitry Andric if (Data + sizeof(T) > End) {
344349cc55cSDimitry Andric return std::error_code();
345349cc55cSDimitry Andric }
346*5f757f3fSDimitry Andric T Val = endian::readNext<T, llvm::endianness::little, unaligned>(Data);
347349cc55cSDimitry Andric return ErrorOr<T>(Val);
348349cc55cSDimitry Andric }
349349cc55cSDimitry Andric
readUnsignedNumber()350349cc55cSDimitry Andric template <typename T> ErrorOr<T> MCPseudoProbeDecoder::readUnsignedNumber() {
351349cc55cSDimitry Andric unsigned NumBytesRead = 0;
352349cc55cSDimitry Andric uint64_t Val = decodeULEB128(Data, &NumBytesRead);
353349cc55cSDimitry Andric if (Val > std::numeric_limits<T>::max() || (Data + NumBytesRead > End)) {
354349cc55cSDimitry Andric return std::error_code();
355349cc55cSDimitry Andric }
356349cc55cSDimitry Andric Data += NumBytesRead;
357349cc55cSDimitry Andric return ErrorOr<T>(static_cast<T>(Val));
358349cc55cSDimitry Andric }
359349cc55cSDimitry Andric
readSignedNumber()360349cc55cSDimitry Andric template <typename T> ErrorOr<T> MCPseudoProbeDecoder::readSignedNumber() {
361349cc55cSDimitry Andric unsigned NumBytesRead = 0;
362349cc55cSDimitry Andric int64_t Val = decodeSLEB128(Data, &NumBytesRead);
363349cc55cSDimitry Andric if (Val > std::numeric_limits<T>::max() || (Data + NumBytesRead > End)) {
364349cc55cSDimitry Andric return std::error_code();
365349cc55cSDimitry Andric }
366349cc55cSDimitry Andric Data += NumBytesRead;
367349cc55cSDimitry Andric return ErrorOr<T>(static_cast<T>(Val));
368349cc55cSDimitry Andric }
369349cc55cSDimitry Andric
readString(uint32_t Size)370349cc55cSDimitry Andric ErrorOr<StringRef> MCPseudoProbeDecoder::readString(uint32_t Size) {
371349cc55cSDimitry Andric StringRef Str(reinterpret_cast<const char *>(Data), Size);
372349cc55cSDimitry Andric if (Data + Size > End) {
373349cc55cSDimitry Andric return std::error_code();
374349cc55cSDimitry Andric }
375349cc55cSDimitry Andric Data += Size;
376349cc55cSDimitry Andric return ErrorOr<StringRef>(Str);
377349cc55cSDimitry Andric }
378349cc55cSDimitry Andric
buildGUID2FuncDescMap(const uint8_t * Start,std::size_t Size)379349cc55cSDimitry Andric bool MCPseudoProbeDecoder::buildGUID2FuncDescMap(const uint8_t *Start,
380349cc55cSDimitry Andric std::size_t Size) {
381349cc55cSDimitry Andric // The pseudo_probe_desc section has a format like:
382349cc55cSDimitry Andric // .section .pseudo_probe_desc,"",@progbits
383349cc55cSDimitry Andric // .quad -5182264717993193164 // GUID
384349cc55cSDimitry Andric // .quad 4294967295 // Hash
385349cc55cSDimitry Andric // .uleb 3 // Name size
386349cc55cSDimitry Andric // .ascii "foo" // Name
387349cc55cSDimitry Andric // .quad -2624081020897602054
388349cc55cSDimitry Andric // .quad 174696971957
389349cc55cSDimitry Andric // .uleb 34
390349cc55cSDimitry Andric // .ascii "main"
391349cc55cSDimitry Andric
392349cc55cSDimitry Andric Data = Start;
393349cc55cSDimitry Andric End = Data + Size;
394349cc55cSDimitry Andric
395349cc55cSDimitry Andric while (Data < End) {
396349cc55cSDimitry Andric auto ErrorOrGUID = readUnencodedNumber<uint64_t>();
397349cc55cSDimitry Andric if (!ErrorOrGUID)
398349cc55cSDimitry Andric return false;
399349cc55cSDimitry Andric
400349cc55cSDimitry Andric auto ErrorOrHash = readUnencodedNumber<uint64_t>();
401349cc55cSDimitry Andric if (!ErrorOrHash)
402349cc55cSDimitry Andric return false;
403349cc55cSDimitry Andric
404349cc55cSDimitry Andric auto ErrorOrNameSize = readUnsignedNumber<uint32_t>();
405349cc55cSDimitry Andric if (!ErrorOrNameSize)
406349cc55cSDimitry Andric return false;
407349cc55cSDimitry Andric uint32_t NameSize = std::move(*ErrorOrNameSize);
408349cc55cSDimitry Andric
409349cc55cSDimitry Andric auto ErrorOrName = readString(NameSize);
410349cc55cSDimitry Andric if (!ErrorOrName)
411349cc55cSDimitry Andric return false;
412349cc55cSDimitry Andric
413349cc55cSDimitry Andric uint64_t GUID = std::move(*ErrorOrGUID);
414349cc55cSDimitry Andric uint64_t Hash = std::move(*ErrorOrHash);
415349cc55cSDimitry Andric StringRef Name = std::move(*ErrorOrName);
416349cc55cSDimitry Andric
417349cc55cSDimitry Andric // Initialize PseudoProbeFuncDesc and populate it into GUID2FuncDescMap
418349cc55cSDimitry Andric GUID2FuncDescMap.emplace(GUID, MCPseudoProbeFuncDesc(GUID, Hash, Name));
419349cc55cSDimitry Andric }
420349cc55cSDimitry Andric assert(Data == End && "Have unprocessed data in pseudo_probe_desc section");
421349cc55cSDimitry Andric return true;
422349cc55cSDimitry Andric }
423349cc55cSDimitry Andric
buildAddress2ProbeMap(MCDecodedPseudoProbeInlineTree * Cur,uint64_t & LastAddr,const Uint64Set & GuidFilter,const Uint64Map & FuncStartAddrs)42481ad6265SDimitry Andric bool MCPseudoProbeDecoder::buildAddress2ProbeMap(
42581ad6265SDimitry Andric MCDecodedPseudoProbeInlineTree *Cur, uint64_t &LastAddr,
426bdd1243dSDimitry Andric const Uint64Set &GuidFilter, const Uint64Map &FuncStartAddrs) {
427349cc55cSDimitry Andric // The pseudo_probe section encodes an inline forest and each tree has a
428bdd1243dSDimitry Andric // format defined in MCPseudoProbe.h
429349cc55cSDimitry Andric
430349cc55cSDimitry Andric uint32_t Index = 0;
431bdd1243dSDimitry Andric bool IsTopLevelFunc = Cur == &DummyInlineRoot;
432bdd1243dSDimitry Andric if (IsTopLevelFunc) {
433349cc55cSDimitry Andric // Use a sequential id for top level inliner.
43481ad6265SDimitry Andric Index = Cur->getChildren().size();
435349cc55cSDimitry Andric } else {
436349cc55cSDimitry Andric // Read inline site for inlinees
437349cc55cSDimitry Andric auto ErrorOrIndex = readUnsignedNumber<uint32_t>();
438349cc55cSDimitry Andric if (!ErrorOrIndex)
439349cc55cSDimitry Andric return false;
440349cc55cSDimitry Andric Index = std::move(*ErrorOrIndex);
441349cc55cSDimitry Andric }
44281ad6265SDimitry Andric
443349cc55cSDimitry Andric // Read guid
444349cc55cSDimitry Andric auto ErrorOrCurGuid = readUnencodedNumber<uint64_t>();
445349cc55cSDimitry Andric if (!ErrorOrCurGuid)
446349cc55cSDimitry Andric return false;
44781ad6265SDimitry Andric uint64_t Guid = std::move(*ErrorOrCurGuid);
44881ad6265SDimitry Andric
44981ad6265SDimitry Andric // Decide if top-level node should be disgarded.
450bdd1243dSDimitry Andric if (IsTopLevelFunc && !GuidFilter.empty() && !GuidFilter.count(Guid))
45181ad6265SDimitry Andric Cur = nullptr;
45281ad6265SDimitry Andric
45381ad6265SDimitry Andric // If the incoming node is null, all its children nodes should be disgarded.
45481ad6265SDimitry Andric if (Cur) {
45581ad6265SDimitry Andric // Switch/add to a new tree node(inlinee)
45681ad6265SDimitry Andric Cur = Cur->getOrAddNode(std::make_tuple(Guid, Index));
45781ad6265SDimitry Andric Cur->Guid = Guid;
458bdd1243dSDimitry Andric if (IsTopLevelFunc && !EncodingIsAddrBased) {
459bdd1243dSDimitry Andric if (auto V = FuncStartAddrs.lookup(Guid))
460bdd1243dSDimitry Andric LastAddr = V;
461bdd1243dSDimitry Andric }
46281ad6265SDimitry Andric }
46381ad6265SDimitry Andric
464349cc55cSDimitry Andric // Read number of probes in the current node.
465349cc55cSDimitry Andric auto ErrorOrNodeCount = readUnsignedNumber<uint32_t>();
466349cc55cSDimitry Andric if (!ErrorOrNodeCount)
467349cc55cSDimitry Andric return false;
468349cc55cSDimitry Andric uint32_t NodeCount = std::move(*ErrorOrNodeCount);
469349cc55cSDimitry Andric // Read number of direct inlinees
470349cc55cSDimitry Andric auto ErrorOrCurChildrenToProcess = readUnsignedNumber<uint32_t>();
471349cc55cSDimitry Andric if (!ErrorOrCurChildrenToProcess)
472349cc55cSDimitry Andric return false;
473349cc55cSDimitry Andric // Read all probes in this node
474349cc55cSDimitry Andric for (std::size_t I = 0; I < NodeCount; I++) {
475349cc55cSDimitry Andric // Read index
476349cc55cSDimitry Andric auto ErrorOrIndex = readUnsignedNumber<uint32_t>();
477349cc55cSDimitry Andric if (!ErrorOrIndex)
478349cc55cSDimitry Andric return false;
479349cc55cSDimitry Andric uint32_t Index = std::move(*ErrorOrIndex);
480349cc55cSDimitry Andric // Read type | flag.
481349cc55cSDimitry Andric auto ErrorOrValue = readUnencodedNumber<uint8_t>();
482349cc55cSDimitry Andric if (!ErrorOrValue)
483349cc55cSDimitry Andric return false;
484349cc55cSDimitry Andric uint8_t Value = std::move(*ErrorOrValue);
485349cc55cSDimitry Andric uint8_t Kind = Value & 0xf;
486349cc55cSDimitry Andric uint8_t Attr = (Value & 0x70) >> 4;
487349cc55cSDimitry Andric // Read address
488349cc55cSDimitry Andric uint64_t Addr = 0;
489349cc55cSDimitry Andric if (Value & 0x80) {
490349cc55cSDimitry Andric auto ErrorOrOffset = readSignedNumber<int64_t>();
491349cc55cSDimitry Andric if (!ErrorOrOffset)
492349cc55cSDimitry Andric return false;
493349cc55cSDimitry Andric int64_t Offset = std::move(*ErrorOrOffset);
494349cc55cSDimitry Andric Addr = LastAddr + Offset;
495349cc55cSDimitry Andric } else {
496349cc55cSDimitry Andric auto ErrorOrAddr = readUnencodedNumber<int64_t>();
497349cc55cSDimitry Andric if (!ErrorOrAddr)
498349cc55cSDimitry Andric return false;
499349cc55cSDimitry Andric Addr = std::move(*ErrorOrAddr);
500bdd1243dSDimitry Andric if (isSentinelProbe(Attr)) {
501bdd1243dSDimitry Andric // For sentinel probe, the addr field actually stores the GUID of the
502bdd1243dSDimitry Andric // split function. Convert it to the real address.
503bdd1243dSDimitry Andric if (auto V = FuncStartAddrs.lookup(Addr))
504bdd1243dSDimitry Andric Addr = V;
505bdd1243dSDimitry Andric } else {
506bdd1243dSDimitry Andric // For now we assume all probe encoding should be either based on
507bdd1243dSDimitry Andric // leading probe address or function start address.
508bdd1243dSDimitry Andric // The scheme is for downwards compatibility.
509bdd1243dSDimitry Andric // TODO: retire this scheme once compatibility is no longer an issue.
510bdd1243dSDimitry Andric EncodingIsAddrBased = true;
511bdd1243dSDimitry Andric }
512349cc55cSDimitry Andric }
51381ad6265SDimitry Andric
51406c3fb27SDimitry Andric uint32_t Discriminator = 0;
51506c3fb27SDimitry Andric if (hasDiscriminator(Attr)) {
51606c3fb27SDimitry Andric auto ErrorOrDiscriminator = readUnsignedNumber<uint32_t>();
51706c3fb27SDimitry Andric if (!ErrorOrDiscriminator)
51806c3fb27SDimitry Andric return false;
51906c3fb27SDimitry Andric Discriminator = std::move(*ErrorOrDiscriminator);
52006c3fb27SDimitry Andric }
52106c3fb27SDimitry Andric
522bdd1243dSDimitry Andric if (Cur && !isSentinelProbe(Attr)) {
523349cc55cSDimitry Andric // Populate Address2ProbesMap
524349cc55cSDimitry Andric auto &Probes = Address2ProbesMap[Addr];
525349cc55cSDimitry Andric Probes.emplace_back(Addr, Cur->Guid, Index, PseudoProbeType(Kind), Attr,
52606c3fb27SDimitry Andric Discriminator, Cur);
527349cc55cSDimitry Andric Cur->addProbes(&Probes.back());
52881ad6265SDimitry Andric }
529349cc55cSDimitry Andric LastAddr = Addr;
530349cc55cSDimitry Andric }
531349cc55cSDimitry Andric
53281ad6265SDimitry Andric uint32_t ChildrenToProcess = std::move(*ErrorOrCurChildrenToProcess);
53381ad6265SDimitry Andric for (uint32_t I = 0; I < ChildrenToProcess; I++) {
534bdd1243dSDimitry Andric buildAddress2ProbeMap(Cur, LastAddr, GuidFilter, FuncStartAddrs);
535349cc55cSDimitry Andric }
536349cc55cSDimitry Andric
537349cc55cSDimitry Andric return true;
538349cc55cSDimitry Andric }
539349cc55cSDimitry Andric
buildAddress2ProbeMap(const uint8_t * Start,std::size_t Size,const Uint64Set & GuidFilter,const Uint64Map & FuncStartAddrs)54081ad6265SDimitry Andric bool MCPseudoProbeDecoder::buildAddress2ProbeMap(
541bdd1243dSDimitry Andric const uint8_t *Start, std::size_t Size, const Uint64Set &GuidFilter,
542bdd1243dSDimitry Andric const Uint64Map &FuncStartAddrs) {
54381ad6265SDimitry Andric Data = Start;
54481ad6265SDimitry Andric End = Data + Size;
54581ad6265SDimitry Andric uint64_t LastAddr = 0;
54681ad6265SDimitry Andric while (Data < End)
547bdd1243dSDimitry Andric buildAddress2ProbeMap(&DummyInlineRoot, LastAddr, GuidFilter,
548bdd1243dSDimitry Andric FuncStartAddrs);
54981ad6265SDimitry Andric assert(Data == End && "Have unprocessed data in pseudo_probe section");
55081ad6265SDimitry Andric return true;
55181ad6265SDimitry Andric }
55281ad6265SDimitry Andric
printGUID2FuncDescMap(raw_ostream & OS)553349cc55cSDimitry Andric void MCPseudoProbeDecoder::printGUID2FuncDescMap(raw_ostream &OS) {
554349cc55cSDimitry Andric OS << "Pseudo Probe Desc:\n";
555349cc55cSDimitry Andric // Make the output deterministic
556349cc55cSDimitry Andric std::map<uint64_t, MCPseudoProbeFuncDesc> OrderedMap(GUID2FuncDescMap.begin(),
557349cc55cSDimitry Andric GUID2FuncDescMap.end());
558349cc55cSDimitry Andric for (auto &I : OrderedMap) {
559349cc55cSDimitry Andric I.second.print(OS);
560349cc55cSDimitry Andric }
561349cc55cSDimitry Andric }
562349cc55cSDimitry Andric
printProbeForAddress(raw_ostream & OS,uint64_t Address)563349cc55cSDimitry Andric void MCPseudoProbeDecoder::printProbeForAddress(raw_ostream &OS,
564349cc55cSDimitry Andric uint64_t Address) {
565349cc55cSDimitry Andric auto It = Address2ProbesMap.find(Address);
566349cc55cSDimitry Andric if (It != Address2ProbesMap.end()) {
567349cc55cSDimitry Andric for (auto &Probe : It->second) {
568349cc55cSDimitry Andric OS << " [Probe]:\t";
569349cc55cSDimitry Andric Probe.print(OS, GUID2FuncDescMap, true);
570349cc55cSDimitry Andric }
571349cc55cSDimitry Andric }
572349cc55cSDimitry Andric }
573349cc55cSDimitry Andric
printProbesForAllAddresses(raw_ostream & OS)574349cc55cSDimitry Andric void MCPseudoProbeDecoder::printProbesForAllAddresses(raw_ostream &OS) {
575*5f757f3fSDimitry Andric auto Entries = make_first_range(Address2ProbesMap);
576*5f757f3fSDimitry Andric SmallVector<uint64_t, 0> Addresses(Entries.begin(), Entries.end());
577fcaf7f86SDimitry Andric llvm::sort(Addresses);
578349cc55cSDimitry Andric for (auto K : Addresses) {
579349cc55cSDimitry Andric OS << "Address:\t";
580349cc55cSDimitry Andric OS << K;
581349cc55cSDimitry Andric OS << "\n";
582349cc55cSDimitry Andric printProbeForAddress(OS, K);
583349cc55cSDimitry Andric }
584349cc55cSDimitry Andric }
585349cc55cSDimitry Andric
586349cc55cSDimitry Andric const MCDecodedPseudoProbe *
getCallProbeForAddr(uint64_t Address) const587349cc55cSDimitry Andric MCPseudoProbeDecoder::getCallProbeForAddr(uint64_t Address) const {
588349cc55cSDimitry Andric auto It = Address2ProbesMap.find(Address);
589349cc55cSDimitry Andric if (It == Address2ProbesMap.end())
590349cc55cSDimitry Andric return nullptr;
591349cc55cSDimitry Andric const auto &Probes = It->second;
592349cc55cSDimitry Andric
593349cc55cSDimitry Andric const MCDecodedPseudoProbe *CallProbe = nullptr;
594349cc55cSDimitry Andric for (const auto &Probe : Probes) {
595349cc55cSDimitry Andric if (Probe.isCall()) {
59606c3fb27SDimitry Andric // Disabling the assert and returning first call probe seen so far.
59706c3fb27SDimitry Andric // Subsequent call probes, if any, are ignored. Due to the the way
59806c3fb27SDimitry Andric // .pseudo_probe section is decoded, probes of the same-named independent
59906c3fb27SDimitry Andric // static functions are merged thus multiple call probes may be seen for a
60006c3fb27SDimitry Andric // callsite. This should only happen to compiler-generated statics, with
60106c3fb27SDimitry Andric // -funique-internal-linkage-names where user statics get unique names.
60206c3fb27SDimitry Andric //
60306c3fb27SDimitry Andric // TODO: re-enable or narrow down the assert to static functions only.
60406c3fb27SDimitry Andric //
60506c3fb27SDimitry Andric // assert(!CallProbe &&
60606c3fb27SDimitry Andric // "There should be only one call probe corresponding to address "
60706c3fb27SDimitry Andric // "which is a callsite.");
608349cc55cSDimitry Andric CallProbe = &Probe;
60906c3fb27SDimitry Andric break;
610349cc55cSDimitry Andric }
611349cc55cSDimitry Andric }
612349cc55cSDimitry Andric return CallProbe;
613349cc55cSDimitry Andric }
614349cc55cSDimitry Andric
615349cc55cSDimitry Andric const MCPseudoProbeFuncDesc *
getFuncDescForGUID(uint64_t GUID) const616349cc55cSDimitry Andric MCPseudoProbeDecoder::getFuncDescForGUID(uint64_t GUID) const {
617349cc55cSDimitry Andric auto It = GUID2FuncDescMap.find(GUID);
618349cc55cSDimitry Andric assert(It != GUID2FuncDescMap.end() && "Function descriptor doesn't exist");
619349cc55cSDimitry Andric return &It->second;
620349cc55cSDimitry Andric }
621349cc55cSDimitry Andric
getInlineContextForProbe(const MCDecodedPseudoProbe * Probe,SmallVectorImpl<MCPseduoProbeFrameLocation> & InlineContextStack,bool IncludeLeaf) const622349cc55cSDimitry Andric void MCPseudoProbeDecoder::getInlineContextForProbe(
623349cc55cSDimitry Andric const MCDecodedPseudoProbe *Probe,
624349cc55cSDimitry Andric SmallVectorImpl<MCPseduoProbeFrameLocation> &InlineContextStack,
625349cc55cSDimitry Andric bool IncludeLeaf) const {
626349cc55cSDimitry Andric Probe->getInlineContext(InlineContextStack, GUID2FuncDescMap);
627349cc55cSDimitry Andric if (!IncludeLeaf)
628349cc55cSDimitry Andric return;
629349cc55cSDimitry Andric // Note that the context from probe doesn't include leaf frame,
630349cc55cSDimitry Andric // hence we need to retrieve and prepend leaf if requested.
631349cc55cSDimitry Andric const auto *FuncDesc = getFuncDescForGUID(Probe->getGuid());
632349cc55cSDimitry Andric InlineContextStack.emplace_back(
633349cc55cSDimitry Andric MCPseduoProbeFrameLocation(FuncDesc->FuncName, Probe->getIndex()));
634349cc55cSDimitry Andric }
635349cc55cSDimitry Andric
getInlinerDescForProbe(const MCDecodedPseudoProbe * Probe) const636349cc55cSDimitry Andric const MCPseudoProbeFuncDesc *MCPseudoProbeDecoder::getInlinerDescForProbe(
637349cc55cSDimitry Andric const MCDecodedPseudoProbe *Probe) const {
638349cc55cSDimitry Andric MCDecodedPseudoProbeInlineTree *InlinerNode = Probe->getInlineTreeNode();
639349cc55cSDimitry Andric if (!InlinerNode->hasInlineSite())
640349cc55cSDimitry Andric return nullptr;
64181ad6265SDimitry Andric return getFuncDescForGUID(InlinerNode->Parent->Guid);
642349cc55cSDimitry Andric }
643