[RFC] Debug Methods in GDB Python

Siva Chandra
2013-01-07T21:22:08Z

[-- Attachment #1: Type: text/plain, Size: 2713 bytes --]

Hi all,

This is a followup to the thread on debug operators here (last
message): http://sourceware.org/ml/gdb-patches/2013-01/msg00005.html

I am starting another thread as I now have, what I feel is, a fairly
independent patch which implements a larger feature (of which C++
operator methods are a part), and some of the un-implemented features
I have mentioned in my last post have been implemented. The patch is
attached. Few points about the patch:

1. The patch is incomplete in the sense that tests and documentation
are missing. Also, ways to enable and disable single or group of debug
methods is missing. At this point, I am looking for feedback on my
direction and the way I am intercepting the normal GDB flow to lookup
methods defined in Python. I will work on completing the patch once
there is an agreement on these basics.

2. I did not intend to provide a way for the user to define new or
override static methods via Python.

3. I did not intend to provide a way for the user to define new
virtual methods in Python. The user can however override existing
virtual and non-virtual methods. The user can also define new
non-virtual methods in Python.

4. Doug suggested that I use the C++ infrastructure in GDB as much as
possible. I feel I have done so.

5. The Changelog for the patch (which is also raw) is as follows:

2013-01-07 Siva Chandra Reddy <sivachandra@google.com>

* Makefile.in: Add entries for new files
* data-directory/Makefile.in: Add entry for new Python file
* eval.c: Invoke methods defined in extension methods.
* ext-function.c: Support for working with functions/methods
defined in an extension language.
* ext-function.h: Support for working with functions/methods
defined in an extension language.
* python/lib/gdb/debugmethods.py: Python side of the support
for debug methods in Python.
* python/py-debugmethods.c: C side of the support for debug
methods in Python.
* python/py-objfile.c: Add 'debug_methods' attribute to
gdb.Objfile.
* python/python-internal.h: Add new function
gdb.enable_debug_methods to the Python module 'gdb'.
* python/python.c: Add new function gdb.enable_debug_methods to
the Python module 'gdb'.
* python/python.h: Add declarations of new functions.
* valarith.c: Invoke operators defined in extension languages.
* valops.c: Lookup methods defined in extension languages.
* value.h: New signature for 'find_overload_match'.

6. The toy program I used for testing, and the corresponding auto load
script are also attached for illustration.

Thanks and regards,
Siva Chandra

[-- Attachment #2: dm_patch_v1.txt --]
[-- Type: text/plain, Size: 51916 bytes --]

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index b065d41..7150781 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -277,6 +277,7 @@ SUBDIR_PYTHON_OBS = \
py-breakpoint.o \
py-cmd.o \
py-continueevent.o \
+ py-debugmethods.o \
py-event.o \
py-evtregistry.o \
py-evts.o \
@@ -310,6 +311,7 @@ SUBDIR_PYTHON_SRCS = \
python/py-breakpoint.c \
python/py-cmd.c \
python/py-continueevent.c \
+ python/py-debugmethods.c \
python/py-event.c \
python/py-evtregistry.c \
python/py-evts.c \
@@ -710,7 +712,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \
dwarf2expr.c dwarf2loc.c dwarf2read.c dwarf2-frame.c \
dwarf2-frame-tailcall.c \
elfread.c environ.c eval.c event-loop.c event-top.c \
- exceptions.c expprint.c \
+ exceptions.c expprint.c ext-function.c \
f-exp.y f-lang.c f-typeprint.c f-valprint.c filesystem.c \
findcmd.c findvar.c frame.c frame-base.c frame-unwind.c \
gdbarch.c arch-utils.c gdb_bfd.c gdbtypes.c gnu-v2-abi.c gnu-v3-abi.c \
@@ -808,7 +810,7 @@ doublest.h regset.h hppa-tdep.h ppc-linux-tdep.h rs6000-tdep.h \
common/gdb_locale.h common/gdb_dirent.h arch-utils.h trad-frame.h gnu-nat.h \
language.h nbsd-tdep.h solib-svr4.h \
macroexp.h ui-file.h regcache.h gdb_string.h tracepoint.h i386-tdep.h \
-inf-child.h p-lang.h event-top.h gdbtypes.h user-regs.h \
+inf-child.h p-lang.h event-top.h ext-function.h gdbtypes.h user-regs.h \
regformats/regdef.h config/alpha/nm-osf3.h config/i386/nm-i386gnu.h \
config/i386/nm-fbsd.h \
config/nm-nto.h config/sparc/nm-sol2.h config/nm-linux.h \
@@ -922,7 +924,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
inferior.o osdata.o gdb_usleep.o record.o gcore.o \
gdb_vecs.o jit.o progspace.o skip.o probe.o \
common-utils.o buffer.o ptid.o gdb-dlfcn.o common-agent.o \
- format.o registry.o
+ format.o registry.o ext-function.o

TSOBS = inflow.o

@@ -2065,6 +2067,10 @@ py-continueevent.o: $(srcdir)/python/py-continueevent.c
$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-continueevent.c
$(POSTCOMPILE)

+py-debugmethods.o: $(srcdir)/python/py-debugmethods.c
+ $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-debugmethods.c
+ $(POSTCOMPILE)
+
py-event.o: $(srcdir)/python/py-event.c
$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-event.c
$(POSTCOMPILE)
diff --git a/gdb/data-directory/Makefile.in b/gdb/data-directory/Makefile.in
index d98ac77..04e5e52 100644
--- a/gdb/data-directory/Makefile.in
+++ b/gdb/data-directory/Makefile.in
@@ -56,6 +56,7 @@ PYTHON_FILES = \
gdb/types.py \
gdb/printing.py \
gdb/prompt.py \
+ gdb/debugmethods.py \
gdb/command/__init__.py \
gdb/command/type_printers.py \
gdb/command/pretty_printers.py \
diff --git a/gdb/eval.c b/gdb/eval.c
index c9630df..4586c92 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -22,6 +22,7 @@
#include "symtab.h"
#include "gdbtypes.h"
#include "value.h"
+#include "ext-function.h"
#include "expression.h"
#include "target.h"
#include "frame.h"
@@ -1593,7 +1594,7 @@ evaluate_subexp_standard (struct type *expect_type,
0, /* strict match */
NULL, NULL, /* pass NULL symbol since
symbol is unknown */
- NULL, &symp, NULL, 0);
+ NULL, &symp, NULL, NULL, 0);

/* Now fix the expression being evaluated. */
exp->elts[save_pos1 + 2].symbol = symp;
@@ -1623,12 +1624,13 @@ evaluate_subexp_standard (struct type *expect_type,
/* Language is C++, do some overload resolution before
evaluation. */
struct value *valp = NULL;
+ struct ext_fn_descriptor *ext_fnp = NULL;

(void) find_overload_match (&argvec[1], nargs, tstr,
METHOD, /* method */
0, /* strict match */
&arg2, /* the object */
- NULL, &valp, NULL,
+ NULL, &valp, NULL, &ext_fnp,
&static_memfuncp, 0);

if (op == OP_SCOPE && !static_memfuncp)
@@ -1638,9 +1640,19 @@ evaluate_subexp_standard (struct type *expect_type,
"`this' pointer"),
function_name);
}
- argvec[1] = arg2; /* the ``this'' pointer */
- argvec[0] = valp; /* Use the method found after overload
- resolution. */
+
+ if (valp)
+ {
+ argvec[1] = arg2; /* the ``this'' pointer */
+ argvec[0] = valp; /* Use the method found after overload
+ resolution. */
+ }
+ if (ext_fnp)
+ {
+ if (ext_fnp->is_method)
+ return ext_fn_invoke_method (ext_fnp, arg2, argvec + 2,
+ nargs - 1);
+ }
}
else
/* Non-C++ case -- or no overload resolution. */
@@ -1700,7 +1712,7 @@ evaluate_subexp_standard (struct type *expect_type,
NON_METHOD, /* not method */
0, /* strict match */
NULL, function, /* the function */
- NULL, &symp, NULL, no_adl);
+ NULL, &symp, NULL, NULL, no_adl);

