1 # 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 """GDB commands for working with frame-filters.""" 18 19 import sys 20 import gdb 21 import copy 22 from gdb.FrameIterator import FrameIterator 23 from gdb.FrameDecorator import FrameDecorator 24 import gdb.frames 25 import itertools 26 27 # GDB Commands. 28 class SetFilterPrefixCmd(gdb.Command): 29 """Prefix command for 'set' frame-filter related operations.""" 30 31 def __init__(self): 32 super(SetFilterPrefixCmd, self).__init__("set frame-filter", 33 gdb.COMMAND_OBSCURE, 34 gdb.COMPLETE_NONE, True) 35 36 class ShowFilterPrefixCmd(gdb.Command): 37 """Prefix command for 'show' frame-filter related operations.""" 38 def __init__(self): 39 super(ShowFilterPrefixCmd, self).__init__("show frame-filter", 40 gdb.COMMAND_OBSCURE, 41 gdb.COMPLETE_NONE, True) 42 class InfoFrameFilter(gdb.Command): 43 """List all registered Python frame-filters. 44 45 Usage: info frame-filters 46 """ 47 48 def __init__(self): 49 super(InfoFrameFilter, self).__init__("info frame-filter", 50 gdb.COMMAND_DATA) 51 @staticmethod 52 def enabled_string(state): 53 """Return "Yes" if filter is enabled, otherwise "No".""" 54 if state: 55 return "Yes" 56 else: 57 return "No" 58 59 def list_frame_filters(self, frame_filters): 60 """ Internal worker function to list and print frame filters 61 in a dictionary. 62 63 Arguments: 64 frame_filters: The name of the dictionary, as 65 specified by GDB user commands. 66 """ 67 68 sorted_frame_filters = sorted(frame_filters.items(), 69 key=lambda i: gdb.frames.get_priority(i[1]), 70 reverse=True) 71 72 if len(sorted_frame_filters) == 0: 73 print(" No frame filters registered.") 74 else: 75 print(" Priority Enabled Name") 76 for frame_filter in sorted_frame_filters: 77 name = frame_filter[0] 78 try: 79 priority = '{:<8}'.format( 80 str(gdb.frames.get_priority(frame_filter[1]))) 81 enabled = '{:<7}'.format( 82 self.enabled_string(gdb.frames.get_enabled(frame_filter[1]))) 83 except Exception: 84 e = sys.exc_info()[1] 85 print(" Error printing filter '"+name+"': "+str(e)) 86 else: 87 print(" %s %s %s" % (priority, enabled, name)) 88 89 def print_list(self, title, filter_list, blank_line): 90 print(title) 91 self.list_frame_filters(filter_list) 92 if blank_line: 93 print("") 94 95 def invoke(self, arg, from_tty): 96 self.print_list("global frame-filters:", gdb.frame_filters, True) 97 98 cp = gdb.current_progspace() 99 self.print_list("progspace %s frame-filters:" % cp.filename, 100 cp.frame_filters, True) 101 102 for objfile in gdb.objfiles(): 103 self.print_list("objfile %s frame-filters:" % objfile.filename, 104 objfile.frame_filters, False) 105 106 # Internal enable/disable functions. 107 108 def _enable_parse_arg(cmd_name, arg): 109 """ Internal worker function to take an argument from 110 enable/disable and return a tuple of arguments. 111 112 Arguments: 113 cmd_name: Name of the command invoking this function. 114 args: The argument as a string. 115 116 Returns: 117 A tuple containing the dictionary, and the argument, or just 118 the dictionary in the case of "all". 119 """ 120 121 argv = gdb.string_to_argv(arg); 122 argc = len(argv) 123 if argv[0] == "all" and argc > 1: 124 raise gdb.GdbError(cmd_name + ": with 'all' " \ 125 "you may not specify a filter.") 126 else: 127 if argv[0] != "all" and argc != 2: 128 raise gdb.GdbError(cmd_name + " takes exactly two arguments.") 129 130 return argv 131 132 def _do_enable_frame_filter(command_tuple, flag): 133 """Worker for enabling/disabling frame_filters. 134 135 Arguments: 136 command_type: A tuple with the first element being the 137 frame filter dictionary, and the second being 138 the frame filter name. 139 flag: True for Enable, False for Disable. 140 """ 141 142 list_op = command_tuple[0] 143 op_list = gdb.frames.return_list(list_op) 144 145 if list_op == "all": 146 for item in op_list: 147 gdb.frames.set_enabled(item, flag) 148 else: 149 frame_filter = command_tuple[1] 150 try: 151 ff = op_list[frame_filter] 152 except KeyError: 153 msg = "frame-filter '" + str(name) + "' not found." 154 raise gdb.GdbError(msg) 155 156 gdb.frames.set_enabled(ff, flag) 157 158 def _complete_frame_filter_list(text, word, all_flag): 159 """Worker for frame filter dictionary name completion. 160 161 Arguments: 162 text: The full text of the command line. 163 word: The most recent word of the command line. 164 all_flag: Whether to include the word "all" in completion. 165 166 Returns: 167 A list of suggested frame filter dictionary name completions 168 from text/word analysis. This list can be empty when there 169 are no suggestions for completion. 170 """ 171 if all_flag == True: 172 filter_locations = ["all", "global", "progspace"] 173 else: 174 filter_locations = ["global", "progspace"] 175 for objfile in gdb.objfiles(): 176 filter_locations.append(objfile.filename) 177 178 # If the user just asked for completions with no completion 179 # hints, just return all the frame filter dictionaries we know 180 # about. 181 if (text == ""): 182 return filter_locations 183 184 # Otherwise filter on what we know. 185 flist = filter(lambda x,y=text:x.startswith(y), filter_locations) 186 187 # If we only have one completion, complete it and return it. 188 if len(flist) == 1: 189 flist[0] = flist[0][len(text)-len(word):] 190 191 # Otherwise, return an empty list, or a list of frame filter 192 # dictionaries that the previous filter operation returned. 193 return flist 194 195 def _complete_frame_filter_name(word, printer_dict): 196 """Worker for frame filter name completion. 197 198 Arguments: 199 200 word: The most recent word of the command line. 201 202 printer_dict: The frame filter dictionary to search for frame 203 filter name completions. 204 205 Returns: A list of suggested frame filter name completions 206 from word analysis of the frame filter dictionary. This list 207 can be empty when there are no suggestions for completion. 208 """ 209 210 printer_keys = printer_dict.keys() 211 if (word == ""): 212 return printer_keys 213 214 flist = filter(lambda x,y=word:x.startswith(y), printer_keys) 215 return flist 216 217 class EnableFrameFilter(gdb.Command): 218 """GDB command to disable the specified frame-filter. 219 220 Usage: enable frame-filter enable DICTIONARY [NAME] 221 222 DICTIONARY is the name of the frame filter dictionary on which to 223 operate. If dictionary is set to "all", perform operations on all 224 dictionaries. Named dictionaries are: "global" for the global 225 frame filter dictionary, "progspace" for the program space's frame 226 filter dictionary. If either all, or the two named dictionaries 227 are not specified, the dictionary name is assumed to be the name 228 of the object-file name. 229 230 NAME matches the name of the frame-filter to operate on. If 231 DICTIONARY is "all", NAME is ignored. 232 """ 233 def __init__(self): 234 super(EnableFrameFilter, self).__init__("enable frame-filter", 235 gdb.COMMAND_DATA) 236 def complete(self, text, word): 237 """Completion function for both frame filter dictionary, and 238 frame filter name.""" 239 if text.count(" ") == 0: 240 return _complete_frame_filter_list(text, word, True) 241 else: 242 printer_list = gdb.frames.return_list(text.split()[0].rstrip()) 243 return _complete_frame_filter_name(word, printer_list) 244 245 def invoke(self, arg, from_tty): 246 command_tuple = _enable_parse_arg("enable frame-filter", arg) 247 _do_enable_frame_filter(command_tuple, True) 248 249 250 class DisableFrameFilter(gdb.Command): 251 """GDB command to disable the specified frame-filter. 252 253 Usage: disable frame-filter disable DICTIONARY [NAME] 254 255 DICTIONARY is the name of the frame filter dictionary on which to 256 operate. If dictionary is set to "all", perform operations on all 257 dictionaries. Named dictionaries are: "global" for the global 258 frame filter dictionary, "progspace" for the program space's frame 259 filter dictionary. If either all, or the two named dictionaries 260 are not specified, the dictionary name is assumed to be the name 261 of the object-file name. 262 263 NAME matches the name of the frame-filter to operate on. If 264 DICTIONARY is "all", NAME is ignored. 265 """ 266 def __init__(self): 267 super(DisableFrameFilter, self).__init__("disable frame-filter", 268 gdb.COMMAND_DATA) 269 270 def complete(self, text, word): 271 """Completion function for both frame filter dictionary, and 272 frame filter name.""" 273 if text.count(" ") == 0: 274 return _complete_frame_filter_list(text, word, True) 275 else: 276 printer_list = gdb.frames.return_list(text.split()[0].rstrip()) 277 return _complete_frame_filter_name(word, printer_list) 278 279 def invoke(self, arg, from_tty): 280 command_tuple = _enable_parse_arg("disable frame-filter", arg) 281 _do_enable_frame_filter(command_tuple, False) 282 283 class SetFrameFilterPriority(gdb.Command): 284 """GDB command to set the priority of the specified frame-filter. 285 286 Usage: set frame-filter priority DICTIONARY NAME PRIORITY 287 288 DICTIONARY is the name of the frame filter dictionary on which to 289 operate. Named dictionaries are: "global" for the global frame 290 filter dictionary, "progspace" for the program space's framefilter 291 dictionary. If either of these two are not specified, the 292 dictionary name is assumed to be the name of the object-file name. 293 294 NAME matches the name of the frame filter to operate on. 295 296 PRIORITY is the an integer to assign the new priority to the frame 297 filter. 298 """ 299 300 def __init__(self): 301 super(SetFrameFilterPriority, self).__init__("set frame-filter " \ 302 "priority", 303 gdb.COMMAND_DATA) 304 305 def _parse_pri_arg(self, arg): 306 """Internal worker to parse a priority from a tuple. 307 308 Arguments: 309 arg: Tuple which contains the arguments from the command. 310 311 Returns: 312 A tuple containing the dictionary, name and priority from 313 the arguments. 314 315 Raises: 316 gdb.GdbError: An error parsing the arguments. 317 """ 318 319 argv = gdb.string_to_argv(arg); 320 argc = len(argv) 321 if argc != 3: 322 print("set frame-filter priority " \ 323 "takes exactly three arguments.") 324 return None 325 326 return argv 327 328 def _set_filter_priority(self, command_tuple): 329 """Internal worker for setting priority of frame-filters, by 330 parsing a tuple and calling _set_priority with the parsed 331 tuple. 332 333 Arguments: 334 command_tuple: Tuple which contains the arguments from the 335 command. 336 """ 337 338 list_op = command_tuple[0] 339 frame_filter = command_tuple[1] 340 341 # GDB returns arguments as a string, so convert priority to 342 # a number. 343 priority = int(command_tuple[2]) 344 345 op_list = gdb.frames.return_list(list_op) 346 347 try: 348 ff = op_list[frame_filter] 349 except KeyError: 350 msg = "frame-filter '" + str(name) + "' not found." 351 raise gdb.GdbError(msg) 352 353 gdb.frames.set_priority(ff, priority) 354 355 def complete(self, text, word): 356 """Completion function for both frame filter dictionary, and 357 frame filter name.""" 358 if text.count(" ") == 0: 359 return _complete_frame_filter_list(text, word, False) 360 else: 361 printer_list = gdb.frames.return_list(text.split()[0].rstrip()) 362 return _complete_frame_filter_name(word, printer_list) 363 364 def invoke(self, arg, from_tty): 365 command_tuple = self._parse_pri_arg(arg) 366 if command_tuple != None: 367 self._set_filter_priority(command_tuple) 368 369 class ShowFrameFilterPriority(gdb.Command): 370 """GDB command to show the priority of the specified frame-filter. 371 372 Usage: show frame-filter priority DICTIONARY NAME 373 374 DICTIONARY is the name of the frame filter dictionary on which to 375 operate. Named dictionaries are: "global" for the global frame 376 filter dictionary, "progspace" for the program space's framefilter 377 dictionary. If either of these two are not specified, the 378 dictionary name is assumed to be the name of the object-file name. 379 380 NAME matches the name of the frame-filter to operate on. 381 """ 382 383 def __init__(self): 384 super(ShowFrameFilterPriority, self).__init__("show frame-filter " \ 385 "priority", 386 gdb.COMMAND_DATA) 387 388 def _parse_pri_arg(self, arg): 389 """Internal worker to parse a dictionary and name from a 390 tuple. 391 392 Arguments: 393 arg: Tuple which contains the arguments from the command. 394 395 Returns: 396 A tuple containing the dictionary, and frame filter name. 397 398 Raises: 399 gdb.GdbError: An error parsing the arguments. 400 """ 401 402 argv = gdb.string_to_argv(arg); 403 argc = len(argv) 404 if argc != 2: 405 print("show frame-filter priority " \ 406 "takes exactly two arguments.") 407 return None 408 409 return argv 410 411 def get_filter_priority(self, frame_filters, name): 412 """Worker for retrieving the priority of frame_filters. 413 414 Arguments: 415 frame_filters: Name of frame filter dictionary. 416 name: object to select printers. 417 418 Returns: 419 The priority of the frame filter. 420 421 Raises: 422 gdb.GdbError: A frame filter cannot be found. 423 """ 424 425 op_list = gdb.frames.return_list(frame_filters) 426 427 try: 428 ff = op_list[name] 429 except KeyError: 430 msg = "frame-filter '" + str(name) + "' not found." 431 raise gdb.GdbError(msg) 432 433 return gdb.frames.get_priority(ff) 434 435 def complete(self, text, word): 436 """Completion function for both frame filter dictionary, and 437 frame filter name.""" 438 439 if text.count(" ") == 0: 440 return _complete_frame_filter_list(text, word, False) 441 else: 442 printer_list = frame._return_list(text.split()[0].rstrip()) 443 return _complete_frame_filter_name(word, printer_list) 444 445 def invoke(self, arg, from_tty): 446 command_tuple = self._parse_pri_arg(arg) 447 if command_tuple == None: 448 return 449 filter_name = command_tuple[1] 450 list_name = command_tuple[0] 451 try: 452 priority = self.get_filter_priority(list_name, filter_name); 453 except Exception: 454 e = sys.exc_info()[1] 455 print("Error printing filter priority for '"+name+"':"+str(e)) 456 else: 457 print("Priority of filter '" + filter_name + "' in list '" \ 458 + list_name + "' is: " + str(priority)) 459 460 # Register commands 461 SetFilterPrefixCmd() 462 ShowFilterPrefixCmd() 463 InfoFrameFilter() 464 EnableFrameFilter() 465 DisableFrameFilter() 466 SetFrameFilterPriority() 467 ShowFrameFilterPriority() 468