# Copyright 2014-2023 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # This file is part of the GDB testsuite. It test the xmethods support # in the Python extension language. import gdb import re from gdb.xmethod import XMethod from gdb.xmethod import XMethodMatcher, XMethodWorker from gdb.xmethod import SimpleXMethodMatcher def A_plus_A(obj, opr): print("From Python :") return obj["a"] + opr["a"] def plus_plus_A(obj): print("From Python :") return obj["a"] + 1 def A_geta(obj): print("From Python :") return obj["a"] def A_getarrayind(obj, index): print("From Python :") return obj["array"][index] def A_indexoper(obj, index): return obj["array"][index].reference_value() def B_indexoper(obj, index): return obj["array"][index].const_value().reference_value() type_A = gdb.parse_and_eval("(dop::A *) 0").type.target() type_B = gdb.parse_and_eval("(dop::B *) 0").type.target() type_int = gdb.parse_and_eval("(int *) 0").type.target() # The E class matcher and worker test two things: # 1. xmethod returning None. # 2. Matcher returning a list of workers. class E_method_char_worker(XMethodWorker): def __init__(self): pass def get_arg_types(self): return gdb.lookup_type("char") def get_result_type(self, obj, arg): return gdb.lookup_type("void") def __call__(self, obj, arg): print("From Python ") return None class E_method_int_worker(XMethodWorker): def __init__(self): pass def get_arg_types(self): return gdb.lookup_type("int") # Note: get_result_type method elided on purpose def __call__(self, obj, arg): print("From Python ") return None class E_method_matcher(XMethodMatcher): def __init__(self): XMethodMatcher.__init__(self, "E_methods") self.methods = [XMethod("method_int"), XMethod("method_char")] def match(self, class_type, method_name): class_tag = class_type.unqualified().tag if not re.match("^dop::E$", class_tag): return None if not re.match("^method$", method_name): return None workers = [] if self.methods[0].enabled: workers.append(E_method_int_worker()) if self.methods[1].enabled: workers.append(E_method_char_worker()) return workers # The G class method matcher and worker illustrate how to write # xmethod matchers and workers for template classes and template # methods. class G_size_diff_worker(XMethodWorker): def __init__(self, class_template_type, method_template_type): self._class_template_type = class_template_type self._method_template_type = method_template_type def get_arg_types(self): pass def __call__(self, obj): print("From Python G<>::size_diff()") return self._method_template_type.sizeof - self._class_template_type.sizeof class G_size_mul_worker(XMethodWorker): def __init__(self, class_template_type, method_template_val): self._class_template_type = class_template_type self._method_template_val = method_template_val def get_arg_types(self): pass def __call__(self, obj): print("From Python G<>::size_mul()") return self._class_template_type.sizeof * self._method_template_val class G_mul_worker(XMethodWorker): def __init__(self, class_template_type, method_template_type): self._class_template_type = class_template_type self._method_template_type = method_template_type def get_arg_types(self): return self._method_template_type def __call__(self, obj, arg): print("From Python G<>::mul()") return obj["t"] * arg class G_methods_matcher(XMethodMatcher): def __init__(self): XMethodMatcher.__init__(self, "G_methods") self.methods = [XMethod("size_diff"), XMethod("size_mul"), XMethod("mul")] def _is_enabled(self, name): for method in self.methods: if method.name == name and method.enabled: return True def match(self, class_type, method_name): class_tag = class_type.unqualified().tag if not re.match("^dop::G<[ ]*[_a-zA-Z][ _a-zA-Z0-9]*>$", class_tag): return None t_name = class_tag[7:-1] try: t_type = gdb.lookup_type(t_name) except gdb.error: return None if re.match("^size_diff<[ ]*[_a-zA-Z][ _a-zA-Z0-9]*>$", method_name): if not self._is_enabled("size_diff"): return None t1_name = method_name[10:-1] try: t1_type = gdb.lookup_type(t1_name) return G_size_diff_worker(t_type, t1_type) except gdb.error: return None if re.match("^size_mul<[ ]*[0-9]+[ ]*>$", method_name): if not self._is_enabled("size_mul"): return None m_val = int(method_name[9:-1]) return G_size_mul_worker(t_type, m_val) if re.match("^mul<[ ]*[_a-zA-Z][ _a-zA-Z0-9]*>$", method_name): if not self._is_enabled("mul"): return None t1_name = method_name[4:-1] try: t1_type = gdb.lookup_type(t1_name) return G_mul_worker(t_type, t1_type) except gdb.error: return None global_dm_list = [ SimpleXMethodMatcher( r"A_plus_A", r"^dop::A$", r"operator\+", A_plus_A, # This is a replacement, hence match the arg type # exactly! type_A.const().reference(), ), SimpleXMethodMatcher(r"plus_plus_A", r"^dop::A$", r"operator\+\+", plus_plus_A), SimpleXMethodMatcher(r"A_geta", r"^dop::A$", r"^geta$", A_geta), SimpleXMethodMatcher( r"A_getarrayind", r"^dop::A$", r"^getarrayind$", A_getarrayind, type_int ), SimpleXMethodMatcher( r"A_indexoper", r"^dop::A$", r"operator\[\]", A_indexoper, type_int ), SimpleXMethodMatcher( r"B_indexoper", r"^dop::B$", r"operator\[\]", B_indexoper, type_int ), ] for matcher in global_dm_list: gdb.xmethod.register_xmethod_matcher(gdb, matcher) gdb.xmethod.register_xmethod_matcher(gdb.current_progspace(), G_methods_matcher()) gdb.xmethod.register_xmethod_matcher(gdb.current_progspace(), E_method_matcher())