packaging: Add python3-base dependency
[platform/upstream/gdb.git] / gdb / python / lib / gdb / frames.py
1 # Frame-filter commands.
2 # Copyright (C) 2013-2023 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
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 def execute_frame_filters(frame, frame_low, frame_high):
160     """Internal function called from GDB that will execute the chain
161     of frame filters.  Each filter is executed in priority order.
162     After the execution completes, slice the iterator to frame_low -
163     frame_high range.
164
165     Arguments:
166         frame: The initial frame.
167
168         frame_low: The low range of the slice.  If this is a negative
169         integer then it indicates a backward slice (ie bt -4) which
170         counts backward from the last frame in the backtrace.
171
172         frame_high: The high range of the slice.  If this is -1 then
173         it indicates all frames until the end of the stack from
174         frame_low.
175
176     Returns:
177         frame_iterator: The sliced iterator after all frame
178         filters have had a change to execute, or None if no frame
179         filters are registered.
180     """
181
182     # Get a sorted list of frame filters.
183     sorted_list = list(_sort_list())
184
185     # Check to see if there are any frame-filters.  If not, just
186     # return None and let default backtrace printing occur.
187     if len(sorted_list) == 0:
188         return None
189
190     frame_iterator = FrameIterator(frame)
191
192     # Apply a basic frame decorator to all gdb.Frames.  This unifies
193     # the interface.  Python 3.x moved the itertools.imap
194     # functionality to map(), so check if it is available.
195     if hasattr(itertools, "imap"):
196         frame_iterator = itertools.imap(FrameDecorator, frame_iterator)
197     else:
198         frame_iterator = map(FrameDecorator, frame_iterator)
199
200     for ff in sorted_list:
201         frame_iterator = ff.filter(frame_iterator)
202
203     # Slicing
204
205     # Is this a slice from the end of the backtrace, ie bt -2?
206     if frame_low < 0:
207         count = 0
208         slice_length = abs(frame_low)
209         # We cannot use MAXLEN argument for deque as it is 2.6 onwards
210         # and some GDB versions might be < 2.6.
211         sliced = collections.deque()
212
213         for frame_item in frame_iterator:
214             if count >= slice_length:
215                 sliced.popleft()
216             count = count + 1
217             sliced.append(frame_item)
218
219         return iter(sliced)
220
221     # -1 for frame_high means until the end of the backtrace.  Set to
222     # None if that is the case, to indicate to itertools.islice to
223     # slice to the end of the iterator.
224     if frame_high == -1:
225         frame_high = None
226     else:
227         # As frames start from 0, add one to frame_high so islice
228         # correctly finds the end
229         frame_high = frame_high + 1
230
231     sliced = itertools.islice(frame_iterator, frame_low, frame_high)
232
233     return sliced