Commit | Line | Data |
---|---|---|
883964a7 | 1 | # Xmethod commands. |
88b9d363 | 2 | # Copyright 2013-2022 Free Software Foundation, Inc. |
883964a7 SC |
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 | """GDB commands for working with xmethods.""" | |
21 | ||
22 | ||
23 | def validate_xm_regexp(part_name, regexp): | |
24 | try: | |
25 | return re.compile(regexp) | |
26 | except SyntaxError: | |
27 | raise SyntaxError("Invalid %s regexp: %s", part_name, regexp) | |
28 | ||
29 | ||
30 | def parse_xm_command_args(arg): | |
31 | """Parses the arguments passed to a xmethod command. | |
32 | ||
33 | Arguments: | |
34 | arg: The argument string passed to a xmethod command. | |
35 | ||
36 | Returns: | |
37 | A 3-tuple: (<locus matching regular expression>, | |
38 | <matcher matching regular expression>, | |
39 | <name matching regular experession>) | |
40 | """ | |
41 | argv = gdb.string_to_argv(arg) | |
42 | argc = len(argv) | |
43 | if argc > 2: | |
44 | raise SyntaxError("Too many arguments to command.") | |
45 | locus_regexp = "" | |
46 | matcher_name_regexp = "" | |
47 | xm_name_regexp = None | |
48 | if argc >= 1: | |
49 | locus_regexp = argv[0] | |
50 | if argc == 2: | |
51 | parts = argv[1].split(";", 1) | |
52 | matcher_name_regexp = parts[0] | |
53 | if len(parts) > 1: | |
54 | xm_name_regexp = parts[1] | |
55 | if xm_name_regexp: | |
56 | name_re = validate_xm_regexp("xmethod name", xm_name_regexp) | |
57 | else: | |
58 | name_re = None | |
13123da8 SM |
59 | return ( |
60 | validate_xm_regexp("locus", locus_regexp), | |
61 | validate_xm_regexp("matcher name", matcher_name_regexp), | |
62 | name_re, | |
63 | ) | |
883964a7 SC |
64 | |
65 | ||
66 | def get_global_method_matchers(locus_re, matcher_re): | |
67 | """Returns a dict of matching globally registered xmethods. | |
68 | ||
69 | Arguments: | |
70 | locus_re: Even though only globally registered xmethods are | |
71 | looked up, they will be looked up only if 'global' matches | |
72 | LOCUS_RE. | |
73 | matcher_re: The regular expression matching the names of xmethods. | |
74 | ||
75 | Returns: | |
76 | A dict of matching globally registered xmethod matchers. The only | |
77 | key in the dict will be 'global'. | |
78 | """ | |
79 | locus_str = "global" | |
13123da8 | 80 | xm_dict = {locus_str: []} |
883964a7 | 81 | if locus_re.match("global"): |
13123da8 | 82 | xm_dict[locus_str].extend([m for m in gdb.xmethods if matcher_re.match(m.name)]) |
883964a7 SC |
83 | return xm_dict |
84 | ||
85 | ||
86 | def get_method_matchers_in_loci(loci, locus_re, matcher_re): | |
87 | """Returns a dict of matching registered xmethods in the LOCI. | |
88 | ||
89 | Arguments: | |
90 | loci: The list of loci to lookup matching xmethods in. | |
70afc5b7 SC |
91 | locus_re: If a locus is an objfile, then xmethod matchers will be |
92 | looked up in it only if its filename matches the regular | |
93 | expression LOCUS_RE. If a locus is the current progspace, | |
94 | then xmethod matchers will be looked up in it only if the | |
95 | string "progspace" matches LOCUS_RE. | |
883964a7 SC |
96 | matcher_re: The regular expression to match the xmethod matcher |
97 | names. | |
98 | ||
99 | Returns: | |
100 | A dict of matching xmethod matchers. The keys of the dict are the | |
101 | filenames of the loci the xmethod matchers belong to. | |
102 | """ | |
103 | xm_dict = {} | |
104 | for locus in loci: | |
105 | if isinstance(locus, gdb.Progspace): | |
13123da8 | 106 | if not locus_re.match("progspace"): |
883964a7 SC |
107 | continue |
108 | locus_type = "progspace" | |
109 | else: | |
110 | if not locus_re.match(locus.filename): | |
111 | continue | |
112 | locus_type = "objfile" | |
113 | locus_str = "%s %s" % (locus_type, locus.filename) | |
13123da8 | 114 | xm_dict[locus_str] = [m for m in locus.xmethods if matcher_re.match(m.name)] |
883964a7 SC |
115 | return xm_dict |
116 | ||
117 | ||
118 | def print_xm_info(xm_dict, name_re): | |
119 | """Print a dictionary of xmethods.""" | |
13123da8 | 120 | |
df2eb078 | 121 | def get_status_string(m): |
883964a7 SC |
122 | if not m.enabled: |
123 | return " [disabled]" | |
124 | else: | |
13123da8 | 125 | return "" |
883964a7 SC |
126 | |
127 | if not xm_dict: | |
128 | return | |
129 | for locus_str in xm_dict: | |
130 | if not xm_dict[locus_str]: | |
131 | continue | |
13123da8 | 132 | print("Xmethods in %s:" % locus_str) |
883964a7 | 133 | for matcher in xm_dict[locus_str]: |
13123da8 | 134 | print(" %s%s" % (matcher.name, get_status_string(matcher))) |
883964a7 SC |
135 | if not matcher.methods: |
136 | continue | |
137 | for m in matcher.methods: | |
138 | if name_re is None or name_re.match(m.name): | |
13123da8 | 139 | print(" %s%s" % (m.name, get_status_string(m))) |
883964a7 SC |
140 | |
141 | ||
142 | def set_xm_status1(xm_dict, name_re, status): | |
143 | """Set the status (enabled/disabled) of a dictionary of xmethods.""" | |
940df408 | 144 | for locus_str, matchers in xm_dict.items(): |
883964a7 SC |
145 | for matcher in matchers: |
146 | if not name_re: | |
147 | # If the name regex is missing, then set the status of the | |
148 | # matcher and move on. | |
149 | matcher.enabled = status | |
150 | continue | |
151 | if not matcher.methods: | |
152 | # The methods attribute could be None. Move on. | |
153 | continue | |
154 | for m in matcher.methods: | |
155 | if name_re.match(m.name): | |
156 | m.enabled = status | |
157 | ||
158 | ||
159 | def set_xm_status(arg, status): | |
160 | """Set the status (enabled/disabled) of xmethods matching ARG. | |
161 | This is a helper function for enable/disable commands. ARG is the | |
162 | argument string passed to the commands. | |
163 | """ | |
164 | locus_re, matcher_re, name_re = parse_xm_command_args(arg) | |
13123da8 | 165 | set_xm_status1(get_global_method_matchers(locus_re, matcher_re), name_re, status) |
883964a7 | 166 | set_xm_status1( |
13123da8 | 167 | get_method_matchers_in_loci([gdb.current_progspace()], locus_re, matcher_re), |
883964a7 | 168 | name_re, |
13123da8 SM |
169 | status, |
170 | ) | |
883964a7 SC |
171 | set_xm_status1( |
172 | get_method_matchers_in_loci(gdb.objfiles(), locus_re, matcher_re), | |
173 | name_re, | |
13123da8 SM |
174 | status, |
175 | ) | |
883964a7 SC |
176 | |
177 | ||
178 | class InfoXMethod(gdb.Command): | |
179 | """GDB command to list registered xmethod matchers. | |
180 | ||
13123da8 | 181 | Usage: info xmethod [LOCUS-REGEXP [NAME-REGEXP]] |
2fb009bb | 182 | |
13123da8 SM |
183 | LOCUS-REGEXP is a regular expression matching the location of the |
184 | xmethod matchers. If it is omitted, all registered xmethod matchers | |
185 | from all loci are listed. A locus could be 'global', a regular expression | |
186 | matching the current program space's filename, or a regular expression | |
187 | matching filenames of objfiles. Locus could be 'progspace' to specify that | |
188 | only xmethods from the current progspace should be listed. | |
2fb009bb | 189 | |
13123da8 SM |
190 | NAME-REGEXP is a regular expression matching the names of xmethod |
191 | matchers. If this omitted for a specified locus, then all registered | |
192 | xmethods in the locus are listed. To list only a certain xmethods | |
193 | managed by a single matcher, the name regexp can be specified as | |
194 | matcher-name-regexp;xmethod-name-regexp.""" | |
883964a7 SC |
195 | |
196 | def __init__(self): | |
13123da8 | 197 | super(InfoXMethod, self).__init__("info xmethod", gdb.COMMAND_DATA) |
883964a7 SC |
198 | |
199 | def invoke(self, arg, from_tty): | |
200 | locus_re, matcher_re, name_re = parse_xm_command_args(arg) | |
13123da8 | 201 | print_xm_info(get_global_method_matchers(locus_re, matcher_re), name_re) |
883964a7 SC |
202 | print_xm_info( |
203 | get_method_matchers_in_loci( | |
13123da8 SM |
204 | [gdb.current_progspace()], locus_re, matcher_re |
205 | ), | |
206 | name_re, | |
207 | ) | |
883964a7 | 208 | print_xm_info( |
13123da8 SM |
209 | get_method_matchers_in_loci(gdb.objfiles(), locus_re, matcher_re), name_re |
210 | ) | |
883964a7 SC |
211 | |
212 | ||
213 | class EnableXMethod(gdb.Command): | |
214 | """GDB command to enable a specified (group of) xmethod(s). | |
215 | ||
13123da8 | 216 | Usage: enable xmethod [LOCUS-REGEXP [NAME-REGEXP]] |
883964a7 | 217 | |
13123da8 SM |
218 | LOCUS-REGEXP is a regular expression matching the location of the |
219 | xmethod matchers. If it is omitted, all registered xmethods matchers | |
220 | from all loci are enabled. A locus could be 'global', a regular expression | |
221 | matching the current program space's filename, or a regular expression | |
222 | matching filenames of objfiles. Locus could be 'progspace' to specify that | |
223 | only xmethods from the current progspace should be enabled. | |
883964a7 | 224 | |
13123da8 SM |
225 | NAME-REGEXP is a regular expression matching the names of xmethods |
226 | within a given locus. If this omitted for a specified locus, then all | |
227 | registered xmethod matchers in the locus are enabled. To enable only | |
228 | a certain xmethods managed by a single matcher, the name regexp can be | |
229 | specified as matcher-name-regexp;xmethod-name-regexp.""" | |
883964a7 SC |
230 | |
231 | def __init__(self): | |
13123da8 | 232 | super(EnableXMethod, self).__init__("enable xmethod", gdb.COMMAND_DATA) |
883964a7 SC |
233 | |
234 | def invoke(self, arg, from_tty): | |
235 | set_xm_status(arg, True) | |
236 | ||
237 | ||
238 | class DisableXMethod(gdb.Command): | |
239 | """GDB command to disable a specified (group of) xmethod(s). | |
240 | ||
13123da8 | 241 | Usage: disable xmethod [LOCUS-REGEXP [NAME-REGEXP]] |
883964a7 | 242 | |
13123da8 SM |
243 | LOCUS-REGEXP is a regular expression matching the location of the |
244 | xmethod matchers. If it is omitted, all registered xmethod matchers | |
245 | from all loci are disabled. A locus could be 'global', a regular | |
246 | expression matching the current program space's filename, or a regular | |
247 | expression filenames of objfiles. Locus could be 'progspace' to specify | |
248 | that only xmethods from the current progspace should be disabled. | |
883964a7 | 249 | |
13123da8 SM |
250 | NAME-REGEXP is a regular expression matching the names of xmethods |
251 | within a given locus. If this omitted for a specified locus, then all | |
252 | registered xmethod matchers in the locus are disabled. To disable | |
253 | only a certain xmethods managed by a single matcher, the name regexp | |
254 | can be specified as matcher-name-regexp;xmethod-name-regexp.""" | |
883964a7 SC |
255 | |
256 | def __init__(self): | |
13123da8 | 257 | super(DisableXMethod, self).__init__("disable xmethod", gdb.COMMAND_DATA) |
883964a7 SC |
258 | |
259 | def invoke(self, arg, from_tty): | |
260 | set_xm_status(arg, False) | |
261 | ||
262 | ||
263 | def register_xmethod_commands(): | |
264 | """Installs the xmethod commands.""" | |
265 | InfoXMethod() | |
266 | EnableXMethod() | |
267 | DisableXMethod() | |
268 | ||
269 | ||
270 | register_xmethod_commands() |