1# Copyright 2014-2023 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 46 47def A_indexoper(obj, index): 48 return obj["array"][index].reference_value() 49 50 51def B_indexoper(obj, index): 52 return obj["array"][index].const_value().reference_value() 53 54 55type_A = gdb.parse_and_eval("(dop::A *) 0").type.target() 56type_B = gdb.parse_and_eval("(dop::B *) 0").type.target() 57type_int = gdb.parse_and_eval("(int *) 0").type.target() 58 59 60# The E class matcher and worker test two things: 61# 1. xmethod returning None. 62# 2. Matcher returning a list of workers. 63 64 65class E_method_char_worker(XMethodWorker): 66 def __init__(self): 67 pass 68 69 def get_arg_types(self): 70 return gdb.lookup_type("char") 71 72 def get_result_type(self, obj, arg): 73 return gdb.lookup_type("void") 74 75 def __call__(self, obj, arg): 76 print("From Python <E_method_char>") 77 return None 78 79 80class E_method_int_worker(XMethodWorker): 81 def __init__(self): 82 pass 83 84 def get_arg_types(self): 85 return gdb.lookup_type("int") 86 87 # Note: get_result_type method elided on purpose 88 89 def __call__(self, obj, arg): 90 print("From Python <E_method_int>") 91 return None 92 93 94class E_method_matcher(XMethodMatcher): 95 def __init__(self): 96 XMethodMatcher.__init__(self, "E_methods") 97 self.methods = [XMethod("method_int"), XMethod("method_char")] 98 99 def match(self, class_type, method_name): 100 class_tag = class_type.unqualified().tag 101 if not re.match("^dop::E$", class_tag): 102 return None 103 if not re.match("^method$", method_name): 104 return None 105 workers = [] 106 if self.methods[0].enabled: 107 workers.append(E_method_int_worker()) 108 if self.methods[1].enabled: 109 workers.append(E_method_char_worker()) 110 return workers 111 112 113# The G class method matcher and worker illustrate how to write 114# xmethod matchers and workers for template classes and template 115# methods. 116 117 118class G_size_diff_worker(XMethodWorker): 119 def __init__(self, class_template_type, method_template_type): 120 self._class_template_type = class_template_type 121 self._method_template_type = method_template_type 122 123 def get_arg_types(self): 124 pass 125 126 def __call__(self, obj): 127 print("From Python G<>::size_diff()") 128 return self._method_template_type.sizeof - self._class_template_type.sizeof 129 130 131class G_size_mul_worker(XMethodWorker): 132 def __init__(self, class_template_type, method_template_val): 133 self._class_template_type = class_template_type 134 self._method_template_val = method_template_val 135 136 def get_arg_types(self): 137 pass 138 139 def __call__(self, obj): 140 print("From Python G<>::size_mul()") 141 return self._class_template_type.sizeof * self._method_template_val 142 143 144class G_mul_worker(XMethodWorker): 145 def __init__(self, class_template_type, method_template_type): 146 self._class_template_type = class_template_type 147 self._method_template_type = method_template_type 148 149 def get_arg_types(self): 150 return self._method_template_type 151 152 def __call__(self, obj, arg): 153 print("From Python G<>::mul()") 154 return obj["t"] * arg 155 156 157class G_methods_matcher(XMethodMatcher): 158 def __init__(self): 159 XMethodMatcher.__init__(self, "G_methods") 160 self.methods = [XMethod("size_diff"), XMethod("size_mul"), XMethod("mul")] 161 162 def _is_enabled(self, name): 163 for method in self.methods: 164 if method.name == name and method.enabled: 165 return True 166 167 def match(self, class_type, method_name): 168 class_tag = class_type.unqualified().tag 169 if not re.match("^dop::G<[ ]*[_a-zA-Z][ _a-zA-Z0-9]*>$", 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( 203 r"A_plus_A", 204 r"^dop::A$", 205 r"operator\+", 206 A_plus_A, 207 # This is a replacement, hence match the arg type 208 # exactly! 209 type_A.const().reference(), 210 ), 211 SimpleXMethodMatcher(r"plus_plus_A", r"^dop::A$", r"operator\+\+", plus_plus_A), 212 SimpleXMethodMatcher(r"A_geta", r"^dop::A$", r"^geta$", A_geta), 213 SimpleXMethodMatcher( 214 r"A_getarrayind", r"^dop::A$", r"^getarrayind$", A_getarrayind, type_int 215 ), 216 SimpleXMethodMatcher( 217 r"A_indexoper", r"^dop::A$", r"operator\[\]", A_indexoper, type_int 218 ), 219 SimpleXMethodMatcher( 220 r"B_indexoper", r"^dop::B$", r"operator\[\]", B_indexoper, type_int 221 ), 222] 223 224for matcher in global_dm_list: 225 gdb.xmethod.register_xmethod_matcher(gdb, matcher) 226gdb.xmethod.register_xmethod_matcher(gdb.current_progspace(), G_methods_matcher()) 227gdb.xmethod.register_xmethod_matcher(gdb.current_progspace(), E_method_matcher()) 228