[PATCH] Debug Methods in GDB Python

Siva Chandra sivachandra@google.com
Tue Nov 26 03:22:00 GMT 2013


Doug pointed out offlist that the ChangeLog was improperly done. Below
is the corrected ChangeLog entry. For convenience, I have also
attached the same patch that I have posted last time.

2013-11-25  Siva Chandra Reddy  <sivachandra@google.com>

        Add Debug methods support in GDB Python.

        * Makefile.in: Add entries for new files.
        * data-directory/Makefile.in: Add entries for new Python files.
        * eval.c (evaluate_subexp_standard): Lookup and invoke methods
        defined in extension languages.
        * valarith.c (value_x_binop, value_x_unop): Lookup and invoke
        overloaded operator methods defined in extension languages.
        * valops.c (find_oload_method_list, find_method_list,
        find_overload_match, find_oload_champ): Lookup methods defined
        in extension languages.
        (value_has_indirect_dynamic_type): New function to determine
        the indirect dynamic type of a value.
        * value.h (find_overload_match): Update signature.
        * ext-function.c: New file.
        * ext-function.h: New file.
        * python/py-debugmethods.c: New file.
        * python/py-objfile.c (objfile_object): New field
        'debug_methods'.
        (objfpy_dealloc): XDECREF on the new debug_methods field.
        (objfpy_new, objfile_to_objfile_object): Initialize
        debug_methods field.
        (objfpy_get_debug_methods): New function.
        (objfile_getset): New entry 'debug_methods'.
        * python/py-progspace.c (pspace_object): New field
        'debug_methods'.
        (pspy_dealloc): XDECREF on the new debug_methods field.
        (pspy_new, pspace_to_pspace_object): Initialize
        debug_methods field.
        (pspy_get_debug_methods): New function.
        (pspace_getset): New entry 'debug_methods'.
        * python/python-internal.h: Add declarations for new functions.
        * python/python.c (_initialize_python): Invoke
        gdbpy_initialize_debugmethods.
        * python/python.h: Add declarations of new functions.
        * python/lib/gdb/__init__.py (debug_methods): New attribute.
        * python/lib/gdb/debugmethods.py: New file.
        * python/lib/gdb/command/debug-methods.py: New file.

        testuite/
        * gdb.python/py-debugmethods.cc: New testcase to test debug
        methods.
        * gdb.python/py-debugmethods.exp: New tests to test debug
        methods.
        * gdb.python/py-debugmethods.py: Python script supporting the
        new testcase and tests.
-------------- next part --------------
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 0591279..75e2be6 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -287,6 +287,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 \
@@ -323,6 +324,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 \
@@ -733,7 +735,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 gdb_obstack.c \
@@ -835,7 +837,7 @@ rs6000-tdep.h rs6000-aix-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 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 \
@@ -957,7 +959,8 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
 	inferior.o osdata.o gdb_usleep.o record.o record-full.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 btrace.o record-btrace.o waitstatus.o
+	format.o registry.o btrace.o record-btrace.o waitstatus.o \
+	ext-function.o
 
 TSOBS = inflow.o
 
@@ -2181,6 +2184,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 1e00c58..6146cf1 100644
--- a/gdb/data-directory/Makefile.in
+++ b/gdb/data-directory/Makefile.in
@@ -61,8 +61,10 @@ PYTHON_FILES = \
 	gdb/types.py \
 	gdb/printing.py \
 	gdb/prompt.py \
+	gdb/debugmethods.py \
 	gdb/command/bound_registers.py \
 	gdb/command/__init__.py \
+	gdb/command/debug_methods.py \
 	gdb/command/frame_filters.py \
 	gdb/command/type_printers.py \
 	gdb/command/pretty_printers.py \
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index ec9d901..9eabd1d 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -23526,6 +23526,7 @@ optional arguments while skipping others.  Example:
 * Selecting Pretty-Printers::   How GDB chooses a pretty-printer.
 * Writing a Pretty-Printer::    Writing a Pretty-Printer.
 * Type Printing API::		Pretty-printing types.
+* Debug Methods In Python::     Debug Methods In Python.
 * Frame Filter API::            Filtering Frames.
 * Frame Decorator API::         Decorating Frames.
 * Writing a Frame Filter::      Writing a Frame Filter.
@@ -24909,6 +24910,75 @@ done then type printers would have to make use of the event system in
 order to avoid holding information that could become stale as the
 inferior changed.
 
+@node Debug Methods In Python
+@subsubsection Debug Methods In Python
+@cindex debug methods in Python
+
+Debug methods are, as the name suggests, method definitions on classes
+but defined in @value{GDBN} Python instead of the source language.  If a
+particular method (which could be an overloaded operator) needs to be
+invoked to evaluate a certain expression in @value{GDBN}, then
+@value{GDBN} invokes the Python implementation of the method if the
+Python definition is better or as good a match as the implementation of
+the method in the source language.  A benefit of having a debug method
+replacement for a source language method is that expressions involving
+the method can be evaluated in @value{GDBN} without running the method
+in the inferior.  Another benefit is with regards to method which
+typically get optimized out by the compiler.  Since debug methods live
+in @value{GDBN} Python and not in the source language, they are never
+optimized out.  Lastly, one could define a debug method in @value{GDBN}
+Python which does not have an equivalent in the source language!
+
+The debug method API provided in @value{GDBN} Python can be illustrated
+with the following example.  Consider a C++ code snippet as follows:
+
+@smallexample
+class A
+@{
+ public:
+  int geta(void)
+  @{
+    return a;
+  @}
+
+ private:
+  int a;
+@};
+@end smallexample
+
+In the above example, the method @code{geta} in @code{class A}, might
+get optimized out in a client executable if @code{geta} is never called.
+However, one might want to call @code{geta} from @value{GDBN} for
+debugging.  For such cases, we could have an equivalent Python
+implementation as a replacement for the C++ method.  The debug method
+can be defined in Python as follows:
+
+@smallexample
+def A_geta(obj):
+  """Function which implemenents a Python replacement for A::geta.
+  Args:
+    obj: This is equivalent of the C++ 'this'
+  """
+  return obj['a']                                                                                         
+
+dm_A_geta = gdb.debugmethods.SimpleDebugMethod(
+    'A_geta',                      # A unique name to the debug method
+    'DEFAULT_DEBUG_METHOD_GROUP',  # A group name for the debug method
+    A_geta,                        # The function implementing the debug
+                                   # method
+    '^dop::A$',                    # The class to which this debug
+                                   # method should belong.
+    '^geta$'                       # The regex which matches the method
+                                   # which this debug method is replacing.
+)
+
+gdb.debugmethods.register_debug_methods(
+    gdb,         # Register the debug method globally
+    [dm_A_geta]  # The list of debug methods to register
+)
+@end smallexample
+
+
 @node Frame Filter API
 @subsubsection Filtering Frames.
 @cindex frame filters api
diff --git a/gdb/eval.c b/gdb/eval.c
index 9d81a92..ebeb02d 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"
@@ -1596,7 +1597,7 @@ evaluate_subexp_standard (struct type *expect_type,
                                NON_METHOD, /* not method */
                                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;
@@ -1626,11 +1627,12 @@ 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 */
 					  &arg2,  /* the object */
-					  NULL, &valp, NULL,
+					  NULL, &valp, NULL, &ext_fnp,
 					  &static_memfuncp, 0);
 
 	      if (op == OP_SCOPE && !static_memfuncp)
@@ -1640,9 +1642,36 @@ 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 (ext_fnp)
+                {
+                  if (ext_fn_is_method (ext_fnp))
+                    {
+                      struct value *ret_val;
+
+                      ret_val = ext_fn_invoke_method (ext_fnp, arg2, argvec + 2,
+                                                      nargs - 1);
+                      if (ret_val == NULL)
+                        error (_("Error invoking debug method for method %s."),
+                               tstr);
+
+                      xfree (ext_fnp);
+
+                      return ret_val;
+                    }
+                  else
+                    {
+                      /* This else should not be taken as only debug methods
+                         are supported currently.  */
+                      internal_error (__FILE__, __LINE__,
+                                      _("Invoking an extension language "
+                                        "function (not a method)."));
+                    }
+                }
+
+              argvec[1] = arg2;     /* the ``this'' pointer */
+              argvec[0] = valp;     /* Use the method found after overload
+                                       resolution.  */
 	    }
 	  else
 	    /* Non-C++ case -- or no overload resolution.  */
