diff mbox

[v12,3/4] Add support for lookup, overload resolution and invocation of C++ debug methods

Message ID CAGyQ6gzpQ-E-p_tLOxVUhknrJOdfvJt5GSodwFyerWvX5aheCg@mail.gmail.com
State Superseded
Headers show

Commit Message

Siva Chandra Reddy April 1, 2014, 10:53 p.m. UTC
This part uses the debug method extension language API to lookup,
perform overload resolution, and invoke debug methods of C++ classes.

Doug had a comment about a call to invoke_debug_method:

Siva> +    ret_val = invoke_debug_method (dm_worker, arg2, argvec + 2,
Siva> +                                                     nargs - 1);

Doug> Can invoke_debug_method throw an error?
Doug> [One could use a cleanup to free dm_worker, regardless.]

Yes, invoke_debug_method can throw an error.  You are probably
pointing out a memory leak here when an error is thrown.  While I did
not address this possibility, how would a cleanup help here?

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

        * eval.c (evaluate_subexp_standard): Lookup and invoke methods
        defined in extension languages.
        * valarith.c (value_x_binop, value_x_unop): Lookup and invoke
        overloaded operator methods defined in extension languages.
        * valops.c (find_oload_method_list, find_method_list,
        find_overload_match, find_oload_champ): Lookup methods defined
        in extension languages.
        (value_has_indirect_dynamic_type): New function to determine
        the indirect dynamic type of a value.
        * value.h (find_overload_match): Update signature.

Comments

Doug Evans April 8, 2014, 11:16 p.m. UTC | #1
Siva Chandra writes:
 > This part uses the debug method extension language API to lookup,
 > perform overload resolution, and invoke debug methods of C++ classes.
 > 
 > Doug had a comment about a call to invoke_debug_method:
 > 
 > Siva> +    ret_val = invoke_debug_method (dm_worker, arg2, argvec + 2,
 > Siva> +                                                     nargs - 1);
 > 
 > Doug> Can invoke_debug_method throw an error?
 > Doug> [One could use a cleanup to free dm_worker, regardless.]
 > 
 > Yes, invoke_debug_method can throw an error.  You are probably
 > pointing out a memory leak here when an error is thrown.  While I did
 > not address this possibility, how would a cleanup help here?

See below.

 > 2014-04-01  Siva Chandra Reddy  <sivachandra@google.com>
 > 
 >         * eval.c (evaluate_subexp_standard): Lookup and invoke methods
 >         defined in extension languages.
 >         * valarith.c (value_x_binop, value_x_unop): Lookup and invoke
 >         overloaded operator methods defined in extension languages.
 >         * valops.c (find_oload_method_list, find_method_list,
 >         find_overload_match, find_oload_champ): Lookup methods defined
 >         in extension languages.
 >         (value_has_indirect_dynamic_type): New function to determine

Just say "New function."

 >         the indirect dynamic type of a value.
 >         * value.h (find_overload_match): Update signature.

Whenever a new argument is added to a function (or deleted), or when the
function's result type is changed, such changes must be explicitly stated
in the ChangeLog.  There's no need to add ChangeLog entries for any callers
that need updating (if that is the only reason they're being changed),
just say "All callers updated." in the changed function's description.

There are several of these in this patch.

I also see missing entries to document the addition of #include "extension.h".

 > diff --git a/gdb/eval.c b/gdb/eval.c
 > index 36615e1..0d26585 100644
 > --- a/gdb/eval.c
 > +++ b/gdb/eval.c
 > @@ -22,6 +22,7 @@
 >  #include "symtab.h"
 >  #include "gdbtypes.h"
 >  #include "value.h"
 > +#include "extension.h"
 >  #include "expression.h"
 >  #include "target.h"
 >  #include "frame.h"
 > @@ -1591,11 +1592,11 @@ evaluate_subexp_standard (struct type *expect_type,
 >            func_name = (char *) alloca (name_len + 1);
 >            strcpy (func_name, &exp->elts[string_pc + 1].string);
 >  
 > -          find_overload_match (&argvec[1], nargs, func_name,
 > -                               NON_METHOD, /* not method */
 > -                               NULL, NULL, /* pass NULL symbol since
 > +	  find_overload_match (&argvec[1], nargs, func_name,
 > +			       NON_METHOD, /* not method */
 > +			       NULL, NULL, /* pass NULL symbol since
 >  					      symbol is unknown */
 > -                               NULL, &symp, NULL, 0);
 > +			       NULL, &symp, NULL, NULL, 0);
 >  
 >            /* Now fix the expression being evaluated.  */
 >            exp->elts[save_pos1 + 2].symbol = symp;
 > @@ -1625,11 +1626,12 @@ evaluate_subexp_standard (struct type *expect_type,
 >  	      /* Language is C++, do some overload resolution before
 >  		 evaluation.  */
 >  	      struct value *valp = NULL;
 > +	      struct debug_method_worker *dm_worker = NULL;
 >  
 >  	      (void) find_overload_match (&argvec[1], nargs, tstr,
 > -	                                  METHOD, /* method */
 > +					  METHOD, /* method */
 >  					  &arg2,  /* the object */
 > -					  NULL, &valp, NULL,
 > +					  NULL, &valp, NULL, &dm_worker,
 >  					  &static_memfuncp, 0);
 >  
 >  	      if (op == OP_SCOPE && !static_memfuncp)
 > @@ -1639,8 +1641,22 @@ evaluate_subexp_standard (struct type *expect_type,
 >  			   "`this' pointer"),
 >  			 function_name);
 >  		}
 > -	      argvec[1] = arg2;	/* the ``this'' pointer */
 > -	      argvec[0] = valp;	/* Use the method found after overload
 > +
 > +	      /* If a method implemented in an extension language is the best
 > +		 match, then invoke it.  */
 > +	      if (dm_worker)
 > +		{
 > +		  struct value *ret_val;
 > +
 > +		  ret_val = invoke_debug_method (dm_worker, arg2, argvec + 2,
 > +						 nargs - 1);
 > +		  xfree (dm_worker);
 > +
 > +		  return ret_val;
 > +		}

Yeah, this needs to register a cleanup to free dm_worker.
E.g.,

	      if (dm_worker)
		{
		  struct cleanup *cleanups = make_cleanup (xfree, dm_worker);
		  struct value *ret_val;

		  ret_val = invoke_debug_method (dm_worker, arg2, argvec + 2,
						 nargs - 1);
		  do_cleanups (cleanups);

		  return ret_val;
		}

This works because it ensures dm_worker is freed regardless of whether
invoke_debug_method throws an error.  This is because before actually
"throwing the error" (ie., before the longjmp to implement the "throw")
all registered cleanups are run.

I didn't look at the entire function in which this snippet lives.
If "cleanups" shadows another local, I'd pick a different name.

 > +
 > +	      argvec[1] = arg2; /* the ``this'' pointer */
 > +	      argvec[0] = valp; /* Use the method found after overload
 >  				   resolution.  */
 >  	    }
 >  	  else
 > @@ -1698,9 +1714,9 @@ evaluate_subexp_standard (struct type *expect_type,
 >  
 >  	      (void) find_overload_match (&argvec[1], nargs,
 >  					  NULL,        /* no need for name */
 > -	                                  NON_METHOD,  /* not method */
 > -	                                  NULL, function, /* the function */
 > -					  NULL, &symp, NULL, no_adl);
 > +					  NON_METHOD,  /* not method */
 > +					  NULL, function, /* the function */
 > +					  NULL, &symp, NULL, NULL, no_adl);
 >  
 >  	      if (op == OP_VAR_VALUE)
 >  		{
 > diff --git a/gdb/valarith.c b/gdb/valarith.c
 > index 8e863e3..9e79412 100644
 > --- a/gdb/valarith.c
 > +++ b/gdb/valarith.c
 > @@ -30,6 +30,7 @@
 >  #include <math.h>
 >  #include "infcall.h"
 >  #include "exceptions.h"
 > +#include "extension.h"
 >  
 >  /* Define whether or not the C operator '/' truncates towards zero for
 >     differently signed operands (truncation direction is undefined in C).  */
 > @@ -282,24 +283,34 @@ unop_user_defined_p (enum exp_opcode op, struct value *arg1)
 >     *STATIC_MEMFUNP will be set to 1, and otherwise 0.
 >     The search if performed through find_overload_match which will handle
 >     member operators, non member operators, operators imported implicitly or
 > -   explicitly, and perform correct overload resolution in all of the above
 > -   situations or combinations thereof.  */
 > +   explicitly, operators implemented as debug methods, and perform correct
 > +   overload resolution in all of the above situations or combinations
 > +   thereof.  If a matching method/function is found in the binary, its
 > +   corresponding value is returned in SRC_FN.  If a debug method is the best
 > +   match, then the corresponding debug method worker is returned in
 > +   DM_WORKER.  */

This needs to document negative case.
E.g. on return exactly one of SRC_FN, DM_WORKER is non-NULL and the
other is NULL.
Plus this function should ensure this, and not require the caller to
first set them to NULL.

 >  
 > -static struct value *
 > +static void
 >  value_user_defined_cpp_op (struct value **args, int nargs, char *operator,
 > -                           int *static_memfuncp)
 > +			   struct value **src_fn,
 > +			   struct debug_method_worker **dm_worker,
 > +			   int *static_memfuncp)
 >  {
 >  
 >    struct symbol *symp = NULL;
 >    struct value *valp = NULL;
 > +  struct debug_method_worker *worker = NULL;
 >  
 >    find_overload_match (args, nargs, operator, BOTH /* could be method */,
 > -                       &args[0] /* objp */,
 > -                       NULL /* pass NULL symbol since symbol is unknown */,
 > -                       &valp, &symp, static_memfuncp, 0);
 > +		       &args[0] /* objp */,
 > +		       NULL /* pass NULL symbol since symbol is unknown */,
 > +		       &valp, &symp, &worker, static_memfuncp, 0);
 >  
 >    if (valp)
 > -    return valp;
 > +    {
 > +      *src_fn = valp;
 > +      return;
 > +    }
 >  
 >    if (symp)
 >      {
 > @@ -307,28 +318,41 @@ value_user_defined_cpp_op (struct value **args, int nargs, char *operator,
 >           expect a reference as its first argument
 >           rather the explicit structure.  */
 >        args[0] = value_ind (args[0]);
 > -      return value_of_variable (symp, 0);
 > +      *src_fn = value_of_variable (symp, 0);
 > +      return;
 > +    }
 > +
 > +  if (worker)
 > +    {
 > +      *dm_worker = worker;
 > +      return;
 >      }
 >  
 >    error (_("Could not find %s."), operator);
 >  }
 >  
 > -/* Lookup user defined operator NAME.  Return a value representing the
 > -   function, otherwise return NULL.  */
 > +/* Lookup user defined operator NAME.  If a matching operator is found in the
 > +   binary, its corresponding value is returned in SRC_FN.  If a debug method
 > +   is the best matching operator, then the corresponding debug method worker
 > +   is returned in DM_WORKER.  */

