1 //===- lib/MC/MCPseudoProbe.cpp - Pseudo probe encoding support ----------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "llvm/MC/MCPseudoProbe.h" 10 #include "llvm/ADT/STLExtras.h" 11 #include "llvm/MC/MCAsmInfo.h" 12 #include "llvm/MC/MCContext.h" 13 #include "llvm/MC/MCExpr.h" 14 #include "llvm/MC/MCFragment.h" 15 #include "llvm/MC/MCObjectFileInfo.h" 16 #include "llvm/MC/MCObjectStreamer.h" 17 #include "llvm/MC/MCSymbol.h" 18 #include "llvm/Support/Endian.h" 19 #include "llvm/Support/LEB128.h" 20 #include "llvm/Support/MD5.h" 21 #include "llvm/Support/raw_ostream.h" 22 #include <algorithm> 23 #include <cassert> 24 #include <limits> 25 #include <memory> 26 #include <sstream> 27 #include <vector> 28 29 #define DEBUG_TYPE "mcpseudoprobe" 30 31 using namespace llvm; 32 using namespace support; 33 34 #ifndef NDEBUG 35 int MCPseudoProbeTable::DdgPrintIndent = 0; 36 #endif 37 38 static const MCExpr *buildSymbolDiff(MCObjectStreamer *MCOS, const MCSymbol *A, 39 const MCSymbol *B) { 40 MCContext &Context = MCOS->getContext(); 41 MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None; 42 const MCExpr *ARef = MCSymbolRefExpr::create(A, Variant, Context); 43 const MCExpr *BRef = MCSymbolRefExpr::create(B, Variant, Context); 44 const MCExpr *AddrDelta = 45 MCBinaryExpr::create(MCBinaryExpr::Sub, ARef, BRef, Context); 46 return AddrDelta; 47 } 48 49 void MCPseudoProbe::emit(MCObjectStreamer *MCOS, 50 const MCPseudoProbe *LastProbe) const { 51 bool IsSentinel = isSentinelProbe(getAttributes()); 52 assert((LastProbe || IsSentinel) && 53 "Last probe should not be null for non-sentinel probes"); 54 55 // Emit Index 56 MCOS->emitULEB128IntValue(Index); 57 // Emit Type and the flag: 58 // Type (bit 0 to 3), with bit 4 to 6 for attributes. 59 // Flag (bit 7, 0 - code address, 1 - address delta). This indicates whether 60 // the following field is a symbolic code address or an address delta. 61 assert(Type <= 0xF && "Probe type too big to encode, exceeding 15"); 62 assert(Attributes <= 0x7 && 63 "Probe attributes too big to encode, exceeding 7"); 64 uint8_t PackedType = Type | (Attributes << 4); 65 uint8_t Flag = 66 !IsSentinel ? ((int8_t)MCPseudoProbeFlag::AddressDelta << 7) : 0; 67 MCOS->emitInt8(Flag | PackedType); 68 69 if (!IsSentinel) { 70 // Emit the delta between the address label and LastProbe. 71 const MCExpr *AddrDelta = 72 buildSymbolDiff(MCOS, Label, LastProbe->getLabel()); 73 int64_t Delta; 74 if (AddrDelta->evaluateAsAbsolute(Delta, MCOS->getAssemblerPtr())) { 75 MCOS->emitSLEB128IntValue(Delta); 76 } else { 77 MCOS->insert(new MCPseudoProbeAddrFragment(AddrDelta)); 78 } 79 } else { 80 // Emit the GUID of the split function that the sentinel probe represents. 81 MCOS->emitInt64(Guid); 82 } 83 84 LLVM_DEBUG({ 85 dbgs().indent(MCPseudoProbeTable::DdgPrintIndent); 86 dbgs() << "Probe: " << Index << "\n"; 87 }); 88 } 89 90 void MCPseudoProbeInlineTree::addPseudoProbe( 91 const MCPseudoProbe &Probe, const MCPseudoProbeInlineStack &InlineStack) { 92 // The function should not be called on the root. 93 assert(isRoot() && "Should only be called on root"); 94 95 // When it comes here, the input look like: 96 // Probe: GUID of C, ... 97 // InlineStack: [88, A], [66, B] 98 // which means, Function A inlines function B at call site with a probe id of 99 // 88, and B inlines C at probe 66. The tri-tree expects a tree path like {[0, 100 // A], [88, B], [66, C]} to locate the tree node where the probe should be 101 // added. Note that the edge [0, A] means A is the top-level function we are 102 // emitting probes for. 103 104 // Make a [0, A] edge. 105 // An empty inline stack means the function that the probe originates from 106 // is a top-level function. 107 InlineSite Top; 108 if (InlineStack.empty()) { 109 Top = InlineSite(Probe.getGuid(), 0); 110 } else { 111 Top = InlineSite(std::get<0>(InlineStack.front()), 0); 112 } 113 114 auto *Cur = getOrAddNode(Top); 115 116 // Make interior edges by walking the inline stack. Once it's done, Cur should 117 // point to the node that the probe originates from. 118 if (!InlineStack.empty()) { 119 auto Iter = InlineStack.begin(); 120 auto Index = std::get<1>(*Iter); 121 Iter++; 122 for (; Iter != InlineStack.end(); Iter++) { 123 // Make an edge by using the previous probe id and current GUID. 124 Cur = Cur->getOrAddNode(InlineSite(std::get<0>(*Iter), Index)); 125 Index = std::get<1>(*Iter); 126 } 127 Cur = Cur->getOrAddNode(InlineSite(Probe.getGuid(), Index)); 128 } 129 130 Cur->Probes.push_back(Probe); 131 } 132 133 void MCPseudoProbeInlineTree::emit(MCObjectStreamer *MCOS, 134 const MCPseudoProbe *&LastProbe) { 135 LLVM_DEBUG({ 136 dbgs().indent(MCPseudoProbeTable::DdgPrintIndent); 137 dbgs() << "Group [\n"; 138 MCPseudoProbeTable::DdgPrintIndent += 2; 139 }); 140 assert(!isRoot() && "Root should be handled seperately"); 141 142 // Emit probes grouped by GUID. 143 LLVM_DEBUG({ 144 dbgs().indent(MCPseudoProbeTable::DdgPrintIndent); 145 dbgs() << "GUID: " << Guid << "\n"; 146 }); 147 // Emit Guid 148 MCOS->emitInt64(Guid); 149 // Emit number of probes in this node, including a sentinel probe for 150 // top-level functions if needed. 151 bool NeedSentinel = false; 152 if (Parent->isRoot()) { 153 assert(isSentinelProbe(LastProbe->getAttributes()) && 154 "Starting probe of a top-level function should be a sentinel probe"); 155 // The main body of a split function doesn't need a sentinel probe. 156 if (LastProbe->getGuid() != Guid) 157 NeedSentinel = true; 158 } 159 160 MCOS->emitULEB128IntValue(Probes.size() + NeedSentinel); 161 // Emit number of direct inlinees 162 MCOS->emitULEB128IntValue(Children.size()); 163 // Emit sentinel probe for top-level functions 164 if (NeedSentinel) 165 LastProbe->emit(MCOS, nullptr); 166 167 // Emit probes in this group 168 for (const auto &Probe : Probes) { 169 Probe.emit(MCOS, LastProbe); 170 LastProbe = &Probe; 171 } 172 173 // Emit sorted descendant. InlineSite is unique for each pair, so there will 174 // be no ordering of Inlinee based on MCPseudoProbeInlineTree* 175 using InlineeType = std::pair<InlineSite, MCPseudoProbeInlineTree *>; 176 auto Comparer = [](const InlineeType &A, const InlineeType &B) { 177 return A.first < B.first; 178 }; 179 std::vector<InlineeType> Inlinees; 180 for (const auto &Child : Children) 181 Inlinees.emplace_back(Child.first, Child.second.get()); 182 std::sort(Inlinees.begin(), Inlinees.end(), Comparer); 183 184 for (const auto &Inlinee : Inlinees) { 185 // Emit probe index 186 MCOS->emitULEB128IntValue(std::get<1>(Inlinee.first)); 187 LLVM_DEBUG({ 188 dbgs().indent(MCPseudoProbeTable::DdgPrintIndent); 189 dbgs() << "InlineSite: " << std::get<1>(Inlinee.first) << "\n"; 190 }); 191 // Emit the group 192 Inlinee.second->emit(MCOS, LastProbe); 193 } 194 195 LLVM_DEBUG({ 196 MCPseudoProbeTable::DdgPrintIndent -= 2; 197 dbgs().indent(MCPseudoProbeTable::DdgPrintIndent); 198 dbgs() << "]\n"; 199 }); 200 } 201 202 void MCPseudoProbeSections::emit(MCObjectStreamer *MCOS) { 203 MCContext &Ctx = MCOS->getContext(); 204 for (auto &ProbeSec : MCProbeDivisions) { 205 const auto *FuncSym = ProbeSec.first; 206 const auto &Root = ProbeSec.second; 207 if (auto *S = Ctx.getObjectFileInfo()->getPseudoProbeSection( 208 FuncSym->getSection())) { 209 // Switch to the .pseudoprobe section or a comdat group. 210 MCOS->switchSection(S); 211 // Emit probes grouped by GUID. 212 // Emit sorted descendant. InlineSite is unique for each pair, so there 213 // will be no ordering of Inlinee based on MCPseudoProbeInlineTree* 214 using InlineeType = std::pair<InlineSite, MCPseudoProbeInlineTree *>; 215 auto Comparer = [](const InlineeType &A, const InlineeType &B) { 216 return A.first < B.first; 217 }; 218 std::vector<InlineeType> Inlinees; 219 for (const auto &Child : Root.getChildren()) 220 Inlinees.emplace_back(Child.first, Child.second.get()); 221 std::sort(Inlinees.begin(), Inlinees.end(), Comparer); 222 223 for (const auto &Inlinee : Inlinees) { 224 // Emit the group guarded by a sentinel probe. 225 MCPseudoProbe SentinelProbe(const_cast<MCSymbol *>(FuncSym), 226 MD5Hash(FuncSym->getName()), 227 (uint32_t)PseudoProbeReservedId::Invalid, 228 (uint32_t)PseudoProbeType::Block, 229 (uint32_t)PseudoProbeAttributes::Sentinel); 230 const MCPseudoProbe *Probe = &SentinelProbe; 231 Inlinee.second->emit(MCOS, Probe); 232 } 233 } 234 } 235 } 236 237 // 238 // This emits the pseudo probe tables. 239 // 240 void MCPseudoProbeTable::emit(MCObjectStreamer *MCOS) { 241 MCContext &Ctx = MCOS->getContext(); 242 auto &ProbeTable = Ctx.getMCPseudoProbeTable(); 243 244 // Bail out early so we don't switch to the pseudo_probe section needlessly 245 // and in doing so create an unnecessary (if empty) section. 246 auto &ProbeSections = ProbeTable.getProbeSections(); 247 if (ProbeSections.empty()) 248 return; 249 250 LLVM_DEBUG(MCPseudoProbeTable::DdgPrintIndent = 0); 251 252 // Put out the probe. 253 ProbeSections.emit(MCOS); 254 } 255 256 static StringRef getProbeFNameForGUID(const GUIDProbeFunctionMap &GUID2FuncMAP, 257 uint64_t GUID) { 258 auto It = GUID2FuncMAP.find(GUID); 259 assert(It != GUID2FuncMAP.end() && 260 "Probe function must exist for a valid GUID"); 261 return It->second.FuncName; 262 } 263 264 void MCPseudoProbeFuncDesc::print(raw_ostream &OS) { 265 OS << "GUID: " << FuncGUID << " Name: " << FuncName << "\n"; 266 OS << "Hash: " << FuncHash << "\n"; 267 } 268 269 void MCDecodedPseudoProbe::getInlineContext( 270 SmallVectorImpl<MCPseduoProbeFrameLocation> &ContextStack, 271 const GUIDProbeFunctionMap &GUID2FuncMAP) const { 272 uint32_t Begin = ContextStack.size(); 273 MCDecodedPseudoProbeInlineTree *Cur = InlineTree; 274 // It will add the string of each node's inline site during iteration. 275 // Note that it won't include the probe's belonging function(leaf location) 276 while (Cur->hasInlineSite()) { 277 StringRef FuncName = getProbeFNameForGUID(GUID2FuncMAP, Cur->Parent->Guid); 278 ContextStack.emplace_back( 279 MCPseduoProbeFrameLocation(FuncName, std::get<1>(Cur->ISite))); 280 Cur = static_cast<MCDecodedPseudoProbeInlineTree *>(Cur->Parent); 281 } 282 // Make the ContextStack in caller-callee order 283 std::reverse(ContextStack.begin() + Begin, ContextStack.end()); 284 } 285 286 std::string MCDecodedPseudoProbe::getInlineContextStr( 287 const GUIDProbeFunctionMap &GUID2FuncMAP) const { 288 std::ostringstream OContextStr; 289 SmallVector<MCPseduoProbeFrameLocation, 16> ContextStack; 290 getInlineContext(ContextStack, GUID2FuncMAP); 291 for (auto &Cxt : ContextStack) { 292 if (OContextStr.str().size()) 293 OContextStr << " @ "; 294 OContextStr << Cxt.first.str() << ":" << Cxt.second; 295 } 296 return OContextStr.str(); 297 } 298 299 static const char *PseudoProbeTypeStr[3] = {"Block", "IndirectCall", 300 "DirectCall"}; 301 302 void MCDecodedPseudoProbe::print(raw_ostream &OS, 303 const GUIDProbeFunctionMap &GUID2FuncMAP, 304 bool ShowName) const { 305 OS << "FUNC: "; 306 if (ShowName) { 307 StringRef FuncName = getProbeFNameForGUID(GUID2FuncMAP, Guid); 308 OS << FuncName.str() << " "; 309 } else { 310 OS << Guid << " "; 311 } 312 OS << "Index: " << Index << " "; 313 OS << "Type: " << PseudoProbeTypeStr[static_cast<uint8_t>(Type)] << " "; 314 std::string InlineContextStr = getInlineContextStr(GUID2FuncMAP); 315 if (InlineContextStr.size()) { 316 OS << "Inlined: @ "; 317 OS << InlineContextStr; 318 } 319 OS << "\n"; 320 } 321 322 template <typename T> ErrorOr<T> MCPseudoProbeDecoder::readUnencodedNumber() { 323 if (Data + sizeof(T) > End) { 324 return std::error_code(); 325 } 326 T Val = endian::readNext<T, little, unaligned>(Data); 327 return ErrorOr<T>(Val); 328 } 329 330 template <typename T> ErrorOr<T> MCPseudoProbeDecoder::readUnsignedNumber() { 331 unsigned NumBytesRead = 0; 332 uint64_t Val = decodeULEB128(Data, &NumBytesRead); 333 if (Val > std::numeric_limits<T>::max() || (Data + NumBytesRead > End)) { 334 return std::error_code(); 335 } 336 Data += NumBytesRead; 337 return ErrorOr<T>(static_cast<T>(Val)); 338 } 339 340 template <typename T> ErrorOr<T> MCPseudoProbeDecoder::readSignedNumber() { 341 unsigned NumBytesRead = 0; 342 int64_t Val = decodeSLEB128(Data, &NumBytesRead); 343 if (Val > std::numeric_limits<T>::max() || (Data + NumBytesRead > End)) { 344 return std::error_code(); 345 } 346 Data += NumBytesRead; 347 return ErrorOr<T>(static_cast<T>(Val)); 348 } 349 350 ErrorOr<StringRef> MCPseudoProbeDecoder::readString(uint32_t Size) { 351 StringRef Str(reinterpret_cast<const char *>(Data), Size); 352 if (Data + Size > End) { 353 return std::error_code(); 354 } 355 Data += Size; 356 return ErrorOr<StringRef>(Str); 357 } 358 359 bool MCPseudoProbeDecoder::buildGUID2FuncDescMap(const uint8_t *Start, 360 std::size_t Size) { 361 // The pseudo_probe_desc section has a format like: 362 // .section .pseudo_probe_desc,"",@progbits 363 // .quad -5182264717993193164 // GUID 364 // .quad 4294967295 // Hash 365 // .uleb 3 // Name size 366 // .ascii "foo" // Name 367 // .quad -2624081020897602054 368 // .quad 174696971957 369 // .uleb 34 370 // .ascii "main" 371 372 Data = Start; 373 End = Data + Size; 374 375 while (Data < End) { 376 auto ErrorOrGUID = readUnencodedNumber<uint64_t>(); 377 if (!ErrorOrGUID) 378 return false; 379 380 auto ErrorOrHash = readUnencodedNumber<uint64_t>(); 381 if (!ErrorOrHash) 382 return false; 383 384 auto ErrorOrNameSize = readUnsignedNumber<uint32_t>(); 385 if (!ErrorOrNameSize) 386 return false; 387 uint32_t NameSize = std::move(*ErrorOrNameSize); 388 389 auto ErrorOrName = readString(NameSize); 390 if (!ErrorOrName) 391 return false; 392 393 uint64_t GUID = std::move(*ErrorOrGUID); 394 uint64_t Hash = std::move(*ErrorOrHash); 395 StringRef Name = std::move(*ErrorOrName); 396 397 // Initialize PseudoProbeFuncDesc and populate it into GUID2FuncDescMap 398 GUID2FuncDescMap.emplace(GUID, MCPseudoProbeFuncDesc(GUID, Hash, Name)); 399 } 400 assert(Data == End && "Have unprocessed data in pseudo_probe_desc section"); 401 return true; 402 } 403 404 bool MCPseudoProbeDecoder::buildAddress2ProbeMap( 405 MCDecodedPseudoProbeInlineTree *Cur, uint64_t &LastAddr, 406 const Uint64Set &GuidFilter, const Uint64Map &FuncStartAddrs) { 407 // The pseudo_probe section encodes an inline forest and each tree has a 408 // format defined in MCPseudoProbe.h 409 410 uint32_t Index = 0; 411 bool IsTopLevelFunc = Cur == &DummyInlineRoot; 412 if (IsTopLevelFunc) { 413 // Use a sequential id for top level inliner. 414 Index = Cur->getChildren().size(); 415 } else { 416 // Read inline site for inlinees 417 auto ErrorOrIndex = readUnsignedNumber<uint32_t>(); 418 if (!ErrorOrIndex) 419 return false; 420 Index = std::move(*ErrorOrIndex); 421 } 422 423 // Read guid 424 auto ErrorOrCurGuid = readUnencodedNumber<uint64_t>(); 425 if (!ErrorOrCurGuid) 426 return false; 427 uint64_t Guid = std::move(*ErrorOrCurGuid); 428 429 // Decide if top-level node should be disgarded. 430 if (IsTopLevelFunc && !GuidFilter.empty() && !GuidFilter.count(Guid)) 431 Cur = nullptr; 432 433 // If the incoming node is null, all its children nodes should be disgarded. 434 if (Cur) { 435 // Switch/add to a new tree node(inlinee) 436 Cur = Cur->getOrAddNode(std::make_tuple(Guid, Index)); 437 Cur->Guid = Guid; 438 if (IsTopLevelFunc && !EncodingIsAddrBased) { 439 if (auto V = FuncStartAddrs.lookup(Guid)) 440 LastAddr = V; 441 } 442 } 443 444 // Read number of probes in the current node. 445 auto ErrorOrNodeCount = readUnsignedNumber<uint32_t>(); 446 if (!ErrorOrNodeCount) 447 return false; 448 uint32_t NodeCount = std::move(*ErrorOrNodeCount); 449 // Read number of direct inlinees 450 auto ErrorOrCurChildrenToProcess = readUnsignedNumber<uint32_t>(); 451 if (!ErrorOrCurChildrenToProcess) 452 return false; 453 // Read all probes in this node 454 for (std::size_t I = 0; I < NodeCount; I++) { 455 // Read index 456 auto ErrorOrIndex = readUnsignedNumber<uint32_t>(); 457 if (!ErrorOrIndex) 458 return false; 459 uint32_t Index = std::move(*ErrorOrIndex); 460 // Read type | flag. 461 auto ErrorOrValue = readUnencodedNumber<uint8_t>(); 462 if (!ErrorOrValue) 463 return false; 464 uint8_t Value = std::move(*ErrorOrValue); 465 uint8_t Kind = Value & 0xf; 466 uint8_t Attr = (Value & 0x70) >> 4; 467 // Read address 468 uint64_t Addr = 0; 469 if (Value & 0x80) { 470 auto ErrorOrOffset = readSignedNumber<int64_t>(); 471 if (!ErrorOrOffset) 472 return false; 473 int64_t Offset = std::move(*ErrorOrOffset); 474 Addr = LastAddr + Offset; 475 } else { 476 auto ErrorOrAddr = readUnencodedNumber<int64_t>(); 477 if (!ErrorOrAddr) 478 return false; 479 Addr = std::move(*ErrorOrAddr); 480 if (isSentinelProbe(Attr)) { 481 // For sentinel probe, the addr field actually stores the GUID of the 482 // split function. Convert it to the real address. 483 if (auto V = FuncStartAddrs.lookup(Addr)) 484 Addr = V; 485 } else { 486 // For now we assume all probe encoding should be either based on 487 // leading probe address or function start address. 488 // The scheme is for downwards compatibility. 489 // TODO: retire this scheme once compatibility is no longer an issue. 490 EncodingIsAddrBased = true; 491 } 492 } 493 494 if (Cur && !isSentinelProbe(Attr)) { 495 // Populate Address2ProbesMap 496 auto &Probes = Address2ProbesMap[Addr]; 497 Probes.emplace_back(Addr, Cur->Guid, Index, PseudoProbeType(Kind), Attr, 498 Cur); 499 Cur->addProbes(&Probes.back()); 500 } 501 LastAddr = Addr; 502 } 503 504 uint32_t ChildrenToProcess = std::move(*ErrorOrCurChildrenToProcess); 505 for (uint32_t I = 0; I < ChildrenToProcess; I++) { 506 buildAddress2ProbeMap(Cur, LastAddr, GuidFilter, FuncStartAddrs); 507 } 508 509 return true; 510 } 511 512 bool MCPseudoProbeDecoder::buildAddress2ProbeMap( 513 const uint8_t *Start, std::size_t Size, const Uint64Set &GuidFilter, 514 const Uint64Map &FuncStartAddrs) { 515 Data = Start; 516 End = Data + Size; 517 uint64_t LastAddr = 0; 518 while (Data < End) 519 buildAddress2ProbeMap(&DummyInlineRoot, LastAddr, GuidFilter, 520 FuncStartAddrs); 521 assert(Data == End && "Have unprocessed data in pseudo_probe section"); 522 return true; 523 } 524 525 void MCPseudoProbeDecoder::printGUID2FuncDescMap(raw_ostream &OS) { 526 OS << "Pseudo Probe Desc:\n"; 527 // Make the output deterministic 528 std::map<uint64_t, MCPseudoProbeFuncDesc> OrderedMap(GUID2FuncDescMap.begin(), 529 GUID2FuncDescMap.end()); 530 for (auto &I : OrderedMap) { 531 I.second.print(OS); 532 } 533 } 534 535 void MCPseudoProbeDecoder::printProbeForAddress(raw_ostream &OS, 536 uint64_t Address) { 537 auto It = Address2ProbesMap.find(Address); 538 if (It != Address2ProbesMap.end()) { 539 for (auto &Probe : It->second) { 540 OS << " [Probe]:\t"; 541 Probe.print(OS, GUID2FuncDescMap, true); 542 } 543 } 544 } 545 546 void MCPseudoProbeDecoder::printProbesForAllAddresses(raw_ostream &OS) { 547 std::vector<uint64_t> Addresses; 548 for (auto Entry : Address2ProbesMap) 549 Addresses.push_back(Entry.first); 550 llvm::sort(Addresses); 551 for (auto K : Addresses) { 552 OS << "Address:\t"; 553 OS << K; 554 OS << "\n"; 555 printProbeForAddress(OS, K); 556 } 557 } 558 559 const MCDecodedPseudoProbe * 560 MCPseudoProbeDecoder::getCallProbeForAddr(uint64_t Address) const { 561 auto It = Address2ProbesMap.find(Address); 562 if (It == Address2ProbesMap.end()) 563 return nullptr; 564 const auto &Probes = It->second; 565 566 const MCDecodedPseudoProbe *CallProbe = nullptr; 567 for (const auto &Probe : Probes) { 568 if (Probe.isCall()) { 569 assert(!CallProbe && 570 "There should be only one call probe corresponding to address " 571 "which is a callsite."); 572 CallProbe = &Probe; 573 } 574 } 575 return CallProbe; 576 } 577 578 const MCPseudoProbeFuncDesc * 579 MCPseudoProbeDecoder::getFuncDescForGUID(uint64_t GUID) const { 580 auto It = GUID2FuncDescMap.find(GUID); 581 assert(It != GUID2FuncDescMap.end() && "Function descriptor doesn't exist"); 582 return &It->second; 583 } 584 585 void MCPseudoProbeDecoder::getInlineContextForProbe( 586 const MCDecodedPseudoProbe *Probe, 587 SmallVectorImpl<MCPseduoProbeFrameLocation> &InlineContextStack, 588 bool IncludeLeaf) const { 589 Probe->getInlineContext(InlineContextStack, GUID2FuncDescMap); 590 if (!IncludeLeaf) 591 return; 592 // Note that the context from probe doesn't include leaf frame, 593 // hence we need to retrieve and prepend leaf if requested. 594 const auto *FuncDesc = getFuncDescForGUID(Probe->getGuid()); 595 InlineContextStack.emplace_back( 596 MCPseduoProbeFrameLocation(FuncDesc->FuncName, Probe->getIndex())); 597 } 598 599 const MCPseudoProbeFuncDesc *MCPseudoProbeDecoder::getInlinerDescForProbe( 600 const MCDecodedPseudoProbe *Probe) const { 601 MCDecodedPseudoProbeInlineTree *InlinerNode = Probe->getInlineTreeNode(); 602 if (!InlinerNode->hasInlineSite()) 603 return nullptr; 604 return getFuncDescForGUID(InlinerNode->Parent->Guid); 605 } 606