Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* [Patch v8] Debug methods using GDB Python
@ 2014-01-28 11:19 Siva Chandra
  2014-01-28 11:33 ` Joel Brobecker
  0 siblings, 1 reply; 4+ messages in thread
From: Siva Chandra @ 2014-01-28 11:19 UTC (permalink / raw)
  To: gdb-patches

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

Hi,

Attached is the latest version of the patch which adds the debug
methods feature to the GDB Python API. Changes from v7:

1. I have cleaned up all formatting issues that I could identify.
Given that the patch is fairly large, I will not be surprised if I
missed some.
2. Fixed a memory leak.

I still do not have doc changes included in the patch. Would be good
to get feedback on the code changes while I am working on the doc
changes.

v7 posting for reference:
https://sourceware.org/ml/gdb-patches/2014-01/msg00882.html

2014-01-28  Siva Chandra Reddy  <sivachandra@google.com>

        * 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
        'debugmethod_matchers'.
        (objfpy_dealloc): XDECREF on the new debugmethod_matcherss field.
        (objfpy_new, objfile_to_objfile_object): Initialize
        debugmethod_macthers field.
        (objfpy_get_debugmethod_matchers): New function.
        (objfile_getset): New entry 'debugmethod_matchers'.
        * python/py-progspace.c (pspace_object): New field
        'debugmethod_matchers'.
        (pspy_dealloc): XDECREF on the new debugmethod_matchers field.
        (pspy_new, pspace_to_pspace_object): Initialize
        debugmethod_matchers field.
        (pspy_get_debugmethod_matchers): 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/debugmethods.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.

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

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index ed84e35..9006dfa 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -292,6 +292,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 \
@@ -328,6 +329,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 \
@@ -739,7 +741,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 \
@@ -841,7 +843,7 @@ rs6000-tdep.h rs6000-aix-tdep.h \
 common/gdb_locale.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 \
@@ -964,7 +966,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
 
@@ -2216,6 +2219,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 29a48e4..972854a 100644
--- a/gdb/data-directory/Makefile.in
+++ b/gdb/data-directory/Makefile.in
@@ -62,8 +62,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/debugmethods.py \
 	gdb/command/frame_filters.py \
 	gdb/command/type_printers.py \
 	gdb/command/pretty_printers.py \
diff --git a/gdb/eval.c b/gdb/eval.c
index 949f76c..b91ffa0 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"
@@ -1592,11 +1593,11 @@ evaluate_subexp_standard (struct type *expect_type,
           func_name = (char *) alloca (name_len + 1);
           strcpy (func_name, &exp->elts[string_pc + 1].string);
 
-          find_overload_match (&argvec[1], nargs, func_name,
-                               NON_METHOD, /* not method */
-                               NULL, NULL, /* pass NULL symbol since
+	  find_overload_match (&argvec[1], nargs, func_name,
+			       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 */
+					  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,38 @@ 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 a method implemented in an extension language is the best
+		 match, then invoke it.  */
+	      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.  */
@@ -1699,9 +1730,9 @@ evaluate_subexp_standard (struct type *expect_type,
 
 	      (void) find_overload_match (&argvec[1], nargs,
 					  NULL,        /* no need for name */
-	                                  NON_METHOD,  /* not method */
-	                                  NULL, function, /* the function */
-					  NULL, &symp, NULL, no_adl);
+					  NON_METHOD,  /* not method */
+					  NULL, function, /* the function */
+					  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..2db5b4d
--- /dev/null
+++ b/gdb/ext-function.c
@@ -0,0 +1,174 @@
+/* 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);
+    }
+
+  VEC_free (ext_fn_descriptor_p, v);
+}
+
+/* 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..e8584ab
--- /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 95a76c2..76e35dc 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.
+debugmethod_matchers = []
 # Initial frame filters.
 frame_filters = {}
 
diff --git a/gdb/python/lib/gdb/command/debugmethods.py b/gdb/python/lib/gdb/command/debugmethods.py
new file mode 100644
index 0000000..cac5c09
--- /dev/null
+++ b/gdb/python/lib/gdb/command/debugmethods.py
@@ -0,0 +1,261 @@
+# 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 validate_dm_regexp(part_name, regexp):
+  try:
+    return re.compile(regexp)
+  except SyntaxError:
+    raise SyntaxError("Invalid %s regexp: %s", part_name, regexp)
+
+
+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_regexp = ""
+    matcher_name_regexp = ""
+    dm_name_regexp = None
+    if argc >= 1:
+        locus_regexp = argv[0]
+    if argc == 2:
+        parts = argv[1].split(";", 1)
+        matcher_name_regexp = parts[0]
+        if len(parts) > 1:
+            dm_name_regexp = parts[1]
+    if dm_name_regexp:
+        name_re = validate_dm_regexp("debugmethod name", dm_name_regexp)
+    else:
+        name_re = None
+    return (validate_dm_regexp("locus", locus_regexp),
+            validate_dm_regexp("matcher name", matcher_name_regexp),
+            name_re)
+
+
+def get_global_method_matchers(locus_re, matcher_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'.
+    """
+    locus_str = "registered globally"
+    dm_dict = { locus_str: [] }
+    if locus_re.match("global"):
+        dm_dict[locus_str].extend(
+            [m for m in gdb.debugmethod_matchers if matcher_re.match(m.name)]
+        )
+    return dm_dict
+
+
+def get_method_matchers_in_loci(loci, locus_re, matcher_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_dict = {}
+    for locus in loci:
+        if not locus_re.match(locus.filename):
+            continue
+        locus_type = "objfile"
+        if isinstance(locus, gdb.Progspace):
+            locus_type = "progspace"
+        locus_str = "registered with %s %s" % (locus_type, locus.filename)
+        dm_dict[locus_str] = [
+            m for m in locus.debugmethod_matchers if matcher_re.match(m.name)
+        ]
+    return dm_dict
+
+
+def get_status(m):
+    if m.enabled:
+        return "enabled"
+    else:
+        return "disabled"
+
+
+def print_dm_info(dm_dict, name_re):
+    """Print a dictionary of debug methods with an optional header."""
+    if not dm_dict:
+        return
+    for locus_str in dm_dict:
+        print ("Debug methods %s:" % locus_str)
+        for matcher in dm_dict[locus_str]:
+            print ("  %s - %s" % (matcher.name, get_status(matcher)))
+            if not matcher.methods:
+                continue
+            for m in matcher.methods:
+                if name_re is None or name_re.match(m.name):
+                    print ("    %s - %s" % (m.name, get_status(m)))
+            
+
+def set_dm_status1(dm_dict, name_re, status):
+    """Set the status (enabled/disabled) of a dictionary of debug methods."""
+    for locus_str, matchers in dm_dict.iteritems():
+        if not matchers:
+            continue
+        for matcher in matchers:
+            if not name_re:
+                matcher.enabled = status
+                continue
+            if not matcher.methods:
+                continue
+            for m in matcher.methods:
+                if name_re.match(m.name):
+                    m.enabled = status
+
+
+def set_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, matcher_re, name_re = parse_dm_command_args(arg)
+    set_dm_status1(get_global_method_matchers(locus_re, matcher_re), name_re,
+                   status)
+    set_dm_status1(
+        get_method_matchers_in_loci(gdb.progspaces(), locus_re, matcher_re),
+        name_re,
+        status
+    )
+    set_dm_status1(
+        get_method_matchers_in_loci(gdb.objfiles(), locus_re, matcher_re),
+        name_re,
+        status
+    )
+
+
+class InfoDebugMethod(gdb.Command):
+    """GDB command to list registered debug method matchers.
+
+    Usage: info debug-method [locus-regexp [name-regexp]]
+
+    LOCUS-REGEXP is a regular expression matching the location of the debug
+    method matcherss.  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 method
+    matchers.  If this omitted for a specified locus, then all registered debug
+    methods in the locus are listed.  To list only a certain debug methods
+    managed by a single matcher, the name regexp can be specified as
+    matcher-name-regexp;debug-method-name-regexp.
+    """
+
+    def __init__(self):
+        super(InfoDebugMethod, self).__init__("info debugmethod",
+                                               gdb.COMMAND_DATA)
+
+    def invoke(self, arg, from_tty):
+        locus_re, matcher_re, name_re = parse_dm_command_args(arg)
+        print_dm_info(get_global_method_matchers(locus_re, matcher_re),
+                      name_re)
+        print_dm_info(
+            get_method_matchers_in_loci(
+                gdb.progspaces(), locus_re, matcher_re),
+            name_re
+        )
+        print_dm_info(
+            get_method_matchers_in_loci(gdb.objfiles(), locus_re, matcher_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 debugmethod",
+                                                gdb.COMMAND_DATA)
+
+    def invoke(self, arg, from_tty):
+        set_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 debugmethod",
+                                                gdb.COMMAND_DATA)
+
+    def invoke(self, arg, from_tty):
+        set_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..08088d7
--- /dev/null
+++ b/gdb/python/lib/gdb/debugmethods.py
@@ -0,0 +1,236 @@
+# Python side of the support for debug methods.
+# Copyright (C) 2014 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""Utilities for defining debug methods"""
+
+import gdb
+import re
+import sys
+
+if sys.version_info[0] > 2:
+    # Python 3 removed basestring and long
+    basestring = str
+    long = int
+
+class DebugMethod(object):
+    """Base class (or a prototype) for debug method description.
+
+    Currently, the description only requires only 'name' and 'enabled'
+    attributes.  Description objects are managed by 'DebugMethodMatcher'
+    objects (see below).
+
+    Attributes:
+        name: The name of the debug method.
+        enabled: A boolean indicating if the debug method is enabled.
+    """
+
+    def __init__(self, name):
+        self.name = name
+        self.enabled = True
+
+
+class DebugMethodMatcher(object):
+    """Abstract base class for matching a debug method.
+
+    When looking for debug methods, GDB invokes the `match' method of a
+    registered debug method matcher to match the object type and method name.
+    The `match' method in concrete classes derived from this class should
+    return a `DebugMethodWorker' object, or a list of `DebugMethodWorker'
+    objects if there is a match (see below for 'DebugMethodWorker' class).
+
+    Attributes:
+        name: The name of the matcher.
+        enabled: A boolean indicating if the matcher is enabled.
+        debug_methods: A sequence of objects of type 'DebugMethod', or objects
+            which have atleast the attribute of a 'DebugMethod' object.
+            This list is used by the 'enable'/'disable'/'info' commands to
+            enable/disable/list the debug methods registered with GDB.  See
+            the 'match' method below to know how this sequence is to be used.
+    """
+
+    def __init__(self, name):
+        """
+        Args:
+            name: An identifying name for the debug method or the group of
+                  debug methods returned by the `match' method.
+        """
+        self.name = name
+        self.enabled = True
+        self.methods = None
+
+    def match(self, class_type, method_name):
+        """Match class type and method name.
+
+        In derived classes, it should return a DebugMethodWorker object, or a
+        sequence of 'DebugMethodWorker' objects.  Only those debug method
+        workers whose corresponding 'DebugMethod' descriptor object is enabled
+        should be returned.
+
+        Args:
+            class_type: The class type (gdb.Type object) to match.
+            method_name: The name (string) of the method to match.
+        """
+        raise NotImplementedError("DebugMethodMatcher match")
+
+
+class DebugMethodWorker(object):
+    """Base class for all debug method workers defined in Python.
+
+    A debug method worker is an object which matches the method arguments, and
+    invokes the method when GDB wants it to.  Internally, GDB first invokes the
+    'get_argtypes' method to perform overload resolution.  If GDB selects to 
+    invoke this Python debug method, then it invokes it via the overridden
+    'invoke' method.
+
+    Derived classes should override the 'get_argtypes' and 'invoke' methods.
+    """
+
+    def get_argtypes(self):
+        """Return a sequence of gdb.Type objects corresponding to the arguments
+           of the debug method.
+        """
+        raise NotImplementedError("DebugMethod get_argtypes")
+
+    def invoke(self, obj, args):
+        """Invoke the debug method.
+
+        Args:
+            obj: The gdb.Value of the object on which the method is to be
+                 invoked.
+            args: The tuple of arguments to the method.
+        """
+        raise NotImplementedError("DebugMethod invoke")
+
+
+class SimpleDebugMethodMatcher(DebugMethodMatcher):
+    """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.
+    """
+
+    class SimpleDebugMethodWorker(DebugMethodWorker):
+        def __init__(self, method_function, argtypes):
+            self._argtypes = argtypes
+            self._method_function = method_function
+
+        def get_argtypes(self):
+            return self._argtypes
+
+        def invoke(self, obj, args):
+            return self._method_function(obj, *args)
+
+
+    def __init__(self, name, class_matcher, method_matcher, method_function,
+                 *argtypes):
+        """
+        Args:
+            name: Name of the debug method matcher.
+            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.
+            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.
+            argtypes: The gdb.Type objects corresponding to the arguments that
+                this debug method takes.
+        """
+        DebugMethodMatcher.__init__(self, name)
+        assert callable(method_function), (
+            "The 'method_function' argument to 'SimpleDebugMethodMatcher' "
+            "__init__ method 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 SimpleDebugMethodMatcher.SimpleDebugMethodWorker(
+                self._method_function, self._argtypes)
+
+
+# A helper function for register_debugmethod_matcher which returns an error
+# object if MATCHER is not having the requisite attributes in the proper
+# format.
+def validate_debugmethod_matcher(matcher):
+    if not isinstance(matcher, DebugMethodMatcher):
+        return TypeError("Debug method matcher is not an instance of "
+                         "'DebugMethodMatcher'")
+    if not hasattr(matcher, "name"):
+        return TypeError("Debug method matcher is missing attribute: name")
+    if not hasattr(matcher, "enabled"):
+        return TypeError("Debug method matcher is missing attribute: enabled")
+    if not isinstance(matcher.name, basestring):
+        return TypeError("Attribute 'name' of debug method matcher is not a "
+                         "string")
+    if matcher.name.find(";") >= 0:
+        return ValueError("Debug method matcher name cannot contain ';' in it")
+
+
+# A helper function for register_debugmethod_matcher which looks up a debug
+# method matcher with NAME in LOCUS.  Returns the index of the debug method
+# matcher in 'debug_method_matchers' sequence attribute of the LOCUS.
+def lookup_debugmethod_matcher(locus, name):
+    i = 0
+    for m in locus.debugmethod_matchers:
+        if m.name == name:
+            return i
+        i = i + 1
+
+
+def register_debugmethod_matcher(locus, matcher, replace=False):
+    """Registers a debug method matcher MATCHER 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.
+        matcher: The debug method matcher to register with the LOCUS.  It
+            should be an instance of 'DebugMethodMatcher' class.
+        replace: If True, replace any existing debug method matcher with the
+            same name in the locus.  Otherwise, if a matcher with the same name
+            exists in the locus, raise an exception.
+    """
+    err = validate_debugmethod_matcher(matcher)
+    if err:
+        raise err
+    if not locus:
+        locus = gdb
+    if locus == gdb:
+        locus_name = 'GDB globally'
+    else:
+        locus_name = locus.filename
+    index = lookup_debugmethod_matcher(locus, matcher.name)
+    if index:
+        if replace:
+            del locus.debugmethod_matchers[index]
+        else:
+            raise RuntimeError('Debug method matcher already registered with '
+                               '%s: %s' % (locus_name, new_method.name))
+    if gdb.parameter("verbose"):
+        gdb.write("Registering debug method matcher '%s' with %s' ...\n") 
+    locus.debugmethod_matchers.insert(0, matcher)
diff --git a/gdb/python/py-debugmethods.c b/gdb/python/py-debugmethods.c
new file mode 100644
index 0000000..da062dc
--- /dev/null
+++ b/gdb/python/py-debugmethods.c
@@ -0,0 +1,638 @@
+/* Support for debug methods in Python.
+
+   Copyright (C) 2014 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"
+
+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 const char matchers_attr_str[] = "debugmethod_matchers";
+
+static PyObject *py_match_method_name = NULL;
+static PyObject *py_get_argtypes_method_name = NULL;
+static PyObject *py_invoke_method_name = NULL;
+
+struct py_ext_object
+{
+  PyObject *worker;
+  PyObject *this_type;
+};
+
+static struct ext_fn_descriptor *new_python_ext_method (PyObject *item,
+							PyObject *py_obj_type);
+
+/* Implementation of free_ext_obj_ftype.  */
+
+static void
+py_free_ext_object (void *ext_obj)
+{
+  struct py_ext_object *ext_object = ext_obj;
+
+  Py_XDECREF (ext_object->worker);
+  Py_XDECREF (ext_object->this_type);
+  xfree (ext_object);
+}
+
+/* Implementation of clone_ext_obj_ftype.  */
+
+static void *
+py_clone_ext_object (void *ext_obj)
+{
+  struct py_ext_object *ext_object = ext_obj, *new_object;
+
+  new_object = XCNEW (struct py_ext_object); 
+  new_object->worker = ext_object->worker;
+  new_object->this_type = ext_object->this_type;
+  Py_XINCREF (new_object->worker);
+  Py_XINCREF (new_object->this_type);
+
+  return new_object;
+}
+
+/* Invoke the "match" method of the MATCHER and return a new reference
+   to the result. Returns NULL on error.  */
+
+static PyObject *
+invoke_match_method (PyObject *matcher, PyObject *py_obj_type,
+		     const char *debugmethod_name)
+{
+  PyObject *py_debugmethod_name;
+  PyObject *match_method, *enabled_field, *match_result;
+  struct cleanup *cleanups;
+  int enabled;
+
+  if (debugmethod_name == NULL)
+    return NULL;
+
+  cleanups = make_cleanup (null_cleanup, NULL);
+
+  enabled_field = PyObject_GetAttrString (matcher, enabled_field_name);
+  if (enabled_field == NULL)
+    {
+      gdbpy_print_stack ();
+      do_cleanups (cleanups);
+
+      return NULL;
+    }
+  make_cleanup_py_decref (enabled_field);
+
+  enabled = PyObject_IsTrue (enabled_field);
+  if (enabled == -1)
+    {
+      gdbpy_print_stack ();
+      do_cleanups (cleanups);
+
+      return NULL;
+    }
+  if (enabled == 0)
+    {
+      do_cleanups (cleanups);
+
+      return NULL;
+    }
+
+  match_method = PyObject_GetAttrString (matcher, match_method_name);
+  if (match_method == NULL)
+    {
+      gdbpy_print_stack ();
+      do_cleanups (cleanups);
+
+      return NULL;
+    }
+  make_cleanup_py_decref (match_method);
+  if (!PyCallable_Check (match_method))
+    {
+      warning (_("Attribute '%s' of a registered Python debug method macther "
+		 "is not a callable.  Ignored!"), match_method_name);
+      do_cleanups (cleanups);
+
+      return NULL;
+    }
+
+  py_debugmethod_name = PyString_FromString (debugmethod_name);
+  if (py_debugmethod_name == NULL)
+    {
+      gdbpy_print_stack ();
+      do_cleanups (cleanups);
+
+      return NULL;
+    }
+  make_cleanup_py_decref (py_debugmethod_name);
+
+  match_result = PyObject_CallMethodObjArgs (matcher,
+					     py_match_method_name,
+					     py_obj_type,
+					     py_debugmethod_name,
+					     NULL);
+  if (match_result == NULL)
+    gdbpy_print_stack ();
+  do_cleanups (cleanups);
+
+  return match_result;
+}
+
+/* Extend LIST1 with LIST2.
+   Similar to list.extend.  Prints the stack and returns NULL on error. */
+
+static PyObject *
+matcher_list_extend (PyObject *list1, PyObject *list2)
+{
+  PyObject *new_list = PySequence_Concat (list1, list2);
+
+  if (new_list == NULL)
+    gdbpy_print_stack ();
+
+  return new_list;
+}
+
+/* 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) *worker_vec = NULL;
+  PyObject *py_type, *py_progspace;
+  PyObject *py_debugmethod_matcher_list = NULL, *list_iter, *matcher;
+
+  if (obj_type == NULL || method_name == NULL)
+    return NULL;
+
+  py_type = type_to_type_object (obj_type);
+  if (py_type == NULL)
+    return NULL;
+  make_cleanup_py_decref (py_type);
+
+  /* Create an empyt list of debug methods.  */
+  py_debugmethod_matcher_list = PyList_New (0);
+  if (py_debugmethod_matcher_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_matchers, *temp = py_debugmethod_matcher_list;
+
+      if (py_objfile == NULL)
+	{
+	  gdbpy_print_stack ();
+	  continue;
+	}
+
+      objfile_matchers = objfpy_get_debugmethod_matchers (py_objfile, NULL);
+      py_debugmethod_matcher_list = matcher_list_extend (temp,
+							 objfile_matchers);
+      if (py_debugmethod_matcher_list == NULL)
+	py_debugmethod_matcher_list = temp;
+      else
+	Py_DECREF (temp);
+      Py_XDECREF (objfile_matchers);
+    }
+
+  /* Gather debug methods matchers registered with the current program
+     space.  */
+  py_progspace = pspace_to_pspace_object (current_program_space);
+  if (py_progspace != NULL)
+    {
+      PyObject *temp = py_debugmethod_matcher_list;
+      PyObject *pspace_matchers = pspy_get_debugmethod_matchers (py_progspace,
+								 NULL);
+
+      py_debugmethod_matcher_list = matcher_list_extend (temp, pspace_matchers);
+      if (py_debugmethod_matcher_list == NULL)
+	py_debugmethod_matcher_list = temp;
+      else
+	Py_DECREF (temp);
+      Py_XDECREF (pspace_matchers);
+    }
+  else
+    gdbpy_print_stack ();
+
+  /* Gather debug methods registered globally.  */
+  if (gdb_python_module != NULL
+      && PyObject_HasAttrString (gdb_python_module, matchers_attr_str))
+    {
+      PyObject *gdb_matchers;
+      PyObject *temp = py_debugmethod_matcher_list;
+
+      gdb_matchers = PyObject_GetAttrString (gdb_python_module,
+					     matchers_attr_str);
+      if (gdb_matchers != NULL)
+	{
+	  py_debugmethod_matcher_list = matcher_list_extend (temp,
+							     gdb_matchers);
+	  if (py_debugmethod_matcher_list == NULL)
+	    py_debugmethod_matcher_list = temp;
+	  else
+	    Py_DECREF (temp);
+	  Py_DECREF (gdb_matchers);
+	}
+      else
+	gdbpy_print_stack ();
+    }
+
+  list_iter = PyObject_GetIter (py_debugmethod_matcher_list);
+  if (list_iter == NULL)
+    {
+      gdbpy_print_stack ();
+      Py_DECREF (py_debugmethod_matcher_list);
+      do_cleanups (cleanups);
+      return NULL;
+    }
+  while ((matcher = PyIter_Next (list_iter)))
+    {
+      PyObject *match_result = invoke_match_method (matcher, py_type,
+						    method_name);
+
+      if (match_result == Py_None || match_result == NULL)
+	;
+      else if (PySequence_Check (match_result))
+	{
+	  PyObject *iter = PyObject_GetIter (match_result);
+	  PyObject *worker;
+
+	  if (iter == NULL)
+	    {
+	      gdbpy_print_stack ();
+	      Py_DECREF (matcher);
+	      Py_DECREF (match_result);
+	      do_cleanups (cleanups);
+
+	      continue;
+	    }
+	  while ((worker = PyIter_Next (iter)))
+	    {
+	      struct ext_fn_descriptor *ext_fn;
+
+	      ext_fn = new_python_ext_method (worker, py_type);
+	      VEC_safe_push (ext_fn_descriptor_p, worker_vec, ext_fn);
+	      Py_DECREF (worker);
+	    }
+	  Py_DECREF (iter);
+	  /* Report any error that could have occurred while iterating.  */
+	  if (PyErr_Occurred ())
+	    gdbpy_print_stack ();
+	}
+      else
+	{
+	  struct ext_fn_descriptor *ext_fn;
+
+	  ext_fn = new_python_ext_method (match_result, py_type);
+	  VEC_safe_push (ext_fn_descriptor_p, worker_vec, ext_fn);
+	}
+
+      Py_XDECREF (match_result);
+      Py_DECREF (matcher);
+    }
+  Py_DECREF (list_iter);
+  /* Report any error that could have occurred while iterating.  */
+  if (PyErr_Occurred ())
+    gdbpy_print_stack ();
+
+  Py_DECREF (py_debugmethod_matcher_list);
+  do_cleanups (cleanups);
+
+  return worker_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 = ext_obj;
+  PyObject *worker = ext_object->worker;
+  PyObject *get_argtypes_method;
+  PyObject *py_argtype_list, *list_iter = NULL, *item;
+  struct cleanup *cleanups;
+  struct type **type_array, *obj_type;
+  int i = 1, arg_count;
+
+  /* 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 (worker,
+						 get_argtypes_method_name);
+  if (get_argtypes_method == NULL)
+    {
+      gdbpy_print_stack ();
+      do_cleanups (cleanups);
+
+      return NULL;
+    }
+  make_cleanup_py_decref (get_argtypes_method);
+
+  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 (worker,
+						py_get_argtypes_method_name,
+						NULL);
+  if (py_argtype_list == NULL)
+    {
+      gdbpy_print_stack ();
+      do_cleanups (cleanups);
+
+      return NULL;
+    }
+  make_cleanup_py_decref (py_argtype_list);
+  if (py_argtype_list == Py_None)
+    arg_count = 0;
+  else if (PySequence_Check (py_argtype_list))
+    {
+      arg_count = PySequence_Size (py_argtype_list);
+      if (arg_count == -1)
+	{
+	  gdbpy_print_stack ();
+	  do_cleanups (cleanups);
+
+	  return NULL;
+	}
+
+      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);
+    }
+  else
+    arg_count = 1;
+
+  /* Include the 'this' argument in the size.  */
+  type_array = XCNEWVEC (struct type *, arg_count + 1);
+  i = 1;
+  if (list_iter != NULL)
+    {
+      while ((item = PyIter_Next (list_iter)))
+	{
+	  struct type *arg_type = type_object_to_type (item);
+
+	  Py_DECREF (item);
+	  if (arg_type == NULL)
+	    {
+	      PyErr_SetString (PyExc_TypeError,
+			       _("Arg type returned by the get_argtypes method "
+				 "of a debug method worker object is not a "
+				 "gdb.Type object."));
+	      break;
+	    }
+
+	  type_array[i] = arg_type;
+	  i++;
+	}
+    }
+  else if (arg_count == 1)
+    {
+      /* py_argtype_list is not actually a list but a single gdb.Type
+	 object.  */
+      struct type *arg_type = type_object_to_type (py_argtype_list);
+
+      if (arg_type == NULL)
+	PyErr_SetString (PyExc_TypeError,
+			 _("Arg type returned by the get_argtypes method "
+			   "of a debug method worker object is not a gdb.Type "
+			   "object."));
+      else
+	{
+	  type_array[1] = arg_type;
+	  i++;
+	}
+    }
+  if (PyErr_Occurred ())
+    {
+      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->this_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;
+  PyObject *invoke_method;
+  struct type *obj_type, *this_type;
+  struct value *result = NULL;
+  struct py_ext_object *py_ext_obj = ext_obj;
+  PyObject *debugmethod_worker = py_ext_obj->worker;
+
+  cleanups = ensure_python_env (get_current_arch (), current_language);
+
+  invoke_method =  PyObject_GetAttrString (debugmethod_worker,
+					   invoke_method_name);
+  if (invoke_method == NULL)
+    {
+      gdbpy_print_stack ();
+      do_cleanups (cleanups);
+
+      return NULL;
+    }
+  make_cleanup_py_decref (invoke_method);
+
+  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;
+    }
+
+  obj_type = check_typedef (value_type (obj));
+  this_type = check_typedef (type_object_to_type (py_ext_obj->this_type));
+  if (TYPE_CODE (obj_type) == TYPE_CODE_PTR)
+    {
+      struct type *this_ptr = lookup_pointer_type (this_type);
+
+      if (!types_equal (obj_type, this_ptr))
+	obj = value_cast (this_ptr, obj);
+    }
+  else if (TYPE_CODE (obj_type) == TYPE_CODE_REF)
+    {
+      struct type *this_ref = lookup_reference_type (this_type);
+
+      if (!types_equal (obj_type, this_ref))
+	obj = value_cast (this_ref, obj);
+    }
+  else
+    {
+      if (!types_equal (obj_type, this_type))
+	obj = value_cast (this_type, obj);
+    }
+  py_value_obj = value_to_value_object (obj);
+  if (py_value_obj == NULL)
+    {
+      gdbpy_print_stack ();
+      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;
+	}
+
+      PyTuple_SET_ITEM (py_arg_tuple, i, py_value_arg);
+    }
+
+  py_result = PyObject_CallMethodObjArgs (debugmethod_worker,
+					  py_invoke_method_name,
+					  py_value_obj,
+					  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.  WORKER is the corresponding
+   debug method worker for object of THIS_TYPE.  */
+
+static struct ext_fn_descriptor *
+new_python_ext_method (PyObject *worker, PyObject *this_type)
+{
+  struct py_ext_object *ext_object = XCNEW (struct py_ext_object);
+
+  ext_object->worker = worker;
+  ext_object->this_type = this_type;
+  Py_XINCREF (worker);
+  Py_XINCREF (this_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);
+
+  py_match_method_name = PyString_FromString (match_method_name);
+  if (py_match_method_name == NULL)
+    return -1;
+
+  py_invoke_method_name = PyString_FromString (invoke_method_name);
+  if (py_invoke_method_name == NULL)
+    return -1;
+
+  py_get_argtypes_method_name = PyString_FromString (get_argtypes_method_name);
+  if (py_get_argtypes_method_name == NULL)
+    return -1;
+
+  return 1;
+}
+
+#endif /* HAVE_PYTHON */
diff --git a/gdb/python/py-objfile.c b/gdb/python/py-objfile.c
index 97fb0be..fd4254a 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 matcher list.  */
+  PyObject *debugmethod_matchers;
 } 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->debugmethod_matchers);
   Py_TYPE (self)->tp_free (self);
 }
 
@@ -99,6 +103,13 @@ objfpy_new (PyTypeObject *type, PyObject *args, PyObject *keywords)
 	  Py_DECREF (self);
 	  return NULL;
 	}
+
+      self->debugmethod_matchers = PyList_New (0);
+      if (self->debugmethod_matchers == 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 'debugmethod_matchers' attribute.  */
+
+PyObject *
+objfpy_get_debugmethod_matchers (PyObject *o, void *ignore)
+{
+  objfile_object *self = (objfile_object *) o;
+
+  Py_INCREF (self->debugmethod_matchers);
+  return self->debugmethod_matchers;
+}
+
 /* Set the 'type_printers' attribute.  */
 
 static int
@@ -292,6 +314,13 @@ objfile_to_objfile_object (struct objfile *objfile)
 	      return NULL;
 	    }
 
+	  object->debugmethod_matchers = PyList_New (0);
+	  if (object->debugmethod_matchers == 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 },
+  { "debugmethod_matchers", objfpy_get_debugmethod_matchers, NULL,
+    "Debug methods.", NULL },
   { NULL }
 };
 
diff --git a/gdb/python/py-progspace.c b/gdb/python/py-progspace.c
index cda5a86..c65d863 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 *debugmethod_matchers;
 } 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->debugmethod_matchers);
   Py_TYPE (self)->tp_free (self);
 }
 
@@ -107,6 +111,13 @@ pspy_new (PyTypeObject *type, PyObject *args, PyObject *keywords)
 	  Py_DECREF (self);
 	  return NULL;
 	}
+
+      self->debugmethod_matchers = PyList_New (0);
+      if (self->debugmethod_matchers == 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 'debugmethod_matchers' attribute.  */
+
+PyObject *
+pspy_get_debugmethod_matchers (PyObject *o, void *ignore)
+{
+  pspace_object *self = (pspace_object *) o;
+
+  Py_INCREF (self->debugmethod_matchers);
+  return self->debugmethod_matchers;
+}
+
 /* Set the 'type_printers' attribute.  */
 
 static int
@@ -288,6 +310,13 @@ pspace_to_pspace_object (struct program_space *pspace)
 	      return NULL;
 	    }
 
+	  object->debugmethod_matchers = PyList_New (0);
+	  if (object->debugmethod_matchers == 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 },
+  { "debugmethod_matchers", pspy_get_debugmethod_matchers, NULL,
+    "Debug methods.", NULL },
   { NULL }
 };
 
diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
index ef5cd3f..8e58c62 100644
--- a/gdb/python/python-internal.h
+++ b/gdb/python/python-internal.h
@@ -317,11 +317,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_debugmethod_matchers (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_debugmethod_matchers (PyObject *, void *);
 
 PyObject *gdbarch_to_arch_object (struct gdbarch *gdbarch);
 
@@ -402,6 +404,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 337c170..d0e0aba 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -1688,7 +1688,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..0ffc59f
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-debugmethods.cc
@@ -0,0 +1,192 @@
+/* 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:
+  /* This class overrides the virtual operator* defined in B.  The
+     associated Python script replaces B::operator* but not D::operator*.
+     Hence, if we have a reference pointing to an instance of D, the C++
+     version of D::operator* should be invoked and not the Python version
+     B::operator* even after loading the python script.  */
+  virtual int operator* (const B &obj);
+};
+
+int
+D::operator* (const B &obj)
+{
+  cout << "From CC <D_star_D>:" << endl;
+  return a * obj.a;
+}
+
+class E : public A
+{
+ public:
+  /* This class has a member named 'a', while the base class also has a
+     member named 'a'.  When one invokes A::geta(), A::a should be
+     returned and not E::a as the 'geta' method is defined on class 'A'.
+     This class tests this aspect of debug methods.  */
+  int a;
+};
+
+template <typename T>
+class G
+{
+ public:
+  template <typename T1>
+  int size_diff ();
+
+  template <int M>
+  int size_mul ();
+
+  template <typename T1>
+  T mul(const T1 t1);
+
+ public:
+  T t;
+};
+
+template <typename T>
+template <typename T1>
+int
+G<T>::size_diff ()
+{
+  cout << "From CC G<>::size_diff:" << endl;
+  return sizeof (T1) - sizeof (T);
+}
+
+template <typename T>
+template <int M>
+int
+G<T>::size_mul ()
+{
+  cout << "From CC G<>::size_mul:" << endl;
+  return M * sizeof (T);
+}
+
+template <typename T>
+template <typename T1>
+T
+G<T>::mul (const T1 t1)
+{
+  cout << "From CC G<>::mul:" << endl;
+  return t1 * t;
+}
+
+}
+
+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_ptr;
+  g.t = 5;
+  g_ptr = &g;
+  E e;
+  e.a = 1000;
+  e.A::a = 100;
+
+  int diff = g.size_diff<float> ();
+  int smul = g.size_mul<2> ();
+  int mul = g.mul (1.0);
+
+  for (int i = 0; i < 10; i++)
+    {
+      a1.array[i] = a2.array[i] = i;
+    }
+
+  return 0; /* Break here.  */ 
+}
diff --git a/gdb/testsuite/gdb.python/py-debugmethods.exp b/gdb/testsuite/gdb.python/py-debugmethods.exp
new file mode 100644
index 0000000..18d8d52
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-debugmethods.exp
@@ -0,0 +1,125 @@
+# 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 e.geta()" "From CC geta.*100" "Before: e.geta()"
+gdb_test "p g.size_diff<float>()" "From CC G<>::size_diff.*" \
+  "Before: g.size_diff<float>()"
+gdb_test "p g.size_diff<unsigned long>()" "Couldn't find method.*" \
+  "Before: g.size_diff<unsigned long>()"
+gdb_test "p g.size_mul<2>()" "From CC G<>::size_mul.*" \
+  "Before: g.size_mul<2>()"
+gdb_test "p g.size_mul<5>()" "Couldn't find method.*" \
+  "Before: g.size_mul<5>()"
+gdb_test "p g.mul<double>(2.0)" "From CC G<>::mul.*" \
+  "Before: g.mul<double>(2.0)"
+gdb_test "p g.mul<char>('a')" "Couldn't find method.*" \
+  "Before: g.mul<char>('a')"
+
+# Load the script which adds the debug methods.
+gdb_test_no_output "source ${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 e.geta()" "From Python <A_geta>.*100" "After: e.geta()"
+gdb_test "p g.size_diff<float>  ()" "From Python G<>::size_diff.*" \
+  "After: g.size_diff<float>()"
+gdb_test "p g.size_diff<  unsigned long  >()" "From Python G<>::size_diff.*" \
+  "After: g.size_diff<unsigned long>()"
+gdb_test "p g.size_mul<2>()" "From Python G<>::size_mul.*" \
+  "After: g.size_mul<2>()"
+gdb_test "p g.size_mul<  5  >()" "From Python G<>::size_mul.*" \
+  "After: g.size_mul<  5  >()"
+gdb_test "p g.mul<double>(2.0)" "From Python G<>::mul.*" \
+  "After: g.mul<double>(2.0)"
+gdb_test "p g.mul<char>('a')" "From Python G<>::mul.*" \
+gdb_test "p g_ptr->mul<char>('a')" "From Python G<>::mul.*" \
+  "After: g->mul<char>('a')"
+
+# Tests for 'disable/enable debugmethod' command.
+gdb_test_no_output "disable debugmethod .*debugmethods G_methods" \
+  "Disable G_methods"
+gdb_test "p g.mul<char>('a')" "Couldn't find method.*" \
+  "g.mul<char>('a') after disabling G_methods"
+gdb_test_no_output "enable debugmethod .*debugmethods G_methods" \
+  "Enable G_methods"
+gdb_test "p g.mul<char>('a')" "From Python G<>::mul.*" \
+  "After enabling G_methods"
+gdb_test_no_output "disable debugmethod .*debugmethods G_methods;mul" \
+  "Disable G_methods;mul"
+gdb_test "p g.mul<char>('a')" "Couldn't find method.*" \
+  "g.mul<char>('a') after disabling G_methods;mul"
+gdb_test_no_output "enable debugmethod .*debugmethods G_methods;mul" \
+  "Enable G_methods;mul"
+gdb_test "p g.mul<char>('a')" "From Python G<>::mul.*" \
+  "After enabling G_methods;mul"
+
+# Test for 'info debug-methods' command
+gdb_test "info debugmethod 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..d263d48
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-debugmethods.py
@@ -0,0 +1,185 @@
+# 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, DebugMethodMatcher, DebugMethodWorker
+from gdb.debugmethods import SimpleDebugMethodMatcher
+
+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):
+  # This function is not defined for objects of class C in the associated C++
+  # file.  However, C is derived from A which has a virtual operator- method.
+  # Hence, if an operator '-' is used on a reference pointing to 'C' after
+  # loading this script, then this Python version should be invoked.
+  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_worker(DebugMethodWorker):
+    def __init__(self, class_template_type, method_template_type):
+        self._class_template_type = class_template_type
+        self._method_template_type = method_template_type
+
+    def get_argtypes(self):
+        pass
+
+    def invoke(self, obj, args):
+        print ('From Python G<>::size_diff()')
+        return (self._method_template_type.sizeof -
+                self._class_template_type.sizeof)
+
+
+class G_size_mul_worker(DebugMethodWorker):
+    def __init__(self, class_template_type, method_template_val):
+        self._class_template_type = class_template_type
+        self._method_template_val = method_template_val
+
+    def get_argtypes(self):
+        pass
+
+    def invoke(self, obj, args):
+        print ('From Python G<>::size_mul()')
+        return self._class_template_type.sizeof * self._method_template_val
+
+
+class G_mul_worker(DebugMethodWorker):
+    def __init__(self, class_template_type, method_template_type):
+        self._class_template_type = class_template_type
+        self._method_template_type = method_template_type
+
+    def get_argtypes(self):
+        return self._method_template_type
+
+    def invoke(self, obj, args):
+        print ('From Python G<>::mul()')
+        return obj['t'] * args[0]
+
+
+class G_methods_matcher(DebugMethodMatcher):
+    def __init__(self):
+        DebugMethodMatcher.__init__(self, 'G_methods')
+        self.methods = [DebugMethod('size_diff'),
+                        DebugMethod('size_mul'),
+                        DebugMethod('mul')]
+
+    def _is_enabled(self, name):
+        for method in self.methods:
+            if method.name == name and method.enabled:
+                return True
+
+    def match(self, class_type, method_name):
+        class_tag = class_type.unqualified().tag
+        if not re.match('^dop::G<[ ]*[_a-zA-Z][ _a-zA-Z0-9]*>$',
+                        class_tag):
+            return None
+        t_name = class_tag[7:-1]
+        try:
+            t_type = gdb.lookup_type(t_name)
+        except Exception:
+            return None
+        if re.match('^size_diff<[ ]*[_a-zA-Z][ _a-zA-Z0-9]*>$', method_name):
+            if not self._is_enabled('size_diff'):
+                return None
+            t1_name = method_name[10:-1]
+            try:
+                t1_type = gdb.lookup_type(t1_name)
+                return G_size_diff_worker(t_type, t1_type)
+            except Exception:
+                return None
+        if re.match('^size_mul<[ ]*[0-9]+[ ]*>$', method_name):
+            if not self._is_enabled('size_mul'):
+                return None
+            m_val = int(method_name[9:-1])
+            return G_size_mul_worker(t_type, m_val)
+        if re.match('^mul<[ ]*[_a-zA-Z][ _a-zA-Z0-9]*>$', method_name):
+            if not self._is_enabled('mul'):
+                return None
+            t1_name = method_name[4:-1]
+            try:
+                t1_type = gdb.lookup_type(t1_name)
+                return G_mul_worker(t_type, t1_type)
+            except Exception:
+                return None
+
+
+global_dm_list = [
+    SimpleDebugMethodMatcher('A_plus_A',
+                             '^dop::A$',
+                             'operator\+',
+                             A_plus_A,
+                             # This is a replacement, hence match the arg type
+                             # exactly!
+                             type_A.const().reference()),
+    SimpleDebugMethodMatcher('plus_plus_A',
+                             '^dop::A$',
+                             'operator\+\+',
+                             plus_plus_A),
+    SimpleDebugMethodMatcher('C_minus_C',
+                             '^dop::C$',
+                             'operator\-',
+                             C_minus_C,
+                             type_C),
+    SimpleDebugMethodMatcher('B_star_B',
+                             '^dop::B$',
+                             'operator\*',
+                             B_star_B,
+                             # This is a replacement, hence match the arg type
+                             # exactly!
+                             type_B.const().reference()),
+    SimpleDebugMethodMatcher('A_geta',
+                             '^dop::A$',
+                             '^geta$',
+                             A_geta),
+    SimpleDebugMethodMatcher('A_getarrayind',
+                             '^dop::A$',
+                             '^getarrayind$',
+                             A_getarrayind,
+                             type_int),
+]
+
+for matcher in global_dm_list:
+    gdb.debugmethods.register_debugmethod_matcher(gdb, matcher)
+gdb.debugmethods.register_debugmethod_matcher(gdb.current_progspace(),
+                                              G_methods_matcher())
diff --git a/gdb/valarith.c b/gdb/valarith.c
index 8e863e3..6f3ed62 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,
-                           int *static_memfuncp)
+			   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);
+		       &args[0] /* objp */,
+		       NULL /* pass NULL symbol since symbol is unknown */,
+		       &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 deb01cb..86681cb 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -42,6 +42,7 @@
 #include "observer.h"
 #include "objfiles.h"
 #include "exceptions.h"
+#include "ext-function.h"
 
 extern unsigned int overload_debug;
 /* Local functions.  */
@@ -70,8 +71,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);
 
@@ -98,9 +99,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);
 
@@ -2293,52 +2295,76 @@ value_struct_elt_bitpos (struct value **argp, int bitpos, struct type *ftype,
 
 /* Search through the methods of an object (and its bases) to find a
    specified method.  Return the pointer to the fn_field list of
-   overloaded instances.
+   overloaded instances defined in the source language.  If available
+   and matching, a vector matching/overloaded debug methods defined in
+   extension languages are also returned.
 
    Helper function for value_find_oload_list.
    ARGP is a pointer to a pointer to a value (the object).
    METHOD is a string containing the method name.
    OFFSET is the offset within the value.
    TYPE is the assumed type of the object.
+   FN_LIST The pointer to matching overloaded instances defined in
+      source language.
    NUM_FNS is the number of overloaded instances.
+   EXT_FN_VEC The vector matching debug methods defined in extension
+      languages.
    BASETYPE is set to the actual type of the subobject where the
       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;
@@ -2355,13 +2381,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.
@@ -2369,14 +2393,20 @@ find_method_list (struct value **argp, const char *method,
    ARGP is a pointer to a pointer to a value (the object).
    METHOD is the method name.
    OFFSET is the offset within the value contents.
+   FN_LIST The pointer to matching overloaded instances defined in
+      source language.
    NUM_FNS is the number of overloaded instances.
+   EXT_FN_VEC The vector matching debug methods defined in extension
+      languages.
    BASETYPE is set to the type of the base subobject that defines the
       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;
@@ -2398,8 +2428,34 @@ 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);
+}
+
+/* Return the dynamic type of OBJ.  */
+
+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
@@ -2427,9 +2483,11 @@ value_find_oload_method_list (struct value **argp, const char *method,
    Return value is an integer: 0 -> good match, 10 -> debugger applied
    non-standard coercions, 100 -> incompatible.
 
-   If a method is being searched for, VALP will hold the value.
-   If a non-method is being searched for, SYMP will hold the symbol 
-   for it.
+   If the best match is a debug function/method implemented in an extension
+   language, then EXT_FN will hold the matching function/method.  Otherwise,
+   VALP will hold the value if a method is being searched for, or SYMP will
+   hold the symbol for the matching function if a non-method is being
+   searched for.
 
    If a method is being searched for, and it is a static method,
    then STATICP will point to a non-zero value.
@@ -2447,6 +2505,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);
@@ -2454,16 +2513,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;
@@ -2475,6 +2542,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.  */
@@ -2503,12 +2572,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) ? "::" : "",
@@ -2519,18 +2588,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));
+	  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);
+	}
 
-	  make_cleanup (xfree, 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)
@@ -2673,21 +2806,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));
@@ -2697,10 +2815,65 @@ 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);
+	}
+      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));
 	}
-      *objp = temp;
     }
+  else
+    *symp = oload_syms[func_oload_champ];
 
   do_cleanups (all_cleanups);
 
@@ -2835,7 +3008,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),
@@ -2873,7 +3046,9 @@ find_oload_champ_namespace_loop (struct value **args, int nargs,
 
 /* Look for a function to take NARGS args of ARGS.  Find
    the best match from among the overloaded methods or functions
-   (depending on METHOD) given by FNS_PTR or OLOAD_SYMS, respectively.
+   given by FNS_PTR or OLOAD_SYMS or EXT_FN_VEC, respectively.  If
+   EXT_FN_VEC is NULL, then METHOD indicates whether to use FNS_PTR
+   or OLOAD_SYMS to find the best match.
    The number of methods/functions in the list is given by NUM_FNS.
    Return the index of the best match; store an indication of the
    quality of the match in OLOAD_CHAMP_BV.
@@ -2883,10 +3058,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.  */
@@ -2896,18 +3073,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
 	{
@@ -2916,13 +3102,18 @@ 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 f846669..74cac84 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
@@ -690,6 +691,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);

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

* Re: [Patch v8] Debug methods using GDB Python
  2014-01-28 11:19 [Patch v8] Debug methods using GDB Python Siva Chandra
@ 2014-01-28 11:33 ` Joel Brobecker
  2014-01-28 11:49   ` Siva Chandra
  0 siblings, 1 reply; 4+ messages in thread
From: Joel Brobecker @ 2014-01-28 11:33 UTC (permalink / raw)
  To: Siva Chandra; +Cc: gdb-patches

Hi Siva,

> Attached is the latest version of the patch which adds the debug
> methods feature to the GDB Python API. Changes from v7:

While looking for the documentation in the patch (I missed the fact
that you said this was in progress), I happen to notice that the
copyright years in the copyright range are not always including 2014.
Also, for those which do have 2014, the range of years should start
with the year the file was first committed to medium. So if you
started working on a given file the year before, the Copyright year
should be 2013-2014 (please always use a single range).

Thank you!
-- 
Joel


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

* Re: [Patch v8] Debug methods using GDB Python
  2014-01-28 11:33 ` Joel Brobecker