@@ -1701,7 +1730,7 @@ evaluate_subexp_standard (struct type *expect_type,
 					  NULL,        /* no need for name */
 	                                  NON_METHOD,  /* not method */
 	                                  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..311c5d5
--- /dev/null
+++ b/gdb/ext-function.c
@@ -0,0 +1,172 @@
+/* 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 "cleanups.h"
+#include "ext-function.h"
+
+#include "gdb_assert.h"
+#include "vec.h"
+
+struct ext_fn_descriptor
+  {
+    const struct ext_func_ops *lang;
+
+    int is_method;
+
+    void *ext_object;
+  };
+
+typedef struct ext_func_ops *ext_lang_p;
+DEF_VEC_P (ext_lang_p);
+static VEC (ext_lang_p) *ext_lang_vec = NULL;
+
+/* Registers an extension language with GDB.  */
+
+void
+register_ext_lang (struct ext_func_ops *lang)
+{
+  if (ext_lang_vec == NULL)
+    ext_lang_vec = VEC_alloc (ext_lang_p, 1);
+      
+  VEC_safe_push (ext_lang_p, ext_lang_vec, lang);
+}
+
+/* Returns a new ext_fn_descriptor object.  LANG is the extention language the
+   new extension function is implemented in.  IS_METHOD indicates whether the
+   new extension function is a method.  EXT_OBJ is the extension language
+   specific data to be encapsulated in the ext_fn_descriptor.  */
+
+struct ext_fn_descriptor *
+new_ext_function (const struct ext_func_ops *lang, int is_method, void *ext_obj)
+{
+  struct ext_fn_descriptor *ext_fn = XCNEW (struct ext_fn_descriptor);
+
+  ext_fn->is_method = is_method;
+  ext_fn->lang = lang;
+  ext_fn->ext_object = ext_obj;
+
+  return ext_fn;
+}
+
+/* Clones EXT_FN and returns a new but identical ext_fn_descriptor.  */
+
+struct ext_fn_descriptor *
+ext_fn_clone (struct ext_fn_descriptor *ext_fn)
+{
+  struct ext_fn_descriptor *new_ext_fn;
+  const struct ext_func_ops *lang = ext_fn->lang;
+
+  new_ext_fn = new_ext_function (lang, ext_fn->is_method,
+                                 lang->clone_ext_object (ext_fn->ext_object));
+
+  return new_ext_fn;
+}
+
+/* If a method of name METHOD is to be invoked on an object of type TYPE, then
+   all entension languages are searched for implementations of methods with 
+   name METHOD in the extension languages.  All matches found are returned as
+   a vector 'struct ent_fn_descriptor' objects.  If no matching methods are
+   found, NULL is returned.  */
+
+VEC (ext_fn_descriptor_p) *
+get_matching_ext_methods (struct type *type, const char *method)
+{
+  VEC (ext_fn_descriptor_p) *ext_methods = NULL;
+  ext_lang_p lang;
+  int i;
+
+  for (i = 0; VEC_iterate (ext_lang_p, ext_lang_vec, i, lang); i++)
+    {
+      VEC (ext_fn_descriptor_p) *lang_methods, *new_vec;
+
+      lang_methods = lang->get_matching_ext_methods (type, method);
+      new_vec = VEC_merge (ext_fn_descriptor_p, ext_methods, lang_methods);
+
+      VEC_free (ext_fn_descriptor_p, ext_methods);
+      VEC_free (ext_fn_descriptor_p, lang_methods);
+      ext_methods = new_vec;
+    }
+
+  return ext_methods;
+}
+
+/* Given an function EXT_FN implemented in an extension language, returns an
+   array of types of the arguments the function accepts.  The length of the
+   array is returned in NARGS.  The type of the 'this' object is returned as
+   the first argument if EXT_FN is a method.  If EXT_FN does not take any
+   arguments, then NULL is returned with 0 in NARGS.  */
+
+struct type **
+ext_fn_get_argtypes (struct ext_fn_descriptor *ext_fn, int *nargs)
+{
+  gdb_assert (ext_fn && ext_fn->lang && ext_fn->lang->get_ext_fn_argtypes);
+
+  return ext_fn->lang->get_ext_fn_argtypes (ext_fn->ext_object, nargs);
+}
+
+/* If EXT_FN is a method implemented in an extension language, invokes  it and
+   returns the resulting value.  The method is invoked on OBJ with arguments
+   ARGS.  NARGS is the length of the ARGS array.  */
+
+struct value *
+ext_fn_invoke_method (struct ext_fn_descriptor *ext_fn, struct value *obj,
+                      struct value **args, int nargs)
+{
+  gdb_assert (ext_fn && ext_fn->is_method && ext_fn->lang
+              && ext_fn->lang->invoke_method);
+
+  return ext_fn->lang->invoke_method (ext_fn->ext_object, obj, args, nargs);
+}
+
+/* Returns true if EXT_FN is a method, 0 otherwise.  */
+
+int
+ext_fn_is_method (struct ext_fn_descriptor *ext_fn)
+{
+  if (ext_fn != NULL)
+    return ext_fn->is_method;
+
+  return 0;
+}
+
+/* Frees a vector of ext_fn_descriptors VEC.  */
+
+static void
+ext_fn_vec_free (void *vec)
+{
+  int i;
+  struct ext_fn_descriptor *ext_fn;
+  VEC (ext_fn_descriptor_p) *v = (VEC (ext_fn_descriptor_p) *) vec;
+
+  for (i = 0; VEC_iterate (ext_fn_descriptor_p, v, i, ext_fn); i++)
+    {
+      ext_fn->lang->free_ext_obj (ext_fn->ext_object);
+      xfree (ext_fn);
+    }
+}
+
+/* Return a cleanup object to free a vector VEC of extension function
+   descriptors.  */
+
+struct cleanup *
+make_ext_fn_vec_cleanup (VEC (ext_fn_descriptor_p) *vec)
+{
+  return make_cleanup (ext_fn_vec_free, (void *) vec);
+}
diff --git a/gdb/ext-function.h b/gdb/ext-function.h
new file mode 100644
index 0000000..db05009
--- /dev/null
+++ b/gdb/ext-function.h
@@ -0,0 +1,75 @@
+/* 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
+
+#include "vec.h"
+
+struct cleanup;
+struct value;
+struct type;
+struct ext_fn_descriptor;
+
+typedef struct ext_fn_descriptor *ext_fn_descriptor_p;
+DEF_VEC_P (ext_fn_descriptor_p);
+typedef VEC (ext_fn_descriptor_p) ext_fn_vec;
+
+typedef struct value* (invoke_method_ftype) (void *ext_obj,
+                                             struct value *,
+                                             struct value **, int nargs);
+
+typedef void * (clone_ext_obj_ftype) (void *ext_obj);
+
+typedef void (free_ext_obj_ftype) (void *ext_obj);
+
+typedef ext_fn_vec *(get_matching_ext_methods_ftype) (struct type *type,
+                                                      const char *method);
+
+typedef struct type** (get_ext_fn_argtypes_ftype) (void *ext_obj, int *nargs);
+
+struct ext_func_ops
+  {
+    clone_ext_obj_ftype *clone_ext_object;
+    free_ext_obj_ftype *free_ext_obj;
+    get_matching_ext_methods_ftype *get_matching_ext_methods;
+    get_ext_fn_argtypes_ftype *get_ext_fn_argtypes;
+    invoke_method_ftype *invoke_method;
+  };
+
+extern void register_ext_lang (struct ext_func_ops *lang);
+
+extern struct value *ext_fn_invoke_method (struct ext_fn_descriptor *,
+                                           struct value *,
+                                           struct value **, int nargs);
+
+extern struct ext_fn_descriptor *ext_fn_clone (struct ext_fn_descriptor *);
+
+extern struct ext_fn_descriptor *new_ext_function (
+    const struct ext_func_ops *lang, int is_method, void *ext_obj);
+
+extern ext_fn_vec *get_matching_ext_methods (struct type *, const char *);
+
+extern struct type **ext_fn_get_argtypes (struct ext_fn_descriptor *, int *);
+
+extern int ext_fn_is_method (struct ext_fn_descriptor *);
+
+extern struct cleanup* make_ext_fn_vec_cleanup (VEC (ext_fn_descriptor_p) *vec);
+
+#endif /* EXT_FUNCTION_H */
diff --git a/gdb/python/lib/gdb/__init__.py b/gdb/python/lib/gdb/__init__.py
index 61f5b5e..d4d7ba7 100644
--- a/gdb/python/lib/gdb/__init__.py
+++ b/gdb/python/lib/gdb/__init__.py
@@ -67,6 +67,8 @@ pretty_printers = []
 
 # Initial type printers.
 type_printers = []
+# Initial debug_methods.
+debug_methods = []
 # Initial frame filters.
 frame_filters = {}
 
diff --git a/gdb/python/lib/gdb/command/debug_methods.py b/gdb/python/lib/gdb/command/debug_methods.py
new file mode 100644
index 0000000..1d2eb25
--- /dev/null
+++ b/gdb/python/lib/gdb/command/debug_methods.py
@@ -0,0 +1,218 @@
+# Debug method commands.
+# Copyright 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/>.
+
+import gdb
+import re
+
+"""GDB commands for working with debug-methods."""
+
+
+def parse_dm_command_args(arg):
+    """Parses the arguments passed to a debug method command.
+
+    Arguments:
+        arg: The argument string passed to a debug method command.
+
+    Returns:
+        A 2-tuple: (<locus matching regular expression>,
+                    <name matching regular expression>)
+    """
+    argv = gdb.string_to_argv(arg)
+    argc = len(argv)
+    if argc > 2:
+        raise SyntaxError("Too many arguments to command.")
+    locus_re = ''
+    name_re = ''
+    if argc >= 1:
+        locus_re = argv[0]
+    if argc == 2:
+        name_re = argv[1]
+    return locus_re, name_re
+
+
+def get_matching_global_methods(locus_re, name_re):
+    """Returns a dict of matching globally registered debug methods.
+
+    Arguments:
+        locus_re: Even though only globally registered debug methods are
+                  looked up, they will be looked up only if 'global' matches
+                  LOCUS_RE.
+        name_re: The regular expression matching the names of debug methods.
+    Returns:
+        A dict of matching globally registered debug methods.  The only key in
+        the dict will be 'global'.
+    """
+    dm = {}
+    if re.match(locus_re, 'global'):
+        matches = [m for m in gdb.debug_methods if re.match(name_re, m.name)]
+        if matches:
+            dm['global'] = matches
+    return dm
+
+
+def get_matching_methods_in_loci(loci, locus_re, name_re):
+    """Returns a dict of macthing registered debug methods in the LOCI.
+
+    Arguments:
+        loci: The list of loci to lookup matching debug methods in.
+        locus_re: Debug methods will be looked up in a particular locus only
+                  if its filename matches the regular expression LOCUS_RE.
+        name_re: The regular expression to match the names of debug methods.
+
+    Returns:
+        A dict of matching debug methods.  The keys of the dict are the
+        filenames of the loci the debug methods belong to.
+    """
+    dm = {}
+    for locus in loci:
+        if not re.match(locus_re, locus.filename):
+            continue
+        matches = [m for m in locus.debug_methods if re.match(name_re, m.name)]
+        if matches:
+            dm[locus.filename] = matches
+    return dm
+
+
+def print_dm_info(header, dm_dict):
+    """Print a dictionary of debug methods with an optional header."""
+    if not dm_dict:
+        return
+    # Global dm info will not have a header.  Space accordingly.
+    space = ''
+    if header:
+        print '%s:' % header
+        space = '  '
+    for locus, dm_list in dm_dict.iteritems():
+        if not dm_list:
+            continue
+        print '%s%s:' % (space, locus)
+        for dm in dm_list:
+            if dm.enabled:
+                status = 'enabled'
+            else:
+                status = 'disabled'
+            print '  %s%s - %s' % (space, dm.name, status)
+            
+
+def set_dm_status(dm_dict, status):
+    """Set the status (enabled/disabled) of a dictionary of debug methods."""
+    for locus, dm_list in dm_dict.iteritems():
+        if not dm_list:
+            continue
+        for dm in dm_list:
+            dm.enabled = status
+
+
+def set_matching_dm_status(arg, status):
+    """Set the status (enabled/disabled) of debug methods matching ARG.
+    This is a helper function for enable/disable commands.  ARG is the
+    argument string passed to the commands.
+    """
+    locus_re, name_re = parse_dm_command_args(arg)
+    set_dm_status(get_matching_global_methods(locus_re, name_re), status)
+    set_dm_status(
+        get_matching_methods_in_loci(gdb.progspaces(), locus_re, name_re),
+        status)
+    set_dm_status(
+        get_matching_methods_in_loci(gdb.objfiles(), locus_re, name_re),
+        status)
+
+
+class InfoDebugMethod(gdb.Command):
+    """GDB command to list registered debug-methods.
+
+    Usage: info debug-method [locus-regexp [name-regexp]]
+
+    LOCUS-REGEXP is a regular expression matching the location of the debug
+    methods.  If it is ommitted, all registered debug methods from all loci
+    are listed.  A locus could be 'global', a regular expression matching
+    filenames of program spaces or a regular expression matching filenames of
+    objfiles.
+
+    NAME-REGEXP is a regular expression matching the names of debug methods
+    within a given locus.  If this omitted for a specified locus, then all
+    registered debug methods in the locus are listed.
+    """
+
+    def __init__(self):
+        super(InfoDebugMethod, self).__init__("info debug-method",
+                                               gdb.COMMAND_DATA)
+
+    def invoke(self, arg, from_tty):
+        locus_re, name_re = parse_dm_command_args(arg)
+        print_dm_info(None, get_matching_global_methods(locus_re, name_re))
+        print_dm_info('progspaces', get_matching_methods_in_loci(
+            gdb.progspaces(), locus_re, name_re))
+        print_dm_info('objfiles', get_matching_methods_in_loci(
+            gdb.objfiles(), locus_re, name_re))
+
+
+class EnableDebugMethod(gdb.Command):
+    """GDB command to enable a specified (group of) debug method(s).
+
+    Usage: enable debug-method [locus-regexp [name-regexp]]
+
+    LOCUS-REGEXP is a regular expression matching the location of the debug
+    methods.  If it is ommitted, all registered debug methods from all loci
+    are enabled.  A locus could be 'global', a regular expression matching
+    filenames of program spaces or a regular expression matching filenames of
+    objfiles.
+
+    NAME-REGEXP is a regular expression matching the names of debug methods
+    within a given locus.  If this omitted for a specified locus, then all
+    registered debug methods in the locus are enabled.
+    """
+
+    def __init__(self):
+        super(EnableDebugMethod, self).__init__("enable debug-method",
+                                                gdb.COMMAND_DATA)
+
+    def invoke(self, arg, from_tty):
+        set_matching_dm_status(arg, True)
+        
+
+class DisableDebugMethod(gdb.Command):
+    """GDB command to disable a specified (group of) debug method(s).
+
+    Usage: disable debug-method [locus-regexp [name-regexp]]
+
+    LOCUS-REGEXP is a regular expression matching the location of the debug
+    methods.  If it is ommitted, all registered debug methods from all loci
+    are disabled.  A locus could be 'global', a regular expression matching
+    filenames of program spaces or a regular expression matching filenames of
+    objfiles.
+
+    NAME-REGEXP is a regular expression matching the names of debug methods
+    within a given locus.  If this omitted for a specified locus, then all
+    registered debug methods in the locus are disabled.
+    """
+
+    def __init__(self):
+        super(DisableDebugMethod, self).__init__("disable debug-method",
+                                                gdb.COMMAND_DATA)
+
+    def invoke(self, arg, from_tty):
+        set_matching_dm_status(arg, False)
+        
+
+def register_debug_method_commands():
+    """Installs the debug method commands."""
+    InfoDebugMethod()
+    EnableDebugMethod()
+    DisableDebugMethod()
+
+
+register_debug_method_commands()
diff --git a/gdb/python/lib/gdb/debugmethods.py b/gdb/python/lib/gdb/debugmethods.py
new file mode 100644
index 0000000..7cfd2e3
--- /dev/null
+++ b/gdb/python/lib/gdb/debugmethods.py
@@ -0,0 +1,160 @@
+# 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 defining debug methods"""
+
+import gdb
+import re
+
+
+class DebugMethod(object):
+    """Base class for all debug methods defined in Python.
+
+    A debug method defined in Python should be derived from this class.  The
+    derived classes should override the methods 'match', 'get_argtypes' and
+    'invoke'.
+
+    Internally, GDB first invokes the 'match' method to match the class type
+    and the method name.  It next gets the argument types of these methods via
+    the 'get_argtypes' method to perform overload resolution.  If GDB selects
+    to invoke a Python debugmethod, then it invokes it via the overridden
+    'invoke' method.
+    """
+
+    def __init__(self, name):
+        """
+        Args:
+            name: An identifying name for the debug method.
+        """
+        self.name = name
+        self.enabled = True
+
+    def match(self, class_type, method_name):
+        """Match class type and method name.
+
+        Args:
+            class_type: The class type to match
+            method_name: The name of the method to match.
+        """
+        gdb.GdbError('ERROR: Invoking abstract method \'match\'.')
+
+    def get_argtypes(self, class_type, method_name):
+        """Return a list of types, as gdb.Type objects, of the arguments of
+           the debug method.
+
+        Args: 
+            class_type: The gdb.Type value of the class on which the method
+                        is defined.
+            method_name: The name of the method whose argument types are to
+                         be returned.
+        """
+        gdb.GdbError('ERROR: Invoking abstract method \'get_argtypes\'.')
+
+    def invoke(self, obj, method_name, args):
+        """Invoke the debug method.
+
+        Args:
+            obj: The gdb.Value of the object on which the method is to be
+                 invoked.
+            method_name: The name of the method being invoked.
+            args: The tuple of arguments to the method.
+        """
+        gdb.GdbError('ERROR: Invoking abstract method \'invoke\'.')
+
+
+class SimpleDebugMethod(DebugMethod):
+    """This is a utility class which does name match by class name of the
+    objects on which the debug methods are defined.  For simple classes and
+    methods, one can choose to use this class.  For complex debug methods,
+    which need to replace/implement template source methods on possibly
+    template classes, one should implement their own debug method classes
+    deriving from the base class 'DebugMethod'.  See the py-debugmethods.py
+    in the testsuite/gdb.python directory of the GDB source tree for
+    examples.
+    """
+
+    def __init__(self, name, method_function, class_matcher, method_matcher,
+                 *argtypes):
+        """
+        Args:
+            name: Name of the debug method.
+            method_function: A Python callable which would be called via the
+                             invoke them of this class to actually invoke the
+                             debug method.  This callable should accept the
+                             object (*this) as the first argument followed by
+                             the rest of the arguments to the method.
+            class_matcher: A regular expression used to match the name of the
+                           class whose method this debug method is
+                           implementing/replacing.
+            method_matcher: A regular expression used to match the name of the
+                            method this debug method is implementing/replacing.
+            argtypes: The gdb.Type objects corresponding to the arguments that
+                      this debug method takes.
+        """
+        DebugMethod.__init__(self, name)
+        assert callable(method_function), (
+            'The "method_function" argument to "SimpleDebugMethod" ' 
+            'constructor should be a callable.')
+        self._method_function = method_function
+        self._class_matcher = class_matcher
+        self._method_matcher = method_matcher
+        self._argtypes = argtypes
+
+    def match(self, class_type, method_name):
+        cm = re.match(self._class_matcher, str(class_type.unqualified().tag))
+        mm = re.match(self._method_matcher, method_name)
+        if cm and mm:
+            return True
+        else:
+            return False
+
+    def get_argtypes(self, class_type, method_name):
+        return self._argtypes
+
+    def invoke(self, obj, method_name, args):
+        return self._method_function(obj, *args)
+
+
+def register_debug_methods(locus, debug_methods):
+    """Registers a list of DEBUG_METHODS with a LOCUS.
+
+    Arguments:
+        locus: The locus in which the debug methods should be registered. It
+               can be 'None' to indicate that the debug methods should be
+               registered globally. Or, it could be a gdb.Objfile or a
+               gdb.Progspace object in which the debug methods should be
+               registered.
+        debug_methods: The list of debug methods to register.
+    """
+    if not locus:
+        locus = gdb
+    if locus == gdb:
+        locus_name = 'global'
+    else:
+        locus_name = locus.filename
+    existing_method_list = []
+    for new_method in debug_methods:
+        assert isinstance(new_method, DebugMethod), (
+            'Debug method objects should be instances of a subclass '
+            'of "DebugMethod".')
+        for old_method in locus.debug_methods:
+            if new_method.name == old_method.name:
+                print ('WARNING: Replacing debug method with name "%s" in '
+                       ' "%s".' % (old_method.name, locus_name))
+                existing_method_list.append(old_method)
+    for old_method in existing_method_list:
+        locus.debug_methods.remove(old_method)
+    locus.debug_methods.extend(debug_methods)
diff --git a/gdb/python/py-debugmethods.c b/gdb/python/py-debugmethods.c
new file mode 100644
index 0000000..8e3f45a
--- /dev/null
+++ b/gdb/python/py-debugmethods.c
@@ -0,0 +1,583 @@
+/* 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 "objfiles.h"
+#include "value.h"
+#include "language.h"
+
+#include "python.h"
+
+#ifdef HAVE_PYTHON
+#include "python-internal.h"
+
+struct py_ext_object
+{
+  /* Holds an instance of the DebugMethod class.  */
+  PyObject *object;
+
+  /* Holds the type of the 'this' object.  */
+  PyObject *match_py_obj_type;
+
+  /* Holds the matching method name.  */
+  const char *match_method;
+};
+
+static const char *enabled_field_name = "enabled";
+static const char *match_method_name = "match";
+static const char *get_argtypes_method_name = "get_argtypes";
+static const char *invoke_method_name = "invoke";
+
+static PyObject *match_method_pystring = NULL;
+static PyObject *get_argtypes_method_pystring = NULL;
+static PyObject *invoke_method_pystring = NULL;
+
+static struct ext_fn_descriptor *new_python_ext_method (PyObject *item,
+                                                        PyObject *py_obj_type,
+                                                        const char *method);
+
+/* Implementation of free_ext_obj_ftype.  */
+
+static void
+py_free_ext_object (void *ext_object)
+{
+  struct py_ext_object *o = ext_object;
+
+  Py_XDECREF (o->object);
+  Py_XDECREF (o->match_py_obj_type);
+  xfree (o);
+}
+
+/* Implementation of clone_ext_obj_ftype.  */
+
+static void *
+py_clone_ext_object (void *obj)
+{
+  struct py_ext_object *new_obj, *old_obj;
+
+  old_obj = (struct py_ext_object *) obj;
+
+  new_obj = XCNEW (struct py_ext_object);
+  new_obj->object = old_obj->object;
+  new_obj->match_py_obj_type = old_obj->match_py_obj_type;
+  new_obj->match_method = old_obj->match_method;
+
+  Py_XINCREF (new_obj->object);
+  Py_XINCREF (new_obj->match_py_obj_type);
+
+  return (void *) new_obj;
+}
+
+/* Returns true if gdb.Type object PY_OBJ_TYPE has a method defined in Python
+   with name METHOD_NAME.  */
+
+static int
+is_matching_debug_method (PyObject *dm_obj, PyObject *py_obj_type,
+                          const char *method_name)
+{
+  PyObject *method_name_pystring;
+  PyObject *match_method, *enabled_field, *match_result;
+  struct cleanup *cleanups;
+  int enabled, match;
+
+  if (method_name == NULL)
+    return 0;
+
+  cleanups = make_cleanup (null_cleanup, NULL);
+
+  enabled_field = PyObject_GetAttrString (dm_obj, enabled_field_name);
+  if (enabled_field == NULL)
+    {
+      gdbpy_print_stack ();
+      do_cleanups (cleanups);
+
+      return 0;
+    }
+  make_cleanup_py_decref (enabled_field);
+
+  enabled = PyObject_IsTrue (enabled_field);
+  if (enabled == -1)
+    {
+      gdbpy_print_stack ();
+      do_cleanups (cleanups);
+
+      return 0;
+    }
+  if (enabled == 0)
+    {
+      do_cleanups (cleanups);
+      return 0;
+    }
+
+  match_method = PyObject_GetAttrString (dm_obj, match_method_name);
+  if (match_method == NULL)
+    {
+      gdbpy_print_stack ();
+      do_cleanups (cleanups);
+
+      return 0;
+    }
+  make_cleanup_py_decref (match_method);
+  if (!PyCallable_Check (match_method))
+    {
+      warning (_("Attribute '%s' of a registered Python debug method is not "
+                 "callable.  Ignored!"), match_method_name);
+      do_cleanups (cleanups);
+
+      return 0;
+    }
+
+  method_name_pystring = PyString_FromString (method_name);
+  if (method_name_pystring == NULL)
+    {
+      gdbpy_print_stack ();
+      do_cleanups (cleanups);
+
+      return 0;
+    }
+  make_cleanup_py_decref (method_name_pystring);
+
+  match_result = PyObject_CallMethodObjArgs (dm_obj,
+                                             match_method_pystring,
+                                             py_obj_type,
+                                             method_name_pystring,
+                                             NULL);
+  if (match_result == NULL)
+    {
+      gdbpy_print_stack ();
+      do_cleanups (cleanups);
+
+      return 0;
+    }
+  make_cleanup_py_decref (match_result);
+
+  match = PyObject_IsTrue (match_result);
+  if (match == -1)
+    {
+      gdbpy_print_stack ();
+      do_cleanups (cleanups);
+
+      return 0;
+    }
+
+  do_cleanups (cleanups);
+
+  return match;
+}
+
+/* Implementation of get_matching_ext_methods_ftype.
+   Return a of vector methods with name METHOD_NAME defined in Python for
+   objects of type OBJ_TYPE.  Returns NULL if no matches are found.  */
+
+static VEC (ext_fn_descriptor_p) *
+py_debugmethod_name_match (struct type *obj_type, const char *method_name)
+{
+  struct cleanup *cleanups;
+  struct objfile *objfile;
+  VEC (ext_fn_descriptor_p) *method_vec = NULL;
+  PyObject *py_type, *py_progspace;
+  PyObject *py_debugmethod_list = NULL, *list_iter, *item;
+
+  if (obj_type == NULL || method_name == NULL)
+    return method_vec;
+
+  py_type = type_to_type_object (obj_type);
+  if (py_type == NULL)
+    return method_vec;
+  make_cleanup_py_decref (py_type);
+
+  /* Create an empyt list of debug methods.  */
+  py_debugmethod_list = PyList_New (0);
+  if (py_debugmethod_list == NULL)
+    return NULL;
+
+  cleanups = ensure_python_env (get_current_arch (), current_language);
+
+  /* Gather debug methods registered with the object files.  */
+  ALL_OBJFILES (objfile)
+    {
+      PyObject *py_objfile = objfile_to_objfile_object (objfile);
+      PyObject *objfile_dmlist, *temp;
+
+      if (py_objfile == NULL)
+        {
+          gdbpy_print_stack ();
+          continue;
+        }
+
+      objfile_dmlist = objfpy_get_debug_methods (py_objfile, NULL);
+      temp = py_debugmethod_list;
+      py_debugmethod_list = PySequence_Concat (temp, objfile_dmlist);
+      if (py_debugmethod_list == NULL)
+        py_debugmethod_list = temp;
+      else
+        Py_DECREF (temp);
+      Py_XDECREF (objfile_dmlist);
+    }
+
+  /* Gather debug methods registered with the current program space.  */
+  py_progspace = pspace_to_pspace_object (current_program_space);
+  if (py_progspace != NULL)
+    {
+      PyObject *temp = py_debugmethod_list;
+      PyObject *pspace_dmlist = pspy_get_debug_methods (py_progspace, NULL);
+
+      py_debugmethod_list = PySequence_Concat (temp, pspace_dmlist);
+      if (py_debugmethod_list == NULL)
+        py_debugmethod_list = temp;
+      else
+        Py_DECREF (temp);
+      Py_XDECREF (pspace_dmlist);
+    }
+
+  /* Gather debug methods registered globally.  */
+  if (gdb_python_module != NULL
+      && PyObject_HasAttrString (gdb_python_module, "debug_methods"))
+    {
+      PyObject *gdb_dmlist;
+      PyObject *temp = py_debugmethod_list;
+
+      gdb_dmlist = PyObject_GetAttrString (gdb_python_module, "debug_methods");
+      if (gdb_dmlist != NULL && PyList_Check (gdb_dmlist))
+        {
+          py_debugmethod_list = PySequence_Concat (temp, gdb_dmlist);
+          if (py_debugmethod_list == NULL)
+            py_debugmethod_list = temp;
+          else
+            Py_DECREF (temp);
+          Py_XDECREF (gdb_dmlist);
+        }
+    }
+
+  list_iter = PyObject_GetIter (py_debugmethod_list);
+  if (list_iter == NULL)
+    {
+      gdbpy_print_stack ();
+      Py_DECREF (py_debugmethod_list);
+      do_cleanups (cleanups);
+      return NULL;
+    }
+
+  while ((item = PyIter_Next (list_iter)))
+    {
+      if (is_matching_debug_method (item, py_type, method_name))
+        {
+          struct ext_fn_descriptor *ext_fn;
+
+          ext_fn = new_python_ext_method (item, py_type, method_name);
+          VEC_safe_push (ext_fn_descriptor_p, method_vec, ext_fn);
+        }
+      Py_DECREF (item);
+    }
+  Py_DECREF (list_iter);
+  /* Report any error that could have occurred while iterating.  */
+  if (PyErr_Occurred ())
+    gdbpy_print_stack ();
+
+  Py_DECREF (py_debugmethod_list);
+  do_cleanups (cleanups);
+
+  return method_vec;
+}
+
+/* Implementation of get_ext_fn_argtypes_ftype.
+   Return an arry of argument types for extension encapsulated in EXT_OBJ.
+   NARGS contains the length of the array.  */
+
+static struct type **
+py_ext_fn_get_argtypes (void *ext_obj, int *nargs)
+{
+  struct py_ext_object *ext_object = (struct py_ext_object *) ext_obj;
+  PyObject *debug_method_obj = ext_object->object;
+  PyObject *get_argtypes_method;
+  PyObject *py_argtype_list, *list_iter, *item, *method_name_pystring;
+  struct cleanup *cleanups;
+  struct type **type_array, *obj_type;
+  int i = 1;
+
+  /* Set nargs to 0 so that any premature return from this function returns
+     0 arg types.  */
+  *nargs = 0;
+
+  cleanups = ensure_python_env (get_current_arch (), current_language);
+
+  get_argtypes_method =  PyObject_GetAttrString (debug_method_obj,
+                                                 get_argtypes_method_name);
+  if (get_argtypes_method == NULL)
+    {
+      gdbpy_print_stack ();
+      do_cleanups (cleanups);
+
+      return NULL;
+    }
+  make_cleanup_py_decref (get_argtypes_method);
+
+  method_name_pystring = PyString_FromString (ext_object->match_method);
+  if (method_name_pystring == NULL)
+    {
+      gdbpy_print_stack ();
+      do_cleanups (cleanups);
+
+      return 0;
+    }
+  make_cleanup_py_decref (method_name_pystring);
+
+  if (!PyCallable_Check (get_argtypes_method))
+    {
+      warning (_("Attribute '%s' of a registered Python debug method is not "
+                 "callable.  Ignored!"), get_argtypes_method_name);
+      do_cleanups (cleanups);
+
+      return NULL;
+    }
+
+  py_argtype_list = PyObject_CallMethodObjArgs (debug_method_obj,
+                                                get_argtypes_method_pystring,
+                                                ext_object->match_py_obj_type,
+                                                method_name_pystring,
+                                                NULL);
+  if (py_argtype_list == NULL)
+    {
+      gdbpy_print_stack ();
+      do_cleanups (cleanups);
+
+      return NULL;
+    }
+  make_cleanup_py_decref (py_argtype_list);
+
+  list_iter = PyObject_GetIter (py_argtype_list);
+  if (list_iter == NULL)
+    {
+      gdbpy_print_stack ();
+      do_cleanups (cleanups);
+
+      return NULL;
+    }
+  make_cleanup_py_decref (list_iter);
+
+  /* Include the 'this' argument in the size.  */
+  type_array = XCNEWVEC (struct type *, PyList_GET_SIZE (py_argtype_list) + 1);
+  while ((item = PyIter_Next (list_iter)))
+    {
+      struct type *arg_type = type_object_to_type (item);
+
+      Py_DECREF (item);
+
+      if (arg_type == NULL)
+        {
+          i = -1;
+          break;
+        }
+
+      type_array[i] = arg_type;
+      i++;
+    }
+  if (PyErr_Occurred () || i == -1)
+    {
+      gdbpy_print_stack ();
+      do_cleanups (cleanups);
+      xfree (type_array);
+
+      return NULL;
+    }
+
+  /* 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);
+  *nargs = i;
+
+  do_cleanups (cleanups);
+
+  return type_array;
+}
+
+/* Implementation of invoke_method_ftype.
+   Invokes a method defined in Python.  The value returned by the method is
+   returned.  NULL is returned in case of errors.  */
+
+static struct value *
+py_ext_fn_invoke_method (void *ext_obj, struct value *obj, struct value **args,
+                         int nargs)
+{
+  int i;
+  struct cleanup *cleanups;
+  PyObject *py_value_obj, *py_arg_tuple, *py_result, *debug_method_obj;
+  PyObject *invoke_method, *method_name_pystring;
+  struct value *result = NULL;
+  struct py_ext_object *py_ext_obj = ext_obj;
+
+  cleanups = ensure_python_env (get_current_arch (), current_language);
+
+  debug_method_obj = py_ext_obj->object;
+
+  invoke_method =  PyObject_GetAttrString (debug_method_obj,
+                                           invoke_method_name);
+  if (invoke_method == NULL)
+    {
+      gdbpy_print_stack ();
+      do_cleanups (cleanups);
+
+      return NULL;
+    }
+  make_cleanup_py_decref (invoke_method);
+
+  method_name_pystring = PyString_FromString (py_ext_obj->match_method);
+  if (method_name_pystring == NULL)
+    {
+      gdbpy_print_stack ();
+      do_cleanups (cleanups);
+
+      return 0;
+    }
+  make_cleanup_py_decref (method_name_pystring);
+
+  if (!PyCallable_Check (invoke_method))
+    {
+      warning (_("Attribute '%s' of a registered Python debug method is not "
+                 "callable.  Ignored!"), invoke_method_name);
+      do_cleanups (cleanups);
+
+      return NULL;
+    }
+
+  py_value_obj = value_to_value_object (obj);
+  if (py_value_obj == NULL)
+    {
+      do_cleanups (cleanups);
+      return NULL;
+    }
+  make_cleanup_py_decref (py_value_obj);
+
+  py_arg_tuple = PyTuple_New (nargs);
+  if (py_arg_tuple == NULL)
+    {
+      gdbpy_print_stack ();
+      do_cleanups (cleanups);
+
+      return NULL;
+    }
+  make_cleanup_py_decref (py_arg_tuple);
+
+  for (i = 0; i < nargs; i++)
+    {
+      PyObject *py_value_arg = value_to_value_object (args[i]);
+
+      if (py_value_arg == NULL)
+        {
+          gdbpy_print_stack ();
+          do_cleanups (cleanups);
+          return NULL;
+        }
+
+      if (PyTuple_SetItem (py_arg_tuple, i, py_value_arg))
+        {
+          gdbpy_print_stack ();
+          do_cleanups (cleanups);
+
+          return NULL;
+        }
+    }
+
+  py_result = PyObject_CallMethodObjArgs (debug_method_obj,
+                                          invoke_method_pystring,
+                                          py_value_obj, 
+                                          method_name_pystring,
+                                          py_arg_tuple, NULL);
+  if (py_result == NULL)
+    {
+      gdbpy_print_stack (); 
+      do_cleanups (cleanups);
+
+      return NULL;
+    }
+  make_cleanup_py_decref (py_result);
+
+  /* Check that a debug method did not return None.  */
+  if (py_result != Py_None)
+    {
+      result = convert_value_from_python (py_result);
+      if (result == NULL)
+        {
+          gdbpy_print_stack ();
+        }
+    }
+  else
+    result = allocate_value (lookup_typename (python_language, python_gdbarch,
+                                              "void", NULL, 0));
+
+  do_cleanups (cleanups);
+
+  return result;
+}
+
+static struct ext_func_ops python_ext_lang = {
+  py_clone_ext_object,
+  py_free_ext_object,
+  py_debugmethod_name_match,
+  py_ext_fn_get_argtypes,
+  py_ext_fn_invoke_method
+};
+
+/* Creates a new python ext_function_descriptor.  DEBUG_METHOD is the
+   debug method object.  PY_OBJ_TYPE is a gdb.Type value corresponding to the
+   type of the object on which the debug method with name METHOD will be
+   invoked.  */
+
+static struct ext_fn_descriptor *
+new_python_ext_method (PyObject *debug_method, PyObject *py_obj_type,
+                       const char *method)
+{
+  struct py_ext_object *ext_object;
+
+  ext_object = XCNEW (struct py_ext_object);
+  ext_object->object = debug_method;
+  ext_object->match_py_obj_type = py_obj_type;
+  ext_object->match_method = method;
+
+  Py_XINCREF (ext_object->object);
+  Py_XINCREF (ext_object->match_py_obj_type);
+
+  return new_ext_function (&python_ext_lang, 1, ext_object);
+}
+
+/* Initializes the Python debug method support.  */
+
+int
+gdbpy_initialize_debugmethods (void)
+{
+  register_ext_lang (&python_ext_lang);
+
+  match_method_pystring = PyString_FromString (match_method_name);
+  if (match_method_pystring == NULL)
+    return -1;
+
+  invoke_method_pystring = PyString_FromString (invoke_method_name);
+  if (invoke_method_pystring == NULL)
+    return -1;
+
+  get_argtypes_method_pystring = PyString_FromString (get_argtypes_method_name);
+  if (get_argtypes_method_pystring == NULL)
+    return -1;
+
+  return 1;
+}
+
+#endif /* HAVE_PYTHON */
diff --git a/gdb/python/py-objfile.c b/gdb/python/py-objfile.c
index 9bbd4c2..4aa0a1a 100644
--- a/gdb/python/py-objfile.c
+++ b/gdb/python/py-objfile.c
@@ -37,6 +37,9 @@ typedef struct
   PyObject *frame_filters;
   /* The type-printer list.  */
   PyObject *type_printers;
+
+  /* The debug method list.  */
+  PyObject *debug_methods;
 } objfile_object;
 
 static PyTypeObject objfile_object_type
