Skip to content

Commit d584d00

Browse files
authored
[lldb] Introduce SBFrameList for lazy frame iteration (llvm#166651)
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]>
1 parent 8321eaa commit d584d00

File tree

17 files changed

+477
-3
lines changed

17 files changed

+477
-3
lines changed
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
%extend lldb::SBFrameList {
2+
3+
#ifdef SWIGPYTHON
4+
%nothreadallow;
5+
#endif
6+
std::string lldb::SBFrameList::__str__ (){
7+
lldb::SBStream description;
8+
if (!$self->GetDescription(description))
9+
return std::string("<empty> lldb.SBFrameList()");
10+
const char *desc = description.GetData();
11+
size_t desc_len = description.GetSize();
12+
if (desc_len > 0 && (desc[desc_len-1] == '\n' || desc[desc_len-1] == '\r'))
13+
--desc_len;
14+
return std::string(desc, desc_len);
15+
}
16+
#ifdef SWIGPYTHON
17+
%clearnothreadallow;
18+
#endif
19+
20+
#ifdef SWIGPYTHON
21+
%pythoncode %{
22+
def __iter__(self):
23+
'''Iterate over all frames in a lldb.SBFrameList object.'''
24+
return lldb_iter(self, 'GetSize', 'GetFrameAtIndex')
25+
26+
def __len__(self):
27+
return int(self.GetSize())
28+
29+
def __getitem__(self, key):
30+
if type(key) is not int:
31+
return None
32+
if key < 0:
33+
count = len(self)
34+
if -count <= key < count:
35+
key %= count
36+
37+
frame = self.GetFrameAtIndex(key)
38+
return frame if frame.IsValid() else None
39+
%}
40+
#endif
41+
}

lldb/bindings/interface/SBThreadExtensions.i

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ STRING_EXTENSION_OUTSIDE(SBThread)
4141
def get_thread_frames(self):
4242
'''An accessor function that returns a list() that contains all frames in a lldb.SBThread object.'''
4343
frames = []
44-
for frame in self:
44+
frame_list = self.GetFrames()
45+
for frame in frame_list:
4546
frames.append(frame)
4647
return frames
4748

lldb/bindings/interfaces.swig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@
119119
%include "lldb/API/SBFileSpecList.h"
120120
%include "lldb/API/SBFormat.h"
121121
%include "lldb/API/SBFrame.h"
122+
%include "lldb/API/SBFrameList.h"
122123
%include "lldb/API/SBFunction.h"
123124
%include "lldb/API/SBHostOS.h"
124125
%include "lldb/API/SBInstruction.h"
@@ -193,6 +194,7 @@
193194
%include "./interface/SBFileSpecExtensions.i"
194195
%include "./interface/SBFileSpecListExtensions.i"
195196
%include "./interface/SBFrameExtensions.i"
197+
%include "./interface/SBFrameListExtensions.i"
196198
%include "./interface/SBFunctionExtensions.i"
197199
%include "./interface/SBInstructionExtensions.i"
198200
%include "./interface/SBInstructionListExtensions.i"

lldb/include/lldb/API/LLDB.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#include "lldb/API/SBFileSpecList.h"
3838
#include "lldb/API/SBFormat.h"
3939
#include "lldb/API/SBFrame.h"
40+
#include "lldb/API/SBFrameList.h"
4041
#include "lldb/API/SBFunction.h"
4142
#include "lldb/API/SBHostOS.h"
4243
#include "lldb/API/SBInstruction.h"

lldb/include/lldb/API/SBDefines.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ class LLDB_API SBFileSpec;
7676
class LLDB_API SBFileSpecList;
7777
class LLDB_API SBFormat;
7878
class LLDB_API SBFrame;
79+
class LLDB_API SBFrameList;
7980
class LLDB_API SBFunction;
8081
class LLDB_API SBHostOS;
8182
class LLDB_API SBInstruction;

