GDB (API)
|
00001 # Frame-filter commands. 00002 # Copyright (C) 2013 Free Software Foundation, Inc. 00003 00004 # This program is free software; you can redistribute it and/or modify 00005 # it under the terms of the GNU General Public License as published by 00006 # the Free Software Foundation; either version 3 of the License, or 00007 # (at your option) any later version. 00008 # 00009 # This program is distributed in the hope that it will be useful, 00010 # but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 # GNU General Public License for more details. 00013 # 00014 # You should have received a copy of the GNU General Public License 00015 # along with this program. If not, see <http://www.gnu.org/licenses/>. 00016 00017 """Internal functions for working with frame-filters.""" 00018 00019 import gdb 00020 from gdb.FrameIterator import FrameIterator 00021 from gdb.FrameDecorator import FrameDecorator 00022 import itertools 00023 import collections 00024 00025 def get_priority(filter_item): 00026 """ Internal worker function to return the frame-filter's priority 00027 from a frame filter object. This is a fail free function as it is 00028 used in sorting and filtering. If a badly implemented frame 00029 filter does not implement the priority attribute, return zero 00030 (otherwise sorting/filtering will fail and prevent other frame 00031 filters from executing). 00032 00033 Arguments: 00034 filter_item: An object conforming to the frame filter 00035 interface. 00036 00037 Returns: 00038 The priority of the frame filter from the "priority" 00039 attribute, or zero. 00040 """ 00041 # Do not fail here, as the sort will fail. If a filter has not 00042 # (incorrectly) set a priority, set it to zero. 00043 return getattr(filter_item, "priority", 0) 00044 00045 def set_priority(filter_item, priority): 00046 """ Internal worker function to set the frame-filter's priority. 00047 00048 Arguments: 00049 filter_item: An object conforming to the frame filter 00050 interface. 00051 priority: The priority to assign as an integer. 00052 """ 00053 00054 filter_item.priority = priority 00055 00056 def get_enabled(filter_item): 00057 """ Internal worker function to return a filter's enabled state 00058 from a frame filter object. This is a fail free function as it is 00059 used in sorting and filtering. If a badly implemented frame 00060 filter does not implement the enabled attribute, return False 00061 (otherwise sorting/filtering will fail and prevent other frame 00062 filters from executing). 00063 00064 Arguments: 00065 filter_item: An object conforming to the frame filter 00066 interface. 00067 00068 Returns: 00069 The enabled state of the frame filter from the "enabled" 00070 attribute, or False. 00071 """ 00072 00073 # If the filter class is badly implemented when called from the 00074 # Python filter command, do not cease filter operations, just set 00075 # enabled to False. 00076 return getattr(filter_item, "enabled", False) 00077 00078 def set_enabled(filter_item, state): 00079 """ Internal Worker function to set the frame-filter's enabled 00080 state. 00081 00082 Arguments: 00083 filter_item: An object conforming to the frame filter 00084 interface. 00085 state: True or False, depending on desired state. 00086 """ 00087 00088 filter_item.enabled = state 00089 00090 def return_list(name): 00091 """ Internal Worker function to return the frame filter 00092 dictionary, depending on the name supplied as an argument. If the 00093 name is not "all", "global" or "progspace", it is assumed to name 00094 an object-file. 00095 00096 Arguments: 00097 name: The name of the list, as specified by GDB user commands. 00098 00099 Returns: 00100 A dictionary object for a single specified dictionary, or a 00101 list containing all the items for "all" 00102 00103 Raises: 00104 gdb.GdbError: A dictionary of that name cannot be found. 00105 """ 00106 00107 # If all dictionaries are wanted in the case of "all" we 00108 # cannot return a combined dictionary as keys() may clash in 00109 # between different dictionaries. As we just want all the frame 00110 # filters to enable/disable them all, just return the combined 00111 # items() as a chained iterator of dictionary values. 00112 if name == "all": 00113 glob = gdb.frame_filters.values() 00114 prog = gdb.current_progspace().frame_filters.values() 00115 return_iter = itertools.chain(glob, prog) 00116 for objfile in gdb.objfiles(): 00117 return_iter = itertools.chain(return_iter, objfile.frame_filters.values()) 00118 00119 return return_iter 00120 00121 if name == "global": 00122 return gdb.frame_filters 00123 else: 00124 if name == "progspace": 00125 cp = gdb.current_progspace() 00126 return cp.frame_filters 00127 else: 00128 for objfile in gdb.objfiles(): 00129 if name == objfile.filename: 00130 return objfile.frame_filters 00131 00132 msg = "Cannot find frame-filter dictionary for '" + name + "'" 00133 raise gdb.GdbError(msg) 00134 00135 def _sort_list(): 00136 """ Internal Worker function to merge all known frame-filter 00137 lists, prune any filters with the state set to "disabled", and 00138 sort the list on the frame-filter's "priority" attribute. 00139 00140 Returns: 00141 sorted_list: A sorted, pruned list of frame filters to 00142 execute. 00143 """ 00144 00145 all_filters = return_list("all") 00146 sorted_frame_filters = sorted(all_filters, key = get_priority, 00147 reverse = True) 00148 00149 sorted_frame_filters = filter(get_enabled, 00150 sorted_frame_filters) 00151 00152 return sorted_frame_filters 00153 00154 def execute_frame_filters(frame, frame_low, frame_high): 00155 """ Internal function called from GDB that will execute the chain 00156 of frame filters. Each filter is executed in priority order. 00157 After the execution completes, slice the iterator to frame_low - 00158 frame_high range. 00159 00160 Arguments: 00161 frame: The initial frame. 00162 00163 frame_low: The low range of the slice. If this is a negative 00164 integer then it indicates a backward slice (ie bt -4) which 00165 counts backward from the last frame in the backtrace. 00166 00167 frame_high: The high range of the slice. If this is -1 then 00168 it indicates all frames until the end of the stack from 00169 frame_low. 00170 00171 Returns: 00172 frame_iterator: The sliced iterator after all frame 00173 filters have had a change to execute, or None if no frame 00174 filters are registered. 00175 """ 00176 00177 # Get a sorted list of frame filters. 00178 sorted_list = list(_sort_list()) 00179 00180 # Check to see if there are any frame-filters. If not, just 00181 # return None and let default backtrace printing occur. 00182 if len(sorted_list) == 0: 00183 return None 00184 00185 frame_iterator = FrameIterator(frame) 00186 00187 # Apply a basic frame decorator to all gdb.Frames. This unifies 00188 # the interface. Python 3.x moved the itertools.imap 00189 # functionality to map(), so check if it is available. 00190 if hasattr(itertools,"imap"): 00191 frame_iterator = itertools.imap(FrameDecorator, frame_iterator) 00192 else: 00193 frame_iterator = map(FrameDecorator, frame_iterator) 00194 00195 for ff in sorted_list: 00196 frame_iterator = ff.filter(frame_iterator) 00197 00198 # Slicing 00199 00200 # Is this a slice from the end of the backtrace, ie bt -2? 00201 if frame_low < 0: 00202 count = 0 00203 slice_length = abs(frame_low) 00204 # We cannot use MAXLEN argument for deque as it is 2.6 onwards 00205 # and some GDB versions might be < 2.6. 00206 sliced = collections.deque() 00207 00208 for frame_item in frame_iterator: 00209 if count >= slice_length: 00210 sliced.popleft(); 00211 count = count + 1 00212 sliced.append(frame_item) 00213 00214 return iter(sliced) 00215 00216 # -1 for frame_high means until the end of the backtrace. Set to 00217 # None if that is the case, to indicate to itertools.islice to 00218 # slice to the end of the iterator. 00219 if frame_high == -1: 00220 frame_high = None 00221 else: 00222 # As frames start from 0, add one to frame_high so islice 00223 # correctly finds the end 00224 frame_high = frame_high + 1; 00225 00226 sliced = itertools.islice(frame_iterator, frame_low, frame_high) 00227 00228 return sliced