@@ -67,6 +70,7 @@ objfpy_dealloc (PyObject *o)
   Py_XDECREF (self->printers);
   Py_XDECREF (self->frame_filters);
   Py_XDECREF (self->type_printers);
+  Py_XDECREF (self->debug_methods);
   Py_TYPE (self)->tp_free (self);
 }
 
@@ -99,6 +103,13 @@ objfpy_new (PyTypeObject *type, PyObject *args, PyObject *keywords)
 	  Py_DECREF (self);
 	  return NULL;
 	}
+
+      self->debug_methods = PyList_New (0);
+      if (self->debug_methods == NULL)
+	{
+	  Py_DECREF (self);
+	  return NULL;
+	}
     }
   return (PyObject *) self;
 }
@@ -193,6 +204,17 @@ objfpy_get_type_printers (PyObject *o, void *ignore)
   return self->type_printers;
 }
 
+/* Get the 'debug_methods' attribute.  */
+
+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
@@ -292,6 +314,13 @@ objfile_to_objfile_object (struct objfile *objfile)
 	      return NULL;
 	    }
 
+	  object->debug_methods = PyList_New (0);
+	  if (object->debug_methods == NULL)
+	    {
+	      Py_DECREF (object);
+	      return NULL;
+	    }
+
 	  set_objfile_data (objfile, objfpy_objfile_data_key, object);
 	}
     }
