Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions lldb/examples/python/templates/scripted_frame_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,34 @@ def get_description(self):
"""
pass

@staticmethod
def get_priority():
"""Get the priority of this frame provider.

This static method is called to determine the evaluation order when
multiple frame providers could apply to the same thread. Lower numbers
indicate higher priority (like Unix nice values).

Returns:
int or None: Priority value where 0 is highest priority.
Return None for default priority (UINT32_MAX - lowest priority).

Example:

.. code-block:: python

@staticmethod
def get_priority():
# High priority - runs before most providers
return 10

@staticmethod
def get_priority():
# Default priority - runs last
return None
"""
return None # Default/lowest priority

def __init__(self, input_frames, args):
"""Construct a scripted frame provider.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,22 @@ class ScriptedFrameProviderInterface : public ScriptedInterface {
/// empty string if no description is available.
virtual std::string GetDescription(llvm::StringRef class_name) { return {}; }

/// Get the priority of this frame provider.
///
/// This is called by the descriptor to fetch the priority from the
/// scripted implementation. Implementations should call a static method
/// on the scripting class to retrieve the priority. Lower numbers indicate
/// higher priority (like Unix nice values).
///
/// \param class_name The name of the scripting class implementing the
/// provider.
///
/// \return Priority value where 0 is highest priority, or std::nullopt for
/// default priority (UINT32_MAX - lowest priority).
virtual std::optional<uint32_t> GetPriority(llvm::StringRef class_name) {
return std::nullopt;
}

virtual StructuredData::ObjectSP GetFrameAtIndex(uint32_t index) {
return {};
}
Expand Down
21 changes: 21 additions & 0 deletions lldb/include/lldb/Target/SyntheticFrameProvider.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,16 @@ struct ScriptedFrameProviderDescriptor {
/// empty string if no description is available.
std::string GetDescription() const;

/// Get the priority of this frame provider.
///
/// Priority determines the order in which providers are evaluated when
/// multiple providers could apply to the same thread. Lower numbers indicate
/// higher priority (like Unix nice values).
///
/// \return Priority value where 0 is highest priority, or std::nullopt for
/// default priority (UINT32_MAX - lowest priority).
std::optional<uint32_t> GetPriority() const;

/// Check if this descriptor applies to the given thread.
bool AppliesToThread(Thread &thread) const {
// If no thread specs specified, applies to all threads.
Expand Down Expand Up @@ -143,6 +153,17 @@ class SyntheticFrameProvider : public PluginInterface {

virtual std::string GetDescription() const = 0;

/// Get the priority of this frame provider.
///
/// Priority determines the order in which providers are evaluated when
/// multiple providers could apply to the same thread. Lower numbers indicate
/// higher priority (like Unix nice values).
///
/// \return
/// Priority value where 0 is highest priority, or std::nullopt for
/// default priority (UINT32_MAX - lowest priority).
virtual std::optional<uint32_t> GetPriority() const { return std::nullopt; }

/// Get a single stack frame at the specified index.
///
/// This method is called lazily - frames are only created when requested.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,24 @@ std::string ScriptedFrameProviderPythonInterface::GetDescription(
return obj->GetStringValue().str();
}

std::optional<uint32_t>
ScriptedFrameProviderPythonInterface::GetPriority(llvm::StringRef class_name) {
Status error;
StructuredData::ObjectSP obj =
CallStaticMethod(class_name, "get_priority", error);

if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj,
error))
return std::nullopt;

// Try to extract as unsigned integer. Return nullopt if Python returned None
// or if extraction fails.
if (StructuredData::UnsignedInteger *int_obj = obj->GetAsUnsignedInteger())
return static_cast<uint32_t>(int_obj->GetValue());

return std::nullopt;
}

StructuredData::ObjectSP
ScriptedFrameProviderPythonInterface::GetFrameAtIndex(uint32_t index) {
Status error;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ class ScriptedFrameProviderPythonInterface

std::string GetDescription(llvm::StringRef class_name) override;

std::optional<uint32_t> GetPriority(llvm::StringRef class_name) override;

StructuredData::ObjectSP GetFrameAtIndex(uint32_t index) override;

static void Initialize();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,13 @@ std::string ScriptedFrameProvider::GetDescription() const {
return m_interface_sp->GetDescription(m_descriptor.GetName());
}

std::optional<uint32_t> ScriptedFrameProvider::GetPriority() const {
if (!m_interface_sp)
return std::nullopt;

return m_interface_sp->GetPriority(m_descriptor.GetName());
}

llvm::Expected<StackFrameSP>
ScriptedFrameProvider::GetFrameAtIndex(uint32_t idx) {
if (!m_interface_sp)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ class ScriptedFrameProvider : public SyntheticFrameProvider {

std::string GetDescription() const override;

std::optional<uint32_t> GetPriority() const override;

/// Get a single stack frame at the specified index.
llvm::Expected<lldb::StackFrameSP> GetFrameAtIndex(uint32_t idx) override;

Expand Down
14 changes: 14 additions & 0 deletions lldb/source/Target/SyntheticFrameProvider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,13 @@ void ScriptedFrameProviderDescriptor::Dump(Stream *s) const {
if (!description.empty())
s->Printf(" Description: %s\n", description.c_str());

// Show priority information.
std::optional<uint32_t> priority = GetPriority();
if (priority.has_value())
s->Printf(" Priority: %u\n", *priority);
else
s->PutCString(" Priority: Default (no priority specified)\n");

// Show thread filter information.
if (thread_specs.empty()) {
s->PutCString(" Thread Filter: (applies to all threads)\n");
Expand Down Expand Up @@ -62,6 +69,13 @@ std::string ScriptedFrameProviderDescriptor::GetDescription() const {
return {};
}

std::optional<uint32_t> ScriptedFrameProviderDescriptor::GetPriority() const {
// If we have an interface, call get_priority() to fetch it.
if (interface_sp && scripted_metadata_sp)
return interface_sp->GetPriority(scripted_metadata_sp->GetClassName());
return std::nullopt;
}

llvm::Expected<SyntheticFrameProviderSP> SyntheticFrameProvider::CreateInstance(
StackFrameListSP input_frames,
const ScriptedFrameProviderDescriptor &descriptor) {
Expand Down
31 changes: 24 additions & 7 deletions lldb/source/Target/Thread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1455,16 +1455,33 @@ StackFrameListSP Thread::GetStackFrameList() {
Target &target = process_sp->GetTarget();
const auto &descriptors = target.GetScriptedFrameProviderDescriptors();

// Find first descriptor that applies to this thread.
// Collect all descriptors that apply to this thread.
std::vector<const ScriptedFrameProviderDescriptor *>
applicable_descriptors;
for (const auto &entry : descriptors) {
const ScriptedFrameProviderDescriptor &descriptor = entry.second;
if (descriptor.IsValid() && descriptor.AppliesToThread(*this)) {
if (llvm::Error error = LoadScriptedFrameProvider(descriptor)) {
LLDB_LOG_ERROR(GetLog(LLDBLog::Thread), std::move(error),
"Failed to load scripted frame provider: {0}");
}
break; // Use first matching descriptor (success or failure).
if (descriptor.IsValid() && descriptor.AppliesToThread(*this))
applicable_descriptors.push_back(&descriptor);
}

// Sort by priority (lower number = higher priority).
llvm::sort(applicable_descriptors,
[](const ScriptedFrameProviderDescriptor *a,
const ScriptedFrameProviderDescriptor *b) {
// nullopt (no priority) sorts last (UINT32_MAX).
uint32_t priority_a = a->GetPriority().value_or(UINT32_MAX);
uint32_t priority_b = b->GetPriority().value_or(UINT32_MAX);
return priority_a < priority_b;
});

// Load the highest priority provider that successfully instantiates.
for (const auto *descriptor : applicable_descriptors) {
if (llvm::Error error = LoadScriptedFrameProvider(*descriptor)) {
LLDB_LOG_ERROR(GetLog(LLDBLog::Thread), std::move(error),
"Failed to load scripted frame provider: {0}");
continue; // Try next provider if this one fails.
}
break; // Successfully loaded provider.
}
}
}
Expand Down
Loading