[Lldb-commits] [lldb] [lldb] Introduce ScriptedFrameProvider for real threads (PR #161870)
Adrian Vogelsgesang via lldb-commits
lldb-commits at lists.llvm.org
Thu Oct 16 12:51:20 PDT 2025
vogelsgesang wrote:
> I quickly looked at the private parts of the change. I had a slightly different design in mind, which I pitched to Ismail in person this morning. I created a quick sequence diagram to show it in action.
Thanks for that updated design!
Afaict, two of my points (lazy unwinding, script-controlled merging strategies) are already addressed in the latest version of this PR and we are also aligned on my third point (global registration) by holding the stack frame provider in the target.
With that high-level alignment out of the way, I now wonder about the detailed design of the interface. If I understand the updated design correctly, Python authors would now have to implement a `get_stack_frames(real_threads, provided_frames, stack_depth)` function. Or is that only an internal implementation detail on the C++ level, and we would expose this differently to the Python layer?
I think a generator-based Python interface would be more user-friendly, as shown by comparing the following two examples (loosely based on the [C++ coroutine unwinding script](https://clang.llvm.org/docs/DebuggingCoroutines.html#gdb-debugger-script)):
**generator / `yield`-based**
```python
def _create_coroutine_frames(coro_frame):
while coro_frame is not None:
yield CoroutineFrame(coro_frame)
coro_frame = _get_continuation(coro_frame.promise_ptr)
class CppCoroutineFrameProvider:
def get_stack_frames(self, input_frames):
for frame in input_frames:
# forward physical frame
yield frame
# Check if we are in a coroutine by looking for `__promise`
try:
promise_ptr = frame.read_var("__promise")
except Exception:
continue
parent_coro = _get_continuation(promise_ptr)
# Add all the async stack frames
if parent_coro is not None:
yield from _create_coroutine_frames(parent_coro)
```
**index-based**
Two downsides:
1. quite a bit of manual book-keeping around `frame_idx`
2. I don't have a way to store state between `get_stack_frames` calls and as such I have to back off until the previous physical frame and redo some stack frames from there
```python
def _create_coroutine_frames(coro_frame, output_frames, frame_idx, frame_count):
while coro_frame is not None and frame_idx < frame_count:
output_frames.SetFrameAt(frame_idx, CoroutineFrame(coro_frame, inferior_frame))
coro_frame = _get_continuation(coro_frame.promise_ptr)
return frame_idx
class CppCoroutineFrameProvider:
def get_stack_frames(self, input_frames, output_frames, frame_count):
# Don't redo the work for frames which we already unrolled
frame_idx = len(output_frames)
# Backtrack until the last physical frame, as we cannot not store the
# `coro_frame ` intermediate state and hence can't resume in the middle
# of `_create_coroutine_frames`
while not output_frames.GetFrameAt(frame_idx).IsPhysicalThread():
--frame_idx
while frame_idx < frame_count
# forward physical frame
output_frames.SetFrameAt(frame_idx, input_frames.GetFrameAt(start_frame_idx)
frame_idx += 1;
# Check if we are in a coroutine by looking for `__promise`
inferior_frame = frame.inferior_frame()
try:
promise_ptr = inferior_frame.read_var("__promise")
except Exception:
continue
parent_coro = _get_continuation(promise_ptr)
# Add all the async stack frames
if parent_coro is not None:
frame_idx = _create_coroutine_frames(parent_coro, output_frames, frame_idx, frame_count)
```
https://github.com/llvm/llvm-project/pull/161870
More information about the lldb-commits
mailing list