@@ -333,6 +362,8 @@ static PyGetSetDef objfile_getset[] =
     objfpy_set_frame_filters, "Frame Filters.", 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/py-progspace.c b/gdb/python/py-progspace.c
index 910c6a3..d425159 100644
--- a/gdb/python/py-progspace.c
+++ b/gdb/python/py-progspace.c
@@ -39,6 +39,9 @@ typedef struct
   PyObject *frame_filters;
   /* The type-printer list.  */
   PyObject *type_printers;
+
+  /* The debug method list.  */
+  PyObject *debug_methods;
 } pspace_object;
 
 static PyTypeObject pspace_object_type
@@ -75,6 +78,7 @@ pspy_dealloc (PyObject *self)
   Py_XDECREF (ps_self->printers);
   Py_XDECREF (ps_self->frame_filters);
   Py_XDECREF (ps_self->type_printers);
+  Py_XDECREF (ps_self->debug_methods);
   Py_TYPE (self)->tp_free (self);
 }
 
@@ -107,6 +111,13 @@ pspy_new (PyTypeObject *type, PyObject *args, PyObject *keywords)
 	  Py_DECREF (self);
 	  return NULL;
 	}
+
+      self->debug_methods = PyList_New (0);
+      if (self->debug_methods == NULL)
+	{
+	  Py_DECREF (self);
+	  return NULL;
+	}
     }
   return (PyObject *) self;
 }
