587842d7360e9d5e0b203ca87d85409c807fae48
[external/binutils.git] / gdb / testsuite / gdb.python / py-xmethods.py
1 # Copyright 2014-2019 Free Software Foundation, Inc.
2
3 # This program is free software; you can redistribute it and/or modify
4 # it under the terms of the GNU General Public License as published by
5 # the Free Software Foundation; either version 3 of the License, or
6 # (at your option) any later version.
7 #
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 # GNU General Public License for more details.
12 #
13 # You should have received a copy of the GNU General Public License
14 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
15
16 # This file is part of the GDB testsuite.  It test the xmethods support
17 # in the Python extension language.
18
19 import gdb
20 import re
21
22 from gdb.xmethod import XMethod
23 from gdb.xmethod import XMethodMatcher, XMethodWorker
24 from gdb.xmethod import SimpleXMethodMatcher
25
26
27 def A_plus_A(obj, opr):
28   print('From Python <A_plus_A>:')
29   return obj['a'] + opr['a']
30
31
32 def plus_plus_A(obj):
33   print('From Python <plus_plus_A>:')
34   return obj['a'] + 1
35
36
37 def A_geta(obj):
38   print('From Python <A_geta>:')
39   return obj['a']
40
41
42 def A_getarrayind(obj, index):
43   print('From Python <A_getarrayind>:')
44   return obj['array'][index]
45
46 def A_indexoper(obj, index):
47   return obj['array'][index].reference_value()
48
49 def B_indexoper(obj, index):
50   return obj['array'][index].const_value().reference_value()
51
52
53 type_A = gdb.parse_and_eval('(dop::A *) 0').type.target()
54 type_B = gdb.parse_and_eval('(dop::B *) 0').type.target()
55 type_int = gdb.parse_and_eval('(int *) 0').type.target()
56
57
58 # The E class matcher and worker test two things:
59 #   1. xmethod returning None.
60 #   2. Matcher returning a list of workers.
61
62 class E_method_char_worker(XMethodWorker):
63     def __init__(self):
64         pass
65
66     def get_arg_types(self):
67         return gdb.lookup_type('char')
68
69     def get_result_type(self, obj, arg):
70         return gdb.lookup_type('void')
71
72     def __call__(self, obj, arg):
73         print('From Python <E_method_char>')
74         return None
75
76
77 class E_method_int_worker(XMethodWorker):
78     def __init__(self):
79         pass
80
81     def get_arg_types(self):
82         return gdb.lookup_type('int')
83
84     # Note: get_result_type method elided on purpose
85
86     def __call__(self, obj, arg):
87         print('From Python <E_method_int>')
88         return None
89
90
91 class E_method_matcher(XMethodMatcher):
92     def __init__(self):
93         XMethodMatcher.__init__(self, 'E_methods')
94         self.methods = [XMethod('method_int'), XMethod('method_char')]
95
96     def match(self, class_type, method_name):
97         class_tag = class_type.unqualified().tag
98         if not re.match('^dop::E$', class_tag):
99             return None
100         if not re.match('^method$', method_name):
101             return None
102         workers = []
103         if self.methods[0].enabled:
104             workers.append(E_method_int_worker())
105         if self.methods[1].enabled:
106             workers.append(E_method_char_worker())
107         return workers
108
109
110 # The G class method matcher and worker illustrate how to write
111 # xmethod matchers and workers for template classes and template
112 # methods.
113
114 class G_size_diff_worker(XMethodWorker):
115     def __init__(self, class_template_type, method_template_type):
116         self._class_template_type = class_template_type
117         self._method_template_type = method_template_type
118
119     def get_arg_types(self):
120         pass
121
122     def __call__(self, obj):
123         print('From Python G<>::size_diff()')
124         return (self._method_template_type.sizeof -
125                 self._class_template_type.sizeof)
126
127
128 class G_size_mul_worker(XMethodWorker):
129     def __init__(self, class_template_type, method_template_val):
130         self._class_template_type = class_template_type
131         self._method_template_val = method_template_val
132
133     def get_arg_types(self):
134         pass
135
136     def __call__(self, obj):
137         print('From Python G<>::size_mul()')
138         return self._class_template_type.sizeof * self._method_template_val
139
140
141 class G_mul_worker(XMethodWorker):
142     def __init__(self, class_template_type, method_template_type):
143         self._class_template_type = class_template_type
144         self._method_template_type = method_template_type
145
146     def get_arg_types(self):
147         return self._method_template_type
148
149     def __call__(self, obj, arg):
150         print('From Python G<>::mul()')
151         return obj['t'] * arg
152
153
154 class G_methods_matcher(XMethodMatcher):
155     def __init__(self):
156         XMethodMatcher.__init__(self, 'G_methods')
157         self.methods = [XMethod('size_diff'),
158                         XMethod('size_mul'),
159                         XMethod('mul')]
160
161     def _is_enabled(self, name):
162         for method in self.methods:
163             if method.name == name and method.enabled:
164                 return True
165
166     def match(self, class_type, method_name):
167         class_tag = class_type.unqualified().tag
168         if not re.match('^dop::G<[ ]*[_a-zA-Z][ _a-zA-Z0-9]*>$',
169                         class_tag):
170             return None
171         t_name = class_tag[7:-1]
172         try:
173             t_type = gdb.lookup_type(t_name)
174         except gdb.error:
175             return None
176         if re.match('^size_diff<[ ]*[_a-zA-Z][ _a-zA-Z0-9]*>$', method_name):
177             if not self._is_enabled('size_diff'):
178                 return None
179             t1_name = method_name[10:-1]
180             try:
181                 t1_type = gdb.lookup_type(t1_name)
182                 return G_size_diff_worker(t_type, t1_type)
183             except gdb.error:
184                 return None
185         if re.match('^size_mul<[ ]*[0-9]+[ ]*>$', method_name):
186             if not self._is_enabled('size_mul'):
187                 return None
188             m_val = int(method_name[9:-1])
189             return G_size_mul_worker(t_type, m_val)
190         if re.match('^mul<[ ]*[_a-zA-Z][ _a-zA-Z0-9]*>$', method_name):
191             if not self._is_enabled('mul'):
192                 return None
193             t1_name = method_name[4:-1]
194             try:
195                 t1_type = gdb.lookup_type(t1_name)
196                 return G_mul_worker(t_type, t1_type)
197             except gdb.error:
198                 return None
199
200
201 global_dm_list = [
202     SimpleXMethodMatcher('A_plus_A',
203                          '^dop::A$',
204                          'operator\+',
205                          A_plus_A,
206                          # This is a replacement, hence match the arg type
207                          # exactly!
208                          type_A.const().reference()),
209     SimpleXMethodMatcher('plus_plus_A',
210                          '^dop::A$',
211                          'operator\+\+',
212                          plus_plus_A),
213     SimpleXMethodMatcher('A_geta',
214                          '^dop::A$',
215                          '^geta$',
216                          A_geta),
217     SimpleXMethodMatcher('A_getarrayind',
218                          '^dop::A$',
219                          '^getarrayind$',
220                          A_getarrayind,
221                          type_int),
222     SimpleXMethodMatcher('A_indexoper',
223                          '^dop::A$',
224                          'operator\\[\\]',
225                          A_indexoper,
226                          type_int),
227     SimpleXMethodMatcher('B_indexoper',
228                          '^dop::B$',
229                          'operator\\[\\]',
230                          B_indexoper,
231                          type_int)
232 ]
233
234 for matcher in global_dm_list:
235     gdb.xmethod.register_xmethod_matcher(gdb, matcher)
236 gdb.xmethod.register_xmethod_matcher(gdb.current_progspace(),
237                                      G_methods_matcher())
238 gdb.xmethod.register_xmethod_matcher(gdb.current_progspace(),
239                                      E_method_matcher())