Document that on return exactly one of SRC_FN, DM_WORKER is set to non-NULL
and the other is set to NULL.

 > -static struct value *
 > +static void
 >  value_user_defined_op (struct value **argp, struct value **args, char *name,
 > -                       int *static_memfuncp, int nargs)
 > +		       int *static_memfuncp, int nargs,
 > +		       struct value **src_fn,
 > +		       struct debug_method_worker **dm_worker)
 >  {
 >    struct value *result = NULL;
 >  
 >    if (current_language->la_language == language_cplus)
 > -    result = value_user_defined_cpp_op (args, nargs, name, static_memfuncp);
 > +    value_user_defined_cpp_op (args, nargs, name, src_fn, dm_worker,
 > +			       static_memfuncp);

Wrap the "then" clause here with { } since it's more than one line.

 >    else
 > -    result = value_struct_elt (argp, args, name, static_memfuncp,
 > -                               "structure");
 > -
 > -  return result;
 > +    {
 > +      result = value_struct_elt (argp, args, name, static_memfuncp,
 > +				 "structure");
 > +      *src_fn = result;
 > +    }
 >  }
 >  
 >  /* We know either arg1 or arg2 is a structure, so try to find the right
 > @@ -345,6 +369,7 @@ value_x_binop (struct value *arg1, struct value *arg2, enum exp_opcode op,
 >  	       enum exp_opcode otherop, enum noside noside)
 >  {
 >    struct value **argvec;
 > +  struct debug_method_worker *dm_worker = NULL;
 >    char *ptr;
 >    char tstr[13];
 >    int static_memfuncp;
 > @@ -359,6 +384,7 @@ value_x_binop (struct value *arg1, struct value *arg2, enum exp_opcode op,
 >      error (_("Can't do that binary op on that type"));	/* FIXME be explicit */
 >  
 >    argvec = (struct value **) alloca (sizeof (struct value *) * 4);
 > +  argvec[0] = NULL;
 >    argvec[1] = value_addr (arg1);
 >    argvec[2] = arg2;
 >    argvec[3] = 0;
 > @@ -471,8 +497,8 @@ value_x_binop (struct value *arg1, struct value *arg2, enum exp_opcode op,
 >        error (_("Invalid binary operation specified."));
 >      }
 >  
 > -  argvec[0] = value_user_defined_op (&arg1, argvec + 1, tstr,
 > -                                     &static_memfuncp, 2);
 > +  value_user_defined_op (&arg1, argvec + 1, tstr, &static_memfuncp, 2,
 > +			 &argvec[0], &dm_worker);
 >  
 >    if (argvec[0])
 >      {
 > @@ -492,6 +518,14 @@ value_x_binop (struct value *arg1, struct value *arg2, enum exp_opcode op,
 >        return call_function_by_hand (argvec[0], 2 - static_memfuncp,
 >  				    argvec + 1);
 >      }
 > +  if (dm_worker != NULL)
 > +    {
 > +      struct value *ret_val = invoke_debug_method (dm_worker, arg1, &arg2, 1);
 > +
 > +      xfree (dm_worker);
 > +
 > +      return ret_val;
 > +    }

This needs a cleanup to free dm_worker.  See above for an example.

 >    throw_error (NOT_FOUND_ERROR,
 >                 _("member function %s not found"), tstr);
 >  #ifdef lint
 > @@ -510,6 +544,7 @@ value_x_unop (struct value *arg1, enum exp_opcode op, enum noside noside)
 >  {
 >    struct gdbarch *gdbarch = get_type_arch (value_type (arg1));
 >    struct value **argvec;
 > +  struct debug_method_worker *dm_worker;
 >    char *ptr;
 >    char tstr[13], mangle_tstr[13];
 >    int static_memfuncp, nargs;
 > @@ -523,6 +558,7 @@ value_x_unop (struct value *arg1, enum exp_opcode op, enum noside noside)
 >      error (_("Can't do that unary op on that type"));	/* FIXME be explicit */
 >  
 >    argvec = (struct value **) alloca (sizeof (struct value *) * 4);
 > +  argvec[0] = NULL;
 >    argvec[1] = value_addr (arg1);
 >    argvec[2] = 0;
 >  
 > @@ -574,8 +610,8 @@ value_x_unop (struct value *arg1, enum exp_opcode op, enum noside noside)
 >        error (_("Invalid unary operation specified."));
 >      }
 >  
 > -  argvec[0] = value_user_defined_op (&arg1, argvec + 1, tstr,
 > -                                     &static_memfuncp, nargs);
 > +  value_user_defined_op (&arg1, argvec + 1, tstr, &static_memfuncp, nargs,
 > +			 &argvec[0], &dm_worker);
 >  
 >    if (argvec[0])
 >      {
 > @@ -595,6 +631,14 @@ value_x_unop (struct value *arg1, enum exp_opcode op, enum noside noside)
 >  	}
 >        return call_function_by_hand (argvec[0], nargs, argvec + 1);
 >      }
 > +  if (dm_worker != NULL)
 > +    {
 > +      struct value *ret_val = invoke_debug_method (dm_worker, arg1, NULL, 0);
 > +
 > +      xfree (dm_worker);
 > +
 > +      return ret_val;
 > +    }

This needs a cleanup to free dm_worker.  See above for an example.

 >    throw_error (NOT_FOUND_ERROR,
 >                 _("member function %s not found"), tstr);
 >  
 > diff --git a/gdb/valops.c b/gdb/valops.c
 > index cf195a3..efd2cfb 100644
 > --- a/gdb/valops.c
 > +++ b/gdb/valops.c
 > @@ -42,6 +42,7 @@
 >  #include "observer.h"
 >  #include "objfiles.h"
 >  #include "exceptions.h"
 > +#include "extension.h"
 >  
 >  extern unsigned int overload_debug;
 >  /* Local functions.  */
 > @@ -70,8 +71,8 @@ int find_oload_champ_namespace_loop (struct value **, int,
 >  				     const int no_adl);
 >  
 >  static int find_oload_champ (struct value **, int, int,
 > -			     struct fn_field *, struct symbol **,
 > -			     struct badness_vector **);
 > +			     struct fn_field *, VEC (debug_method_worker_ptr) *,
 > +			     struct symbol **, struct badness_vector **);
 >  
 >  static int oload_method_static (int, struct fn_field *, int);
 >  
 > @@ -98,9 +99,10 @@ static CORE_ADDR allocate_space_in_inferior (int);
 >  
 >  static struct value *cast_into_complex (struct type *, struct value *);
 >  
 > -static struct fn_field *find_method_list (struct value **, const char *,
 > -					  int, struct type *, int *,
 > -					  struct type **, int *);
 > +static void find_method_list (struct value **, const char *,
 > +			      int, struct type *, struct fn_field **, int *,
 > +			      VEC (debug_method_worker_ptr) **,
 > +			      struct type **, int *);
 >  
 >  void _initialize_valops (void);
 >  
 > @@ -2242,53 +2244,83 @@ value_struct_elt_bitpos (struct value **argp, int bitpos, struct type *ftype,
 >  }
 >  
 >  /* Search through the methods of an object (and its bases) to find a
 > -   specified method.  Return the pointer to the fn_field list of
 > -   overloaded instances.
 > +   specified method.  Return the pointer to the fn_field list FN_LIST of
 > +   overloaded instances defined in the source language.  If available
 > +   and matching, a vector of matching debug methods defined in
 > +   extension languages are also returned in DM_WORKER_VEC
 >  
 >     Helper function for value_find_oload_list.
 >     ARGP is a pointer to a pointer to a value (the object).
 >     METHOD is a string containing the method name.
 >     OFFSET is the offset within the value.
 >     TYPE is the assumed type of the object.
 > +   FN_LIST The pointer to matching overloaded instances defined in
 > +      source language.
 >     NUM_FNS is the number of overloaded instances.
 > +   DM_WORKER_VEC The vector of matching debug method workers.
 >     BASETYPE is set to the actual type of the subobject where the
 >        method is found.
 >     BOFFSET is the offset of the base subobject where the method is found.  */
 >  
 > -static struct fn_field *
 > +static void
 >  find_method_list (struct value **argp, const char *method,
 > -		  int offset, struct type *type, int *num_fns,
 > +		  int offset, struct type *type,
 > +		  struct fn_field **fn_list, int *num_fns,
 > +		  VEC (debug_method_worker_ptr) **dm_worker_vec,
 >  		  struct type **basetype, int *boffset)
 >  {
 >    int i;
 > -  struct fn_field *f;
 > -  CHECK_TYPEDEF (type);
 > +  struct fn_field *f = NULL;
 >  
 > -  *num_fns = 0;
 > +  CHECK_TYPEDEF (type);
 >  
 > -  /* First check in object itself.  */
 > -  for (i = TYPE_NFN_FIELDS (type) - 1; i >= 0; i--)
 > +  /* First check in object itself.
 > +     This function is called recurssively to search through base classes.

recursively

 > +     If there is a source method match found at some stage, then we need not
 > +     look for source methods in consequent recursive calls.  */
 > +  if (fn_list && !(*fn_list))

Don't use ! to compare with NULL, use !=/==.
ref: https://sourceware.org/gdb/wiki/Internals%20GDB-C-Coding-Standards

I realize what you've got is shorter than

if (fn_list != NULL && (*fn_list) == NULL)

but alas that's the convention we have.
I'm not sure it's always followed, but I've noticed other reviewers
enforcing this and I'm just "going with the flow" here.

OTOH, I don't mind "if (ptr)" instead of "if (ptr != NULL)".
[but less so "if (!ptr)"]

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

Here's an example where I think this is fine as written, and doesn't need
to be:

	  if (fn_field_name != NULL
	      && (strcmp_iw (fn_field_name, method) == 0))

A stronger reason to keep the code as you've written is of course
because that's how the code originally was, you've just moved it,
so let's keep it as you've written in this case.

 > +	    {
 > +	      int len = TYPE_FN_FIELDLIST_LENGTH (type, i);
 > +	      f = TYPE_FN_FIELDLIST1 (type, i);
 > +	      *fn_list = f;
 >  
 > -	  /* Resolve any stub methods.  */
 > -	  check_stub_method_group (type, i);
 > +	      *num_fns = len;
 > +	      *basetype = type;
 > +	      *boffset = offset;
 > +
 > +	      /* Resolve any stub methods.  */
 > +	      check_stub_method_group (type, i);
 >  
 > -	  return f;
 > +	      break;
 > +	    }
 >  	}
 >      }
 >  
 > -  /* Not found in object, check in base subobjects.  */
 > +  /* Unlike source methods, debug methods can be accumulated over successive
 > +     recursive calls.  In other words, a debug method named 'm' in a class
 > +     will not hide a debug method named 'm' in its base class(es).  */
 > +  if (dm_worker_vec)
 > +    {
 > +      VEC (debug_method_worker_ptr) *worker_vec = NULL, *new_vec = NULL;
 > +
 > +      worker_vec = get_matching_debug_method_workers (type, method);
 > +      new_vec = VEC_merge (debug_method_worker_ptr, *dm_worker_vec, worker_vec);
 > +
 > +      VEC_free (debug_method_worker_ptr, *dm_worker_vec);
 > +      VEC_free (debug_method_worker_ptr, worker_vec);
 > +      *dm_worker_vec = new_vec;
 > +    }
 > +
 > +  /* If source methods are not found in current class, look for them in the
 > +     base classes.  We have to go through the base classes to gather extension
 > +     methods anyway.  */
 >    for (i = TYPE_N_BASECLASSES (type) - 1; i >= 0; i--)
 >      {
 >        int base_offset;
 > @@ -2305,28 +2337,35 @@ find_method_list (struct value **argp, const char *method,
 >  	{
 >  	  base_offset = TYPE_BASECLASS_BITPOS (type, i) / 8;
 >  	}
 > -      f = find_method_list (argp, method, base_offset + offset,
 > -			    TYPE_BASECLASS (type, i), num_fns, 
 > -			    basetype, boffset);
 > -      if (f)
 > -	return f;
 > +
 > +      find_method_list (argp, method, base_offset + offset,
 > +			TYPE_BASECLASS (type, i), fn_list, num_fns,
 > +			dm_worker_vec, basetype, boffset);
 >      }
 > -  return NULL;
 >  }
 >  
 > -/* Return the list of overloaded methods of a specified name.
 > +/* Return the list of overloaded methods of a specified name.  The methods
 > +   could be those GDB finds in the binary, or debug methods.  Methods found
 > +   in the binary are returned in FN_LIST, and debug methods are returned in
 > +   DM_WORKER_VEC.
 >  
 >     ARGP is a pointer to a pointer to a value (the object).
 >     METHOD is the method name.
 >     OFFSET is the offset within the value contents.
 > +   FN_LIST The pointer to matching overloaded instances defined in
 > +      source language.
 >     NUM_FNS is the number of overloaded instances.
 > +   DM_WORKER_VEC The vector of matching debug method workers defined in
 > +      extension languages.
 >     BASETYPE is set to the type of the base subobject that defines the
 >        method.
 >     BOFFSET is the offset of the base subobject which defines the method.  */
 >  
 > -static struct fn_field *
 > +static void
 >  value_find_oload_method_list (struct value **argp, const char *method,
 > -			      int offset, int *num_fns, 
 > +                              int offset, struct fn_field **fn_list,
 > +                              int *num_fns,
 > +                              VEC (debug_method_worker_ptr) **dm_worker_vec,
 >  			      struct type **basetype, int *boffset)
 >  {
 >    struct type *t;
 > @@ -2348,8 +2387,35 @@ value_find_oload_method_list (struct value **argp, const char *method,
 >      error (_("Attempt to extract a component of a "
 >  	     "value that is not a struct or union"));
 >  
 > -  return find_method_list (argp, method, 0, t, num_fns, 
 > -			   basetype, boffset);
 > +  /* Clear the lists.  */
 > +  if (fn_list)

!= NULL

 > +    {
 > +      *fn_list = NULL;
 > +      *num_fns = 0;
 > +    }
 > +  if (dm_worker_vec)

!= NULL

 > +    *dm_worker_vec = VEC_alloc (debug_method_worker_ptr, 1);

NULL is defined to be a valid value for a VEC, and the VEC routines
are supposed to [AFAICT] handle it appropriately.
Thus I'd rather see this be:

    *dm_worker_vec = NULL;

Or is there a reason why that doesn't work?

 > +
 > +  find_method_list (argp, method, 0, t, fn_list, num_fns, dm_worker_vec,
 > +		    basetype, boffset);
 > +}
 > +
 > +/* Return the dynamic type of OBJ.  NULL is returned if OBJ does not have any
 > +   dynamic type.  */
 > +
 > +static struct type *
 > +value_has_indirect_dynamic_type (struct value *obj)
 > +{
 > +  struct type *stype, *dtype, *dtype_ind;
 > +
 > +  stype = check_typedef (TYPE_TARGET_TYPE (value_type (obj)));
 > +  dtype_ind = value_rtti_indirect_type (obj, NULL, NULL, NULL);
 > +  dtype = dtype_ind ? check_typedef (TYPE_TARGET_TYPE (dtype_ind)) : stype;
 > +
 > +  if (class_types_same_p (stype, dtype))
 > +    return NULL;
 > +  else
 > +    return dtype_ind;

Seems like there's got to be a more efficient way to do this.
But that's an implementation detail that can be improved on later.

 >  }
 >  
 >  /* Given an array of arguments (ARGS) (which includes an
 > @@ -2377,9 +2443,10 @@ value_find_oload_method_list (struct value **argp, const char *method,
 >     Return value is an integer: 0 -> good match, 10 -> debugger applied
 >     non-standard coercions, 100 -> incompatible.
 >  
 > -   If a method is being searched for, VALP will hold the value.
 > -   If a non-method is being searched for, SYMP will hold the symbol 
 > -   for it.
 > +   If the best match is a debug method then DM_WORKER will hold the matching
 > +   debug method worker.  Otherwise, VALP will hold the value if a method is
 > +   being searched for, or SYMP will hold the symbol for the matching function
 > +   if a non-method is being searched for.
 >  
 >     If a method is being searched for, and it is a static method,
 >     then STATICP will point to a non-zero value.
 > @@ -2397,6 +2464,7 @@ find_overload_match (struct value **args, int nargs,
 >  		     const char *name, enum oload_search_type method,
 >  		     struct value **objp, struct symbol *fsym,
 >  		     struct value **valp, struct symbol **symp, 
 > +		     struct debug_method_worker **dm_worker,
 >  		     int *staticp, const int no_adl)
 >  {
 >    struct value *obj = (objp ? *objp : NULL);
 > @@ -2404,16 +2472,24 @@ find_overload_match (struct value **args, int nargs,
 >    /* Index of best overloaded function.  */
 >    int func_oload_champ = -1;
 >    int method_oload_champ = -1;
 > +  int src_method_oload_champ = -1;
 > +  int src_method_oload_champ_orig = -1;
 > +  int ext_method_oload_champ = -1;
 > +  int src_and_ext_equal = 0;
 >  
 >    /* The measure for the current best match.  */
 >    struct badness_vector *method_badness = NULL;
 >    struct badness_vector *func_badness = NULL;
 > +  struct badness_vector *ext_method_badness = NULL;
 > +  struct badness_vector *src_method_badness = NULL;
 >  
 >    struct value *temp = obj;
 >    /* For methods, the list of overloaded methods.  */
 >    struct fn_field *fns_ptr = NULL;
 >    /* For non-methods, the list of overloaded function symbols.  */
 >    struct symbol **oload_syms = NULL;
 > +  /* For extension functions, the VEC of extension function descriptors.  */

Replace "extension function descriptors" with something else,
"debug method workers"?

 > +  VEC (debug_method_worker_ptr) *dm_worker_vec = NULL;
 >    /* Number of overloaded instances being considered.  */
 >    int num_fns = 0;
 >    struct type *basetype = NULL;
 > @@ -2425,6 +2501,8 @@ find_overload_match (struct value **args, int nargs,
 >    const char *func_name = NULL;
 >    enum oload_classification match_quality;
 >    enum oload_classification method_match_quality = INCOMPATIBLE;
 > +  enum oload_classification src_method_match_quality = INCOMPATIBLE;
 > +  enum oload_classification ext_method_match_quality = INCOMPATIBLE;
 >    enum oload_classification func_match_quality = INCOMPATIBLE;
 >  
 >    /* Get the list of overloaded methods or functions.  */
 > @@ -2453,12 +2531,12 @@ find_overload_match (struct value **args, int nargs,
 >  	}
 >  
 >        /* Retrieve the list of methods with the name NAME.  */
 > -      fns_ptr = value_find_oload_method_list (&temp, name, 
 > -					      0, &num_fns, 
 > -					      &basetype, &boffset);
 > +      value_find_oload_method_list (&temp, name, 0, &fns_ptr, &num_fns,
 > +				    dm_worker ? &dm_worker_vec : NULL,
 > +				    &basetype, &boffset);
 >        /* If this is a method only search, and no methods were found
 >           the search has faild.  */
 > -      if (method == METHOD && (!fns_ptr || !num_fns))
 > +      if (method == METHOD && (!fns_ptr || !num_fns) && !dm_worker_vec)

Yeah, gdb doesn't consistently follow this rule as well as it could.
Let's leave this as is (and not write dm_worker_vec == NULL).

 >  	error (_("Couldn't find method %s%s%s"),
 >  	       obj_type_name,
 >  	       (obj_type_name && *obj_type_name) ? "::" : "",
 > @@ -2469,18 +2547,90 @@ find_overload_match (struct value **args, int nargs,
 >        if (fns_ptr)
 >  	{
 >  	  gdb_assert (TYPE_DOMAIN_TYPE (fns_ptr[0].type) != NULL);
 > -	  method_oload_champ = find_oload_champ (args, nargs,
 > -	                                         num_fns, fns_ptr,
 > -	                                         NULL, &method_badness);
 >  
 > -	  method_match_quality =
 > -	      classify_oload_match (method_badness, nargs,
 > -	                            oload_method_static (method, fns_ptr,
 > -	                                                 method_oload_champ));
 > +	  src_method_oload_champ = find_oload_champ (args, nargs,
 > +						     num_fns, fns_ptr, NULL,
 > +						     NULL, &src_method_badness);
 > +
 > +	  src_method_match_quality = classify_oload_match
 > +	    (src_method_badness, nargs,
 > +	     oload_method_static (method, fns_ptr, src_method_oload_champ));
 >  
 > -	  make_cleanup (xfree, method_badness);
 > +	  make_cleanup (xfree, src_method_badness);
 >  	}
 >  
 > +      if (dm_worker && VEC_length (debug_method_worker_ptr, dm_worker_vec))
 > +	{
 > +	  ext_method_oload_champ = find_oload_champ (args, nargs,
 > +						     0, NULL, dm_worker_vec,
 > +						     NULL, &ext_method_badness);
 > +	  ext_method_match_quality = classify_oload_match (ext_method_badness,
 > +							   nargs, 0);
 > +	  make_cleanup (xfree, ext_method_badness);
 > +	  make_debug_method_worker_vec_cleanup (dm_worker_vec);
 > +	}
 > +
 > +      if (src_method_oload_champ >= 0 && ext_method_oload_champ >= 0)
 > +	{
 > +	  switch (compare_badness (ext_method_badness, src_method_badness))
 > +	    {
 > +	      case 0: /* Src method and debug method are equally good.  */
 > +		src_and_ext_equal = 1;
 > +		/* If src method and debug method are equally good, then debug
 > +		   method should be the winner.  Hence, fall through to the
 > +		   case where a debug method is better than the source
 > +		   method, except when the debug method match quality is
 > +		   non-standard.  */
 > +		/* FALLTHROUGH */
 > +	      case 1: /* Src method and ext method are incompatible.  */
 > +		/* If ext method match is not standard, then let source method
 > +		   win.  Otherwise, fallthrough to let debug method win.  */
 > +		if (ext_method_match_quality != STANDARD)
 > +		  {
 > +		    method_oload_champ = src_method_oload_champ;
 > +		    method_badness = src_method_badness;
 > +		    ext_method_oload_champ = -1;
 > +		    method_match_quality = src_method_match_quality;
 > +		    break;
 > +		  }
 > +		/* FALLTHROUGH */
 > +	      case 2: /* Ext method is champion.  */
 > +		method_oload_champ = ext_method_oload_champ;
 > +		method_badness = ext_method_badness;
 > +		/* We save the source overload champ index so that it can be
 > +		   used to determine whether the source method is virtual
 > +		   later in this function.  */
 > +		src_method_oload_champ_orig = src_method_oload_champ;
 > +		src_method_oload_champ = -1;
 > +		method_match_quality = ext_method_match_quality;
 > +		break;
 > +	      case 3: /* Src method is champion.  */
 > +		method_oload_champ = src_method_oload_champ;
 > +		method_badness = src_method_badness;
 > +		ext_method_oload_champ = -1;
 > +		method_match_quality = src_method_match_quality;
 > +		break;
 > +	      default:
 > +		gdb_assert_not_reached (_("Internal error: unexpected overload "
 > +					  "comparison result"));

No need for I18N on args to gdb_assert_not_reached.

 > +		break;
 > +	    }
 > +	}
 > +      else

I think this would read better as:

      else if (src_method_oload_champ >= 0)
	{
	  ...;
	}
      else if (ext_method_oload_champ >= 0)
	{
	  ...;
	}

 > +	{
 > +	  if (src_method_oload_champ >= 0)
 > +	    {
 > +	      method_oload_champ = src_method_oload_champ;
 > +	      method_badness = src_method_badness;
 > +	      method_match_quality = src_method_match_quality;
 > +	    }
 > +	  if (ext_method_oload_champ >= 0)
 > +	    {
 > +	      method_oload_champ = ext_method_oload_champ;
 > +	      method_badness = ext_method_badness;
 > +	      method_match_quality = ext_method_match_quality;
 > +	    }
 > +	}
 >      }
 >  
 >    if (method == NON_METHOD || method == BOTH)
 > @@ -2623,21 +2773,6 @@ find_overload_match (struct value **args, int nargs,
 >  		 func_name);
 >      }
 >  
 > -  if (staticp != NULL)
 > -    *staticp = oload_method_static (method, fns_ptr, method_oload_champ);
 > -
 > -  if (method_oload_champ >= 0)
 > -    {
 > -      if (TYPE_FN_FIELD_VIRTUAL_P (fns_ptr, method_oload_champ))
 > -	*valp = value_virtual_fn_field (&temp, fns_ptr, method_oload_champ,
 > -					basetype, boffset);
 > -      else
 > -	*valp = value_fn_field (&temp, fns_ptr, method_oload_champ,
 > -				basetype, boffset);
 > -    }
 > -  else
 > -    *symp = oload_syms[func_oload_champ];
 > -
 >    if (objp)
 >      {
 >        struct type *temp_type = check_typedef (value_type (temp));
 > @@ -2647,10 +2782,75 @@ find_overload_match (struct value **args, int nargs,
 >  	  && (TYPE_CODE (objtype) == TYPE_CODE_PTR
 >  	      || TYPE_CODE (objtype) == TYPE_CODE_REF))
 >  	{
 > -	  temp = value_addr (temp);
 > +	  *objp = value_addr (temp);
 > +	}
 > +      else
 > +	*objp = temp;
 > +    }
 > +
 > +  if (staticp != NULL)
 > +    *staticp = oload_method_static (method, fns_ptr, method_oload_champ);
 > +

The following code to handle dynamic types seems excessively complex.
Plus we do a lot of work only to throw it away and start over (by calling
find_overload_match on the dynamic type).
Maybe instead of starting over, just look for the debug method on the
dynamic type and use that if it exists?  Thoughts?

 > +  if (method_oload_champ >= 0)
 > +    {
 > +      if (src_method_oload_champ >= 0)
 > +	{
 > +	  /* Even if the source method was the winner, it could be a virtual
 > +	     function.  In such a case, we should look for the possibility of
 > +	     debug methods defined on the object's dynamic type.  */
 > +	  if (TYPE_FN_FIELD_VIRTUAL_P (fns_ptr, method_oload_champ))
 > +	    {
 > +	      struct type *dtype;
 > +
 > +	      dtype = value_has_indirect_dynamic_type (args[0]);
 > +	      if (dtype)

!= NULL

 > +		{
 > +		  /* If the object has a dynamic type, then look for matching
 > +		     methods for its dynamic type.  */
 > +		  args[0] = value_cast (dtype, args[0]);
 > +		  do_cleanups (all_cleanups);
 > +		  return find_overload_match (args, nargs, name, method,
 > +					      objp, fsym, valp, symp, dm_worker,
 > +					      staticp, no_adl);
 > +		}
 > +	      else
 > +		*valp = value_virtual_fn_field (&temp, fns_ptr,
 > +						method_oload_champ,
 > +						basetype, boffset);
 > +	    }
 > +	  else
 > +	    *valp = value_fn_field (&temp, fns_ptr, method_oload_champ,
 > +				    basetype, boffset);
 > +	}
 > +      else
 > +	{
 > +	  /* Debug methods cannot be virtual.  However, if a debug method is as
 > +	     good as the source method, and if the source method is virtual, we
 > +	     should look for the possibility of better matching methods defined
 > +	     for the dynamic type of the object.  */
 > +	  if (src_and_ext_equal
 > +	      && TYPE_FN_FIELD_VIRTUAL_P (fns_ptr, src_method_oload_champ_orig))
 > +	    {
 > +	      struct type *dtype;
 > +
 > +	      dtype = value_has_indirect_dynamic_type (args[0]);
 > +	      if (dtype)

!= NULL

 > +		{
 > +		  args[0] = value_cast (dtype, args[0]);
 > +		  do_cleanups (all_cleanups);
 > +		  return find_overload_match (args, nargs, name, method,
 > +					      objp, fsym, valp, symp, dm_worker,
 > +					      staticp, no_adl);
 > +		}
 > +	    }
 > +
 > +	  *dm_worker = clone_debug_method_worker (
 > +	     VEC_index (debug_method_worker_ptr, dm_worker_vec,
 > +			ext_method_oload_champ));
 >  	}
 > -      *objp = temp;
 >      }
 > +  else
 > +    *symp = oload_syms[func_oload_champ];
 >  
 >    do_cleanups (all_cleanups);
 >  
 > @@ -2785,7 +2985,7 @@ find_oload_champ_namespace_loop (struct value **args, int nargs,
 >      ++num_fns;
 >  
 >    new_oload_champ = find_oload_champ (args, nargs, num_fns,
 > -				      NULL, new_oload_syms,
 > +				      NULL, NULL, new_oload_syms,
 >  				      &new_oload_champ_bv);
 >  
 >    /* Case 1: We found a good match.  Free earlier matches (if any),
 > @@ -2823,9 +3023,13 @@ find_oload_champ_namespace_loop (struct value **args, int nargs,
 >  
 >  /* Look for a function to take NARGS args of ARGS.  Find
 >     the best match from among the overloaded methods or functions
 > -   given by FNS_PTR or OLOAD_SYMS, respectively.  One, and only one of
 > -   FNS_PTR and OLOAD_SYMS can be non-NULL.  The number of
 > -   methods/functions in the non-NULL list is given by NUM_FNS.
 > +   given by FNS_PTR or OLOAD_SYMS or DM_WORKER_VEC, respectively.
 > +   One, and only one of FNS_PTR, OLOAD_SYMS and DM_WORKER_VEC can be
 > +   non-NULL.
 > +
 > +   If DM_WORKER_VEC is NULL, then the length of the arrays FNS_PTR
 > +   or OLOAD_SYMS (whichever is non-NULL) is specified in NUM_FNS.
 > +
 >     Return the index of the best match; store an indication of the
 >     quality of the match in OLOAD_CHAMP_BV.
 >  
 > @@ -2834,10 +3038,13 @@ find_oload_champ_namespace_loop (struct value **args, int nargs,
 >  static int
 >  find_oload_champ (struct value **args, int nargs,
 >  		  int num_fns, struct fn_field *fns_ptr,
 > +		  VEC (debug_method_worker_ptr) *dm_worker_vec,
 >  		  struct symbol **oload_syms,
 >  		  struct badness_vector **oload_champ_bv)
 >  {
 >    int ix;
 > +  int fn_count;
 > +  int dm_worker_vec_n = VEC_length (debug_method_worker_ptr, dm_worker_vec);
 >    /* A measure of how good an overloaded instance is.  */
 >    struct badness_vector *bv;
 >    /* Index of best overloaded function.  */
 > @@ -2847,40 +3054,49 @@ find_oload_champ (struct value **args, int nargs,
 >    /* 0 => no ambiguity, 1 => two good funcs, 2 => incomparable funcs.  */
 >  
 >    /* A champion can be found among methods alone, or among functions
 > -     alone, but not both.  */
 > -  gdb_assert ((fns_ptr != NULL) + (oload_syms != NULL) == 1);
 > +     alone, or in debug methods alone, but not in more than one of these
 > +     groups.  */
 > +  gdb_assert ((fns_ptr != NULL) + (oload_syms != NULL) + (dm_worker_vec != NULL)
 > +	      == 1);
 >  
 >    *oload_champ_bv = NULL;
 >  
 > +  fn_count = (dm_worker_vec != NULL
 > +	      ? VEC_length (debug_method_worker_ptr, dm_worker_vec)
 > +	      : num_fns);
 >    /* Consider each candidate in turn.  */
 > -  for (ix = 0; ix < num_fns; ix++)
 > +  for (ix = 0; ix < fn_count; ix++)
 >      {
 >        int jj;
 > -      int static_offset;
 > +      int static_offset = 0;
 >        int nparms;
 >        struct type **parm_types;
 > +      struct debug_method_worker *worker = NULL;
 >  
 > -      if (fns_ptr != NULL)
 > +      if (dm_worker_vec != NULL)
 >  	{
 > -	  nparms = TYPE_NFIELDS (TYPE_FN_FIELD_TYPE (fns_ptr, ix));
 > -	  static_offset = oload_method_static (1, fns_ptr, ix);
 > +	  worker = VEC_index (debug_method_worker_ptr, dm_worker_vec, ix);
 > +	  parm_types = get_debug_method_arg_types (worker, &nparms);
 >  	}
 >        else
 >  	{
 > -	  /* If it's not a method, this is the proper place.  */
 > -	  nparms = TYPE_NFIELDS (SYMBOL_TYPE (oload_syms[ix]));
 > -	  static_offset = 0;
 > +	  if (fns_ptr != NULL)
 > +	    {
 > +	      nparms = TYPE_NFIELDS (TYPE_FN_FIELD_TYPE (fns_ptr, ix));
 > +	      static_offset = oload_method_static (1, fns_ptr, ix);
 > +	    }
 > +	  else
 > +	    nparms = TYPE_NFIELDS (SYMBOL_TYPE (oload_syms[ix]));
 > +
 > +	  parm_types = (struct type **)
 > +	    xmalloc (nparms * (sizeof (struct type *)));
 > +	  for (jj = 0; jj < nparms; jj++)
 > +	    parm_types[jj] = (fns_ptr != NULL
 > +			      ? (TYPE_FN_FIELD_ARGS (fns_ptr, ix)[jj].type)
 > +			      : TYPE_FIELD_TYPE (SYMBOL_TYPE (oload_syms[ix]),
 > +			      jj));
 >  	}
 >  
 > -      /* Prepare array of parameter types.  */
 > -      parm_types = (struct type **) 
 > -	xmalloc (nparms * (sizeof (struct type *)));
 > -      for (jj = 0; jj < nparms; jj++)
 > -	parm_types[jj] = (fns_ptr != NULL
 > -			  ? (TYPE_FN_FIELD_ARGS (fns_ptr, ix)[jj].type)
 > -			  : TYPE_FIELD_TYPE (SYMBOL_TYPE (oload_syms[ix]), 
 > -					     jj));
 > -
 >        /* Compare parameter types to supplied argument types.  Skip
 >           THIS for static methods.  */
 >        bv = rank_function (parm_types, nparms, 
 > @@ -2914,10 +3130,14 @@ find_oload_champ (struct value **args, int nargs,
 >        xfree (parm_types);
 >        if (overload_debug)
 >  	{
 > -	  if (fns_ptr)
 > +	  if (fns_ptr != NULL)
 >  	    fprintf_filtered (gdb_stderr,
 >  			      "Overloaded method instance %s, # of parms %d\n",
 >  			      fns_ptr[ix].physname, nparms);
 > +	  else if (dm_worker_vec != NULL)
 > +	    fprintf_filtered (gdb_stderr,
 > +			      "Debug method worker, # of parms %d\n",
 > +			      nparms);
 >  	  else
 >  	    fprintf_filtered (gdb_stderr,
 >  			      "Overloaded function instance "

Hmmm, this should use gdb_stdlog, but that's a separate patch
since the existing code is wrong.  Leave your patch as is,
and leave fixing it to some later cleanup pass.

 > diff --git a/gdb/value.h b/gdb/value.h
 > index f846669..87bd109 100644
 > --- a/gdb/value.h
 > +++ b/gdb/value.h
 > @@ -31,6 +31,7 @@ struct type;
 >  struct ui_file;
 >  struct language_defn;
 >  struct value_print_options;
 > +struct debug_method_worker;
 >  
 >  /* The structure which defines the type of a value.  It should never
 >     be possible for a program lval value to survive over a call to the
 > @@ -690,6 +691,7 @@ extern int find_overload_match (struct value **args, int nargs,
 >  				enum oload_search_type method,
 >  				struct value **objp, struct symbol *fsym,
 >  				struct value **valp, struct symbol **symp,
 > +				struct debug_method_worker **dm_worker,
 >  				int *staticp, const int no_adl);
 >  
 >  extern struct value *value_field (struct value *arg1, int fieldno);
diff mbox

Patch

diff --git a/gdb/eval.c b/gdb/eval.c
index 36615e1..0d26585 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -22,6 +22,7 @@ 
 #include "symtab.h"
 #include "gdbtypes.h"
 #include "value.h"
+#include "extension.h"
 #include "expression.h"
 #include "target.h"
 #include "frame.h"
@@ -1591,11 +1592,11 @@  evaluate_subexp_standard (struct type *expect_type,
           func_name = (char *) alloca (name_len + 1);
           strcpy (func_name, &exp->elts[string_pc + 1].string);
 
-          find_overload_match (&argvec[1], nargs, func_name,
-                               NON_METHOD, /* not method */
-                               NULL, NULL, /* pass NULL symbol since
+	  find_overload_match (&argvec[1], nargs, func_name,
+			       NON_METHOD, /* not method */
+			       NULL, NULL, /* pass NULL symbol since
 					      symbol is unknown */
-                               NULL, &symp, NULL, 0);
+			       NULL, &symp, NULL, NULL, 0);
 
           /* Now fix the expression being evaluated.  */
           exp->elts[save_pos1 + 2].symbol = symp;
@@ -1625,11 +1626,12 @@  evaluate_subexp_standard (struct type *expect_type,
 	      /* Language is C++, do some overload resolution before
 		 evaluation.  */
 	      struct value *valp = NULL;
+	      struct debug_method_worker *dm_worker = NULL;
 
 	      (void) find_overload_match (&argvec[1], nargs, tstr,
-	                                  METHOD, /* method */
+					  METHOD, /* method */
 					  &arg2,  /* the object */
-					  NULL, &valp, NULL,
+					  NULL, &valp, NULL, &dm_worker,
 					  &static_memfuncp, 0);
 
 	      if (op == OP_SCOPE && !static_memfuncp)
@@ -1639,8 +1641,22 @@  evaluate_subexp_standard (struct type *expect_type,
 			   "`this' pointer"),
 			 function_name);
 		}
-	      argvec[1] = arg2;	/* the ``this'' pointer */
-	      argvec[0] = valp;	/* Use the method found after overload
+
+	      /* If a method implemented in an extension language is the best
+		 match, then invoke it.  */
+	      if (dm_worker)
+		{
+		  struct value *ret_val;
+
+		  ret_val = invoke_debug_method (dm_worker, arg2, argvec + 2,
+						 nargs - 1);
+		  xfree (dm_worker);
+
+		  return ret_val;
+		}
+
+	      argvec[1] = arg2; /* the ``this'' pointer */
+	      argvec[0] = valp; /* Use the method found after overload
 				   resolution.  */
 	    }
 	  else
@@ -1698,9 +1714,9 @@  evaluate_subexp_standard (struct type *expect_type,
 
 	      (void) find_overload_match (&argvec[1], nargs,
 					  NULL,        /* no need for name */
-	                                  NON_METHOD,  /* not method */
-	                                  NULL, function, /* the function */
-					  NULL, &symp, NULL, no_adl);
+					  NON_METHOD,  /* not method */
+					  NULL, function, /* the function */
+					  NULL, &symp, NULL, NULL, no_adl);
 
 	      if (op == OP_VAR_VALUE)
 		{
diff --git a/gdb/valarith.c b/gdb/valarith.c
index 8e863e3..9e79412 100644
--- a/gdb/valarith.c
+++ b/gdb/valarith.c
@@ -30,6 +30,7 @@ 
 #include <math.h>
 #include "infcall.h"
 #include "exceptions.h"
+#include "extension.h"
 
 /* Define whether or not the C operator '/' truncates towards zero for
    differently signed operands (truncation direction is undefined in C).  */
@@ -282,24 +283,34 @@  unop_user_defined_p (enum exp_opcode op, struct value *arg1)
    *STATIC_MEMFUNP will be set to 1, and otherwise 0.
    The search if performed through find_overload_match which will handle
    member operators, non member operators, operators imported implicitly or
-   explicitly, and perform correct overload resolution in all of the above
-   situations or combinations thereof.  */
+   explicitly, operators implemented as debug methods, and perform correct
+   overload resolution in all of the above situations or combinations
+   thereof.  If a matching method/function is found in the binary, its
+   corresponding value is returned in SRC_FN.  If a debug method is the best
+   match, then the corresponding debug method worker is returned in
+   DM_WORKER.  */
 
-static struct value *
+static void
 value_user_defined_cpp_op (struct value **args, int nargs, char *operator,
-                           int *static_memfuncp)
+			   struct value **src_fn,
+			   struct debug_method_worker **dm_worker,
+			   int *static_memfuncp)
 {
 
   struct symbol *symp = NULL;
   struct value *valp = NULL;
+  struct debug_method_worker *worker = NULL;
 
   find_overload_match (args, nargs, operator, BOTH /* could be method */,
-                       &args[0] /* objp */,
-                       NULL /* pass NULL symbol since symbol is unknown */,
-                       &valp, &symp, static_memfuncp, 0);
+		       &args[0] /* objp */,
+		       NULL /* pass NULL symbol since symbol is unknown */,
+		       &valp, &symp, &worker, static_memfuncp, 0);
 
   if (valp)
-    return valp;
+    {
+      *src_fn = valp;
+      return;
+    }
 
   if (symp)
     {
@@ -307,28 +318,41 @@  value_user_defined_cpp_op (struct value **args, int nargs, char *operator,
          expect a reference as its first argument
          rather the explicit structure.  */
       args[0] = value_ind (args[0]);
-      return value_of_variable (symp, 0);
+      *src_fn = value_of_variable (symp, 0);
+      return;
+    }
+
+  if (worker)
+    {
+      *dm_worker = worker;
+      return;
     }
 
   error (_("Could not find %s."), operator);
 }
 
-/* Lookup user defined operator NAME.  Return a value representing the
-   function, otherwise return NULL.  */
+/* Lookup user defined operator NAME.  If a matching operator is found in the
+   binary, its corresponding value is returned in SRC_FN.  If a debug method
+   is the best matching operator, then the corresponding debug method worker
+   is returned in DM_WORKER.  */
 
-static struct value *
+static void
 value_user_defined_op (struct value **argp, struct value **args, char *name,
-                       int *static_memfuncp, int nargs)
+		       int *static_memfuncp, int nargs,
+		       struct value **src_fn,
+		       struct debug_method_worker **dm_worker)
 {
   struct value *result = NULL;
 
   if (current_language->la_language == language_cplus)
-    result = value_user_defined_cpp_op (args, nargs, name, static_memfuncp);
+    value_user_defined_cpp_op (args, nargs, name, src_fn, dm_worker,
+			       static_memfuncp);
   else
-    result = value_struct_elt (argp, args, name, static_memfuncp,
-                               "structure");
-
-  return result;
+    {
+      result = value_struct_elt (argp, args, name, static_memfuncp,
+				 "structure");
+      *src_fn = result;
+    }
 }
 
 /* We know either arg1 or arg2 is a structure, so try to find the right
@@ -345,6 +369,7 @@  value_x_binop (struct value *arg1, struct value *arg2, enum exp_opcode op,
 	       enum exp_opcode otherop, enum noside noside)
 {
   struct value **argvec;
+  struct debug_method_worker *dm_worker = NULL;
   char *ptr;
   char tstr[13];
   int static_memfuncp;
@@ -359,6 +384,7 @@  value_x_binop (struct value *arg1, struct value *arg2, enum exp_opcode op,
     error (_("Can't do that binary op on that type"));	/* FIXME be explicit */
 
   argvec = (struct value **) alloca (sizeof (struct value *) * 4);
+  argvec[0] = NULL;
   argvec[1] = value_addr (arg1);
   argvec[2] = arg2;
   argvec[3] = 0;
@@ -471,8 +497,8 @@  value_x_binop (struct value *arg1, struct value *arg2, enum exp_opcode op,
       error (_("Invalid binary operation specified."));
     }
 
-  argvec[0] = value_user_defined_op (&arg1, argvec + 1, tstr,
-                                     &static_memfuncp, 2);
+  value_user_defined_op (&arg1, argvec + 1, tstr, &static_memfuncp, 2,
+			 &argvec[0], &dm_worker);
 
   if (argvec[0])
     {
@@ -492,6 +518,14 @@  value_x_binop (struct value *arg1, struct value *arg2, enum exp_opcode op,
       return call_function_by_hand (argvec[0], 2 - static_memfuncp,
 				    argvec + 1);
     }
+  if (dm_worker != NULL)
+    {
+      struct value *ret_val = invoke_debug_method (dm_worker, arg1, &arg2, 1);
+
+      xfree (dm_worker);
+
+      return ret_val;
+    }
   throw_error (NOT_FOUND_ERROR,
                _("member function %s not found"), tstr);
 #ifdef lint
@@ -510,6 +544,7 @@  value_x_unop (struct value *arg1, enum exp_opcode op, enum noside noside)
 {
   struct gdbarch *gdbarch = get_type_arch (value_type (arg1));
   struct value **argvec;
+  struct debug_method_worker *dm_worker;
   char *ptr;
   char tstr[13], mangle_tstr[13];
   int static_memfuncp, nargs;
@@ -523,6 +558,7 @@  value_x_unop (struct value *arg1, enum exp_opcode op, enum noside noside)
     error (_("Can't do that unary op on that type"));	/* FIXME be explicit */
 
   argvec = (struct value **) alloca (sizeof (struct value *) * 4);
+  argvec[0] = NULL;
   argvec[1] = value_addr (arg1);
   argvec[2] = 0;
 
@@ -574,8 +610,8 @@  value_x_unop (struct value *arg1, enum exp_opcode op, enum noside noside)
       error (_("Invalid unary operation specified."));
     }
 
-  argvec[0] = value_user_defined_op (&arg1, argvec + 1, tstr,
-                                     &static_memfuncp, nargs);
+  value_user_defined_op (&arg1, argvec + 1, tstr, &static_memfuncp, nargs,
+			 &argvec[0], &dm_worker);
 
   if (argvec[0])
     {
@@ -595,6 +631,14 @@  value_x_unop (struct value *arg1, enum exp_opcode op, enum noside noside)
 	}
       return call_function_by_hand (argvec[0], nargs, argvec + 1);
     }
+  if (dm_worker != NULL)
+    {
+      struct value *ret_val = invoke_debug_method (dm_worker, arg1, NULL, 0);
+
+      xfree (dm_worker);
+
+      return ret_val;
+    }
   throw_error (NOT_FOUND_ERROR,
                _("member function %s not found"), tstr);
 
diff --git a/gdb/valops.c b/gdb/valops.c
index cf195a3..efd2cfb 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -42,6 +42,7 @@ 
 #include "observer.h"
 #include "objfiles.h"
 #include "exceptions.h"
+#include "extension.h"
 
 extern unsigned int overload_debug;
 /* Local functions.  */
@@ -70,8 +71,8 @@  int find_oload_champ_namespace_loop (struct value **, int,
 				     const int no_adl);
 
 static int find_oload_champ (struct value **, int, int,
-			     struct fn_field *, struct symbol **,
-			     struct badness_vector **);
+			     struct fn_field *, VEC (debug_method_worker_ptr) *,
+			     struct symbol **, struct badness_vector **);
 
 static int oload_method_static (int, struct fn_field *, int);
 
@@ -98,9 +99,10 @@  static CORE_ADDR allocate_space_in_inferior (int);
 
 static struct value *cast_into_complex (struct type *, struct value *);
 
-static struct fn_field *find_method_list (struct value **, const char *,
-					  int, struct type *, int *,
-					  struct type **, int *);
+static void find_method_list (struct value **, const char *,
+			      int, struct type *, struct fn_field **, int *,
+			      VEC (debug_method_worker_ptr) **,
+			      struct type **, int *);
 
 void _initialize_valops (void);
 
@@ -2242,53 +2244,83 @@  value_struct_elt_bitpos (struct value **argp, int bitpos, struct type *ftype,
 }
 
 /* Search through the methods of an object (and its bases) to find a
-   specified method.  Return the pointer to the fn_field list of
-   overloaded instances.
+   specified method.  Return the pointer to the fn_field list FN_LIST of
+   overloaded instances defined in the source language.  If available
+   and matching, a vector of matching debug methods defined in
+   extension languages are also returned in DM_WORKER_VEC
 
    Helper function for value_find_oload_list.
    ARGP is a pointer to a pointer to a value (the object).
    METHOD is a string containing the method name.
    OFFSET is the offset within the value.
    TYPE is the assumed type of the object.
+   FN_LIST The pointer to matching overloaded instances defined in
+      source language.
    NUM_FNS is the number of overloaded instances.
+   DM_WORKER_VEC The vector of matching debug method workers.
    BASETYPE is set to the actual type of the subobject where the
       method is found.
    BOFFSET is the offset of the base subobject where the method is found.  */
 
-static struct fn_field *
+static void
 find_method_list (struct value **argp, const char *method,
-		  int offset, struct type *type, int *num_fns,
+		  int offset, struct type *type,
+		  struct fn_field **fn_list, int *num_fns,
+		  VEC (debug_method_worker_ptr) **dm_worker_vec,
 		  struct type **basetype, int *boffset)
 {
   int i;
-  struct fn_field *f;
-  CHECK_TYPEDEF (type);
+  struct fn_field *f = NULL;
 
-  *num_fns = 0;
+  CHECK_TYPEDEF (type);
 
-  /* First check in object itself.  */
-  for (i = TYPE_NFN_FIELDS (type) - 1; i >= 0; i--)
+  /* First check in object itself.
+     This function is called recurssively to search through base classes.
+     If there is a source method match found at some stage, then we need not
+     look for source methods in consequent recursive calls.  */
+  if (fn_list && !(*fn_list))
     {
-      /* pai: FIXME What about operators and type conversions?  */
-      const char *fn_field_name = TYPE_FN_FIELDLIST_NAME (type, i);
-
-      if (fn_field_name && (strcmp_iw (fn_field_name, method) == 0))
+      for (i = TYPE_NFN_FIELDS (type) - 1; i >= 0; i--)
 	{
-	  int len = TYPE_FN_FIELDLIST_LENGTH (type, i);
-	  struct fn_field *f = TYPE_FN_FIELDLIST1 (type, i);
+	  /* pai: FIXME What about operators and type conversions?  */
+	  const char *fn_field_name = TYPE_FN_FIELDLIST_NAME (type, i);
 
-	  *num_fns = len;
-	  *basetype = type;
-	  *boffset = offset;
+	  if (fn_field_name && (strcmp_iw (fn_field_name, method) == 0))
+	    {
+	      int len = TYPE_FN_FIELDLIST_LENGTH (type, i);
+	      f = TYPE_FN_FIELDLIST1 (type, i);
+	      *fn_list = f;
 
-	  /* Resolve any stub methods.  */
-	  check_stub_method_group (type, i);
+	      *num_fns = len;
+	      *basetype = type;
+	      *boffset = offset;
+
+	      /* Resolve any stub methods.  */
+	      check_stub_method_group (type, i);
 
-	  return f;
+	      break;
+	    }
 	}
     }
 
-  /* Not found in object, check in base subobjects.  */
+  /* Unlike source methods, debug methods can be accumulated over successive
+     recursive calls.  In other words, a debug method named 'm' in a class
+     will not hide a debug method named 'm' in its base class(es).  */
+  if (dm_worker_vec)
+    {
+      VEC (debug_method_worker_ptr) *worker_vec = NULL, *new_vec = NULL;
+
+      worker_vec = get_matching_debug_method_workers (type, method);
+      new_vec = VEC_merge (debug_method_worker_ptr, *dm_worker_vec, worker_vec);
+
+      VEC_free (debug_method_worker_ptr, *dm_worker_vec);
+      VEC_free (debug_method_worker_ptr, worker_vec);
+      *dm_worker_vec = new_vec;
+    }
+
+  /* If source methods are not found in current class, look for them in the
+     base classes.  We have to go through the base classes to gather extension
+     methods anyway.  */
   for (i = TYPE_N_BASECLASSES (type) - 1; i >= 0; i--)
     {
       int base_offset;
@@ -2305,28 +2337,35 @@  find_method_list (struct value **argp, const char *method,
 	{
 	  base_offset = TYPE_BASECLASS_BITPOS (type, i) / 8;
 	}
-      f = find_method_list (argp, method, base_offset + offset,
-			    TYPE_BASECLASS (type, i), num_fns, 
-			    basetype, boffset);
-      if (f)
-	return f;
+
+      find_method_list (argp, method, base_offset + offset,
+			TYPE_BASECLASS (type, i), fn_list, num_fns,
+			dm_worker_vec, basetype, boffset);
     }
-  return NULL;
 }
 
-/* Return the list of overloaded methods of a specified name.
+/* Return the list of overloaded methods of a specified name.  The methods
+   could be those GDB finds in the binary, or debug methods.  Methods found
+   in the binary are returned in FN_LIST, and debug methods are returned in
+   DM_WORKER_VEC.
 
    ARGP is a pointer to a pointer to a value (the object).
    METHOD is the method name.
    OFFSET is the offset within the value contents.
+   FN_LIST The pointer to matching overloaded instances defined in
+      source language.
    NUM_FNS is the number of overloaded instances.
+   DM_WORKER_VEC The vector of matching debug method workers defined in
+      extension languages.
    BASETYPE is set to the type of the base subobject that defines the
       method.
    BOFFSET is the offset of the base subobject which defines the method.  */
 
-static struct fn_field *
+static void
 value_find_oload_method_list (struct value **argp, const char *method,
-			      int offset, int *num_fns, 
+                              int offset, struct fn_field **fn_list,
+                              int *num_fns,
+                              VEC (debug_method_worker_ptr) **dm_worker_vec,
 			      struct type **basetype, int *boffset)
 {
   struct type *t;
@@ -2348,8 +2387,35 @@  value_find_oload_method_list (struct value **argp, const char *method,
     error (_("Attempt to extract a component of a "
 	     "value that is not a struct or union"));
 
-  return find_method_list (argp, method, 0, t, num_fns, 
-			   basetype, boffset);
+  /* Clear the lists.  */
+  if (fn_list)
+    {
+      *fn_list = NULL;
+      *num_fns = 0;
+    }
+  if (dm_worker_vec)
+    *dm_worker_vec = VEC_alloc (debug_method_worker_ptr, 1);
+
+  find_method_list (argp, method, 0, t, fn_list, num_fns, dm_worker_vec,
+		    basetype, boffset);
+}
+
+/* Return the dynamic type of OBJ.  NULL is returned if OBJ does not have any
+   dynamic type.  */
+
+static struct type *
+value_has_indirect_dynamic_type (struct value *obj)
+{
+  struct type *stype, *dtype, *dtype_ind;
+
+  stype = check_typedef (TYPE_TARGET_TYPE (value_type (obj)));
+  dtype_ind = value_rtti_indirect_type (obj, NULL, NULL, NULL);
+  dtype = dtype_ind ? check_typedef (TYPE_TARGET_TYPE (dtype_ind)) : stype;
+
+  if (class_types_same_p (stype, dtype))
+    return NULL;
+  else
+    return dtype_ind;
 }
 
 /* Given an array of arguments (ARGS) (which includes an
@@ -2377,9 +2443,10 @@  value_find_oload_method_list (struct value **argp, const char *method,
    Return value is an integer: 0 -> good match, 10 -> debugger applied
    non-standard coercions, 100 -> incompatible.
 
-   If a method is being searched for, VALP will hold the value.
-   If a non-method is being searched for, SYMP will hold the symbol 
-   for it.
+   If the best match is a debug method then DM_WORKER will hold the matching
+   debug method worker.  Otherwise, VALP will hold the value if a method is
+   being searched for, or SYMP will hold the symbol for the matching function
+   if a non-method is being searched for.
 
    If a method is being searched for, and it is a static method,
    then STATICP will point to a non-zero value.
@@ -2397,6 +2464,7 @@  find_overload_match (struct value **args, int nargs,
 		     const char *name, enum oload_search_type method,
 		     struct value **objp, struct symbol *fsym,
 		     struct value **valp, struct symbol **symp, 
+		     struct debug_method_worker **dm_worker,
 		     int *staticp, const int no_adl)
 {
   struct value *obj = (objp ? *objp : NULL);
@@ -2404,16 +2472,24 @@  find_overload_match (struct value **args, int nargs,
   /* Index of best overloaded function.  */
   int func_oload_champ = -1;
   int method_oload_champ = -1;
+  int src_method_oload_champ = -1;
+  int src_method_oload_champ_orig = -1;
+  int ext_method_oload_champ = -1;
+  int src_and_ext_equal = 0;
 
   /* The measure for the current best match.  */
   struct badness_vector *method_badness = NULL;
   struct badness_vector *func_badness = NULL;
+  struct badness_vector *ext_method_badness = NULL;
+  struct badness_vector *src_method_badness = NULL;
 
   struct value *temp = obj;
   /* For methods, the list of overloaded methods.  */
   struct fn_field *fns_ptr = NULL;
   /* For non-methods, the list of overloaded function symbols.  */
   struct symbol **oload_syms = NULL;
+  /* For extension functions, the VEC of extension function descriptors.  */
+  VEC (debug_method_worker_ptr) *dm_worker_vec = NULL;
   /* Number of overloaded instances being considered.  */
   int num_fns = 0;
   struct type *basetype = NULL;
@@ -2425,6 +2501,8 @@  find_overload_match (struct value **args, int nargs,
   const char *func_name = NULL;
   enum oload_classification match_quality;
   enum oload_classification method_match_quality = INCOMPATIBLE;
+  enum oload_classification src_method_match_quality = INCOMPATIBLE;
+  enum oload_classification ext_method_match_quality = INCOMPATIBLE;
   enum oload_classification func_match_quality = INCOMPATIBLE;
 
   /* Get the list of overloaded methods or functions.  */
@@ -2453,12 +2531,12 @@  find_overload_match (struct value **args, int nargs,
 	}
 
       /* Retrieve the list of methods with the name NAME.  */
-      fns_ptr = value_find_oload_method_list (&temp, name, 
-					      0, &num_fns, 
-					      &basetype, &boffset);
+      value_find_oload_method_list (&temp, name, 0, &fns_ptr, &num_fns,
+				    dm_worker ? &dm_worker_vec : NULL,
+				    &basetype, &boffset);
       /* If this is a method only search, and no methods were found
          the search has faild.  */
-      if (method == METHOD && (!fns_ptr || !num_fns))
+      if (method == METHOD && (!fns_ptr || !num_fns) && !dm_worker_vec)
 	error (_("Couldn't find method %s%s%s"),
 	       obj_type_name,
 	       (obj_type_name && *obj_type_name) ? "::" : "",
@@ -2469,18 +2547,90 @@  find_overload_match (struct value **args, int nargs,
       if (fns_ptr)
 	{
 	  gdb_assert (TYPE_DOMAIN_TYPE (fns_ptr[0].type) != NULL);
-	  method_oload_champ = find_oload_champ (args, nargs,
-	                                         num_fns, fns_ptr,
-	                                         NULL, &method_badness);
 
-	  method_match_quality =
-	      classify_oload_match (method_badness, nargs,
-	                            oload_method_static (method, fns_ptr,
-	                                                 method_oload_champ));
+	  src_method_oload_champ = find_oload_champ (args, nargs,
+						     num_fns, fns_ptr, NULL,
+						     NULL, &src_method_badness);
+
+	  src_method_match_quality = classify_oload_match
+	    (src_method_badness, nargs,
+	     oload_method_static (method, fns_ptr, src_method_oload_champ));
 
-	  make_cleanup (xfree, method_badness);
+	  make_cleanup (xfree, src_method_badness);
 	}
 
+      if (dm_worker && VEC_length (debug_method_worker_ptr, dm_worker_vec))
+	{
+	  ext_method_oload_champ = find_oload_champ (args, nargs,
+						     0, NULL, dm_worker_vec,
+						     NULL, &ext_method_badness);
+	  ext_method_match_quality = classify_oload_match (ext_method_badness,
+							   nargs, 0);
+	  make_cleanup (xfree, ext_method_badness);
+	  make_debug_method_worker_vec_cleanup (dm_worker_vec);
+	}
+
+      if (src_method_oload_champ >= 0 && ext_method_oload_champ >= 0)
+	{
+	  switch (compare_badness (ext_method_badness, src_method_badness))
+	    {
+	      case 0: /* Src method and debug method are equally good.  */
+		src_and_ext_equal = 1;
+		/* If src method and debug method are equally good, then debug
+		   method should be the winner.  Hence, fall through to the
+		   case where a debug method is better than the source
+		   method, except when the debug method match quality is
+		   non-standard.  */
+		/* FALLTHROUGH */
+	      case 1: /* Src method and ext method are incompatible.  */
+		/* If ext method match is not standard, then let source method
+		   win.  Otherwise, fallthrough to let debug method win.  */
+		if (ext_method_match_quality != STANDARD)
+		  {
+		    method_oload_champ = src_method_oload_champ;
+		    method_badness = src_method_badness;
+		    ext_method_oload_champ = -1;
+		    method_match_quality = src_method_match_quality;
+		    break;
+		  }
+		/* FALLTHROUGH */
+	      case 2: /* Ext method is champion.  */
+		method_oload_champ = ext_method_oload_champ;
+		method_badness = ext_method_badness;
+		/* We save the source overload champ index so that it can be
+		   used to determine whether the source method is virtual
+		   later in this function.  */
+		src_method_oload_champ_orig = src_method_oload_champ;
+		src_method_oload_champ = -1;
+		method_match_quality = ext_method_match_quality;
+		break;
+	      case 3: /* Src method is champion.  */
+		method_oload_champ = src_method_oload_champ;
+		method_badness = src_method_badness;
+		ext_method_oload_champ = -1;
+		method_match_quality = src_method_match_quality;
+		break;
+	      default:
+		gdb_assert_not_reached (_("Internal error: unexpected overload "
+					  "comparison result"));
+		break;
+	    }
+	}
+      else
+	{
+	  if (src_method_oload_champ >= 0)
+	    {
+	      method_oload_champ = src_method_oload_champ;
+	      method_badness = src_method_badness;
+	      method_match_quality = src_method_match_quality;
+	    }
+	  if (ext_method_oload_champ >= 0)
+	    {
+	      method_oload_champ = ext_method_oload_champ;
+	      method_badness = ext_method_badness;
+	      method_match_quality = ext_method_match_quality;
+	    }
+	}
     }
 
   if (method == NON_METHOD || method == BOTH)
@@ -2623,21 +2773,6 @@  find_overload_match (struct value **args, int nargs,
 		 func_name);
     }
 
-  if (staticp != NULL)
-    *staticp = oload_method_static (method, fns_ptr, method_oload_champ);
-
-  if (method_oload_champ >= 0)
-    {
-      if (TYPE_FN_FIELD_VIRTUAL_P (fns_ptr, method_oload_champ))
-	*valp = value_virtual_fn_field (&temp, fns_ptr, method_oload_champ,
-					basetype, boffset);
-      else
-	*valp = value_fn_field (&temp, fns_ptr, method_oload_champ,
-				basetype, boffset);
-    }
-  else
-    *symp = oload_syms[func_oload_champ];
-
   if (objp)
     {
       struct type *temp_type = check_typedef (value_type (temp));
@@ -2647,10 +2782,75 @@  find_overload_match (struct value **args, int nargs,
 	  && (TYPE_CODE (objtype) == TYPE_CODE_PTR
 	      || TYPE_CODE (objtype) == TYPE_CODE_REF))
 	{
-	  temp = value_addr (temp);
+	  *objp = value_addr (temp);
+	}
+      else
+	*objp = temp;
+    }
+
+  if (staticp != NULL)
+    *staticp = oload_method_static (method, fns_ptr, method_oload_champ);
+
+  if (method_oload_champ >= 0)
+    {
+      if (src_method_oload_champ >= 0)
+	{
+	  /* Even if the source method was the winner, it could be a virtual
+	     function.  In such a case, we should look for the possibility of
+	     debug methods defined on the object's dynamic type.  */
+	  if (TYPE_FN_FIELD_VIRTUAL_P (fns_ptr, method_oload_champ))
+	    {
+	      struct type *dtype;
+
+	      dtype = value_has_indirect_dynamic_type (args[0]);
+	      if (dtype)
+		{
+		  /* If the object has a dynamic type, then look for matching
+		     methods for its dynamic type.  */
+		  args[0] = value_cast (dtype, args[0]);
+		  do_cleanups (all_cleanups);
+		  return find_overload_match (args, nargs, name, method,
+					      objp, fsym, valp, symp, dm_worker,
+					      staticp, no_adl);
+		}
+	      else
+		*valp = value_virtual_fn_field (&temp, fns_ptr,
+						method_oload_champ,
+						basetype, boffset);
+	    }
+	  else
+	    *valp = value_fn_field (&temp, fns_ptr, method_oload_champ,
+				    basetype, boffset);
+	}
+      else
+	{
+	  /* Debug methods cannot be virtual.  However, if a debug method is as
+	     good as the source method, and if the source method is virtual, we
+	     should look for the possibility of better matching methods defined
+	     for the dynamic type of the object.  */
+	  if (src_and_ext_equal
+	      && TYPE_FN_FIELD_VIRTUAL_P (fns_ptr, src_method_oload_champ_orig))
+	    {
+	      struct type *dtype;
+
+	      dtype = value_has_indirect_dynamic_type (args[0]);
+	      if (dtype)
+		{
+		  args[0] = value_cast (dtype, args[0]);
+		  do_cleanups (all_cleanups);
+		  return find_overload_match (args, nargs, name, method,
+					      objp, fsym, valp, symp, dm_worker,
+					      staticp, no_adl);
+		}
+	    }
+
+	  *dm_worker = clone_debug_method_worker (
+	     VEC_index (debug_method_worker_ptr, dm_worker_vec,
+			ext_method_oload_champ));
 	}
-      *objp = temp;
     }
+  else
+    *symp = oload_syms[func_oload_champ];
 
   do_cleanups (all_cleanups);
 
@@ -2785,7 +2985,7 @@  find_oload_champ_namespace_loop (struct value **args, int nargs,
     ++num_fns;
 
   new_oload_champ = find_oload_champ (args, nargs, num_fns,
-				      NULL, new_oload_syms,
+				      NULL, NULL, new_oload_syms,
 				      &new_oload_champ_bv);
 
   /* Case 1: We found a good match.  Free earlier matches (if any),
@@ -2823,9 +3023,13 @@  find_oload_champ_namespace_loop (struct value **args, int nargs,
 
 /* Look for a function to take NARGS args of ARGS.  Find
    the best match from among the overloaded methods or functions
-   given by FNS_PTR or OLOAD_SYMS, respectively.  One, and only one of
-   FNS_PTR and OLOAD_SYMS can be non-NULL.  The number of
-   methods/functions in the non-NULL list is given by NUM_FNS.
+   given by FNS_PTR or OLOAD_SYMS or DM_WORKER_VEC, respectively.
+   One, and only one of FNS_PTR, OLOAD_SYMS and DM_WORKER_VEC can be
+   non-NULL.
+
+   If DM_WORKER_VEC is NULL, then the length of the arrays FNS_PTR
+   or OLOAD_SYMS (whichever is non-NULL) is specified in NUM_FNS.
+
    Return the index of the best match; store an indication of the
    quality of the match in OLOAD_CHAMP_BV.
 
@@ -2834,10 +3038,13 @@  find_oload_champ_namespace_loop (struct value **args, int nargs,
 static int
 find_oload_champ (struct value **args, int nargs,
 		  int num_fns, struct fn_field *fns_ptr,
+		  VEC (debug_method_worker_ptr) *dm_worker_vec,
 		  struct symbol **oload_syms,
 		  struct badness_vector **oload_champ_bv)
 {
   int ix;
+  int fn_count;
+  int dm_worker_vec_n = VEC_length (debug_method_worker_ptr, dm_worker_vec);
   /* A measure of how good an overloaded instance is.  */
   struct badness_vector *bv;
   /* Index of best overloaded function.  */
@@ -2847,40 +3054,49 @@  find_oload_champ (struct value **args, int nargs,
   /* 0 => no ambiguity, 1 => two good funcs, 2 => incomparable funcs.  */
 
   /* A champion can be found among methods alone, or among functions
-     alone, but not both.  */
-  gdb_assert ((fns_ptr != NULL) + (oload_syms != NULL) == 1);
+     alone, or in debug methods alone, but not in more than one of these
+     groups.  */
+  gdb_assert ((fns_ptr != NULL) + (oload_syms != NULL) + (dm_worker_vec != NULL)
+	      == 1);
 
   *oload_champ_bv = NULL;
 
+  fn_count = (dm_worker_vec != NULL
+	      ? VEC_length (debug_method_worker_ptr, dm_worker_vec)
+	      : num_fns);
   /* Consider each candidate in turn.  */
-  for (ix = 0; ix < num_fns; ix++)
+  for (ix = 0; ix < fn_count; ix++)
     {
       int jj;
-      int static_offset;
+      int static_offset = 0;
       int nparms;
       struct type **parm_types;
+      struct debug_method_worker *worker = NULL;
 
-      if (fns_ptr != NULL)
+      if (dm_worker_vec != NULL)
 	{
-	  nparms = TYPE_NFIELDS (TYPE_FN_FIELD_TYPE (fns_ptr, ix));
-	  static_offset = oload_method_static (1, fns_ptr, ix);
+	  worker = VEC_index (debug_method_worker_ptr, dm_worker_vec, ix);
+	  parm_types = get_debug_method_arg_types (worker, &nparms);
 	}
       else
 	{
-	  /* If it's not a method, this is the proper place.  */
-	  nparms = TYPE_NFIELDS (SYMBOL_TYPE (oload_syms[ix]));
-	  static_offset = 0;
+	  if (fns_ptr != NULL)
+	    {
+	      nparms = TYPE_NFIELDS (TYPE_FN_FIELD_TYPE (fns_ptr, ix));
+	      static_offset = oload_method_static (1, fns_ptr, ix);
+	    }
+	  else
+	    nparms = TYPE_NFIELDS (SYMBOL_TYPE (oload_syms[ix]));
+
+	  parm_types = (struct type **)
+	    xmalloc (nparms * (sizeof (struct type *)));
+	  for (jj = 0; jj < nparms; jj++)
+	    parm_types[jj] = (fns_ptr != NULL
+			      ? (TYPE_FN_FIELD_ARGS (fns_ptr, ix)[jj].type)
+			      : TYPE_FIELD_TYPE (SYMBOL_TYPE (oload_syms[ix]),
+			      jj));
 	}
 
-      /* Prepare array of parameter types.  */
-      parm_types = (struct type **) 
-	xmalloc (nparms * (sizeof (struct type *)));
-      for (jj = 0; jj < nparms; jj++)
-	parm_types[jj] = (fns_ptr != NULL
-			  ? (TYPE_FN_FIELD_ARGS (fns_ptr, ix)[jj].type)
-			  : TYPE_FIELD_TYPE (SYMBOL_TYPE (oload_syms[ix]), 
-					     jj));
-
       /* Compare parameter types to supplied argument types.  Skip
          THIS for static methods.  */
       bv = rank_function (parm_types, nparms, 
@@ -2914,10 +3130,14 @@  find_oload_champ (struct value **args, int nargs,
       xfree (parm_types);
       if (overload_debug)
 	{
-	  if (fns_ptr)
+	  if (fns_ptr != NULL)
 	    fprintf_filtered (gdb_stderr,
 			      "Overloaded method instance %s, # of parms %d\n",
 			      fns_ptr[ix].physname, nparms);
+	  else if (dm_worker_vec != NULL)
+	    fprintf_filtered (gdb_stderr,
+			      "Debug method worker, # of parms %d\n",
+			      nparms);
 	  else
 	    fprintf_filtered (gdb_stderr,
 			      "Overloaded function instance "
diff --git a/gdb/value.h b/gdb/value.h
index f846669..87bd109 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -31,6 +31,7 @@  struct type;
 struct ui_file;
 struct language_defn;
 struct value_print_options;
+struct debug_method_worker;
 
 /* The structure which defines the type of a value.  It should never
    be possible for a program lval value to survive over a call to the
@@ -690,6 +691,7 @@  extern int find_overload_match (struct value **args, int nargs,
 				enum oload_search_type method,
 				struct value **objp, struct symbol *fsym,
 				struct value **valp, struct symbol **symp,
+				struct debug_method_worker **dm_worker,
 				int *staticp, const int no_adl);
 
 extern struct value *value_field (struct value *arg1, int fieldno);