@@ -201,6 +212,17 @@ pspy_get_type_printers (PyObject *o, void *ignore)
   return self->type_printers;
 }
 
+/* Get the 'debug_methods' attribute.  */
+
+PyObject *
+pspy_get_debug_methods (PyObject *o, void *ignore)
+{
+  pspace_object *self = (pspace_object *) o;
+
+  Py_INCREF (self->debug_methods);
+  return self->debug_methods;
+}
+
 /* Set the 'type_printers' attribute.  */
 
 static int
@@ -288,6 +310,13 @@ pspace_to_pspace_object (struct program_space *pspace)
 	      return NULL;
 	    }
 
+	  object->debug_methods = PyList_New (0);
+	  if (object->debug_methods == NULL)
+	    {
+	      Py_DECREF (object);
+	      return NULL;
+	    }
+
 	  set_program_space_data (pspace, pspy_pspace_data_key, object);
 	}
     }
@@ -320,6 +349,8 @@ static PyGetSetDef pspace_getset[] =
     "Frame filters.", NULL },
   { "type_printers", pspy_get_type_printers, pspy_set_type_printers,
     "Type printers.", NULL },
+  { "debug_methods", pspy_get_debug_methods, NULL,
+    "Debug methods.", NULL },
   { NULL }
 };
 
diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
index 7d8c4ad..62eb49b 100644
--- a/gdb/python/python-internal.h
+++ b/gdb/python/python-internal.h
@@ -316,11 +316,13 @@ PyObject *pspace_to_pspace_object (struct program_space *)
     CPYCHECKER_RETURNS_BORROWED_REF;
 PyObject *pspy_get_printers (PyObject *, void *);
 PyObject *pspy_get_frame_filters (PyObject *, void *);
+PyObject *pspy_get_debug_methods (PyObject *, void *);
 
 PyObject *objfile_to_objfile_object (struct objfile *)
     CPYCHECKER_RETURNS_BORROWED_REF;
 PyObject *objfpy_get_printers (PyObject *, void *);
 PyObject *objfpy_get_frame_filters (PyObject *, void *);
+PyObject *objfpy_get_debug_methods (PyObject *, void *);
 
 PyObject *gdbarch_to_arch_object (struct gdbarch *gdbarch);
 
@@ -401,6 +403,8 @@ int gdbpy_initialize_new_objfile_event (void)
   CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
 int gdbpy_initialize_arch (void)
   CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
+int gdbpy_initialize_debugmethods (void)
+  CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
 
 struct cleanup *make_cleanup_py_decref (PyObject *py);
 struct cleanup *make_cleanup_py_xdecref (PyObject *py);
diff --git a/gdb/python/python.c b/gdb/python/python.c
index 7cdf8a7..f5a0132 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -1687,7 +1687,8 @@ message == an error message without a stack will be printed."),
       || gdbpy_initialize_exited_event () < 0
       || gdbpy_initialize_thread_event () < 0
       || gdbpy_initialize_new_objfile_event ()  < 0
-      || gdbpy_initialize_arch () < 0)
+      || gdbpy_initialize_arch () < 0
+      || gdbpy_initialize_debugmethods () < 0)
     goto fail;
 
   observer_attach_before_prompt (before_prompt_hook);
