]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gdb/python/lib/gdb/xmethod.py
gdb/python: remove Python 2 support
[thirdparty/binutils-gdb.git] / gdb / python / lib / gdb / xmethod.py
CommitLineData
883964a7 1# Python side of the support for xmethods.
4a94e368 2# Copyright (C) 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"""Utilities for defining xmethods"""
18
19import gdb
20import re
21import sys
22
23
883964a7
SC
24class XMethod(object):
25 """Base class (or a template) for an xmethod description.
26
27 Currently, the description requires only the 'name' and 'enabled'
28 attributes. Description objects are managed by 'XMethodMatcher'
29 objects (see below). Note that this is only a template for the
30 interface of the XMethodMatcher.methods objects. One could use
31 this class or choose to use an object which supports this exact same
32 interface. Also, an XMethodMatcher can choose not use it 'methods'
33 attribute. In such cases this class (or an equivalent) is not used.
34
35 Attributes:
36 name: The name of the xmethod.
37 enabled: A boolean indicating if the xmethod is enabled.
38 """
39
40 def __init__(self, name):
41 self.name = name
42 self.enabled = True
43
44
45class XMethodMatcher(object):
46 """Abstract base class for matching an xmethod.
47
48 When looking for xmethods, GDB invokes the `match' method of a
49 registered xmethod matcher to match the object type and method name.
50 The `match' method in concrete classes derived from this class should
51 return an `XMethodWorker' object, or a list of `XMethodWorker'
52 objects if there is a match (see below for 'XMethodWorker' class).
53
54 Attributes:
55 name: The name of the matcher.
56 enabled: A boolean indicating if the matcher is enabled.
57 methods: A sequence of objects of type 'XMethod', or objects
58 which have at least the attributes of an 'XMethod' object.
59 This list is used by the 'enable'/'disable'/'info' commands to
60 enable/disable/list the xmethods registered with GDB. See
61 the 'match' method below to know how this sequence is used.
62 This attribute is None if the matcher chooses not have any
63 xmethods managed by it.
64 """
65
66 def __init__(self, name):
67 """
68 Args:
69 name: An identifying name for the xmethod or the group of
70 xmethods returned by the `match' method.
71 """
72 self.name = name
73 self.enabled = True
74 self.methods = None
75
76 def match(self, class_type, method_name):
77 """Match class type and method name.
78
79 In derived classes, it should return an XMethodWorker object, or a
80 sequence of 'XMethodWorker' objects. Only those xmethod workers
81 whose corresponding 'XMethod' descriptor object is enabled should be
82 returned.
83
84 Args:
85 class_type: The class type (gdb.Type object) to match.
86 method_name: The name (string) of the method to match.
87 """
88 raise NotImplementedError("XMethodMatcher match")
89
90
91class XMethodWorker(object):
92 """Base class for all xmethod workers defined in Python.
93
94 An xmethod worker is an object which matches the method arguments, and
95 invokes the method when GDB wants it to. Internally, GDB first invokes the
96 'get_arg_types' method to perform overload resolution. If GDB selects to
97 invoke this Python xmethod, then it invokes it via the overridden
2ce1cdbf
DE
98 '__call__' method. The 'get_result_type' method is used to implement
99 'ptype' on the xmethod.
883964a7 100
2ce1cdbf
DE
101 Derived classes should override the 'get_arg_types', 'get_result_type'
102 and '__call__' methods.
883964a7
SC
103 """
104
105 def get_arg_types(self):
106 """Return arguments types of an xmethod.
107
108 A sequence of gdb.Type objects corresponding to the arguments of the
109 xmethod are returned. If the xmethod takes no arguments, then 'None'
110 or an empty sequence is returned. If the xmethod takes only a single
111 argument, then a gdb.Type object or a sequence with a single gdb.Type
112 element is returned.
113 """
114 raise NotImplementedError("XMethodWorker get_arg_types")
115
2ce1cdbf
DE
116 def get_result_type(self, *args):
117 """Return the type of the result of the xmethod.
118
119 Args:
120 args: Arguments to the method. Each element of the tuple is a
121 gdb.Value object. The first element is the 'this' pointer
122 value. These are the same arguments passed to '__call__'.
123
124 Returns:
125 A gdb.Type object representing the type of the result of the
126 xmethod.
127 """
128 raise NotImplementedError("XMethodWorker get_result_type")
129
883964a7
SC
130 def __call__(self, *args):
131 """Invoke the xmethod.
132
133 Args:
134 args: Arguments to the method. Each element of the tuple is a
135 gdb.Value object. The first element is the 'this' pointer
136 value.
137
138 Returns:
139 A gdb.Value corresponding to the value returned by the xmethod.
140 Returns 'None' if the method does not return anything.
141 """
142 raise NotImplementedError("XMethodWorker __call__")
143
144
145class SimpleXMethodMatcher(XMethodMatcher):
146 """A utility class to implement simple xmethod mathers and workers.
147
148 See the __init__ method below for information on how instances of this
149 class can be used.
150
151 For simple classes and methods, one can choose to use this class. For
152 complex xmethods, which need to replace/implement template methods on
153 possibly template classes, one should implement their own xmethod
154 matchers and workers. See py-xmethods.py in testsuite/gdb.python
155 directory of the GDB source tree for examples.
156 """
157
158 class SimpleXMethodWorker(XMethodWorker):
159 def __init__(self, method_function, arg_types):
160 self._arg_types = arg_types
161 self._method_function = method_function
162
163 def get_arg_types(self):
164 return self._arg_types
165
166 def __call__(self, *args):
167 return self._method_function(*args)
168
13123da8
SM
169 def __init__(
170 self, name, class_matcher, method_matcher, method_function, *arg_types
171 ):
883964a7
SC
172 """
173 Args:
174 name: Name of the xmethod matcher.
175 class_matcher: A regular expression used to match the name of the
176 class whose method this xmethod is implementing/replacing.
177 method_matcher: A regular expression used to match the name of the
178 method this xmethod is implementing/replacing.
179 method_function: A Python callable which would be called via the
180 'invoke' method of the worker returned by the objects of this
181 class. This callable should accept the object (*this) as the
182 first argument followed by the rest of the arguments to the
183 method. All arguments to this function should be gdb.Value
184 objects.
185 arg_types: The gdb.Type objects corresponding to the arguments that
186 this xmethod takes. It can be None, or an empty sequence,
187 or a single gdb.Type object, or a sequence of gdb.Type objects.
188 """
189 XMethodMatcher.__init__(self, name)
190 assert callable(method_function), (
191 "The 'method_function' argument to 'SimpleXMethodMatcher' "
13123da8
SM
192 "__init__ method should be a callable."
193 )
883964a7
SC
194 self._method_function = method_function
195 self._class_matcher = class_matcher
196 self._method_matcher = method_matcher
197 self._arg_types = arg_types
198
199 def match(self, class_type, method_name):
200 cm = re.match(self._class_matcher, str(class_type.unqualified().tag))
201 mm = re.match(self._method_matcher, method_name)
202 if cm and mm:
203 return SimpleXMethodMatcher.SimpleXMethodWorker(
13123da8
SM
204 self._method_function, self._arg_types
205 )
883964a7
SC
206
207
208# A helper function for register_xmethod_matcher which returns an error
209# object if MATCHER is not having the requisite attributes in the proper
210# format.
211
13123da8 212
883964a7
SC
213def _validate_xmethod_matcher(matcher):
214 if not hasattr(matcher, "match"):
215 return TypeError("Xmethod matcher is missing method: match")
216 if not hasattr(matcher, "name"):
217 return TypeError("Xmethod matcher is missing attribute: name")
218 if not hasattr(matcher, "enabled"):
219 return TypeError("Xmethod matcher is missing attribute: enabled")
edae3fd6 220 if not isinstance(matcher.name, str):
13123da8 221 return TypeError("Attribute 'name' of xmethod matcher is not a " "string")
883964a7
SC
222 if matcher.name.find(";") >= 0:
223 return ValueError("Xmethod matcher name cannot contain ';' in it")
224
225
13123da8 226# A helper function for register_xmethod_matcher which looks up an
883964a7
SC
227# xmethod matcher with NAME in LOCUS. Returns the index of the xmethod
228# matcher in 'xmethods' sequence attribute of the LOCUS. If NAME is not
229# found in LOCUS, then -1 is returned.
230
13123da8 231
883964a7
SC
232def _lookup_xmethod_matcher(locus, name):
233 for i in range(0, len(locus.xmethods)):
234 if locus.xmethods[i].name == name:
235 return i
236 return -1
237
238
239def register_xmethod_matcher(locus, matcher, replace=False):
240 """Registers a xmethod matcher MATCHER with a LOCUS.
241
242 Arguments:
243 locus: The locus in which the xmethods should be registered.
244 It can be 'None' to indicate that the xmethods should be
245 registered globally. Or, it could be a gdb.Objfile or a
246 gdb.Progspace object in which the xmethods should be
247 registered.
248 matcher: The xmethod matcher to register with the LOCUS. It
249 should be an instance of 'XMethodMatcher' class.
250 replace: If True, replace any existing xmethod matcher with the
251 same name in the locus. Otherwise, if a matcher with the same name
252 exists in the locus, raise an exception.
253 """
254 err = _validate_xmethod_matcher(matcher)
255 if err:
256 raise err
257 if not locus:
258 locus = gdb
259 if locus == gdb:
260 locus_name = "global"
261 else:
262 locus_name = locus.filename
263 index = _lookup_xmethod_matcher(locus, matcher.name)
264 if index >= 0:
265 if replace:
266 del locus.xmethods[index]
267 else:
13123da8
SM
268 raise RuntimeError(
269 "Xmethod matcher already registered with "
270 "%s: %s" % (locus_name, matcher.name)
271 )
883964a7
SC
272 if gdb.parameter("verbose"):
273 gdb.write("Registering xmethod matcher '%s' with %s' ...\n")
274 locus.xmethods.insert(0, matcher)