Index: gdb/python/lib/gdb/frames.py |
diff --git a/gdb/python/lib/gdb/frames.py b/gdb/python/lib/gdb/frames.py |
new file mode 100644 |
index 0000000000000000000000000000000000000000..c148b9826e84727437756e07e4eaafcb99c67ff9 |
--- /dev/null |
+++ b/gdb/python/lib/gdb/frames.py |
@@ -0,0 +1,228 @@ |
+# Frame-filter commands. |
+# Copyright (C) 2013 Free Software Foundation, Inc. |
+ |
+# This program is free software; you can redistribute it and/or modify |
+# it under the terms of the GNU General Public License as published by |
+# the Free Software Foundation; either version 3 of the License, or |
+# (at your option) any later version. |
+# |
+# This program is distributed in the hope that it will be useful, |
+# but WITHOUT ANY WARRANTY; without even the implied warranty of |
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
+# GNU General Public License for more details. |
+# |
+# You should have received a copy of the GNU General Public License |
+# along with this program. If not, see <http://www.gnu.org/licenses/>. |
+ |
+"""Internal functions for working with frame-filters.""" |
+ |
+import gdb |
+from gdb.FrameIterator import FrameIterator |
+from gdb.FrameDecorator import FrameDecorator |
+import itertools |
+import collections |
+ |
+def get_priority(filter_item): |
+ """ Internal worker function to return the frame-filter's priority |
+ from a frame filter object. This is a fail free function as it is |
+ used in sorting and filtering. If a badly implemented frame |
+ filter does not implement the priority attribute, return zero |
+ (otherwise sorting/filtering will fail and prevent other frame |
+ filters from executing). |
+ |
+ Arguments: |
+ filter_item: An object conforming to the frame filter |
+ interface. |
+ |
+ Returns: |
+ The priority of the frame filter from the "priority" |
+ attribute, or zero. |
+ """ |
+ # Do not fail here, as the sort will fail. If a filter has not |
+ # (incorrectly) set a priority, set it to zero. |
+ return getattr(filter_item, "priority", 0) |
+ |
+def set_priority(filter_item, priority): |
+ """ Internal worker function to set the frame-filter's priority. |
+ |
+ Arguments: |
+ filter_item: An object conforming to the frame filter |
+ interface. |
+ priority: The priority to assign as an integer. |
+ """ |
+ |
+ filter_item.priority = priority |
+ |
+def get_enabled(filter_item): |
+ """ Internal worker function to return a filter's enabled state |
+ from a frame filter object. This is a fail free function as it is |
+ used in sorting and filtering. If a badly implemented frame |
+ filter does not implement the enabled attribute, return False |
+ (otherwise sorting/filtering will fail and prevent other frame |
+ filters from executing). |
+ |
+ Arguments: |
+ filter_item: An object conforming to the frame filter |
+ interface. |
+ |
+ Returns: |
+ The enabled state of the frame filter from the "enabled" |
+ attribute, or False. |
+ """ |
+ |
+ # If the filter class is badly implemented when called from the |
+ # Python filter command, do not cease filter operations, just set |
+ # enabled to False. |
+ return getattr(filter_item, "enabled", False) |
+ |
+def set_enabled(filter_item, state): |
+ """ Internal Worker function to set the frame-filter's enabled |
+ state. |
+ |
+ Arguments: |
+ filter_item: An object conforming to the frame filter |
+ interface. |
+ state: True or False, depending on desired state. |
+ """ |
+ |
+ filter_item.enabled = state |
+ |
+def return_list(name): |
+ """ Internal Worker function to return the frame filter |
+ dictionary, depending on the name supplied as an argument. If the |
+ name is not "all", "global" or "progspace", it is assumed to name |
+ an object-file. |
+ |
+ Arguments: |
+ name: The name of the list, as specified by GDB user commands. |
+ |
+ Returns: |
+ A dictionary object for a single specified dictionary, or a |
+ list containing all the items for "all" |
+ |
+ Raises: |
+ gdb.GdbError: A dictionary of that name cannot be found. |
+ """ |
+ |
+ # If all dictionaries are wanted in the case of "all" we |
+ # cannot return a combined dictionary as keys() may clash in |
+ # between different dictionaries. As we just want all the frame |
+ # filters to enable/disable them all, just return the combined |
+ # items() as a chained iterator of dictionary values. |
+ if name == "all": |
+ glob = gdb.frame_filters.values() |
+ prog = gdb.current_progspace().frame_filters.values() |
+ return_iter = itertools.chain(glob, prog) |
+ for objfile in gdb.objfiles(): |
+ return_iter = itertools.chain(return_iter, objfile.frame_filters.values()) |
+ |
+ return return_iter |
+ |
+ if name == "global": |
+ return gdb.frame_filters |
+ else: |
+ if name == "progspace": |
+ cp = gdb.current_progspace() |
+ return cp.frame_filters |
+ else: |
+ for objfile in gdb.objfiles(): |
+ if name == objfile.filename: |
+ return objfile.frame_filters |
+ |
+ msg = "Cannot find frame-filter dictionary for '" + name + "'" |
+ raise gdb.GdbError(msg) |
+ |
+def _sort_list(): |
+ """ Internal Worker function to merge all known frame-filter |
+ lists, prune any filters with the state set to "disabled", and |
+ sort the list on the frame-filter's "priority" attribute. |
+ |
+ Returns: |
+ sorted_list: A sorted, pruned list of frame filters to |
+ execute. |
+ """ |
+ |
+ all_filters = return_list("all") |
+ sorted_frame_filters = sorted(all_filters, key = get_priority, |
+ reverse = True) |
+ |
+ sorted_frame_filters = filter(get_enabled, |
+ sorted_frame_filters) |
+ |
+ return sorted_frame_filters |
+ |
+def execute_frame_filters(frame, frame_low, frame_high): |
+ """ Internal function called from GDB that will execute the chain |
+ of frame filters. Each filter is executed in priority order. |
+ After the execution completes, slice the iterator to frame_low - |
+ frame_high range. |
+ |
+ Arguments: |
+ frame: The initial frame. |
+ |
+ frame_low: The low range of the slice. If this is a negative |
+ integer then it indicates a backward slice (ie bt -4) which |
+ counts backward from the last frame in the backtrace. |
+ |
+ frame_high: The high range of the slice. If this is -1 then |
+ it indicates all frames until the end of the stack from |
+ frame_low. |
+ |
+ Returns: |
+ frame_iterator: The sliced iterator after all frame |
+ filters have had a change to execute, or None if no frame |
+ filters are registered. |
+ """ |
+ |
+ # Get a sorted list of frame filters. |
+ sorted_list = list(_sort_list()) |
+ |
+ # Check to see if there are any frame-filters. If not, just |
+ # return None and let default backtrace printing occur. |
+ if len(sorted_list) == 0: |
+ return None |
+ |
+ frame_iterator = FrameIterator(frame) |
+ |
+ # Apply a basic frame decorator to all gdb.Frames. This unifies |
+ # the interface. Python 3.x moved the itertools.imap |
+ # functionality to map(), so check if it is available. |
+ if hasattr(itertools,"imap"): |
+ frame_iterator = itertools.imap(FrameDecorator, frame_iterator) |
+ else: |
+ frame_iterator = map(FrameDecorator, frame_iterator) |
+ |
+ for ff in sorted_list: |
+ frame_iterator = ff.filter(frame_iterator) |
+ |
+ # Slicing |
+ |
+ # Is this a slice from the end of the backtrace, ie bt -2? |
+ if frame_low < 0: |
+ count = 0 |
+ slice_length = abs(frame_low) |
+ # We cannot use MAXLEN argument for deque as it is 2.6 onwards |
+ # and some GDB versions might be < 2.6. |
+ sliced = collections.deque() |
+ |
+ for frame_item in frame_iterator: |
+ if count >= slice_length: |
+ sliced.popleft(); |
+ count = count + 1 |
+ sliced.append(frame_item) |
+ |
+ return iter(sliced) |
+ |
+ # -1 for frame_high means until the end of the backtrace. Set to |
+ # None if that is the case, to indicate to itertools.islice to |
+ # slice to the end of the iterator. |
+ if frame_high == -1: |
+ frame_high = None |
+ else: |
+ # As frames start from 0, add one to frame_high so islice |
+ # correctly finds the end |
+ frame_high = frame_high + 1; |
+ |
+ sliced = itertools.islice(frame_iterator, frame_low, frame_high) |
+ |
+ return sliced |