lldb/include/lldb/API/SBFrame.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,7 @@ class LLDB_API SBFrame {
222222
protected:
223223
friend class SBBlock;
224224
friend class SBExecutionContext;
225+
friend class SBFrameList;
225226
friend class SBInstruction;
226227
friend class SBThread;
227228
friend class SBValue;
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
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_API_SBFRAMELIST_H
10+
#define LLDB_API_SBFRAMELIST_H
11+
12+
#include "lldb/API/SBDefines.h"
13+
14+
namespace lldb {
15+
16+
/// Represents a list of SBFrame objects.
17+
///
18+
/// SBFrameList provides a way to iterate over stack frames lazily,
19+
/// materializing frames on-demand as they are accessed. This is more
20+
/// efficient than eagerly creating all frames upfront.
21+
class LLDB_API SBFrameList {
22+
public:
23+
SBFrameList();
24+
25+
SBFrameList(const lldb::SBFrameList &rhs);
26+
27+
~SBFrameList();
28+
29+
const lldb::SBFrameList &operator=(const lldb::SBFrameList &rhs);
30+
31+
explicit operator bool() const;
32+
33+
bool IsValid() const;
34+
35+
/// Returns the number of frames in the list.
36+
uint32_t GetSize() const;
37+
38+
/// Returns the frame at the given index.
39+
///
40+
/// \param[in] idx
41+
/// The index of the frame to retrieve (0-based).
42+
///
43+
/// \return
44+
/// An SBFrame object for the frame at the specified index.
45+
/// Returns an invalid SBFrame if idx is out of range.
46+
lldb::SBFrame GetFrameAtIndex(uint32_t idx) const;
47+
48+
/// Get the thread associated with this frame list.
49+
///
50+
/// \return
51+
/// An SBThread object representing the thread.
52+
lldb::SBThread GetThread() const;
53+
54+
/// Clear all frames from this list.
55+
void Clear();
56+
57+
/// Get a description of this frame list.
58+
///
59+
/// \param[in] description
60+
/// The stream to write the description to.
61+
///
62+
/// \return
63+
/// True if the description was successfully written.
64+
bool GetDescription(lldb::SBStream &description) const;
65+
66+
protected:
67+
friend class SBThread;
68+
69+
private:
70+
SBFrameList(const lldb::StackFrameListSP &frame_list_sp);
71+
72+
void SetFrameList(const lldb::StackFrameListSP &frame_list_sp);
73+
74+
// This needs to be a shared_ptr since an SBFrameList can be passed to
75+
// scripting affordances like ScriptedFrameProviders but also out of
76+
// convenience because Thread::GetStackFrameList returns a StackFrameListSP.
77+
lldb::StackFrameListSP m_opaque_sp;
78+
};
79+
80+
} // namespace lldb
81+
82+
#endif // LLDB_API_SBFRAMELIST_H

lldb/include/lldb/API/SBStream.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ class LLDB_API SBStream {
8181
friend class SBFileSpec;
8282
friend class SBFileSpecList;
8383
friend class SBFrame;
84+
friend class SBFrameList;
8485
friend class SBFunction;
8586
friend class SBInstruction;
8687
friend class SBInstructionList;

lldb/include/lldb/API/SBThread.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,8 @@ class LLDB_API SBThread {
186186

187187
lldb::SBFrame GetFrameAtIndex(uint32_t idx);
188188

189+
lldb::SBFrameList GetFrames();
190+
189191
lldb::SBFrame GetSelectedFrame();
190192

191193
lldb::SBFrame SetSelectedFrame(uint32_t frame_idx);
@@ -244,6 +246,7 @@ class LLDB_API SBThread {
244246
friend class SBSaveCoreOptions;
245247
friend class SBExecutionContext;
246248
friend class SBFrame;
249+
friend class SBFrameList;
247250
friend class SBProcess;
248251
friend class SBDebugger;
249252
friend class SBValue;

lldb/include/lldb/Target/StackFrameList.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,9 @@ class StackFrameList {
101101
/// Returns whether we have currently fetched all the frames of a stack.
102102
bool WereAllFramesFetched() const;
103103

104+
/// Get the thread associated with this frame list.
105+
Thread &GetThread() const { return m_thread; }
106+
104107
protected:
105108
friend class Thread;
106109
friend class ScriptedThread;

0 commit comments

Comments
 (0)