
Currently, the xmethod commands lookup xmethod matchers in the current progspace even if the locus regular expression matches the progspace's filename. Pretty printer commands do not match the current progspace's filename. gdb/ * python/lib/gdb/command/xmethods.py (get_method_matchers_in_loci): Lookup xmethod matchers in the current progspace only if the string "progspace" matches LOCUS_RE. gdb/testsuite * gdb.python/py-xmethods.exp: Use "progspace" instead of the progspace's filename in 'info', 'enable' and 'disable' command tests.
274 lines
9.9 KiB
Python
274 lines
9.9 KiB
Python
# Xmethod commands.
|
|
# Copyright 2013-2014 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(method):
|
|
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" % matcher.name)
|
|
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.iteritems():
|
|
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()
|