if (op == OP_VAR_VALUE)
{
diff --git a/gdb/ext-function.c b/gdb/ext-function.c
new file mode 100644
index 0000000..c3f2216
--- /dev/null
+++ b/gdb/ext-function.c
@@ -0,0 +1,170 @@
+/* Support for functions defined in extension languages.
+
+ Copyright (C) 2013 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ 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 "defs.h"
+#include "ext-function.h"
+#include "python/python.h"
+
+static ULONGEST enabled_ext_languages = EXT_LANG_PYTHON;
+
+struct ext_fn_descriptor *
+new_ext_function (void)
+{
+ struct ext_fn_descriptor *ext_fn =
+ (struct ext_fn_descriptor *) xzalloc (sizeof (struct ext_fn_descriptor));
+
+ ext_fn->next = NULL;
+ ext_fn->is_method = 0;
+ ext_fn->lang = EXT_LANG_UNKNOWN;
+ ext_fn->ext_object = NULL;
+
+ return ext_fn;
+}
+
+void
+ext_fn_list_free (struct ext_fn_descriptor *list)
+{
+ while (list)
+ {
+ struct ext_fn_descriptor *item = list;
+
+ list = list->next;
+
+ if (item->is_method)
+ {
+ if (item->lang == EXT_LANG_PYTHON)
+ py_free_ext_object (item->ext_object);
+ }
+
+ xfree (item);
+ }
+}
+
+struct ext_fn_descriptor *
+ext_fn_list_extend (struct ext_fn_descriptor *l1, struct ext_fn_descriptor *l2)
+{
+ struct ext_fn_descriptor *item = l1;
+
+ if (!l1)
+ return l2;
+
+ while (item->next)
+ item = item->next;
+
+ item->next = l2;
+
+ return l1;
+}
+
+struct ext_fn_descriptor *
+ext_fn_list_prepend (struct ext_fn_descriptor *list,
+ struct ext_fn_descriptor *item)
+{
+ struct ext_fn_descriptor *last_item;
+ if (!list)
+ return item;
+
+ if (!item)
+ return list;
+
+ item->next = list;
+
+ return item;
+}
+
+struct ext_fn_descriptor *
+ext_fn_list_remove (struct ext_fn_descriptor *list,
+ struct ext_fn_descriptor *item)
+{
+ struct ext_fn_descriptor *prev_item = NULL, *head = list;
+
+ while (list)
+ {
+ if (list == item)
+ {
+ if (prev_item)
+ {
+ prev_item->next = list->next;
+ item->next = NULL;
+ }
+ else
+ {
+ head = list->next;
+ item->next = NULL;
+ }
+
+ break;
+ }
+
+ prev_item = list;
+ list = list->next;
+ }
+
+ return head;
+}
+
+struct ext_fn_descriptor *
+ext_fn_list_get (struct ext_fn_descriptor *list, int index)
+{
+ int i = 0;
+
+ while (list)
+ {
+ if (i == index)
+ return list;
+
+ i++;
+ list = list->next;
+ }
+
+ return NULL;
+}
+
+struct ext_fn_descriptor *
+get_matching_ext_methods (struct type *type, const char *method)
+{
+ struct ext_fn_descriptor *python_methods = NULL;
+
+ if (enabled_ext_languages && EXT_LANG_PYTHON)
+ python_methods = py_debugmethod_name_match (type, method);
+
+ return python_methods;
+}
+
+struct type **
+ext_fn_get_argtypes (struct ext_fn_descriptor *ext_fn, int *nargs)
+{
+ if ((enabled_ext_languages && EXT_LANG_PYTHON)
+ && (ext_fn->lang == EXT_LANG_PYTHON))
+ return py_ext_fn_get_argtypes (ext_fn, nargs);
+
+ *nargs = 0;
+ return NULL;
+}
+
+struct value *
+ext_fn_invoke_method (struct ext_fn_descriptor *ext_fn, struct value *obj,
+ struct value **args, int nargs)
+{
+ if ((enabled_ext_languages && EXT_LANG_PYTHON)
+ && (ext_fn->lang == EXT_LANG_PYTHON))
+ return py_ext_fn_invoke_method (ext_fn, obj, args, nargs);
+
+ return NULL;
+}
diff --git a/gdb/ext-function.h b/gdb/ext-function.h
new file mode 100644
index 0000000..7f87cb7
--- /dev/null
+++ b/gdb/ext-function.h
@@ -0,0 +1,71 @@
+/* Support for functions defined in extension languages.
+
+ Copyright (C) 2013 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ 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/>. */
+
+#if !defined (EXT_FUNCTION_H)
+#define EXT_FUNCTION_H
+
+struct value;
+struct type;
+
+enum ext_lang
+ {
+ EXT_LANG_UNKNOWN = 0,
+ /* Values for extension languages are powers of 2. */
+ EXT_LANG_GUILE = 1,
+ EXT_LANG_PYTHON = 2
+ /* Next extension language should have value of 4. */
+ };
+
+struct ext_fn_descriptor
+ {
+ enum ext_lang lang;
+
+ int is_method;
+
+ void *ext_object;
+
+ struct ext_fn_descriptor *next;
+ };
+
+extern struct value *ext_fn_invoke_method (struct ext_fn_descriptor *,
+ struct value *,
+ struct value **, int nargs);
+
+extern struct ext_fn_descriptor *ext_fn_list_remove (
+ struct ext_fn_descriptor *list, struct ext_fn_descriptor *item);
+
+extern struct ext_fn_descriptor *ext_fn_list_get (
+ struct ext_fn_descriptor *list, int);
+
+extern struct ext_fn_descriptor *
+ext_fn_list_extend (struct ext_fn_descriptor *, struct ext_fn_descriptor *);
+
+extern struct ext_fn_descriptor *ext_fn_list_prepend (
+ struct ext_fn_descriptor *list, struct ext_fn_descriptor *item);
+
+extern void ext_fn_list_free (struct ext_fn_descriptor *list);
+
+extern struct ext_fn_descriptor *new_ext_function (void);
+
+extern struct ext_fn_descriptor *get_matching_ext_methods (struct type *,
+ const char *);
+
+extern struct type **ext_fn_get_argtypes (struct ext_fn_descriptor *, int *);
+
+#endif /* EXT_FUNCTION_H */
diff --git a/gdb/python/lib/gdb/debugmethods.py b/gdb/python/lib/gdb/debugmethods.py
new file mode 100644
index 0000000..9d0c706
--- /dev/null
+++ b/gdb/python/lib/gdb/debugmethods.py
@@ -0,0 +1,113 @@
+# Python side of the support for debug methods.
+# Copyright (C) 2013 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/>.
+
+"""Utilities for adding debug methods"""
+
+import gdb
+import re
+
+DEFAULT_DEBUG_METHOD_GROUP = 'DEFAULT_DEBUG_METHOD_GROUP'
+
+
+class DebugMethod(object):
+
+ def __init__(self, name, group=DEFAULT_DEBUG_METHOD_GROUP):
+ self._name = name
+ self.group = group
+ self.enabled = True
+
+ @property
+ def name(self):
+ return self._name
+
+ def match_class(self, class_name):
+ gdb.GdbError('ERROR: Invoking abstract method \'match_class\'.')
+
+ def match_method(self, method_name):
+ gdb.GdbError('ERROR: Invoking abstract method \'match_method\'.')
+
+ def get_argtypes(self, class_type, method_name):
+ gdb.GdbError('ERROR: Invoking abstract method \'get_argtypes\'.')
+
+ def invoke(self, obj, *args):
+ gdb.GdbError('ERROR: Invoking abstract method \'invoke\'.')
+
+
+class SimpleDebugMethod(DebugMethod):
+ def __init__(self, name, group, method_function, class_matcher,
+ method_matcher, *argtypes):
+ DebugMethod.__init__(self, name, group)
+ self._method_function = method_function
+ self._class_matcher = class_matcher
+ self._method_matcher = method_matcher
+ self._argtypes = argtypes
+
+ def match_class(self, class_type):
+ if re.match(self._class_matcher, str(class_type.unqualified().tag)):
+ return True
+ else:
+ return False
+
+ def match_method(self, method_name):
+ if re.match(self._method_matcher, method_name):
+ return True
+ else:
+ return False
+
+ def get_argtypes(self, class_type, method_name):
+ return self._argtypes
+
+ def invoke(self, obj, *args):
+ return self._method_function(obj, *args)
+
+
+def get_matching_methods(class_type, method_name):
+ match_list = []
+ for objfile in gdb.objfiles():
+ for debug_method in objfile.debug_methods:
+ if (debug_method.enabled and
+ debug_method.match_class(class_type) and
+ debug_method.match_method(method_name)):
+ match_list.append(debug_method)
+ return match_list
+
+
+def get_method_argtypes(debug_method, class_type, method_name):
+ return debug_method.get_argtypes(class_type, method_name)
+
+
+def invoke_debug_method(debug_method, obj, args):
+ return debug_method.invoke(obj, *args)
+
+
+def register_debug_methods(objfile, debug_methods):
+ existing_method_list = []
+ for new_method in debug_methods:
+ for old_method in objfile.debug_methods:
+ if (new_method.group == old_method.group and
+ new_method.name == old_method.name):
+ print ('WARNING: Replacing debug method with name "%s" in '
+ 'group "%s".' % (old_method.name, old_method.group))
+ existing_method_list.append(old_method)
+ for old_method in existing_method_list:
+ objfile.debug_methods.remove(old_method)
+ objfile.debug_methods.extend(debug_methods)
+
+
+# Python debug methods feature will be enabled when a user imports this
+# module.
+gdb.enable_debug_methods(get_matching_methods, get_method_argtypes,
+ invoke_debug_method)
diff --git a/gdb/python/py-debugmethods.c b/gdb/python/py-debugmethods.c
new file mode 100644
index 0000000..d160695
--- /dev/null
+++ b/gdb/python/py-debugmethods.c
@@ -0,0 +1,212 @@
+/* Support for debug methods in Python.
+
+ Copyright (C) 2013 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ 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 "defs.h"
+#include "arch-utils.h"
+#include "ext-function.h"
+#include "value.h"
+#include "language.h"
+#include "python-internal.h"
+#include "python.h"
+
+struct py_ext_object
+{
+ PyObject *object;
+ PyObject *match_py_obj_type;
+ const char *match_method;
+};
+
+PyObject *match_methods_callable = NULL;
+PyObject *get_argtypes_callable = NULL;
+PyObject *invoke_method_callable = NULL;
+
+PyObject *
+gdbpy_enable_debug_methods (PyObject *self, PyObject *args)
+{
+ PyObject *match_methods_temp, *get_argtypes_temp, *invoke_method_temp;
+ PyObject *result = NULL;
+
+ if (!PyArg_ParseTuple (args, "OOO", &match_methods_temp, &get_argtypes_temp,
+ &invoke_method_temp))
+ return result;
+
+ if (PyCallable_Check (match_methods_temp)
+ && PyCallable_Check (get_argtypes_temp)
+ && PyCallable_Check (invoke_method_temp))
+ {
+ Py_XDECREF (match_methods_callable);
+ Py_XDECREF (get_argtypes_callable);
+ Py_XDECREF (invoke_method_callable);
+
+ Py_INCREF (match_methods_temp);
+ Py_INCREF (get_argtypes_temp);
+ Py_INCREF (invoke_method_temp);
+
+ match_methods_callable = match_methods_temp;
+ get_argtypes_callable = get_argtypes_temp;
+ invoke_method_callable = invoke_method_temp;
+
+ Py_INCREF (Py_None);
+ result = Py_None;
+ }
+
+ return result;
+}
+
+static struct ext_fn_descriptor *
+new_python_ext_method (PyObject *item, PyObject *py_obj_type,
+ const char *method)
+{
+ struct ext_fn_descriptor *ext_fn = new_ext_function ();
+ struct py_ext_object *ext_object;
+
+ ext_object = (struct py_ext_object *) xzalloc (sizeof (struct py_ext_object));
+ ext_object->object = item;
+ ext_object->match_py_obj_type = py_obj_type;
+ ext_object->match_method = method;
+
+ ext_fn->lang = EXT_LANG_PYTHON;
+ ext_fn->is_method = 1;
+ ext_fn->ext_object = (void *) ext_object;
+
+ return ext_fn;
+}
+
+void
+py_free_ext_object (void *ext_object)
+{
+ struct py_ext_object *o = (struct py_ext_object *) ext_object;
+
+ Py_XDECREF (o->object);
+ xfree (o);
+}
+
+struct ext_fn_descriptor *
+py_debugmethod_name_match (struct type *obj_type, const char *method_name)
+{
+ PyObject *py_type, *py_debugmethod_list = NULL, *list_iter, *item;
+ struct cleanup *cleanups;
+ struct ext_fn_descriptor *method_list = NULL;
+
+ if (!obj_type)
+ return NULL;
+
+ cleanups = ensure_python_env (get_current_arch (), current_language);
+
+ py_type = type_to_type_object (obj_type);
+ py_debugmethod_list = PyObject_CallFunction (match_methods_callable,
+ "Os",
+ py_type, method_name);
+
+ list_iter = PyObject_GetIter (py_debugmethod_list);
+ while ((item = PyIter_Next (list_iter)))
+ {
+ struct ext_fn_descriptor *ext_fn;
+
+ ext_fn = new_python_ext_method (item, py_type, method_name);
+ method_list = ext_fn_list_prepend (method_list, ext_fn);
+ }
+
+ Py_DECREF (list_iter);
+ Py_DECREF (py_debugmethod_list);
+
+ do_cleanups (cleanups);
+ return method_list;
+}
+
+struct type **
+py_ext_fn_get_argtypes (struct ext_fn_descriptor *ext_fn, int *nargs)
+{
+ if (ext_fn->is_method)
+ {
+ struct py_ext_object *ext_object =
+ (struct py_ext_object *) ext_fn->ext_object;
+ PyObject *py_argtype_list, *list_iter, *item;
+ struct cleanup *cleanups;
+ struct type **type_array, *obj_type;
+ int i = 1;
+
+ cleanups = ensure_python_env (get_current_arch (), current_language);
+ py_argtype_list = PyObject_CallFunction (get_argtypes_callable,
+ "OOs",
+ ext_object->object,
+ ext_object->match_py_obj_type,
+ ext_object->match_method);
+
+ list_iter = PyObject_GetIter (py_argtype_list);
+ *nargs = PySequence_Size (py_argtype_list) + 1; /* Include 'this' */
+ type_array = (struct type **) xmalloc (*nargs * sizeof (struct type *));
+ while ((item = PyIter_Next (list_iter)))
+ {
+ type_array[i] = type_object_to_type (item);
+ i++;
+ Py_XDECREF (item);
+ }
+
+ /* Add the type of 'this' as the first argument. */
+ obj_type = type_object_to_type (ext_object->match_py_obj_type);
+ type_array[0] = make_cv_type (1, 0, lookup_pointer_type (obj_type), NULL);
+
+ Py_XDECREF (list_iter);
+ Py_XDECREF (py_argtype_list);
+ do_cleanups (cleanups);
+
+ return type_array;
+ }
+
+ *nargs = 0;
+ return NULL;
+}
+
+struct value *
+py_ext_fn_invoke_method (struct ext_fn_descriptor *ext_fn, struct value *obj,
+ struct value **args, int nargs)
+{
+ int i;
+ struct cleanup *cleanups;
+ PyObject *py_obj, *py_arg_tuple, *py_result, *debug_method;
+ struct value *result = NULL;
+
+ if (!ext_fn->is_method)
+ return NULL;
+
+ cleanups = ensure_python_env (get_current_arch (), current_language);
+
+ debug_method = ((struct py_ext_object *) ext_fn->ext_object)->object;
+ py_obj = value_to_value_object (obj);
+ py_arg_tuple = PyTuple_New (nargs);
+ for (i = 0; i < nargs; i++)
+ {
+ PyObject *py_arg_value = value_to_value_object (args[i]);
+
+ PyTuple_SetItem (py_arg_tuple, i, py_arg_value);
+ }
+
+ py_result = PyObject_CallFunction (invoke_method_callable, "OOO",
+ debug_method, py_obj, py_arg_tuple);
+
+ result = convert_value_from_python (py_result);
+
+ Py_XDECREF (py_obj);
+ Py_XDECREF (py_arg_tuple);
+ Py_XDECREF (py_result);
+ do_cleanups (cleanups);
+
+ return result;
+}
diff --git a/gdb/python/py-objfile.c b/gdb/python/py-objfile.c
index db51f50..c2bef3e 100644
--- a/gdb/python/py-objfile.c
+++ b/gdb/python/py-objfile.c
@@ -35,6 +35,9 @@ typedef struct

