[v18,4/4] Add xmethod support to the Python API

Message ID CAGyQ6gz5zh64AcfeHcqiXtYKpJf7GWpD+5FmKe38fg1bOMJc_w@mail.gmail.com
State Superseded
Headers

Commit Message

Siva Chandra Reddy May 23, 2014, 9:01 p.m. UTC
  The attached patch addresses all of Doug's comments for this part from
last time. The previous version for this part was not numbered 17. I
am syncing all parts to v18 now to avoid confusion.

ChangeLog:
2014-05-23  Siva Chandra Reddy  <sivachandra@google.com>

        * python/py-xmethods.c: New file.
        * python/py-objfile.c (objfile_object): New field 'xmethods'.
        (objfpy_dealloc): XDECREF on the new xmethods field.
        (objfpy_new, objfile_to_objfile_object): Initialize xmethods
        field.
        (objfpy_get_xmethods): New function.
        (objfile_getset): New entry 'xmethods'.
        * python/py-progspace.c (pspace_object): New field 'xmethods'.
        (pspy_dealloc): XDECREF on the new xmethods field.
        (pspy_new, pspace_to_pspace_object): Initialize xmethods
        field.
        (pspy_get_xmethods): New function.
        (pspace_getset): New entry 'xmethods'.
        * python/python-internal.h: Add declarations for new functions.
        * python/python.c (_initialize_python): Invoke
        gdbpy_initialize_xmethods.
        * python/lib/gdb/__init__.py (xmethods): New
        attribute.
        * python/lib/gdb/xmethod.py: New file.
        * python/lib/gdb/command/xmethods.py: New file.

        testuite/
        * gdb.python/py-xmethods.cc: New testcase to test xmethods.
        * gdb.python/py-xmethods.exp: New tests to test xmethods.
        * gdb.python/py-xmethods.py: Python script supporting the
        new testcase and tests.
  

Comments

Doug Evans May 25, 2014, 11:31 p.m. UTC | #1
Siva Chandra <sivachandra@google.com> writes:

> The attached patch addresses all of Doug's comments for this part from
> last time. The previous version for this part was not numbered 17. I
> am syncing all parts to v18 now to avoid confusion.
>
> ChangeLog:
> 2014-05-23  Siva Chandra Reddy  <sivachandra@google.com>
>
>         * python/py-xmethods.c: New file.
>         * python/py-objfile.c (objfile_object): New field 'xmethods'.
>         (objfpy_dealloc): XDECREF on the new xmethods field.
>         (objfpy_new, objfile_to_objfile_object): Initialize xmethods
>         field.
>         (objfpy_get_xmethods): New function.
>         (objfile_getset): New entry 'xmethods'.
>         * python/py-progspace.c (pspace_object): New field 'xmethods'.
>         (pspy_dealloc): XDECREF on the new xmethods field.
>         (pspy_new, pspace_to_pspace_object): Initialize xmethods
>         field.
>         (pspy_get_xmethods): New function.
>         (pspace_getset): New entry 'xmethods'.
>         * python/python-internal.h: Add declarations for new functions.
>         * python/python.c (_initialize_python): Invoke
>         gdbpy_initialize_xmethods.
>         * python/lib/gdb/__init__.py (xmethods): New
>         attribute.
>         * python/lib/gdb/xmethod.py: New file.
>         * python/lib/gdb/command/xmethods.py: New file.
>
>         testuite/
>         * gdb.python/py-xmethods.cc: New testcase to test xmethods.
>         * gdb.python/py-xmethods.exp: New tests to test xmethods.
>         * gdb.python/py-xmethods.py: Python script supporting the
>         new testcase and tests.

Still a few things I think we need to address.
Sorry for not catching them sooner.
I think they're simple though.

