-
Notifications
You must be signed in to change notification settings - Fork 15.1k
[lldb/Interpreter] Implement ScriptedFrameProvider{,Python}Interface #166662
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
medismailben
merged 1 commit into
llvm:main
from
medismailben:scripted-frame-provider-interface
Nov 6, 2025
+346
−1
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
113 changes: 113 additions & 0 deletions
113
lldb/examples/python/templates/scripted_frame_provider.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,113 @@ | ||
| from abc import ABCMeta, abstractmethod | ||
|
|
||
| import lldb | ||
|
|
||
|
|
||
| class ScriptedFrameProvider(metaclass=ABCMeta): | ||
| """ | ||
| The base class for a scripted frame provider. | ||
|
|
||
| A scripted frame provider allows you to provide custom stack frames for a | ||
| thread, which can be used to augment or replace the standard unwinding | ||
| mechanism. This is useful for: | ||
|
|
||
| - Providing frames for custom calling conventions or languages | ||
| - Reconstructing missing frames from crash dumps or core files | ||
| - Adding diagnostic or synthetic frames for debugging | ||
| - Visualizing state machines or async execution contexts | ||
|
|
||
| Most of the base class methods are `@abstractmethod` that need to be | ||
| overwritten by the inheriting class. | ||
|
|
||
| Example usage: | ||
|
|
||
| .. code-block:: python | ||
|
|
||
| # Attach a frame provider to a thread | ||
| thread = process.GetSelectedThread() | ||
| error = thread.SetScriptedFrameProvider( | ||
| "my_module.MyFrameProvider", | ||
| lldb.SBStructuredData() | ||
| ) | ||
| """ | ||
|
|
||
| @abstractmethod | ||
| def __init__(self, input_frames, args): | ||
| """Construct a scripted frame provider. | ||
|
|
||
| Args: | ||
| input_frames (lldb.SBFrameList): The frame list to use as input. | ||
| This allows you to access frames by index. The frames are | ||
| materialized lazily as you access them. | ||
| args (lldb.SBStructuredData): A Dictionary holding arbitrary | ||
| key/value pairs used by the scripted frame provider. | ||
| """ | ||
| self.input_frames = None | ||
| self.args = None | ||
| self.thread = None | ||
| self.target = None | ||
| self.process = None | ||
|
|
||
| if isinstance(input_frames, lldb.SBFrameList) and input_frames.IsValid(): | ||
| self.input_frames = input_frames | ||
| self.thread = input_frames.GetThread() | ||
| if self.thread and self.thread.IsValid(): | ||
| self.process = self.thread.GetProcess() | ||
| if self.process and self.process.IsValid(): | ||
| self.target = self.process.GetTarget() | ||
|
|
||
| if isinstance(args, lldb.SBStructuredData) and args.IsValid(): | ||
| self.args = args | ||
|
|
||
| @abstractmethod | ||
| def get_frame_at_index(self, index): | ||
| """Get a single stack frame at the given index. | ||
|
|
||
| This method is called lazily when a specific frame is needed in the | ||
| thread's backtrace (e.g., via the 'bt' command). Each frame is | ||
| requested individually as needed. | ||
|
|
||
| Args: | ||
| index (int): The frame index to retrieve (0 for youngest/top frame). | ||
|
|
||
| Returns: | ||
| Dict or None: A frame dictionary describing the stack frame, or None | ||
| if no frame exists at this index. The dictionary should contain: | ||
|
|
||
| Required fields: | ||
| - idx (int): The synthetic frame index (0 for youngest/top frame) | ||
| - pc (int): The program counter address for the synthetic frame | ||
|
|
||
| Alternatively, you can return: | ||
| - A ScriptedFrame object for full control over frame behavior | ||
| - An integer representing an input frame index to reuse | ||
| - None to indicate no more frames exist | ||
|
|
||
| Example: | ||
|
|
||
| .. code-block:: python | ||
|
|
||
| def get_frame_at_index(self, index): | ||
| # Return None when there are no more frames | ||
| if index >= self.total_frames: | ||
| return None | ||
|
|
||
| # Re-use an input frame by returning its index | ||
| if self.should_use_input_frame(index): | ||
| return index # Returns input frame at this index | ||
|
|
||
| # Or create a custom frame dictionary | ||
| if index == 0: | ||
| return { | ||
| "idx": 0, | ||
| "pc": 0x100001234, | ||
| } | ||
|
|
||
| return None | ||
|
|
||
| Note: | ||
| The frames are indexed from 0 (youngest/top) to N (oldest/bottom). | ||
| This method will be called repeatedly with increasing indices until | ||
| None is returned. | ||
| """ | ||
| pass |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
30 changes: 30 additions & 0 deletions
30
lldb/include/lldb/Interpreter/Interfaces/ScriptedFrameProviderInterface.h
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| // See https://llvm.org/LICENSE.txt for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef LLDB_INTERPRETER_INTERFACES_SCRIPTEDFRAMEPROVIDERINTERFACE_H | ||
| #define LLDB_INTERPRETER_INTERFACES_SCRIPTEDFRAMEPROVIDERINTERFACE_H | ||
|
|
||
| #include "lldb/lldb-private.h" | ||
|
|
||
| #include "ScriptedInterface.h" | ||
|
|
||
| namespace lldb_private { | ||
| class ScriptedFrameProviderInterface : public ScriptedInterface { | ||
| public: | ||
| virtual llvm::Expected<StructuredData::GenericSP> | ||
| CreatePluginObject(llvm::StringRef class_name, | ||
| lldb::StackFrameListSP input_frames, | ||
| StructuredData::DictionarySP args_sp) = 0; | ||
|
|
||
| virtual StructuredData::ObjectSP GetFrameAtIndex(uint32_t index) { | ||
| return {}; | ||
| } | ||
| }; | ||
| } // namespace lldb_private | ||
|
|
||
| #endif // LLDB_INTERPRETER_INTERFACES_SCRIPTEDFRAMEPROVIDERINTERFACE_H |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
57 changes: 57 additions & 0 deletions
57
...urce/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedFrameProviderPythonInterface.cpp
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| // See https://llvm.org/LICENSE.txt for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "lldb/Host/Config.h" | ||
| #include "lldb/Target/Thread.h" | ||
| #include "lldb/Utility/Log.h" | ||
| #include "lldb/lldb-enumerations.h" | ||
|
|
||
| #if LLDB_ENABLE_PYTHON | ||
|
|
||
| // LLDB Python header must be included first | ||
| #include "../lldb-python.h" | ||
|
|
||
| #include "../SWIGPythonBridge.h" | ||
| #include "../ScriptInterpreterPythonImpl.h" | ||
| #include "ScriptedFrameProviderPythonInterface.h" | ||
| #include <optional> | ||
|
|
||
| using namespace lldb; | ||
| using namespace lldb_private; | ||
| using namespace lldb_private::python; | ||
| using Locker = ScriptInterpreterPythonImpl::Locker; | ||
|
|
||
| ScriptedFrameProviderPythonInterface::ScriptedFrameProviderPythonInterface( | ||
| ScriptInterpreterPythonImpl &interpreter) | ||
| : ScriptedFrameProviderInterface(), ScriptedPythonInterface(interpreter) {} | ||
|
|
||
| llvm::Expected<StructuredData::GenericSP> | ||
| ScriptedFrameProviderPythonInterface::CreatePluginObject( | ||
| const llvm::StringRef class_name, lldb::StackFrameListSP input_frames, | ||
| StructuredData::DictionarySP args_sp) { | ||
| if (!input_frames) | ||
| return llvm::createStringError("Invalid frame list"); | ||
|
|
||
| StructuredDataImpl sd_impl(args_sp); | ||
| return ScriptedPythonInterface::CreatePluginObject(class_name, nullptr, | ||
| input_frames, sd_impl); | ||
| } | ||
|
|
||
| StructuredData::ObjectSP | ||
| ScriptedFrameProviderPythonInterface::GetFrameAtIndex(uint32_t index) { | ||
| Status error; | ||
| StructuredData::ObjectSP obj = Dispatch("get_frame_at_index", error, index); | ||
|
|
||
| if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj, | ||
| error)) | ||
| return {}; | ||
|
|
||
| return obj; | ||
| } | ||
|
|
||
| #endif | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.