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" 12*81ad6265SDimitry Andric #include "llvm/MC/MCExpr.h" 13*81ad6265SDimitry Andric #include "llvm/MC/MCFragment.h" 14e8d8bef9SDimitry Andric #include "llvm/MC/MCObjectFileInfo.h" 15e8d8bef9SDimitry Andric #include "llvm/MC/MCObjectStreamer.h" 16349cc55cSDimitry Andric #include "llvm/Support/Endian.h" 17349cc55cSDimitry Andric #include "llvm/Support/LEB128.h" 18349cc55cSDimitry Andric #include "llvm/Support/raw_ostream.h" 19349cc55cSDimitry Andric #include <limits> 20349cc55cSDimitry Andric #include <memory> 21349cc55cSDimitry Andric #include <sstream> 22e8d8bef9SDimitry Andric 23e8d8bef9SDimitry Andric #define DEBUG_TYPE "mcpseudoprobe" 24e8d8bef9SDimitry Andric 25e8d8bef9SDimitry Andric using namespace llvm; 26349cc55cSDimitry Andric using namespace support; 27e8d8bef9SDimitry Andric 28e8d8bef9SDimitry Andric #ifndef NDEBUG 29e8d8bef9SDimitry Andric int MCPseudoProbeTable::DdgPrintIndent = 0; 30e8d8bef9SDimitry Andric #endif 31e8d8bef9SDimitry Andric 32e8d8bef9SDimitry Andric static const MCExpr *buildSymbolDiff(MCObjectStreamer *MCOS, const MCSymbol *A, 33e8d8bef9SDimitry Andric const MCSymbol *B) { 34e8d8bef9SDimitry Andric MCContext &Context = MCOS->getContext(); 35e8d8bef9SDimitry Andric MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None; 36e8d8bef9SDimitry Andric const MCExpr *ARef = MCSymbolRefExpr::create(A, Variant, Context); 37e8d8bef9SDimitry Andric const MCExpr *BRef = MCSymbolRefExpr::create(B, Variant, Context); 38e8d8bef9SDimitry Andric const MCExpr *AddrDelta = 39e8d8bef9SDimitry Andric MCBinaryExpr::create(MCBinaryExpr::Sub, ARef, BRef, Context); 40e8d8bef9SDimitry Andric return AddrDelta; 41e8d8bef9SDimitry Andric } 42e8d8bef9SDimitry Andric 43e8d8bef9SDimitry Andric void MCPseudoProbe::emit(MCObjectStreamer *MCOS, 44e8d8bef9SDimitry Andric const MCPseudoProbe *LastProbe) const { 45e8d8bef9SDimitry Andric // Emit Index 46e8d8bef9SDimitry Andric MCOS->emitULEB128IntValue(Index); 47e8d8bef9SDimitry Andric // Emit Type and the flag: 48e8d8bef9SDimitry Andric // Type (bit 0 to 3), with bit 4 to 6 for attributes. 49e8d8bef9SDimitry Andric // Flag (bit 7, 0 - code address, 1 - address delta). This indicates whether 50e8d8bef9SDimitry Andric // the following field is a symbolic code address or an address delta. 51e8d8bef9SDimitry Andric assert(Type <= 0xF && "Probe type too big to encode, exceeding 15"); 52e8d8bef9SDimitry Andric assert(Attributes <= 0x7 && 53e8d8bef9SDimitry Andric "Probe attributes too big to encode, exceeding 7"); 54e8d8bef9SDimitry Andric uint8_t PackedType = Type | (Attributes << 4); 55e8d8bef9SDimitry Andric uint8_t Flag = LastProbe ? ((int8_t)MCPseudoProbeFlag::AddressDelta << 7) : 0; 56e8d8bef9SDimitry Andric MCOS->emitInt8(Flag | PackedType); 57e8d8bef9SDimitry Andric 58e8d8bef9SDimitry Andric if (LastProbe) { 59e8d8bef9SDimitry Andric // Emit the delta between the address label and LastProbe. 60e8d8bef9SDimitry Andric const MCExpr *AddrDelta = 61e8d8bef9SDimitry Andric buildSymbolDiff(MCOS, Label, LastProbe->getLabel()); 62e8d8bef9SDimitry Andric int64_t Delta; 63e8d8bef9SDimitry Andric if (AddrDelta->evaluateAsAbsolute(Delta, MCOS->getAssemblerPtr())) { 64e8d8bef9SDimitry Andric MCOS->emitSLEB128IntValue(Delta); 65e8d8bef9SDimitry Andric } else { 66e8d8bef9SDimitry Andric MCOS->insert(new MCPseudoProbeAddrFragment(AddrDelta)); 67e8d8bef9SDimitry Andric } 68e8d8bef9SDimitry Andric } else { 69e8d8bef9SDimitry Andric // Emit label as a symbolic code address. 70e8d8bef9SDimitry Andric MCOS->emitSymbolValue( 71e8d8bef9SDimitry Andric Label, MCOS->getContext().getAsmInfo()->getCodePointerSize()); 72e8d8bef9SDimitry Andric } 73e8d8bef9SDimitry Andric 74e8d8bef9SDimitry Andric LLVM_DEBUG({ 75e8d8bef9SDimitry Andric dbgs().indent(MCPseudoProbeTable::DdgPrintIndent); 76e8d8bef9SDimitry Andric dbgs() << "Probe: " << Index << "\n"; 77e8d8bef9SDimitry Andric }); 78e8d8bef9SDimitry Andric } 79e8d8bef9SDimitry Andric 80e8d8bef9SDimitry Andric void MCPseudoProbeInlineTree::addPseudoProbe( 81e8d8bef9SDimitry Andric const MCPseudoProbe &Probe, const MCPseudoProbeInlineStack &InlineStack) { 82e8d8bef9SDimitry Andric // The function should not be called on the root. 83e8d8bef9SDimitry Andric assert(isRoot() && "Should not be called on root"); 84e8d8bef9SDimitry Andric 85e8d8bef9SDimitry Andric // When it comes here, the input look like: 86e8d8bef9SDimitry Andric // Probe: GUID of C, ... 87e8d8bef9SDimitry Andric // InlineStack: [88, A], [66, B] 88e8d8bef9SDimitry Andric // which means, Function A inlines function B at call site with a probe id of 89e8d8bef9SDimitry Andric // 88, and B inlines C at probe 66. The tri-tree expects a tree path like {[0, 90e8d8bef9SDimitry Andric // A], [88, B], [66, C]} to locate the tree node where the probe should be 91e8d8bef9SDimitry Andric // added. Note that the edge [0, A] means A is the top-level function we are 92e8d8bef9SDimitry Andric // emitting probes for. 93e8d8bef9SDimitry Andric 94e8d8bef9SDimitry Andric // Make a [0, A] edge. 95e8d8bef9SDimitry Andric // An empty inline stack means the function that the probe originates from 96e8d8bef9SDimitry Andric // is a top-level function. 97e8d8bef9SDimitry Andric InlineSite Top; 98e8d8bef9SDimitry Andric if (InlineStack.empty()) { 99e8d8bef9SDimitry Andric Top = InlineSite(Probe.getGuid(), 0); 100e8d8bef9SDimitry Andric } else { 101e8d8bef9SDimitry Andric Top = InlineSite(std::get<0>(InlineStack.front()), 0); 102e8d8bef9SDimitry Andric } 103e8d8bef9SDimitry Andric 104e8d8bef9SDimitry Andric auto *Cur = getOrAddNode(Top); 105e8d8bef9SDimitry Andric 106e8d8bef9SDimitry Andric // Make interior edges by walking the inline stack. Once it's done, Cur should 107e8d8bef9SDimitry Andric // point to the node that the probe originates from. 108e8d8bef9SDimitry Andric if (!InlineStack.empty()) { 109e8d8bef9SDimitry Andric auto Iter = InlineStack.begin(); 110e8d8bef9SDimitry Andric auto Index = std::get<1>(*Iter); 111e8d8bef9SDimitry Andric Iter++; 112e8d8bef9SDimitry Andric for (; Iter != InlineStack.end(); Iter++) { 113e8d8bef9SDimitry Andric // Make an edge by using the previous probe id and current GUID. 114e8d8bef9SDimitry Andric Cur = Cur->getOrAddNode(InlineSite(std::get<0>(*Iter), Index)); 115e8d8bef9SDimitry Andric Index = std::get<1>(*Iter); 116e8d8bef9SDimitry Andric } 117e8d8bef9SDimitry Andric Cur = Cur->getOrAddNode(InlineSite(Probe.getGuid(), Index)); 118e8d8bef9SDimitry Andric } 119e8d8bef9SDimitry Andric 120e8d8bef9SDimitry Andric Cur->Probes.push_back(Probe); 121e8d8bef9SDimitry Andric } 122e8d8bef9SDimitry Andric 123e8d8bef9SDimitry Andric void MCPseudoProbeInlineTree::emit(MCObjectStreamer *MCOS, 124e8d8bef9SDimitry Andric const MCPseudoProbe *&LastProbe) { 125e8d8bef9SDimitry Andric LLVM_DEBUG({ 126e8d8bef9SDimitry Andric dbgs().indent(MCPseudoProbeTable::DdgPrintIndent); 127e8d8bef9SDimitry Andric dbgs() << "Group [\n"; 128e8d8bef9SDimitry Andric MCPseudoProbeTable::DdgPrintIndent += 2; 129e8d8bef9SDimitry Andric }); 130e8d8bef9SDimitry Andric // Emit probes grouped by GUID. 131e8d8bef9SDimitry Andric if (Guid != 0) { 132e8d8bef9SDimitry Andric LLVM_DEBUG({ 133e8d8bef9SDimitry Andric dbgs().indent(MCPseudoProbeTable::DdgPrintIndent); 134e8d8bef9SDimitry Andric dbgs() << "GUID: " << Guid << "\n"; 135e8d8bef9SDimitry Andric }); 136e8d8bef9SDimitry Andric // Emit Guid 137e8d8bef9SDimitry Andric MCOS->emitInt64(Guid); 138e8d8bef9SDimitry Andric // Emit number of probes in this node 139e8d8bef9SDimitry Andric MCOS->emitULEB128IntValue(Probes.size()); 140e8d8bef9SDimitry Andric // Emit number of direct inlinees 141349cc55cSDimitry Andric MCOS->emitULEB128IntValue(Children.size()); 142e8d8bef9SDimitry Andric // Emit probes in this group 143e8d8bef9SDimitry Andric for (const auto &Probe : Probes) { 144e8d8bef9SDimitry Andric Probe.emit(MCOS, LastProbe); 145e8d8bef9SDimitry Andric LastProbe = &Probe; 146e8d8bef9SDimitry Andric } 147e8d8bef9SDimitry Andric } else { 148e8d8bef9SDimitry Andric assert(Probes.empty() && "Root should not have probes"); 149e8d8bef9SDimitry Andric } 150e8d8bef9SDimitry Andric 151349cc55cSDimitry Andric // Emit sorted descendant 152349cc55cSDimitry Andric // InlineSite is unique for each pair, 153349cc55cSDimitry Andric // so there will be no ordering of Inlinee based on MCPseudoProbeInlineTree* 154349cc55cSDimitry Andric std::map<InlineSite, MCPseudoProbeInlineTree *> Inlinees; 1550eae32dcSDimitry Andric for (auto &Child : Children) 1560eae32dcSDimitry Andric Inlinees[Child.first] = Child.second.get(); 157349cc55cSDimitry Andric 158e8d8bef9SDimitry Andric for (const auto &Inlinee : Inlinees) { 159e8d8bef9SDimitry Andric if (Guid) { 160e8d8bef9SDimitry Andric // Emit probe index 161e8d8bef9SDimitry Andric MCOS->emitULEB128IntValue(std::get<1>(Inlinee.first)); 162e8d8bef9SDimitry Andric LLVM_DEBUG({ 163e8d8bef9SDimitry Andric dbgs().indent(MCPseudoProbeTable::DdgPrintIndent); 164e8d8bef9SDimitry Andric dbgs() << "InlineSite: " << std::get<1>(Inlinee.first) << "\n"; 165e8d8bef9SDimitry Andric }); 166e8d8bef9SDimitry Andric } 167e8d8bef9SDimitry Andric // Emit the group 168e8d8bef9SDimitry Andric Inlinee.second->emit(MCOS, LastProbe); 169e8d8bef9SDimitry Andric } 170e8d8bef9SDimitry Andric 171e8d8bef9SDimitry Andric LLVM_DEBUG({ 172e8d8bef9SDimitry Andric MCPseudoProbeTable::DdgPrintIndent -= 2; 173e8d8bef9SDimitry Andric dbgs().indent(MCPseudoProbeTable::DdgPrintIndent); 174e8d8bef9SDimitry Andric dbgs() << "]\n"; 175e8d8bef9SDimitry Andric }); 176e8d8bef9SDimitry Andric } 177e8d8bef9SDimitry Andric 178e8d8bef9SDimitry Andric void MCPseudoProbeSection::emit(MCObjectStreamer *MCOS) { 179e8d8bef9SDimitry Andric MCContext &Ctx = MCOS->getContext(); 180e8d8bef9SDimitry Andric 181e8d8bef9SDimitry Andric for (auto &ProbeSec : MCProbeDivisions) { 182e8d8bef9SDimitry Andric const MCPseudoProbe *LastProbe = nullptr; 183e8d8bef9SDimitry Andric if (auto *S = 184e8d8bef9SDimitry Andric Ctx.getObjectFileInfo()->getPseudoProbeSection(ProbeSec.first)) { 185e8d8bef9SDimitry Andric // Switch to the .pseudoprobe section or a comdat group. 186*81ad6265SDimitry Andric MCOS->switchSection(S); 187e8d8bef9SDimitry Andric // Emit probes grouped by GUID. 188e8d8bef9SDimitry Andric ProbeSec.second.emit(MCOS, LastProbe); 189e8d8bef9SDimitry Andric } 190e8d8bef9SDimitry Andric } 191e8d8bef9SDimitry Andric } 192e8d8bef9SDimitry Andric 193e8d8bef9SDimitry Andric // 194e8d8bef9SDimitry Andric // This emits the pseudo probe tables. 195e8d8bef9SDimitry Andric // 196e8d8bef9SDimitry Andric void MCPseudoProbeTable::emit(MCObjectStreamer *MCOS) { 197e8d8bef9SDimitry Andric MCContext &Ctx = MCOS->getContext(); 198e8d8bef9SDimitry Andric auto &ProbeTable = Ctx.getMCPseudoProbeTable(); 199e8d8bef9SDimitry Andric 200e8d8bef9SDimitry Andric // Bail out early so we don't switch to the pseudo_probe section needlessly 201e8d8bef9SDimitry Andric // and in doing so create an unnecessary (if empty) section. 202e8d8bef9SDimitry Andric auto &ProbeSections = ProbeTable.getProbeSections(); 203e8d8bef9SDimitry Andric if (ProbeSections.empty()) 204e8d8bef9SDimitry Andric return; 205e8d8bef9SDimitry Andric 206e8d8bef9SDimitry Andric LLVM_DEBUG(MCPseudoProbeTable::DdgPrintIndent = 0); 207e8d8bef9SDimitry Andric 208e8d8bef9SDimitry Andric // Put out the probe. 209e8d8bef9SDimitry Andric ProbeSections.emit(MCOS); 210e8d8bef9SDimitry Andric } 211349cc55cSDimitry Andric 212349cc55cSDimitry Andric static StringRef getProbeFNameForGUID(const GUIDProbeFunctionMap &GUID2FuncMAP, 213349cc55cSDimitry Andric uint64_t GUID) { 214349cc55cSDimitry Andric auto It = GUID2FuncMAP.find(GUID); 215349cc55cSDimitry Andric assert(It != GUID2FuncMAP.end() && 216349cc55cSDimitry Andric "Probe function must exist for a valid GUID"); 217349cc55cSDimitry Andric return It->second.FuncName; 218349cc55cSDimitry Andric } 219349cc55cSDimitry Andric 220349cc55cSDimitry Andric void MCPseudoProbeFuncDesc::print(raw_ostream &OS) { 221349cc55cSDimitry Andric OS << "GUID: " << FuncGUID << " Name: " << FuncName << "\n"; 222349cc55cSDimitry Andric OS << "Hash: " << FuncHash << "\n"; 223349cc55cSDimitry Andric } 224349cc55cSDimitry Andric 225349cc55cSDimitry Andric void MCDecodedPseudoProbe::getInlineContext( 226349cc55cSDimitry Andric SmallVectorImpl<MCPseduoProbeFrameLocation> &ContextStack, 227349cc55cSDimitry Andric const GUIDProbeFunctionMap &GUID2FuncMAP) const { 228349cc55cSDimitry Andric uint32_t Begin = ContextStack.size(); 229349cc55cSDimitry Andric MCDecodedPseudoProbeInlineTree *Cur = InlineTree; 230349cc55cSDimitry Andric // It will add the string of each node's inline site during iteration. 231349cc55cSDimitry Andric // Note that it won't include the probe's belonging function(leaf location) 232349cc55cSDimitry Andric while (Cur->hasInlineSite()) { 233*81ad6265SDimitry Andric StringRef FuncName = getProbeFNameForGUID(GUID2FuncMAP, Cur->Parent->Guid); 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 360*81ad6265SDimitry Andric bool MCPseudoProbeDecoder::buildAddress2ProbeMap( 361*81ad6265SDimitry Andric MCDecodedPseudoProbeInlineTree *Cur, uint64_t &LastAddr, 362*81ad6265SDimitry Andric std::unordered_set<uint64_t> &GuildFilter) { 363349cc55cSDimitry Andric // The pseudo_probe section encodes an inline forest and each tree has a 364349cc55cSDimitry Andric // format like: 365349cc55cSDimitry Andric // FUNCTION BODY (one for each uninlined function present in the text 366349cc55cSDimitry Andric // section) 367349cc55cSDimitry Andric // GUID (uint64) 368349cc55cSDimitry Andric // GUID of the function 369349cc55cSDimitry Andric // NPROBES (ULEB128) 370349cc55cSDimitry Andric // Number of probes originating from this function. 371349cc55cSDimitry Andric // NUM_INLINED_FUNCTIONS (ULEB128) 372349cc55cSDimitry Andric // Number of callees inlined into this function, aka number of 373349cc55cSDimitry Andric // first-level inlinees 374349cc55cSDimitry Andric // PROBE RECORDS 375349cc55cSDimitry Andric // A list of NPROBES entries. Each entry contains: 376349cc55cSDimitry Andric // INDEX (ULEB128) 377349cc55cSDimitry Andric // TYPE (uint4) 378349cc55cSDimitry Andric // 0 - block probe, 1 - indirect call, 2 - direct call 379349cc55cSDimitry Andric // ATTRIBUTE (uint3) 380349cc55cSDimitry Andric // 1 - tail call, 2 - dangling 381349cc55cSDimitry Andric // ADDRESS_TYPE (uint1) 382349cc55cSDimitry Andric // 0 - code address, 1 - address delta 383349cc55cSDimitry Andric // CODE_ADDRESS (uint64 or ULEB128) 384349cc55cSDimitry Andric // code address or address delta, depending on Flag 385349cc55cSDimitry Andric // INLINED FUNCTION RECORDS 386349cc55cSDimitry Andric // A list of NUM_INLINED_FUNCTIONS entries describing each of the 387349cc55cSDimitry Andric // inlined callees. Each record contains: 388349cc55cSDimitry Andric // INLINE SITE 389349cc55cSDimitry Andric // Index of the callsite probe (ULEB128) 390349cc55cSDimitry Andric // FUNCTION BODY 391349cc55cSDimitry Andric // A FUNCTION BODY entry describing the inlined function. 392349cc55cSDimitry Andric 393349cc55cSDimitry Andric uint32_t Index = 0; 394*81ad6265SDimitry Andric if (Cur == &DummyInlineRoot) { 395349cc55cSDimitry Andric // Use a sequential id for top level inliner. 396*81ad6265SDimitry Andric Index = Cur->getChildren().size(); 397349cc55cSDimitry Andric } else { 398349cc55cSDimitry Andric // Read inline site for inlinees 399349cc55cSDimitry Andric auto ErrorOrIndex = readUnsignedNumber<uint32_t>(); 400349cc55cSDimitry Andric if (!ErrorOrIndex) 401349cc55cSDimitry Andric return false; 402349cc55cSDimitry Andric Index = std::move(*ErrorOrIndex); 403349cc55cSDimitry Andric } 404*81ad6265SDimitry Andric 405349cc55cSDimitry Andric // Read guid 406349cc55cSDimitry Andric auto ErrorOrCurGuid = readUnencodedNumber<uint64_t>(); 407349cc55cSDimitry Andric if (!ErrorOrCurGuid) 408349cc55cSDimitry Andric return false; 409*81ad6265SDimitry Andric uint64_t Guid = std::move(*ErrorOrCurGuid); 410*81ad6265SDimitry Andric 411*81ad6265SDimitry Andric // Decide if top-level node should be disgarded. 412*81ad6265SDimitry Andric if (Cur == &DummyInlineRoot && !GuildFilter.empty() && 413*81ad6265SDimitry Andric !GuildFilter.count(Guid)) 414*81ad6265SDimitry Andric Cur = nullptr; 415*81ad6265SDimitry Andric 416*81ad6265SDimitry Andric // If the incoming node is null, all its children nodes should be disgarded. 417*81ad6265SDimitry Andric if (Cur) { 418*81ad6265SDimitry Andric // Switch/add to a new tree node(inlinee) 419*81ad6265SDimitry Andric Cur = Cur->getOrAddNode(std::make_tuple(Guid, Index)); 420*81ad6265SDimitry Andric Cur->Guid = Guid; 421*81ad6265SDimitry Andric } 422*81ad6265SDimitry Andric 423349cc55cSDimitry Andric // Read number of probes in the current node. 424349cc55cSDimitry Andric auto ErrorOrNodeCount = readUnsignedNumber<uint32_t>(); 425349cc55cSDimitry Andric if (!ErrorOrNodeCount) 426349cc55cSDimitry Andric return false; 427349cc55cSDimitry Andric uint32_t NodeCount = std::move(*ErrorOrNodeCount); 428349cc55cSDimitry Andric // Read number of direct inlinees 429349cc55cSDimitry Andric auto ErrorOrCurChildrenToProcess = readUnsignedNumber<uint32_t>(); 430349cc55cSDimitry Andric if (!ErrorOrCurChildrenToProcess) 431349cc55cSDimitry Andric return false; 432349cc55cSDimitry Andric // Read all probes in this node 433349cc55cSDimitry Andric for (std::size_t I = 0; I < NodeCount; I++) { 434349cc55cSDimitry Andric // Read index 435349cc55cSDimitry Andric auto ErrorOrIndex = readUnsignedNumber<uint32_t>(); 436349cc55cSDimitry Andric if (!ErrorOrIndex) 437349cc55cSDimitry Andric return false; 438349cc55cSDimitry Andric uint32_t Index = std::move(*ErrorOrIndex); 439349cc55cSDimitry Andric // Read type | flag. 440349cc55cSDimitry Andric auto ErrorOrValue = readUnencodedNumber<uint8_t>(); 441349cc55cSDimitry Andric if (!ErrorOrValue) 442349cc55cSDimitry Andric return false; 443349cc55cSDimitry Andric uint8_t Value = std::move(*ErrorOrValue); 444349cc55cSDimitry Andric uint8_t Kind = Value & 0xf; 445349cc55cSDimitry Andric uint8_t Attr = (Value & 0x70) >> 4; 446349cc55cSDimitry Andric // Read address 447349cc55cSDimitry Andric uint64_t Addr = 0; 448349cc55cSDimitry Andric if (Value & 0x80) { 449349cc55cSDimitry Andric auto ErrorOrOffset = readSignedNumber<int64_t>(); 450349cc55cSDimitry Andric if (!ErrorOrOffset) 451349cc55cSDimitry Andric return false; 452349cc55cSDimitry Andric int64_t Offset = std::move(*ErrorOrOffset); 453349cc55cSDimitry Andric Addr = LastAddr + Offset; 454349cc55cSDimitry Andric } else { 455349cc55cSDimitry Andric auto ErrorOrAddr = readUnencodedNumber<int64_t>(); 456349cc55cSDimitry Andric if (!ErrorOrAddr) 457349cc55cSDimitry Andric return false; 458349cc55cSDimitry Andric Addr = std::move(*ErrorOrAddr); 459349cc55cSDimitry Andric } 460*81ad6265SDimitry Andric 461*81ad6265SDimitry Andric if (Cur) { 462349cc55cSDimitry Andric // Populate Address2ProbesMap 463349cc55cSDimitry Andric auto &Probes = Address2ProbesMap[Addr]; 464349cc55cSDimitry Andric Probes.emplace_back(Addr, Cur->Guid, Index, PseudoProbeType(Kind), Attr, 465349cc55cSDimitry Andric Cur); 466349cc55cSDimitry Andric Cur->addProbes(&Probes.back()); 467*81ad6265SDimitry Andric } 468349cc55cSDimitry Andric LastAddr = Addr; 469349cc55cSDimitry Andric } 470349cc55cSDimitry Andric 471*81ad6265SDimitry Andric uint32_t ChildrenToProcess = std::move(*ErrorOrCurChildrenToProcess); 472*81ad6265SDimitry Andric for (uint32_t I = 0; I < ChildrenToProcess; I++) { 473*81ad6265SDimitry Andric buildAddress2ProbeMap(Cur, LastAddr, GuildFilter); 474349cc55cSDimitry Andric } 475349cc55cSDimitry Andric 476349cc55cSDimitry Andric return true; 477349cc55cSDimitry Andric } 478349cc55cSDimitry Andric 479*81ad6265SDimitry Andric bool MCPseudoProbeDecoder::buildAddress2ProbeMap( 480*81ad6265SDimitry Andric const uint8_t *Start, std::size_t Size, 481*81ad6265SDimitry Andric std::unordered_set<uint64_t> &GuildFilter) { 482*81ad6265SDimitry Andric Data = Start; 483*81ad6265SDimitry Andric End = Data + Size; 484*81ad6265SDimitry Andric uint64_t LastAddr = 0; 485*81ad6265SDimitry Andric while (Data < End) 486*81ad6265SDimitry Andric buildAddress2ProbeMap(&DummyInlineRoot, LastAddr, GuildFilter); 487*81ad6265SDimitry Andric assert(Data == End && "Have unprocessed data in pseudo_probe section"); 488*81ad6265SDimitry Andric return true; 489*81ad6265SDimitry Andric } 490*81ad6265SDimitry Andric 491*81ad6265SDimitry Andric bool MCPseudoProbeDecoder::buildAddress2ProbeMap(const uint8_t *Start, 492*81ad6265SDimitry Andric std::size_t Size) { 493*81ad6265SDimitry Andric std::unordered_set<uint64_t> GuildFilter; 494*81ad6265SDimitry Andric return buildAddress2ProbeMap(Start, Size, GuildFilter); 495*81ad6265SDimitry Andric } 496*81ad6265SDimitry Andric 497349cc55cSDimitry Andric void MCPseudoProbeDecoder::printGUID2FuncDescMap(raw_ostream &OS) { 498349cc55cSDimitry Andric OS << "Pseudo Probe Desc:\n"; 499349cc55cSDimitry Andric // Make the output deterministic 500349cc55cSDimitry Andric std::map<uint64_t, MCPseudoProbeFuncDesc> OrderedMap(GUID2FuncDescMap.begin(), 501349cc55cSDimitry Andric GUID2FuncDescMap.end()); 502349cc55cSDimitry Andric for (auto &I : OrderedMap) { 503349cc55cSDimitry Andric I.second.print(OS); 504349cc55cSDimitry Andric } 505349cc55cSDimitry Andric } 506349cc55cSDimitry Andric 507349cc55cSDimitry Andric void MCPseudoProbeDecoder::printProbeForAddress(raw_ostream &OS, 508349cc55cSDimitry Andric uint64_t Address) { 509349cc55cSDimitry Andric auto It = Address2ProbesMap.find(Address); 510349cc55cSDimitry Andric if (It != Address2ProbesMap.end()) { 511349cc55cSDimitry Andric for (auto &Probe : It->second) { 512349cc55cSDimitry Andric OS << " [Probe]:\t"; 513349cc55cSDimitry Andric Probe.print(OS, GUID2FuncDescMap, true); 514349cc55cSDimitry Andric } 515349cc55cSDimitry Andric } 516349cc55cSDimitry Andric } 517349cc55cSDimitry Andric 518349cc55cSDimitry Andric void MCPseudoProbeDecoder::printProbesForAllAddresses(raw_ostream &OS) { 519349cc55cSDimitry Andric std::vector<uint64_t> Addresses; 520349cc55cSDimitry Andric for (auto Entry : Address2ProbesMap) 521349cc55cSDimitry Andric Addresses.push_back(Entry.first); 522349cc55cSDimitry Andric std::sort(Addresses.begin(), Addresses.end()); 523349cc55cSDimitry Andric for (auto K : Addresses) { 524349cc55cSDimitry Andric OS << "Address:\t"; 525349cc55cSDimitry Andric OS << K; 526349cc55cSDimitry Andric OS << "\n"; 527349cc55cSDimitry Andric printProbeForAddress(OS, K); 528349cc55cSDimitry Andric } 529349cc55cSDimitry Andric } 530349cc55cSDimitry Andric 531349cc55cSDimitry Andric const MCDecodedPseudoProbe * 532349cc55cSDimitry Andric MCPseudoProbeDecoder::getCallProbeForAddr(uint64_t Address) const { 533349cc55cSDimitry Andric auto It = Address2ProbesMap.find(Address); 534349cc55cSDimitry Andric if (It == Address2ProbesMap.end()) 535349cc55cSDimitry Andric return nullptr; 536349cc55cSDimitry Andric const auto &Probes = It->second; 537349cc55cSDimitry Andric 538349cc55cSDimitry Andric const MCDecodedPseudoProbe *CallProbe = nullptr; 539349cc55cSDimitry Andric for (const auto &Probe : Probes) { 540349cc55cSDimitry Andric if (Probe.isCall()) { 541349cc55cSDimitry Andric assert(!CallProbe && 542349cc55cSDimitry Andric "There should be only one call probe corresponding to address " 543349cc55cSDimitry Andric "which is a callsite."); 544349cc55cSDimitry Andric CallProbe = &Probe; 545349cc55cSDimitry Andric } 546349cc55cSDimitry Andric } 547349cc55cSDimitry Andric return CallProbe; 548349cc55cSDimitry Andric } 549349cc55cSDimitry Andric 550349cc55cSDimitry Andric const MCPseudoProbeFuncDesc * 551349cc55cSDimitry Andric MCPseudoProbeDecoder::getFuncDescForGUID(uint64_t GUID) const { 552349cc55cSDimitry Andric auto It = GUID2FuncDescMap.find(GUID); 553349cc55cSDimitry Andric assert(It != GUID2FuncDescMap.end() && "Function descriptor doesn't exist"); 554349cc55cSDimitry Andric return &It->second; 555349cc55cSDimitry Andric } 556349cc55cSDimitry Andric 557349cc55cSDimitry Andric void MCPseudoProbeDecoder::getInlineContextForProbe( 558349cc55cSDimitry Andric const MCDecodedPseudoProbe *Probe, 559349cc55cSDimitry Andric SmallVectorImpl<MCPseduoProbeFrameLocation> &InlineContextStack, 560349cc55cSDimitry Andric bool IncludeLeaf) const { 561349cc55cSDimitry Andric Probe->getInlineContext(InlineContextStack, GUID2FuncDescMap); 562349cc55cSDimitry Andric if (!IncludeLeaf) 563349cc55cSDimitry Andric return; 564349cc55cSDimitry Andric // Note that the context from probe doesn't include leaf frame, 565349cc55cSDimitry Andric // hence we need to retrieve and prepend leaf if requested. 566349cc55cSDimitry Andric const auto *FuncDesc = getFuncDescForGUID(Probe->getGuid()); 567349cc55cSDimitry Andric InlineContextStack.emplace_back( 568349cc55cSDimitry Andric MCPseduoProbeFrameLocation(FuncDesc->FuncName, Probe->getIndex())); 569349cc55cSDimitry Andric } 570349cc55cSDimitry Andric 571349cc55cSDimitry Andric const MCPseudoProbeFuncDesc *MCPseudoProbeDecoder::getInlinerDescForProbe( 572349cc55cSDimitry Andric const MCDecodedPseudoProbe *Probe) const { 573349cc55cSDimitry Andric MCDecodedPseudoProbeInlineTree *InlinerNode = Probe->getInlineTreeNode(); 574349cc55cSDimitry Andric if (!InlinerNode->hasInlineSite()) 575349cc55cSDimitry Andric return nullptr; 576*81ad6265SDimitry Andric return getFuncDescForGUID(InlinerNode->Parent->Guid); 577349cc55cSDimitry Andric } 578