> diff --git a/gdb/python/lib/gdb/command/xmethods.py b/gdb/python/lib/gdb/command/xmethods.py
> new file mode 100644
> index 0000000..f61e7fb
> --- /dev/null
> +++ b/gdb/python/lib/gdb/command/xmethods.py
> @@ -0,0 +1,272 @@
> + [...]
> +
> +class DisableXMethod(gdb.Command):
> +    """GDB command to disable a specified (group of) xmethod(s).
> +
> +    Usage: disable xmethod [locus-regexp [name-regexp]]
> +
> +    LOCUS-REGEXP is a regular expression matching the location of the
> +    xmethod matcherss.  If it is omitted, all registered xmethod matchers

matchers.

> diff --git a/gdb/python/lib/gdb/xmethod.py b/gdb/python/lib/gdb/xmethod.py
> new file mode 100644
> index 0000000..9d0deff
> --- /dev/null
> +++ b/gdb/python/lib/gdb/xmethod.py
> @@ -0,0 +1,254 @@
> + [...]
> +
> +    def get_arg_types(self):
> +        """Return arguments types of an xmethod.
> +
> +        A sequence of gdb.Type objects corresponding to the arguments of the
> +        xmethod are returned.  If the xmethod takes no arguments, then 'None'
> +        or an empty sequence is returned.  If the xmethod takes only a single
> +        argument, then a gdb.Type object or a sequence with a single gdb.Type
> +        element is returned.
> +        """
> +        raise NotImplementedError("XMethod get_arg_types")

raise NotImplementedError("XMethodWorker get_arg_types")

> +
> +    def invoke(self, obj, args):
> +        """Invoke the xmethod.
> +
> +        Args:
> +            obj: The gdb.Value of the object on which the method is to be
> +                 invoked.
> +            args: The tuple of arguments to the method.  Each element of the
> +                  tuple is a gdb.Value object.
> +
> +        Returns:
> +            A gdb.Value corresponding to the value returned by the xmethod.
> +            Returns 'None' if the method does not return anything.
> +        """
> +        raise NotImplementedError("XMethod invoke")

raise NotImplementedError("XMethodWorker invoke")

> +# A helper function for register_xmethod_matcher which returns an error
> +# object if MATCHER is not having the requisite attributes in the proper
> +# format.
> +
> +def validate_xmethod_matcher(matcher):

I think all the internal routines in this file should have an "_" prefix.
My patch in the 1/4 reply lists them all.
I don't feel as strongly about gdb/command/xmethods.py since it isn't
likely to be imported for random usage.

> diff --git a/gdb/python/py-xmethods.c b/gdb/python/py-xmethods.c
> new file mode 100644
> index 0000000..0868c9f
> --- /dev/null
> +++ b/gdb/python/py-xmethods.c
> @@ -0,0 +1,648 @@
> +/* Support for debug methods in Python.
> +
> +   Copyright (C) 2013-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 "extension-priv.h"
> +#include "objfiles.h"
> +#include "value.h"
> +#include "language.h"
> +
> +#include "python.h"
> +#include "python-internal.h"
> +
> +static const char enabled_field_name[] = "enabled";
> +static const char match_method_name[] = "match";
> +static const char get_arg_types_method_name[] = "get_arg_types";
> +static const char invoke_method_name[] = "invoke";
> +static const char matchers_attr_str[] = "xmethods";
> +
> +static PyObject *py_match_method_name = NULL;
> +static PyObject *py_get_arg_types_method_name = NULL;
> +static PyObject *py_invoke_method_name = NULL;
> +
> +struct gdbpy_worker_data
> +{
> +  PyObject *worker;
> +  PyObject *this_type;
> +};
> +
> +static struct xmethod_worker *new_python_xmethod_worker
> +  (PyObject *item, PyObject *py_obj_type);
> +
> +/* Implementation of free_xmethod_worker_data for Python.  */
> +
> +void
> +gdbpy_free_xmethod_worker_data
> +  (const struct extension_language_defn *extlang, void *data)

The line length here can be handled using gdb's existing formatting
rules, so let's do that.

gdbpy_free_xmethod_worker_data (const struct extension_language_defn *extlang,
				void *data)

Plus this function needs to acquire the GIL.  gdb can crash otherwise.
I went with the canonical ensure_python_env in the patch in the 1/4 reply,
though I see py-breakpoint.c has some direct calls to
PyGILState_Ensure, PyGILState_Release.

> +{
> +  struct gdbpy_worker_data *worker_data = data;
> +
> +  gdb_assert (worker_data->worker != NULL && worker_data->this_type != NULL);
> +
> +  Py_DECREF (worker_data->worker);
> +  Py_DECREF (worker_data->this_type);
> +  xfree (worker_data);
> +}
> +
> +/* Implementation of clone_xmethod_worker_data for Python.  */
> +
> +void *
> +gdbpy_clone_xmethod_worker_data
> +  (const struct extension_language_defn *extlang, void *data)

Similarly,

gdbpy_clone_xmethod_worker_data (const struct extension_language_defn *extlang,
				 void *data)

And similarly this function should, I think, acquire the GIL.


> +{
> +  struct gdbpy_worker_data *worker_data = data, *new_data;
> +
> +  gdb_assert (worker_data->worker != NULL && worker_data->this_type != NULL);
> +
> +  new_data = XCNEW (struct gdbpy_worker_data);
> +  new_data->worker = worker_data->worker;
> +  new_data->this_type = worker_data->this_type;
> +  Py_INCREF (new_data->worker);
> +  Py_INCREF (new_data->this_type);
> +
> +  return new_data;
> +}
> +
> + [...]
> +
> +/* Implementation of get_matching_xmethod_workers for Python.  */
> +
> +enum ext_lang_rc
> +gdbpy_get_matching_xmethod_workers
> +  (const struct extension_language_defn *extlang,
> +   struct type *obj_type, const char *method_name,
> +   xmethod_worker_vec **dm_vec)
> +{
> +  struct cleanup *cleanups;
> +  struct objfile *objfile;
> +  VEC (xmethod_worker_ptr) *worker_vec = NULL;
> +  PyObject *py_type, *py_progspace;
> +  PyObject *py_xmethod_matcher_list = NULL, *list_iter, *matcher;
> +
> +  gdb_assert (obj_type != NULL && method_name != NULL);
> +
> +  cleanups = ensure_python_env (get_current_arch (), current_language);
> +
> +  py_type = type_to_type_object (obj_type);
> +  if (py_type == NULL)
> +    {
> +      gdbpy_print_stack ();
> +      do_cleanups (cleanups);
> +
> +      return EXT_LANG_RC_ERROR;
> +    }
> +  make_cleanup_py_decref (py_type);
> +
> +  /* Create an empty list of debug methods.  */
> +  py_xmethod_matcher_list = PyList_New (0);
> +  if (py_xmethod_matcher_list == NULL)
> +    {
> +      gdbpy_print_stack ();
> +      do_cleanups (cleanups);
> +
> +      return EXT_LANG_RC_ERROR;
> +    }
> +
> +  /* Gather debug method matchers registered with the object files.  */

I'd extend this comment thusly:

  /* Gather debug method matchers registered with the object files.
     This could be done differently by iterating over each objfile's matcher
     list individually, but there's no data yet to show it's needed.  */

> +  ALL_OBJFILES (objfile)
> +    {
> +      PyObject *py_objfile = objfile_to_objfile_object (objfile);
> +      PyObject *objfile_matchers, *temp = py_xmethod_matcher_list;
> +
> +      if (py_objfile == NULL)
> +	{
> +	  gdbpy_print_stack ();
> +	  Py_DECREF (py_xmethod_matcher_list);
> +	  do_cleanups (cleanups);
> +
> +	  return EXT_LANG_RC_ERROR;
> +	}
> +
> +      objfile_matchers = objfpy_get_xmethods (py_objfile, NULL);
> +      py_xmethod_matcher_list = PySequence_Concat (temp,
> +							objfile_matchers);

Left over TODO from xmethod rename I think:

      py_xmethod_matcher_list = PySequence_Concat (temp, objfile_matchers);

> +      Py_DECREF (temp);
> +      Py_DECREF (objfile_matchers);
> +      if (py_xmethod_matcher_list == NULL)
> +	{
> +	  gdbpy_print_stack ();
> +	  do_cleanups (cleanups);
> +
> +	  return EXT_LANG_RC_ERROR;
> +	}
> +    }
> +
> +  /* 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_xmethod_matcher_list;
> +      PyObject *pspace_matchers = pspy_get_xmethods (py_progspace, NULL);
> +
> +      py_xmethod_matcher_list = PySequence_Concat (temp, pspace_matchers);
> +      Py_DECREF (temp);
> +      Py_DECREF (pspace_matchers);
> +      if (py_xmethod_matcher_list == NULL)
> +	{
> +	  gdbpy_print_stack ();
> +	  do_cleanups (cleanups);
> +
> +	  return EXT_LANG_RC_ERROR;
> +	}
> +    }
> +  else
> +    {
> +      gdbpy_print_stack ();
> +      Py_DECREF (py_xmethod_matcher_list);
> +      do_cleanups (cleanups);
> +
> +      return EXT_LANG_RC_ERROR;
> +    }
> +
> +  /* Gather debug method matchers registered globally.  */
> +  if (gdb_python_module != NULL
> +      && PyObject_HasAttrString (gdb_python_module, matchers_attr_str))
> +    {
> +      PyObject *gdb_matchers;
> +      PyObject *temp = py_xmethod_matcher_list;
> +
> +      gdb_matchers = PyObject_GetAttrString (gdb_python_module,
> +					     matchers_attr_str);
> +      if (gdb_matchers != NULL)
> +	{
> +	  py_xmethod_matcher_list = PySequence_Concat (temp,
> +							   gdb_matchers);

Left over TODO from xmethod rename I think:

	  py_xmethod_matcher_list = PySequence_Concat (temp, gdb_matchers);

> +	  Py_DECREF (temp);
> +	  Py_DECREF (gdb_matchers);
> +	  if (py_xmethod_matcher_list == NULL)
> +	    {
> +	      gdbpy_print_stack ();
> +	      do_cleanups (cleanups);
> +
> +	      return EXT_LANG_RC_ERROR;
> +	    }
> +	}
> +      else
> +	{
> +	  gdbpy_print_stack ();
> +	  Py_DECREF (py_xmethod_matcher_list);
> +	  do_cleanups (cleanups);
> +
> +	  return EXT_LANG_RC_ERROR;
> +	}
> +    }
> +
> +  /* Safe to make a cleanup for py_xmethod_matcher_list now as it
> +     will not change any more.  */
> +  make_cleanup_py_decref (py_xmethod_matcher_list);
> +
> +  list_iter = PyObject_GetIter (py_xmethod_matcher_list);
> +  if (list_iter == NULL)
> +    {
> +      gdbpy_print_stack ();
> +      do_cleanups (cleanups);
> +
> +      return EXT_LANG_RC_ERROR;
> +    }
> +  while ((matcher = PyIter_Next (list_iter)) != NULL)
> +    {
> +      PyObject *match_result = invoke_match_method (matcher, py_type,
> +						    method_name);
> +
> +      if (match_result == NULL)
> +	{
> +	  gdbpy_print_stack ();
> +	  Py_DECREF (matcher);
> +	  do_cleanups (cleanups);
> +
> +	  return EXT_LANG_RC_ERROR;
> +	}
> +      if (match_result == Py_None)
> +	; /* This means there was no match.  */
> +      else if (PySequence_Check (match_result))
> +	{
> +	  PyObject *iter = PyObject_GetIter (match_result);
> +	  PyObject *py_worker;
> +
> +	  if (iter == NULL)
> +	    {
> +	      gdbpy_print_stack ();
> +	      Py_DECREF (matcher);
> +	      Py_DECREF (match_result);
> +	      do_cleanups (cleanups);
> +
> +	      return EXT_LANG_RC_ERROR;
> +	    }
> +	  while ((py_worker = PyIter_Next (iter)) != NULL)
> +	    {
> +	      struct xmethod_worker *worker;
> +

Regarding not requiring user code to "enabled" handling:
Can we check the enabled flag here before pushing?

> +	      worker = new_python_xmethod_worker (py_worker, py_type);
> +	      VEC_safe_push (xmethod_worker_ptr, worker_vec, worker);
> +	      Py_DECREF (py_worker);
> +	    }
> +	  Py_DECREF (iter);
> +	  /* Report any error that could have occurred while iterating.  */
> +	  if (PyErr_Occurred ())
> +	    {
> +	      gdbpy_print_stack ();
> +	      Py_DECREF (matcher);
> +	      Py_DECREF (match_result);
> +	      do_cleanups (cleanups);
> +
> +	      return EXT_LANG_RC_ERROR;
> +	    }
> +	}
> +      else
> +	{
> +	  struct xmethod_worker *worker;
> +

Also here?  [check the "enabled" flag before pushing]

> +	  worker = new_python_xmethod_worker (match_result, py_type);
> +	  VEC_safe_push (xmethod_worker_ptr, worker_vec, worker);
> +	}
> +
> +      Py_DECREF (match_result);
> +      Py_DECREF (matcher);
> +    }
> +  Py_DECREF (list_iter);
> +  /* Report any error that could have occurred while iterating.  */
> +  if (PyErr_Occurred ())
> +    {
> +      gdbpy_print_stack ();
> +      do_cleanups (cleanups);
> +
> +      return EXT_LANG_RC_ERROR;
> +    }
> +
> +  do_cleanups (cleanups);
> +  *dm_vec = worker_vec;
> +
> +  return EXT_LANG_RC_OK;
> +}
> +
> +/* Implementation of get_xmethod_arg_types for Python.  */
> +
> +enum ext_lang_rc
> +gdbpy_get_xmethod_arg_types (const struct extension_language_defn *extlang,
> +				  struct xmethod_worker *worker,
> +				  int *nargs, struct type ***arg_types)

My notes say this arg list can be re-indented.

> +{
> +  struct gdbpy_worker_data *worker_data = worker->data;
> +  PyObject *py_worker = worker_data->worker;
> +  PyObject *get_arg_types_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 -1 so that any premature return from this function returns
> +     an invalid/unusable number of arg types.  */
> +  *nargs = -1;
> +
> +  cleanups = ensure_python_env (get_current_arch (), current_language);
> +
> +  get_arg_types_method =  PyObject_GetAttrString (py_worker,
> +						  get_arg_types_method_name);
> +  if (get_arg_types_method == NULL)
> +    {
> +      gdbpy_print_stack ();
> +      do_cleanups (cleanups);
> +
> +      return EXT_LANG_RC_ERROR;
> +    }
> +  make_cleanup_py_decref (get_arg_types_method);
> +
> +  py_argtype_list = PyObject_CallMethodObjArgs (py_worker,
> +						py_get_arg_types_method_name,
> +						NULL);
> +  if (py_argtype_list == NULL)
> +    {
> +      gdbpy_print_stack ();
> +      do_cleanups (cleanups);
> +
> +      return EXT_LANG_RC_ERROR;
> +    }
> +  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 EXT_LANG_RC_ERROR;
> +	}
> +
> +      list_iter = PyObject_GetIter (py_argtype_list);
> +      if (list_iter == NULL)
> +	{
> +	  gdbpy_print_stack ();
> +	  do_cleanups (cleanups);
> +
> +	  return EXT_LANG_RC_ERROR;
> +	}
> +      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)) != NULL)
> +	{
> +	  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_arg_types "
> +				 "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_arg_types method "
> +			   "of a debug method worker object is not a gdb.Type "
> +			   "object."));

Wrap the above PyErr_SetString call in {} since it's more than one line.

> +      else
> +	{
> +	  type_array[1] = arg_type;

I'd use "i" here instead of "1".

> +	  i++;
> +	}
> +    }
> +  if (PyErr_Occurred ())
> +    {
> +      gdbpy_print_stack ();
> +      do_cleanups (cleanups);
> +      xfree (type_array);
> +
> +      return EXT_LANG_RC_ERROR;
> +    }
> +
> +  /* Add the type of 'this' as the first argument.  */
> +  obj_type = type_object_to_type (worker_data->this_type);

Add comment explaining why passing 1 for "is const" is ok here:

> +  type_array[0] = make_cv_type (1, 0, lookup_pointer_type (obj_type), NULL);
> +  *nargs = i;
> +  *arg_types = type_array;
> +  do_cleanups (cleanups);
> +
> +  return EXT_LANG_RC_OK;
> +}
> +
> +/* Implementation of invoke_xmethod for Python.  */
> +
> +enum ext_lang_rc
> +gdbpy_invoke_xmethod (const struct extension_language_defn *extlang,
> +			   struct xmethod_worker *worker,
> +			   struct value *obj, struct value **args, int nargs,
> +			   struct value **result)

My notes say this arg list can be reindented.

> +{
> +  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 *res = NULL;
> +  struct gdbpy_worker_data *worker_data = worker->data;
> +  PyObject *xmethod_worker = worker_data->worker;
> +
> +  cleanups = ensure_python_env (get_current_arch (), current_language);
> +
> +  invoke_method =  PyObject_GetAttrString (xmethod_worker,
> +					   invoke_method_name);
> +  if (invoke_method == NULL)
> +    {
> +      gdbpy_print_stack ();
> +      do_cleanups (cleanups);
> +
> +      return EXT_LANG_RC_ERROR;
> +    }
> +  make_cleanup_py_decref (invoke_method);
> +

This whole block from here ...

> +  obj_type = check_typedef (value_type (obj));
> +  this_type = check_typedef (type_object_to_type (worker_data->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 EXT_LANG_RC_ERROR;
> +    }
> +  make_cleanup_py_decref (py_value_obj);

... to here needs to be wrapped in a TRY_CATCH.
There's several examples in python/*.c
The problem here is that check_typedef and value_cast can throw gdb
exceptions.  We need to catch them, flag them if necessary, and
return EXT_LANG_RC_ERROR (I think).

> +
> +  py_arg_tuple = PyTuple_New (nargs);
> +  if (py_arg_tuple == NULL)
> +    {
> +      gdbpy_print_stack ();
> +      do_cleanups (cleanups);
> +
> +      return EXT_LANG_RC_ERROR;
> +    }
> +  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 EXT_LANG_RC_ERROR;
> +	}
> +
> +      PyTuple_SET_ITEM (py_arg_tuple, i, py_value_arg);
> +    }
> +
> +  py_result = PyObject_CallMethodObjArgs (xmethod_worker,
> +					  py_invoke_method_name,
> +					  py_value_obj,
> +					  py_arg_tuple, NULL);
> +  if (py_result == NULL)
> +    {
> +      gdbpy_print_stack ();
> +      do_cleanups (cleanups);
> +
> +      return EXT_LANG_RC_ERROR;
> +    }
> +  make_cleanup_py_decref (py_result);
> +
> +  if (py_result != Py_None)
> +    {
> +      res = convert_value_from_python (py_result);
> +      if (res == NULL)
> +	{
> +	  gdbpy_print_stack ();
> +	  do_cleanups (cleanups);
> +
> +	  return EXT_LANG_RC_ERROR;
> +	}
> +    }
> +  else
> +    {
> +      res = allocate_value (lookup_typename (python_language, python_gdbarch,
> +					     "void", NULL, 0));
> +    }
> +
> +  *result = res;
> +  do_cleanups (cleanups);
> +
> +  return EXT_LANG_RC_OK;
> +}
  
Doug Evans May 28, 2014, 5:02 a.m. UTC | #2
Doug Evans <xdje42@gmail.com> writes:

> This whole block from here ...
>
>> +  obj_type = check_typedef (value_type (obj));
>> +  this_type = check_typedef (type_object_to_type (worker_data->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 EXT_LANG_RC_ERROR;
>> +    }
>> +  make_cleanup_py_decref (py_value_obj);
>
> ... to here needs to be wrapped in a TRY_CATCH.
> There's several examples in python/*.c
> The problem here is that check_typedef and value_cast can throw gdb
> exceptions.  We need to catch them, flag them if necessary, and
> return EXT_LANG_RC_ERROR (I think).

Ok, let's do this.

extension.c:invoke_xmethod will throw an error if this function
returns EXT_LANG_RC_ERROR:

  if (rc == EXT_LANG_RC_ERROR)
    {
      error (_("Error while invoking a xmethod defined in %s"),
	     worker->extlang->capitalized_name);
    }

So there's no real difference between a gdb-detected error in, say,
value_cast and a python-detected error from invoking the xmethod.
So why not have gdbpy_invoke_xmethod return a struct value *,
and if a python error is detected then throw a gdb error.

IOW:

struct value *
gdbpy_invoke_xmethod (const struct extension_language_defn *extlang,
		      struct xmethod_worker *worker,
		      struct value *obj, struct value **args, int nargs)
{
  ...
  if (error_return_from_python)
    {
      gdbpy_print_stack ();
      error (_("Error while executing Python code."));
    }
  ...
}
  
Doug Evans May 28, 2014, 5:41 a.m. UTC | #3
Siva Chandra <sivachandra@google.com> writes:

Hi.  Comments inline and at the end.

> diff --git a/gdb/python/lib/gdb/xmethod.py b/gdb/python/lib/gdb/xmethod.py
> new file mode 100644
> index 0000000..9d0deff
> --- /dev/null
> +++ b/gdb/python/lib/gdb/xmethod.py
> @@ -0,0 +1,254 @@
> +# Python side of the support for xmethods.
> +# Copyright (C) 2013-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 xmethods"""
> +
> +import gdb
> +import re
> +import sys
> +
> +
> +if sys.version_info[0] > 2:
> +    # Python 3 removed basestring and long
> +    basestring = str
> +    long = int
> +
> +
> +class XMethod(object):
> +    """Base class (or a prototype) for an xmethod description.
> +
> +    Currently, the description only requires only 'name' and 'enabled'
> +    attributes.  Description objects are managed by 'XMethodMatcher'
> +    objects (see below).

Please add text here that says this class is only used when
XMethodMatcher.methods is used, and that this class specifies the
interface of XMethodMatcher.methods objects.

> +
> +    Attributes:
> +        name: The name of the xmethod.
> +        enabled: A boolean indicating if the xmethod is enabled.
> +    """
> +
> +    def __init__(self, name):
> +        self.name = name
> +        self.enabled = True
> +
> +
> +class XMethodMatcher(object):
> +    """Abstract base class for matching an xmethod.
> +
> +    When looking for xmethods, GDB invokes the `match' method of a
> +    registered xmethod matcher to match the object type and method name.
> +    The `match' method in concrete classes derived from this class should
> +    return an `XMethodWorker' object, or a list of `XMethodWorker'
> +    objects if there is a match (see below for 'XMethodWorker' class).
> +
> +    Attributes:
> +        name: The name of the matcher.
> +        enabled: A boolean indicating if the matcher is enabled.
> +        methods: A sequence of objects of type 'XMethod', or objects
> +            which have at least the attributes of an 'XMethod' object.
> +            This list is used by the 'enable'/'disable'/'info' commands to
> +            enable/disable/list the xmethods registered with GDB.  See
> +            the 'match' method below to know how this sequence is used.
> +    """
> +
> +    def __init__(self, name):
> +        """
> +        Args:
> +            name: An identifying name for the xmethod or the group of
> +                  xmethods 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 an XMethodWorker object, or a
> +        sequence of 'XMethodWorker' objects.  Only those xmethod workers
> +        whose corresponding 'XMethod' 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("XMethodMatcher match")
> +
> +
> +class XMethodWorker(object):
> +    """Base class for all xmethod workers defined in Python.
> +
> +    An xmethod worker is an object which matches the method arguments, and
> +    invokes the method when GDB wants it to.  Internally, GDB first invokes the
> +    'get_arg_types' method to perform overload resolution.  If GDB selects to
> +    invoke this Python xmethod, then it invokes it via the overridden
> +    'invoke' method.
> +
> +    Derived classes should override the 'get_arg_types' and 'invoke' methods.
> +    """
> +
> +    def get_arg_types(self):
> +        """Return arguments types of an xmethod.
> +
> +        A sequence of gdb.Type objects corresponding to the arguments of the
> +        xmethod are returned.  If the xmethod takes no arguments, then 'None'
> +        or an empty sequence is returned.  If the xmethod takes only a single
> +        argument, then a gdb.Type object or a sequence with a single gdb.Type
> +        element is returned.
> +        """
> +        raise NotImplementedError("XMethod get_arg_types")
> +
> +    def invoke(self, obj, args):
> +        """Invoke the xmethod.
> +
> +        Args:
> +            obj: The gdb.Value of the object on which the method is to be
> +                 invoked.
> +            args: The tuple of arguments to the method.  Each element of the
> +                  tuple is a gdb.Value object.
> +
> +        Returns:
> +            A gdb.Value corresponding to the value returned by the xmethod.
> +            Returns 'None' if the method does not return anything.
> +        """
> +        raise NotImplementedError("XMethod invoke")
> +
> +
> +class SimpleXMethodMatcher(XMethodMatcher):
> +    """A utility class to implement simple xmethod mathers and workers.
> +
> +    See the __init__ method below for information on how instances of this
> +    class can be used.
> +
> +    For simple classes and methods, one can choose to use this class.  For
> +    complex xmethods, which need to replace/implement template methods on
> +    possibly template classes, one should implement their own xmethod
> +    matchers and workers.  See py-xmethods.py in testsuite/gdb.python
> +    directory of the GDB source tree for examples.
> +    """
> +
> +    class SimpleXMethodWorker(XMethodWorker):
> +        def __init__(self, method_function, arg_types):
> +            self._arg_types = arg_types
> +            self._method_function = method_function
> +
> +        def get_arg_types(self):
> +            return self._arg_types
> +
> +        def invoke(self, obj, args):
> +            return self._method_function(obj, *args)
> +
> +
> +    def __init__(self, name, class_matcher, method_matcher, method_function,
> +                 *arg_types):
> +        """
> +        Args:
> +            name: Name of the xmethod matcher.
> +            class_matcher: A regular expression used to match the name of the
> +                class whose method this xmethod is implementing/replacing.
> +            method_matcher: A regular expression used to match the name of the
> +                method this xmethod is implementing/replacing.
> +            method_function: A Python callable which would be called via the
> +                'invoke' method of the worker returned by the objects of this
> +                class.  This callable should accept the object (*this) as the
> +                first argument followed by the rest of the arguments to the
> +                method. All arguments to this function should be gdb.Value
> +                objects.
> +            arg_types: The gdb.Type objects corresponding to the arguments that
> +                this xmethod takes. It can be None, or an empty sequence,
> +                or a single gdb.Type object, or a sequence of gdb.Type objects.
> +        """
> +        XMethodMatcher.__init__(self, name)
> +        assert callable(method_function), (
> +            "The 'method_function' argument to 'SimpleXMethodMatcher' "
> +            "__init__ method should be a callable.")
> +        self._method_function = method_function
> +        self._class_matcher = class_matcher
> +        self._method_matcher = method_matcher
> +        self._arg_types = arg_types
> +
> +    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 SimpleXMethodMatcher.SimpleXMethodWorker(
> +                self._method_function, self._arg_types)

Hi.  Reading this got a bit confusing until I checked the pretty-printer
support. Note that the baseclass XMethodMatcher has an attribute, methods,
that is not used and not needed by derived class SimpleXMethodMatcher.
XMethodMatcher.methods is present for the same reason as
PrettyPrinter.subprinters, documented like this in python/lib/gdb/printing.py:

    # While one might want to push subprinters into the subclass, it's
    # present here to formalize such support to simplify
    # commands/pretty_printers.py.

Please add a comment identical to this one to XMethodMatcher.

Plus,
the description for PrettyPrinter.subprinters has this to say
about the value None"

            Or this is None if there are no subprinters.

Please add identical text to XMethodMatcher.methods.
[s/subprinters/methods/ of course]

---

Another thing occurs to me.
Pretty-printers are invoked, initially, via __call__, not via a "print"
method or some such.
It would be more python-esque if XMethodMatcher.match was renamed __call__
and XMethodWorker.invoke was renamed __call__.

Finally, IWBN if XMethodWorker.__call__ can be written using the same
arg list as the c++ method (instead of the "args" argument that exists
now).  I don't know python well enough to say if this is possible,
but if it is we should do that.
I tried the following simple experiment that gives me hope this is possible.

---snip---
class XMethodWorker(object):
    def __call__(self, obj):
        raise NotImplementedError("XMethodWorker invoke")

class MyXMWorker1(XMethodWorker):
    def __call__(self, obj, arg1):
        return arg1 + 1

class MyXMWorker2(XMethodWorker):
    def __call__(self, obj, arg1, arg2):
        return arg1 + arg2

this = 42
foo1 = MyXMWorker1()
foo2 = MyXMWorker2()

print "%d" % foo1(this, 1)
print "%d" % foo2(this, 1, 2)
---snip---

bash$ python foo.py
2
3
bash$
  
Siva Chandra Reddy May 28, 2014, 7:12 p.m. UTC | #4
On Tue, May 27, 2014 at 10:41 PM, Doug Evans <xdje42@gmail.com> wrote:
> Another thing occurs to me.
> Pretty-printers are invoked, initially, via __call__, not via a "print"
> method or some such.
> It would be more python-esque if XMethodMatcher.match was renamed __call__
> and XMethodWorker.invoke was renamed __call__.

While I agree XMethodWorker.invoke can be removed and we could make
XMethodWorker a callable, I am not sure we want to make XMethodMatcher
a callable. I know pretty printers are callables but do not know the
reason why they are so (probably because there is an old way and a new
way of writing pretty printers and both have to be supported). For me,
a __call__ method in Python is like operator() in C++ which I feel
should be used only if it is meaningful to make the objects callable.
Even for the XMethodWorker, I preferred a method 'invoke' over making
workers callables because they are named as workers and not as
methods. The only reason I had to bring in the notion of XMethods
(which are used only for enable/disable) and XMethodWorker is because
I had to ape the pretty printer setup. I propose a slightly different
design here which does not ape the pretty printers completely but
makes it less confusing:

1. Have XMethodMatchers with a method named 'match'. Matchers have an
attribute 'enabled'. GDB invokes the 'match' method on registered
matchers if they are enabled. On a match, the matcher returns a
sequence of matching and enabled XMethods. See #2 to know what
XMethods are. An XMethodMatcher also has an attribute 'method', which
is a sequence of XMethods the matcher manages. This provides a way to
enable/disable individual XMethods from enable/disable commands.
2. Have XMethods which are callables, but also have a method
'get_arg_types'. XMethods also have an 'enabled' attribute to indicate
whether they are enabled or not. GDB calls an XMethod (they are
callables) if it determines that the XMethod is the best overload
match.

> Finally, IWBN if XMethodWorker.__call__ can be written using the same
> arg list as the c++ method (instead of the "args" argument that exists
> now).

This can be done. I did play with this idea in the past, but do not
remember now as to why I abandoned it.
  
Doug Evans May 28, 2014, 8:30 p.m. UTC | #5
On Wed, May 28, 2014 at 12:12 PM, Siva Chandra <sivachandra@google.com> wrote:
> On Tue, May 27, 2014 at 10:41 PM, Doug Evans <xdje42@gmail.com> wrote:
>> Another thing occurs to me.
>> Pretty-printers are invoked, initially, via __call__, not via a "print"
>> method or some such.
>> It would be more python-esque if XMethodMatcher.match was renamed __call__
>> and XMethodWorker.invoke was renamed __call__.
>
> While I agree XMethodWorker.invoke can be removed and we could make
> XMethodWorker a callable, I am not sure we want to make XMethodMatcher
> a callable. I know pretty printers are callables but do not know the
> reason why they are so (probably because there is an old way and a new
> way of writing pretty printers and both have to be supported). For me,
> a __call__ method in Python is like operator() in C++ which I feel
> should be used only if it is meaningful to make the objects callable.
> Even for the XMethodWorker, I preferred a method 'invoke' over making
> workers callables because they are named as workers and not as
> methods. The only reason I had to bring in the notion of XMethods
> (which are used only for enable/disable) and XMethodWorker is because
> I had to ape the pretty printer setup. I propose a slightly different
> design here which does not ape the pretty printers completely but
> makes it less confusing:
>
> 1. Have XMethodMatchers with a method named 'match'. Matchers have an
> attribute 'enabled'. GDB invokes the 'match' method on registered
> matchers if they are enabled. On a match, the matcher returns a
> sequence of matching and enabled XMethods. See #2 to know what
> XMethods are. An XMethodMatcher also has an attribute 'method', which
> is a sequence of XMethods the matcher manages. This provides a way to
> enable/disable individual XMethods from enable/disable commands.
> 2. Have XMethods which are callables, but also have a method
> 'get_arg_types'. XMethods also have an 'enabled' attribute to indicate
> whether they are enabled or not. GDB calls an XMethod (they are
> callables) if it determines that the XMethod is the best overload
> match.

By analogy, what this does is merge SubPrettyPrinter with the
pretty-printer worker object.

FAOD,

XMethodMatcher
  attributes: name, enabled, methods, match

XMethod
  attributes: name, enabled, get_arg_types, __call__

"works for me"
  
Siva Chandra Reddy May 28, 2014, 8:44 p.m. UTC | #6
On Tue, May 27, 2014 at 10:02 PM, Doug Evans <xdje42@gmail.com> wrote:
> Ok, let's do this.
>
> extension.c:invoke_xmethod will throw an error if this function
> returns EXT_LANG_RC_ERROR:
>
>   if (rc == EXT_LANG_RC_ERROR)
>     {
>       error (_("Error while invoking a xmethod defined in %s"),
>              worker->extlang->capitalized_name);
>     }

I did not understand this part. Since you suggest below that
gdbpy_invoke_xmethod return value * and throw GDB errors for Python
errors as well, where would invoke_xmethod get RC from?

>
> So there's no real difference between a gdb-detected error in, say,
> value_cast and a python-detected error from invoking the xmethod.
> So why not have gdbpy_invoke_xmethod return a struct value *,
> and if a python error is detected then throw a gdb error.
>
> IOW:
>
> struct value *
> gdbpy_invoke_xmethod (const struct extension_language_defn *extlang,
>                       struct xmethod_worker *worker,
>                       struct value *obj, struct value **args, int nargs)
> {
>   ...
>   if (error_return_from_python)
>     {
>       gdbpy_print_stack ();
>       error (_("Error while executing Python code."));
>     }
>   ...
> }
  
Doug Evans May 28, 2014, 8:58 p.m. UTC | #7
On Wed, May 28, 2014 at 1:44 PM, Siva Chandra <sivachandra@google.com> wrote:
> On Tue, May 27, 2014 at 10:02 PM, Doug Evans <xdje42@gmail.com> wrote:
>> Ok, let's do this.
>>
>> extension.c:invoke_xmethod will throw an error if this function
>> returns EXT_LANG_RC_ERROR:
>>
>>   if (rc == EXT_LANG_RC_ERROR)
>>     {
>>       error (_("Error while invoking a xmethod defined in %s"),
>>              worker->extlang->capitalized_name);
>>     }
>
> I did not understand this part. Since you suggest below that
> gdbpy_invoke_xmethod return value * and throw GDB errors for Python
> errors as well, where would invoke_xmethod get RC from?

invoke_method would look like this:

struct value *
invoke_xmethod (struct xmethod_worker *worker, struct value *obj,
                struct value **args, int nargs)
{
  gdb_assert (worker->extlang->ops->invoke_xmethod != NULL);

  return worker->extlang->ops->invoke_xmethod (worker->extlang, worker,
                                               obj, args, nargs);
}

Sorry for the confusion.
  

Patch

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index f2c16ec..bb86602 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -344,6 +344,7 @@  SUBDIR_PYTHON_OBS = \
 	py-breakpoint.o \
 	py-cmd.o \
 	py-continueevent.o \
+	py-xmethods.o \
 	py-event.o \
 	py-evtregistry.o \
 	py-evts.o \
@@ -380,6 +381,7 @@  SUBDIR_PYTHON_SRCS = \
 	python/py-breakpoint.c \
 	python/py-cmd.c \
 	python/py-continueevent.c \
+	python/py-xmethods.c \
 	python/py-event.c \
 	python/py-evtregistry.c \
 	python/py-evts.c \
@@ -2378,6 +2380,10 @@  py-continueevent.o: $(srcdir)/python/py-continueevent.c
 	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-continueevent.c
 	$(POSTCOMPILE)
 
+py-xmethods.o: $(srcdir)/python/py-xmethods.c
+	$(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-xmethods.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 3288e50..b9fcc03 100644
--- a/gdb/data-directory/Makefile.in
+++ b/gdb/data-directory/Makefile.in
@@ -63,8 +63,10 @@  PYTHON_FILES = \
 	gdb/types.py \
 	gdb/printing.py \
 	gdb/prompt.py \
+	gdb/xmethod.py \
 	gdb/command/bound_registers.py \
 	gdb/command/__init__.py \
+	gdb/command/xmethods.py \
 	gdb/command/frame_filters.py \
 	gdb/command/type_printers.py \
 	gdb/command/pretty_printers.py \
diff --git a/gdb/python/lib/gdb/__init__.py b/gdb/python/lib/gdb/__init__.py
index 95a76c2..557e168 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 xmethod matchers.
+xmethods = []
 # Initial frame filters.
 frame_filters = {}
 
diff --git a/gdb/python/lib/gdb/command/xmethods.py b/gdb/python/lib/gdb/command/xmethods.py
new file mode 100644
index 0000000..f61e7fb
--- /dev/null
+++ b/gdb/python/lib/gdb/command/xmethods.py
@@ -0,0 +1,272 @@ 
+# Xmethod commands.
+# Copyright 2013-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/>.
+
+import gdb
+import re
+
+"""GDB commands for working with xmethods."""
+
+
+def validate_xm_regexp(part_name, regexp):
+    try:
+        return re.compile(regexp)
+    except SyntaxError:
+        raise SyntaxError("Invalid %s regexp: %s", part_name, regexp)
+
+
+def parse_xm_command_args(arg):
+    """Parses the arguments passed to a xmethod command.
+
+    Arguments:
+        arg: The argument string passed to a xmethod command.
+
+    Returns:
+        A 3-tuple: (<locus matching regular expression>,
+                    <matcher matching regular expression>,
+                    <name matching regular experession>)
+    """
+    argv = gdb.string_to_argv(arg)
+    argc = len(argv)
+    if argc > 2:
+        raise SyntaxError("Too many arguments to command.")
+    locus_regexp = ""
+    matcher_name_regexp = ""
+    xm_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:
+            xm_name_regexp = parts[1]
+    if xm_name_regexp:
+        name_re = validate_xm_regexp("xmethod name", xm_name_regexp)
+    else:
+        name_re = None
+    return (validate_xm_regexp("locus", locus_regexp),
+            validate_xm_regexp("matcher name", matcher_name_regexp),
+            name_re)
+
+
+def get_global_method_matchers(locus_re, matcher_re):
+    """Returns a dict of matching globally registered xmethods.
+
+    Arguments:
+        locus_re: Even though only globally registered xmethods are
+                  looked up, they will be looked up only if 'global' matches
+                  LOCUS_RE.
+        matcher_re: The regular expression matching the names of xmethods.
+
+    Returns:
+        A dict of matching globally registered xmethod matchers.  The only
+        key in the dict will be 'global'.
+    """
+    locus_str = "global"
+    xm_dict = { locus_str: [] }
+    if locus_re.match("global"):
+        xm_dict[locus_str].extend(
+            [m for m in gdb.xmethods if matcher_re.match(m.name)])
+    return xm_dict
+
+
+def get_method_matchers_in_loci(loci, locus_re, matcher_re):
+    """Returns a dict of matching registered xmethods in the LOCI.
+
+    Arguments:
+        loci: The list of loci to lookup matching xmethods in.
+        locus_re: Xmethod matchers will be looked up in a particular locus
+                  only if its filename matches the regular expression LOCUS_RE.
+        matcher_re: The regular expression to match the xmethod matcher
+                    names.
+
+    Returns:
+        A dict of matching xmethod matchers.  The keys of the dict are the
+        filenames of the loci the xmethod matchers belong to.
+    """
+    xm_dict = {}
+    for locus in loci:
+        if isinstance(locus, gdb.Progspace):
+            if (not locus_re.match(locus.filename) and
+                not locus_re.match('progspace')):
+                continue
+            locus_type = "progspace"
+        else:
+            if not locus_re.match(locus.filename):
+                continue
+            locus_type = "objfile"
+        locus_str = "%s %s" % (locus_type, locus.filename)
+        xm_dict[locus_str] = [
+            m for m in locus.xmethods if matcher_re.match(m.name)]
+    return xm_dict
+
+
+def print_xm_info(xm_dict, name_re):
+    """Print a dictionary of xmethods."""
+    def get_status_string(method):
+        if not m.enabled:
+            return " [disabled]"
+        else:
+          return ""
+
+    if not xm_dict:
+        return
+    for locus_str in xm_dict:
+        if not xm_dict[locus_str]:
+            continue
+        print ("Xmethods in %s:" % locus_str)
+        for matcher in xm_dict[locus_str]:
+            print ("  %s" % matcher.name)
+            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_string(m)))
+
+
+def set_xm_status1(xm_dict, name_re, status):
+    """Set the status (enabled/disabled) of a dictionary of xmethods."""
+    for locus_str, matchers in xm_dict.iteritems():
+        for matcher in matchers:
+            if not name_re:
+                # If the name regex is missing, then set the status of the
+                # matcher and move on.
+                matcher.enabled = status
+                continue
+            if not matcher.methods:
+                # The methods attribute could be None.  Move on.
+                continue
+            for m in matcher.methods:
+                if name_re.match(m.name):
+                    m.enabled = status
+
+
+def set_xm_status(arg, status):
+    """Set the status (enabled/disabled) of xmethods 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_xm_command_args(arg)
+    set_xm_status1(get_global_method_matchers(locus_re, matcher_re), name_re,
+                   status)
+    set_xm_status1(
+        get_method_matchers_in_loci(
+            [gdb.current_progspace()], locus_re, matcher_re),
+        name_re,
+        status)
+    set_xm_status1(
+        get_method_matchers_in_loci(gdb.objfiles(), locus_re, matcher_re),
+        name_re,
+        status)
+
+
+class InfoXMethod(gdb.Command):
+    """GDB command to list registered xmethod matchers.
+
+    Usage: info xmethod [locus-regexp [name-regexp]]
+
+    LOCUS-REGEXP is a regular expression matching the location of the
+    xmethod matchers.  If it is omitted, all registered xmethod matchers
+    from all loci are listed.  A locus could be 'global', a regular expression
+    matching the current program space's filename, or a regular expression
+    matching filenames of objfiles.  Locus could be 'progspace' to specify that
+    only xmethods from the current progspace should be listed.
+
+    NAME-REGEXP is a regular expression matching the names of xmethod
+    matchers.  If this omitted for a specified locus, then all registered
+    xmethods in the locus are listed.  To list only a certain xmethods
+    managed by a single matcher, the name regexp can be specified as
+    matcher-name-regexp;xmethod-name-regexp.
+    """
+
+    def __init__(self):
+        super(InfoXMethod, self).__init__("info xmethod",
+                                          gdb.COMMAND_DATA)
+
+    def invoke(self, arg, from_tty):
+        locus_re, matcher_re, name_re = parse_xm_command_args(arg)
+        print_xm_info(get_global_method_matchers(locus_re, matcher_re),
+                      name_re)
+        print_xm_info(
+            get_method_matchers_in_loci(
+                [gdb.current_progspace()], locus_re, matcher_re),
+            name_re)
+        print_xm_info(
+            get_method_matchers_in_loci(gdb.objfiles(), locus_re, matcher_re),
+            name_re)
+
+
+class EnableXMethod(gdb.Command):
+    """GDB command to enable a specified (group of) xmethod(s).
+
+    Usage: enable xmethod [locus-regexp [name-regexp]]
+
+    LOCUS-REGEXP is a regular expression matching the location of the
+    xmethod matchers.  If it is omitted, all registered xmethods matchers
+    from all loci are enabled.  A locus could be 'global', a regular expression
+    matching the current program space's filename, or a regular expression
+    matching filenames of objfiles.  Locus could be 'progspace' to specify that
+    only xmethods from the current progspace should be enabled.
+
+    NAME-REGEXP is a regular expression matching the names of xmethods
+    within a given locus.  If this omitted for a specified locus, then all
+    registered xmethod matchers in the locus are enabled.  To enable only
+    a certain xmethods managed by a single matcher, the name regexp can be
+    specified as matcher-name-regexp;xmethod-name-regexp.
+    """
+
+    def __init__(self):
+        super(EnableXMethod, self).__init__("enable xmethod",
+                                            gdb.COMMAND_DATA)
+
+    def invoke(self, arg, from_tty):
+        set_xm_status(arg, True)
+
+
+class DisableXMethod(gdb.Command):
+    """GDB command to disable a specified (group of) xmethod(s).
+
+    Usage: disable xmethod [locus-regexp [name-regexp]]
+
+    LOCUS-REGEXP is a regular expression matching the location of the
+    xmethod matcherss.  If it is omitted, all registered xmethod matchers
+    from all loci are disabled.  A locus could be 'global', a regular
+    expression matching the current program space's filename, or a regular
+    expression filenames of objfiles. Locus could be 'progspace' to specify
+    that only xmethods from the current progspace should be disabled.
+
+    NAME-REGEXP is a regular expression matching the names of xmethods
+    within a given locus.  If this omitted for a specified locus, then all
+    registered xmethod matchers in the locus are disabled.  To disable
+    only a certain xmethods managed by a single matcher, the name regexp
+    can be specified as matcher-name-regexp;xmethod-name-regexp.
+    """
+
+    def __init__(self):
+        super(DisableXMethod, self).__init__("disable xmethod",
+                                             gdb.COMMAND_DATA)
+
+    def invoke(self, arg, from_tty):
+        set_xm_status(arg, False)
+
+
+def register_xmethod_commands():
+    """Installs the xmethod commands."""
+    InfoXMethod()
+    EnableXMethod()
+    DisableXMethod()
+
+
+register_xmethod_commands()
diff --git a/gdb/python/lib/gdb/xmethod.py b/gdb/python/lib/gdb/xmethod.py
new file mode 100644
index 0000000..9d0deff
--- /dev/null
+++ b/gdb/python/lib/gdb/xmethod.py
@@ -0,0 +1,254 @@ 
+# Python side of the support for xmethods.
+# Copyright (C) 2013-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 xmethods"""
+
+import gdb
+import re
+import sys
+
+
+if sys.version_info[0] > 2:
+    # Python 3 removed basestring and long
+    basestring = str
+    long = int
+
+
+class XMethod(object):
+    """Base class (or a prototype) for an xmethod description.
+
+    Currently, the description only requires only 'name' and 'enabled'
+    attributes.  Description objects are managed by 'XMethodMatcher'
+    objects (see below).
+
+    Attributes:
+        name: The name of the xmethod.
+        enabled: A boolean indicating if the xmethod is enabled.
+    """
+
+    def __init__(self, name):
+        self.name = name
+        self.enabled = True
+
+
+class XMethodMatcher(object):
+    """Abstract base class for matching an xmethod.
+
+    When looking for xmethods, GDB invokes the `match' method of a
+    registered xmethod matcher to match the object type and method name.
+    The `match' method in concrete classes derived from this class should
+    return an `XMethodWorker' object, or a list of `XMethodWorker'
+    objects if there is a match (see below for 'XMethodWorker' class).
+
+    Attributes:
+        name: The name of the matcher.
+        enabled: A boolean indicating if the matcher is enabled.
+        methods: A sequence of objects of type 'XMethod', or objects
+            which have at least the attributes of an 'XMethod' object.
+            This list is used by the 'enable'/'disable'/'info' commands to
+            enable/disable/list the xmethods registered with GDB.  See
+            the 'match' method below to know how this sequence is used.
+    """
+
+    def __init__(self, name):
+        """
+        Args:
+            name: An identifying name for the xmethod or the group of
+                  xmethods 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 an XMethodWorker object, or a
+        sequence of 'XMethodWorker' objects.  Only those xmethod workers
+        whose corresponding 'XMethod' 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("XMethodMatcher match")
+
+
+class XMethodWorker(object):
+    """Base class for all xmethod workers defined in Python.
+
+    An xmethod worker is an object which matches the method arguments, and
+    invokes the method when GDB wants it to.  Internally, GDB first invokes the
+    'get_arg_types' method to perform overload resolution.  If GDB selects to
+    invoke this Python xmethod, then it invokes it via the overridden
+    'invoke' method.
+
+    Derived classes should override the 'get_arg_types' and 'invoke' methods.
+    """
+
+    def get_arg_types(self):
+        """Return arguments types of an xmethod.
+
+        A sequence of gdb.Type objects corresponding to the arguments of the
+        xmethod are returned.  If the xmethod takes no arguments, then 'None'
+        or an empty sequence is returned.  If the xmethod takes only a single
+        argument, then a gdb.Type object or a sequence with a single gdb.Type
+        element is returned.
+        """
+        raise NotImplementedError("XMethod get_arg_types")
+
+    def invoke(self, obj, args):
+        """Invoke the xmethod.
+
+        Args:
+            obj: The gdb.Value of the object on which the method is to be
+                 invoked.
+            args: The tuple of arguments to the method.  Each element of the
+                  tuple is a gdb.Value object.
+
+        Returns:
+            A gdb.Value corresponding to the value returned by the xmethod.
+            Returns 'None' if the method does not return anything.
+        """
+        raise NotImplementedError("XMethod invoke")
+
+
+class SimpleXMethodMatcher(XMethodMatcher):
+    """A utility class to implement simple xmethod mathers and workers.
+
+    See the __init__ method below for information on how instances of this
+    class can be used.
+
+    For simple classes and methods, one can choose to use this class.  For
+    complex xmethods, which need to replace/implement template methods on
+    possibly template classes, one should implement their own xmethod
+    matchers and workers.  See py-xmethods.py in testsuite/gdb.python
+    directory of the GDB source tree for examples.
+    """
+
+    class SimpleXMethodWorker(XMethodWorker):
+        def __init__(self, method_function, arg_types):
+            self._arg_types = arg_types
+            self._method_function = method_function
+
+        def get_arg_types(self):
+            return self._arg_types
+
+        def invoke(self, obj, args):
+            return self._method_function(obj, *args)
+
+
+    def __init__(self, name, class_matcher, method_matcher, method_function,
+                 *arg_types):
+        """
+        Args:
+            name: Name of the xmethod matcher.
+            class_matcher: A regular expression used to match the name of the
+                class whose method this xmethod is implementing/replacing.
+            method_matcher: A regular expression used to match the name of the
+                method this xmethod is implementing/replacing.
+            method_function: A Python callable which would be called via the
+                'invoke' method of the worker returned by the objects of this
+                class.  This callable should accept the object (*this) as the
+                first argument followed by the rest of the arguments to the
+                method. All arguments to this function should be gdb.Value
+                objects.
+            arg_types: The gdb.Type objects corresponding to the arguments that
+                this xmethod takes. It can be None, or an empty sequence,
+                or a single gdb.Type object, or a sequence of gdb.Type objects.
+        """
+        XMethodMatcher.__init__(self, name)
+        assert callable(method_function), (
+            "The 'method_function' argument to 'SimpleXMethodMatcher' "
+            "__init__ method should be a callable.")
+        self._method_function = method_function
+        self._class_matcher = class_matcher
+        self._method_matcher = method_matcher
+        self._arg_types = arg_types
+
+    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 SimpleXMethodMatcher.SimpleXMethodWorker(
+                self._method_function, self._arg_types)
+
+
+# A helper function for register_xmethod_matcher which returns an error
+# object if MATCHER is not having the requisite attributes in the proper
+# format.
+
+def validate_xmethod_matcher(matcher):
+    if not hasattr(matcher, "match"):
+        return TypeError("Xmethod matcher is missing method: match")
+    if not hasattr(matcher, "name"):
+        return TypeError("Xmethod matcher is missing attribute: name")
+    if not hasattr(matcher, "enabled"):
+        return TypeError("Xmethod matcher is missing attribute: enabled")
+    if not isinstance(matcher.name, basestring):
+        return TypeError("Attribute 'name' of xmethod matcher is not a "
+                         "string")
+    if matcher.name.find(";") >= 0:
+        return ValueError("Xmethod matcher name cannot contain ';' in it")
+
+
+# A helper function for register_xmethod_matcher which looks up an 
+# xmethod matcher with NAME in LOCUS.  Returns the index of the xmethod
+# matcher in 'xmethods' sequence attribute of the LOCUS.
+
+def lookup_xmethod_matcher(locus, name):
+    i = 0
+    for m in locus.xmethods:
+        if m.name == name:
+            return i
+        i = i + 1
+
+
+def register_xmethod_matcher(locus, matcher, replace=False):
+    """Registers a xmethod matcher MATCHER with a LOCUS.
+
+    Arguments:
+        locus: The locus in which the xmethods should be registered.  It
+               can be 'None' to indicate that the xmethods should be
+               registered globally. Or, it could be a gdb.Objfile or a
+               gdb.Progspace object in which the xmethods should be
+               registered.
+        matcher: The xmethod matcher to register with the LOCUS.  It
+            should be an instance of 'XMethodMatcher' class.
+        replace: If True, replace any existing xmethod 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_xmethod_matcher(matcher)
+    if err:
+        raise err
+    if not locus:
+        locus = gdb
+    if locus == gdb:
+        locus_name = "global"
+    else:
+        locus_name = locus.filename
+    index = lookup_xmethod_matcher(locus, matcher.name)
+    if index:
+        if replace:
+            del locus.xmethods[index]
+        else:
+            raise RuntimeError("Xmethod matcher already registered with "
+                               "%s: %s" % (locus_name, new_method.name))
+    if gdb.parameter("verbose"):
+        gdb.write("Registering xmethod matcher '%s' with %s' ...\n")
+    locus.xmethods.insert(0, matcher)
diff --git a/gdb/python/py-objfile.c b/gdb/python/py-objfile.c
index 97fb0be..5d00d62 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 *xmethods;
 } 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->xmethods);
   Py_TYPE (self)->tp_free (self);
 }
 
