|
| 1 | +//===----------------------------------------------------------------------===// |
| 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 | +#ifndef LLDB_TARGET_SYNTHETICFRAMEPROVIDER_H |
| 10 | +#define LLDB_TARGET_SYNTHETICFRAMEPROVIDER_H |
| 11 | + |
| 12 | +#include "lldb/Core/PluginInterface.h" |
| 13 | +#include "lldb/Target/StackFrameList.h" |
| 14 | +#include "lldb/Target/ThreadSpec.h" |
| 15 | +#include "lldb/Utility/ScriptedMetadata.h" |
| 16 | +#include "lldb/Utility/Status.h" |
| 17 | +#include "lldb/lldb-forward.h" |
| 18 | +#include "llvm/Support/Error.h" |
| 19 | + |
| 20 | +#include <optional> |
| 21 | +#include <vector> |
| 22 | + |
| 23 | +namespace lldb_private { |
| 24 | + |
| 25 | +/// This struct contains the metadata needed to instantiate a frame provider |
| 26 | +/// and optional filters to control which threads it applies to. |
| 27 | +struct SyntheticFrameProviderDescriptor { |
| 28 | + /// Metadata for instantiating the provider (e.g. script class name and args). |
| 29 | + lldb::ScriptedMetadataSP scripted_metadata_sp; |
| 30 | + |
| 31 | + /// Optional list of thread specifications to which this provider applies. |
| 32 | + /// If empty, the provider applies to all threads. A thread matches if it |
| 33 | + /// satisfies ANY of the specs in this vector (OR logic). |
| 34 | + std::vector<ThreadSpec> thread_specs; |
| 35 | + |
| 36 | + SyntheticFrameProviderDescriptor() = default; |
| 37 | + |
| 38 | + SyntheticFrameProviderDescriptor(lldb::ScriptedMetadataSP metadata_sp) |
| 39 | + : scripted_metadata_sp(metadata_sp) {} |
| 40 | + |
| 41 | + SyntheticFrameProviderDescriptor(lldb::ScriptedMetadataSP metadata_sp, |
| 42 | + const std::vector<ThreadSpec> &specs) |
| 43 | + : scripted_metadata_sp(metadata_sp), thread_specs(specs) {} |
| 44 | + |
| 45 | + /// Get the name of this descriptor (the scripted class name). |
| 46 | + llvm::StringRef GetName() const { |
| 47 | + return scripted_metadata_sp ? scripted_metadata_sp->GetClassName() : ""; |
| 48 | + } |
| 49 | + |
| 50 | + /// Check if this descriptor applies to the given thread. |
| 51 | + bool AppliesToThread(Thread &thread) const { |
| 52 | + // If no thread specs specified, applies to all threads. |
| 53 | + if (thread_specs.empty()) |
| 54 | + return true; |
| 55 | + |
| 56 | + // Check if the thread matches any of the specs (OR logic). |
| 57 | + for (const auto &spec : thread_specs) { |
| 58 | + if (spec.ThreadPassesBasicTests(thread)) |
| 59 | + return true; |
| 60 | + } |
| 61 | + return false; |
| 62 | + } |
| 63 | + |
| 64 | + /// Check if this descriptor has valid metadata for script-based providers. |
| 65 | + bool IsValid() const { return scripted_metadata_sp != nullptr; } |
| 66 | + |
| 67 | + void Dump(Stream *s) const; |
| 68 | +}; |
| 69 | + |
| 70 | +/// Base class for all synthetic frame providers. |
| 71 | +/// |
| 72 | +/// Synthetic frame providers allow modifying or replacing the stack frames |
| 73 | +/// shown for a thread. This is useful for: |
| 74 | +/// - Providing frames for custom calling conventions or languages. |
| 75 | +/// - Reconstructing missing frames from crash dumps or core files. |
| 76 | +/// - Adding diagnostic or synthetic frames for debugging. |
| 77 | +/// - Visualizing state machines or async execution contexts. |
| 78 | +class SyntheticFrameProvider : public PluginInterface { |
| 79 | +public: |
| 80 | + /// Try to create a SyntheticFrameProvider instance for the given input |
| 81 | + /// frames and descriptor. |
| 82 | + /// |
| 83 | + /// This method iterates through all registered SyntheticFrameProvider |
| 84 | + /// plugins and returns the first one that can handle the given descriptor. |
| 85 | + /// |
| 86 | + /// \param[in] input_frames |
| 87 | + /// The input stack frame list that this provider will transform. |
| 88 | + /// This could be real unwound frames or output from another provider. |
| 89 | + /// |
| 90 | + /// \param[in] descriptor |
| 91 | + /// The descriptor containing metadata for the provider. |
| 92 | + /// |
| 93 | + /// \return |
| 94 | + /// A shared pointer to a SyntheticFrameProvider if one could be created, |
| 95 | + /// otherwise an \a llvm::Error. |
| 96 | + static llvm::Expected<lldb::SyntheticFrameProviderSP> |
| 97 | + CreateInstance(lldb::StackFrameListSP input_frames, |
| 98 | + const SyntheticFrameProviderDescriptor &descriptor); |
| 99 | + |
| 100 | + /// Try to create a SyntheticFrameProvider instance for the given input |
| 101 | + /// frames using a specific C++ plugin. |
| 102 | + /// |
| 103 | + /// This method directly invokes a specific SyntheticFrameProvider plugin |
| 104 | + /// by name, bypassing the descriptor-based plugin iteration. This is useful |
| 105 | + /// for C++ plugins that don't require scripted metadata. |
| 106 | + /// |
| 107 | + /// \param[in] input_frames |
| 108 | + /// The input stack frame list that this provider will transform. |
| 109 | + /// This could be real unwound frames or output from another provider. |
| 110 | + /// |
| 111 | + /// \param[in] plugin_name |
| 112 | + /// The name of the plugin to use for creating the provider. |
| 113 | + /// |
| 114 | + /// \param[in] thread_specs |
| 115 | + /// Optional list of thread specifications to which this provider applies. |
| 116 | + /// If empty, the provider applies to all threads. |
| 117 | + /// |
| 118 | + /// \return |
| 119 | + /// A shared pointer to a SyntheticFrameProvider if one could be created, |
| 120 | + /// otherwise an \a llvm::Error. |
| 121 | + static llvm::Expected<lldb::SyntheticFrameProviderSP> |
| 122 | + CreateInstance(lldb::StackFrameListSP input_frames, |
| 123 | + llvm::StringRef plugin_name, |
| 124 | + const std::vector<ThreadSpec> &thread_specs = {}); |
| 125 | + |
| 126 | + ~SyntheticFrameProvider() override; |
| 127 | + |
| 128 | + /// Get a single stack frame at the specified index. |
| 129 | + /// |
| 130 | + /// This method is called lazily - frames are only created when requested. |
| 131 | + /// The provider can access its input frames via GetInputFrames() if needed. |
| 132 | + /// |
| 133 | + /// \param[in] idx |
| 134 | + /// The index of the frame to create. |
| 135 | + /// |
| 136 | + /// \return |
| 137 | + /// An Expected containing the StackFrameSP if successful. Returns an |
| 138 | + /// error when the index is beyond the last frame to signal the end of |
| 139 | + /// the frame list. |
| 140 | + virtual llvm::Expected<lldb::StackFrameSP> GetFrameAtIndex(uint32_t idx) = 0; |
| 141 | + |
| 142 | + /// Get the thread associated with this provider. |
| 143 | + Thread &GetThread() { return m_input_frames->GetThread(); } |
| 144 | + |
| 145 | + /// Get the input frames that this provider transforms. |
| 146 | + lldb::StackFrameListSP GetInputFrames() const { return m_input_frames; } |
| 147 | + |
| 148 | +protected: |
| 149 | + SyntheticFrameProvider(lldb::StackFrameListSP input_frames); |
| 150 | + |
| 151 | + lldb::StackFrameListSP m_input_frames; |
| 152 | +}; |
| 153 | + |
| 154 | +} // namespace lldb_private |
| 155 | + |
| 156 | +#endif // LLDB_TARGET_SYNTHETICFRAMEPROVIDER_H |
0 commit comments