]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gdb/python/lib/gdb/dap/frames.py
Update copyright year range in header of all files managed by GDB
[thirdparty/binutils-gdb.git] / gdb / python / lib / gdb / dap / frames.py
CommitLineData
1d506c26 1# Copyright 2022-2024 Free Software Foundation, Inc.
de7d7cb5
TT
2
3# This program is free software; you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by
5# the Free Software Foundation; either version 3 of the License, or
6# (at your option) any later version.
7#
8# This program is distributed in the hope that it will be useful,
9# but WITHOUT ANY WARRANTY; without even the implied warranty of
10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11# GNU General Public License for more details.
12#
13# You should have received a copy of the GNU General Public License
14# along with this program. If not, see <http://www.gnu.org/licenses/>.
15
16import gdb
19201489
TT
17import itertools
18
19from gdb.frames import frame_iterator
de7d7cb5
TT
20
21from .startup import in_gdb_thread
22
23
85c72d70
TT
24# A list of all the frames we've reported. A frame's index in the
25# list is its ID. We don't use a hash here because frames are not
26# hashable.
27_all_frames = []
de7d7cb5
TT
28
29
19201489
TT
30# Map from a global thread ID to a memoizing frame iterator.
31_iter_map = {}
32
33
de7d7cb5
TT
34# Clear all the frame IDs.
35@in_gdb_thread
36def _clear_frame_ids(evt):
85c72d70
TT
37 global _all_frames
38 _all_frames = []
19201489
TT
39 global _iter_map
40 _iter_map = {}
de7d7cb5
TT
41
42
43# Clear the frame ID map whenever the inferior runs.
44gdb.events.cont.connect(_clear_frame_ids)
45
46
de7d7cb5
TT
47@in_gdb_thread
48def frame_for_id(id):
49 """Given a frame identifier ID, return the corresponding frame."""
85c72d70
TT
50 global _all_frames
51 return _all_frames[id]
5b86f108
TT
52
53
54@in_gdb_thread
55def select_frame(id):
56 """Given a frame identifier ID, select the corresponding frame."""
57 frame = frame_for_id(id)
58 frame.inferior_frame().select()
19201489
TT
59
60
61# A simple memoizing iterator. Note that this is not very robust.
62# For example, you can't start two copies of the iterator and then
63# alternate fetching items from each. Instead, it implements just
64# what is needed for the current callers.
65class _MemoizingIterator:
66 def __init__(self, iterator):
67 self.iterator = iterator
68 self.seen = []
69
70 def __iter__(self):
71 # First the memoized items.
72 for item in self.seen:
73 yield item
74 # Now memoize new items.
75 for item in self.iterator:
76 self.seen.append(item)
77 yield item
78
79
80# A generator that fetches frames and pairs them with a frame ID. It
81# yields tuples of the form (ID, ELIDED, FRAME), where ID is the
82# generated ID, ELIDED is a boolean indicating if the frame should be
83# elided, and FRAME is the frame itself. This approach lets us
84# memoize the result and assign consistent IDs, independent of how
85# "includeAll" is set in the request.
86@in_gdb_thread
87def _frame_id_generator():
88 try:
89 base_iterator = frame_iterator(gdb.newest_frame(), 0, -1)
90 except gdb.error:
91 base_iterator = ()
92
93 # Helper function to assign an ID to a frame.
94 def get_id(frame):
95 global _all_frames
96 num = len(_all_frames)
97 _all_frames.append(frame)
98 return num
99
100 def yield_frames(iterator, for_elided):
101 for frame in iterator:
102 # Unfortunately the frame filter docs don't describe
103 # whether the elided frames conceptually come before or
104 # after the eliding frame. Here we choose after.
105 yield (get_id(frame), for_elided, frame)
106
107 elided = frame.elided()
108 if elided is not None:
109 yield from yield_frames(frame.elided(), True)
110
111 yield from yield_frames(base_iterator, False)
112
113
114# Return the memoizing frame iterator for the selected thread.
115@in_gdb_thread
116def _get_frame_iterator():
117 thread_id = gdb.selected_thread().global_num
118 global _iter_map
119 if thread_id not in _iter_map:
120 _iter_map[thread_id] = _MemoizingIterator(_frame_id_generator())
121 return _iter_map[thread_id]
122
123
124# A helper function that creates an iterable that returns (ID, FRAME)
125# pairs. It uses the memoizing frame iterator, but also handles the
126# "includeAll" member of StackFrameFormat.
127@in_gdb_thread
128def dap_frame_generator(frame_low, levels, include_all):
129 """A generator that yields identifiers and frames.
130
131 Each element is a pair of the form (ID, FRAME).
132 ID is the internally-assigned frame ID.
133 FRAME is a FrameDecorator of some kind.
134
135 Arguments are as to the stackTrace request."""
136
137 base_iterator = _get_frame_iterator()
138
139 if not include_all:
140 base_iterator = itertools.filterfalse(lambda item: item[1], base_iterator)
141
142 if levels == 0:
143 # Zero means all remaining frames.
144 frame_high = None
145 else:
146 frame_high = frame_low + levels
147 base_iterator = itertools.islice(base_iterator, frame_low, frame_high)
148
149 for ident, _, frame in base_iterator:
150 yield (ident, frame)