blob: 59ee67cc7b356b0b3a325a86da450e00fc3562cc [file] [log] [blame]
# Unwinder commands.
# Copyright 2015-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/>.
import gdb
import re
def validate_regexp(exp, idstring):
try:
return re.compile(exp)
except SyntaxError:
raise SyntaxError("Invalid %s regexp: %s." % (idstring, exp))
def parse_unwinder_command_args(arg):
"""Internal utility to parse unwinder command argv.
Arguments:
arg: The arguments to the command. The format is:
[locus-regexp [name-regexp]]
Returns:
A 2-tuple of compiled regular expressions.
Raises:
SyntaxError: an error processing ARG
"""
argv = gdb.string_to_argv(arg)
argc = len(argv)
if argc > 2:
raise SyntaxError("Too many arguments.")
locus_regexp = ""
name_regexp = ""
if argc >= 1:
locus_regexp = argv[0]
if argc >= 2:
name_regexp = argv[1]
return (
validate_regexp(locus_regexp, "locus"),
validate_regexp(name_regexp, "unwinder"),
)
class InfoUnwinder(gdb.Command):
"""GDB command to list unwinders.
Usage: info unwinder [LOCUS-REGEXP [NAME-REGEXP]]
LOCUS-REGEXP is a regular expression matching the location of the
unwinder. If it is omitted, all registered unwinders from all
loci are listed. A locus can be 'global', 'progspace' to list
the unwinders from the current progspace, or a regular expression
matching filenames of objfiles.
NAME-REGEXP is a regular expression to filter unwinder names. If
this omitted for a specified locus, then all registered unwinders
in the locus are listed."""
def __init__(self):
super(InfoUnwinder, self).__init__("info unwinder", gdb.COMMAND_STACK)
def list_unwinders(self, title, unwinders, name_re):
"""Lists the unwinders whose name matches regexp.
Arguments:
title: The line to print before the list.
unwinders: The list of the unwinders.
name_re: unwinder name filter.
"""
if not unwinders:
return
print(title)
for unwinder in unwinders:
if name_re.match(unwinder.name):
print(
" %s%s"
% (unwinder.name, "" if unwinder.enabled else " [disabled]")
)
def invoke(self, arg, from_tty):
locus_re, name_re = parse_unwinder_command_args(arg)
if locus_re.match("global"):
self.list_unwinders("Global:", gdb.frame_unwinders, name_re)
if locus_re.match("progspace"):
cp = gdb.current_progspace()
self.list_unwinders(
"Progspace %s:" % cp.filename, cp.frame_unwinders, name_re
)
for objfile in gdb.objfiles():
if locus_re.match(objfile.filename):
self.list_unwinders(
"Objfile %s:" % objfile.filename, objfile.frame_unwinders, name_re
)
def do_enable_unwinder1(unwinders, name_re, flag):
"""Enable/disable unwinders whose names match given regex.
Arguments:
unwinders: The list of unwinders.
name_re: Unwinder name filter.
flag: Enable/disable.
Returns:
The number of unwinders affected.
"""
total = 0
for unwinder in unwinders:
if name_re.match(unwinder.name):
unwinder.enabled = flag
total += 1
return total
def do_enable_unwinder(arg, flag):
"""Enable/disable unwinder(s)."""
(locus_re, name_re) = parse_unwinder_command_args(arg)
total = 0
if locus_re.match("global"):
total += do_enable_unwinder1(gdb.frame_unwinders, name_re, flag)
if locus_re.match("progspace"):
total += do_enable_unwinder1(
gdb.current_progspace().frame_unwinders, name_re, flag
)
for objfile in gdb.objfiles():
if locus_re.match(objfile.filename):
total += do_enable_unwinder1(objfile.frame_unwinders, name_re, flag)
if total > 0:
gdb.invalidate_cached_frames()
print(
"%d unwinder%s %s"
% (total, "" if total == 1 else "s", "enabled" if flag else "disabled")
)
class EnableUnwinder(gdb.Command):
"""GDB command to enable unwinders.
Usage: enable unwinder [LOCUS-REGEXP [NAME-REGEXP]]
LOCUS-REGEXP is a regular expression specifying the unwinders to
enable. It can 'global', 'progspace', or the name of an objfile
within that progspace.
NAME_REGEXP is a regular expression to filter unwinder names. If
this omitted for a specified locus, then all registered unwinders
in the locus are affected."""
def __init__(self):
super(EnableUnwinder, self).__init__("enable unwinder", gdb.COMMAND_STACK)
def invoke(self, arg, from_tty):
"""GDB calls this to perform the command."""
do_enable_unwinder(arg, True)
class DisableUnwinder(gdb.Command):
"""GDB command to disable the specified unwinder.
Usage: disable unwinder [LOCUS-REGEXP [NAME-REGEXP]]
LOCUS-REGEXP is a regular expression specifying the unwinders to
disable. It can 'global', 'progspace', or the name of an objfile
within that progspace.
NAME_REGEXP is a regular expression to filter unwinder names. If
this omitted for a specified locus, then all registered unwinders
in the locus are affected."""
def __init__(self):
super(DisableUnwinder, self).__init__("disable unwinder", gdb.COMMAND_STACK)
def invoke(self, arg, from_tty):
"""GDB calls this to perform the command."""
do_enable_unwinder(arg, False)
def register_unwinder_commands():
"""Installs the unwinder commands."""
InfoUnwinder()
EnableUnwinder()
DisableUnwinder()
register_unwinder_commands()