274 lines
10 KiB
Python
274 lines
10 KiB
Python
# Xmethod commands.
|
|
# Copyright 2013-2016 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 re
|
|
|
|
"""GDB commands for working with xmethods."""
|
|
|
|
|
|
def validate_xm_regexp(part_name, regexp):
|
|
try:
|
|
return re.compile(regexp)
|
|
except SyntaxError:
|
|
raise SyntaxError("Invalid %s regexp: %s", part_name, regexp)
|
|
|
|
|
|
def parse_xm_command_args(arg):
|
|
"""Parses the arguments passed to a xmethod command.
|
|
|
|
Arguments:
|
|
arg: The argument string passed to a xmethod command.
|
|
|
|
Returns:
|
|
A 3-tuple: (<locus matching regular expression>,
|
|
<matcher matching regular expression>,
|
|
<name matching regular experession>)
|
|
"""
|
|
argv = gdb.string_to_argv(arg)
|
|
argc = len(argv)
|
|
if argc > 2:
|
|
raise SyntaxError("Too many arguments to command.")
|
|
locus_regexp = ""
|
|
matcher_name_regexp = ""
|
|
xm_name_regexp = None
|
|
if argc >= 1:
|
|
locus_regexp = argv[0]
|
|
if argc == 2:
|
|
parts = argv[1].split(";", 1)
|
|
matcher_name_regexp = parts[0]
|
|
if len(parts) > 1:
|
|
xm_name_regexp = parts[1]
|
|
if xm_name_regexp:
|
|
name_re = validate_xm_regexp("xmethod name", xm_name_regexp)
|
|
else:
|
|
name_re = None
|
|
return (validate_xm_regexp("locus", locus_regexp),
|
|
validate_xm_regexp("matcher name", matcher_name_regexp),
|
|
name_re)
|
|
|
|
|
|
def get_global_method_matchers(locus_re, matcher_re):
|
|
"""Returns a dict of matching globally registered xmethods.
|
|
|
|
Arguments:
|
|
locus_re: Even though only globally registered xmethods are
|
|
looked up, they will be looked up only if 'global' matches
|
|
LOCUS_RE.
|
|
matcher_re: The regular expression matching the names of xmethods.
|
|
|
|
Returns:
|
|
A dict of matching globally registered xmethod matchers. The only
|
|
key in the dict will be 'global'.
|
|
"""
|
|
locus_str = "global"
|
|
xm_dict = { locus_str: [] }
|
|
if locus_re.match("global"):
|
|
xm_dict[locus_str].extend(
|
|
[m for m in gdb.xmethods if matcher_re.match(m.name)])
|
|
return xm_dict
|
|
|
|
|
|
def get_method_matchers_in_loci(loci, locus_re, matcher_re):
|
|
"""Returns a dict of matching registered xmethods in the LOCI.
|
|
|
|
Arguments:
|
|
loci: The list of loci to lookup matching xmethods in.
|
|
locus_re: If a locus is an objfile, then xmethod matchers will be
|
|
looked up in it only if its filename matches the regular
|
|
expression LOCUS_RE. If a locus is the current progspace,
|
|
then xmethod matchers will be looked up in it only if the
|
|
string "progspace" matches LOCUS_RE.
|
|
matcher_re: The regular expression to match the xmethod matcher
|
|
names.
|
|
|
|
Returns:
|
|
A dict of matching xmethod matchers. The keys of the dict are the
|
|
filenames of the loci the xmethod matchers belong to.
|
|
"""
|
|
xm_dict = {}
|
|
for locus in loci:
|
|
if isinstance(locus, gdb.Progspace):
|
|
if not locus_re.match('progspace'):
|
|
continue
|
|
locus_type = "progspace"
|
|
else:
|
|
if not locus_re.match(locus.filename):
|
|
continue
|
|
locus_type = "objfile"
|
|
locus_str = "%s %s" % (locus_type, locus.filename)
|
|
xm_dict[locus_str] = [
|
|
m for m in locus.xmethods if matcher_re.match(m.name)]
|
|
return xm_dict
|
|
|
|
|
|
def print_xm_info(xm_dict, name_re):
|
|
"""Print a dictionary of xmethods."""
|
|
def get_status_string(m):
|
|
if not m.enabled:
|
|
return " [disabled]"
|
|
else:
|
|
return ""
|
|
|
|
if not xm_dict:
|
|
return
|
|
for locus_str in xm_dict:
|
|
if not xm_dict[locus_str]:
|
|
continue
|
|
print ("Xmethods in %s:" % locus_str)
|
|
for matcher in xm_dict[locus_str]:
|
|
print (" %s%s" % (matcher.name, get_status_string(matcher)))
|
|
if not matcher.methods:
|
|
continue
|
|
for m in matcher.methods:
|
|
if name_re is None or name_re.match(m.name):
|
|
print (" %s%s" % (m.name, get_status_string(m)))
|
|
|
|
|
|
def set_xm_status1(xm_dict, name_re, status):
|
|
"""Set the status (enabled/disabled) of a dictionary of xmethods."""
|
|
for locus_str, matchers in xm_dict.items():
|
|
for matcher in matchers:
|
|
if not name_re:
|
|
# If the name regex is missing, then set the status of the
|
|
# matcher and move on.
|
|
matcher.enabled = status
|
|
continue
|
|
if not matcher.methods:
|
|
# The methods attribute could be None. Move on.
|
|
continue
|
|
for m in matcher.methods:
|
|
if name_re.match(m.name):
|
|
m.enabled = status
|
|
|
|
|
|
def set_xm_status(arg, status):
|
|
"""Set the status (enabled/disabled) of xmethods matching ARG.
|
|
This is a helper function for enable/disable commands. ARG is the
|
|
argument string passed to the commands.
|
|
"""
|
|
locus_re, matcher_re, name_re = parse_xm_command_args(arg)
|
|
set_xm_status1(get_global_method_matchers(locus_re, matcher_re), name_re,
|
|
status)
|
|
set_xm_status1(
|
|
get_method_matchers_in_loci(
|
|
[gdb.current_progspace()], locus_re, matcher_re),
|
|
name_re,
|
|
status)
|
|
set_xm_status1(
|
|
get_method_matchers_in_loci(gdb.objfiles(), locus_re, matcher_re),
|
|
name_re,
|
|
status)
|
|
|
|
|
|
class InfoXMethod(gdb.Command):
|
|
"""GDB command to list registered xmethod matchers.
|
|
|
|
Usage: info xmethod [locus-regexp [name-regexp]]
|
|
|
|
LOCUS-REGEXP is a regular expression matching the location of the
|
|
xmethod matchers. If it is omitted, all registered xmethod matchers
|
|
from all loci are listed. A locus could be 'global', a regular expression
|
|
matching the current program space's filename, or a regular expression
|
|
matching filenames of objfiles. Locus could be 'progspace' to specify that
|
|
only xmethods from the current progspace should be listed.
|
|
|
|
NAME-REGEXP is a regular expression matching the names of xmethod
|
|
matchers. If this omitted for a specified locus, then all registered
|
|
xmethods in the locus are listed. To list only a certain xmethods
|
|
managed by a single matcher, the name regexp can be specified as
|
|
matcher-name-regexp;xmethod-name-regexp.
|
|
"""
|
|
|
|
def __init__(self):
|
|
super(InfoXMethod, self).__init__("info xmethod",
|
|
gdb.COMMAND_DATA)
|
|
|
|
def invoke(self, arg, from_tty):
|
|
locus_re, matcher_re, name_re = parse_xm_command_args(arg)
|
|
print_xm_info(get_global_method_matchers(locus_re, matcher_re),
|
|
name_re)
|
|
print_xm_info(
|
|
get_method_matchers_in_loci(
|
|
[gdb.current_progspace()], locus_re, matcher_re),
|
|
name_re)
|
|
print_xm_info(
|
|
get_method_matchers_in_loci(gdb.objfiles(), locus_re, matcher_re),
|
|
name_re)
|
|
|
|
|
|
class EnableXMethod(gdb.Command):
|
|
"""GDB command to enable a specified (group of) xmethod(s).
|
|
|
|
Usage: enable xmethod [locus-regexp [name-regexp]]
|
|
|
|
LOCUS-REGEXP is a regular expression matching the location of the
|
|
xmethod matchers. If it is omitted, all registered xmethods matchers
|
|
from all loci are enabled. A locus could be 'global', a regular expression
|
|
matching the current program space's filename, or a regular expression
|
|
matching filenames of objfiles. Locus could be 'progspace' to specify that
|
|
only xmethods from the current progspace should be enabled.
|
|
|
|
NAME-REGEXP is a regular expression matching the names of xmethods
|
|
within a given locus. If this omitted for a specified locus, then all
|
|
registered xmethod matchers in the locus are enabled. To enable only
|
|
a certain xmethods managed by a single matcher, the name regexp can be
|
|
specified as matcher-name-regexp;xmethod-name-regexp.
|
|
"""
|
|
|
|
def __init__(self):
|
|
super(EnableXMethod, self).__init__("enable xmethod",
|
|
gdb.COMMAND_DATA)
|
|
|
|
def invoke(self, arg, from_tty):
|
|
set_xm_status(arg, True)
|
|
|
|
|
|
class DisableXMethod(gdb.Command):
|
|
"""GDB command to disable a specified (group of) xmethod(s).
|
|
|
|
Usage: disable xmethod [locus-regexp [name-regexp]]
|
|
|
|
LOCUS-REGEXP is a regular expression matching the location of the
|
|
xmethod matchers. If it is omitted, all registered xmethod matchers
|
|
from all loci are disabled. A locus could be 'global', a regular
|
|
expression matching the current program space's filename, or a regular
|
|
expression filenames of objfiles. Locus could be 'progspace' to specify
|
|
that only xmethods from the current progspace should be disabled.
|
|
|
|
NAME-REGEXP is a regular expression matching the names of xmethods
|
|
within a given locus. If this omitted for a specified locus, then all
|
|
registered xmethod matchers in the locus are disabled. To disable
|
|
only a certain xmethods managed by a single matcher, the name regexp
|
|
can be specified as matcher-name-regexp;xmethod-name-regexp.
|
|
"""
|
|
|
|
def __init__(self):
|
|
super(DisableXMethod, self).__init__("disable xmethod",
|
|
gdb.COMMAND_DATA)
|
|
|
|
def invoke(self, arg, from_tty):
|
|
set_xm_status(arg, False)
|
|
|
|
|
|
def register_xmethod_commands():
|
|
"""Installs the xmethod commands."""
|
|
InfoXMethod()
|
|
EnableXMethod()
|
|
DisableXMethod()
|
|
|
|
|
|
register_xmethod_commands()
|