]>
Commit | Line | Data |
---|---|---|
d11916aa | 1 | # Unwinder commands. |
1d506c26 | 2 | # Copyright 2015-2024 Free Software Foundation, Inc. |
d11916aa SS |
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 | ||
17 | import gdb | |
18 | import re | |
19 | ||
20 | ||
21 | def 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 | ||
28 | def 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] | |
13123da8 SM |
52 | return ( |
53 | validate_regexp(locus_regexp, "locus"), | |
54 | validate_regexp(name_regexp, "unwinder"), | |
55 | ) | |
d11916aa SS |
56 | |
57 | ||
58 | class InfoUnwinder(gdb.Command): | |
59 | """GDB command to list unwinders. | |
60 | ||
13123da8 | 61 | Usage: info unwinder [LOCUS-REGEXP [NAME-REGEXP]] |
d11916aa | 62 | |
13123da8 SM |
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. | |
d11916aa | 68 | |
13123da8 SM |
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.""" | |
d11916aa SS |
72 | |
73 | def __init__(self): | |
13123da8 | 74 | super(InfoUnwinder, self).__init__("info unwinder", gdb.COMMAND_STACK) |
d11916aa SS |
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 | |
40d2f8d6 | 86 | print(title) |
d11916aa SS |
87 | for unwinder in unwinders: |
88 | if name_re.match(unwinder.name): | |
13123da8 SM |
89 | print( |
90 | " %s%s" | |
91 | % (unwinder.name, "" if unwinder.enabled else " [disabled]") | |
92 | ) | |
d11916aa SS |
93 | |
94 | def invoke(self, arg, from_tty): | |
95 | locus_re, name_re = parse_unwinder_command_args(arg) | |
96 | if locus_re.match("global"): | |
13123da8 | 97 | self.list_unwinders("Global:", gdb.frame_unwinders, name_re) |
d11916aa SS |
98 | if locus_re.match("progspace"): |
99 | cp = gdb.current_progspace() | |
13123da8 SM |
100 | self.list_unwinders( |
101 | "Progspace %s:" % cp.filename, cp.frame_unwinders, name_re | |
102 | ) | |
d11916aa SS |
103 | for objfile in gdb.objfiles(): |
104 | if locus_re.match(objfile.filename): | |
13123da8 SM |
105 | self.list_unwinders( |
106 | "Objfile %s:" % objfile.filename, objfile.frame_unwinders, name_re | |
107 | ) | |
d11916aa SS |
108 | |
109 | ||
110 | def 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 | ||
129 | def 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"): | |
13123da8 SM |
136 | total += do_enable_unwinder1( |
137 | gdb.current_progspace().frame_unwinders, name_re, flag | |
138 | ) | |
d11916aa SS |
139 | for objfile in gdb.objfiles(): |
140 | if locus_re.match(objfile.filename): | |
13123da8 | 141 | total += do_enable_unwinder1(objfile.frame_unwinders, name_re, flag) |
e0f3fd7c TT |
142 | if total > 0: |
143 | gdb.invalidate_cached_frames() | |
13123da8 SM |
144 | print( |
145 | "%d unwinder%s %s" | |
146 | % (total, "" if total == 1 else "s", "enabled" if flag else "disabled") | |
147 | ) | |
d11916aa SS |
148 | |
149 | ||
150 | class EnableUnwinder(gdb.Command): | |
151 | """GDB command to enable unwinders. | |
152 | ||
13123da8 | 153 | Usage: enable unwinder [LOCUS-REGEXP [NAME-REGEXP]] |
d11916aa | 154 | |
13123da8 SM |
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. | |
d11916aa | 158 | |
13123da8 SM |
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.""" | |
d11916aa SS |
162 | |
163 | def __init__(self): | |
13123da8 | 164 | super(EnableUnwinder, self).__init__("enable unwinder", gdb.COMMAND_STACK) |
d11916aa SS |
165 | |
166 | def invoke(self, arg, from_tty): | |
167 | """GDB calls this to perform the command.""" | |
168 | do_enable_unwinder(arg, True) | |
169 | ||
170 | ||
171 | class DisableUnwinder(gdb.Command): | |
172 | """GDB command to disable the specified unwinder. | |
173 | ||
13123da8 | 174 | Usage: disable unwinder [LOCUS-REGEXP [NAME-REGEXP]] |
d11916aa | 175 | |
13123da8 SM |
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. | |
d11916aa | 179 | |
13123da8 SM |
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.""" | |
d11916aa SS |
183 | |
184 | def __init__(self): | |
13123da8 | 185 | super(DisableUnwinder, self).__init__("disable unwinder", gdb.COMMAND_STACK) |
d11916aa SS |
186 | |
187 | def invoke(self, arg, from_tty): | |
188 | """GDB calls this to perform the command.""" | |
189 | do_enable_unwinder(arg, False) | |
190 | ||
191 | ||
192 | def register_unwinder_commands(): | |
193 | """Installs the unwinder commands.""" | |
194 | InfoUnwinder() | |
195 | EnableUnwinder() | |
196 | DisableUnwinder() | |
197 | ||
198 | ||
199 | register_unwinder_commands() |