xref: /netbsd-src/external/gpl3/gdb.old/dist/gdb/python/lib/gdb/command/unwinders.py (revision 6881a4007f077b54e5f51159c52b9b25f57deb0d)
1# Unwinder commands.
2# Copyright 2015-2023 Free Software Foundation, Inc.
3
4# This program is free software; you can redistribute it and/or modify
5# it under the terms of the GNU General Public License as published by
6# the Free Software Foundation; either version 3 of the License, or
7# (at your option) any later version.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License
15# along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
17import gdb
18import re
19
20
21def validate_regexp(exp, idstring):
22    try:
23        return re.compile(exp)
24    except SyntaxError:
25        raise SyntaxError("Invalid %s regexp: %s." % (idstring, exp))
26
27
28def parse_unwinder_command_args(arg):
29    """Internal utility to parse unwinder command argv.
30
31    Arguments:
32        arg: The arguments to the command. The format is:
33             [locus-regexp [name-regexp]]
34
35    Returns:
36        A 2-tuple of compiled regular expressions.
37
38    Raises:
39        SyntaxError: an error processing ARG
40    """
41
42    argv = gdb.string_to_argv(arg)
43    argc = len(argv)
44    if argc > 2:
45        raise SyntaxError("Too many arguments.")
46    locus_regexp = ""
47    name_regexp = ""
48    if argc >= 1:
49        locus_regexp = argv[0]
50        if argc >= 2:
51            name_regexp = argv[1]
52    return (
53        validate_regexp(locus_regexp, "locus"),
54        validate_regexp(name_regexp, "unwinder"),
55    )
56
57
58class InfoUnwinder(gdb.Command):
59    """GDB command to list unwinders.
60
61    Usage: info unwinder [LOCUS-REGEXP [NAME-REGEXP]]
62
63    LOCUS-REGEXP is a regular expression matching the location of the
64    unwinder.  If it is omitted, all registered unwinders from all
65    loci are listed.  A locus can be 'global', 'progspace' to list
66    the unwinders from the current progspace, or a regular expression
67    matching filenames of objfiles.
68
69    NAME-REGEXP is a regular expression to filter unwinder names.  If
70    this omitted for a specified locus, then all registered unwinders
71    in the locus are listed."""
72
73    def __init__(self):
74        super(InfoUnwinder, self).__init__("info unwinder", gdb.COMMAND_STACK)
75
76    def list_unwinders(self, title, unwinders, name_re):
77        """Lists the unwinders whose name matches regexp.
78
79        Arguments:
80            title: The line to print before the list.
81            unwinders: The list of the unwinders.
82            name_re: unwinder name filter.
83        """
84        if not unwinders:
85            return
86        print(title)
87        for unwinder in unwinders:
88            if name_re.match(unwinder.name):
89                print(
90                    "  %s%s"
91                    % (unwinder.name, "" if unwinder.enabled else " [disabled]")
92                )
93
94    def invoke(self, arg, from_tty):
95        locus_re, name_re = parse_unwinder_command_args(arg)
96        if locus_re.match("global"):
97            self.list_unwinders("Global:", gdb.frame_unwinders, name_re)
98        if locus_re.match("progspace"):
99            cp = gdb.current_progspace()
100            self.list_unwinders(
101                "Progspace %s:" % cp.filename, cp.frame_unwinders, name_re
102            )
103        for objfile in gdb.objfiles():
104            if locus_re.match(objfile.filename):
105                self.list_unwinders(
106                    "Objfile %s:" % objfile.filename, objfile.frame_unwinders, name_re
107                )
108
109
110def do_enable_unwinder1(unwinders, name_re, flag):
111    """Enable/disable unwinders whose names match given regex.
112
113    Arguments:
114        unwinders: The list of unwinders.
115        name_re: Unwinder name filter.
116        flag: Enable/disable.
117
118    Returns:
119        The number of unwinders affected.
120    """
121    total = 0
122    for unwinder in unwinders:
123        if name_re.match(unwinder.name):
124            unwinder.enabled = flag
125            total += 1
126    return total
127
128
129def do_enable_unwinder(arg, flag):
130    """Enable/disable unwinder(s)."""
131    (locus_re, name_re) = parse_unwinder_command_args(arg)
132    total = 0
133    if locus_re.match("global"):
134        total += do_enable_unwinder1(gdb.frame_unwinders, name_re, flag)
135    if locus_re.match("progspace"):
136        total += do_enable_unwinder1(
137            gdb.current_progspace().frame_unwinders, name_re, flag
138        )
139    for objfile in gdb.objfiles():
140        if locus_re.match(objfile.filename):
141            total += do_enable_unwinder1(objfile.frame_unwinders, name_re, flag)
142    if total > 0:
143        gdb.invalidate_cached_frames()
144    print(
145        "%d unwinder%s %s"
146        % (total, "" if total == 1 else "s", "enabled" if flag else "disabled")
147    )
148
149
150class EnableUnwinder(gdb.Command):
151    """GDB command to enable unwinders.
152
153    Usage: enable unwinder [LOCUS-REGEXP [NAME-REGEXP]]
154
155    LOCUS-REGEXP is a regular expression specifying the unwinders to
156    enable.  It can 'global', 'progspace', or the name of an objfile
157    within that progspace.
158
159    NAME_REGEXP is a regular expression to filter unwinder names.  If
160    this omitted for a specified locus, then all registered unwinders
161    in the locus are affected."""
162
163    def __init__(self):
164        super(EnableUnwinder, self).__init__("enable unwinder", gdb.COMMAND_STACK)
165
166    def invoke(self, arg, from_tty):
167        """GDB calls this to perform the command."""
168        do_enable_unwinder(arg, True)
169
170
171class DisableUnwinder(gdb.Command):
172    """GDB command to disable the specified unwinder.
173
174    Usage: disable unwinder [LOCUS-REGEXP [NAME-REGEXP]]
175
176    LOCUS-REGEXP is a regular expression specifying the unwinders to
177    disable.  It can 'global', 'progspace', or the name of an objfile
178    within that progspace.
179
180    NAME_REGEXP is a regular expression to filter unwinder names.  If
181    this omitted for a specified locus, then all registered unwinders
182    in the locus are affected."""
183
184    def __init__(self):
185        super(DisableUnwinder, self).__init__("disable unwinder", gdb.COMMAND_STACK)
186
187    def invoke(self, arg, from_tty):
188        """GDB calls this to perform the command."""
189        do_enable_unwinder(arg, False)
190
191
192def register_unwinder_commands():
193    """Installs the unwinder commands."""
194    InfoUnwinder()
195    EnableUnwinder()
196    DisableUnwinder()
197
198
199register_unwinder_commands()
200