diff --git a/gdb/testsuite/gdb.python/py-debugmethods.cc b/gdb/testsuite/gdb.python/py-debugmethods.cc
new file mode 100644
index 0000000..f292a62
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-debugmethods.cc
@@ -0,0 +1,173 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 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/>.  */
+
+#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 CC <A_plus_A>:" << endl;
+  return a + obj.a;
+}
+
+int A::operator- (const A &obj)
+{
+  cout << "From CC <A_minus_A>:" << endl;
+  return a - obj.a;
+}
+
+int A::geta (void)
+{
+  cout << "From CC geta:" << endl;
+  return a;
+}
+
+class B : public A
+{
+ public:
+  virtual int operator* (const B &obj);
+};
+
+int
+B::operator* (const B &obj)
+{
+  cout << "From CC <B_star_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 CC <D_star_D>:" << endl;
+  return a * obj.a;
+}
+
+template <typename T>
+class G
+{
+ public:
+  template <typename T1>
+  int size_diff ();
+
+  template <int M>
+  int size_mul ();
+
+  template <typename T1>
+  T mul(const T1 t1);
+
+ public:
+  T t;
+};
+
+template <typename T>
+template <typename T1>
+int
+G<T>::size_diff ()
+{
+  cout << "From CC G<>::size_diff:" << endl;
+  return sizeof (T1) - sizeof (T);
+}
+
+template <typename T>
+template <int M>
+int
+G<T>::size_mul ()
+{
+  cout << "From CC G<>::size_mul:" << endl;
+  return M * sizeof (T);
+}
+
+template <typename T>
+template <typename T1>
+T
+G<T>::mul (const T1 t1)
+{
+  cout << "From CC G<>::mul:" << endl;
+  return t1 * t;
+}
+
+}
+
+using namespace dop;
+
+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;
+  G<int> g;
+  g.t = 5;
+
+  int diff = g.size_diff<float> ();
+  int smul = g.size_mul<2> ();
+  int mul = g.mul (1.0);
+
+  for (int i = 0; i < 10; i++)
+    {
+      a1.array[i] = a2.array[i] = i;
+    }
+
+  return 0; /* Break here.  */ 
+}
diff --git a/gdb/testsuite/gdb.python/py-debugmethods.exp b/gdb/testsuite/gdb.python/py-debugmethods.exp
new file mode 100644
index 0000000..802fdba
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-debugmethods.exp
@@ -0,0 +1,112 @@
+# Copyright 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/>.
+
+# This file is part of the GDB testsuite.  It tests the debug methods
+# feature in the Python extension language.
+
+load_lib gdb-python.exp
+
+if { [skip_cplus_tests] } { continue }
+
+standard_testfile py-debugmethods.cc
+
+if {[prepare_for_testing $testfile.exp $testfile $srcfile {debug c++}]} {
+    return -1
+}
+
+# Skip all tests if Python scripting is not enabled.
+if { [skip_python_tests] } { continue }
+
+if ![runto_main] {
+   return -1
+}
+
+set debug_methods_script "${srcdir}/${subdir}/${testfile}.py"
+
+gdb_breakpoint [gdb_get_line_number "Break here."]
+gdb_continue_to_breakpoint "Break here" ".*Break here.*"
+
+# Tests before loading the debug methods.
+gdb_test "p a1 + a2" "From CC <A_plus_A>.*15" "Before: a1 + a2"
+gdb_test "p a2 - a1" "From CC <A_minus_A>.*5" "Before: a1 - a2"
+gdb_test "p b1 - a1" "From CC <A_minus_A>.*25" "Before: b1 - a1"
+gdb_test "p c1 - a1" "From CC <A_minus_A>.*15" "Before: c1 - a1"
+gdb_test "p c1 - c1" "From CC <A_minus_A>.*0" "Before: c1 - c1"
+gdb_test "p a1.geta()" "From CC geta.*5" "Before: a1.geta()"
+gdb_test "p ref_c - a1" "From CC <A_minus_A>.*15" "Before: ref_c - a1"
+gdb_test "p ref_c - c1" "From CC <A_minus_A>.*0" "Before: ref_c - c1"
+gdb_test "p b1 * b1" "From CC <B_star_B>.*900" "Before: b1 * b1"
+gdb_test "p ref_c * b1" "No symbol.*" "Before: ref_c * b1"
+gdb_test "p ref_d * b1" "From CC <D_star_D>.*1500" "Before: ref_d * b1"
+gdb_test "p bt * c1" "From CC <B_star_B>.*800" "Before: bt * c1"
+gdb_test "p ++a1" "No symbol.*" "Before: ++a1"
+gdb_test "p a1.getarrayind(5)" "Couldn't find method.*" \
+  "Before: a1.getarrayind(5)"
+gdb_test "p g.size_diff<float>()" "From CC G<>::size_diff.*" \
+  "Before: g.size_diff<float>()"
+gdb_test "p g.size_diff<unsigned long>()" "Couldn't find method.*" \
+  "Before: g.size_diff<unsigned long>()"
+gdb_test "p g.size_mul<2>()" "From CC G<>::size_mul.*" \
+  "Before: g.size_mul<2>()"
+gdb_test "p g.size_mul<5>()" "Couldn't find method.*" \
+  "Before: g.size_mul<5>()"
+gdb_test "p g.mul<double>(2.0)" "From CC G<>::mul.*" \
+  "Before: g.mul<double>(2.0)"
+gdb_test "p g.mul<char>('a')" "Couldn't find method.*" \
+  "Before: g.mul<char>('a')"
+
+# Load the script which adds the debug methods.
+gdb_test_no_output "source ${debug_methods_script}" "load the script file"
+
+# Tests after loading debug methods.
+gdb_test "p a1 + a2" "From Python <A_plus_A>.*15" "After: a1 + a2"
+gdb_test "p a2 - a1" "From CC <A_minus_A>.*5" "After: a1 - a2"
+gdb_test "p b1 - a1" "From CC <A_minus_A>.*25" "After: b1 - a2"
+gdb_test "p c1 - a1" "From CC <A_minus_A>.*15" "After: c1 - a1"
+gdb_test "p c1 - c1" "From Python <C_minus_C>.*0" "After: c1 - c1"
+gdb_test "p a1.geta()" "From Python <A_geta>.*5" "After: a1.geta()"
+gdb_test "p ref_c - a1" "From CC <A_minus_A>.*15" "After: ref_c - a1"
+gdb_test "p ref_c - c1" "From Python <C_minus_C>.*0" "After: ref_c - c1"
+gdb_test "p b1 * b1" "From Python <B_star_B>.*900" "After: b1 * b1"
+gdb_test "p ref_c * b1" "No symbol.*" "After: ref_c * b1 failure"
+gdb_test "p ref_d * b1" "From CC <D_star_D>.*1500" "After: ref_d * b1"
+gdb_test "p bt * c1" "From Python <B_star_B>.*800" "After: bt * c1"
+gdb_test "p ++a1" "From Python <plus_plus_A>.*6" "After: ++a1"
+gdb_test "p a1.getarrayind(5)" "From Python <A_getarrayind>.*5" \
+  "After: a1.getarrayind(5)"
+gdb_test "p g.size_diff<float>  ()" "From Python G<>::size_diff.*" \
+  "After: g.size_diff<float>()"
+gdb_test "p g.size_diff<  unsigned long  >()" "From Python G<>::size_diff.*" \
+  "After: g.size_diff<unsigned long>()"
+gdb_test "p g.size_mul<2>()" "From Python G<>::size_mul.*" \
+  "After: g.size_mul<2>()"
+gdb_test "p g.size_mul<  5  >()" "From Python G<>::size_mul.*" \
+  "After: g.size_mul<  5  >()"
+gdb_test "p g.mul<double>(2.0)" "From Python G<>::mul.*" \
+  "After: g.mul<double>(2.0)"
+gdb_test "p g.mul<char>('a')" "From Python G<>::mul.*" \
+  "After: g.mul<char>('a')"
+
+# Tests for 'disable/enable debug-method' command.
+gdb_test_no_output "disable debug-method .*debugmethods G_mul" "Disable G_mul"
+gdb_test "p g.mul<char>('a')" "Couldn't find method.*" \
+  "After disabling g.mul<char>('a')"
+gdb_test_no_output "enable debug-method .*debugmethods G_mul" "Enable G_mul"
+gdb_test "p g.mul<char>('a')" "From Python G<>::mul.*" \
+  "After enabling g.mul<char>('a')"
+
+# Test for 'info debug-methods' command
+gdb_test "info debug-method global plus" "global.*plus_plus_A - enabled" \
+  "info debug-method global plus"
diff --git a/gdb/testsuite/gdb.python/py-debugmethods.py b/gdb/testsuite/gdb.python/py-debugmethods.py
new file mode 100644
index 0000000..8147611
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-debugmethods.py
@@ -0,0 +1,180 @@
+# Copyright 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/>.
+
+# This file is part of the GDB testsuite.  It implements debug methods
+# in the Python extension language.
+
+import gdb
+import re
+
+from gdb.debugmethods import DebugMethod, SimpleDebugMethod
+
+def A_plus_A(obj, opr):
+  print 'From Python <A_plus_A>:'
+  return obj['a'] + opr['a']
+
+def plus_plus_A(obj):
+  print 'From Python <plus_plus_A>:'
+  return obj['a'] + 1
+
+def 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_getarrayind(obj, index):
+  print 'From Python <A_getarrayind>:'
+  return obj['array'][index]
+
+
+type_A = gdb.parse_and_eval('(dop::A *) 0').type.target()
+type_B = gdb.parse_and_eval('(dop::B *) 0').type.target()
+type_C = gdb.parse_and_eval('(dop::C *) 0').type.target()
+type_int = gdb.parse_and_eval('(int *) 0').type.target()
+
+
+class G_size_diff(DebugMethod):
+    def __init__(self):
+        DebugMethod.__init__(self, 'G_size_diff')
+
+    def match(self, class_type, method_name):
+        if not re.match('^dop::G<[ ]*[_a-zA-Z][ _a-zA-Z0-9]*>$',
+                        class_type.unqualified().tag):
+            return False
+        if not re.match('^size_diff<[ ]*[_a-zA-Z][ _a-zA-Z0-9]*>$',
+                        method_name):
+            return False
+        return True
+
+    def get_argtypes(self, class_type, method_name):
+        return []
+
+    def invoke(self, obj, method_name, args):
+        t1_search = re.search('<[ ]*[_a-zA-Z][ _a-zA-Z0-9]*>', method_name)
+        if not t1_search:
+            raise gdb.GdbError(
+                'Unable to find template argument from %s.' % method_name)
+        t1_name = t1_search.group(0)[1:-1]
+        try:
+            t1_type = gdb.lookup_type(t1_name)
+        except Exception:
+            raise gdb.GdbError('Unknown template type %s.' % t1_name)
+        print 'From Python G<>::size_diff<%s>' % t1_name
+        return t1_type.sizeof - obj['t'].type.sizeof
+        
+
+class G_size_mul(DebugMethod):
+    def __init__(self):
+        DebugMethod.__init__(self, 'G_size_mull')
+
+    def match(self, class_type, method_name):
+        if not re.match('^dop::G<[ ]*[_a-zA-Z][ _a-zA-Z0-9]*>$',
+                        class_type.unqualified().tag):
+            return False
+        if not re.match('^size_mul<[ ]*[0-9]+[ ]*>$',
+                        method_name):
+            return False
+        return True
+
+    def get_argtypes(self, class_type, method_name):
+        return []
+
+    def invoke(self, obj, method_name, args):
+        m_search = re.search('<[ ]*[0-9]+[ ]*>', method_name)
+        if not m_search:
+            raise gdb.GdbError(
+                'Unable to find template argument from %s.' % method_name)
+        m_val = int(m_search.group(0)[1:-1])
+        print 'From Python G<>::size_mul<%d>' % m_val
+        return m_val * obj['t'].type.sizeof
+        
+
+class G_mul(DebugMethod):
+    def __init__(self):
+        DebugMethod.__init__(self, 'G_mul')
+
+    def match(self, class_type, method_name):
+        if not re.match('^dop::G<[ ]*[_a-zA-Z][ _a-zA-Z0-9]*>$',
+                        class_type.unqualified().tag):
+            return False
+        if not re.match('^mul<[ ]*[_a-zA-Z][ _a-zA-Z0-9]*>$',
+                        method_name):
+            return False
+        return True
+
+    def get_argtypes(self, class_type, method_name):
+        t1_search = re.search('<[ ]*[_a-zA-Z][ _a-zA-Z0-9]*>', method_name)
+        if not t1_search:
+            raise gdb.GdbError(
+                'Unable to find template argument from %s.' % method_name)
+        t1_name = t1_search.group(0)[1:-1]
+        try:
+            t1_type = gdb.lookup_type(t1_name)
+        except Exception:
+            raise gdb.GdbError('Unknown template type %s.' % t1_name)
+        return [t1_type]
+
+    def invoke(self, obj, method_name, args):
+        print 'From Python G<>::mul<%s>' % args[0].type
+        return args[0] * obj['t']
+        
+
+global_dm_list = [
+    SimpleDebugMethod('A_plus_A',
+                      A_plus_A,
+                      '^dop::A$',
+                      'operator\+',
+                      # This is a replacement, hence match the arg type
+                      # exactly!
+                      type_A.const().reference()),
+    SimpleDebugMethod('plus_plus_A',
+                      plus_plus_A,
+                      '^dop::A$',
+                      'operator\+\+'),
+    SimpleDebugMethod('C_minus_C',
+                      C_minus_C,
+                      '^dop::C$',
+                      'operator\-',
+                      type_C),
+    SimpleDebugMethod('B_star_B',
+                      B_star_B,
+                      '^dop::B$',
+                      'operator\*',
+                      # This is a replacement, hence match the arg type
+                      # exactly!
+                      type_B.const().reference()),
+    SimpleDebugMethod('A_geta',
+                      A_geta,
+                      '^dop::A$',
+                      '^geta$'),
+    SimpleDebugMethod('A_getarrayind',
+                      A_getarrayind,
+                      '^dop::A$',
+                      '^getarrayind$',
+                      type_int),
+]
+
+pspace_dm_list = [G_size_diff(), G_size_mul(), G_mul()]
+
+gdb.debugmethods.register_debug_methods(gdb, global_dm_list)
+gdb.debugmethods.register_debug_methods(gdb.current_progspace(),
+                                        pspace_dm_list)
diff --git a/gdb/valarith.c b/gdb/valarith.c
index 49c8bdc..e486b24 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 */,
                        &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,29 @@ 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 (ext_fn))