/* The type-printer list. */
PyObject *type_printers;
+
+ /* The debug method list. */
+ PyObject *debug_methods;
} objfile_object;

static PyTypeObject objfile_object_type;
@@ -62,6 +65,7 @@ objfpy_dealloc (PyObject *o)

Py_XDECREF (self->printers);
Py_XDECREF (self->type_printers);
+ Py_XDECREF (self->debug_methods);
Py_TYPE (self)->tp_free (self);
}

@@ -87,6 +91,13 @@ objfpy_new (PyTypeObject *type, PyObject *args, PyObject *keywords)
Py_DECREF (self);
return NULL;
}
+
+ self->debug_methods = PyList_New (0);
+ if (!self->debug_methods)
+ {
+ Py_DECREF (self);
+ return NULL;
+ }
}
return (PyObject *) self;
}
@@ -140,6 +151,17 @@ objfpy_get_type_printers (PyObject *o, void *ignore)
return self->type_printers;
}

+/* Get the 'debug_methods' attribute. */
+
+static PyObject *
+objfpy_get_debug_methods (PyObject *o, void *ignore)
+{
+ objfile_object *self = (objfile_object *) o;
+
+ Py_INCREF (self->debug_methods);
+ return self->debug_methods;
+}
+
/* Set the 'type_printers' attribute. */

