]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gdb/python/lib/gdb/frames.py
Update copyright year range in header of all files managed by GDB
[thirdparty/binutils-gdb.git] / gdb / python / lib / gdb / frames.py
1 # Frame-filter commands.
2 # Copyright (C) 2013-2024 Free Software Foundation, Inc.
3
4 # This program is free software; you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License as published by
6 # the Free Software Foundation; either version 3 of the License, or
7 # (at your option) any later version.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17 """Internal functions for working with frame-filters."""
18
19 import gdb
20 from gdb.FrameIterator import FrameIterator
21 from gdb.FrameDecorator import FrameDecorator, DAPFrameDecorator
22 import itertools
23 import collections
24
25
26 def get_priority(filter_item):
27 """Internal worker function to return the frame-filter's priority
28 from a frame filter object. This is a fail free function as it is
29 used in sorting and filtering. If a badly implemented frame
30 filter does not implement the priority attribute, return zero
31 (otherwise sorting/filtering will fail and prevent other frame
32 filters from executing).
33
34 Arguments:
35 filter_item: An object conforming to the frame filter
36 interface.
37
38 Returns:
39 The priority of the frame filter from the "priority"
40 attribute, or zero.
41 """
42 # Do not fail here, as the sort will fail. If a filter has not
43 # (incorrectly) set a priority, set it to zero.
44 return getattr(filter_item, "priority", 0)
45
46
47 def set_priority(filter_item, priority):
48 """Internal worker function to set the frame-filter's priority.
49
50 Arguments:
51 filter_item: An object conforming to the frame filter
52 interface.
53 priority: The priority to assign as an integer.
54 """
55
56 filter_item.priority = priority
57
58
59 def get_enabled(filter_item):
60 """Internal worker function to return a filter's enabled state
61 from a frame filter object. This is a fail free function as it is
62 used in sorting and filtering. If a badly implemented frame
63 filter does not implement the enabled attribute, return False
64 (otherwise sorting/filtering will fail and prevent other frame
65 filters from executing).
66
67 Arguments:
68 filter_item: An object conforming to the frame filter
69 interface.
70
71 Returns:
72 The enabled state of the frame filter from the "enabled"
73 attribute, or False.
74 """
75
76 # If the filter class is badly implemented when called from the
77 # Python filter command, do not cease filter operations, just set
78 # enabled to False.
79 return getattr(filter_item, "enabled", False)
80
81
82 def set_enabled(filter_item, state):
83 """Internal Worker function to set the frame-filter's enabled
84 state.
85
86 Arguments:
87 filter_item: An object conforming to the frame filter
88 interface.
89 state: True or False, depending on desired state.
90 """
91
92 filter_item.enabled = state
93
94
95 def return_list(name):
96 """Internal Worker function to return the frame filter
97 dictionary, depending on the name supplied as an argument. If the
98 name is not "all", "global" or "progspace", it is assumed to name
99 an object-file.
100
101 Arguments:
102 name: The name of the list, as specified by GDB user commands.
103
104 Returns:
105 A dictionary object for a single specified dictionary, or a
106 list containing all the items for "all"
107
108 Raises:
109 gdb.GdbError: A dictionary of that name cannot be found.
110 """
111
112 # If all dictionaries are wanted in the case of "all" we
113 # cannot return a combined dictionary as keys() may clash in
114 # between different dictionaries. As we just want all the frame
115 # filters to enable/disable them all, just return the combined
116 # items() as a chained iterator of dictionary values.
117 if name == "all":
118 glob = gdb.frame_filters.values()
119 prog = gdb.current_progspace().frame_filters.values()
120 return_iter = itertools.chain(glob, prog)
121 for objfile in gdb.objfiles():
122 return_iter = itertools.chain(return_iter, objfile.frame_filters.values())
123
124 return return_iter
125
126 if name == "global":
127 return gdb.frame_filters
128 else:
129 if name == "progspace":
130 cp = gdb.current_progspace()
131 return cp.frame_filters
132 else:
133 for objfile in gdb.objfiles():
134 if name == objfile.filename:
135 return objfile.frame_filters
136
137 msg = "Cannot find frame-filter dictionary for '" + name + "'"
138 raise gdb.GdbError(msg)
139
140
141 def _sort_list():
142 """Internal Worker function to merge all known frame-filter
143 lists, prune any filters with the state set to "disabled", and
144 sort the list on the frame-filter's "priority" attribute.
145
146 Returns:
147 sorted_list: A sorted, pruned list of frame filters to
148 execute.
149 """
150
151 all_filters = return_list("all")
152 sorted_frame_filters = sorted(all_filters, key=get_priority, reverse=True)
153
154 sorted_frame_filters = filter(get_enabled, sorted_frame_filters)
155
156 return sorted_frame_filters
157
158
159 # Internal function that implements frame_iterator and
160 # execute_frame_filters. If DAP_SEMANTICS is True, then this will
161 # always return an iterator and will wrap frames in DAPFrameDecorator.
162 def _frame_iterator(frame, frame_low, frame_high, dap_semantics):
163 # Get a sorted list of frame filters.
164 sorted_list = list(_sort_list())
165
166 # Check to see if there are any frame-filters. If not, just
167 # return None and let default backtrace printing occur.
168 if not dap_semantics and len(sorted_list) == 0:
169 return None
170
171 frame_iterator = FrameIterator(frame)
172
173 # Apply a basic frame decorator to all gdb.Frames. This unifies
174 # the interface.
175 if dap_semantics:
176 decorator = DAPFrameDecorator
177 else:
178 decorator = FrameDecorator
179 frame_iterator = map(decorator, frame_iterator)
180
181 for ff in sorted_list:
182 frame_iterator = ff.filter(frame_iterator)
183
184 # Slicing
185
186 # Is this a slice from the end of the backtrace, ie bt -2?
187 if frame_low < 0:
188 count = 0
189 slice_length = abs(frame_low)
190 # We cannot use MAXLEN argument for deque as it is 2.6 onwards
191 # and some GDB versions might be < 2.6.
192 sliced = collections.deque()
193
194 for frame_item in frame_iterator:
195 if count >= slice_length:
196 sliced.popleft()
197 count = count + 1
198 sliced.append(frame_item)
199
200 return iter(sliced)
201
202 # -1 for frame_high means until the end of the backtrace. Set to
203 # None if that is the case, to indicate to itertools.islice to
204 # slice to the end of the iterator.
205 if frame_high == -1:
206 frame_high = None
207 else:
208 # As frames start from 0, add one to frame_high so islice
209 # correctly finds the end
210 frame_high = frame_high + 1
211
212 sliced = itertools.islice(frame_iterator, frame_low, frame_high)
213
214 return sliced
215
216
217 def frame_iterator(frame, frame_low, frame_high):
218 """Helper function that will execute the chain of frame filters.
219 Each filter is executed in priority order. After the execution
220 completes, slice the iterator to frame_low - frame_high range. An
221 iterator is always returned. The iterator will always yield
222 frame decorator objects, but note that these decorators have
223 slightly different semantics from the ordinary ones: they will
224 always return a fully-qualified 'filename' (if possible) and will
225 never substitute the objfile name.
226
227 Arguments:
228 frame: The initial frame.
229
230 frame_low: The low range of the slice, counting from 0. If
231 this is a negative integer then it indicates a backward slice
232 (ie bt -4) which counts backward from the last frame in the
233 backtrace.
234
235 frame_high: The high range of the slice, inclusive. If this
236 is -1 then it indicates all frames until the end of the stack
237 from frame_low.
238
239 Returns:
240 frame_iterator: The sliced iterator after all frame
241 filters have had a chance to execute.
242 """
243
244 return _frame_iterator(frame, frame_low, frame_high, True)
245
246
247 def execute_frame_filters(frame, frame_low, frame_high):
248 """Internal function called from GDB that will execute the chain
249 of frame filters. Each filter is executed in priority order.
250 After the execution completes, slice the iterator to frame_low -
251 frame_high range.
252
253 Arguments:
254 frame: The initial frame.
255
256 frame_low: The low range of the slice, counting from 0. If
257 this is a negative integer then it indicates a backward slice
258 (ie bt -4) which counts backward from the last frame in the
259 backtrace.
260
261 frame_high: The high range of the slice, inclusive. If this
262 is -1 then it indicates all frames until the end of the stack
263 from frame_low.
264
265 Returns:
266 frame_iterator: The sliced iterator after all frame
267 filters have had a chance to execute, or None if no frame
268 filters are registered.
269
270 """
271
272 return _frame_iterator(frame, frame_low, frame_high, False)