2013-05-10 Phil Muldoon <pmuldoon@redhat.com>
* stack.c (backtrace_command_1): Add "no-filters", and Python frame filter logic. (backtrace_command): Add "no-filters" option parsing. (_initialize_stack): Alter help to reflect "no-filters" option. * Makefile.in (SUBDIR_PYTHON_OBS): Add py-framefilter.o (SUBDIR_PYTHON_SRCS): Add py-framefilter.c (py-frame.o): Add target * data-directory/Makefile.in (PYTHON_DIR): Add Python frame filter files. * python/python.h: Add new frame filter constants, and flag enum. (apply_frame_filter): Add definition. * python/python.c (apply_frame_filter): New non-Python enabled function. * python/py-utils.c (py_xdecref): New function. (make_cleanup_py_xdecref): Ditto. * python/py-objfile.c: Declare frame_filters dictionary. (objfpy_dealloc): Add frame_filters dealloc. (objfpy_new): Initialize frame_filters attribute. (objfile_to_objfile_object): Ditto. (objfpy_get_frame_filters): New function. (objfpy_set_frame_filters): New function. * python/py-progspace.c: Declare frame_filters dictionary. (pspy_dealloc): Add frame_filters dealloc. (pspy_new): Initialize frame_filters attribute. (pspacee_to_pspace_object): Ditto. (pspy_get_frame_filters): New function. (pspy_set_frame_filters): New function. * python/py-framefilter.c: New file. * python/lib/gdb/command/frame_filters.py: New file. * python/lib/gdb/frames.py: New file. * python/lib/gdb/__init__.py: Initialize global frame_filters dictionary * python/lib/gdb/FrameDecorator.py: New file. * python/lib/gdb/FrameIterator.py: New file. * mi/mi-cmds.c (mi_cmds): Add frame filters command. * mi/mi-cmds.h: Declare. * mi/mi-cmd-stack.c (mi_cmd_stack_list_frames): Add --no-frame-filter logic, and Python frame filter logic. (stack_enable_frame_filters): New function. (parse_no_frame_option): Ditto. (mi_cmd_stack_list_frames): Add --no-frame-filter and Python frame filter logic. (mi_cmd_stack_list_locals): Ditto. (mi_cmd_stack_list_args): Ditto. (mi_cmd_stack_list_variables): Ditto. * NEWS: Add frame filter note. 2013-05-10 Phil Muldoon <pmuldoon@redhat.com> * gdb.python/py-framefilter.py: New File. * gdb.python/py-framefilter-mi.exp: Ditto. * gdb.python/py-framefilter.c: Ditto. * gdb.python/py-framefilter-mi.exp: Ditto. * gdb.python/py-framefilter-mi.c: Ditto, * gdb.python/py-framefilter-gdb.py.in: Ditto. 2013-05-10 Phil Muldoon <pmuldoon@redhat.com> * gdb.texinfo (Backtrace): Add "no-filter" argument. (Python API): Add Frame Filters API, Frame Wrapper API, Writing a Frame Filter/Wrapper, Managing Management of Frame Filters chapter entries. (Frame Filters API): New Node. (Frame Wrapper API): New Node. (Writing a Frame Filter): New Node. (Managing Frame Filters): New Node. (Progspaces In Python): Add note about frame_filters attribute. (Objfiles in Python): Ditto. (GDB/MI Stack Manipulation): Add -enable-frame-filters command, @anchors and --no-frame-filters option to -stack-list-variables, -stack-list-frames, -stack-list-locals and -stack-list-arguments commands.
This commit is contained in:
parent
3ecb733811
commit
1e611234ee
29 changed files with 4846 additions and 88 deletions
285
gdb/python/lib/gdb/FrameDecorator.py
Normal file
285
gdb/python/lib/gdb/FrameDecorator.py
Normal file
|
@ -0,0 +1,285 @@
|
|||
# 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/>.
|
||||
|
||||
import gdb
|
||||
|
||||
class FrameDecorator(object):
|
||||
"""Basic implementation of a Frame Decorator"""
|
||||
|
||||
""" This base frame decorator decorates a frame or another frame
|
||||
decorator, and provides convenience methods. If this object is
|
||||
wrapping a frame decorator, defer to that wrapped object's method
|
||||
if it has one. This allows for frame decorators that have
|
||||
sub-classed FrameDecorator object, but also wrap other frame
|
||||
decorators on the same frame to correctly execute.
|
||||
|
||||
E.g
|
||||
|
||||
If the result of frame filters running means we have one gdb.Frame
|
||||
wrapped by multiple frame decorators, all sub-classed from
|
||||
FrameDecorator, the resulting hierarchy will be:
|
||||
|
||||
Decorator1
|
||||
-- (wraps) Decorator2
|
||||
-- (wraps) FrameDecorator
|
||||
-- (wraps) gdb.Frame
|
||||
|
||||
In this case we have two frame decorators, both of which are
|
||||
sub-classed from FrameDecorator. If Decorator1 just overrides the
|
||||
'function' method, then all of the other methods are carried out
|
||||
by the super-class FrameDecorator. But Decorator2 may have
|
||||
overriden other methods, so FrameDecorator will look at the
|
||||
'base' parameter and defer to that class's methods. And so on,
|
||||
down the chain."""
|
||||
|
||||
# 'base' can refer to a gdb.Frame or another frame decorator. In
|
||||
# the latter case, the child class will have called the super
|
||||
# method and _base will be an object conforming to the Frame Filter
|
||||
# class.
|
||||
def __init__(self, base):
|
||||
self._base = base
|
||||
|
||||
@staticmethod
|
||||
def _is_limited_frame(frame):
|
||||
"""Internal utility to determine if the frame is special or
|
||||
limited."""
|
||||
sal = frame.find_sal()
|
||||
|
||||
if (not sal.symtab or not sal.symtab.filename
|
||||
or frame.type() == gdb.DUMMY_FRAME
|
||||
or frame.type() == gdb.SIGTRAMP_FRAME):
|
||||
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def elided(self):
|
||||
"""Return any elided frames that this class might be
|
||||
wrapping, or None."""
|
||||
if hasattr(self._base, "elided"):
|
||||
return self._base.elided()
|
||||
|
||||
return None
|
||||
|
||||
def function(self):
|
||||
""" Return the name of the frame's function or an address of
|
||||
the function of the frame. First determine if this is a
|
||||
special frame. If not, try to determine filename from GDB's
|
||||
frame internal function API. Finally, if a name cannot be
|
||||
determined return the address. If this function returns an
|
||||
address, GDB will attempt to determine the function name from
|
||||
its internal minimal symbols store (for example, for inferiors
|
||||
without debug-info)."""
|
||||
|
||||
# Both gdb.Frame, and FrameDecorator have a method called
|
||||
# "function", so determine which object this is.
|
||||
if not isinstance(self._base, gdb.Frame):
|
||||
if hasattr(self._base, "function"):
|
||||
# If it is not a gdb.Frame, and there is already a
|
||||
# "function" method, use that.
|
||||
return self._base.function()
|
||||
|
||||
frame = self.inferior_frame()
|
||||
|
||||
if frame.type() == gdb.DUMMY_FRAME:
|
||||
return "<function called from gdb>"
|
||||
elif frame.type() == gdb.SIGTRAMP_FRAME:
|
||||
return "<signal handler called>"
|
||||
|
||||
func = frame.function()
|
||||
|
||||
# If we cannot determine the function name, return the
|
||||
# address. If GDB detects an integer value from this function
|
||||
# it will attempt to find the function name from minimal
|
||||
# symbols via its own internal functions.
|
||||
if func == None:
|
||||
pc = frame.pc()
|
||||
return pc
|
||||
|
||||
return str(func)
|
||||
|
||||
def address(self):
|
||||
""" Return the address of the frame's pc"""
|
||||
|
||||
if hasattr(self._base, "address"):
|
||||
return self._base.address()
|
||||
|
||||
frame = self.inferior_frame()
|
||||
return frame.pc()
|
||||
|
||||
def filename(self):
|
||||
""" Return the filename associated with this frame, detecting
|
||||
and returning the appropriate library name is this is a shared
|
||||
library."""
|
||||
|
||||
if hasattr(self._base, "filename"):
|
||||
return self._base.filename()
|
||||
|
||||
frame = self.inferior_frame()
|
||||
sal = frame.find_sal()
|
||||
if not sal.symtab or not sal.symtab.filename:
|
||||
pc = frame.pc()
|
||||
return gdb.solib_name(pc)
|
||||
else:
|
||||
return sal.symtab.filename
|
||||
|
||||
def frame_args(self):
|
||||
""" Return an iterable of frame arguments for this frame, if
|
||||
any. The iterable object contains objects conforming with the
|
||||
Symbol/Value interface. If there are no frame arguments, or
|
||||
if this frame is deemed to be a special case, return None."""
|
||||
|
||||
if hasattr(self._base, "frame_args"):
|
||||
return self._base.frame_args()
|
||||
|
||||
frame = self.inferior_frame()
|
||||
if self._is_limited_frame(frame):
|
||||
return None
|
||||
|
||||
args = FrameVars(frame)
|
||||
return args.fetch_frame_args()
|
||||
|
||||
def frame_locals(self):
|
||||
""" Return an iterable of local variables for this frame, if
|
||||
any. The iterable object contains objects conforming with the
|
||||
Symbol/Value interface. If there are no frame locals, or if
|
||||
this frame is deemed to be a special case, return None."""
|
||||
|
||||
if hasattr(self._base, "frame_locals"):
|
||||
return self._base.frame_locals()
|
||||
|
||||
frame = self.inferior_frame()
|
||||
if self._is_limited_frame(frame):
|
||||
return None
|
||||
|
||||
args = FrameVars(frame)
|
||||
return args.fetch_frame_locals()
|
||||
|
||||
def line(self):
|
||||
""" Return line number information associated with the frame's
|
||||
pc. If symbol table/line information does not exist, or if
|
||||
this frame is deemed to be a special case, return None"""
|
||||
|
||||
if hasattr(self._base, "line"):
|
||||
return self._base.line()
|
||||
|
||||
frame = self.inferior_frame()
|
||||
if self._is_limited_frame(frame):
|
||||
return None
|
||||
|
||||
sal = frame.find_sal()
|
||||
if (sal):
|
||||
return sal.line
|
||||
else:
|
||||
return None
|
||||
|
||||
def inferior_frame(self):
|
||||
""" Return the gdb.Frame underpinning this frame decorator."""
|
||||
|
||||
# If 'base' is a frame decorator, we want to call its inferior
|
||||
# frame method. If '_base' is a gdb.Frame, just return that.
|
||||
if hasattr(self._base, "inferior_frame"):
|
||||
return self._base.inferior_frame()
|
||||
return self._base
|
||||
|
||||
class SymValueWrapper(object):
|
||||
"""A container class conforming to the Symbol/Value interface
|
||||
which holds frame locals or frame arguments."""
|
||||
def __init__(self, symbol, value):
|
||||
self.sym = symbol
|
||||
self.val = value
|
||||
|
||||
def value(self):
|
||||
""" Return the value associated with this symbol, or None"""
|
||||
return self.val
|
||||
|
||||
def symbol(self):
|
||||
""" Return the symbol, or Python text, associated with this
|
||||
symbol, or None"""
|
||||
return self.sym
|
||||
|
||||
class FrameVars(object):
|
||||
|
||||
"""Utility class to fetch and store frame local variables, or
|
||||
frame arguments."""
|
||||
|
||||
def __init__(self, frame):
|
||||
self.frame = frame
|
||||
self.symbol_class = {
|
||||
gdb.SYMBOL_LOC_STATIC: True,
|
||||
gdb.SYMBOL_LOC_REGISTER: True,
|
||||
gdb.SYMBOL_LOC_ARG: True,
|
||||
gdb.SYMBOL_LOC_REF_ARG: True,
|
||||
gdb.SYMBOL_LOC_LOCAL: True,
|
||||
gdb.SYMBOL_LOC_REGPARM_ADDR: True,
|
||||
gdb.SYMBOL_LOC_COMPUTED: True
|
||||
}
|
||||
|
||||
def fetch_b(self, sym):
|
||||
""" Local utility method to determine if according to Symbol
|
||||
type whether it should be included in the iterator. Not all
|
||||
symbols are fetched, and only symbols that return
|
||||
True from this method should be fetched."""
|
||||
|
||||
# SYM may be a string instead of a symbol in the case of
|
||||
# synthetic local arguments or locals. If that is the case,
|
||||
# always fetch.
|
||||
if isinstance(sym, basestring):
|
||||
return True
|
||||
|
||||
sym_type = sym.addr_class
|
||||
|
||||
return self.symbol_class.get(sym_type, False)
|
||||
|
||||
def fetch_frame_locals(self):
|
||||
"""Public utility method to fetch frame local variables for
|
||||
the stored frame. Frame arguments are not fetched. If there
|
||||
are no frame local variables, return an empty list."""
|
||||
lvars = []
|
||||
|
||||
block = self.frame.block()
|
||||
|
||||
while block != None:
|
||||
if block.is_global or block.is_static:
|
||||
break
|
||||
for sym in block:
|
||||
if sym.is_argument:
|
||||
continue;
|
||||
if self.fetch_b(sym):
|
||||
lvars.append(SymValueWrapper(sym, None))
|
||||
|
||||
block = block.superblock
|
||||
|
||||
return lvars
|
||||
|
||||
def fetch_frame_args(self):
|
||||
"""Public utility method to fetch frame arguments for the
|
||||
stored frame. Frame arguments are the only type fetched. If
|
||||
there are no frame argument variables, return an empty list."""
|
||||
|
||||
args = []
|
||||
block = self.frame.block()
|
||||
while block != None:
|
||||
if block.function != None:
|
||||
break
|
||||
block = block.superblock
|
||||
|
||||
if block != None:
|
||||
for sym in block:
|
||||
if not sym.is_argument:
|
||||
continue;
|
||||
args.append(SymValueWrapper(sym, None))
|
||||
|
||||
return args
|
45
gdb/python/lib/gdb/FrameIterator.py
Normal file
45
gdb/python/lib/gdb/FrameIterator.py
Normal file
|
@ -0,0 +1,45 @@
|
|||
# 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/>.
|
||||
|
||||
import gdb
|
||||
import itertools
|
||||
|
||||
class FrameIterator(object):
|
||||
"""A gdb.Frame iterator. Iterates over gdb.Frames or objects that
|
||||
conform to that interface."""
|
||||
|
||||
def __init__(self, frame_obj):
|
||||
"""Initialize a FrameIterator.
|
||||
|
||||
Arguments:
|
||||
frame_obj the starting frame."""
|
||||
|
||||
super(FrameIterator, self).__init__()
|
||||
self.frame = frame_obj
|
||||
|
||||
def __iter__(self):
|
||||
return self
|
||||
|
||||
def next(self):
|
||||
"""next implementation.
|
||||
|
||||
Returns:
|
||||
The next oldest frame."""
|
||||
|
||||
result = self.frame
|
||||
if result is None:
|
||||
raise StopIteration
|
||||
self.frame = result.older()
|
||||
return result
|
|
@ -67,6 +67,8 @@ pretty_printers = []
|
|||
|
||||
# Initial type printers.
|
||||
type_printers = []
|
||||
# Initial frame filters.
|
||||
frame_filters = {}
|
||||
|
||||
# Convenience variable to GDB's python directory
|
||||
PYTHONDIR = os.path.dirname(os.path.dirname(__file__))
|
||||
|
|
461
gdb/python/lib/gdb/command/frame_filters.py
Normal file
461
gdb/python/lib/gdb/command/frame_filters.py
Normal file
|
@ -0,0 +1,461 @@
|
|||
# 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/>.
|
||||
|
||||
"""GDB commands for working with frame-filters."""
|
||||
|
||||
import gdb
|
||||
import copy
|
||||
from gdb.FrameIterator import FrameIterator
|
||||
from gdb.FrameDecorator import FrameDecorator
|
||||
import gdb.frames
|
||||
import itertools
|
||||
|
||||
# GDB Commands.
|
||||
class SetFilterPrefixCmd(gdb.Command):
|
||||
"""Prefix command for 'set' frame-filter related operations."""
|
||||
|
||||
def __init__(self):
|
||||
super(SetFilterPrefixCmd, self).__init__("set frame-filter",
|
||||
gdb.COMMAND_OBSCURE,
|
||||
gdb.COMPLETE_NONE, True)
|
||||
|
||||
class ShowFilterPrefixCmd(gdb.Command):
|
||||
"""Prefix command for 'show' frame-filter related operations."""
|
||||
def __init__(self):
|
||||
super(ShowFilterPrefixCmd, self).__init__("show frame-filter",
|
||||
gdb.COMMAND_OBSCURE,
|
||||
gdb.COMPLETE_NONE, True)
|
||||
class InfoFrameFilter(gdb.Command):
|
||||
"""List all registered Python frame-filters.
|
||||
|
||||
Usage: info frame-filters
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super(InfoFrameFilter, self).__init__("info frame-filter",
|
||||
gdb.COMMAND_DATA)
|
||||
@staticmethod
|
||||
def enabled_string(state):
|
||||
"""Return "Yes" if filter is enabled, otherwise "No"."""
|
||||
if state:
|
||||
return "Yes"
|
||||
else:
|
||||
return "No"
|
||||
|
||||
def list_frame_filters(self, frame_filters):
|
||||
""" Internal worker function to list and print frame filters
|
||||
in a dictionary.
|
||||
|
||||
Arguments:
|
||||
frame_filters: The name of the dictionary, as
|
||||
specified by GDB user commands.
|
||||
"""
|
||||
|
||||
sorted_frame_filters = sorted(frame_filters.items(),
|
||||
key=lambda i: gdb.frames.get_priority(i[1]),
|
||||
reverse=True)
|
||||
|
||||
if len(sorted_frame_filters) == 0:
|
||||
print(" No frame filters registered.")
|
||||
else:
|
||||
print(" Priority Enabled Name")
|
||||
for frame_filter in sorted_frame_filters:
|
||||
name = frame_filter[0]
|
||||
try:
|
||||
priority = '{:<8}'.format(
|
||||
str(gdb.frames.get_priority(frame_filter[1])))
|
||||
enabled = '{:<7}'.format(
|
||||
self.enabled_string(gdb.frames.get_enabled(frame_filter[1])))
|
||||
except Exception as e:
|
||||
print(" Error printing filter '"+name+"': "+str(e))
|
||||
else:
|
||||
print(" %s %s %s" % (priority, enabled, name))
|
||||
|
||||
def print_list(self, title, filter_list, blank_line):
|
||||
print(title)
|
||||
self.list_frame_filters(filter_list)
|
||||
if blank_line:
|
||||
print("")
|
||||
|
||||
def invoke(self, arg, from_tty):
|
||||
self.print_list("global frame-filters:", gdb.frame_filters, True)
|
||||
|
||||
cp = gdb.current_progspace()
|
||||
self.print_list("progspace %s frame-filters:" % cp.filename,
|
||||
cp.frame_filters, True)
|
||||
|
||||
for objfile in gdb.objfiles():
|
||||
self.print_list("objfile %s frame-filters:" % objfile.filename,
|
||||
objfile.frame_filters, False)
|
||||
|
||||
# Internal enable/disable functions.
|
||||
|
||||
def _enable_parse_arg(cmd_name, arg):
|
||||
""" Internal worker function to take an argument from
|
||||
enable/disable and return a tuple of arguments.
|
||||
|
||||
Arguments:
|
||||
cmd_name: Name of the command invoking this function.
|
||||
args: The argument as a string.
|
||||
|
||||
Returns:
|
||||
A tuple containing the dictionary, and the argument, or just
|
||||
the dictionary in the case of "all".
|
||||
"""
|
||||
|
||||
argv = gdb.string_to_argv(arg);
|
||||
argc = len(argv)
|
||||
if argv[0] == "all" and argc > 1:
|
||||
raise gdb.GdbError(cmd_name + ": with 'all' " \
|
||||
"you may not specify a filter.")
|
||||
else:
|
||||
if argv[0] != "all" and argc != 2:
|
||||
raise gdb.GdbError(cmd_name + " takes exactly two arguments.")
|
||||
|
||||
return argv
|
||||
|
||||
def _do_enable_frame_filter(command_tuple, flag):
|
||||
"""Worker for enabling/disabling frame_filters.
|
||||
|
||||
Arguments:
|
||||
command_type: A tuple with the first element being the
|
||||
frame filter dictionary, and the second being
|
||||
the frame filter name.
|
||||
flag: True for Enable, False for Disable.
|
||||
"""
|
||||
|
||||
list_op = command_tuple[0]
|
||||
op_list = gdb.frames.return_list(list_op)
|
||||
|
||||
if list_op == "all":
|
||||
for item in op_list:
|
||||
gdb.frames.set_enabled(item, flag)
|
||||
else:
|
||||
frame_filter = command_tuple[1]
|
||||
try:
|
||||
ff = op_list[frame_filter]
|
||||
except KeyError:
|
||||
msg = "frame-filter '" + str(name) + "' not found."
|
||||
raise gdb.GdbError(msg)
|
||||
|
||||
gdb.frames.set_enabled(ff, flag)
|
||||
|
||||
def _complete_frame_filter_list(text, word, all_flag):
|
||||
"""Worker for frame filter dictionary name completion.
|
||||
|
||||
Arguments:
|
||||
text: The full text of the command line.
|
||||
word: The most recent word of the command line.
|
||||
all_flag: Whether to include the word "all" in completion.
|
||||
|
||||
Returns:
|
||||
A list of suggested frame filter dictionary name completions
|
||||
from text/word analysis. This list can be empty when there
|
||||
are no suggestions for completion.
|
||||
"""
|
||||
if all_flag == True:
|
||||
filter_locations = ["all", "global", "progspace"]
|
||||
else:
|
||||
filter_locations = ["global", "progspace"]
|
||||
for objfile in gdb.objfiles():
|
||||
filter_locations.append(objfile.filename)
|
||||
|
||||
# If the user just asked for completions with no completion
|
||||
# hints, just return all the frame filter dictionaries we know
|
||||
# about.
|
||||
if (text == ""):
|
||||
return filter_locations
|
||||
|
||||
# Otherwise filter on what we know.
|
||||
flist = filter(lambda x,y=text:x.startswith(y), filter_locations)
|
||||
|
||||
# If we only have one completion, complete it and return it.
|
||||
if len(flist) == 1:
|
||||
flist[0] = flist[0][len(text)-len(word):]
|
||||
|
||||
# Otherwise, return an empty list, or a list of frame filter
|
||||
# dictionaries that the previous filter operation returned.
|
||||
return flist
|
||||
|
||||
def _complete_frame_filter_name(word, printer_dict):
|
||||
"""Worker for frame filter name completion.
|
||||
|
||||
Arguments:
|
||||
|
||||
word: The most recent word of the command line.
|
||||
|
||||
printer_dict: The frame filter dictionary to search for frame
|
||||
filter name completions.
|
||||
|
||||
Returns: A list of suggested frame filter name completions
|
||||
from word analysis of the frame filter dictionary. This list
|
||||
can be empty when there are no suggestions for completion.
|
||||
"""
|
||||
|
||||
printer_keys = printer_dict.keys()
|
||||
if (word == ""):
|
||||
return printer_keys
|
||||
|
||||
flist = filter(lambda x,y=word:x.startswith(y), printer_keys)
|
||||
return flist
|
||||
|
||||
class EnableFrameFilter(gdb.Command):
|
||||
"""GDB command to disable the specified frame-filter.
|
||||
|
||||
Usage: enable frame-filter enable DICTIONARY [NAME]
|
||||
|
||||
DICTIONARY is the name of the frame filter dictionary on which to
|
||||
operate. If dictionary is set to "all", perform operations on all
|
||||
dictionaries. Named dictionaries are: "global" for the global
|
||||
frame filter dictionary, "progspace" for the program space's frame
|
||||
filter dictionary. If either all, or the two named dictionaries
|
||||
are not specified, the dictionary name is assumed to be the name
|
||||
of the object-file name.
|
||||
|
||||
NAME matches the name of the frame-filter to operate on. If
|
||||
DICTIONARY is "all", NAME is ignored.
|
||||
"""
|
||||
def __init__(self):
|
||||
super(EnableFrameFilter, self).__init__("enable frame-filter",
|
||||
gdb.COMMAND_DATA)
|
||||
def complete(self, text, word):
|
||||
"""Completion function for both frame filter dictionary, and
|
||||
frame filter name."""
|
||||
if text.count(" ") == 0:
|
||||
return _complete_frame_filter_list(text, word, True)
|
||||
else:
|
||||
printer_list = gdb.frames.return_list(text.split()[0].rstrip())
|
||||
return _complete_frame_filter_name(word, printer_list)
|
||||
|
||||
def invoke(self, arg, from_tty):
|
||||
command_tuple = _enable_parse_arg("enable frame-filter", arg)
|
||||
_do_enable_frame_filter(command_tuple, True)
|
||||
|
||||
|
||||
class DisableFrameFilter(gdb.Command):
|
||||
"""GDB command to disable the specified frame-filter.
|
||||
|
||||
Usage: disable frame-filter disable DICTIONARY [NAME]
|
||||
|
||||
DICTIONARY is the name of the frame filter dictionary on which to
|
||||
operate. If dictionary is set to "all", perform operations on all
|
||||
dictionaries. Named dictionaries are: "global" for the global
|
||||
frame filter dictionary, "progspace" for the program space's frame
|
||||
filter dictionary. If either all, or the two named dictionaries
|
||||
are not specified, the dictionary name is assumed to be the name
|
||||
of the object-file name.
|
||||
|
||||
NAME matches the name of the frame-filter to operate on. If
|
||||
DICTIONARY is "all", NAME is ignored.
|
||||
"""
|
||||
def __init__(self):
|
||||
super(DisableFrameFilter, self).__init__("disable frame-filter",
|
||||
gdb.COMMAND_DATA)
|
||||
|
||||
def complete(self, text, word):
|
||||
"""Completion function for both frame filter dictionary, and
|
||||
frame filter name."""
|
||||
if text.count(" ") == 0:
|
||||
return _complete_frame_filter_list(text, word, True)
|
||||
else:
|
||||
printer_list = gdb.frames.return_list(text.split()[0].rstrip())
|
||||
return _complete_frame_filter_name(word, printer_list)
|
||||
|
||||
def invoke(self, arg, from_tty):
|
||||
command_tuple = _enable_parse_arg("disable frame-filter", arg)
|
||||
_do_enable_frame_filter(command_tuple, False)
|
||||
|
||||
class SetFrameFilterPriority(gdb.Command):
|
||||
"""GDB command to set the priority of the specified frame-filter.
|
||||
|
||||
Usage: set frame-filter priority DICTIONARY NAME PRIORITY
|
||||
|
||||
DICTIONARY is the name of the frame filter dictionary on which to
|
||||
operate. Named dictionaries are: "global" for the global frame
|
||||
filter dictionary, "progspace" for the program space's framefilter
|
||||
dictionary. If either of these two are not specified, the
|
||||
dictionary name is assumed to be the name of the object-file name.
|
||||
|
||||
NAME matches the name of the frame filter to operate on.
|
||||
|
||||
PRIORITY is the an integer to assign the new priority to the frame
|
||||
filter.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super(SetFrameFilterPriority, self).__init__("set frame-filter " \
|
||||
"priority",
|
||||
gdb.COMMAND_DATA)
|
||||
|
||||
def _parse_pri_arg(self, arg):
|
||||
"""Internal worker to parse a priority from a tuple.
|
||||
|
||||
Arguments:
|
||||
arg: Tuple which contains the arguments from the command.
|
||||
|
||||
Returns:
|
||||
A tuple containing the dictionary, name and priority from
|
||||
the arguments.
|
||||
|
||||
Raises:
|
||||
gdb.GdbError: An error parsing the arguments.
|
||||
"""
|
||||
|
||||
argv = gdb.string_to_argv(arg);
|
||||
argc = len(argv)
|
||||
if argc != 3:
|
||||
print("set frame-filter priority " \
|
||||
"takes exactly three arguments.")
|
||||
return None
|
||||
|
||||
return argv
|
||||
|
||||
def _set_filter_priority(self, command_tuple):
|
||||
"""Internal worker for setting priority of frame-filters, by
|
||||
parsing a tuple and calling _set_priority with the parsed
|
||||
tuple.
|
||||
|
||||
Arguments:
|
||||
command_tuple: Tuple which contains the arguments from the
|
||||
command.
|
||||
"""
|
||||
|
||||
list_op = command_tuple[0]
|
||||
frame_filter = command_tuple[1]
|
||||
priority = command_tuple[2]
|
||||
|
||||
op_list = gdb.frames.return_list(list_op)
|
||||
|
||||
try:
|
||||
ff = op_list[frame_filter]
|
||||
except KeyError:
|
||||
msg = "frame-filter '" + str(name) + "' not found."
|
||||
raise gdb.GdbError(msg)
|
||||
|
||||
gdb.frames.set_priority(ff, priority)
|
||||
|
||||
def complete(self, text, word):
|
||||
"""Completion function for both frame filter dictionary, and
|
||||
frame filter name."""
|
||||
if text.count(" ") == 0:
|
||||
return _complete_frame_filter_list(text, word, False)
|
||||
else:
|
||||
printer_list = gdb.frames.return_list(text.split()[0].rstrip())
|
||||
return _complete_frame_filter_name(word, printer_list)
|
||||
|
||||
def invoke(self, arg, from_tty):
|
||||
command_tuple = self._parse_pri_arg(arg)
|
||||
if command_tuple != None:
|
||||
self._set_filter_priority(command_tuple)
|
||||
|
||||
class ShowFrameFilterPriority(gdb.Command):
|
||||
"""GDB command to show the priority of the specified frame-filter.
|
||||
|
||||
Usage: show frame-filter priority DICTIONARY NAME
|
||||
|
||||
DICTIONARY is the name of the frame filter dictionary on which to
|
||||
operate. Named dictionaries are: "global" for the global frame
|
||||
filter dictionary, "progspace" for the program space's framefilter
|
||||
dictionary. If either of these two are not specified, the
|
||||
dictionary name is assumed to be the name of the object-file name.
|
||||
|
||||
NAME matches the name of the frame-filter to operate on.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super(ShowFrameFilterPriority, self).__init__("show frame-filter " \
|
||||
"priority",
|
||||
gdb.COMMAND_DATA)
|
||||
|
||||
def _parse_pri_arg(self, arg):
|
||||
"""Internal worker to parse a dictionary and name from a
|
||||
tuple.
|
||||
|
||||
Arguments:
|
||||
arg: Tuple which contains the arguments from the command.
|
||||
|
||||
Returns:
|
||||
A tuple containing the dictionary, and frame filter name.
|
||||
|
||||
Raises:
|
||||
gdb.GdbError: An error parsing the arguments.
|
||||
"""
|
||||
|
||||
argv = gdb.string_to_argv(arg);
|
||||
argc = len(argv)
|
||||
if argc != 2:
|
||||
print("show frame-filter priority " \
|
||||
"takes exactly two arguments.")
|
||||
return None
|
||||
|
||||
return argv
|
||||
|
||||
def get_filter_priority(self, frame_filters, name):
|
||||
"""Worker for retrieving the priority of frame_filters.
|
||||
|
||||
Arguments:
|
||||
frame_filters: Name of frame filter dictionary.
|
||||
name: object to select printers.
|
||||
|
||||
Returns:
|
||||
The priority of the frame filter.
|
||||
|
||||
Raises:
|
||||
gdb.GdbError: A frame filter cannot be found.
|
||||
"""
|
||||
|
||||
op_list = gdb.frames.return_list(frame_filters)
|
||||
|
||||
try:
|
||||
ff = op_list[name]
|
||||
except KeyError:
|
||||
msg = "frame-filter '" + str(name) + "' not found."
|
||||
raise gdb.GdbError(msg)
|
||||
|
||||
return gdb.frames.get_priority(ff)
|
||||
|
||||
def complete(self, text, word):
|
||||
"""Completion function for both frame filter dictionary, and
|
||||
frame filter name."""
|
||||
|
||||
if text.count(" ") == 0:
|
||||
return _complete_frame_filter_list(text, word, False)
|
||||
else:
|
||||
printer_list = frame._return_list(text.split()[0].rstrip())
|
||||
return _complete_frame_filter_name(word, printer_list)
|
||||
|
||||
def invoke(self, arg, from_tty):
|
||||
command_tuple = self._parse_pri_arg(arg)
|
||||
if command_tuple == None:
|
||||
return
|
||||
filter_name = command_tuple[1]
|
||||
list_name = command_tuple[0]
|
||||
try:
|
||||
priority = self.get_filter_priority(list_name, filter_name);
|
||||
except Exception as e:
|
||||
print("Error printing filter priority for '"+name+"':"+str(e))
|
||||
else:
|
||||
print("Priority of filter '" + filter_name + "' in list '" \
|
||||
+ list_name + "' is: " + str(priority))
|
||||
|
||||
# Register commands
|
||||
SetFilterPrefixCmd()
|
||||
ShowFilterPrefixCmd()
|
||||
InfoFrameFilter()
|
||||
EnableFrameFilter()
|
||||
DisableFrameFilter()
|
||||
SetFrameFilterPriority()
|
||||
ShowFrameFilterPriority()
|
229
gdb/python/lib/gdb/frames.py
Normal file
229
gdb/python/lib/gdb/frames.py
Normal file
|
@ -0,0 +1,229 @@
|
|||
# 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 list.
|
||||
if name == "all":
|
||||
all_dicts = gdb.frame_filters.values()
|
||||
all_dicts = all_dicts + gdb.current_progspace().frame_filters.values()
|
||||
for objfile in gdb.objfiles():
|
||||
all_dicts = all_dicts + objfile.frame_filters.values()
|
||||
return all_dicts
|
||||
|
||||
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 = []
|
||||
for objfile in gdb.objfiles():
|
||||
all_filters = all_filters + objfile.frame_filters.values()
|
||||
cp = gdb.current_progspace()
|
||||
|
||||
all_filters = all_filters + cp.frame_filters.values()
|
||||
all_filters = all_filters + gdb.frame_filters.values()
|
||||
|
||||
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 = _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.
|
||||
frame_iterator = itertools.imap(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
|
Loading…
Add table
Add a link
Reference in a new issue