static int
@@ -232,6 +254,13 @@ objfile_to_objfile_object (struct objfile *objfile)
return NULL;
}

+ object->debug_methods = PyList_New (0);
+ if (!object->debug_methods)
+ {
+ Py_DECREF (object);
+ return NULL;
+ }
+
set_objfile_data (objfile, objfpy_objfile_data_key, object);
}
}
@@ -272,6 +301,8 @@ static PyGetSetDef objfile_getset[] =
"Pretty printers.", NULL },
{ "type_printers", objfpy_get_type_printers, objfpy_set_type_printers,
"Type printers.", NULL },
+ { "debug_methods", objfpy_get_debug_methods, NULL,
+ "Debug methods.", NULL },
{ NULL }
};

diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
index 7d52c06..b457a6c 100644
--- a/gdb/python/python-internal.h
+++ b/gdb/python/python-internal.h
@@ -231,6 +231,7 @@ PyObject *gdbpy_selected_inferior (PyObject *self, PyObject *args);
PyObject *gdbpy_string_to_argv (PyObject *self, PyObject *args);
PyObject *gdbpy_parameter (PyObject *self, PyObject *args);
PyObject *gdbpy_parameter_value (enum var_types type, void *var);
+PyObject *gdbpy_enable_debug_methods (PyObject *self, PyObject *args);
char *gdbpy_parse_command_name (const char *name,
struct cmd_list_element ***base_list,
struct cmd_list_element **start_list);
diff --git a/gdb/python/python.c b/gdb/python/python.c
index b0f71a2..43a8b9c 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -1825,6 +1825,9 @@ Return the selected inferior object." },
{ "inferiors", gdbpy_inferiors, METH_NOARGS,
"inferiors () -> (gdb.Inferior, ...).\n\
Return a tuple containing all inferiors." },
+ { "enable_debug_methods", gdbpy_enable_debug_methods, METH_VARARGS,
+ "inferiors (meth_match_function, args_match_function) -> None.\n\
+Enables Python debug methods feature." },
{NULL, NULL, 0, NULL}
};

diff --git a/gdb/python/python.h b/gdb/python/python.h
index 24e3077..d4adafe 100644
--- a/gdb/python/python.h
+++ b/gdb/python/python.h
@@ -49,6 +49,17 @@ int gdbpy_should_stop (struct breakpoint_object *bp_obj);

int gdbpy_breakpoint_has_py_cond (struct breakpoint_object *bp_obj);

+struct ext_fn_descriptor *py_debugmethod_name_match (struct type *,
+ const char *);
+
+void py_free_ext_object (void *ext_object);
+
+struct type **py_ext_fn_get_argtypes (struct ext_fn_descriptor *, int *);
+
+struct value *py_ext_fn_invoke_method (struct ext_fn_descriptor *,
+ struct value *,
+ struct value **, int nargs);
+
void *start_type_printers (void);

