| # Unwinder commands. |
| # Copyright 2015 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) |
| 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() |