@ 2014-01-28 11:49   ` Siva Chandra
  2014-01-28 11:58     ` Joel Brobecker
  0 siblings, 1 reply; 4+ messages in thread
From: Siva Chandra @ 2014-01-28 11:49 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: gdb-patches

On Tue, Jan 28, 2014 at 3:32 AM, Joel Brobecker <brobecker@adacore.com> wrote:
> copyright years in the copyright range are not always including 2014.

I have fixed it locally now. Should come out correctly in v9.

> Also, for those which do have 2014, the range of years should start
> with the year the file was first committed to medium. So if you
> started working on a given file the year before, the Copyright year
> should be 2013-2014 (please always use a single range).

None of the new files were committed to the repo ever. But, most of
them were posted for review in 2013. Should they still have 2013-2014
range in the Copyright notice?


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

* Re: [Patch v8] Debug methods using GDB Python
  2014-01-28 11:49   ` Siva Chandra
@ 2014-01-28 11:58     ` Joel Brobecker
  0 siblings, 0 replies; 4+ messages in thread
From: Joel Brobecker @ 2014-01-28 11:58 UTC (permalink / raw)
  To: Siva Chandra; +Cc: gdb-patches

> I have fixed it locally now. Should come out correctly in v9.

[...]

> None of the new files were committed to the repo ever. But, most of
> them were posted for review in 2013. Should they still have 2013-2014
> range in the Copyright notice?

Yes, that's correct. When I asked the FSF about it, the answer was
that as long as it was saved somewhere, the range should include
that year. The year when it actually gets committed to the FSF
repo isn't really relevant in that case.

Thank you!
-- 
Joel


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

end of thread, other threads:[~2014-01-28 11:58 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-01-28 11:19 [Patch v8] Debug methods using GDB Python Siva Chandra
2014-01-28 11:33 ` Joel Brobecker
2014-01-28 11:49   ` Siva Chandra
2014-01-28 11:58     ` Joel Brobecker

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