char *apply_type_printers (void *, struct type *type);
diff --git a/gdb/valarith.c b/gdb/valarith.c
index 074cf36..7f53de7 100644
--- a/gdb/valarith.c
+++ b/gdb/valarith.c
@@ -30,6 +30,7 @@
#include <math.h>
#include "infcall.h"
#include "exceptions.h"
+#include "ext-function.h"

/* Define whether or not the C operator '/' truncates towards zero for
differently signed operands (truncation direction is undefined in C). */
@@ -285,21 +286,27 @@ unop_user_defined_p (enum exp_opcode op, struct value *arg1)
explicitly, and perform correct overload resolution in all of the above
situations or combinations thereof. */

-static struct value *
+static void
value_user_defined_cpp_op (struct value **args, int nargs, char *operator,
+ struct value **src_fn,
+ struct ext_fn_descriptor **ext_fn,
int *static_memfuncp)
{

struct symbol *symp = NULL;
struct value *valp = NULL;
+ struct ext_fn_descriptor *ext_fnp = NULL;

find_overload_match (args, nargs, operator, BOTH /* could be method */,
0 /* strict match */, &args[0], /* objp */
NULL /* pass NULL symbol since symbol is unknown */,
- &valp, &symp, static_memfuncp, 0);
+ &valp, &symp, &ext_fnp, static_memfuncp, 0);

if (valp)
- return valp;
+ {
+ *src_fn = valp;
+ return;
+ }

if (symp)
{
@@ -307,7 +314,14 @@ value_user_defined_cpp_op (struct value **args, int nargs, char *operator,
expect a reference as its first argument
rather the explicit structure. */
args[0] = value_ind (args[0]);
- return value_of_variable (symp, 0);
+ *src_fn = value_of_variable (symp, 0);
+ return;
+ }
+
+ if (ext_fnp)
+ {
+ *ext_fn = ext_fnp;
+ return;
}

error (_("Could not find %s."), operator);
@@ -316,19 +330,22 @@ value_user_defined_cpp_op (struct value **args, int nargs, char *operator,
/* Lookup user defined operator NAME. Return a value representing the
function, otherwise return NULL. */

-static struct value *
+static void
value_user_defined_op (struct value **argp, struct value **args, char *name,
- int *static_memfuncp, int nargs)
+ int *static_memfuncp, int nargs,
+ struct value **src_fn, struct ext_fn_descriptor **ext_fn)
{
struct value *result = NULL;

if (current_language->la_language == language_cplus)
- result = value_user_defined_cpp_op (args, nargs, name, static_memfuncp);
+ value_user_defined_cpp_op (args, nargs, name, src_fn, ext_fn,
+ static_memfuncp);
else
- result = value_struct_elt (argp, args, name, static_memfuncp,
- "structure");
-
- return result;
+ {
+ result = value_struct_elt (argp, args, name, static_memfuncp,
+ "structure");
+ *src_fn = result;
+ }
}

/* We know either arg1 or arg2 is a structure, so try to find the right
@@ -345,6 +362,7 @@ value_x_binop (struct value *arg1, struct value *arg2, enum exp_opcode op,
enum exp_opcode otherop, enum noside noside)
{
struct value **argvec;
+ struct ext_fn_descriptor *ext_fn = NULL;
char *ptr;
char tstr[13];
int static_memfuncp;
@@ -359,6 +377,7 @@ value_x_binop (struct value *arg1, struct value *arg2, enum exp_opcode op,
error (_("Can't do that binary op on that type")); /* FIXME be explicit */

argvec = (struct value **) alloca (sizeof (struct value *) * 4);
+ argvec[0] = NULL;
argvec[1] = value_addr (arg1);
argvec[2] = arg2;
argvec[3] = 0;
@@ -471,8 +490,8 @@ value_x_binop (struct value *arg1, struct value *arg2, enum exp_opcode op,
error (_("Invalid binary operation specified."));
}

- argvec[0] = value_user_defined_op (&arg1, argvec + 1, tstr,
- &static_memfuncp, 2);
+ value_user_defined_op (&arg1, argvec + 1, tstr, &static_memfuncp, 2,
+ &argvec[0], &ext_fn);

if (argvec[0])
{
@@ -492,6 +511,11 @@ value_x_binop (struct value *arg1, struct value *arg2, enum exp_opcode op,
return call_function_by_hand (argvec[0], 2 - static_memfuncp,
argvec + 1);
}
+ if (ext_fn)
+ {
+ if (ext_fn->is_method)
+ return ext_fn_invoke_method (ext_fn, arg1, &arg2, 1);
+ }
throw_error (NOT_FOUND_ERROR,
_("member function %s not found"), tstr);
#ifdef lint
@@ -510,6 +534,7 @@ value_x_unop (struct value *arg1, enum exp_opcode op, enum noside noside)
{
struct gdbarch *gdbarch = get_type_arch (value_type (arg1));
struct value **argvec;
+ struct ext_fn_descriptor *ext_fn;
char *ptr, *mangle_ptr;
char tstr[13], mangle_tstr[13];
int static_memfuncp, nargs;
@@ -523,6 +548,7 @@ value_x_unop (struct value *arg1, enum exp_opcode op, enum noside noside)
error (_("Can't do that unary op on that type")); /* FIXME be explicit */

argvec = (struct value **) alloca (sizeof (struct value *) * 4);
+ argvec[0] = NULL;
argvec[1] = value_addr (arg1);
argvec[2] = 0;

@@ -575,8 +601,8 @@ value_x_unop (struct value *arg1, enum exp_opcode op, enum noside noside)
error (_("Invalid unary operation specified."));
}

- argvec[0] = value_user_defined_op (&arg1, argvec + 1, tstr,
- &static_memfuncp, nargs);
+ value_user_defined_op (&arg1, argvec + 1, tstr, &static_memfuncp, nargs,
+ &argvec[0], &ext_fn);

if (argvec[0])
{
@@ -595,6 +621,11 @@ value_x_unop (struct value *arg1, enum exp_opcode op, enum noside noside)
return value_zero (return_type, VALUE_LVAL (arg1));
}
return call_function_by_hand (argvec[0], nargs, argvec + 1);
+ }
+ if (ext_fn)
+ {
+ if (ext_fn->is_method)
+ return ext_fn_invoke_method (ext_fn, arg1, NULL, 0);
}
throw_error (NOT_FOUND_ERROR,
_("member function %s not found"), tstr);
diff --git a/gdb/valops.c b/gdb/valops.c
index e3d36a1..2cc67d9 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -45,6 +45,7 @@
#include "objfiles.h"
#include "symtab.h"
#include "exceptions.h"
+#include "ext-function.h"

extern unsigned int overload_debug;
/* Local functions. */
@@ -73,8 +74,8 @@ int find_oload_champ_namespace_loop (struct value **, int,
const int no_adl);

static int find_oload_champ (struct value **, int, int, int,
- struct fn_field *, struct symbol **,
- struct badness_vector **);
+ struct fn_field *, struct ext_fn_descriptor *,
+ struct symbol **, struct badness_vector **);

static int oload_method_static (int, struct fn_field *, int);

@@ -101,9 +102,10 @@ static CORE_ADDR allocate_space_in_inferior (int);

static struct value *cast_into_complex (struct type *, struct value *);

