]>
Commit | Line | Data |
---|---|---|
d11916aa | 1 | # Unwinder commands. |
b811d2c2 | 2 | # Copyright 2015-2020 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] | |
52 | return (validate_regexp(locus_regexp, "locus"), | |
53 | validate_regexp(name_regexp, "unwinder")) | |
54 | ||
55 | ||
56 | class InfoUnwinder(gdb.Command): | |
57 | """GDB command to list unwinders. | |
58 | ||
2fb009bb | 59 | Usage: info unwinder [LOCUS-REGEXP [NAME-REGEXP]] |
d11916aa | 60 | |
2fb009bb TT |
61 | LOCUS-REGEXP is a regular expression matching the location of the |
62 | unwinder. If it is omitted, all registered unwinders from all | |
63 | loci are listed. A locus can be 'global', 'progspace' to list | |
64 | the unwinders from the current progspace, or a regular expression | |
65 | matching filenames of objfiles. | |
d11916aa | 66 | |
2fb009bb TT |
67 | NAME-REGEXP is a regular expression to filter unwinder names. If |
68 | this omitted for a specified locus, then all registered unwinders | |
69 | in the locus are listed.""" | |
d11916aa SS |
70 | |
71 | def __init__(self): | |
72 | super(InfoUnwinder, self).__init__("info unwinder", | |
73 | gdb.COMMAND_STACK) | |
74 | ||
75 | def list_unwinders(self, title, unwinders, name_re): | |
76 | """Lists the unwinders whose name matches regexp. | |
77 | ||
78 | Arguments: | |
79 | title: The line to print before the list. | |
80 | unwinders: The list of the unwinders. | |
81 | name_re: unwinder name filter. | |
82 | """ | |
83 | if not unwinders: | |
84 | return | |
40d2f8d6 | 85 | print(title) |
d11916aa SS |
86 | for unwinder in unwinders: |
87 | if name_re.match(unwinder.name): | |
88 | print(" %s%s" % (unwinder.name, | |
89 | "" if unwinder.enabled else " [disabled]")) | |
90 | ||
91 | def invoke(self, arg, from_tty): | |
92 | locus_re, name_re = parse_unwinder_command_args(arg) | |
93 | if locus_re.match("global"): | |
94 | self.list_unwinders("Global:", gdb.frame_unwinders, | |
95 | name_re) | |
96 | if locus_re.match("progspace"): | |
97 | cp = gdb.current_progspace() | |
98 | self.list_unwinders("Progspace %s:" % cp.filename, | |
99 | cp.frame_unwinders, name_re) | |
100 | for objfile in gdb.objfiles(): | |
101 | if locus_re.match(objfile.filename): | |
102 | self.list_unwinders("Objfile %s:" % objfile.filename, | |
103 | objfile.frame_unwinders, name_re) | |
104 | ||
105 | ||
106 | def do_enable_unwinder1(unwinders, name_re, flag): | |
107 | """Enable/disable unwinders whose names match given regex. | |
108 | ||
109 | Arguments: | |
110 | unwinders: The list of unwinders. | |
111 | name_re: Unwinder name filter. | |
112 | flag: Enable/disable. | |
113 | ||
114 | Returns: | |
115 | The number of unwinders affected. | |
116 | """ | |
117 | total = 0 | |
118 | for unwinder in unwinders: | |
119 | if name_re.match(unwinder.name): | |
120 | unwinder.enabled = flag | |
121 | total += 1 | |
122 | return total | |
123 | ||
124 | ||
125 | def do_enable_unwinder(arg, flag): | |
126 | """Enable/disable unwinder(s).""" | |
127 | (locus_re, name_re) = parse_unwinder_command_args(arg) | |
128 | total = 0 | |
129 | if locus_re.match("global"): | |
130 | total += do_enable_unwinder1(gdb.frame_unwinders, name_re, flag) | |
131 | if locus_re.match("progspace"): | |
132 | total += do_enable_unwinder1(gdb.current_progspace().frame_unwinders, | |
133 | name_re, flag) | |
134 | for objfile in gdb.objfiles(): | |
135 | if locus_re.match(objfile.filename): | |
136 | total += do_enable_unwinder1(objfile.frame_unwinders, name_re, | |
137 | flag) | |
e0f3fd7c TT |
138 | if total > 0: |
139 | gdb.invalidate_cached_frames() | |
d11916aa SS |
140 | print("%d unwinder%s %s" % (total, "" if total == 1 else "s", |
141 | "enabled" if flag else "disabled")) | |
142 | ||
143 | ||
144 | class EnableUnwinder(gdb.Command): | |
145 | """GDB command to enable unwinders. | |
146 | ||
2fb009bb | 147 | Usage: enable unwinder [LOCUS-REGEXP [NAME-REGEXP]] |
d11916aa | 148 | |
2fb009bb TT |
149 | LOCUS-REGEXP is a regular expression specifying the unwinders to |
150 | enable. It can 'global', 'progspace', or the name of an objfile | |
151 | within that progspace. | |
d11916aa | 152 | |
2fb009bb TT |
153 | NAME_REGEXP is a regular expression to filter unwinder names. If |
154 | this omitted for a specified locus, then all registered unwinders | |
155 | in the locus are affected.""" | |
d11916aa SS |
156 | |
157 | def __init__(self): | |
158 | super(EnableUnwinder, self).__init__("enable unwinder", | |
159 | gdb.COMMAND_STACK) | |
160 | ||
161 | def invoke(self, arg, from_tty): | |
162 | """GDB calls this to perform the command.""" | |
163 | do_enable_unwinder(arg, True) | |
164 | ||
165 | ||
166 | class DisableUnwinder(gdb.Command): | |
167 | """GDB command to disable the specified unwinder. | |
168 | ||
2fb009bb | 169 | Usage: disable unwinder [LOCUS-REGEXP [NAME-REGEXP]] |
d11916aa | 170 | |
2fb009bb TT |
171 | LOCUS-REGEXP is a regular expression specifying the unwinders to |
172 | disable. It can 'global', 'progspace', or the name of an objfile | |
173 | within that progspace. | |
d11916aa | 174 | |
2fb009bb TT |
175 | NAME_REGEXP is a regular expression to filter unwinder names. If |
176 | this omitted for a specified locus, then all registered unwinders | |
177 | in the locus are affected.""" | |
d11916aa SS |
178 | |
179 | def __init__(self): | |
180 | super(DisableUnwinder, self).__init__("disable unwinder", | |
181 | gdb.COMMAND_STACK) | |
182 | ||
183 | def invoke(self, arg, from_tty): | |
184 | """GDB calls this to perform the command.""" | |
185 | do_enable_unwinder(arg, False) | |
186 | ||
187 | ||
188 | def register_unwinder_commands(): | |
189 | """Installs the unwinder commands.""" | |
190 | InfoUnwinder() | |
191 | EnableUnwinder() | |
192 | DisableUnwinder() | |
193 | ||
194 | ||
195 | register_unwinder_commands() |