xref: /freebsd-src/contrib/llvm-project/llvm/lib/MC/MCPseudoProbe.cpp (revision 0eae32dcef82f6f06de6419a0d623d7def0cc8f6)
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"
10e8d8bef9SDimitry Andric #include "llvm/MC/MCAsmInfo.h"
11e8d8bef9SDimitry Andric #include "llvm/MC/MCContext.h"
12e8d8bef9SDimitry Andric #include "llvm/MC/MCObjectFileInfo.h"
13e8d8bef9SDimitry Andric #include "llvm/MC/MCObjectStreamer.h"
14e8d8bef9SDimitry Andric #include "llvm/MC/MCStreamer.h"
15349cc55cSDimitry Andric #include "llvm/Support/Endian.h"
16349cc55cSDimitry Andric #include "llvm/Support/LEB128.h"
17349cc55cSDimitry Andric #include "llvm/Support/raw_ostream.h"
18349cc55cSDimitry Andric #include <limits>
19349cc55cSDimitry Andric #include <memory>
20349cc55cSDimitry Andric #include <sstream>
21e8d8bef9SDimitry Andric 
22e8d8bef9SDimitry Andric #define DEBUG_TYPE "mcpseudoprobe"
23e8d8bef9SDimitry Andric 
24e8d8bef9SDimitry Andric using namespace llvm;
25349cc55cSDimitry Andric using namespace support;
26e8d8bef9SDimitry Andric 
27e8d8bef9SDimitry Andric #ifndef NDEBUG
28e8d8bef9SDimitry Andric int MCPseudoProbeTable::DdgPrintIndent = 0;
29e8d8bef9SDimitry Andric #endif
30e8d8bef9SDimitry Andric 
31e8d8bef9SDimitry Andric static const MCExpr *buildSymbolDiff(MCObjectStreamer *MCOS, const MCSymbol *A,
32e8d8bef9SDimitry Andric                                      const MCSymbol *B) {
33e8d8bef9SDimitry Andric   MCContext &Context = MCOS->getContext();
34e8d8bef9SDimitry Andric   MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None;
35e8d8bef9SDimitry Andric   const MCExpr *ARef = MCSymbolRefExpr::create(A, Variant, Context);
36e8d8bef9SDimitry Andric   const MCExpr *BRef = MCSymbolRefExpr::create(B, Variant, Context);
37e8d8bef9SDimitry Andric   const MCExpr *AddrDelta =
38e8d8bef9SDimitry Andric       MCBinaryExpr::create(MCBinaryExpr::Sub, ARef, BRef, Context);
39e8d8bef9SDimitry Andric   return AddrDelta;
40e8d8bef9SDimitry Andric }
41e8d8bef9SDimitry Andric 
42e8d8bef9SDimitry Andric void MCPseudoProbe::emit(MCObjectStreamer *MCOS,
43e8d8bef9SDimitry Andric                          const MCPseudoProbe *LastProbe) const {
44e8d8bef9SDimitry Andric   // Emit Index
45e8d8bef9SDimitry Andric   MCOS->emitULEB128IntValue(Index);
46e8d8bef9SDimitry Andric   // Emit Type and the flag:
47e8d8bef9SDimitry Andric   // Type (bit 0 to 3), with bit 4 to 6 for attributes.
48e8d8bef9SDimitry Andric   // Flag (bit 7, 0 - code address, 1 - address delta). This indicates whether
49e8d8bef9SDimitry Andric   // the following field is a symbolic code address or an address delta.
50e8d8bef9SDimitry Andric   assert(Type <= 0xF && "Probe type too big to encode, exceeding 15");
51e8d8bef9SDimitry Andric   assert(Attributes <= 0x7 &&
52e8d8bef9SDimitry Andric          "Probe attributes too big to encode, exceeding 7");
53e8d8bef9SDimitry Andric   uint8_t PackedType = Type | (Attributes << 4);
54e8d8bef9SDimitry Andric   uint8_t Flag = LastProbe ? ((int8_t)MCPseudoProbeFlag::AddressDelta << 7) : 0;
55e8d8bef9SDimitry Andric   MCOS->emitInt8(Flag | PackedType);
56e8d8bef9SDimitry Andric 
57e8d8bef9SDimitry Andric   if (LastProbe) {
58e8d8bef9SDimitry Andric     // Emit the delta between the address label and LastProbe.
59e8d8bef9SDimitry Andric     const MCExpr *AddrDelta =
60e8d8bef9SDimitry Andric         buildSymbolDiff(MCOS, Label, LastProbe->getLabel());
61e8d8bef9SDimitry Andric     int64_t Delta;
62e8d8bef9SDimitry Andric     if (AddrDelta->evaluateAsAbsolute(Delta, MCOS->getAssemblerPtr())) {
63e8d8bef9SDimitry Andric       MCOS->emitSLEB128IntValue(Delta);
64e8d8bef9SDimitry Andric     } else {
65e8d8bef9SDimitry Andric       MCOS->insert(new MCPseudoProbeAddrFragment(AddrDelta));
66e8d8bef9SDimitry Andric     }
67e8d8bef9SDimitry Andric   } else {
68e8d8bef9SDimitry Andric     // Emit label as a symbolic code address.
69e8d8bef9SDimitry Andric     MCOS->emitSymbolValue(
70e8d8bef9SDimitry Andric         Label, MCOS->getContext().getAsmInfo()->getCodePointerSize());
71e8d8bef9SDimitry Andric   }
72e8d8bef9SDimitry Andric 
73e8d8bef9SDimitry Andric   LLVM_DEBUG({
74e8d8bef9SDimitry Andric     dbgs().indent(MCPseudoProbeTable::DdgPrintIndent);
75e8d8bef9SDimitry Andric     dbgs() << "Probe: " << Index << "\n";
76e8d8bef9SDimitry Andric   });
77e8d8bef9SDimitry Andric }
78e8d8bef9SDimitry Andric 
79e8d8bef9SDimitry Andric void MCPseudoProbeInlineTree::addPseudoProbe(
80e8d8bef9SDimitry Andric     const MCPseudoProbe &Probe, const MCPseudoProbeInlineStack &InlineStack) {
81e8d8bef9SDimitry Andric   // The function should not be called on the root.
82e8d8bef9SDimitry Andric   assert(isRoot() && "Should not be called on root");
83e8d8bef9SDimitry Andric 
84e8d8bef9SDimitry Andric   // When it comes here, the input look like:
85e8d8bef9SDimitry Andric   //    Probe: GUID of C, ...
86e8d8bef9SDimitry Andric   //    InlineStack: [88, A], [66, B]
87e8d8bef9SDimitry Andric   // which means, Function A inlines function B at call site with a probe id of
88e8d8bef9SDimitry Andric   // 88, and B inlines C at probe 66. The tri-tree expects a tree path like {[0,
89e8d8bef9SDimitry Andric   // A], [88, B], [66, C]} to locate the tree node where the probe should be
90e8d8bef9SDimitry Andric   // added. Note that the edge [0, A] means A is the top-level function we are
91e8d8bef9SDimitry Andric   // emitting probes for.
92e8d8bef9SDimitry Andric 
93e8d8bef9SDimitry Andric   // Make a [0, A] edge.
94e8d8bef9SDimitry Andric   // An empty inline stack means the function that the probe originates from
95e8d8bef9SDimitry Andric   // is a top-level function.
96e8d8bef9SDimitry Andric   InlineSite Top;
97e8d8bef9SDimitry Andric   if (InlineStack.empty()) {
98e8d8bef9SDimitry Andric     Top = InlineSite(Probe.getGuid(), 0);
99e8d8bef9SDimitry Andric   } else {
100e8d8bef9SDimitry Andric     Top = InlineSite(std::get<0>(InlineStack.front()), 0);
101e8d8bef9SDimitry Andric   }
102e8d8bef9SDimitry Andric 
103e8d8bef9SDimitry Andric   auto *Cur = getOrAddNode(Top);
104e8d8bef9SDimitry Andric 
105e8d8bef9SDimitry Andric   // Make interior edges by walking the inline stack. Once it's done, Cur should
106e8d8bef9SDimitry Andric   // point to the node that the probe originates from.
107e8d8bef9SDimitry Andric   if (!InlineStack.empty()) {
108e8d8bef9SDimitry Andric     auto Iter = InlineStack.begin();
109e8d8bef9SDimitry Andric     auto Index = std::get<1>(*Iter);
110e8d8bef9SDimitry Andric     Iter++;
111e8d8bef9SDimitry Andric     for (; Iter != InlineStack.end(); Iter++) {
112e8d8bef9SDimitry Andric       // Make an edge by using the previous probe id and current GUID.
113e8d8bef9SDimitry Andric       Cur = Cur->getOrAddNode(InlineSite(std::get<0>(*Iter), Index));
114e8d8bef9SDimitry Andric       Index = std::get<1>(*Iter);
115e8d8bef9SDimitry Andric     }
116e8d8bef9SDimitry Andric     Cur = Cur->getOrAddNode(InlineSite(Probe.getGuid(), Index));
117e8d8bef9SDimitry Andric   }
118e8d8bef9SDimitry Andric 
119e8d8bef9SDimitry Andric   Cur->Probes.push_back(Probe);
120e8d8bef9SDimitry Andric }
121e8d8bef9SDimitry Andric 
122e8d8bef9SDimitry Andric void MCPseudoProbeInlineTree::emit(MCObjectStreamer *MCOS,
123e8d8bef9SDimitry Andric                                    const MCPseudoProbe *&LastProbe) {
124e8d8bef9SDimitry Andric   LLVM_DEBUG({
125e8d8bef9SDimitry Andric     dbgs().indent(MCPseudoProbeTable::DdgPrintIndent);
126e8d8bef9SDimitry Andric     dbgs() << "Group [\n";
127e8d8bef9SDimitry Andric     MCPseudoProbeTable::DdgPrintIndent += 2;
128e8d8bef9SDimitry Andric   });
129e8d8bef9SDimitry Andric   // Emit probes grouped by GUID.
130e8d8bef9SDimitry Andric   if (Guid != 0) {
131e8d8bef9SDimitry Andric     LLVM_DEBUG({
132e8d8bef9SDimitry Andric       dbgs().indent(MCPseudoProbeTable::DdgPrintIndent);
133e8d8bef9SDimitry Andric       dbgs() << "GUID: " << Guid << "\n";
134e8d8bef9SDimitry Andric     });
135e8d8bef9SDimitry Andric     // Emit Guid
136e8d8bef9SDimitry Andric     MCOS->emitInt64(Guid);
137e8d8bef9SDimitry Andric     // Emit number of probes in this node
138e8d8bef9SDimitry Andric     MCOS->emitULEB128IntValue(Probes.size());
139e8d8bef9SDimitry Andric     // Emit number of direct inlinees
140349cc55cSDimitry Andric     MCOS->emitULEB128IntValue(Children.size());
141e8d8bef9SDimitry Andric     // Emit probes in this group
142e8d8bef9SDimitry Andric     for (const auto &Probe : Probes) {
143e8d8bef9SDimitry Andric       Probe.emit(MCOS, LastProbe);
144e8d8bef9SDimitry Andric       LastProbe = &Probe;
145e8d8bef9SDimitry Andric     }
146e8d8bef9SDimitry Andric   } else {
147e8d8bef9SDimitry Andric     assert(Probes.empty() && "Root should not have probes");
148e8d8bef9SDimitry Andric   }
149e8d8bef9SDimitry Andric 
150349cc55cSDimitry Andric   // Emit sorted descendant
151349cc55cSDimitry Andric   // InlineSite is unique for each pair,
152349cc55cSDimitry Andric   // so there will be no ordering of Inlinee based on MCPseudoProbeInlineTree*
153349cc55cSDimitry Andric   std::map<InlineSite, MCPseudoProbeInlineTree *> Inlinees;
154*0eae32dcSDimitry Andric   for (auto &Child : Children)
155*0eae32dcSDimitry Andric     Inlinees[Child.first] = Child.second.get();
156349cc55cSDimitry Andric 
157e8d8bef9SDimitry Andric   for (const auto &Inlinee : Inlinees) {
158e8d8bef9SDimitry Andric     if (Guid) {
159e8d8bef9SDimitry Andric       // Emit probe index
160e8d8bef9SDimitry Andric       MCOS->emitULEB128IntValue(std::get<1>(Inlinee.first));
161e8d8bef9SDimitry Andric       LLVM_DEBUG({
162e8d8bef9SDimitry Andric         dbgs().indent(MCPseudoProbeTable::DdgPrintIndent);
163e8d8bef9SDimitry Andric         dbgs() << "InlineSite: " << std::get<1>(Inlinee.first) << "\n";
164e8d8bef9SDimitry Andric       });
165e8d8bef9SDimitry Andric     }
166e8d8bef9SDimitry Andric     // Emit the group
167e8d8bef9SDimitry Andric     Inlinee.second->emit(MCOS, LastProbe);
168e8d8bef9SDimitry Andric   }
169e8d8bef9SDimitry Andric 
170e8d8bef9SDimitry Andric   LLVM_DEBUG({
171e8d8bef9SDimitry Andric     MCPseudoProbeTable::DdgPrintIndent -= 2;
172e8d8bef9SDimitry Andric     dbgs().indent(MCPseudoProbeTable::DdgPrintIndent);
173e8d8bef9SDimitry Andric     dbgs() << "]\n";
174e8d8bef9SDimitry Andric   });
175e8d8bef9SDimitry Andric }
176e8d8bef9SDimitry Andric 
177e8d8bef9SDimitry Andric void MCPseudoProbeSection::emit(MCObjectStreamer *MCOS) {
178e8d8bef9SDimitry Andric   MCContext &Ctx = MCOS->getContext();
179e8d8bef9SDimitry Andric 
180e8d8bef9SDimitry Andric   for (auto &ProbeSec : MCProbeDivisions) {
181e8d8bef9SDimitry Andric     const MCPseudoProbe *LastProbe = nullptr;
182e8d8bef9SDimitry Andric     if (auto *S =
183e8d8bef9SDimitry Andric             Ctx.getObjectFileInfo()->getPseudoProbeSection(ProbeSec.first)) {
184e8d8bef9SDimitry Andric       // Switch to the .pseudoprobe section or a comdat group.
185e8d8bef9SDimitry Andric       MCOS->SwitchSection(S);
186e8d8bef9SDimitry Andric       // Emit probes grouped by GUID.
187e8d8bef9SDimitry Andric       ProbeSec.second.emit(MCOS, LastProbe);
188e8d8bef9SDimitry Andric     }
189e8d8bef9SDimitry Andric   }
190e8d8bef9SDimitry Andric }
191e8d8bef9SDimitry Andric 
192e8d8bef9SDimitry Andric //
193e8d8bef9SDimitry Andric // This emits the pseudo probe tables.
194e8d8bef9SDimitry Andric //
195e8d8bef9SDimitry Andric void MCPseudoProbeTable::emit(MCObjectStreamer *MCOS) {
196e8d8bef9SDimitry Andric   MCContext &Ctx = MCOS->getContext();
197e8d8bef9SDimitry Andric   auto &ProbeTable = Ctx.getMCPseudoProbeTable();
198e8d8bef9SDimitry Andric 
199e8d8bef9SDimitry Andric   // Bail out early so we don't switch to the pseudo_probe section needlessly
200e8d8bef9SDimitry Andric   // and in doing so create an unnecessary (if empty) section.
201e8d8bef9SDimitry Andric   auto &ProbeSections = ProbeTable.getProbeSections();
202e8d8bef9SDimitry Andric   if (ProbeSections.empty())
203e8d8bef9SDimitry Andric     return;
204e8d8bef9SDimitry Andric 
205e8d8bef9SDimitry Andric   LLVM_DEBUG(MCPseudoProbeTable::DdgPrintIndent = 0);
206e8d8bef9SDimitry Andric 
207e8d8bef9SDimitry Andric   // Put out the probe.
208e8d8bef9SDimitry Andric   ProbeSections.emit(MCOS);
209e8d8bef9SDimitry Andric }
210349cc55cSDimitry Andric 
211349cc55cSDimitry Andric static StringRef getProbeFNameForGUID(const GUIDProbeFunctionMap &GUID2FuncMAP,
212349cc55cSDimitry Andric                                       uint64_t GUID) {
213349cc55cSDimitry Andric   auto It = GUID2FuncMAP.find(GUID);
214349cc55cSDimitry Andric   assert(It != GUID2FuncMAP.end() &&
215349cc55cSDimitry Andric          "Probe function must exist for a valid GUID");
216349cc55cSDimitry Andric   return It->second.FuncName;
217349cc55cSDimitry Andric }
218349cc55cSDimitry Andric 
219349cc55cSDimitry Andric void MCPseudoProbeFuncDesc::print(raw_ostream &OS) {
220349cc55cSDimitry Andric   OS << "GUID: " << FuncGUID << " Name: " << FuncName << "\n";
221349cc55cSDimitry Andric   OS << "Hash: " << FuncHash << "\n";
222349cc55cSDimitry Andric }
223349cc55cSDimitry Andric 
224349cc55cSDimitry Andric void MCDecodedPseudoProbe::getInlineContext(
225349cc55cSDimitry Andric     SmallVectorImpl<MCPseduoProbeFrameLocation> &ContextStack,
226349cc55cSDimitry Andric     const GUIDProbeFunctionMap &GUID2FuncMAP) const {
227349cc55cSDimitry Andric   uint32_t Begin = ContextStack.size();
228349cc55cSDimitry Andric   MCDecodedPseudoProbeInlineTree *Cur = InlineTree;
229349cc55cSDimitry Andric   // It will add the string of each node's inline site during iteration.
230349cc55cSDimitry Andric   // Note that it won't include the probe's belonging function(leaf location)
231349cc55cSDimitry Andric   while (Cur->hasInlineSite()) {
232349cc55cSDimitry Andric     StringRef FuncName =
233349cc55cSDimitry Andric         getProbeFNameForGUID(GUID2FuncMAP, std::get<0>(Cur->ISite));
234349cc55cSDimitry Andric     ContextStack.emplace_back(
235349cc55cSDimitry Andric         MCPseduoProbeFrameLocation(FuncName, std::get<1>(Cur->ISite)));
236349cc55cSDimitry Andric     Cur = static_cast<MCDecodedPseudoProbeInlineTree *>(Cur->Parent);
237349cc55cSDimitry Andric   }
238349cc55cSDimitry Andric   // Make the ContextStack in caller-callee order
239349cc55cSDimitry Andric   std::reverse(ContextStack.begin() + Begin, ContextStack.end());
240349cc55cSDimitry Andric }
241349cc55cSDimitry Andric 
242349cc55cSDimitry Andric std::string MCDecodedPseudoProbe::getInlineContextStr(
243349cc55cSDimitry Andric     const GUIDProbeFunctionMap &GUID2FuncMAP) const {
244349cc55cSDimitry Andric   std::ostringstream OContextStr;
245349cc55cSDimitry Andric   SmallVector<MCPseduoProbeFrameLocation, 16> ContextStack;
246349cc55cSDimitry Andric   getInlineContext(ContextStack, GUID2FuncMAP);
247349cc55cSDimitry Andric   for (auto &Cxt : ContextStack) {
248349cc55cSDimitry Andric     if (OContextStr.str().size())
249349cc55cSDimitry Andric       OContextStr << " @ ";
250349cc55cSDimitry Andric     OContextStr << Cxt.first.str() << ":" << Cxt.second;
251349cc55cSDimitry Andric   }
252349cc55cSDimitry Andric   return OContextStr.str();
253349cc55cSDimitry Andric }
254349cc55cSDimitry Andric 
255349cc55cSDimitry Andric static const char *PseudoProbeTypeStr[3] = {"Block", "IndirectCall",
256349cc55cSDimitry Andric                                             "DirectCall"};
257349cc55cSDimitry Andric 
258349cc55cSDimitry Andric void MCDecodedPseudoProbe::print(raw_ostream &OS,
259349cc55cSDimitry Andric                                  const GUIDProbeFunctionMap &GUID2FuncMAP,
260349cc55cSDimitry Andric                                  bool ShowName) const {
261349cc55cSDimitry Andric   OS << "FUNC: ";
262349cc55cSDimitry Andric   if (ShowName) {
263349cc55cSDimitry Andric     StringRef FuncName = getProbeFNameForGUID(GUID2FuncMAP, Guid);
264349cc55cSDimitry Andric     OS << FuncName.str() << " ";
265349cc55cSDimitry Andric   } else {
266349cc55cSDimitry Andric     OS << Guid << " ";
267349cc55cSDimitry Andric   }
268349cc55cSDimitry Andric   OS << "Index: " << Index << "  ";
269349cc55cSDimitry Andric   OS << "Type: " << PseudoProbeTypeStr[static_cast<uint8_t>(Type)] << "  ";
270349cc55cSDimitry Andric   std::string InlineContextStr = getInlineContextStr(GUID2FuncMAP);
271349cc55cSDimitry Andric   if (InlineContextStr.size()) {
272349cc55cSDimitry Andric     OS << "Inlined: @ ";
273349cc55cSDimitry Andric     OS << InlineContextStr;
274349cc55cSDimitry Andric   }
275349cc55cSDimitry Andric   OS << "\n";
276349cc55cSDimitry Andric }
277349cc55cSDimitry Andric 
278349cc55cSDimitry Andric template <typename T> ErrorOr<T> MCPseudoProbeDecoder::readUnencodedNumber() {
279349cc55cSDimitry Andric   if (Data + sizeof(T) > End) {
280349cc55cSDimitry Andric     return std::error_code();
281349cc55cSDimitry Andric   }
282349cc55cSDimitry Andric   T Val = endian::readNext<T, little, unaligned>(Data);
283349cc55cSDimitry Andric   return ErrorOr<T>(Val);
284349cc55cSDimitry Andric }
285349cc55cSDimitry Andric 
286349cc55cSDimitry Andric template <typename T> ErrorOr<T> MCPseudoProbeDecoder::readUnsignedNumber() {
287349cc55cSDimitry Andric   unsigned NumBytesRead = 0;
288349cc55cSDimitry Andric   uint64_t Val = decodeULEB128(Data, &NumBytesRead);
289349cc55cSDimitry Andric   if (Val > std::numeric_limits<T>::max() || (Data + NumBytesRead > End)) {
290349cc55cSDimitry Andric     return std::error_code();
291349cc55cSDimitry Andric   }
292349cc55cSDimitry Andric   Data += NumBytesRead;
293349cc55cSDimitry Andric   return ErrorOr<T>(static_cast<T>(Val));
294349cc55cSDimitry Andric }
295349cc55cSDimitry Andric 
296349cc55cSDimitry Andric template <typename T> ErrorOr<T> MCPseudoProbeDecoder::readSignedNumber() {
297349cc55cSDimitry Andric   unsigned NumBytesRead = 0;
298349cc55cSDimitry Andric   int64_t Val = decodeSLEB128(Data, &NumBytesRead);
299349cc55cSDimitry Andric   if (Val > std::numeric_limits<T>::max() || (Data + NumBytesRead > End)) {
300349cc55cSDimitry Andric     return std::error_code();
301349cc55cSDimitry Andric   }
302349cc55cSDimitry Andric   Data += NumBytesRead;
303349cc55cSDimitry Andric   return ErrorOr<T>(static_cast<T>(Val));
304349cc55cSDimitry Andric }
305349cc55cSDimitry Andric 
306349cc55cSDimitry Andric ErrorOr<StringRef> MCPseudoProbeDecoder::readString(uint32_t Size) {
307349cc55cSDimitry Andric   StringRef Str(reinterpret_cast<const char *>(Data), Size);
308349cc55cSDimitry Andric   if (Data + Size > End) {
309349cc55cSDimitry Andric     return std::error_code();
310349cc55cSDimitry Andric   }
311349cc55cSDimitry Andric   Data += Size;
312349cc55cSDimitry Andric   return ErrorOr<StringRef>(Str);
313349cc55cSDimitry Andric }
314349cc55cSDimitry Andric 
315349cc55cSDimitry Andric bool MCPseudoProbeDecoder::buildGUID2FuncDescMap(const uint8_t *Start,
316349cc55cSDimitry Andric                                                  std::size_t Size) {
317349cc55cSDimitry Andric   // The pseudo_probe_desc section has a format like:
318349cc55cSDimitry Andric   // .section .pseudo_probe_desc,"",@progbits
319349cc55cSDimitry Andric   // .quad -5182264717993193164   // GUID
320349cc55cSDimitry Andric   // .quad 4294967295             // Hash
321349cc55cSDimitry Andric   // .uleb 3                      // Name size
322349cc55cSDimitry Andric   // .ascii "foo"                 // Name
323349cc55cSDimitry Andric   // .quad -2624081020897602054
324349cc55cSDimitry Andric   // .quad 174696971957
325349cc55cSDimitry Andric   // .uleb 34
326349cc55cSDimitry Andric   // .ascii "main"
327349cc55cSDimitry Andric 
328349cc55cSDimitry Andric   Data = Start;
329349cc55cSDimitry Andric   End = Data + Size;
330349cc55cSDimitry Andric 
331349cc55cSDimitry Andric   while (Data < End) {
332349cc55cSDimitry Andric     auto ErrorOrGUID = readUnencodedNumber<uint64_t>();
333349cc55cSDimitry Andric     if (!ErrorOrGUID)
334349cc55cSDimitry Andric       return false;
335349cc55cSDimitry Andric 
336349cc55cSDimitry Andric     auto ErrorOrHash = readUnencodedNumber<uint64_t>();
337349cc55cSDimitry Andric     if (!ErrorOrHash)
338349cc55cSDimitry Andric       return false;
339349cc55cSDimitry Andric 
340349cc55cSDimitry Andric     auto ErrorOrNameSize = readUnsignedNumber<uint32_t>();
341349cc55cSDimitry Andric     if (!ErrorOrNameSize)
342349cc55cSDimitry Andric       return false;
343349cc55cSDimitry Andric     uint32_t NameSize = std::move(*ErrorOrNameSize);
344349cc55cSDimitry Andric 
345349cc55cSDimitry Andric     auto ErrorOrName = readString(NameSize);
346349cc55cSDimitry Andric     if (!ErrorOrName)
347349cc55cSDimitry Andric       return false;
348349cc55cSDimitry Andric 
349349cc55cSDimitry Andric     uint64_t GUID = std::move(*ErrorOrGUID);
350349cc55cSDimitry Andric     uint64_t Hash = std::move(*ErrorOrHash);
351349cc55cSDimitry Andric     StringRef Name = std::move(*ErrorOrName);
352349cc55cSDimitry Andric 
353349cc55cSDimitry Andric     // Initialize PseudoProbeFuncDesc and populate it into GUID2FuncDescMap
354349cc55cSDimitry Andric     GUID2FuncDescMap.emplace(GUID, MCPseudoProbeFuncDesc(GUID, Hash, Name));
355349cc55cSDimitry Andric   }
356349cc55cSDimitry Andric   assert(Data == End && "Have unprocessed data in pseudo_probe_desc section");
357349cc55cSDimitry Andric   return true;
358349cc55cSDimitry Andric }
359349cc55cSDimitry Andric 
360349cc55cSDimitry Andric bool MCPseudoProbeDecoder::buildAddress2ProbeMap(const uint8_t *Start,
361349cc55cSDimitry Andric                                                  std::size_t Size) {
362349cc55cSDimitry Andric   // The pseudo_probe section encodes an inline forest and each tree has a
363349cc55cSDimitry Andric   // format like:
364349cc55cSDimitry Andric   //  FUNCTION BODY (one for each uninlined function present in the text
365349cc55cSDimitry Andric   //  section)
366349cc55cSDimitry Andric   //     GUID (uint64)
367349cc55cSDimitry Andric   //         GUID of the function
368349cc55cSDimitry Andric   //     NPROBES (ULEB128)
369349cc55cSDimitry Andric   //         Number of probes originating from this function.
370349cc55cSDimitry Andric   //     NUM_INLINED_FUNCTIONS (ULEB128)
371349cc55cSDimitry Andric   //         Number of callees inlined into this function, aka number of
372349cc55cSDimitry Andric   //         first-level inlinees
373349cc55cSDimitry Andric   //     PROBE RECORDS
374349cc55cSDimitry Andric   //         A list of NPROBES entries. Each entry contains:
375349cc55cSDimitry Andric   //           INDEX (ULEB128)
376349cc55cSDimitry Andric   //           TYPE (uint4)
377349cc55cSDimitry Andric   //             0 - block probe, 1 - indirect call, 2 - direct call
378349cc55cSDimitry Andric   //           ATTRIBUTE (uint3)
379349cc55cSDimitry Andric   //             1 - tail call, 2 - dangling
380349cc55cSDimitry Andric   //           ADDRESS_TYPE (uint1)
381349cc55cSDimitry Andric   //             0 - code address, 1 - address delta
382349cc55cSDimitry Andric   //           CODE_ADDRESS (uint64 or ULEB128)
383349cc55cSDimitry Andric   //             code address or address delta, depending on Flag
384349cc55cSDimitry Andric   //     INLINED FUNCTION RECORDS
385349cc55cSDimitry Andric   //         A list of NUM_INLINED_FUNCTIONS entries describing each of the
386349cc55cSDimitry Andric   //         inlined callees.  Each record contains:
387349cc55cSDimitry Andric   //           INLINE SITE
388349cc55cSDimitry Andric   //             Index of the callsite probe (ULEB128)
389349cc55cSDimitry Andric   //           FUNCTION BODY
390349cc55cSDimitry Andric   //             A FUNCTION BODY entry describing the inlined function.
391349cc55cSDimitry Andric 
392349cc55cSDimitry Andric   Data = Start;
393349cc55cSDimitry Andric   End = Data + Size;
394349cc55cSDimitry Andric 
395349cc55cSDimitry Andric   MCDecodedPseudoProbeInlineTree *Root = &DummyInlineRoot;
396349cc55cSDimitry Andric   MCDecodedPseudoProbeInlineTree *Cur = &DummyInlineRoot;
397349cc55cSDimitry Andric   uint64_t LastAddr = 0;
398349cc55cSDimitry Andric   uint32_t Index = 0;
399349cc55cSDimitry Andric   // A DFS-based decoding
400349cc55cSDimitry Andric   while (Data < End) {
401349cc55cSDimitry Andric     if (Root == Cur) {
402349cc55cSDimitry Andric       // Use a sequential id for top level inliner.
403349cc55cSDimitry Andric       Index = Root->getChildren().size();
404349cc55cSDimitry Andric     } else {
405349cc55cSDimitry Andric       // Read inline site for inlinees
406349cc55cSDimitry Andric       auto ErrorOrIndex = readUnsignedNumber<uint32_t>();
407349cc55cSDimitry Andric       if (!ErrorOrIndex)
408349cc55cSDimitry Andric         return false;
409349cc55cSDimitry Andric       Index = std::move(*ErrorOrIndex);
410349cc55cSDimitry Andric     }
411349cc55cSDimitry Andric     // Switch/add to a new tree node(inlinee)
412349cc55cSDimitry Andric     Cur = Cur->getOrAddNode(std::make_tuple(Cur->Guid, Index));
413349cc55cSDimitry Andric     // Read guid
414349cc55cSDimitry Andric     auto ErrorOrCurGuid = readUnencodedNumber<uint64_t>();
415349cc55cSDimitry Andric     if (!ErrorOrCurGuid)
416349cc55cSDimitry Andric       return false;
417349cc55cSDimitry Andric     Cur->Guid = std::move(*ErrorOrCurGuid);
418349cc55cSDimitry Andric     // Read number of probes in the current node.
419349cc55cSDimitry Andric     auto ErrorOrNodeCount = readUnsignedNumber<uint32_t>();
420349cc55cSDimitry Andric     if (!ErrorOrNodeCount)
421349cc55cSDimitry Andric       return false;
422349cc55cSDimitry Andric     uint32_t NodeCount = std::move(*ErrorOrNodeCount);
423349cc55cSDimitry Andric     // Read number of direct inlinees
424349cc55cSDimitry Andric     auto ErrorOrCurChildrenToProcess = readUnsignedNumber<uint32_t>();
425349cc55cSDimitry Andric     if (!ErrorOrCurChildrenToProcess)
426349cc55cSDimitry Andric       return false;
427349cc55cSDimitry Andric     Cur->ChildrenToProcess = std::move(*ErrorOrCurChildrenToProcess);
428349cc55cSDimitry Andric     // Read all probes in this node
429349cc55cSDimitry Andric     for (std::size_t I = 0; I < NodeCount; I++) {
430349cc55cSDimitry Andric       // Read index
431349cc55cSDimitry Andric       auto ErrorOrIndex = readUnsignedNumber<uint32_t>();
432349cc55cSDimitry Andric       if (!ErrorOrIndex)
433349cc55cSDimitry Andric         return false;
434349cc55cSDimitry Andric       uint32_t Index = std::move(*ErrorOrIndex);
435349cc55cSDimitry Andric       // Read type | flag.
436349cc55cSDimitry Andric       auto ErrorOrValue = readUnencodedNumber<uint8_t>();
437349cc55cSDimitry Andric       if (!ErrorOrValue)
438349cc55cSDimitry Andric         return false;
439349cc55cSDimitry Andric       uint8_t Value = std::move(*ErrorOrValue);
440349cc55cSDimitry Andric       uint8_t Kind = Value & 0xf;
441349cc55cSDimitry Andric       uint8_t Attr = (Value & 0x70) >> 4;
442349cc55cSDimitry Andric       // Read address
443349cc55cSDimitry Andric       uint64_t Addr = 0;
444349cc55cSDimitry Andric       if (Value & 0x80) {
445349cc55cSDimitry Andric         auto ErrorOrOffset = readSignedNumber<int64_t>();
446349cc55cSDimitry Andric         if (!ErrorOrOffset)
447349cc55cSDimitry Andric           return false;
448349cc55cSDimitry Andric         int64_t Offset = std::move(*ErrorOrOffset);
449349cc55cSDimitry Andric         Addr = LastAddr + Offset;
450349cc55cSDimitry Andric       } else {
451349cc55cSDimitry Andric         auto ErrorOrAddr = readUnencodedNumber<int64_t>();
452349cc55cSDimitry Andric         if (!ErrorOrAddr)
453349cc55cSDimitry Andric           return false;
454349cc55cSDimitry Andric         Addr = std::move(*ErrorOrAddr);
455349cc55cSDimitry Andric       }
456349cc55cSDimitry Andric       // Populate Address2ProbesMap
457349cc55cSDimitry Andric       auto &Probes = Address2ProbesMap[Addr];
458349cc55cSDimitry Andric       Probes.emplace_back(Addr, Cur->Guid, Index, PseudoProbeType(Kind), Attr,
459349cc55cSDimitry Andric                           Cur);
460349cc55cSDimitry Andric       Cur->addProbes(&Probes.back());
461349cc55cSDimitry Andric       LastAddr = Addr;
462349cc55cSDimitry Andric     }
463349cc55cSDimitry Andric 
464349cc55cSDimitry Andric     // Look for the parent for the next node by subtracting the current
465349cc55cSDimitry Andric     // node count from tree counts along the parent chain. The first node
466349cc55cSDimitry Andric     // in the chain that has a non-zero tree count is the target.
467349cc55cSDimitry Andric     while (Cur != Root) {
468349cc55cSDimitry Andric       if (Cur->ChildrenToProcess == 0) {
469349cc55cSDimitry Andric         Cur = static_cast<MCDecodedPseudoProbeInlineTree *>(Cur->Parent);
470349cc55cSDimitry Andric         if (Cur != Root) {
471349cc55cSDimitry Andric           assert(Cur->ChildrenToProcess > 0 &&
472349cc55cSDimitry Andric                  "Should have some unprocessed nodes");
473349cc55cSDimitry Andric           Cur->ChildrenToProcess -= 1;
474349cc55cSDimitry Andric         }
475349cc55cSDimitry Andric       } else {
476349cc55cSDimitry Andric         break;
477349cc55cSDimitry Andric       }
478349cc55cSDimitry Andric     }
479349cc55cSDimitry Andric   }
480349cc55cSDimitry Andric 
481349cc55cSDimitry Andric   assert(Data == End && "Have unprocessed data in pseudo_probe section");
482349cc55cSDimitry Andric   assert(Cur == Root &&
483349cc55cSDimitry Andric          " Cur should point to root when the forest is fully built up");
484349cc55cSDimitry Andric   return true;
485349cc55cSDimitry Andric }
486349cc55cSDimitry Andric 
487349cc55cSDimitry Andric void MCPseudoProbeDecoder::printGUID2FuncDescMap(raw_ostream &OS) {
488349cc55cSDimitry Andric   OS << "Pseudo Probe Desc:\n";
489349cc55cSDimitry Andric   // Make the output deterministic
490349cc55cSDimitry Andric   std::map<uint64_t, MCPseudoProbeFuncDesc> OrderedMap(GUID2FuncDescMap.begin(),
491349cc55cSDimitry Andric                                                        GUID2FuncDescMap.end());
492349cc55cSDimitry Andric   for (auto &I : OrderedMap) {
493349cc55cSDimitry Andric     I.second.print(OS);
494349cc55cSDimitry Andric   }
495349cc55cSDimitry Andric }
496349cc55cSDimitry Andric 
497349cc55cSDimitry Andric void MCPseudoProbeDecoder::printProbeForAddress(raw_ostream &OS,
498349cc55cSDimitry Andric                                                 uint64_t Address) {
499349cc55cSDimitry Andric   auto It = Address2ProbesMap.find(Address);
500349cc55cSDimitry Andric   if (It != Address2ProbesMap.end()) {
501349cc55cSDimitry Andric     for (auto &Probe : It->second) {
502349cc55cSDimitry Andric       OS << " [Probe]:\t";
503349cc55cSDimitry Andric       Probe.print(OS, GUID2FuncDescMap, true);
504349cc55cSDimitry Andric     }
505349cc55cSDimitry Andric   }
506349cc55cSDimitry Andric }
507349cc55cSDimitry Andric 
508349cc55cSDimitry Andric void MCPseudoProbeDecoder::printProbesForAllAddresses(raw_ostream &OS) {
509349cc55cSDimitry Andric   std::vector<uint64_t> Addresses;
510349cc55cSDimitry Andric   for (auto Entry : Address2ProbesMap)
511349cc55cSDimitry Andric     Addresses.push_back(Entry.first);
512349cc55cSDimitry Andric   std::sort(Addresses.begin(), Addresses.end());
513349cc55cSDimitry Andric   for (auto K : Addresses) {
514349cc55cSDimitry Andric     OS << "Address:\t";
515349cc55cSDimitry Andric     OS << K;
516349cc55cSDimitry Andric     OS << "\n";
517349cc55cSDimitry Andric     printProbeForAddress(OS, K);
518349cc55cSDimitry Andric   }
519349cc55cSDimitry Andric }
520349cc55cSDimitry Andric 
521349cc55cSDimitry Andric const MCDecodedPseudoProbe *
522349cc55cSDimitry Andric MCPseudoProbeDecoder::getCallProbeForAddr(uint64_t Address) const {
523349cc55cSDimitry Andric   auto It = Address2ProbesMap.find(Address);
524349cc55cSDimitry Andric   if (It == Address2ProbesMap.end())
525349cc55cSDimitry Andric     return nullptr;
526349cc55cSDimitry Andric   const auto &Probes = It->second;
527349cc55cSDimitry Andric 
528349cc55cSDimitry Andric   const MCDecodedPseudoProbe *CallProbe = nullptr;
529349cc55cSDimitry Andric   for (const auto &Probe : Probes) {
530349cc55cSDimitry Andric     if (Probe.isCall()) {
531349cc55cSDimitry Andric       assert(!CallProbe &&
532349cc55cSDimitry Andric              "There should be only one call probe corresponding to address "
533349cc55cSDimitry Andric              "which is a callsite.");
534349cc55cSDimitry Andric       CallProbe = &Probe;
535349cc55cSDimitry Andric     }
536349cc55cSDimitry Andric   }
537349cc55cSDimitry Andric   return CallProbe;
538349cc55cSDimitry Andric }
539349cc55cSDimitry Andric 
540349cc55cSDimitry Andric const MCPseudoProbeFuncDesc *
541349cc55cSDimitry Andric MCPseudoProbeDecoder::getFuncDescForGUID(uint64_t GUID) const {
542349cc55cSDimitry Andric   auto It = GUID2FuncDescMap.find(GUID);
543349cc55cSDimitry Andric   assert(It != GUID2FuncDescMap.end() && "Function descriptor doesn't exist");
544349cc55cSDimitry Andric   return &It->second;
545349cc55cSDimitry Andric }
546349cc55cSDimitry Andric 
547349cc55cSDimitry Andric void MCPseudoProbeDecoder::getInlineContextForProbe(
548349cc55cSDimitry Andric     const MCDecodedPseudoProbe *Probe,
549349cc55cSDimitry Andric     SmallVectorImpl<MCPseduoProbeFrameLocation> &InlineContextStack,
550349cc55cSDimitry Andric     bool IncludeLeaf) const {
551349cc55cSDimitry Andric   Probe->getInlineContext(InlineContextStack, GUID2FuncDescMap);
552349cc55cSDimitry Andric   if (!IncludeLeaf)
553349cc55cSDimitry Andric     return;
554349cc55cSDimitry Andric   // Note that the context from probe doesn't include leaf frame,
555349cc55cSDimitry Andric   // hence we need to retrieve and prepend leaf if requested.
556349cc55cSDimitry Andric   const auto *FuncDesc = getFuncDescForGUID(Probe->getGuid());
557349cc55cSDimitry Andric   InlineContextStack.emplace_back(
558349cc55cSDimitry Andric       MCPseduoProbeFrameLocation(FuncDesc->FuncName, Probe->getIndex()));
559349cc55cSDimitry Andric }
560349cc55cSDimitry Andric 
561349cc55cSDimitry Andric const MCPseudoProbeFuncDesc *MCPseudoProbeDecoder::getInlinerDescForProbe(
562349cc55cSDimitry Andric     const MCDecodedPseudoProbe *Probe) const {
563349cc55cSDimitry Andric   MCDecodedPseudoProbeInlineTree *InlinerNode = Probe->getInlineTreeNode();
564349cc55cSDimitry Andric   if (!InlinerNode->hasInlineSite())
565349cc55cSDimitry Andric     return nullptr;
566349cc55cSDimitry Andric   return getFuncDescForGUID(std::get<0>(InlinerNode->ISite));
567349cc55cSDimitry Andric }
568