# Frame-filter commands.
|
# Copyright (C) 2013-2021 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 sys
|
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 print_list(self, title, frame_filters, blank_line):
|
sorted_frame_filters = sorted(frame_filters.items(),
|
key=lambda i: gdb.frames.get_priority(i[1]),
|
reverse=True)
|
|
if len(sorted_frame_filters) == 0:
|
return 0
|
|
print(title)
|
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])))
|
print(" %s %s %s" % (priority, enabled, name))
|
except Exception:
|
e = sys.exc_info()[1]
|
print(" Error printing filter '"+name+"': "+str(e))
|
if blank_line:
|
print("")
|
return 1
|
|
def invoke(self, arg, from_tty):
|
any_printed = self.print_list("global frame-filters:", gdb.frame_filters, True)
|
|
cp = gdb.current_progspace()
|
any_printed += self.print_list("progspace %s frame-filters:" % cp.filename,
|
cp.frame_filters, True)
|
|
for objfile in gdb.objfiles():
|
any_printed += self.print_list("objfile %s frame-filters:" % objfile.filename,
|
objfile.frame_filters, False)
|
|
if any_printed == 0:
|
print ("No frame filters.")
|
|
# 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 argc == 0:
|
raise gdb.GdbError(cmd_name + " requires an argument")
|
if argv[0] == "all":
|
if argc > 1:
|
raise gdb.GdbError(cmd_name + ": with 'all' " \
|
"you may not specify a filter.")
|
elif 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(frame_filter) + "' 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 enable the specified frame-filter.
|
|
Usage: enable frame-filter 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 an "objfile" -- a shared library or an executable.
|
|
NAME matches the name of the frame-filter to operate on."""
|
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 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 an "objfile" -- a shared library or an executable.
|
|
NAME matches the name of the frame-filter to operate on."""
|
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 an "objfile" -- a
|
shared library or an executable.
|
|
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]
|
|
# GDB returns arguments as a string, so convert priority to
|
# a number.
|
priority = int(command_tuple[2])
|
|
op_list = gdb.frames.return_list(list_op)
|
|
try:
|
ff = op_list[frame_filter]
|
except KeyError:
|
msg = "frame-filter '" + str(frame_filter) + "' 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 an "objfile" -- a
|
shared library or an executable.
|
|
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:
|
e = sys.exc_info()[1]
|
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()
|