Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* [RFC] Debug Methods in GDB Python
@ 2013-01-07 21:22 Siva Chandra
  2013-01-29  1:51 ` Siva Chandra
  0 siblings, 1 reply; 18+ messages in thread
From: Siva Chandra @ 2013-01-07 21:22 UTC (permalink / raw)
  To: gdb-patches; +Cc: Doug Evans

[-- 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

^ permalink raw reply	[flat|nested] 18+ messages in thread

end of thread, other threads:[~2013-11-20  2:42 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-01-07 21:22 [RFC] Debug Methods in GDB Python Siva Chandra
2013-01-29  1:51 ` Siva Chandra
2013-02-25 23:02   ` Siva Chandra
2013-05-10 19:33   ` Tom Tromey
2013-05-10 19:55     ` Siva Chandra
2013-05-14 19:33       ` Tom Tromey
2013-06-17 19:10         ` Siva Chandra
2013-07-22 20:47           ` Tom Tromey
2013-11-12  2:56             ` Siva Chandra
2013-11-15 22:28               ` Tom Tromey
2013-11-16  0:05                 ` Siva Chandra
2013-11-16  0:54                   ` Doug Evans
2013-11-16  1:03                     ` Siva Chandra
2013-11-16  2:48                       ` Siva Chandra
2013-11-20  0:03                         ` Doug Evans
2013-11-19 23:52                       ` Doug Evans
2013-11-20  0:39                         ` Siva Chandra
2013-11-20  2:48                         ` Doug Evans

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox