Imported Upstream version 7.9
[platform/upstream/gdb.git] / gdb / python / lib / gdb / frames.py
1 # Frame-filter commands.
2 # Copyright (C) 2013-2015 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 def get_priority(filter_item):
26     """ Internal worker function to return the frame-filter's priority
27     from a frame filter object.  This is a fail free function as it is
28     used in sorting and filtering.  If a badly implemented frame
29     filter does not implement the priority attribute, return zero
30     (otherwise sorting/filtering will fail and prevent other frame
31     filters from executing).
32
33     Arguments:
34         filter_item: An object conforming to the frame filter
35                      interface.
36
37     Returns:
38         The priority of the frame filter from the "priority"
39         attribute, or zero.
40     """
41     # Do not fail here, as the sort will fail.  If a filter has not
42     # (incorrectly) set a priority, set it to zero.
43     return getattr(filter_item, "priority", 0)
44
45 def set_priority(filter_item, priority):
46     """ Internal worker function to set the frame-filter's priority.
47
48     Arguments:
49         filter_item: An object conforming to the frame filter
50                      interface.
51         priority: The priority to assign as an integer.
52     """
53
54     filter_item.priority = priority
55
56 def get_enabled(filter_item):
57     """ Internal worker function to return a filter's enabled state
58     from a frame filter object.  This is a fail free function as it is
59     used in sorting and filtering.  If a badly implemented frame
60     filter does not implement the enabled attribute, return False
61     (otherwise sorting/filtering will fail and prevent other frame
62     filters from executing).
63
64     Arguments:
65         filter_item: An object conforming to the frame filter
66                      interface.
67
68     Returns:
69         The enabled state of the frame filter from the "enabled"
70         attribute, or False.
71     """
72
73     # If the filter class is badly implemented when called from the
74     # Python filter command, do not cease filter operations, just set
75     # enabled to False.
76     return getattr(filter_item, "enabled", False)
77
78 def set_enabled(filter_item, state):
79     """ Internal Worker function to set the frame-filter's enabled
80     state.
81
82     Arguments:
83         filter_item: An object conforming to the frame filter
84                      interface.
85         state: True or False, depending on desired state.
86     """
87
88     filter_item.enabled = state
89
90 def return_list(name):
91     """ Internal Worker function to return the frame filter
92     dictionary, depending on the name supplied as an argument.  If the
93     name is not "all", "global" or "progspace", it is assumed to name
94     an object-file.
95
96     Arguments:
97         name: The name of the list, as specified by GDB user commands.
98
99     Returns:
100         A dictionary object for a single specified dictionary, or a
101         list containing all the items for "all"
102
103     Raises:
104         gdb.GdbError:  A dictionary of that name cannot be found.
105     """
106
107     # If all dictionaries are wanted in the case of "all" we
108     # cannot return a combined dictionary as keys() may clash in
109     # between different dictionaries.  As we just want all the frame
110     # filters to enable/disable them all, just return the combined
111     # items() as a chained iterator of dictionary values.
112     if name == "all":
113         glob = gdb.frame_filters.values()
114         prog = gdb.current_progspace().frame_filters.values()
115         return_iter = itertools.chain(glob, prog)
116         for objfile in gdb.objfiles():
117             return_iter = itertools.chain(return_iter, objfile.frame_filters.values())
118
119         return return_iter
120
121     if name == "global":
122         return gdb.frame_filters
123     else:
124         if name == "progspace":
125             cp = gdb.current_progspace()
126             return cp.frame_filters
127         else:
128             for objfile in gdb.objfiles():
129                 if name == objfile.filename:
130                     return objfile.frame_filters
131
132     msg = "Cannot find frame-filter dictionary for '" + name + "'"
133     raise gdb.GdbError(msg)
134
135 def _sort_list():
136     """ Internal Worker function to merge all known frame-filter
137     lists, prune any filters with the state set to "disabled", and
138     sort the list on the frame-filter's "priority" attribute.
139
140     Returns:
141         sorted_list: A sorted, pruned list of frame filters to
142                      execute.
143     """
144
145     all_filters = return_list("all")
146     sorted_frame_filters = sorted(all_filters, key = get_priority,
147                                   reverse = True)
148
149     sorted_frame_filters = filter(get_enabled,
150                                   sorted_frame_filters)
151
152     return sorted_frame_filters
153
154 def execute_frame_filters(frame, frame_low, frame_high):
155     """ Internal function called from GDB that will execute the chain
156     of frame filters.  Each filter is executed in priority order.
157     After the execution completes, slice the iterator to frame_low -
158     frame_high range.
159
160     Arguments:
161         frame: The initial frame.
162
163         frame_low: The low range of the slice.  If this is a negative
164         integer then it indicates a backward slice (ie bt -4) which
165         counts backward from the last frame in the backtrace.
166
167         frame_high: The high range of the slice.  If this is -1 then
168         it indicates all frames until the end of the stack from
169         frame_low.
170
171     Returns:
172         frame_iterator: The sliced iterator after all frame
173         filters have had a change to execute, or None if no frame
174         filters are registered.
175     """
176
177     # Get a sorted list of frame filters.
178     sorted_list = list(_sort_list())
179
180     # Check to see if there are any frame-filters.  If not, just
181     # return None and let default backtrace printing occur.
182     if len(sorted_list) == 0:
183         return None
184
185     frame_iterator = FrameIterator(frame)
186
187     # Apply a basic frame decorator to all gdb.Frames.  This unifies
188     # the interface.  Python 3.x moved the itertools.imap
189     # functionality to map(), so check if it is available.
190     if hasattr(itertools,"imap"):
191         frame_iterator = itertools.imap(FrameDecorator, frame_iterator)
192     else:
193         frame_iterator = map(FrameDecorator, frame_iterator)
194
195     for ff in sorted_list:
196         frame_iterator = ff.filter(frame_iterator)
197
198     # Slicing
199
200     # Is this a slice from the end of the backtrace, ie bt -2?
201     if frame_low < 0:
202         count = 0
203         slice_length = abs(frame_low)
204         # We cannot use MAXLEN argument for deque as it is 2.6 onwards
205         # and some GDB versions might be < 2.6.
206         sliced = collections.deque()
207
208         for frame_item in frame_iterator:
209             if count >= slice_length:
210                 sliced.popleft();
211             count = count + 1
212             sliced.append(frame_item)
213
214         return iter(sliced)
215
216     # -1 for frame_high means until the end of the backtrace.  Set to
217     # None if that is the case, to indicate to itertools.islice to
218     # slice to the end of the iterator.
219     if frame_high == -1:
220         frame_high = None
221     else:
222         # As frames start from 0, add one to frame_high so islice
223         # correctly finds the end
224         frame_high = frame_high + 1;
225
226     sliced = itertools.islice(frame_iterator, frame_low, frame_high)
227
228     return sliced