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