-static struct fn_field *find_method_list (struct value **, const char *,
- int, struct type *, int *,
- struct type **, int *);
+static void find_method_list (struct value **, const char *,
+ int, struct type *, struct fn_field **, int *,
+ struct ext_fn_descriptor **,
+ struct type **, int *);

void _initialize_valops (void);

@@ -2433,40 +2435,53 @@ value_struct_elt (struct value **argp, struct value **args,
method is found.
BOFFSET is the offset of the base subobject where the method is found. */

-static struct fn_field *
+static void
find_method_list (struct value **argp, const char *method,
- int offset, struct type *type, int *num_fns,
+ int offset, struct type *type,
+ struct fn_field **fn_list, int *num_fns,
+ struct ext_fn_descriptor **ext_fn_list,
struct type **basetype, int *boffset)
{
int i;
- struct fn_field *f;
- CHECK_TYPEDEF (type);
+ struct fn_field *f = NULL;
+ struct ext_fn_descriptor *ef = NULL;

- *num_fns = 0;
+ CHECK_TYPEDEF (type);

/* First check in object itself. */
- for (i = TYPE_NFN_FIELDS (type) - 1; i >= 0; i--)
- {
- /* pai: FIXME What about operators and type conversions? */
- const char *fn_field_name = TYPE_FN_FIELDLIST_NAME (type, i);

- if (fn_field_name && (strcmp_iw (fn_field_name, method) == 0))
- {
- int len = TYPE_FN_FIELDLIST_LENGTH (type, i);
- struct fn_field *f = TYPE_FN_FIELDLIST1 (type, i);
-
- *num_fns = len;
- *basetype = type;
- *boffset = offset;
-
- /* Resolve any stub methods. */
- check_stub_method_group (type, i);
+ if (fn_list && !(*fn_list))
+ for (i = TYPE_NFN_FIELDS (type) - 1; i >= 0; i--)
+ {
+ /* pai: FIXME What about operators and type conversions? */
+ const char *fn_field_name = TYPE_FN_FIELDLIST_NAME (type, i);
+
+ if (fn_field_name && (strcmp_iw (fn_field_name, method) == 0))
+ {
+ int len = TYPE_FN_FIELDLIST_LENGTH (type, i);
+ f = TYPE_FN_FIELDLIST1 (type, i);
+ *fn_list = f;
+
+ *num_fns = len;
+ *basetype = type;
+ *boffset = offset;
+
+ /* Resolve any stub methods. */
+ check_stub_method_group (type, i);
+
+ break;
+ }
+ }

- return f;
- }
+ if (ext_fn_list)
+ {
+ ef = get_matching_ext_methods (type, method);
+ *ext_fn_list = ext_fn_list_extend (*ext_fn_list, ef);
}

- /* Not found in object, check in base subobjects. */
+ /* If source methods are not found in current class, look for them in the
+ base classes. We have to go through the base classes to gather extension
+ methods anyway. */
for (i = TYPE_N_BASECLASSES (type) - 1; i >= 0; i--)
{
int base_offset;
@@ -2483,13 +2498,11 @@ find_method_list (struct value **argp, const char *method,
{
base_offset = TYPE_BASECLASS_BITPOS (type, i) / 8;
}
- f = find_method_list (argp, method, base_offset + offset,
- TYPE_BASECLASS (type, i), num_fns,
- basetype, boffset);
- if (f)
- return f;
+
+ find_method_list (argp, method, base_offset + offset,
+ TYPE_BASECLASS (type, i), fn_list, num_fns,
+ ext_fn_list, basetype, boffset);
}
- return NULL;
}

/* Return the list of overloaded methods of a specified name.
@@ -2502,9 +2515,11 @@ find_method_list (struct value **argp, const char *method,
method.
BOFFSET is the offset of the base subobject which defines the method. */

-static struct fn_field *
+static void
value_find_oload_method_list (struct value **argp, const char *method,
- int offset, int *num_fns,
+ int offset, struct fn_field **fn_list,
+ int *num_fns,
+ struct ext_fn_descriptor **ext_fn_list,
struct type **basetype, int *boffset)
{
struct type *t;
@@ -2526,8 +2541,32 @@ value_find_oload_method_list (struct value **argp, const char *method,
error (_("Attempt to extract a component of a "
"value that is not a struct or union"));

- return find_method_list (argp, method, 0, t, num_fns,
- basetype, boffset);
+ /* Clear the lists. */
+ if (fn_list)
+ {
+ *fn_list = NULL;
+ *num_fns = 0;
+ }
+ if (ext_fn_list)
+ *ext_fn_list = NULL;
+
+ find_method_list (argp, method, 0, t, fn_list, num_fns, ext_fn_list,
+ basetype, boffset);
+}
+
+static struct type *
+value_has_indirect_dynamic_type (struct value *obj)
+{
+ struct type *stype, *dtype, *dtype_ind;
+
+ stype = check_typedef (TYPE_TARGET_TYPE (value_type (obj)));
+ dtype_ind = value_rtti_indirect_type (obj, NULL, NULL, NULL);
+ dtype = dtype_ind ? check_typedef (TYPE_TARGET_TYPE (dtype_ind)) : stype;
+
+ if (class_types_same_p (stype, dtype))
+ return NULL;
+ else
+ return dtype_ind;
}

/* Given an array of arguments (ARGS) (which includes an
@@ -2576,7 +2615,8 @@ int
find_overload_match (struct value **args, int nargs,
const char *name, enum oload_search_type method,
int lax, struct value **objp, struct symbol *fsym,
- struct value **valp, struct symbol **symp,
+ struct value **valp, struct symbol **symp,
+ struct ext_fn_descriptor **ext_fn,
int *staticp, const int no_adl)
{
struct value *obj = (objp ? *objp : NULL);
@@ -2584,16 +2624,24 @@ find_overload_match (struct value **args, int nargs,
/* Index of best overloaded function. */
int func_oload_champ = -1;
int method_oload_champ = -1;
+ int src_method_oload_champ = -1;
+ int src_method_oload_champ_bkp = -1;
+ int ext_method_oload_champ = -1;
+ int src_and_ext_equal = 0;

/* The measure for the current best match. */
struct badness_vector *method_badness = NULL;
struct badness_vector *func_badness = NULL;
+ struct badness_vector *ext_method_badness = NULL;
+ struct badness_vector *src_method_badness = NULL;

struct value *temp = obj;
/* For methods, the list of overloaded methods. */
struct fn_field *fns_ptr = NULL;
/* For non-methods, the list of overloaded function symbols. */
struct symbol **oload_syms = NULL;
+ /* For extension functions, the list of extension function descriptors. */
+ struct ext_fn_descriptor *ext_fn_list = NULL;
/* Number of overloaded instances being considered. */
int num_fns = 0;
struct type *basetype = NULL;
@@ -2605,6 +2653,8 @@ find_overload_match (struct value **args, int nargs,
const char *func_name = NULL;
enum oload_classification match_quality;
enum oload_classification method_match_quality = INCOMPATIBLE;
+ enum oload_classification src_method_match_quality = INCOMPATIBLE;
+ enum oload_classification ext_method_match_quality = INCOMPATIBLE;
enum oload_classification func_match_quality = INCOMPATIBLE;

/* Get the list of overloaded methods or functions. */
@@ -2633,12 +2683,13 @@ find_overload_match (struct value **args, int nargs,
}

/* Retrieve the list of methods with the name NAME. */
- fns_ptr = value_find_oload_method_list (&temp, name,
- 0, &num_fns,
- &basetype, &boffset);
+ value_find_oload_method_list (&temp, name, 0, &fns_ptr, &num_fns,
+ ext_fn ? &ext_fn_list : NULL,
+ &basetype, &boffset);
/* If this is a method only search, and no methods were found
the search has faild. */
- if (method == METHOD && (!fns_ptr || !num_fns))
+ if (method == METHOD && (!fns_ptr || !num_fns)
+ && (ext_fn && !ext_fn_list))
error (_("Couldn't find method %s%s%s"),
obj_type_name,
(obj_type_name && *obj_type_name) ? "::" : "",
@@ -2649,18 +2700,81 @@ find_overload_match (struct value **args, int nargs,
if (fns_ptr)
{
gdb_assert (TYPE_DOMAIN_TYPE (fns_ptr[0].type) != NULL);
- method_oload_champ = find_oload_champ (args, nargs, method,
- num_fns, fns_ptr,
- oload_syms, &method_badness);
-
- method_match_quality =
- classify_oload_match (method_badness, nargs,
- oload_method_static (method, fns_ptr,
- method_oload_champ));
-
- make_cleanup (xfree, method_badness);
+ src_method_oload_champ = find_oload_champ (args, nargs, method,
+ num_fns, fns_ptr, NULL,
+ oload_syms,
+ &src_method_badness);
+
+ src_method_match_quality =
+ classify_oload_match (
+ src_method_badness, nargs,
+ oload_method_static (method, fns_ptr,
+ src_method_oload_champ));
+
+ make_cleanup (xfree, src_method_badness);
}

+ if (ext_fn_list)
+ {
+ ext_method_oload_champ = find_oload_champ (args, nargs, method,
+ 0, NULL, ext_fn_list,
+ NULL, &ext_method_badness);
+ ext_method_match_quality = classify_oload_match (ext_method_badness,
+ nargs, 0);
+ make_cleanup (xfree, ext_method_badness);
+ }
+
+ if (src_method_oload_champ >= 0 && ext_method_oload_champ >= 0)
+ {
+ switch (compare_badness (ext_method_badness, src_method_badness))
+ {
+ case 0: /* Src method and ext method are equally good. */
+ src_and_ext_equal = 1;
+ case 1: /* Src method and ext method are incompatible */
+ /* if ext method match is not standard, then let source method
+ win. */
+ if (ext_method_match_quality != STANDARD)
+ {
+ method_oload_champ = src_method_oload_champ;
+ method_badness = src_method_badness;
+ ext_method_oload_champ = -1;
+ method_match_quality = src_method_match_quality;
+ break;
+ }
+ case 2: /* Ext method is champion. */
+ method_oload_champ = ext_method_oload_champ;
+ method_badness = ext_method_badness;
+ src_method_oload_champ_bkp = src_method_oload_champ;
+ src_method_oload_champ = -1;
+ method_match_quality = ext_method_match_quality;
+ break;
+ case 3: /* Src method is champion. */
+ method_oload_champ = src_method_oload_champ;
+ method_badness = src_method_badness;
+ ext_method_oload_champ = -1;
+ method_match_quality = src_method_match_quality;
+ break;
+ default:
+ error (_("Internal error: unexpected overload comparison "
+ "result"));
+ break;
+ }
+ }
+ else
+ {
+ if (src_method_oload_champ >= 0)
+ {
+ method_oload_champ = src_method_oload_champ;
+ method_badness = src_method_badness;
+ method_match_quality = src_method_match_quality;
+ }
+ if (ext_method_oload_champ >= 0)
+ {
+ method_oload_champ = ext_method_oload_champ;
+ method_badness = ext_method_badness;
+ method_match_quality = ext_method_match_quality;
+ }
+ }
}

if (method == NON_METHOD || method == BOTH)
@@ -2803,21 +2917,6 @@ find_overload_match (struct value **args, int nargs,
func_name);
}

- if (staticp != NULL)
- *staticp = oload_method_static (method, fns_ptr, method_oload_champ);
-
- if (method_oload_champ >= 0)
- {
- if (TYPE_FN_FIELD_VIRTUAL_P (fns_ptr, method_oload_champ))
- *valp = value_virtual_fn_field (&temp, fns_ptr, method_oload_champ,
- basetype, boffset);
- else
- *valp = value_fn_field (&temp, fns_ptr, method_oload_champ,
- basetype, boffset);
- }
- else
- *symp = oload_syms[func_oload_champ];
-
if (objp)
{
struct type *temp_type = check_typedef (value_type (temp));
@@ -2827,10 +2926,66 @@ find_overload_match (struct value **args, int nargs,
&& (TYPE_CODE (objtype) == TYPE_CODE_PTR
|| TYPE_CODE (objtype) == TYPE_CODE_REF))
{
- temp = value_addr (temp);
+ *objp = value_addr (temp);
}
- *objp = temp;
+ else
+ *objp = temp;
+ }
+
+ if (staticp != NULL)
+ *staticp = oload_method_static (method, fns_ptr, method_oload_champ);
+
+ if (method_oload_champ >= 0)
+ {
+ if (src_method_oload_champ >= 0)
+ {
+ if (TYPE_FN_FIELD_VIRTUAL_P (fns_ptr, method_oload_champ))
+ {
+ struct type *dtype;
+
+ dtype = value_has_indirect_dynamic_type (args[0]);
+ if (dtype)
+ {
+ args[0] = value_cast (dtype, args[0]);
+ do_cleanups (all_cleanups);
+ return find_overload_match (args, nargs, name, method, lax,
+ objp, fsym, valp, symp, ext_fn,
+ staticp, no_adl);
+ }
+ else
+ *valp = value_virtual_fn_field (&temp, fns_ptr,
+ method_oload_champ,
+ basetype, boffset);
+ }
+ else
+ *valp = value_fn_field (&temp, fns_ptr, method_oload_champ,
+ basetype, boffset);
+ }
+ else
+ {
+ if (src_and_ext_equal
+ && TYPE_FN_FIELD_VIRTUAL_P (fns_ptr, src_method_oload_champ_bkp))
+ {
+ struct type *dtype;
+
+ dtype = value_has_indirect_dynamic_type (args[0]);
+ if (dtype)
+ {
+ args[0] = value_cast (dtype, args[0]);
+ do_cleanups (all_cleanups);
+ return find_overload_match (args, nargs, name, method, lax,
+ objp, fsym, valp, symp, ext_fn,
+ staticp, no_adl);
+ }
+ }
+
+ *ext_fn = ext_fn_list_get (ext_fn_list, ext_method_oload_champ);
+ ext_fn_list = ext_fn_list_remove (ext_fn_list, *ext_fn);
+ ext_fn_list_free (ext_fn_list);
+ }
}
+ else
+ *symp = oload_syms[func_oload_champ];

do_cleanups (all_cleanups);

@@ -2965,7 +3120,7 @@ find_oload_champ_namespace_loop (struct value **args, int nargs,
++num_fns;

new_oload_champ = find_oload_champ (args, nargs, 0, num_fns,
- NULL, new_oload_syms,
+ NULL, NULL, new_oload_syms,
&new_oload_champ_bv);

/* Case 1: We found a good match. Free earlier matches (if any),
@@ -3013,6 +3168,7 @@ find_oload_champ_namespace_loop (struct value **args, int nargs,
static int
find_oload_champ (struct value **args, int nargs, int method,
int num_fns, struct fn_field *fns_ptr,
+ struct ext_fn_descriptor *ext_fn_list,
struct symbol **oload_syms,
struct badness_vector **oload_champ_bv)
{
@@ -3028,16 +3184,24 @@ find_oload_champ (struct value **args, int nargs, int method,
*oload_champ_bv = NULL;

/* Consider each candidate in turn. */
- for (ix = 0; ix < num_fns; ix++)
+ for (ix = 0; (ix < num_fns) || ext_fn_list; ix++)
{
int jj;
- int static_offset = oload_method_static (method, fns_ptr, ix);
+ int static_offset = 0;
int nparms;
struct type **parm_types;
+ struct ext_fn_descriptor *ext_fn = ext_fn_list;
+
+ if (ext_fn_list)
+ ext_fn_list = ext_fn_list->next;

if (method)
{
- nparms = TYPE_NFIELDS (TYPE_FN_FIELD_TYPE (fns_ptr, ix));
+ if (fns_ptr)
+ {
+ static_offset = oload_method_static (method, fns_ptr, ix);
+ nparms = TYPE_NFIELDS (TYPE_FN_FIELD_TYPE (fns_ptr, ix));
+ }
}
else
{
@@ -3046,13 +3210,20 @@ find_oload_champ (struct value **args, int nargs, int method,
}

/* Prepare array of parameter types. */
- parm_types = (struct type **)
- xmalloc (nparms * (sizeof (struct type *)));
- for (jj = 0; jj < nparms; jj++)
- parm_types[jj] = (method
- ? (TYPE_FN_FIELD_ARGS (fns_ptr, ix)[jj].type)
- : TYPE_FIELD_TYPE (SYMBOL_TYPE (oload_syms[ix]),
- jj));
+ if (fns_ptr || oload_syms)
+ {
+ parm_types = (struct type **)
+ xmalloc (nparms * (sizeof (struct type *)));
+ for (jj = 0; jj < nparms; jj++)
+ parm_types[jj] = (method
+ ? (TYPE_FN_FIELD_ARGS (fns_ptr, ix)[jj].type)
+ : TYPE_FIELD_TYPE (SYMBOL_TYPE (oload_syms[ix]),
+ jj));
+ }
+ else
+ {
+ parm_types = ext_fn_get_argtypes (ext_fn, &nparms);
+ }

/* Compare parameter types to supplied argument types. Skip
THIS for static methods. */
diff --git a/gdb/value.h b/gdb/value.h
index 67f1d04..08991f0 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -31,6 +31,7 @@ struct type;
struct ui_file;
struct language_defn;
struct value_print_options;
+struct ext_fn_descriptor;

/* The structure which defines the type of a value. It should never
be possible for a program lval value to survive over a call to the
@@ -648,6 +649,7 @@ extern int find_overload_match (struct value **args, int nargs,
enum oload_search_type method, int lax,
struct value **objp, struct symbol *fsym,
struct value **valp, struct symbol **symp,
+ struct ext_fn_descriptor **ext_fn,
int *staticp, const int no_adl);

extern struct value *value_field (struct value *arg1, int fieldno);

[-- Attachment #3: dm.cc --]
[-- Type: application/octet-stream, Size: 1251 bytes --]

#include <iostream>

using namespace std;

namespace dop
{

class A
{
public:
int a;
int array[10];
virtual ~A();
int operator+(const A &obj);
virtual int operator-(const A &obj);
virtual int geta();
};

A::~A()
{
}

int A::operator+(const A &obj)
{
cout << "From C++, A + A" << endl;
return a + obj.a;
}

int A::operator-(const A &obj)
{
cout << "From C++, A - A" << endl;
return a - obj.a;
}

int A::geta(void)
{
return a;
}

class B : public A
{
public:
virtual int operator*(const B &obj);
};

int
B::operator*(const B &obj)
{
cout << "From C++, B * B" << endl;
return a * obj.a;
}

typedef B Bt;

typedef Bt Btt;

class C : public Bt
{
public:
virtual ~C();
};

C::~C() { }

class D : public B
{
public:
virtual int operator*(const B &obj);
};

int
D::operator*(const B &obj)
{
cout << "From C++, D * D" << endl;
return a * obj.a;
}

}

using namespace dop;

int func(const A &a)
{
return a.a;
}

int main(void)
{
A a1, a2;
a1.a = 5;
a2.a = 10;
C c1;
c1.a = 20;
B b1;
b1.a = 30;
D d1;
d1.a = 50;
Bt bt;
bt.a = 40;
A &ref_c = c1;
B &ref_d = d1;
Btt btt;
btt.a = -5;

for (int i = 0; i < 10; i++)
{
a1.array[i] = a2.array[i] = i;
}

return ref_c - ref_d;
}

[-- Attachment #4: dm-gdb.py --]
[-- Type: application/octet-stream, Size: 2401 bytes --]

from gdb.debugmethods import SimpleDebugMethod

def A_plus_A(obj, opr):
print 'From Python (A_plus_A)'
return obj['a'] + opr['a']

def plus_plus_A(obj):
return obj['a'] + 1

def C_minus_C(obj, opr):
print 'From Python (C_minus_C)'
return obj['a'] - opr['a']

def B_star_B(obj, opr):
print 'From Python (B_star_B)'
return obj['a'] * opr['a']

def A_geta(obj):
print 'From Python (A_geta)'
return obj['a']

def A_getarray(obj, index):
print 'From Python (A_getarray)'
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_C = gdb.parse_and_eval('(dop::C *) 0').type.target()
type_int = gdb.parse_and_eval('(int *) 0').type.target()

dm_list = [
SimpleDebugMethod('A_plus_A',
'DEFAULT_DEBUG_METHOD_GROUP',
A_plus_A,
'^dop::A$',
'operator\+',
# This is a replacement, hence match the arg type
# exactly!
type_A.const().reference()),
SimpleDebugMethod('plus_plus_A',
'DEFAULT_DEBUG_METHOD_GROUP',
plus_plus_A,
'^dop::A$',
'operator\+\+'),
SimpleDebugMethod('C_minus_C',
'DEFAULT_DEBUG_METHOD_GROUP',
C_minus_C,
'^dop::C$',
'operator\-',
type_C),
SimpleDebugMethod('B_star_B',
'DEFAULT_DEBUG_METHOD_GROUP',
B_star_B,
'^dop::B$',
'operator\*',
# This is a replacement, hence match the arg type
# exactly!
type_B.const().reference()),
SimpleDebugMethod('A_geta',
'DEFAULT_DEBUG_METHOD_GROUP',
A_geta,
'^dop::A$',
'^geta$'),
SimpleDebugMethod('A_getarray',
'DEFAULT_DEBUG_METHOD_GROUP',
A_getarray,
'^dop::A$',
'^getarray$',
type_int),
]

gdb.debugmethods.register_debug_methods(gdb.current_objfile(), dm_list)

debug_methods = gdb.current_objfile().debug_methods