@@ -99,6 +103,13 @@  objfpy_new (PyTypeObject *type, PyObject *args, PyObject *keywords)
 	  Py_DECREF (self);
 	  return NULL;
 	}
+
+      self->xmethods = PyList_New (0);
+      if (self->xmethods == 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 'xmethods' attribute.  */
+
+PyObject *
+objfpy_get_xmethods (PyObject *o, void *ignore)
+{
+  objfile_object *self = (objfile_object *) o;
+
+  Py_INCREF (self->xmethods);
+  return self->xmethods;
+}
+
 /* Set the 'type_printers' attribute.  */
 
 static int
@@ -292,6 +314,13 @@  objfile_to_objfile_object (struct objfile *objfile)
 	      return NULL;
 	    }
 
+	  object->xmethods = PyList_New (0);
+	  if (object->xmethods == 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 },
+  { "xmethods", objfpy_get_xmethods, NULL,
+    "Debug methods.", NULL },
   { NULL }
 };
 
diff --git a/gdb/python/py-progspace.c b/gdb/python/py-progspace.c
index db4c564..b0092c5 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 *xmethods;
 } 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->xmethods);
   Py_TYPE (self)->tp_free (self);
 }
 
@@ -107,6 +111,13 @@  pspy_new (PyTypeObject *type, PyObject *args, PyObject *keywords)
 	  Py_DECREF (self);
 	  return NULL;
 	}
+
+      self->xmethods = PyList_New (0);
+      if (self->xmethods == 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 'xmethods' attribute.  */
+
+PyObject *
+pspy_get_xmethods (PyObject *o, void *ignore)
+{
+  pspace_object *self = (pspace_object *) o;
+
+  Py_INCREF (self->xmethods);
+  return self->xmethods;
+}
+
 /* Set the 'type_printers' attribute.  */
 
 static int
@@ -297,6 +319,13 @@  pspace_to_pspace_object (struct program_space *pspace)
 	      return NULL;
 	    }
 
+	  object->xmethods = PyList_New (0);
+	  if (object->xmethods == NULL)
+	    {
+	      Py_DECREF (object);
+	      return NULL;
+	    }
+
 	  set_program_space_data (pspace, pspy_pspace_data_key, object);
 	}
     }
@@ -329,6 +358,8 @@  static PyGetSetDef pspace_getset[] =
     "Frame filters.", NULL },
   { "type_printers", pspy_get_type_printers, pspy_set_type_printers,
     "Type printers.", NULL },
+  { "xmethods", pspy_get_xmethods, NULL,
+    "Debug methods.", NULL },
   { NULL }
 };
 
diff --git a/gdb/python/py-xmethods.c b/gdb/python/py-xmethods.c
new file mode 100644
index 0000000..0868c9f
--- /dev/null
+++ b/gdb/python/py-xmethods.c
@@ -0,0 +1,648 @@ 
+/* Support for debug methods in Python.
+
+   Copyright (C) 2013-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 "extension-priv.h"
+#include "objfiles.h"
+#include "value.h"
+#include "language.h"
+
+#include "python.h"
+#include "python-internal.h"
+
+static const char enabled_field_name[] = "enabled";
+static const char match_method_name[] = "match";
+static const char get_arg_types_method_name[] = "get_arg_types";
+static const char invoke_method_name[] = "invoke";
+static const char matchers_attr_str[] = "xmethods";
+
+static PyObject *py_match_method_name = NULL;
+static PyObject *py_get_arg_types_method_name = NULL;
+static PyObject *py_invoke_method_name = NULL;
+
+struct gdbpy_worker_data
+{
+  PyObject *worker;
+  PyObject *this_type;
+};
+
+static struct xmethod_worker *new_python_xmethod_worker
+  (PyObject *item, PyObject *py_obj_type);
+
+/* Implementation of free_xmethod_worker_data for Python.  */
+
+void
+gdbpy_free_xmethod_worker_data
+  (const struct extension_language_defn *extlang, void *data)
+{
+  struct gdbpy_worker_data *worker_data = data;
+
+  gdb_assert (worker_data->worker != NULL && worker_data->this_type != NULL);
+
+  Py_DECREF (worker_data->worker);
+  Py_DECREF (worker_data->this_type);
+  xfree (worker_data);
+}
+
+/* Implementation of clone_xmethod_worker_data for Python.  */
+
+void *
+gdbpy_clone_xmethod_worker_data
+  (const struct extension_language_defn *extlang, void *data)
+{
+  struct gdbpy_worker_data *worker_data = data, *new_data;
+
+  gdb_assert (worker_data->worker != NULL && worker_data->this_type != NULL);
+
+  new_data = XCNEW (struct gdbpy_worker_data);
+  new_data->worker = worker_data->worker;
+  new_data->this_type = worker_data->this_type;
+  Py_INCREF (new_data->worker);
+  Py_INCREF (new_data->this_type);
+
+  return new_data;
+}
+
+/* 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 *xmethod_name)
+{
+  PyObject *py_xmethod_name;
+  PyObject *match_method, *enabled_field, *match_result;
+  struct cleanup *cleanups;
+  int enabled;
+
+  cleanups = make_cleanup (null_cleanup, NULL);
+
+  enabled_field = PyObject_GetAttrString (matcher, enabled_field_name);
+  if (enabled_field == NULL)
+    {
+      do_cleanups (cleanups);
+      return NULL;
+    }
+  make_cleanup_py_decref (enabled_field);
+
+  enabled = PyObject_IsTrue (enabled_field);
+  if (enabled == -1)
+    {
+      do_cleanups (cleanups);
+      return NULL;
+    }
+  if (enabled == 0)
+    {
+      /* Return 'None' if the matcher is not enabled.  */
+      do_cleanups (cleanups);
+      Py_RETURN_NONE;
+    }
+
+  match_method = PyObject_GetAttrString (matcher, match_method_name);
+  if (match_method == NULL)
+    {
+      do_cleanups (cleanups);
+      return NULL;
+    }
+  make_cleanup_py_decref (match_method);
+
+  py_xmethod_name = PyString_FromString (xmethod_name);
+  if (py_xmethod_name == NULL)
+    {
+      do_cleanups (cleanups);
+      return NULL;
+    }
+  make_cleanup_py_decref (py_xmethod_name);
+
+  match_result = PyObject_CallMethodObjArgs (matcher,
+					     py_match_method_name,
+					     py_obj_type,
+					     py_xmethod_name,
+					     NULL);
+
+  do_cleanups (cleanups);
+
+  return match_result;
+}
+
+/* Implementation of get_matching_xmethod_workers for Python.  */
+
+enum ext_lang_rc
+gdbpy_get_matching_xmethod_workers
+  (const struct extension_language_defn *extlang,
+   struct type *obj_type, const char *method_name,
+   xmethod_worker_vec **dm_vec)
+{
+  struct cleanup *cleanups;
+  struct objfile *objfile;
+  VEC (xmethod_worker_ptr) *worker_vec = NULL;
+  PyObject *py_type, *py_progspace;
+  PyObject *py_xmethod_matcher_list = NULL, *list_iter, *matcher;
+
+  gdb_assert (obj_type != NULL && method_name != NULL);
+
+  cleanups = ensure_python_env (get_current_arch (), current_language);
+
+  py_type = type_to_type_object (obj_type);
+  if (py_type == NULL)
+    {
+      gdbpy_print_stack ();
+      do_cleanups (cleanups);
+
+      return EXT_LANG_RC_ERROR;
+    }
+  make_cleanup_py_decref (py_type);
+
+  /* Create an empty list of debug methods.  */
+  py_xmethod_matcher_list = PyList_New (0);
+  if (py_xmethod_matcher_list == NULL)
+    {
+      gdbpy_print_stack ();
+      do_cleanups (cleanups);
+
+      return EXT_LANG_RC_ERROR;
+    }
+
+  /* Gather debug method matchers registered with the object files.  */
+  ALL_OBJFILES (objfile)
+    {
+      PyObject *py_objfile = objfile_to_objfile_object (objfile);
+      PyObject *objfile_matchers, *temp = py_xmethod_matcher_list;
+
+      if (py_objfile == NULL)
+	{
+	  gdbpy_print_stack ();
+	  Py_DECREF (py_xmethod_matcher_list);
+	  do_cleanups (cleanups);
+
+	  return EXT_LANG_RC_ERROR;
+	}
+
+      objfile_matchers = objfpy_get_xmethods (py_objfile, NULL);
+      py_xmethod_matcher_list = PySequence_Concat (temp,
+							objfile_matchers);
+      Py_DECREF (temp);
+      Py_DECREF (objfile_matchers);
+      if (py_xmethod_matcher_list == NULL)
+	{
+	  gdbpy_print_stack ();
+	  do_cleanups (cleanups);
+
+	  return EXT_LANG_RC_ERROR;
+	}
+    }
+
+  /* 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_xmethod_matcher_list;
+      PyObject *pspace_matchers = pspy_get_xmethods (py_progspace, NULL);
+
+      py_xmethod_matcher_list = PySequence_Concat (temp, pspace_matchers);
+      Py_DECREF (temp);
+      Py_DECREF (pspace_matchers);
+      if (py_xmethod_matcher_list == NULL)
+	{
+	  gdbpy_print_stack ();
+	  do_cleanups (cleanups);
+
+	  return EXT_LANG_RC_ERROR;
+	}
+    }
+  else
+    {
+      gdbpy_print_stack ();
+      Py_DECREF (py_xmethod_matcher_list);
+      do_cleanups (cleanups);
+
+      return EXT_LANG_RC_ERROR;
+    }
+
+  /* Gather debug method matchers registered globally.  */
+  if (gdb_python_module != NULL
+      && PyObject_HasAttrString (gdb_python_module, matchers_attr_str))
+    {
+      PyObject *gdb_matchers;
+      PyObject *temp = py_xmethod_matcher_list;
+
+      gdb_matchers = PyObject_GetAttrString (gdb_python_module,
+					     matchers_attr_str);
+      if (gdb_matchers != NULL)
+	{
+	  py_xmethod_matcher_list = PySequence_Concat (temp,
+							   gdb_matchers);
+	  Py_DECREF (temp);
+	  Py_DECREF (gdb_matchers);
+	  if (py_xmethod_matcher_list == NULL)
+	    {
+	      gdbpy_print_stack ();
+	      do_cleanups (cleanups);
+
+	      return EXT_LANG_RC_ERROR;
+	    }
+	}
+      else
+	{
+	  gdbpy_print_stack ();
+	  Py_DECREF (py_xmethod_matcher_list);
+	  do_cleanups (cleanups);
+
+	  return EXT_LANG_RC_ERROR;
+	}
+    }
+
+  /* Safe to make a cleanup for py_xmethod_matcher_list now as it
+     will not change any more.  */
+  make_cleanup_py_decref (py_xmethod_matcher_list);
+
+  list_iter = PyObject_GetIter (py_xmethod_matcher_list);
+  if (list_iter == NULL)
+    {
+      gdbpy_print_stack ();
+      do_cleanups (cleanups);
+
+      return EXT_LANG_RC_ERROR;
+    }
+  while ((matcher = PyIter_Next (list_iter)) != NULL)
+    {
+      PyObject *match_result = invoke_match_method (matcher, py_type,
+						    method_name);
+
+      if (match_result == NULL)
+	{
+	  gdbpy_print_stack ();
+	  Py_DECREF (matcher);
+	  do_cleanups (cleanups);
+
+	  return EXT_LANG_RC_ERROR;
+	}
+      if (match_result == Py_None)
+	; /* This means there was no match.  */
+      else if (PySequence_Check (match_result))
+	{
+	  PyObject *iter = PyObject_GetIter (match_result);
+	  PyObject *py_worker;
+
+	  if (iter == NULL)
+	    {
+	      gdbpy_print_stack ();
+	      Py_DECREF (matcher);
+	      Py_DECREF (match_result);
+	      do_cleanups (cleanups);
+
+	      return EXT_LANG_RC_ERROR;
+	    }
+	  while ((py_worker = PyIter_Next (iter)) != NULL)
+	    {
+	      struct xmethod_worker *worker;
+
+	      worker = new_python_xmethod_worker (py_worker, py_type);
+	      VEC_safe_push (xmethod_worker_ptr, worker_vec, worker);
+	      Py_DECREF (py_worker);
+	    }
+	  Py_DECREF (iter);
+	  /* Report any error that could have occurred while iterating.  */
+	  if (PyErr_Occurred ())
+	    {
+	      gdbpy_print_stack ();
+	      Py_DECREF (matcher);
+	      Py_DECREF (match_result);
+	      do_cleanups (cleanups);
+
+	      return EXT_LANG_RC_ERROR;
+	    }
+	}
+      else
+	{
+	  struct xmethod_worker *worker;
+
+	  worker = new_python_xmethod_worker (match_result, py_type);
+	  VEC_safe_push (xmethod_worker_ptr, worker_vec, worker);
+	}
+
+      Py_DECREF (match_result);
+      Py_DECREF (matcher);
+    }
+  Py_DECREF (list_iter);
+  /* Report any error that could have occurred while iterating.  */
+  if (PyErr_Occurred ())
+    {
+      gdbpy_print_stack ();
+      do_cleanups (cleanups);
+
+      return EXT_LANG_RC_ERROR;
+    }
+
+  do_cleanups (cleanups);
+  *dm_vec = worker_vec;
+
+  return EXT_LANG_RC_OK;
+}
+
+/* Implementation of get_xmethod_arg_types for Python.  */
+
+enum ext_lang_rc
+gdbpy_get_xmethod_arg_types (const struct extension_language_defn *extlang,
+				  struct xmethod_worker *worker,
+				  int *nargs, struct type ***arg_types)
+{
+  struct gdbpy_worker_data *worker_data = worker->data;
+  PyObject *py_worker = worker_data->worker;
+  PyObject *get_arg_types_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 -1 so that any premature return from this function returns
+     an invalid/unusable number of arg types.  */
+  *nargs = -1;
+
+  cleanups = ensure_python_env (get_current_arch (), current_language);
+
+  get_arg_types_method =  PyObject_GetAttrString (py_worker,
+						  get_arg_types_method_name);
+  if (get_arg_types_method == NULL)
+    {
+      gdbpy_print_stack ();
+      do_cleanups (cleanups);
+
+      return EXT_LANG_RC_ERROR;
+    }
+  make_cleanup_py_decref (get_arg_types_method);
+
+  py_argtype_list = PyObject_CallMethodObjArgs (py_worker,
+						py_get_arg_types_method_name,
+						NULL);
+  if (py_argtype_list == NULL)
+    {
+      gdbpy_print_stack ();
+      do_cleanups (cleanups);
+
+      return EXT_LANG_RC_ERROR;
+    }
+  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 EXT_LANG_RC_ERROR;
+	}
+
+      list_iter = PyObject_GetIter (py_argtype_list);
+      if (list_iter == NULL)
+	{
+	  gdbpy_print_stack ();
+	  do_cleanups (cleanups);
+
+	  return EXT_LANG_RC_ERROR;
+	}
+      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)) != NULL)
+	{
+	  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_arg_types "
+				 "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_arg_types 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 EXT_LANG_RC_ERROR;
+    }
+
+  /* Add the type of 'this' as the first argument.  */
+  obj_type = type_object_to_type (worker_data->this_type);
+  type_array[0] = make_cv_type (1, 0, lookup_pointer_type (obj_type), NULL);
+  *nargs = i;
+  *arg_types = type_array;
+  do_cleanups (cleanups);
+
+  return EXT_LANG_RC_OK;
+}
+
+/* Implementation of invoke_xmethod for Python.  */
+
+enum ext_lang_rc
+gdbpy_invoke_xmethod (const struct extension_language_defn *extlang,
+			   struct xmethod_worker *worker,
+			   struct value *obj, struct value **args, int nargs,
+			   struct value **result)
+{
+  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 *res = NULL;
+  struct gdbpy_worker_data *worker_data = worker->data;
+  PyObject *xmethod_worker = worker_data->worker;
+
+  cleanups = ensure_python_env (get_current_arch (), current_language);
+
+  invoke_method =  PyObject_GetAttrString (xmethod_worker,
+					   invoke_method_name);
+  if (invoke_method == NULL)
+    {
+      gdbpy_print_stack ();
+      do_cleanups (cleanups);
+
+      return EXT_LANG_RC_ERROR;
+    }
+  make_cleanup_py_decref (invoke_method);
+
+  obj_type = check_typedef (value_type (obj));
+  this_type = check_typedef (type_object_to_type (worker_data->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 EXT_LANG_RC_ERROR;
+    }
+  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 EXT_LANG_RC_ERROR;
+    }
+  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 EXT_LANG_RC_ERROR;
+	}
+
+      PyTuple_SET_ITEM (py_arg_tuple, i, py_value_arg);
+    }
+
+  py_result = PyObject_CallMethodObjArgs (xmethod_worker,
+					  py_invoke_method_name,
+					  py_value_obj,
+					  py_arg_tuple, NULL);
+  if (py_result == NULL)
+    {
+      gdbpy_print_stack ();
+      do_cleanups (cleanups);
+
+      return EXT_LANG_RC_ERROR;
+    }
+  make_cleanup_py_decref (py_result);
+
+  if (py_result != Py_None)
+    {
+      res = convert_value_from_python (py_result);
+      if (res == NULL)
+	{
+	  gdbpy_print_stack ();
+	  do_cleanups (cleanups);
+
+	  return EXT_LANG_RC_ERROR;
+	}
+    }
+  else
+    {
+      res = allocate_value (lookup_typename (python_language, python_gdbarch,
+					     "void", NULL, 0));
+    }
+
+  *result = res;
+  do_cleanups (cleanups);
+
+  return EXT_LANG_RC_OK;
+}
+
+/* Creates a new Python xmethod_worker object.
+   The new object has data of type 'struct gdbpy_worker_data' composed
+   with the components PY_WORKER and THIS_TYPE.  */
+
+static struct xmethod_worker *
+new_python_xmethod_worker (PyObject *py_worker, PyObject *this_type)
+{
+  struct gdbpy_worker_data *data;
+
+  gdb_assert (py_worker != NULL && this_type != NULL);
+
+  data = XCNEW (struct gdbpy_worker_data);
+  data->worker = py_worker;
+  data->this_type = this_type;
+  Py_INCREF (py_worker);
+  Py_INCREF (this_type);
+
+  return new_xmethod_worker (&extension_language_python, data);
+}
+
+int
+gdbpy_initialize_xmethods (void)
+{
+  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_arg_types_method_name
+    = PyString_FromString (get_arg_types_method_name);
+  if (py_get_arg_types_method_name == NULL)
+    return -1;
+
+  return 1;
+}
diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
index 07650f7..7e4a7bc 100644
--- a/gdb/python/python-internal.h
+++ b/gdb/python/python-internal.h
@@ -307,6 +307,25 @@  extern enum ext_lang_bp_stop gdbpy_breakpoint_cond_says_stop
   (const struct extension_language_defn *, struct breakpoint *);
 extern int gdbpy_breakpoint_has_cond (const struct extension_language_defn *,
 				      struct breakpoint *b);
