]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gdb/python/lib/gdb/xmethod.py
Xmethod support in Python.
[thirdparty/binutils-gdb.git] / gdb / python / lib / gdb / xmethod.py
1 # Python side of the support for xmethods.
2 # Copyright (C) 2013-2014 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.
105
106 Derived classes should override the 'get_arg_types' and '__call__' methods.
107 """
108
109 def get_arg_types(self):
110 """Return arguments types of an xmethod.
111
112 A sequence of gdb.Type objects corresponding to the arguments of the
113 xmethod are returned. If the xmethod takes no arguments, then 'None'
114 or an empty sequence is returned. If the xmethod takes only a single
115 argument, then a gdb.Type object or a sequence with a single gdb.Type
116 element is returned.
117 """
118 raise NotImplementedError("XMethodWorker get_arg_types")
119
120 def __call__(self, *args):
121 """Invoke the xmethod.
122
123 Args:
124 args: Arguments to the method. Each element of the tuple is a
125 gdb.Value object. The first element is the 'this' pointer
126 value.
127
128 Returns:
129 A gdb.Value corresponding to the value returned by the xmethod.
130 Returns 'None' if the method does not return anything.
131 """
132 raise NotImplementedError("XMethodWorker __call__")
133
134
135 class SimpleXMethodMatcher(XMethodMatcher):
136 """A utility class to implement simple xmethod mathers and workers.
137
138 See the __init__ method below for information on how instances of this
139 class can be used.
140
141 For simple classes and methods, one can choose to use this class. For
142 complex xmethods, which need to replace/implement template methods on
143 possibly template classes, one should implement their own xmethod
144 matchers and workers. See py-xmethods.py in testsuite/gdb.python
145 directory of the GDB source tree for examples.
146 """
147
148 class SimpleXMethodWorker(XMethodWorker):
149 def __init__(self, method_function, arg_types):
150 self._arg_types = arg_types
151 self._method_function = method_function
152
153 def get_arg_types(self):
154 return self._arg_types
155
156 def __call__(self, *args):
157 return self._method_function(*args)
158
159
160 def __init__(self, name, class_matcher, method_matcher, method_function,
161 *arg_types):
162 """
163 Args:
164 name: Name of the xmethod matcher.
165 class_matcher: A regular expression used to match the name of the
166 class whose method this xmethod is implementing/replacing.
167 method_matcher: A regular expression used to match the name of the
168 method this xmethod is implementing/replacing.
169 method_function: A Python callable which would be called via the
170 'invoke' method of the worker returned by the objects of this
171 class. This callable should accept the object (*this) as the
172 first argument followed by the rest of the arguments to the
173 method. All arguments to this function should be gdb.Value
174 objects.
175 arg_types: The gdb.Type objects corresponding to the arguments that
176 this xmethod takes. It can be None, or an empty sequence,
177 or a single gdb.Type object, or a sequence of gdb.Type objects.
178 """
179 XMethodMatcher.__init__(self, name)
180 assert callable(method_function), (
181 "The 'method_function' argument to 'SimpleXMethodMatcher' "
182 "__init__ method should be a callable.")
183 self._method_function = method_function
184 self._class_matcher = class_matcher
185 self._method_matcher = method_matcher
186 self._arg_types = arg_types
187
188 def match(self, class_type, method_name):
189 cm = re.match(self._class_matcher, str(class_type.unqualified().tag))
190 mm = re.match(self._method_matcher, method_name)
191 if cm and mm:
192 return SimpleXMethodMatcher.SimpleXMethodWorker(
193 self._method_function, self._arg_types)
194
195
196 # A helper function for register_xmethod_matcher which returns an error
197 # object if MATCHER is not having the requisite attributes in the proper
198 # format.
199
200 def _validate_xmethod_matcher(matcher):
201 if not hasattr(matcher, "match"):
202 return TypeError("Xmethod matcher is missing method: match")
203 if not hasattr(matcher, "name"):
204 return TypeError("Xmethod matcher is missing attribute: name")
205 if not hasattr(matcher, "enabled"):
206 return TypeError("Xmethod matcher is missing attribute: enabled")
207 if not isinstance(matcher.name, basestring):
208 return TypeError("Attribute 'name' of xmethod matcher is not a "
209 "string")
210 if matcher.name.find(";") >= 0:
211 return ValueError("Xmethod matcher name cannot contain ';' in it")
212
213
214 # A helper function for register_xmethod_matcher which looks up an
215 # xmethod matcher with NAME in LOCUS. Returns the index of the xmethod
216 # matcher in 'xmethods' sequence attribute of the LOCUS. If NAME is not
217 # found in LOCUS, then -1 is returned.
218
219 def _lookup_xmethod_matcher(locus, name):
220 for i in range(0, len(locus.xmethods)):
221 if locus.xmethods[i].name == name:
222 return i
223 return -1
224
225
226 def register_xmethod_matcher(locus, matcher, replace=False):
227 """Registers a xmethod matcher MATCHER with a LOCUS.
228
229 Arguments:
230 locus: The locus in which the xmethods should be registered.
231 It can be 'None' to indicate that the xmethods should be
232 registered globally. Or, it could be a gdb.Objfile or a
233 gdb.Progspace object in which the xmethods should be
234 registered.
235 matcher: The xmethod matcher to register with the LOCUS. It
236 should be an instance of 'XMethodMatcher' class.
237 replace: If True, replace any existing xmethod matcher with the
238 same name in the locus. Otherwise, if a matcher with the same name
239 exists in the locus, raise an exception.
240 """
241 err = _validate_xmethod_matcher(matcher)
242 if err:
243 raise err
244 if not locus:
245 locus = gdb
246 if locus == gdb:
247 locus_name = "global"
248 else:
249 locus_name = locus.filename
250 index = _lookup_xmethod_matcher(locus, matcher.name)
251 if index >= 0:
252 if replace:
253 del locus.xmethods[index]
254 else:
255 raise RuntimeError("Xmethod matcher already registered with "
256 "%s: %s" % (locus_name, matcher.name))
257 if gdb.parameter("verbose"):
258 gdb.write("Registering xmethod matcher '%s' with %s' ...\n")
259 locus.xmethods.insert(0, matcher)