py-xmethods.py revision 1.7
1# Copyright 2014-2020 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 19import gdb 20import re 21 22from gdb.xmethod import XMethod 23from gdb.xmethod import XMethodMatcher, XMethodWorker 24from gdb.xmethod import SimpleXMethodMatcher 25 26 27def A_plus_A(obj, opr): 28 print('From Python <A_plus_A>:') 29 return obj['a'] + opr['a'] 30 31 32def plus_plus_A(obj): 33 print('From Python <plus_plus_A>:') 34 return obj['a'] + 1 35 36 37def A_geta(obj): 38 print('From Python <A_geta>:') 39 return obj['a'] 40 41 42def A_getarrayind(obj, index): 43 print('From Python <A_getarrayind>:') 44 return obj['array'][index] 45 46def A_indexoper(obj, index): 47 return obj['array'][index].reference_value() 48 49def B_indexoper(obj, index): 50 return obj['array'][index].const_value().reference_value() 51 52 53type_A = gdb.parse_and_eval('(dop::A *) 0').type.target() 54type_B = gdb.parse_and_eval('(dop::B *) 0').type.target() 55type_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 62class 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 77class 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 91class 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 114class 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 128class 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 141class 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 154class 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 201global_dm_list = [ 202 SimpleXMethodMatcher(r'A_plus_A', 203 r'^dop::A$', 204 r'operator\+', 205 A_plus_A, 206 # This is a replacement, hence match the arg type 207 # exactly! 208 type_A.const().reference()), 209 SimpleXMethodMatcher(r'plus_plus_A', 210 r'^dop::A$', 211 r'operator\+\+', 212 plus_plus_A), 213 SimpleXMethodMatcher(r'A_geta', 214 r'^dop::A$', 215 r'^geta$', 216 A_geta), 217 SimpleXMethodMatcher(r'A_getarrayind', 218 r'^dop::A$', 219 r'^getarrayind$', 220 A_getarrayind, 221 type_int), 222 SimpleXMethodMatcher(r'A_indexoper', 223 r'^dop::A$', 224 r'operator\[\]', 225 A_indexoper, 226 type_int), 227 SimpleXMethodMatcher(r'B_indexoper', 228 r'^dop::B$', 229 r'operator\[\]', 230 B_indexoper, 231 type_int) 232] 233 234for matcher in global_dm_list: 235 gdb.xmethod.register_xmethod_matcher(gdb, matcher) 236gdb.xmethod.register_xmethod_matcher(gdb.current_progspace(), 237 G_methods_matcher()) 238gdb.xmethod.register_xmethod_matcher(gdb.current_progspace(), 239 E_method_matcher()) 240