+        {
+          struct value *ret_val = ext_fn_invoke_method (ext_fn, arg1, &arg2, 1);
+
+          if (ret_val == NULL)
+              error (_("Error invoking debug method implementation for "
+                       "method %s"), tstr);
+
+          xfree (ext_fn);
+
+          return ret_val;
+        }
+      else
+        {
+          /* This else should not be taken as only debug methods
+             are supported currently.  */
+          internal_error (__FILE__, __LINE__,
+                          _("Invoking an extension language "
+                            "function (not a method)."));
+        }
+    }
   throw_error (NOT_FOUND_ERROR,
                _("member function %s not found"), tstr);
 #ifdef lint
@@ -510,6 +552,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;
   char tstr[13], mangle_tstr[13];
   int static_memfuncp, nargs;
@@ -523,6 +566,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;
 
@@ -574,8 +618,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])
     {
@@ -594,6 +638,29 @@ 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 (ext_fn))
+        {
+          struct value *ret_val = ext_fn_invoke_method (ext_fn, arg1, NULL, 0);
+
+          if (ret_val == NULL)
+              error (_("Error invoking debug method implementation for "
+                       "method %s"), tstr);
+
+          xfree (ext_fn);
+
+          return ret_val;
+        }
+      else
+        {
+          /* This else should not be taken as only debug methods
+             are supported currently.  */
+          internal_error (__FILE__, __LINE__,
+                          _("Invoking an extension language "
+                            "function (not a method)."));
+        }
     }
   throw_error (NOT_FOUND_ERROR,
                _("member function %s not found"), tstr);
diff --git a/gdb/valops.c b/gdb/valops.c
index 4fc57ec..9dbf333 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -44,6 +44,7 @@
 #include "objfiles.h"
 #include "symtab.h"
 #include "exceptions.h"
+#include "ext-function.h"
 
 extern unsigned int overload_debug;
 /* Local functions.  */
@@ -72,8 +73,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 *, VEC (ext_fn_descriptor_p) *,
+                             struct symbol **, struct badness_vector **);
 
 static int oload_method_static (int, struct fn_field *, int);
 
@@ -100,9 +101,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 *,
+                              VEC (ext_fn_descriptor_p) **,
+                              struct type **, int *);
 
 void _initialize_valops (void);
 
@@ -2261,40 +2263,58 @@ 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,
+                  VEC (ext_fn_descriptor_p) **ext_fn_vec,
 		  struct type **basetype, int *boffset)
 {
   int i;
-  struct fn_field *f;
-  CHECK_TYPEDEF (type);
+  struct fn_field *f = 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);
+  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;
+  	}
+      }
 
-	  *num_fns = len;
-	  *basetype = type;
-	  *boffset = offset;
+  if (ext_fn_vec)
+    {
+      VEC (ext_fn_descriptor_p) *ef_vec = NULL, *new_vec = NULL;
 
-	  /* Resolve any stub methods.  */
-	  check_stub_method_group (type, i);
+      ef_vec = get_matching_ext_methods (type, method);
+      new_vec = VEC_merge (ext_fn_descriptor_p, *ext_fn_vec, ef_vec);
 
-	  return f;
-	}
+      VEC_free (ext_fn_descriptor_p, *ext_fn_vec);
+      VEC_free (ext_fn_descriptor_p, ef_vec);
+      *ext_fn_vec = new_vec;
     }
 
-  /* 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;
@@ -2311,13 +2331,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_vec, basetype, boffset);
     }
-  return NULL;
 }
 
 /* Return the list of overloaded methods of a specified name.
@@ -2330,9 +2348,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,
+                              VEC (ext_fn_descriptor_p) **ext_fn_vec,
 			      struct type **basetype, int *boffset)
 {
   struct type *t;
@@ -2354,8 +2374,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_vec)
+    *ext_fn_vec = VEC_alloc (ext_fn_descriptor_p, 1);
+
+  find_method_list (argp, method, 0, t, fn_list, num_fns, ext_fn_vec,
+                    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
@@ -2403,6 +2447,7 @@ find_overload_match (struct value **args, int nargs,
 		     const char *name, enum oload_search_type method,
 		     struct value **objp, struct symbol *fsym,
 		     struct value **valp, struct symbol **symp, 
+                     struct ext_fn_descriptor **ext_fn,
 		     int *staticp, const int no_adl)
 {
   struct value *obj = (objp ? *objp : NULL);
@@ -2410,16 +2455,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 VEC of extension function descriptors.  */
+  VEC (ext_fn_descriptor_p) *ext_fn_vec = NULL;
   /* Number of overloaded instances being considered.  */
   int num_fns = 0;
   struct type *basetype = NULL;
@@ -2431,6 +2484,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.  */
@@ -2459,12 +2514,12 @@ 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_vec : 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_vec)
 	error (_("Couldn't find method %s%s%s"),
 	       obj_type_name,
 	       (obj_type_name && *obj_type_name) ? "::" : "",
@@ -2475,18 +2530,82 @@ 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 && VEC_length (ext_fn_descriptor_p, ext_fn_vec))
+        {
+          ext_method_oload_champ = find_oload_champ (args, nargs, method,
+                                                     0, NULL, ext_fn_vec,
+                                                     NULL, &ext_method_badness);
+          ext_method_match_quality = classify_oload_match (ext_method_badness,
+                                                           nargs, 0);
+          make_cleanup (xfree, ext_method_badness);
+          make_ext_fn_vec_cleanup (ext_fn_vec);
+        }
+
+      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)
@@ -2629,21 +2748,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));
@@ -2653,11 +2757,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,
+                                              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,
+                                              objp, fsym, valp, symp, ext_fn,
+		                              staticp, no_adl);
+                }
+            }
+
+          *ext_fn = ext_fn_clone (VEC_index (ext_fn_descriptor_p, ext_fn_vec,
+                                             ext_method_oload_champ));
+        }
+    }
+  else
+    *symp = oload_syms[func_oload_champ];
+
   do_cleanups (all_cleanups);
 
   switch (match_quality)
@@ -2791,7 +2950,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),
@@ -2839,10 +2998,12 @@ 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,
+                  VEC (ext_fn_descriptor_p) *ext_fn_vec,
 		  struct symbol **oload_syms,
 		  struct badness_vector **oload_champ_bv)
 {
   int ix;
+  int ext_fn_vec_n = 0;
   /* A measure of how good an overloaded instance is.  */
   struct badness_vector *bv;
   /* Index of best overloaded function.  */
@@ -2852,18 +3013,27 @@ find_oload_champ (struct value **args, int nargs, int method,
   /* 0 => no ambiguity, 1 => two good funcs, 2 => incomparable funcs.  */
 
   *oload_champ_bv = NULL;
+  ext_fn_vec_n = ext_fn_vec ? VEC_length (ext_fn_descriptor_p, ext_fn_vec) : 0;
 
   /* Consider each candidate in turn.  */
-  for (ix = 0; ix < num_fns; ix++)
+  for (ix = 0; (ix < num_fns) || (ix < ext_fn_vec_n); 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 = NULL;
+
+      if (ext_fn_vec)
+        ext_fn = VEC_index (ext_fn_descriptor_p, ext_fn_vec, ix);
 
       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
 	{
@@ -2872,13 +3042,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 db964e3..3216249 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
@@ -671,6 +672,7 @@ extern int find_overload_match (struct value **args, int nargs,
 				enum oload_search_type method,
 				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);


More information about the Gdb-patches mailing list