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