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" 11e8d8bef9SDimitry Andric #include "llvm/MC/MCAsmInfo.h" 12e8d8bef9SDimitry Andric #include "llvm/MC/MCContext.h" 1381ad6265SDimitry Andric #include "llvm/MC/MCExpr.h" 1481ad6265SDimitry Andric #include "llvm/MC/MCFragment.h" 15e8d8bef9SDimitry Andric #include "llvm/MC/MCObjectFileInfo.h" 16e8d8bef9SDimitry Andric #include "llvm/MC/MCObjectStreamer.h" 17*bdd1243dSDimitry Andric #include "llvm/MC/MCSymbol.h" 18349cc55cSDimitry Andric #include "llvm/Support/Endian.h" 19349cc55cSDimitry Andric #include "llvm/Support/LEB128.h" 20*bdd1243dSDimitry Andric #include "llvm/Support/MD5.h" 21349cc55cSDimitry Andric #include "llvm/Support/raw_ostream.h" 22*bdd1243dSDimitry Andric #include <algorithm> 23*bdd1243dSDimitry Andric #include <cassert> 24349cc55cSDimitry Andric #include <limits> 25349cc55cSDimitry Andric #include <memory> 26349cc55cSDimitry Andric #include <sstream> 27*bdd1243dSDimitry Andric #include <vector> 28e8d8bef9SDimitry Andric 29e8d8bef9SDimitry Andric #define DEBUG_TYPE "mcpseudoprobe" 30e8d8bef9SDimitry Andric 31e8d8bef9SDimitry Andric using namespace llvm; 32349cc55cSDimitry Andric using namespace support; 33e8d8bef9SDimitry Andric 34e8d8bef9SDimitry Andric #ifndef NDEBUG 35e8d8bef9SDimitry Andric int MCPseudoProbeTable::DdgPrintIndent = 0; 36e8d8bef9SDimitry Andric #endif 37e8d8bef9SDimitry Andric 38e8d8bef9SDimitry Andric static const MCExpr *buildSymbolDiff(MCObjectStreamer *MCOS, const MCSymbol *A, 39e8d8bef9SDimitry Andric const MCSymbol *B) { 40e8d8bef9SDimitry Andric MCContext &Context = MCOS->getContext(); 41e8d8bef9SDimitry Andric MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None; 42e8d8bef9SDimitry Andric const MCExpr *ARef = MCSymbolRefExpr::create(A, Variant, Context); 43e8d8bef9SDimitry Andric const MCExpr *BRef = MCSymbolRefExpr::create(B, Variant, Context); 44e8d8bef9SDimitry Andric const MCExpr *AddrDelta = 45e8d8bef9SDimitry Andric MCBinaryExpr::create(MCBinaryExpr::Sub, ARef, BRef, Context); 46e8d8bef9SDimitry Andric return AddrDelta; 47e8d8bef9SDimitry Andric } 48e8d8bef9SDimitry Andric 49e8d8bef9SDimitry Andric void MCPseudoProbe::emit(MCObjectStreamer *MCOS, 50e8d8bef9SDimitry Andric const MCPseudoProbe *LastProbe) const { 51*bdd1243dSDimitry Andric bool IsSentinel = isSentinelProbe(getAttributes()); 52*bdd1243dSDimitry Andric assert((LastProbe || IsSentinel) && 53*bdd1243dSDimitry Andric "Last probe should not be null for non-sentinel probes"); 54*bdd1243dSDimitry Andric 55e8d8bef9SDimitry Andric // Emit Index 56e8d8bef9SDimitry Andric MCOS->emitULEB128IntValue(Index); 57e8d8bef9SDimitry Andric // Emit Type and the flag: 58e8d8bef9SDimitry Andric // Type (bit 0 to 3), with bit 4 to 6 for attributes. 59e8d8bef9SDimitry Andric // Flag (bit 7, 0 - code address, 1 - address delta). This indicates whether 60e8d8bef9SDimitry Andric // the following field is a symbolic code address or an address delta. 61e8d8bef9SDimitry Andric assert(Type <= 0xF && "Probe type too big to encode, exceeding 15"); 62e8d8bef9SDimitry Andric assert(Attributes <= 0x7 && 63e8d8bef9SDimitry Andric "Probe attributes too big to encode, exceeding 7"); 64e8d8bef9SDimitry Andric uint8_t PackedType = Type | (Attributes << 4); 65*bdd1243dSDimitry Andric uint8_t Flag = 66*bdd1243dSDimitry Andric !IsSentinel ? ((int8_t)MCPseudoProbeFlag::AddressDelta << 7) : 0; 67e8d8bef9SDimitry Andric MCOS->emitInt8(Flag | PackedType); 68e8d8bef9SDimitry Andric 69*bdd1243dSDimitry Andric if (!IsSentinel) { 70e8d8bef9SDimitry Andric // Emit the delta between the address label and LastProbe. 71e8d8bef9SDimitry Andric const MCExpr *AddrDelta = 72e8d8bef9SDimitry Andric buildSymbolDiff(MCOS, Label, LastProbe->getLabel()); 73e8d8bef9SDimitry Andric int64_t Delta; 74e8d8bef9SDimitry Andric if (AddrDelta->evaluateAsAbsolute(Delta, MCOS->getAssemblerPtr())) { 75e8d8bef9SDimitry Andric MCOS->emitSLEB128IntValue(Delta); 76e8d8bef9SDimitry Andric } else { 77e8d8bef9SDimitry Andric MCOS->insert(new MCPseudoProbeAddrFragment(AddrDelta)); 78e8d8bef9SDimitry Andric } 79e8d8bef9SDimitry Andric } else { 80*bdd1243dSDimitry Andric // Emit the GUID of the split function that the sentinel probe represents. 81*bdd1243dSDimitry Andric MCOS->emitInt64(Guid); 82e8d8bef9SDimitry Andric } 83e8d8bef9SDimitry Andric 84e8d8bef9SDimitry Andric LLVM_DEBUG({ 85e8d8bef9SDimitry Andric dbgs().indent(MCPseudoProbeTable::DdgPrintIndent); 86e8d8bef9SDimitry Andric dbgs() << "Probe: " << Index << "\n"; 87e8d8bef9SDimitry Andric }); 88e8d8bef9SDimitry Andric } 89e8d8bef9SDimitry Andric 90e8d8bef9SDimitry Andric void MCPseudoProbeInlineTree::addPseudoProbe( 91e8d8bef9SDimitry Andric const MCPseudoProbe &Probe, const MCPseudoProbeInlineStack &InlineStack) { 92e8d8bef9SDimitry Andric // The function should not be called on the root. 93*bdd1243dSDimitry Andric assert(isRoot() && "Should only be called on root"); 94e8d8bef9SDimitry Andric 95e8d8bef9SDimitry Andric // When it comes here, the input look like: 96e8d8bef9SDimitry Andric // Probe: GUID of C, ... 97e8d8bef9SDimitry Andric // InlineStack: [88, A], [66, B] 98e8d8bef9SDimitry Andric // which means, Function A inlines function B at call site with a probe id of 99e8d8bef9SDimitry Andric // 88, and B inlines C at probe 66. The tri-tree expects a tree path like {[0, 100e8d8bef9SDimitry Andric // A], [88, B], [66, C]} to locate the tree node where the probe should be 101e8d8bef9SDimitry Andric // added. Note that the edge [0, A] means A is the top-level function we are 102e8d8bef9SDimitry Andric // emitting probes for. 103e8d8bef9SDimitry Andric 104e8d8bef9SDimitry Andric // Make a [0, A] edge. 105e8d8bef9SDimitry Andric // An empty inline stack means the function that the probe originates from 106e8d8bef9SDimitry Andric // is a top-level function. 107e8d8bef9SDimitry Andric InlineSite Top; 108e8d8bef9SDimitry Andric if (InlineStack.empty()) { 109e8d8bef9SDimitry Andric Top = InlineSite(Probe.getGuid(), 0); 110e8d8bef9SDimitry Andric } else { 111e8d8bef9SDimitry Andric Top = InlineSite(std::get<0>(InlineStack.front()), 0); 112e8d8bef9SDimitry Andric } 113e8d8bef9SDimitry Andric 114e8d8bef9SDimitry Andric auto *Cur = getOrAddNode(Top); 115e8d8bef9SDimitry Andric 116e8d8bef9SDimitry Andric // Make interior edges by walking the inline stack. Once it's done, Cur should 117e8d8bef9SDimitry Andric // point to the node that the probe originates from. 118e8d8bef9SDimitry Andric if (!InlineStack.empty()) { 119e8d8bef9SDimitry Andric auto Iter = InlineStack.begin(); 120e8d8bef9SDimitry Andric auto Index = std::get<1>(*Iter); 121e8d8bef9SDimitry Andric Iter++; 122e8d8bef9SDimitry Andric for (; Iter != InlineStack.end(); Iter++) { 123e8d8bef9SDimitry Andric // Make an edge by using the previous probe id and current GUID. 124e8d8bef9SDimitry Andric Cur = Cur->getOrAddNode(InlineSite(std::get<0>(*Iter), Index)); 125e8d8bef9SDimitry Andric Index = std::get<1>(*Iter); 126e8d8bef9SDimitry Andric } 127e8d8bef9SDimitry Andric Cur = Cur->getOrAddNode(InlineSite(Probe.getGuid(), Index)); 128e8d8bef9SDimitry Andric } 129e8d8bef9SDimitry Andric 130e8d8bef9SDimitry Andric Cur->Probes.push_back(Probe); 131e8d8bef9SDimitry Andric } 132e8d8bef9SDimitry Andric 133e8d8bef9SDimitry Andric void MCPseudoProbeInlineTree::emit(MCObjectStreamer *MCOS, 134e8d8bef9SDimitry Andric const MCPseudoProbe *&LastProbe) { 135e8d8bef9SDimitry Andric LLVM_DEBUG({ 136e8d8bef9SDimitry Andric dbgs().indent(MCPseudoProbeTable::DdgPrintIndent); 137e8d8bef9SDimitry Andric dbgs() << "Group [\n"; 138e8d8bef9SDimitry Andric MCPseudoProbeTable::DdgPrintIndent += 2; 139e8d8bef9SDimitry Andric }); 140*bdd1243dSDimitry Andric assert(!isRoot() && "Root should be handled seperately"); 141*bdd1243dSDimitry Andric 142e8d8bef9SDimitry Andric // Emit probes grouped by GUID. 143e8d8bef9SDimitry Andric LLVM_DEBUG({ 144e8d8bef9SDimitry Andric dbgs().indent(MCPseudoProbeTable::DdgPrintIndent); 145e8d8bef9SDimitry Andric dbgs() << "GUID: " << Guid << "\n"; 146e8d8bef9SDimitry Andric }); 147e8d8bef9SDimitry Andric // Emit Guid 148e8d8bef9SDimitry Andric MCOS->emitInt64(Guid); 149*bdd1243dSDimitry Andric // Emit number of probes in this node, including a sentinel probe for 150*bdd1243dSDimitry Andric // top-level functions if needed. 151*bdd1243dSDimitry Andric bool NeedSentinel = false; 152*bdd1243dSDimitry Andric if (Parent->isRoot()) { 153*bdd1243dSDimitry Andric assert(isSentinelProbe(LastProbe->getAttributes()) && 154*bdd1243dSDimitry Andric "Starting probe of a top-level function should be a sentinel probe"); 155*bdd1243dSDimitry Andric // The main body of a split function doesn't need a sentinel probe. 156*bdd1243dSDimitry Andric if (LastProbe->getGuid() != Guid) 157*bdd1243dSDimitry Andric NeedSentinel = true; 158*bdd1243dSDimitry Andric } 159*bdd1243dSDimitry Andric 160*bdd1243dSDimitry Andric MCOS->emitULEB128IntValue(Probes.size() + NeedSentinel); 161e8d8bef9SDimitry Andric // Emit number of direct inlinees 162349cc55cSDimitry Andric MCOS->emitULEB128IntValue(Children.size()); 163*bdd1243dSDimitry Andric // Emit sentinel probe for top-level functions 164*bdd1243dSDimitry Andric if (NeedSentinel) 165*bdd1243dSDimitry Andric LastProbe->emit(MCOS, nullptr); 166*bdd1243dSDimitry Andric 167e8d8bef9SDimitry Andric // Emit probes in this group 168e8d8bef9SDimitry Andric for (const auto &Probe : Probes) { 169e8d8bef9SDimitry Andric Probe.emit(MCOS, LastProbe); 170e8d8bef9SDimitry Andric LastProbe = &Probe; 171e8d8bef9SDimitry Andric } 172e8d8bef9SDimitry Andric 173*bdd1243dSDimitry Andric // Emit sorted descendant. InlineSite is unique for each pair, so there will 174*bdd1243dSDimitry Andric // be no ordering of Inlinee based on MCPseudoProbeInlineTree* 175*bdd1243dSDimitry Andric using InlineeType = std::pair<InlineSite, MCPseudoProbeInlineTree *>; 176*bdd1243dSDimitry Andric auto Comparer = [](const InlineeType &A, const InlineeType &B) { 177*bdd1243dSDimitry Andric return A.first < B.first; 178*bdd1243dSDimitry Andric }; 179*bdd1243dSDimitry Andric std::vector<InlineeType> Inlinees; 180*bdd1243dSDimitry Andric for (const auto &Child : Children) 181*bdd1243dSDimitry Andric Inlinees.emplace_back(Child.first, Child.second.get()); 182*bdd1243dSDimitry Andric std::sort(Inlinees.begin(), Inlinees.end(), Comparer); 183349cc55cSDimitry Andric 184e8d8bef9SDimitry Andric for (const auto &Inlinee : Inlinees) { 185e8d8bef9SDimitry Andric // Emit probe index 186e8d8bef9SDimitry Andric MCOS->emitULEB128IntValue(std::get<1>(Inlinee.first)); 187e8d8bef9SDimitry Andric LLVM_DEBUG({ 188e8d8bef9SDimitry Andric dbgs().indent(MCPseudoProbeTable::DdgPrintIndent); 189e8d8bef9SDimitry Andric dbgs() << "InlineSite: " << std::get<1>(Inlinee.first) << "\n"; 190e8d8bef9SDimitry Andric }); 191e8d8bef9SDimitry Andric // Emit the group 192e8d8bef9SDimitry Andric Inlinee.second->emit(MCOS, LastProbe); 193e8d8bef9SDimitry Andric } 194e8d8bef9SDimitry Andric 195e8d8bef9SDimitry Andric LLVM_DEBUG({ 196e8d8bef9SDimitry Andric MCPseudoProbeTable::DdgPrintIndent -= 2; 197e8d8bef9SDimitry Andric dbgs().indent(MCPseudoProbeTable::DdgPrintIndent); 198e8d8bef9SDimitry Andric dbgs() << "]\n"; 199e8d8bef9SDimitry Andric }); 200e8d8bef9SDimitry Andric } 201e8d8bef9SDimitry Andric 202*bdd1243dSDimitry Andric void MCPseudoProbeSections::emit(MCObjectStreamer *MCOS) { 203e8d8bef9SDimitry Andric MCContext &Ctx = MCOS->getContext(); 204e8d8bef9SDimitry Andric for (auto &ProbeSec : MCProbeDivisions) { 205*bdd1243dSDimitry Andric const auto *FuncSym = ProbeSec.first; 206*bdd1243dSDimitry Andric const auto &Root = ProbeSec.second; 207*bdd1243dSDimitry Andric if (auto *S = Ctx.getObjectFileInfo()->getPseudoProbeSection( 208*bdd1243dSDimitry Andric FuncSym->getSection())) { 209e8d8bef9SDimitry Andric // Switch to the .pseudoprobe section or a comdat group. 21081ad6265SDimitry Andric MCOS->switchSection(S); 211e8d8bef9SDimitry Andric // Emit probes grouped by GUID. 212*bdd1243dSDimitry Andric // Emit sorted descendant. InlineSite is unique for each pair, so there 213*bdd1243dSDimitry Andric // will be no ordering of Inlinee based on MCPseudoProbeInlineTree* 214*bdd1243dSDimitry Andric using InlineeType = std::pair<InlineSite, MCPseudoProbeInlineTree *>; 215*bdd1243dSDimitry Andric auto Comparer = [](const InlineeType &A, const InlineeType &B) { 216*bdd1243dSDimitry Andric return A.first < B.first; 217*bdd1243dSDimitry Andric }; 218*bdd1243dSDimitry Andric std::vector<InlineeType> Inlinees; 219*bdd1243dSDimitry Andric for (const auto &Child : Root.getChildren()) 220*bdd1243dSDimitry Andric Inlinees.emplace_back(Child.first, Child.second.get()); 221*bdd1243dSDimitry Andric std::sort(Inlinees.begin(), Inlinees.end(), Comparer); 222*bdd1243dSDimitry Andric 223*bdd1243dSDimitry Andric for (const auto &Inlinee : Inlinees) { 224*bdd1243dSDimitry Andric // Emit the group guarded by a sentinel probe. 225*bdd1243dSDimitry Andric MCPseudoProbe SentinelProbe(const_cast<MCSymbol *>(FuncSym), 226*bdd1243dSDimitry Andric MD5Hash(FuncSym->getName()), 227*bdd1243dSDimitry Andric (uint32_t)PseudoProbeReservedId::Invalid, 228*bdd1243dSDimitry Andric (uint32_t)PseudoProbeType::Block, 229*bdd1243dSDimitry Andric (uint32_t)PseudoProbeAttributes::Sentinel); 230*bdd1243dSDimitry Andric const MCPseudoProbe *Probe = &SentinelProbe; 231*bdd1243dSDimitry Andric Inlinee.second->emit(MCOS, Probe); 232*bdd1243dSDimitry Andric } 233e8d8bef9SDimitry Andric } 234e8d8bef9SDimitry Andric } 235e8d8bef9SDimitry Andric } 236e8d8bef9SDimitry Andric 237e8d8bef9SDimitry Andric // 238e8d8bef9SDimitry Andric // This emits the pseudo probe tables. 239e8d8bef9SDimitry Andric // 240e8d8bef9SDimitry Andric void MCPseudoProbeTable::emit(MCObjectStreamer *MCOS) { 241e8d8bef9SDimitry Andric MCContext &Ctx = MCOS->getContext(); 242e8d8bef9SDimitry Andric auto &ProbeTable = Ctx.getMCPseudoProbeTable(); 243e8d8bef9SDimitry Andric 244e8d8bef9SDimitry Andric // Bail out early so we don't switch to the pseudo_probe section needlessly 245e8d8bef9SDimitry Andric // and in doing so create an unnecessary (if empty) section. 246e8d8bef9SDimitry Andric auto &ProbeSections = ProbeTable.getProbeSections(); 247e8d8bef9SDimitry Andric if (ProbeSections.empty()) 248e8d8bef9SDimitry Andric return; 249e8d8bef9SDimitry Andric 250e8d8bef9SDimitry Andric LLVM_DEBUG(MCPseudoProbeTable::DdgPrintIndent = 0); 251e8d8bef9SDimitry Andric 252e8d8bef9SDimitry Andric // Put out the probe. 253e8d8bef9SDimitry Andric ProbeSections.emit(MCOS); 254e8d8bef9SDimitry Andric } 255349cc55cSDimitry Andric 256349cc55cSDimitry Andric static StringRef getProbeFNameForGUID(const GUIDProbeFunctionMap &GUID2FuncMAP, 257349cc55cSDimitry Andric uint64_t GUID) { 258349cc55cSDimitry Andric auto It = GUID2FuncMAP.find(GUID); 259349cc55cSDimitry Andric assert(It != GUID2FuncMAP.end() && 260349cc55cSDimitry Andric "Probe function must exist for a valid GUID"); 261349cc55cSDimitry Andric return It->second.FuncName; 262349cc55cSDimitry Andric } 263349cc55cSDimitry Andric 264349cc55cSDimitry Andric void MCPseudoProbeFuncDesc::print(raw_ostream &OS) { 265349cc55cSDimitry Andric OS << "GUID: " << FuncGUID << " Name: " << FuncName << "\n"; 266349cc55cSDimitry Andric OS << "Hash: " << FuncHash << "\n"; 267349cc55cSDimitry Andric } 268349cc55cSDimitry Andric 269349cc55cSDimitry Andric void MCDecodedPseudoProbe::getInlineContext( 270349cc55cSDimitry Andric SmallVectorImpl<MCPseduoProbeFrameLocation> &ContextStack, 271349cc55cSDimitry Andric const GUIDProbeFunctionMap &GUID2FuncMAP) const { 272349cc55cSDimitry Andric uint32_t Begin = ContextStack.size(); 273349cc55cSDimitry Andric MCDecodedPseudoProbeInlineTree *Cur = InlineTree; 274349cc55cSDimitry Andric // It will add the string of each node's inline site during iteration. 275349cc55cSDimitry Andric // Note that it won't include the probe's belonging function(leaf location) 276349cc55cSDimitry Andric while (Cur->hasInlineSite()) { 27781ad6265SDimitry Andric StringRef FuncName = getProbeFNameForGUID(GUID2FuncMAP, Cur->Parent->Guid); 278349cc55cSDimitry Andric ContextStack.emplace_back( 279349cc55cSDimitry Andric MCPseduoProbeFrameLocation(FuncName, std::get<1>(Cur->ISite))); 280349cc55cSDimitry Andric Cur = static_cast<MCDecodedPseudoProbeInlineTree *>(Cur->Parent); 281349cc55cSDimitry Andric } 282349cc55cSDimitry Andric // Make the ContextStack in caller-callee order 283349cc55cSDimitry Andric std::reverse(ContextStack.begin() + Begin, ContextStack.end()); 284349cc55cSDimitry Andric } 285349cc55cSDimitry Andric 286349cc55cSDimitry Andric std::string MCDecodedPseudoProbe::getInlineContextStr( 287349cc55cSDimitry Andric const GUIDProbeFunctionMap &GUID2FuncMAP) const { 288349cc55cSDimitry Andric std::ostringstream OContextStr; 289349cc55cSDimitry Andric SmallVector<MCPseduoProbeFrameLocation, 16> ContextStack; 290349cc55cSDimitry Andric getInlineContext(ContextStack, GUID2FuncMAP); 291349cc55cSDimitry Andric for (auto &Cxt : ContextStack) { 292349cc55cSDimitry Andric if (OContextStr.str().size()) 293349cc55cSDimitry Andric OContextStr << " @ "; 294349cc55cSDimitry Andric OContextStr << Cxt.first.str() << ":" << Cxt.second; 295349cc55cSDimitry Andric } 296349cc55cSDimitry Andric return OContextStr.str(); 297349cc55cSDimitry Andric } 298349cc55cSDimitry Andric 299349cc55cSDimitry Andric static const char *PseudoProbeTypeStr[3] = {"Block", "IndirectCall", 300349cc55cSDimitry Andric "DirectCall"}; 301349cc55cSDimitry Andric 302349cc55cSDimitry Andric void MCDecodedPseudoProbe::print(raw_ostream &OS, 303349cc55cSDimitry Andric const GUIDProbeFunctionMap &GUID2FuncMAP, 304349cc55cSDimitry Andric bool ShowName) const { 305349cc55cSDimitry Andric OS << "FUNC: "; 306349cc55cSDimitry Andric if (ShowName) { 307349cc55cSDimitry Andric StringRef FuncName = getProbeFNameForGUID(GUID2FuncMAP, Guid); 308349cc55cSDimitry Andric OS << FuncName.str() << " "; 309349cc55cSDimitry Andric } else { 310349cc55cSDimitry Andric OS << Guid << " "; 311349cc55cSDimitry Andric } 312349cc55cSDimitry Andric OS << "Index: " << Index << " "; 313349cc55cSDimitry Andric OS << "Type: " << PseudoProbeTypeStr[static_cast<uint8_t>(Type)] << " "; 314349cc55cSDimitry Andric std::string InlineContextStr = getInlineContextStr(GUID2FuncMAP); 315349cc55cSDimitry Andric if (InlineContextStr.size()) { 316349cc55cSDimitry Andric OS << "Inlined: @ "; 317349cc55cSDimitry Andric OS << InlineContextStr; 318349cc55cSDimitry Andric } 319349cc55cSDimitry Andric OS << "\n"; 320349cc55cSDimitry Andric } 321349cc55cSDimitry Andric 322349cc55cSDimitry Andric template <typename T> ErrorOr<T> MCPseudoProbeDecoder::readUnencodedNumber() { 323349cc55cSDimitry Andric if (Data + sizeof(T) > End) { 324349cc55cSDimitry Andric return std::error_code(); 325349cc55cSDimitry Andric } 326349cc55cSDimitry Andric T Val = endian::readNext<T, little, unaligned>(Data); 327349cc55cSDimitry Andric return ErrorOr<T>(Val); 328349cc55cSDimitry Andric } 329349cc55cSDimitry Andric 330349cc55cSDimitry Andric template <typename T> ErrorOr<T> MCPseudoProbeDecoder::readUnsignedNumber() { 331349cc55cSDimitry Andric unsigned NumBytesRead = 0; 332349cc55cSDimitry Andric uint64_t Val = decodeULEB128(Data, &NumBytesRead); 333349cc55cSDimitry Andric if (Val > std::numeric_limits<T>::max() || (Data + NumBytesRead > End)) { 334349cc55cSDimitry Andric return std::error_code(); 335349cc55cSDimitry Andric } 336349cc55cSDimitry Andric Data += NumBytesRead; 337349cc55cSDimitry Andric return ErrorOr<T>(static_cast<T>(Val)); 338349cc55cSDimitry Andric } 339349cc55cSDimitry Andric 340349cc55cSDimitry Andric template <typename T> ErrorOr<T> MCPseudoProbeDecoder::readSignedNumber() { 341349cc55cSDimitry Andric unsigned NumBytesRead = 0; 342349cc55cSDimitry Andric int64_t Val = decodeSLEB128(Data, &NumBytesRead); 343349cc55cSDimitry Andric if (Val > std::numeric_limits<T>::max() || (Data + NumBytesRead > End)) { 344349cc55cSDimitry Andric return std::error_code(); 345349cc55cSDimitry Andric } 346349cc55cSDimitry Andric Data += NumBytesRead; 347349cc55cSDimitry Andric return ErrorOr<T>(static_cast<T>(Val)); 348349cc55cSDimitry Andric } 349349cc55cSDimitry Andric 350349cc55cSDimitry Andric ErrorOr<StringRef> MCPseudoProbeDecoder::readString(uint32_t Size) { 351349cc55cSDimitry Andric StringRef Str(reinterpret_cast<const char *>(Data), Size); 352349cc55cSDimitry Andric if (Data + Size > End) { 353349cc55cSDimitry Andric return std::error_code(); 354349cc55cSDimitry Andric } 355349cc55cSDimitry Andric Data += Size; 356349cc55cSDimitry Andric return ErrorOr<StringRef>(Str); 357349cc55cSDimitry Andric } 358349cc55cSDimitry Andric 359349cc55cSDimitry Andric bool MCPseudoProbeDecoder::buildGUID2FuncDescMap(const uint8_t *Start, 360349cc55cSDimitry Andric std::size_t Size) { 361349cc55cSDimitry Andric // The pseudo_probe_desc section has a format like: 362349cc55cSDimitry Andric // .section .pseudo_probe_desc,"",@progbits 363349cc55cSDimitry Andric // .quad -5182264717993193164 // GUID 364349cc55cSDimitry Andric // .quad 4294967295 // Hash 365349cc55cSDimitry Andric // .uleb 3 // Name size 366349cc55cSDimitry Andric // .ascii "foo" // Name 367349cc55cSDimitry Andric // .quad -2624081020897602054 368349cc55cSDimitry Andric // .quad 174696971957 369349cc55cSDimitry Andric // .uleb 34 370349cc55cSDimitry Andric // .ascii "main" 371349cc55cSDimitry Andric 372349cc55cSDimitry Andric Data = Start; 373349cc55cSDimitry Andric End = Data + Size; 374349cc55cSDimitry Andric 375349cc55cSDimitry Andric while (Data < End) { 376349cc55cSDimitry Andric auto ErrorOrGUID = readUnencodedNumber<uint64_t>(); 377349cc55cSDimitry Andric if (!ErrorOrGUID) 378349cc55cSDimitry Andric return false; 379349cc55cSDimitry Andric 380349cc55cSDimitry Andric auto ErrorOrHash = readUnencodedNumber<uint64_t>(); 381349cc55cSDimitry Andric if (!ErrorOrHash) 382349cc55cSDimitry Andric return false; 383349cc55cSDimitry Andric 384349cc55cSDimitry Andric auto ErrorOrNameSize = readUnsignedNumber<uint32_t>(); 385349cc55cSDimitry Andric if (!ErrorOrNameSize) 386349cc55cSDimitry Andric return false; 387349cc55cSDimitry Andric uint32_t NameSize = std::move(*ErrorOrNameSize); 388349cc55cSDimitry Andric 389349cc55cSDimitry Andric auto ErrorOrName = readString(NameSize); 390349cc55cSDimitry Andric if (!ErrorOrName) 391349cc55cSDimitry Andric return false; 392349cc55cSDimitry Andric 393349cc55cSDimitry Andric uint64_t GUID = std::move(*ErrorOrGUID); 394349cc55cSDimitry Andric uint64_t Hash = std::move(*ErrorOrHash); 395349cc55cSDimitry Andric StringRef Name = std::move(*ErrorOrName); 396349cc55cSDimitry Andric 397349cc55cSDimitry Andric // Initialize PseudoProbeFuncDesc and populate it into GUID2FuncDescMap 398349cc55cSDimitry Andric GUID2FuncDescMap.emplace(GUID, MCPseudoProbeFuncDesc(GUID, Hash, Name)); 399349cc55cSDimitry Andric } 400349cc55cSDimitry Andric assert(Data == End && "Have unprocessed data in pseudo_probe_desc section"); 401349cc55cSDimitry Andric return true; 402349cc55cSDimitry Andric } 403349cc55cSDimitry Andric 40481ad6265SDimitry Andric bool MCPseudoProbeDecoder::buildAddress2ProbeMap( 40581ad6265SDimitry Andric MCDecodedPseudoProbeInlineTree *Cur, uint64_t &LastAddr, 406*bdd1243dSDimitry Andric const Uint64Set &GuidFilter, const Uint64Map &FuncStartAddrs) { 407349cc55cSDimitry Andric // The pseudo_probe section encodes an inline forest and each tree has a 408*bdd1243dSDimitry Andric // format defined in MCPseudoProbe.h 409349cc55cSDimitry Andric 410349cc55cSDimitry Andric uint32_t Index = 0; 411*bdd1243dSDimitry Andric bool IsTopLevelFunc = Cur == &DummyInlineRoot; 412*bdd1243dSDimitry Andric if (IsTopLevelFunc) { 413349cc55cSDimitry Andric // Use a sequential id for top level inliner. 41481ad6265SDimitry Andric Index = Cur->getChildren().size(); 415349cc55cSDimitry Andric } else { 416349cc55cSDimitry Andric // Read inline site for inlinees 417349cc55cSDimitry Andric auto ErrorOrIndex = readUnsignedNumber<uint32_t>(); 418349cc55cSDimitry Andric if (!ErrorOrIndex) 419349cc55cSDimitry Andric return false; 420349cc55cSDimitry Andric Index = std::move(*ErrorOrIndex); 421349cc55cSDimitry Andric } 42281ad6265SDimitry Andric 423349cc55cSDimitry Andric // Read guid 424349cc55cSDimitry Andric auto ErrorOrCurGuid = readUnencodedNumber<uint64_t>(); 425349cc55cSDimitry Andric if (!ErrorOrCurGuid) 426349cc55cSDimitry Andric return false; 42781ad6265SDimitry Andric uint64_t Guid = std::move(*ErrorOrCurGuid); 42881ad6265SDimitry Andric 42981ad6265SDimitry Andric // Decide if top-level node should be disgarded. 430*bdd1243dSDimitry Andric if (IsTopLevelFunc && !GuidFilter.empty() && !GuidFilter.count(Guid)) 43181ad6265SDimitry Andric Cur = nullptr; 43281ad6265SDimitry Andric 43381ad6265SDimitry Andric // If the incoming node is null, all its children nodes should be disgarded. 43481ad6265SDimitry Andric if (Cur) { 43581ad6265SDimitry Andric // Switch/add to a new tree node(inlinee) 43681ad6265SDimitry Andric Cur = Cur->getOrAddNode(std::make_tuple(Guid, Index)); 43781ad6265SDimitry Andric Cur->Guid = Guid; 438*bdd1243dSDimitry Andric if (IsTopLevelFunc && !EncodingIsAddrBased) { 439*bdd1243dSDimitry Andric if (auto V = FuncStartAddrs.lookup(Guid)) 440*bdd1243dSDimitry Andric LastAddr = V; 441*bdd1243dSDimitry Andric } 44281ad6265SDimitry Andric } 44381ad6265SDimitry Andric 444349cc55cSDimitry Andric // Read number of probes in the current node. 445349cc55cSDimitry Andric auto ErrorOrNodeCount = readUnsignedNumber<uint32_t>(); 446349cc55cSDimitry Andric if (!ErrorOrNodeCount) 447349cc55cSDimitry Andric return false; 448349cc55cSDimitry Andric uint32_t NodeCount = std::move(*ErrorOrNodeCount); 449349cc55cSDimitry Andric // Read number of direct inlinees 450349cc55cSDimitry Andric auto ErrorOrCurChildrenToProcess = readUnsignedNumber<uint32_t>(); 451349cc55cSDimitry Andric if (!ErrorOrCurChildrenToProcess) 452349cc55cSDimitry Andric return false; 453349cc55cSDimitry Andric // Read all probes in this node 454349cc55cSDimitry Andric for (std::size_t I = 0; I < NodeCount; I++) { 455349cc55cSDimitry Andric // Read index 456349cc55cSDimitry Andric auto ErrorOrIndex = readUnsignedNumber<uint32_t>(); 457349cc55cSDimitry Andric if (!ErrorOrIndex) 458349cc55cSDimitry Andric return false; 459349cc55cSDimitry Andric uint32_t Index = std::move(*ErrorOrIndex); 460349cc55cSDimitry Andric // Read type | flag. 461349cc55cSDimitry Andric auto ErrorOrValue = readUnencodedNumber<uint8_t>(); 462349cc55cSDimitry Andric if (!ErrorOrValue) 463349cc55cSDimitry Andric return false; 464349cc55cSDimitry Andric uint8_t Value = std::move(*ErrorOrValue); 465349cc55cSDimitry Andric uint8_t Kind = Value & 0xf; 466349cc55cSDimitry Andric uint8_t Attr = (Value & 0x70) >> 4; 467349cc55cSDimitry Andric // Read address 468349cc55cSDimitry Andric uint64_t Addr = 0; 469349cc55cSDimitry Andric if (Value & 0x80) { 470349cc55cSDimitry Andric auto ErrorOrOffset = readSignedNumber<int64_t>(); 471349cc55cSDimitry Andric if (!ErrorOrOffset) 472349cc55cSDimitry Andric return false; 473349cc55cSDimitry Andric int64_t Offset = std::move(*ErrorOrOffset); 474349cc55cSDimitry Andric Addr = LastAddr + Offset; 475349cc55cSDimitry Andric } else { 476349cc55cSDimitry Andric auto ErrorOrAddr = readUnencodedNumber<int64_t>(); 477349cc55cSDimitry Andric if (!ErrorOrAddr) 478349cc55cSDimitry Andric return false; 479349cc55cSDimitry Andric Addr = std::move(*ErrorOrAddr); 480*bdd1243dSDimitry Andric if (isSentinelProbe(Attr)) { 481*bdd1243dSDimitry Andric // For sentinel probe, the addr field actually stores the GUID of the 482*bdd1243dSDimitry Andric // split function. Convert it to the real address. 483*bdd1243dSDimitry Andric if (auto V = FuncStartAddrs.lookup(Addr)) 484*bdd1243dSDimitry Andric Addr = V; 485*bdd1243dSDimitry Andric } else { 486*bdd1243dSDimitry Andric // For now we assume all probe encoding should be either based on 487*bdd1243dSDimitry Andric // leading probe address or function start address. 488*bdd1243dSDimitry Andric // The scheme is for downwards compatibility. 489*bdd1243dSDimitry Andric // TODO: retire this scheme once compatibility is no longer an issue. 490*bdd1243dSDimitry Andric EncodingIsAddrBased = true; 491*bdd1243dSDimitry Andric } 492349cc55cSDimitry Andric } 49381ad6265SDimitry Andric 494*bdd1243dSDimitry Andric if (Cur && !isSentinelProbe(Attr)) { 495349cc55cSDimitry Andric // Populate Address2ProbesMap 496349cc55cSDimitry Andric auto &Probes = Address2ProbesMap[Addr]; 497349cc55cSDimitry Andric Probes.emplace_back(Addr, Cur->Guid, Index, PseudoProbeType(Kind), Attr, 498349cc55cSDimitry Andric Cur); 499349cc55cSDimitry Andric Cur->addProbes(&Probes.back()); 50081ad6265SDimitry Andric } 501349cc55cSDimitry Andric LastAddr = Addr; 502349cc55cSDimitry Andric } 503349cc55cSDimitry Andric 50481ad6265SDimitry Andric uint32_t ChildrenToProcess = std::move(*ErrorOrCurChildrenToProcess); 50581ad6265SDimitry Andric for (uint32_t I = 0; I < ChildrenToProcess; I++) { 506*bdd1243dSDimitry Andric buildAddress2ProbeMap(Cur, LastAddr, GuidFilter, FuncStartAddrs); 507349cc55cSDimitry Andric } 508349cc55cSDimitry Andric 509349cc55cSDimitry Andric return true; 510349cc55cSDimitry Andric } 511349cc55cSDimitry Andric 51281ad6265SDimitry Andric bool MCPseudoProbeDecoder::buildAddress2ProbeMap( 513*bdd1243dSDimitry Andric const uint8_t *Start, std::size_t Size, const Uint64Set &GuidFilter, 514*bdd1243dSDimitry Andric const Uint64Map &FuncStartAddrs) { 51581ad6265SDimitry Andric Data = Start; 51681ad6265SDimitry Andric End = Data + Size; 51781ad6265SDimitry Andric uint64_t LastAddr = 0; 51881ad6265SDimitry Andric while (Data < End) 519*bdd1243dSDimitry Andric buildAddress2ProbeMap(&DummyInlineRoot, LastAddr, GuidFilter, 520*bdd1243dSDimitry Andric FuncStartAddrs); 52181ad6265SDimitry Andric assert(Data == End && "Have unprocessed data in pseudo_probe section"); 52281ad6265SDimitry Andric return true; 52381ad6265SDimitry Andric } 52481ad6265SDimitry Andric 525349cc55cSDimitry Andric void MCPseudoProbeDecoder::printGUID2FuncDescMap(raw_ostream &OS) { 526349cc55cSDimitry Andric OS << "Pseudo Probe Desc:\n"; 527349cc55cSDimitry Andric // Make the output deterministic 528349cc55cSDimitry Andric std::map<uint64_t, MCPseudoProbeFuncDesc> OrderedMap(GUID2FuncDescMap.begin(), 529349cc55cSDimitry Andric GUID2FuncDescMap.end()); 530349cc55cSDimitry Andric for (auto &I : OrderedMap) { 531349cc55cSDimitry Andric I.second.print(OS); 532349cc55cSDimitry Andric } 533349cc55cSDimitry Andric } 534349cc55cSDimitry Andric 535349cc55cSDimitry Andric void MCPseudoProbeDecoder::printProbeForAddress(raw_ostream &OS, 536349cc55cSDimitry Andric uint64_t Address) { 537349cc55cSDimitry Andric auto It = Address2ProbesMap.find(Address); 538349cc55cSDimitry Andric if (It != Address2ProbesMap.end()) { 539349cc55cSDimitry Andric for (auto &Probe : It->second) { 540349cc55cSDimitry Andric OS << " [Probe]:\t"; 541349cc55cSDimitry Andric Probe.print(OS, GUID2FuncDescMap, true); 542349cc55cSDimitry Andric } 543349cc55cSDimitry Andric } 544349cc55cSDimitry Andric } 545349cc55cSDimitry Andric 546349cc55cSDimitry Andric void MCPseudoProbeDecoder::printProbesForAllAddresses(raw_ostream &OS) { 547349cc55cSDimitry Andric std::vector<uint64_t> Addresses; 548349cc55cSDimitry Andric for (auto Entry : Address2ProbesMap) 549349cc55cSDimitry Andric Addresses.push_back(Entry.first); 550fcaf7f86SDimitry Andric llvm::sort(Addresses); 551349cc55cSDimitry Andric for (auto K : Addresses) { 552349cc55cSDimitry Andric OS << "Address:\t"; 553349cc55cSDimitry Andric OS << K; 554349cc55cSDimitry Andric OS << "\n"; 555349cc55cSDimitry Andric printProbeForAddress(OS, K); 556349cc55cSDimitry Andric } 557349cc55cSDimitry Andric } 558349cc55cSDimitry Andric 559349cc55cSDimitry Andric const MCDecodedPseudoProbe * 560349cc55cSDimitry Andric MCPseudoProbeDecoder::getCallProbeForAddr(uint64_t Address) const { 561349cc55cSDimitry Andric auto It = Address2ProbesMap.find(Address); 562349cc55cSDimitry Andric if (It == Address2ProbesMap.end()) 563349cc55cSDimitry Andric return nullptr; 564349cc55cSDimitry Andric const auto &Probes = It->second; 565349cc55cSDimitry Andric 566349cc55cSDimitry Andric const MCDecodedPseudoProbe *CallProbe = nullptr; 567349cc55cSDimitry Andric for (const auto &Probe : Probes) { 568349cc55cSDimitry Andric if (Probe.isCall()) { 569349cc55cSDimitry Andric assert(!CallProbe && 570349cc55cSDimitry Andric "There should be only one call probe corresponding to address " 571349cc55cSDimitry Andric "which is a callsite."); 572349cc55cSDimitry Andric CallProbe = &Probe; 573349cc55cSDimitry Andric } 574349cc55cSDimitry Andric } 575349cc55cSDimitry Andric return CallProbe; 576349cc55cSDimitry Andric } 577349cc55cSDimitry Andric 578349cc55cSDimitry Andric const MCPseudoProbeFuncDesc * 579349cc55cSDimitry Andric MCPseudoProbeDecoder::getFuncDescForGUID(uint64_t GUID) const { 580349cc55cSDimitry Andric auto It = GUID2FuncDescMap.find(GUID); 581349cc55cSDimitry Andric assert(It != GUID2FuncDescMap.end() && "Function descriptor doesn't exist"); 582349cc55cSDimitry Andric return &It->second; 583349cc55cSDimitry Andric } 584349cc55cSDimitry Andric 585349cc55cSDimitry Andric void MCPseudoProbeDecoder::getInlineContextForProbe( 586349cc55cSDimitry Andric const MCDecodedPseudoProbe *Probe, 587349cc55cSDimitry Andric SmallVectorImpl<MCPseduoProbeFrameLocation> &InlineContextStack, 588349cc55cSDimitry Andric bool IncludeLeaf) const { 589349cc55cSDimitry Andric Probe->getInlineContext(InlineContextStack, GUID2FuncDescMap); 590349cc55cSDimitry Andric if (!IncludeLeaf) 591349cc55cSDimitry Andric return; 592349cc55cSDimitry Andric // Note that the context from probe doesn't include leaf frame, 593349cc55cSDimitry Andric // hence we need to retrieve and prepend leaf if requested. 594349cc55cSDimitry Andric const auto *FuncDesc = getFuncDescForGUID(Probe->getGuid()); 595349cc55cSDimitry Andric InlineContextStack.emplace_back( 596349cc55cSDimitry Andric MCPseduoProbeFrameLocation(FuncDesc->FuncName, Probe->getIndex())); 597349cc55cSDimitry Andric } 598349cc55cSDimitry Andric 599349cc55cSDimitry Andric const MCPseudoProbeFuncDesc *MCPseudoProbeDecoder::getInlinerDescForProbe( 600349cc55cSDimitry Andric const MCDecodedPseudoProbe *Probe) const { 601349cc55cSDimitry Andric MCDecodedPseudoProbeInlineTree *InlinerNode = Probe->getInlineTreeNode(); 602349cc55cSDimitry Andric if (!InlinerNode->hasInlineSite()) 603349cc55cSDimitry Andric return nullptr; 60481ad6265SDimitry Andric return getFuncDescForGUID(InlinerNode->Parent->Guid); 605349cc55cSDimitry Andric } 606