+
+extern void *gdbpy_clone_xmethod_worker_data
+  (const struct extension_language_defn *extlang, void *data);
+extern void gdbpy_free_xmethod_worker_data
+  (const struct extension_language_defn *extlang, void *data);
+extern enum ext_lang_rc gdbpy_get_matching_xmethod_workers
+  (const struct extension_language_defn *extlang,
+   struct type *obj_type, const char *method_name,
+   xmethod_worker_vec **dm_vec);
+extern enum ext_lang_rc gdbpy_get_xmethod_arg_types
+  (const struct extension_language_defn *extlang,
+   struct xmethod_worker *worker,
+   int *nargs,
+   struct type ***arg_types);
+extern enum ext_lang_rc gdbpy_invoke_xmethod
+  (const struct extension_language_defn *extlang,
+   struct xmethod_worker *worker,
+   struct value *obj, struct value **args, int nargs,
+   struct value **result);
 
 PyObject *gdbpy_history (PyObject *self, PyObject *args);
 PyObject *gdbpy_breakpoints (PyObject *, PyObject *);
@@ -345,11 +364,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_xmethods (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_xmethods (PyObject *, void *);
 
 PyObject *gdbarch_to_arch_object (struct gdbarch *gdbarch);
 
@@ -430,6 +451,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_xmethods (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 cbfa73a..369a249 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -186,7 +186,13 @@  static const struct extension_language_ops python_extension_ops =
   gdbpy_set_quit_flag,
   gdbpy_check_quit_flag,
 
-  gdbpy_before_prompt_hook
+  gdbpy_before_prompt_hook,
+
+  gdbpy_clone_xmethod_worker_data,
+  gdbpy_free_xmethod_worker_data,
+  gdbpy_get_matching_xmethod_workers,
+  gdbpy_get_xmethod_arg_types,
+  gdbpy_invoke_xmethod
 };
 
 /* Architecture and language to be used in callbacks from
@@ -1752,7 +1758,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_xmethods () < 0)
     goto fail;
 
   gdbpy_to_string_cst = PyString_FromString ("to_string");
diff --git a/gdb/testsuite/gdb.python/py-xmethods.cc b/gdb/testsuite/gdb.python/py-xmethods.cc
new file mode 100644
index 0000000..076cba6
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-xmethods.cc
@@ -0,0 +1,186 @@ 
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2014 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see  <http://www.gnu.org/licenses/>.  */
+
+#include <iostream>
+
+using namespace std;
+
+namespace dop
+{
+
+class A
+{
+public:
+  int a;
+  int array [10];
+  virtual ~A ();
+  int operator+ (const A &obj);
+  int operator- (const A &obj);
+  int operator+ (const int i);
+  int operator- (const int i);
+  virtual int geta (void);
+};
+
+A::~A () { }
+
+int
+A::operator+ (const A &obj)
+{
+  cout << "From CC <A_plus_A>:" << endl;
+  return a + obj.a;
+}
+
+int
+A::operator- (const A &obj)
+{
+  cout << "From CC <A_minus_A>:" << endl;
+  return a - obj.a;
+}
+
+int
+A::operator+ (const int i)
+{
+  cout << "From CC <A_plus_i>:" << endl;
+  return a + i;
+}
+
+int
+A::operator- (const int i)
+{
+  cout << "From CC <A_minus_i>:" << endl;
+  return a - i;
+}
+
+int
+A::geta (void)
+{
+  cout << "From CC A::geta:" << endl;
+  return a;
+}
+
+class B : public A
+{
+public:
+  virtual int geta (void);
+};
+
+int
+B::geta (void)
+{
+  cout << "From CC B::geta:" << endl;
+  return 2 * a;
+}
+
+typedef B Bt;
+
+typedef Bt Btt;
+
+class E : public A
+{
+public:
+  /* This class has a member named 'a', while the base class also has a
+     member named 'a'.  When one invokes A::geta(), A::a should be
+     returned and not E::a as the 'geta' method is defined on class 'A'.
+     This class tests this aspect of debug methods.  */
+  int a;
+};
+
+template <typename T>
+class G
+{
+ public:
+  template <typename T1>
+  int size_diff ();
+
+  template <int M>
+  int size_mul ();
+
+  template <typename T1>
+  T mul(const T1 t1);
+
+ public:
+  T t;
+};
+
+template <typename T>
+template <typename T1>
+int
+G<T>::size_diff ()
+{
+  cout << "From CC G<>::size_diff:" << endl;
+  return sizeof (T1) - sizeof (T);
+}
+
+template <typename T>
+template <int M>
+int
+G<T>::size_mul ()
+{
+  cout << "From CC G<>::size_mul:" << endl;
+  return M * sizeof (T);
+}
+
+template <typename T>
+template <typename T1>
+T
+G<T>::mul (const T1 t1)
+{
+  cout << "From CC G<>::mul:" << endl;
+  return t1 * t;
+}
+
+}  // namespaxe dop
+
+using namespace dop;
+
+int main(void)
+{
+  A a1, a2;
+  a1.a = 5;
+  a2.a = 10;
+
+  B b1;
+  b1.a = 30;
+  A *a_ptr = &b1;
+
+  Bt bt;
+  bt.a = 40;
+
+  Btt btt;
+  btt.a = -5;
+
+  G<int> g, *g_ptr;
+  g.t = 5;
+  g_ptr = &g;
+
+  E e;
+  E &e_ref = e;
+  E *e_ptr = &e;
+  e.a = 1000;
+  e.A::a = 100;
+
+  int diff = g.size_diff<float> ();
+  int smul = g.size_mul<2> ();
+  int mul = g.mul (1.0);
+
+  for (int i = 0; i < 10; i++)
+    {
+      a1.array[i] = a2.array[i] = i;
+    }
+
+  return 0; /* Break here.  */
+}
diff --git a/gdb/testsuite/gdb.python/py-xmethods.exp b/gdb/testsuite/gdb.python/py-xmethods.exp
new file mode 100644
index 0000000..3cac478
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-xmethods.exp
@@ -0,0 +1,126 @@ 
+# Copyright 2014 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# This file is part of the GDB testsuite.  It tests the debug methods
+# feature in the Python extension language.
+
+load_lib gdb-python.exp
+
+if { [skip_cplus_tests] } { continue }
+
+standard_testfile py-xmethods.cc
+
+if {[prepare_for_testing $testfile.exp $testfile $srcfile {debug c++}]} {
+    return -1
+}
+
+# Skip all tests if Python scripting is not enabled.
+if { [skip_python_tests] } { continue }
+
+if ![runto_main] {
+   return -1
+}
+
+set xmethods_script [gdb_remote_download host \
+		     ${srcdir}/${subdir}/${testfile}.py]
+
+gdb_breakpoint [gdb_get_line_number "Break here."]
+gdb_continue_to_breakpoint "Break here" ".*Break here.*"
+
+# Tests before loading the debug methods.
+gdb_test "p a1 + a2" "From CC <A_plus_A>.*15" "Before: a1 + a2"
+gdb_test "p a2 - a1" "From CC <A_minus_A>.*5" "Before: a1 - a2"
+gdb_test "p b1 - a1" "From CC <A_minus_A>.*25" "Before: b1 - a1"
+gdb_test "p a1.geta()" "From CC A::geta.*5" "Before: a1.geta()"
+gdb_test "p ++a1" "No symbol.*" "Before: ++a1"
+gdb_test "p a1.getarrayind(5)" "Couldn't find method.*" \
+  "Before: a1.getarrayind(5)"
+gdb_test "p a_ptr->geta()" "From CC B::geta.*60" "Before: a_ptr->geta()"
+gdb_test "p e.geta()" "From CC A::geta.*100" "Before: e.geta()"
+gdb_test "p g.size_diff<float>()" "From CC G<>::size_diff.*" \
+  "Before: g.size_diff<float>()"
+gdb_test "p g.size_diff<unsigned long>()" "Couldn't find method.*" \
+  "Before: g.size_diff<unsigned long>()"
+gdb_test "p g.size_mul<2>()" "From CC G<>::size_mul.*" \
+  "Before: g.size_mul<2>()"
+gdb_test "p g.size_mul<5>()" "Couldn't find method.*" \
+  "Before: g.size_mul<5>()"
+gdb_test "p g.mul<double>(2.0)" "From CC G<>::mul.*" \
+  "Before: g.mul<double>(2.0)"
+gdb_test "p g.mul<char>('a')" "Couldn't find method.*" \
+  "Before: g.mul<char>('a')"
+
+# Load the script which adds the debug methods.
+gdb_test_no_output "source ${xmethods_script}" "load the script file"
+
+# Tests after loading debug methods.
+gdb_test "p a1 + a2" "From Python <A_plus_A>.*15" "After: a1 + a2"
+gdb_test "p a2 - a1" "From CC <A_minus_A>.*5" "After: a1 - a2"
+gdb_test "p b1 - a1" "From CC <A_minus_A>.*25" "After: b1 - a2"
+gdb_test "p a1.geta()" "From Python <A_geta>.*5" "After: a1.geta()"
+gdb_test "p ++a1" "From Python <plus_plus_A>.*6" "After: ++a1"
+gdb_test "p a1.getarrayind(5)" "From Python <A_getarrayind>.*5" \
+  "After: a1.getarrayind(5)"
+# Note the following test.  Xmethods on dynamc types are not looked up
+# currently.  Hence, even though a_ptr points to a B object, the xmethod
+# defined for A objects is invoked.
+gdb_test "p a_ptr->geta()" "From Python <A_geta>.*30" "After: a_ptr->geta()"
+gdb_test "p e.geta()" "From Python <A_geta>.*100" "After: e.geta()"
+gdb_test "p e_ptr->geta()" "From Python <A_geta>.*100" "After: e_ptr->geta()"
+gdb_test "p e_ref.geta()" "From Python <A_geta>.*100" "After: e_ref.geta()"
+gdb_test "p e.method(10)" "From Python <E_method_int>.*" "After: e.method(10)"
+gdb_test "p e.method('a')" "From Python <E_method_char>.*" \
+  "After: e.method('a')"
+gdb_test "p g.size_diff<float>  ()" "From Python G<>::size_diff.*" \
+  "After: g.size_diff<float>()"
+gdb_test "p g.size_diff<  unsigned long  >()" "From Python G<>::size_diff.*" \
+  "After: g.size_diff<unsigned long>()"
+gdb_test "p g.size_mul<2>()" "From Python G<>::size_mul.*" \
+  "After: g.size_mul<2>()"
+gdb_test "p g.size_mul<  5  >()" "From Python G<>::size_mul.*" \
+  "After: g.size_mul<  5  >()"
+gdb_test "p g.mul<double>(2.0)" "From Python G<>::mul.*" \
+  "After: g.mul<double>(2.0)"
+gdb_test "p g.mul<char>('a')" "From Python G<>::mul.*" \
+gdb_test "p g_ptr->mul<char>('a')" "From Python G<>::mul.*" \
+  "After: g_ptr->mul<char>('a')"
+
+# Tests for 'disable/enable xmethod' command.
+gdb_test_no_output "disable xmethod .*xmethods G_methods" \
+  "Disable G_methods"
+gdb_test "p g.mul<char>('a')" "Couldn't find method.*" \
+  "g.mul<char>('a') after disabling G_methods"
+gdb_test_no_output "enable xmethod .*xmethods G_methods" \
+  "Enable G_methods"
+gdb_test "p g.mul<char>('a')" "From Python G<>::mul.*" \
+  "After enabling G_methods"
+gdb_test_no_output "disable xmethod .*xmethods G_methods;mul" \
+  "Disable G_methods;mul"
+gdb_test "p g.mul<char>('a')" "Couldn't find method.*" \
+  "g.mul<char>('a') after disabling G_methods;mul"
+gdb_test_no_output "enable xmethod .*xmethods G_methods;mul" \
+  "Enable G_methods;mul"
+gdb_test "p g.mul<char>('a')" "From Python G<>::mul.*" \
+  "After enabling G_methods;mul"
+
+# Test for 'info xmethods' command
+gdb_test "info xmethod global plus" "global.*plus_plus_A" \
+  "info xmethod global plus 1"
+gdb_test_no_output "disable xmethod .*xmethods E_methods;method_int" \
+  "disable xmethod .*xmethods E_methods;method_int"
+gdb_test "info xmethod .*xmethods E_methods;method_int" ".* \\\[disabled\\\]" \
+  "info xmethod xmethods E_methods;method_int"
+
+remote_file host delete ${xmethods_script}
diff --git a/gdb/testsuite/gdb.python/py-xmethods.py b/gdb/testsuite/gdb.python/py-xmethods.py
new file mode 100644
index 0000000..71107e5
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-xmethods.py
@@ -0,0 +1,218 @@ 
+# Copyright 2014 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# This file is part of the GDB testsuite.  It test the xmethods support
+# in the Python extension language.
+
+import gdb
+import re
+
+from gdb.xmethod import XMethod
+from gdb.xmethod import XMethodMatcher, XMethodWorker
+from gdb.xmethod import SimpleXMethodMatcher
+
+
+def A_plus_A(obj, opr):
+  print ('From Python <A_plus_A>:')
+  return obj['a'] + opr['a']
+
+
+def plus_plus_A(obj):
+  print ('From Python <plus_plus_A>:')
+  return obj['a'] + 1
+
+
+def A_geta(obj):
+  print ('From Python <A_geta>:')
+  return obj['a']
+
+
+def A_getarrayind(obj, index):
+  print 'From Python <A_getarrayind>:'
+  return obj['array'][index]
+
+
+type_A = gdb.parse_and_eval('(dop::A *) 0').type.target()
+type_B = gdb.parse_and_eval('(dop::B *) 0').type.target()
+type_int = gdb.parse_and_eval('(int *) 0').type.target()
+
+
+# The E class matcher and worker test two things:
+#   1. xmethod returning None.
+#   2. Matcher returning a list of workers.
+
+class E_method_char_worker(XMethodWorker):
+    def __init__(self):
+        pass
+
+    def get_arg_types(self):
+        return gdb.lookup_type('char')
+
+    def invoke(self, obj, args):
+        print 'From Python <E_method_char>'
+        return None
+
+
+class E_method_int_worker(XMethodWorker):
+    def __init__(self):
+        pass
+
+    def get_arg_types(self):
+        return gdb.lookup_type('int')
+
+    def invoke(self, obj, args):
+        print 'From Python <E_method_int>'
+        return None
+
+
+class E_method_matcher(XMethodMatcher):
+    def __init__(self):
+        XMethodMatcher.__init__(self, 'E_methods')
+        self.methods = [XMethod('method_int'), XMethod('method_char')]
+
+    def match(self, class_type, method_name):
+        class_tag = class_type.unqualified().tag
+        if not re.match('^dop::E$', class_tag):
+            return None
+	if not re.match('^method$', method_name):
+            return None
+        workers = []
+        if self.methods[0].enabled:
+            workers.append(E_method_int_worker())
+        if self.methods[1].enabled:
+            workers.append(E_method_char_worker())
+        return workers
+
+
+# The G class method matcher and worker illustrate how to write
+# xmethod matchers and workers for template classes and template
+# methods.
+
+class G_size_diff_worker(XMethodWorker):
+    def __init__(self, class_template_type, method_template_type):
+        self._class_template_type = class_template_type
+        self._method_template_type = method_template_type
+
+    def get_arg_types(self):
+        pass
+
+    def 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(XMethodWorker):
+    def __init__(self, class_template_type, method_template_val):
+        self._class_template_type = class_template_type
+        self._method_template_val = method_template_val
+
+    def get_arg_types(self):
+        pass
+
+    def invoke(self, obj, args):
+        print ('From Python G<>::size_mul()')
+        return self._class_template_type.sizeof * self._method_template_val
+
+
+class G_mul_worker(XMethodWorker):
+    def __init__(self, class_template_type, method_template_type):
+        self._class_template_type = class_template_type
+        self._method_template_type = method_template_type
+
+    def get_arg_types(self):
+        return self._method_template_type
+
+    def invoke(self, obj, args):
+        print ('From Python G<>::mul()')
+        return obj['t'] * args[0]
+
+
+class G_methods_matcher(XMethodMatcher):
+    def __init__(self):
+        XMethodMatcher.__init__(self, 'G_methods')
+        self.methods = [XMethod('size_diff'),
+                        XMethod('size_mul'),
+                        XMethod('mul')]
+
+    def _is_enabled(self, name):
+        for method in self.methods:
+            if method.name == name and method.enabled:
+                return True
+
+    def match(self, class_type, method_name):
+        class_tag = class_type.unqualified().tag
+        if not re.match('^dop::G<[ ]*[_a-zA-Z][ _a-zA-Z0-9]*>$',
+                        class_tag):
+            return None
+        t_name = class_tag[7:-1]
+        try:
+            t_type = gdb.lookup_type(t_name)
+        except gdb.error:
+            return None
+        if re.match('^size_diff<[ ]*[_a-zA-Z][ _a-zA-Z0-9]*>$', method_name):
+            if not self._is_enabled('size_diff'):
+                return None
+            t1_name = method_name[10:-1]
+            try:
+                t1_type = gdb.lookup_type(t1_name)
+                return G_size_diff_worker(t_type, t1_type)
+            except gdb.error:
+                return None
+        if re.match('^size_mul<[ ]*[0-9]+[ ]*>$', method_name):
+            if not self._is_enabled('size_mul'):
+                return None
+            m_val = int(method_name[9:-1])
+            return G_size_mul_worker(t_type, m_val)
+        if re.match('^mul<[ ]*[_a-zA-Z][ _a-zA-Z0-9]*>$', method_name):
+            if not self._is_enabled('mul'):
+                return None
+            t1_name = method_name[4:-1]
+            try:
+                t1_type = gdb.lookup_type(t1_name)
+                return G_mul_worker(t_type, t1_type)
+            except gdb.error:
+                return None
+
+
+global_dm_list = [
+    SimpleXMethodMatcher('A_plus_A',
+                         '^dop::A$',
+                         'operator\+',
+                         A_plus_A,
+                         # This is a replacement, hence match the arg type
+                         # exactly!
+                         type_A.const().reference()),
+    SimpleXMethodMatcher('plus_plus_A',
+                         '^dop::A$',
+                         'operator\+\+',
+                         plus_plus_A),
+    SimpleXMethodMatcher('A_geta',
+                         '^dop::A$',
+                         '^geta$',
+                         A_geta),
+    SimpleXMethodMatcher('A_getarrayind',
+                         '^dop::A$',
+                         '^getarrayind$',
+                         A_getarrayind,
+                         type_int),
+]
+
+for matcher in global_dm_list:
+    gdb.xmethod.register_xmethod_matcher(gdb, matcher)
+gdb.xmethod.register_xmethod_matcher(gdb.current_progspace(),
+                                     G_methods_matcher())
+gdb.xmethod.register_xmethod_matcher(gdb.current_progspace(),
+                                     E_method_matcher())