blob: 19172e7a69477f58220eb482c389f7f1a9a76d0b [file] [log] [blame]
Ben Cheng7334f0a2014-04-30 14:28:17 -07001# Frame-filter commands.
2# Copyright (C) 2013-2014 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
19import gdb
20from gdb.FrameIterator import FrameIterator
21from gdb.FrameDecorator import FrameDecorator
22import itertools
23import collections
24
25def 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
45def 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
56def 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
78def 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
90def 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
135def _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
154def 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