Skip to content

Conversation

@medismailben
Copy link

@medismailben medismailben commented Nov 11, 2025

This PR implements various things:

  1. Introduces a new SBFrameList class and make sure SBFrame can resolve the SBFrameList it came from:
  1. Implement a lazy scripted interface for {Synthetic,Scripted}FrameProvider:
  1. Improved the ScriptedInterface to be able to call staticmethod/classmethod as well as resolve the scripted interface module file path:
  1. Made most of StackFrame's methods virtual and added a new BorrowedStackFrame class:
  1. Improved FormatEntity to support PC-less ynthetic frames:
  1. Made us of all the above to load foreign (Python) sources in debug session with native threads / backtrace:

rdar://161834688

@medismailben
Copy link
Author

@swift-ci test

@medismailben medismailben changed the base branch from stable/21.x to swift/release/6.3 November 30, 2025 00:14
@medismailben medismailben requested a review from a team as a code owner November 30, 2025 00:14
@medismailben
Copy link
Author

@swift-ci test

@medismailben medismailben changed the title [lldb] Introduce SBFrameList, SyntheticFrameProvider & ScriptedFrameProvider [lldb] Introduce SBFrameList, SyntheticFrameProvider, BorrowedStackFrame & ScriptedFrameProvider Nov 30, 2025
@medismailben
Copy link
Author

@swift-ci test

@medismailben
Copy link
Author

@swift-ci please test windows

@medismailben
Copy link
Author

@swift-ci test

