diff options
author | Siva Chandra <sivachandra@chromium.org> | 2014-05-20 06:53:04 -0700 |
---|---|---|
committer | Siva Chandra <sivachandra@chromium.org> | 2014-06-03 10:03:07 -0700 |
commit | 883964a75e8c6531f167391354f1a4d83d203988 (patch) | |
tree | 75eb5ad7ee3808a76dd561f58b6412be5c52b3a0 /gdb/testsuite/gdb.python | |
parent | 58992dc550f2012ca04f190cb77d2d829301cb72 (diff) | |
download | gdb-883964a75e8c6531f167391354f1a4d83d203988.zip gdb-883964a75e8c6531f167391354f1a4d83d203988.tar.gz gdb-883964a75e8c6531f167391354f1a4d83d203988.tar.bz2 |
Xmethod support in Python.
* python/py-xmethods.c: New file.
* python/py-objfile.c (objfile_object): New field 'xmethods'.
(objfpy_dealloc): XDECREF on the new xmethods field.
(objfpy_new, objfile_to_objfile_object): Initialize xmethods
field.
(objfpy_get_xmethods): New function.
(objfile_getset): New entry 'xmethods'.
* python/py-progspace.c (pspace_object): New field 'xmethods'.
(pspy_dealloc): XDECREF on the new xmethods field.
(pspy_new, pspace_to_pspace_object): Initialize xmethods
field.
(pspy_get_xmethods): New function.
(pspace_getset): New entry 'xmethods'.
* python/python-internal.h: Add declarations for new functions.
* python/python.c (_initialize_python): Invoke
gdbpy_initialize_xmethods.
* python/lib/gdb/__init__.py (xmethods): New
attribute.
* python/lib/gdb/xmethod.py: New file.
* python/lib/gdb/command/xmethods.py: New file.
testuite/
* gdb.python/py-xmethods.cc: New testcase to test xmethods.
* gdb.python/py-xmethods.exp: New tests to test xmethods.
* gdb.python/py-xmethods.py: Python script supporting the
new testcase and tests.
Diffstat (limited to 'gdb/testsuite/gdb.python')
-rw-r--r-- | gdb/testsuite/gdb.python/py-xmethods.cc | 170 | ||||
-rw-r--r-- | gdb/testsuite/gdb.python/py-xmethods.exp | 127 | ||||
-rw-r--r-- | gdb/testsuite/gdb.python/py-xmethods.py | 218 |
3 files changed, 515 insertions, 0 deletions
diff --git a/gdb/testsuite/gdb.python/py-xmethods.cc b/gdb/testsuite/gdb.python/py-xmethods.cc new file mode 100644 index 0000000..96637d8 --- /dev/null +++ b/gdb/testsuite/gdb.python/py-xmethods.cc @@ -0,0 +1,170 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2014 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 <http://www.gnu.org/licenses/>. */ + +#include <iostream> + +using namespace std; + +namespace dop +{ + +class A +{ +public: + int a; + int array [10]; + virtual ~A (); + int operator+ (const A &obj); + int operator- (const A &obj); + virtual int geta (void); +}; + +A::~A () { } + +int +A::operator+ (const A &obj) +{ + cout << "From CC <A_plus_A>:" << endl; + return a + obj.a; +} + +int +A::operator- (const A &obj) +{ + cout << "From CC <A_minus_A>:" << endl; + return a - obj.a; +} + +int +A::geta (void) +{ + cout << "From CC A::geta:" << endl; + return a; +} + +class B : public A +{ +public: + virtual int geta (void); +}; + +int +B::geta (void) +{ + cout << "From CC B::geta:" << endl; + return 2 * a; +} + +typedef B Bt; + +typedef Bt Btt; + +class E : public A +{ +public: + /* This class has a member named 'a', while the base class also has a + member named 'a'. When one invokes A::geta(), A::a should be + returned and not E::a as the 'geta' method is defined on class 'A'. + This class tests this aspect of debug methods. */ + int a; +}; + +template <typename T> +class G +{ + public: + template <typename T1> + int size_diff (); + + template <int M> + int size_mul (); + + template <typename T1> + T mul(const T1 t1); + + public: + T t; +}; + +template <typename T> +template <typename T1> +int +G<T>::size_diff () +{ + cout << "From CC G<>::size_diff:" << endl; + return sizeof (T1) - sizeof (T); +} + +template <typename T> +template <int M> +int +G<T>::size_mul () +{ + cout << "From CC G<>::size_mul:" << endl; + return M * sizeof (T); +} + +template <typename T> +template <typename T1> +T +G<T>::mul (const T1 t1) +{ + cout << "From CC G<>::mul:" << endl; + return t1 * t; +} + +} // namespaxe dop + +using namespace dop; + +int main(void) +{ + A a1, a2; + a1.a = 5; + a2.a = 10; + + B b1; + b1.a = 30; + A *a_ptr = &b1; + + Bt bt; + bt.a = 40; + + Btt btt; + btt.a = -5; + + G<int> g, *g_ptr; + g.t = 5; + g_ptr = &g; + + E e; + E &e_ref = e; + E *e_ptr = &e; + e.a = 1000; + e.A::a = 100; + + int diff = g.size_diff<float> (); + int smul = g.size_mul<2> (); + int mul = g.mul (1.0); + + for (int i = 0; i < 10; i++) + { + a1.array[i] = a2.array[i] = i; + } + + return 0; /* Break here. */ +} diff --git a/gdb/testsuite/gdb.python/py-xmethods.exp b/gdb/testsuite/gdb.python/py-xmethods.exp new file mode 100644 index 0000000..97b6ffa --- /dev/null +++ b/gdb/testsuite/gdb.python/py-xmethods.exp @@ -0,0 +1,127 @@ +# Copyright 2014 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 <http://www.gnu.org/licenses/>. + +# This file is part of the GDB testsuite. It tests the debug methods +# feature in the Python extension language. + +load_lib gdb-python.exp + +if { [skip_cplus_tests] } { continue } + +standard_testfile py-xmethods.cc + +if {[prepare_for_testing $testfile.exp $testfile $srcfile {debug c++}]} { + return -1 +} + +# Skip all tests if Python scripting is not enabled. +if { [skip_python_tests] } { continue } + +if ![runto_main] { + return -1 +} + +set xmethods_script [gdb_remote_download host \ + ${srcdir}/${subdir}/${testfile}.py] + +gdb_breakpoint [gdb_get_line_number "Break here."] +gdb_continue_to_breakpoint "Break here" ".*Break here.*" + +# Tests before loading the debug methods. +gdb_test "p a1 + a2" "From CC <A_plus_A>.*15" "Before: a1 + a2" +gdb_test "p a2 - a1" "From CC <A_minus_A>.*5" "Before: a1 - a2" +gdb_test "p b1 - a1" "From CC <A_minus_A>.*25" "Before: b1 - a1" +gdb_test "p a1.geta()" "From CC A::geta.*5" "Before: a1.geta()" +gdb_test "p ++a1" "No symbol.*" "Before: ++a1" +gdb_test "p a1.getarrayind(5)" "Couldn't find method.*" \ + "Before: a1.getarrayind(5)" +gdb_test "p a_ptr->geta()" "From CC B::geta.*60" "Before: a_ptr->geta()" +gdb_test "p e.geta()" "From CC A::geta.*100" "Before: e.geta()" +gdb_test "p g.size_diff<float>()" "From CC G<>::size_diff.*" \ + "Before: g.size_diff<float>()" +gdb_test "p g.size_diff<unsigned long>()" "Couldn't find method.*" \ + "Before: g.size_diff<unsigned long>()" +gdb_test "p g.size_mul<2>()" "From CC G<>::size_mul.*" \ + "Before: g.size_mul<2>()" +gdb_test "p g.size_mul<5>()" "Couldn't find method.*" \ + "Before: g.size_mul<5>()" +gdb_test "p g.mul<double>(2.0)" "From CC G<>::mul.*" \ + "Before: g.mul<double>(2.0)" +gdb_test "p g.mul<char>('a')" "Couldn't find method.*" \ + "Before: g.mul<char>('a')" + +# Load the script which adds the debug methods. +gdb_test_no_output "source ${xmethods_script}" "load the script file" + +# Tests after loading debug methods. +gdb_test "p a1 + a2" "From Python <A_plus_A>.*15" "After: a1 + a2" +gdb_test "p a2 - a1" "From CC <A_minus_A>.*5" "After: a1 - a2" +gdb_test "p b1 + a1" "From Python <A_plus_A>.*35" "After: b1 + a1" +gdb_test "p b1 - a1" "From CC <A_minus_A>.*25" "After: b1 - a1" +gdb_test "p a1.geta()" "From Python <A_geta>.*5" "After: a1.geta()" +gdb_test "p ++a1" "From Python <plus_plus_A>.*6" "After: ++a1" +gdb_test "p a1.getarrayind(5)" "From Python <A_getarrayind>.*5" \ + "After: a1.getarrayind(5)" +# Note the following test. Xmethods on dynamc types are not looked up +# currently. Hence, even though a_ptr points to a B object, the xmethod +# defined for A objects is invoked. +gdb_test "p a_ptr->geta()" "From Python <A_geta>.*30" "After: a_ptr->geta()" +gdb_test "p e.geta()" "From Python <A_geta>.*100" "After: e.geta()" +gdb_test "p e_ptr->geta()" "From Python <A_geta>.*100" "After: e_ptr->geta()" +gdb_test "p e_ref.geta()" "From Python <A_geta>.*100" "After: e_ref.geta()" +gdb_test "p e.method(10)" "From Python <E_method_int>.*" "After: e.method(10)" +gdb_test "p e.method('a')" "From Python <E_method_char>.*" \ + "After: e.method('a')" +gdb_test "p g.size_diff<float> ()" "From Python G<>::size_diff.*" \ + "After: g.size_diff<float>()" +gdb_test "p g.size_diff< unsigned long >()" "From Python G<>::size_diff.*" \ + "After: g.size_diff<unsigned long>()" +gdb_test "p g.size_mul<2>()" "From Python G<>::size_mul.*" \ + "After: g.size_mul<2>()" +gdb_test "p g.size_mul< 5 >()" "From Python G<>::size_mul.*" \ + "After: g.size_mul< 5 >()" +gdb_test "p g.mul<double>(2.0)" "From Python G<>::mul.*" \ + "After: g.mul<double>(2.0)" +gdb_test "p g.mul<char>('a')" "From Python G<>::mul.*" \ +gdb_test "p g_ptr->mul<char>('a')" "From Python G<>::mul.*" \ + "After: g_ptr->mul<char>('a')" + +# Tests for 'disable/enable xmethod' command. +gdb_test_no_output "disable xmethod .*xmethods G_methods" \ + "Disable G_methods" +gdb_test "p g.mul<char>('a')" "Couldn't find method.*" \ + "g.mul<char>('a') after disabling G_methods" +gdb_test_no_output "enable xmethod .*xmethods G_methods" \ + "Enable G_methods" +gdb_test "p g.mul<char>('a')" "From Python G<>::mul.*" \ + "After enabling G_methods" +gdb_test_no_output "disable xmethod .*xmethods G_methods;mul" \ + "Disable G_methods;mul" +gdb_test "p g.mul<char>('a')" "Couldn't find method.*" \ + "g.mul<char>('a') after disabling G_methods;mul" +gdb_test_no_output "enable xmethod .*xmethods G_methods;mul" \ + "Enable G_methods;mul" +gdb_test "p g.mul<char>('a')" "From Python G<>::mul.*" \ + "After enabling G_methods;mul" + +# Test for 'info xmethods' command +gdb_test "info xmethod global plus" "global.*plus_plus_A" \ + "info xmethod global plus 1" +gdb_test_no_output "disable xmethod .*xmethods E_methods;method_int" \ + "disable xmethod .*xmethods E_methods;method_int" +gdb_test "info xmethod .*xmethods E_methods;method_int" ".* \\\[disabled\\\]" \ + "info xmethod xmethods E_methods;method_int" + +remote_file host delete ${xmethods_script} diff --git a/gdb/testsuite/gdb.python/py-xmethods.py b/gdb/testsuite/gdb.python/py-xmethods.py new file mode 100644 index 0000000..6fecf2b --- /dev/null +++ b/gdb/testsuite/gdb.python/py-xmethods.py @@ -0,0 +1,218 @@ +# Copyright 2014 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 <http://www.gnu.org/licenses/>. + +# 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 <A_plus_A>:') + return obj['a'] + opr['a'] + + +def plus_plus_A(obj): + print ('From Python <plus_plus_A>:') + return obj['a'] + 1 + + +def A_geta(obj): + print ('From Python <A_geta>:') + return obj['a'] + + +def A_getarrayind(obj, index): + print 'From Python <A_getarrayind>:' + return obj['array'][index] + + +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 __call__(self, obj, arg): + print 'From Python <E_method_char>' + return None + + +class E_method_int_worker(XMethodWorker): + def __init__(self): + pass + + def get_arg_types(self): + return gdb.lookup_type('int') + + def __call__(self, obj, arg): + print 'From Python <E_method_int>' + 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('A_plus_A', + '^dop::A$', + 'operator\+', + A_plus_A, + # This is a replacement, hence match the arg type + # exactly! + type_A.const().reference()), + SimpleXMethodMatcher('plus_plus_A', + '^dop::A$', + 'operator\+\+', + plus_plus_A), + SimpleXMethodMatcher('A_geta', + '^dop::A$', + '^geta$', + A_geta), + SimpleXMethodMatcher('A_getarrayind', + '^dop::A$', + '^getarrayind$', + A_getarrayind, + 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()) |