]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gdb/python/lib/gdb/command/xmethods.py
Update copyright year range in header of all files managed by GDB
[thirdparty/binutils-gdb.git] / gdb / python / lib / gdb / command / xmethods.py
1 # Xmethod commands.
2 # Copyright 2013-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
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 (
60 validate_xm_regexp("locus", locus_regexp),
61 validate_xm_regexp("matcher name", matcher_name_regexp),
62 name_re,
63 )
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"
80 xm_dict = {locus_str: []}
81 if locus_re.match("global"):
82 xm_dict[locus_str].extend([m for m in gdb.xmethods if matcher_re.match(m.name)])
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.
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.
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):
106 if not locus_re.match("progspace"):
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)
114 xm_dict[locus_str] = [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
121 def get_status_string(m):
122 if not m.enabled:
123 return " [disabled]"
124 else:
125 return ""
126
127 if not xm_dict:
128 return
129 for locus_str in xm_dict:
130 if not xm_dict[locus_str]:
131 continue
132 print("Xmethods in %s:" % locus_str)
133 for matcher in xm_dict[locus_str]:
134 print(" %s%s" % (matcher.name, get_status_string(matcher)))
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):
139 print(" %s%s" % (m.name, get_status_string(m)))
140
141
142 def set_xm_status1(xm_dict, name_re, status):
143 """Set the status (enabled/disabled) of a dictionary of xmethods."""
144 for locus_str, matchers in xm_dict.items():
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)
165 set_xm_status1(get_global_method_matchers(locus_re, matcher_re), name_re, status)
166 set_xm_status1(
167 get_method_matchers_in_loci([gdb.current_progspace()], locus_re, matcher_re),
168 name_re,
169 status,
170 )
171 set_xm_status1(
172 get_method_matchers_in_loci(gdb.objfiles(), locus_re, matcher_re),
173 name_re,
174 status,
175 )
176
177
178 class InfoXMethod(gdb.Command):
179 """GDB command to list registered xmethod matchers.
180
181 Usage: info xmethod [LOCUS-REGEXP [NAME-REGEXP]]
182
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.
189
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."""
195
196 def __init__(self):
197 super(InfoXMethod, self).__init__("info xmethod", gdb.COMMAND_DATA)
198
199 def invoke(self, arg, from_tty):
200 locus_re, matcher_re, name_re = parse_xm_command_args(arg)
201 print_xm_info(get_global_method_matchers(locus_re, matcher_re), name_re)
202 print_xm_info(
203 get_method_matchers_in_loci(
204 [gdb.current_progspace()], locus_re, matcher_re
205 ),
206 name_re,
207 )
208 print_xm_info(
209 get_method_matchers_in_loci(gdb.objfiles(), locus_re, matcher_re), name_re
210 )
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 def __init__(self):
232 super(EnableXMethod, self).__init__("enable xmethod", gdb.COMMAND_DATA)
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
241 Usage: disable xmethod [LOCUS-REGEXP [NAME-REGEXP]]
242
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.
249
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."""
255
256 def __init__(self):
257 super(DisableXMethod, self).__init__("disable xmethod", gdb.COMMAND_DATA)
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()