…C) (llvm#170187)

This fixes a typo in ScriptedPythonInterface and changes
`AbstrackMethodCheckerPayload` to `AbstractMethodCheckerPayload`.

Signed-off-by: Med Ismail Bennani <[email protected]>
(cherry picked from commit fd8bf3c)
…nterface (llvm#170188)

Extract `__func__` attribute from staticmethod/classmethod descriptors
before treating them as callables. Python's `@staticmethod` and
`@classmethod` decorators wrap methods in descriptor objects that are
not directly usable as PythonCallable, when calling PyCallable_Check.

The actual callable function is stored in the `__func__` attribute of
these descriptors, so we need to unwrap them to properly validate and
invoke the decorated methods in scripted interfaces.

Signed-off-by: Med Ismail Bennani <[email protected]>
(cherry picked from commit 3ca85e7)
llvm#170202)

This adds a new virtual method `GetScriptedModulePath()` to
`ScriptedInterface` that allows retrieving the file path of the Python
module containing the scripted object implementation.

The Python implementation acquires the GIL and walks through the
object's `__class__.__module__` to find the module's `__file__`
attribute. This will be used by ScriptedFrame to populate the module and
compile unit for frames pointing to Python source files.

Signed-off-by: Med Ismail Bennani <[email protected]>
(cherry picked from commit b7c358c)
This fixes a typo in `ScriptedPythonInterface::GetScriptedModulePath`.

Signed-off-by: Med Ismail Bennani <[email protected]>
(cherry picked from commit 0e0c0b7)
This patch introduces `SBFrameList`, a new SBAPI class that allows
iterating over stack frames lazily without calling
`SBThread::GetFrameAtIndex` in a loop.

The new `SBThread::GetFrames()` method returns an `SBFrameList` that
supports Python iteration (`for frame in frame_list:`), indexing
(`frame_list[0]`, `frame_list[-1]`), and length queries (`len()`).

The implementation uses `StackFrameListSP` as the opaque pointer,
sharing the thread's underlying frame list to ensure frames are
materialized on-demand.

This is particularly useful for ScriptedFrameProviders, where user
scripts will be to iterate, filter, and replace frames lazily without
materializing the entire stack upfront.

Signed-off-by: Med Ismail Bennani <[email protected]>
(cherry picked from commit d584d00)
This patch introduces a new way to reconstruct the thread stackframe
list.

New `SyntheticFrameProvider` classes can lazy fetch a StackFrame at
index using a provided StackFrameList.

In can either be the real unwinder StackFrameList or we could also chain
SyntheticFrameProviders to each others.

This is the foundation work to implement ScriptedFrameProviders, which
will come in a follow-up patch.

Signed-off-by: Med Ismail Bennani <[email protected]>

Signed-off-by: Med Ismail Bennani <[email protected]>
(cherry picked from commit 71cb0bb)
…lvm#166662)

This patch implements the base and python interface for the
ScriptedFrameProvider class.

This is necessary to call python APIs from the ScriptedFrameProvider
that will come in a follow-up.

Signed-off-by: Med Ismail Bennani <[email protected]>

Signed-off-by: Med Ismail Bennani <[email protected]>
(cherry picked from commit 4cd17ee)
…dencies (llvm#170226)

This change adds tracking of the StackFrameList that produced each frame
by storing a weak pointer (m_frame_list_wp) in both `StackFrame` and
`ExecutionContextRef`.

When resolving frames through `ExecutionContextRef::GetFrameSP`, the
code now first attempts to use the remembered frame list instead of
immediately calling `Thread::GetStackFrameList`. This breaks circular
dependencies that can occur during frame provider initialization, where
creating a frame provider might trigger `ExecutionContext` resolution,
which would then call back into `Thread::GetStackFrameList()`, creating
an infinite loop.

The `StackFrameList` now sets m_frame_list_wp on every frame it creates,
and a new virtual method `GetOriginatingStackFrameList` allows frames to
expose their originating list.

Signed-off-by: Med Ismail Bennani <[email protected]>
(cherry picked from commit 755733e)
…ual (llvm#170191)

This change makes StackFrame methods virtual to enable subclass
overrides and introduces BorrowedStackFrame, a wrapper that presents an
existing StackFrame with a different frame index.

This enables creating synthetic frame views or renumbering frames
without copying the underlying frame data, which is useful for frame
manipulation scenarios.

This also adds a new borrowed-info format entity to show what was the
original frame index of the borrowed frame.

Signed-off-by: Med Ismail Bennani <[email protected]>
(cherry picked from commit 41a53c0)
…#161870)" (llvm#170236)

This patch re-lands llvm#161870 with fixes to the previous test failures.

rdar://161834688

Signed-off-by: Med Ismail Bennani <[email protected]>
(cherry picked from commit c50802c)
On ARM32, FixCodeAddress unconditionally clears bit 0 (the Thumb bit)
from all code addresses, including synthetic frame PCs. This causes
test failures where synthetic PCs like 0xFFFF and 0xDEADBEEF become
0xFFFE and 0xDEADBEEE respectively.

This adjusts the tests to expect the modified PC values on ARM32.

Signed-off-by: Med Ismail Bennani <[email protected]>
(cherry picked from commit b30a48c)
This patch disables TestFrameProviderCircularDependency.py on Windows
since the scripted frame provider uses SBTarget.FindFunctions which
doesn't seem to be working (according to TestTargetAPI.test_find_functions).

Signed-off-by: Med Ismail Bennani <[email protected]>
(cherry picked from commit 2cf2768)
Signed-off-by: Med Ismail Bennani <[email protected]>
(cherry picked from commit 82c6ad6)
It looks like the providers don't get loaded on arm32 bots:

llvm#170412

Skipping for now since I don't have access to a machine to investigate
it.

Signed-off-by: Med Ismail Bennani <[email protected]>
(cherry picked from commit 6f5a69b)
Signed-off-by: Med Ismail Bennani <[email protected]>
(cherry picked from commit 542a8f2)
This patch adds the documentation for ScriptedFrameProviders to the
lldb website.

Signed-off-by: Med Ismail Bennani <[email protected]>
(cherry picked from commit 0dcbc87)
…ess ranges (llvm#158811)

Scripted frames that materialize Python functions are PC-less by design,
meaning they don't have valid address ranges. Previously,
LineEntry::IsValid()
required both a valid address range and a line number, preventing
scripted
frames from creating valid line entries for these synthetic stack
frames.

Relaxing this requirement is necessary since
`SBSymbolContext::SetLineEntry`
will first check if the LineEntry is valid and discard it otherwise.

This change introduces an `synthetic` flag that gets set when LineEntry
objects are created or modified through the SBAPI (specifically via
SetLine).
When this flag is set, IsValid() no longer requires a valid address
range,
only a valid line number.

This is risk-free because the flag is only set for LineEntry objects
created
through the SBAPI, which are primarily used by scripted processes and
frames.
Regular debug information-derived line entries continue to require valid
address ranges.

Signed-off-by: Med Ismail Bennani <[email protected]>
(cherry picked from commit 41f643a)
Scripted frames that materialize Python functions or other non-native
code are PC-less by design, meaning they don't have valid program
counter values. Previously, these frames would display invalid addresses
(`0xffffffffffffffff`) in backtrace output.

This patch updates `FormatEntity` to detect and suppress invalid address
display for PC-less frames, adds fallback to frame methods when symbol
context is unavailable, and modifies `StackFrame::GetSymbolContext` to
skip PC-based symbol resolution for invalid addresses.

The changes enable PC-less frames to display cleanly with proper
function names, file paths, and line numbers, and allow for source
display of foreign sources (like Python). Includes comprehensive test
coverage demonstrating frames pointing to Python source files.

Signed-off-by: Med Ismail Bennani <[email protected]>
(cherry picked from commit 96c733e)
@medismailben
Copy link
Author

@swift-ci test

@medismailben medismailben changed the title [lldb] Introduce SBFrameList, SyntheticFrameProvider, BorrowedStackFrame & ScriptedFrameProvider [lldb] Introduce ScriptedFrameProvider infrastructure for foreign PC-less (Python) scripted frames Dec 6, 2025
@medismailben
Copy link
Author

@swift-ci test macOS platform

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant