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