diff mbox

[2/2,v2] Enable having chained function calls in expressions

Message ID CAGyQ6gy8tQ0L4t3Dy1hJhuiW=mVvm+iJ4fkv9P0VnA09wi_jhw@mail.gmail.com
State New
Headers show

Commit Message

Siva Chandra Reddy Oct. 1, 2014, 12:45 a.m. UTC
Enable having chained function calls in expressions.

Link to description: https://sourceware.org/ml/gdb-patches/2014-09/msg00788.html

gdb/ChangeLog:

2014-09-30  Siva Chandra Reddy  <sivachandra@google.com>

        * eval.c (evaluate_expression): Cleanup stack mirrors that might
        have been created.
        (add_value_to_expression_stack, skip_current_expression_stack): New
        functions.
        * infcall.c (call_function_by_hand): New argument EXP of type
        struct expression *. Setup stack mirrors for return values.
        (get_return_value_from_memory): New function.
        * infcall.h (call_function_by_hand): Update signature and all callers.
        * valarith.c (value_x_binop): New argument EXP of type
        struct expression *.
        (value_x_unop): Likewise.
        * value.c (add_value_to_expression_stack)
        (skip_current_expression_stack): New functions.
        * value.h (add_value_to_expression_stack)
        (skip_current_expression_stack): Declare.
        (value_x_binop, value_x_unop): Update signature and all callers.

gdb/testsuite/ChangeLog:

2014-09-30  Siva Chandra Reddy  <sivachandra@google.com>

        * gdb.cp/chained-calls.cc: New file.
        * gdb.cp/chained-calls.exp: New file.
        * gdb.cp/smartp.exp: Remove KFAIL from c2->inta.
diff mbox

Patch

diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index c7e50e2..df849b8 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -10290,7 +10290,7 @@  ada_evaluate_subexp (struct type *expect_type, struct expression *exp,
 		return allocate_value (TYPE_TARGET_TYPE (rtype));
 	      return allocate_value (rtype);
 	    }
-          return call_function_by_hand (argvec[0], nargs, argvec + 1);
+          return call_function_by_hand (argvec[0], nargs, argvec + 1, exp);
 	case TYPE_CODE_INTERNAL_FUNCTION:
 	  if (noside == EVAL_AVOID_SIDE_EFFECTS)
 	    /* We don't know anything about what the internal
diff --git a/gdb/elfread.c b/gdb/elfread.c
index 9b8233c..588953f 100644
--- a/gdb/elfread.c
+++ b/gdb/elfread.c
@@ -952,7 +952,7 @@  elf_gnu_ifunc_resolve_addr (struct gdbarch *gdbarch, CORE_ADDR pc)
   /* STT_GNU_IFUNC resolver functions have no parameters.  FUNCTION is the
      function entry address.  ADDRESS may be a function descriptor.  */
 
-  address_val = call_function_by_hand (function, 0, NULL);
+  address_val = call_function_by_hand (function, 0, NULL, NULL);
   address = value_as_address (address_val);
   address = gdbarch_convert_from_func_ptr_addr (gdbarch, address,
 						&current_target);
diff --git a/gdb/eval.c b/gdb/eval.c
index c379209..1811e9f 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -39,6 +39,7 @@ 
 #include "valprint.h"
 #include "gdb_obstack.h"
 #include "objfiles.h"
+#include "common/vec.h"
 #include <ctype.h>
 
 /* This is defined in valops.c */
@@ -138,8 +139,58 @@  struct value *
 evaluate_expression (struct expression *exp)
 {
   int pc = 0;
+  struct value *res;
+  struct cleanup *cleanups;
 
-  return evaluate_subexp (NULL_TYPE, exp, &pc, EVAL_NORMAL);
+  cleanups = make_cleanup (VEC_cleanup (value_ptr), &exp->stack_mirror_vec);
+  res = evaluate_subexp (NULL_TYPE, exp, &pc, EVAL_NORMAL);
+  do_cleanups (cleanups);
+
+  return res;
+
+}
+
+/* Add value V to the expression stack of expression EXP.  */
+
+void
+add_value_to_expression_stack (struct expression *exp, struct value *v)
+{
+  gdb_assert (exp != NULL);
+  VEC_safe_push (value_ptr, exp->stack_mirror_vec, v);
+}
+
+/* Return an address after skipping over the current values on the expression
+   stack of EXP.  SP is the current stack frame pointer.  Non-zero DOWNWARD
+   indicates that the stack grows downwards/backwards.  */
+
+CORE_ADDR
+skip_current_expression_stack (struct expression *exp, CORE_ADDR sp,
+			       int downward)
+{
+  CORE_ADDR addr = sp;
+
+  gdb_assert (exp != NULL);
+  if (!VEC_empty (value_ptr, exp->stack_mirror_vec))
+    {
+      struct value *v = VEC_last (value_ptr, exp->stack_mirror_vec);
+      CORE_ADDR val_addr = value_address (v);
+
+      if (downward)
+	{
+	  gdb_assert (sp >= val_addr);
+	  addr = val_addr;
+	}
+      else
+	{
+	  struct type *type;
+
+	  gdb_assert (sp <= val_addr);
+	  type = value_type (v);
+	  addr = val_addr + TYPE_LENGTH (type);
+	}
+    }
+
+  return addr;
 }
 
 /* Evaluate an expression, avoiding all memory references
@@ -1144,12 +1195,12 @@  evaluate_subexp_standard (struct type *expect_type,
 	argvec[3] = value_from_longest (long_type, selector);
 	argvec[4] = 0;
 
-	ret = call_function_by_hand (argvec[0], 3, argvec + 1);
+	ret = call_function_by_hand (argvec[0], 3, argvec + 1, exp);
 	if (gnu_runtime)
 	  {
 	    /* Function objc_msg_lookup returns a pointer.  */
 	    argvec[0] = ret;
-	    ret = call_function_by_hand (argvec[0], 3, argvec + 1);
+	    ret = call_function_by_hand (argvec[0], 3, argvec + 1, exp);
 	  }
 	if (value_as_long (ret) == 0)
 	  error (_("Target does not respond to this message selector."));
@@ -1166,11 +1217,11 @@  evaluate_subexp_standard (struct type *expect_type,
 	argvec[3] = value_from_longest (long_type, selector);
 	argvec[4] = 0;
 
-	ret = call_function_by_hand (argvec[0], 3, argvec + 1);
+	ret = call_function_by_hand (argvec[0], 3, argvec + 1, exp);
 	if (gnu_runtime)
 	  {
 	    argvec[0] = ret;
-	    ret = call_function_by_hand (argvec[0], 3, argvec + 1);
+	    ret = call_function_by_hand (argvec[0], 3, argvec + 1, exp);
 	  }
 
 	/* ret should now be the selector.  */
@@ -1312,10 +1363,10 @@  evaluate_subexp_standard (struct type *expect_type,
 	    deprecated_set_value_type (argvec[0],
 				       lookup_pointer_type (lookup_function_type (value_type (argvec[0]))));
 	    argvec[0]
-	      = call_function_by_hand (argvec[0], nargs + 2, argvec + 1);
+	      = call_function_by_hand (argvec[0], nargs + 2, argvec + 1, exp);
 	  }
 
-	ret = call_function_by_hand (argvec[0], nargs + 2, argvec + 1);
+	ret = call_function_by_hand (argvec[0], nargs + 2, argvec + 1, exp);
 	return ret;
       }
       break;
@@ -1432,7 +1483,7 @@  evaluate_subexp_standard (struct type *expect_type,
 		  struct value *value = NULL;
 		  TRY_CATCH (except, RETURN_MASK_ERROR)
 		    {
-		      value = value_x_unop (arg2, op, noside);
+		      value = value_x_unop (arg2, op, noside, exp);
 		    }
 
 		  if (except.reason < 0)
@@ -1735,7 +1786,7 @@  evaluate_subexp_standard (struct type *expect_type,
 	case TYPE_CODE_XMETHOD:
 	  return call_xmethod (argvec[0], nargs, argvec + 1);
 	default:
-	  return call_function_by_hand (argvec[0], nargs, argvec + 1);
+	  return call_function_by_hand (argvec[0], nargs, argvec + 1, exp);
 	}
       /* pai: FIXME save value from call_function_by_hand, then adjust
 	 pc by adjust_fn_pc if +ve.  */
@@ -1846,7 +1897,7 @@  evaluate_subexp_standard (struct type *expect_type,
 	  struct value *value = NULL;
 	  TRY_CATCH (except, RETURN_MASK_ERROR)
 	    {
-	      value = value_x_unop (arg1, op, noside);
+	      value = value_x_unop (arg1, op, noside, exp);
 	    }
 
 	  if (except.reason < 0)
@@ -1946,7 +1997,7 @@  evaluate_subexp_standard (struct type *expect_type,
       if (noside == EVAL_SKIP)
 	goto nosideret;
       if (binop_user_defined_p (op, arg1, arg2))
-	return value_x_binop (arg1, arg2, op, OP_NULL, noside);
+	return value_x_binop (arg1, arg2, op, OP_NULL, noside, exp);
       else
 	return value_concat (arg1, arg2);
 
@@ -1957,7 +2008,7 @@  evaluate_subexp_standard (struct type *expect_type,
       if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS)
 	return arg1;
       if (binop_user_defined_p (op, arg1, arg2))
-	return value_x_binop (arg1, arg2, op, OP_NULL, noside);
+	return value_x_binop (arg1, arg2, op, OP_NULL, noside, exp);
       else
 	return value_assign (arg1, arg2);
 
@@ -1969,7 +2020,8 @@  evaluate_subexp_standard (struct type *expect_type,
 	return arg1;
       op = exp->elts[pc + 1].opcode;
       if (binop_user_defined_p (op, arg1, arg2))
-	return value_x_binop (arg1, arg2, BINOP_ASSIGN_MODIFY, op, noside);
+	return value_x_binop (arg1, arg2, BINOP_ASSIGN_MODIFY, op, noside,
+			      exp);
       else if (op == BINOP_ADD && ptrmath_type_p (exp->language_defn,
 						  value_type (arg1))
 	       && is_integral_type (value_type (arg2)))
@@ -2000,7 +2052,7 @@  evaluate_subexp_standard (struct type *expect_type,
       if (noside == EVAL_SKIP)
 	goto nosideret;
       if (binop_user_defined_p (op, arg1, arg2))
-	return value_x_binop (arg1, arg2, op, OP_NULL, noside);
+	return value_x_binop (arg1, arg2, op, OP_NULL, noside, exp);
       else if (ptrmath_type_p (exp->language_defn, value_type (arg1))
 	       && is_integral_type (value_type (arg2)))
 	return value_ptradd (arg1, value_as_long (arg2));
@@ -2019,7 +2071,7 @@  evaluate_subexp_standard (struct type *expect_type,
       if (noside == EVAL_SKIP)
 	goto nosideret;
       if (binop_user_defined_p (op, arg1, arg2))
-	return value_x_binop (arg1, arg2, op, OP_NULL, noside);
+	return value_x_binop (arg1, arg2, op, OP_NULL, noside, exp);
       else if (ptrmath_type_p (exp->language_defn, value_type (arg1))
 	       && ptrmath_type_p (exp->language_defn, value_type (arg2)))
 	{
@@ -2052,7 +2104,7 @@  evaluate_subexp_standard (struct type *expect_type,
       if (noside == EVAL_SKIP)
 	goto nosideret;
       if (binop_user_defined_p (op, arg1, arg2))
-	return value_x_binop (arg1, arg2, op, OP_NULL, noside);
+	return value_x_binop (arg1, arg2, op, OP_NULL, noside, exp);
       else
 	{
 	  /* If EVAL_AVOID_SIDE_EFFECTS and we're dividing by zero,
@@ -2095,7 +2147,7 @@  evaluate_subexp_standard (struct type *expect_type,
       if (noside == EVAL_SKIP)
 	goto nosideret;
       if (binop_user_defined_p (op, arg1, arg2))
-	return value_x_binop (arg1, arg2, op, OP_NULL, noside);
+	return value_x_binop (arg1, arg2, op, OP_NULL, noside, exp);
       else
 	{
 	  /* If the user attempts to subscript something that is not an
@@ -2161,7 +2213,7 @@  evaluate_subexp_standard (struct type *expect_type,
 
 	  if (binop_user_defined_p (op, arg1, arg2))
 	    {
-	      arg1 = value_x_binop (arg1, arg2, op, OP_NULL, noside);
+	      arg1 = value_x_binop (arg1, arg2, op, OP_NULL, noside, exp);
 	    }
 	  else
 	    {
@@ -2245,7 +2297,7 @@  evaluate_subexp_standard (struct type *expect_type,
       if (binop_user_defined_p (op, arg1, arg2))
 	{
 	  arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
-	  return value_x_binop (arg1, arg2, op, OP_NULL, noside);
+	  return value_x_binop (arg1, arg2, op, OP_NULL, noside, exp);
 	}
       else
 	{
@@ -2272,7 +2324,7 @@  evaluate_subexp_standard (struct type *expect_type,
       if (binop_user_defined_p (op, arg1, arg2))
 	{
 	  arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
-	  return value_x_binop (arg1, arg2, op, OP_NULL, noside);
+	  return value_x_binop (arg1, arg2, op, OP_NULL, noside, exp);
 	}
       else
 	{
@@ -2291,7 +2343,7 @@  evaluate_subexp_standard (struct type *expect_type,
 	goto nosideret;
       if (binop_user_defined_p (op, arg1, arg2))
 	{
-	  return value_x_binop (arg1, arg2, op, OP_NULL, noside);
+	  return value_x_binop (arg1, arg2, op, OP_NULL, noside, exp);
 	}
       else
 	{
@@ -2308,7 +2360,7 @@  evaluate_subexp_standard (struct type *expect_type,
 	goto nosideret;
       if (binop_user_defined_p (op, arg1, arg2))
 	{
-	  return value_x_binop (arg1, arg2, op, OP_NULL, noside);
+	  return value_x_binop (arg1, arg2, op, OP_NULL, noside, exp);
 	}
       else
 	{
@@ -2325,7 +2377,7 @@  evaluate_subexp_standard (struct type *expect_type,
 	goto nosideret;
       if (binop_user_defined_p (op, arg1, arg2))
 	{
-	  return value_x_binop (arg1, arg2, op, OP_NULL, noside);
+	  return value_x_binop (arg1, arg2, op, OP_NULL, noside, exp);
 	}
       else
 	{
@@ -2342,7 +2394,7 @@  evaluate_subexp_standard (struct type *expect_type,
 	goto nosideret;
       if (binop_user_defined_p (op, arg1, arg2))
 	{
-	  return value_x_binop (arg1, arg2, op, OP_NULL, noside);
+	  return value_x_binop (arg1, arg2, op, OP_NULL, noside, exp);
 	}
       else
 	{
@@ -2359,7 +2411,7 @@  evaluate_subexp_standard (struct type *expect_type,
 	goto nosideret;
       if (binop_user_defined_p (op, arg1, arg2))
 	{
-	  return value_x_binop (arg1, arg2, op, OP_NULL, noside);
+	  return value_x_binop (arg1, arg2, op, OP_NULL, noside, exp);
 	}
       else
 	{
@@ -2376,7 +2428,7 @@  evaluate_subexp_standard (struct type *expect_type,
 	goto nosideret;
       if (binop_user_defined_p (op, arg1, arg2))
 	{
-	  return value_x_binop (arg1, arg2, op, OP_NULL, noside);
+	  return value_x_binop (arg1, arg2, op, OP_NULL, noside, exp);
 	}
       else
 	{
@@ -2411,7 +2463,7 @@  evaluate_subexp_standard (struct type *expect_type,
       if (noside == EVAL_SKIP)
 	goto nosideret;
       if (unop_user_defined_p (op, arg1))
-	return value_x_unop (arg1, op, noside);
+	return value_x_unop (arg1, op, noside, exp);
       else
 	{
 	  unop_promote (exp->language_defn, exp->gdbarch, &arg1);
@@ -2423,7 +2475,7 @@  evaluate_subexp_standard (struct type *expect_type,
       if (noside == EVAL_SKIP)
 	goto nosideret;
       if (unop_user_defined_p (op, arg1))
-	return value_x_unop (arg1, op, noside);
+	return value_x_unop (arg1, op, noside, exp);
       else
 	{
 	  unop_promote (exp->language_defn, exp->gdbarch, &arg1);
@@ -2438,7 +2490,7 @@  evaluate_subexp_standard (struct type *expect_type,
       if (noside == EVAL_SKIP)
 	goto nosideret;
       if (unop_user_defined_p (UNOP_COMPLEMENT, arg1))
-	return value_x_unop (arg1, UNOP_COMPLEMENT, noside);
+	return value_x_unop (arg1, UNOP_COMPLEMENT, noside, exp);
       else
 	{
 	  unop_promote (exp->language_defn, exp->gdbarch, &arg1);
@@ -2450,7 +2502,7 @@  evaluate_subexp_standard (struct type *expect_type,
       if (noside == EVAL_SKIP)
 	goto nosideret;
       if (unop_user_defined_p (op, arg1))
-	return value_x_unop (arg1, op, noside);
+	return value_x_unop (arg1, op, noside, exp);
       else
 	{
 	  type = language_bool_type (exp->language_defn, exp->gdbarch);
@@ -2469,7 +2521,7 @@  evaluate_subexp_standard (struct type *expect_type,
       if (noside == EVAL_SKIP)
 	goto nosideret;
       if (unop_user_defined_p (op, arg1))
-	return value_x_unop (arg1, op, noside);
+	return value_x_unop (arg1, op, noside, exp);
       else if (noside == EVAL_AVOID_SIDE_EFFECTS)
 	{
 	  type = check_typedef (value_type (arg1));
@@ -2603,7 +2655,7 @@  evaluate_subexp_standard (struct type *expect_type,
 	return arg1;
       else if (unop_user_defined_p (op, arg1))
 	{
-	  return value_x_unop (arg1, op, noside);
+	  return value_x_unop (arg1, op, noside, exp);
 	}
       else
 	{
@@ -2627,7 +2679,7 @@  evaluate_subexp_standard (struct type *expect_type,
 	return arg1;
       else if (unop_user_defined_p (op, arg1))
 	{
-	  return value_x_unop (arg1, op, noside);
+	  return value_x_unop (arg1, op, noside, exp);
 	}
       else
 	{
@@ -2651,7 +2703,7 @@  evaluate_subexp_standard (struct type *expect_type,
 	return arg1;
       else if (unop_user_defined_p (op, arg1))
 	{
-	  return value_x_unop (arg1, op, noside);
+	  return value_x_unop (arg1, op, noside, exp);
 	}
       else
 	{
@@ -2678,7 +2730,7 @@  evaluate_subexp_standard (struct type *expect_type,
 	return arg1;
       else if (unop_user_defined_p (op, arg1))
 	{
-	  return value_x_unop (arg1, op, noside);
+	  return value_x_unop (arg1, op, noside, exp);
 	}
       else
 	{
@@ -2828,7 +2880,7 @@  evaluate_subexp_for_address (struct expression *exp, int *pos,
       /* We can't optimize out "&*" if there's a user-defined operator*.  */
       if (unop_user_defined_p (op, x))
 	{
-	  x = value_x_unop (x, op, noside);
+	  x = value_x_unop (x, op, noside, exp);
 	  goto default_case_after_eval;
 	}
 
diff --git a/gdb/expression.h b/gdb/expression.h
index 4081a60..96b33c2 100644
--- a/gdb/expression.h
+++ b/gdb/expression.h
@@ -76,11 +76,17 @@  union exp_element
     struct objfile *objfile;
   };
 
+struct value;
+typedef struct value *value_ptr;
+DEF_VEC_P (value_ptr);
+typedef VEC (value_ptr) value_vec;
+
 struct expression
   {
     const struct language_defn *language_defn;	/* language it was
 						   entered in.  */
     struct gdbarch *gdbarch;  /* architecture it was parsed in.  */
+    value_vec *stack_mirror_vec; 
     int nelts;
     union exp_element elts[1];
   };
diff --git a/gdb/gcore.c b/gdb/gcore.c
index d2adfc8..c4ba961 100644
--- a/gdb/gcore.c
+++ b/gdb/gcore.c
@@ -308,7 +308,7 @@  call_target_sbrk (int sbrk_arg)
   target_sbrk_arg = value_from_longest (builtin_type (gdbarch)->builtin_int, 
 					sbrk_arg);
   gdb_assert (target_sbrk_arg);
-  ret = call_function_by_hand (sbrk_fn, 1, &target_sbrk_arg);
+  ret = call_function_by_hand (sbrk_fn, 1, &target_sbrk_arg, NULL);
   if (ret == NULL)
     return (bfd_vma) 0;
 
diff --git a/gdb/infcall.c b/gdb/infcall.c
index e60d1d4..b0cb5ca 100644
--- a/gdb/infcall.c
+++ b/gdb/infcall.c
@@ -456,6 +456,35 @@  cleanup_delete_std_terminate_breakpoint (void *ignore)
   delete_std_terminate_breakpoint ();
 }
 
+/* Reads a value returned by an inferior function for those return
+   values whose address is passed as the hidden first argument.
+   TYPE is the type of value.  ADDR is the address from where to read it.
+   EXP is the expression whose evaluation lead to calling the inferior
+   function.  It is NULL if the inferior function call was not made while
+   evaluating an expression.  */
+
+static struct value *
+get_return_value_from_memory (struct type *type, CORE_ADDR addr,
+			      struct expression *exp)
+{
+  struct value *retval;
+  if (exp != NULL)
+    {
+      struct value *mirror;
+
+      mirror = value_from_contents_and_address (type, NULL, addr);
+      add_value_to_expression_stack (exp, mirror);
+      retval = allocate_value_mirrored_on_stack (mirror);
+    }
+  else
+    retval = allocate_value (type);
+
+  read_value_memory (retval, 0, 1, addr, value_contents_raw (retval),
+		     TYPE_LENGTH (type));
+
+  return retval;
+}
+
 /* All this stuff with a dummy frame may seem unnecessarily complicated
    (why not just save registers in GDB?).  The purpose of pushing a dummy
    frame which looks just like a real frame is so that if you call a
@@ -472,10 +501,14 @@  cleanup_delete_std_terminate_breakpoint (void *ignore)
    May fail to return, if a breakpoint or signal is hit
    during the execution of the function.
 
-   ARGS is modified to contain coerced values.  */
+   ARGS is modified to contain coerced values.
+   EXP is the expression whose evaluation lead to calling the inferior
+   function.  It is NULL if the inferior function call was not made while
+   evaluating an expression.  */
 
 struct value *
-call_function_by_hand (struct value *function, int nargs, struct value **args)
+call_function_by_hand (struct value *function, int nargs, struct value **args,
+		       struct expression *exp)
 {
   CORE_ADDR sp;
   struct type *values_type, *target_values_type;
@@ -533,6 +566,16 @@  call_function_by_hand (struct value *function, int nargs, struct value **args)
   {
     CORE_ADDR old_sp = get_frame_sp (frame);
 
+    /* Skip over the stack mirrors that might have been generated during the
+       evaluation of the current expression.  */
+    if (exp != NULL)
+      {
+	if (gdbarch_inner_than (gdbarch, 1, 2))
+	  old_sp = skip_current_expression_stack (exp, old_sp, 1);
+	else
+	  old_sp = skip_current_expression_stack (exp, old_sp, 0);
+      }
+
     if (gdbarch_frame_align_p (gdbarch))
       {
 	sp = gdbarch_frame_align (gdbarch, old_sp);
@@ -719,10 +762,17 @@  call_function_by_hand (struct value *function, int nargs, struct value **args)
   }
 
   /* Reserve space for the return structure to be written on the
-     stack, if necessary.  Make certain that the value is correctly
-     aligned.  */
+     stack if necessary.  Make certain that the value is correctly
+     aligned.
 
-  if (struct_return || hidden_first_param_p)
+     While evaluating expressions, we reserve space on the stack for the
+     return value even if the language ABI and the target ABI do not require
+     that the return value be passed as an hidden first argument.  This is
+     because we want to store the return value as an on-stack mirror of the
+     actual value returned by this function.  This enables us to have chained
+     function calls in expressions.  */
+
+  if (struct_return || hidden_first_param_p || exp != NULL)
     {
       if (gdbarch_inner_than (gdbarch, 1, 2))
 	{
@@ -1060,33 +1110,39 @@  When the function is done executing, GDB will silently stop."),
        At this stage, leave the RETBUF alone.  */
     restore_infcall_control_state (inf_status);
 
-    /* Figure out the value returned by the function.  */
-    retval = allocate_value (values_type);
-
     if (hidden_first_param_p)
-      read_value_memory (retval, 0, 1, struct_addr,
-			 value_contents_raw (retval),
-			 TYPE_LENGTH (values_type));
+      retval = get_return_value_from_memory (values_type, struct_addr, exp);
     else if (TYPE_CODE (target_values_type) != TYPE_CODE_VOID)
       {
 	/* If the function returns void, don't bother fetching the
 	   return value.  */
+	struct value *mirror;
+
 	switch (gdbarch_return_value (gdbarch, function, target_values_type,
 				      NULL, NULL, NULL))
 	  {
 	  case RETURN_VALUE_REGISTER_CONVENTION:
 	  case RETURN_VALUE_ABI_RETURNS_ADDRESS:
 	  case RETURN_VALUE_ABI_PRESERVES_ADDRESS:
+	    retval = allocate_value (values_type);
 	    gdbarch_return_value (gdbarch, function, values_type,
 				  retbuf, value_contents_raw (retval), NULL);
+	    if (exp != NULL)
+	      {
+		struct value *mirror;
+
+		mirror = setup_stack_mirror (retval, struct_addr);
+		add_value_to_expression_stack (exp, mirror);
+	      }
 	    break;
 	  case RETURN_VALUE_STRUCT_CONVENTION:
-	    read_value_memory (retval, 0, 1, struct_addr,
-			       value_contents_raw (retval),
-			       TYPE_LENGTH (values_type));
+	    retval = get_return_value_from_memory (values_type, struct_addr,
+						   exp);
 	    break;
 	  }
       }
+    else
+      retval = allocate_value (values_type);
 
     do_cleanups (retbuf_cleanup);
 
diff --git a/gdb/infcall.h b/gdb/infcall.h
index c6dcdc3..4de931b 100644
--- a/gdb/infcall.h
+++ b/gdb/infcall.h
@@ -22,6 +22,7 @@ 
 
 struct value;
 struct type;
+struct expression;
 
 extern CORE_ADDR find_function_addr (struct value *function, 
 				     struct type **retval_type);
@@ -36,6 +37,7 @@  extern CORE_ADDR find_function_addr (struct value *function,
    ARGS is modified to contain coerced values.  */
 
 extern struct value *call_function_by_hand (struct value *function, int nargs,
-					    struct value **args);
+					    struct value **args,
+					    struct expression *exp);
 
 #endif
diff --git a/gdb/linux-fork.c b/gdb/linux-fork.c
index 835e612..8ba4741 100644
--- a/gdb/linux-fork.c
+++ b/gdb/linux-fork.c
@@ -468,7 +468,7 @@  inferior_call_waitpid (ptid_t pptid, int pid)
   argv[2] = value_from_longest (builtin_type (gdbarch)->builtin_int, 0);
   argv[3] = 0;
 
-  retv = call_function_by_hand (waitpid_fn, 3, argv);
+  retv = call_function_by_hand (waitpid_fn, 3, argv, NULL);
   if (value_as_long (retv) < 0)
     goto out;
 
@@ -683,7 +683,7 @@  checkpoint_command (char *args, int from_tty)
   old_chain = make_cleanup_restore_integer (&checkpointing_pid);
   checkpointing_pid = ptid_get_pid (inferior_ptid);
 
-  ret = call_function_by_hand (fork_fn, 0, &ret);
+  ret = call_function_by_hand (fork_fn, 0, &ret, NULL);
   do_cleanups (old_chain);
   if (!ret)	/* Probably can't happen.  */
     error (_("checkpoint: call_function_by_hand returned null."));
diff --git a/gdb/objc-lang.c b/gdb/objc-lang.c
index d911d8f..08c2d6b 100644
--- a/gdb/objc-lang.c
+++ b/gdb/objc-lang.c
@@ -132,7 +132,7 @@  lookup_objc_class (struct gdbarch *gdbarch, char *classname)
   classval = value_string (classname, strlen (classname) + 1, char_type);
   classval = value_coerce_array (classval);
   return (CORE_ADDR) value_as_long (call_function_by_hand (function, 
-							   1, &classval));
+							   1, &classval, NULL));
 }
 
 CORE_ADDR
@@ -161,7 +161,7 @@  lookup_child_selector (struct gdbarch *gdbarch, char *selname)
   selstring = value_coerce_array (value_string (selname, 
 						strlen (selname) + 1,
 						char_type));
-  return value_as_long (call_function_by_hand (function, 1, &selstring));
+  return value_as_long (call_function_by_hand (function, 1, &selstring, NULL));
 }
 
 struct value * 
@@ -182,12 +182,12 @@  value_nsstring (struct gdbarch *gdbarch, char *ptr, int len)
   if (lookup_minimal_symbol("_NSNewStringFromCString", 0, 0).minsym)
     {
       function = find_function_in_inferior("_NSNewStringFromCString", NULL);
-      nsstringValue = call_function_by_hand(function, 1, &stringValue[2]);
+      nsstringValue = call_function_by_hand(function, 1, &stringValue[2], NULL);
     }
   else if (lookup_minimal_symbol("istr", 0, 0).minsym)
     {
       function = find_function_in_inferior("istr", NULL);
-      nsstringValue = call_function_by_hand(function, 1, &stringValue[2]);
+      nsstringValue = call_function_by_hand(function, 1, &stringValue[2], NULL);
     }
   else if (lookup_minimal_symbol("+[NSString stringWithCString:]", 0, 0).minsym)
     {
@@ -199,7 +199,7 @@  value_nsstring (struct gdbarch *gdbarch, char *ptr, int len)
 	(type, lookup_objc_class (gdbarch, "NSString"));
       stringValue[1] = value_from_longest 
 	(type, lookup_child_selector (gdbarch, "stringWithCString:"));
-      nsstringValue = call_function_by_hand(function, 3, &stringValue[0]);
+      nsstringValue = call_function_by_hand(function, 3, &stringValue[0], NULL);
     }
   else
     error (_("NSString: internal error -- no way to create new NSString"));
@@ -1195,7 +1195,7 @@  print_object_command (char *args, int from_tty)
   if (function == NULL)
     error (_("Unable to locate _NSPrintForDebugger in child process"));
 
-  description = call_function_by_hand (function, 1, &object);
+  description = call_function_by_hand (function, 1, &object, NULL);
 
   string_addr = value_as_long (description);
   if (string_addr == 0)
diff --git a/gdb/parse.c b/gdb/parse.c
index 420afc5..d72934d 100644
--- a/gdb/parse.c
+++ b/gdb/parse.c
@@ -194,6 +194,7 @@  initialize_expout (struct parser_state *ps, size_t initial_size,
 			+ EXP_ELEM_TO_BYTES (ps->expout_size));
   ps->expout->language_defn = lang;
   ps->expout->gdbarch = gdbarch;
+  ps->expout->stack_mirror_vec = NULL;
 }
 
 /* See definition in parser-defs.h.  */
diff --git a/gdb/python/py-value.c b/gdb/python/py-value.c
index bdec389..2d84ceb 100644
--- a/gdb/python/py-value.c
+++ b/gdb/python/py-value.c
@@ -796,7 +796,7 @@  valpy_call (PyObject *self, PyObject *args, PyObject *keywords)
       struct cleanup *cleanup = make_cleanup_value_free_to_mark (mark);
       struct value *return_value;
 
-      return_value = call_function_by_hand (function, args_count, vargs);
+      return_value = call_function_by_hand (function, args_count, vargs, NULL);
       result = value_to_value_object (return_value);
       do_cleanups (cleanup);
     }
@@ -1040,7 +1040,10 @@  valpy_binop (enum valpy_opcode opcode, PyObject *self, PyObject *other)
       if (!handled)
 	{
 	  if (binop_user_defined_p (op, arg1, arg2))
-	    res_val = value_x_binop (arg1, arg2, op, OP_NULL, EVAL_NORMAL);
+	    {
+	      res_val = value_x_binop (arg1, arg2, op, OP_NULL,
+				       EVAL_NORMAL, NULL);
+	    }
 	  else
 	    res_val = value_binop (arg1, arg2, op);
 	}
diff --git a/gdb/spu-tdep.c b/gdb/spu-tdep.c
index c9af4fd..e5bb95d 100644
--- a/gdb/spu-tdep.c
+++ b/gdb/spu-tdep.c
@@ -2059,7 +2059,7 @@  flush_ea_cache (void)
       type = lookup_pointer_type (type);
       addr = BMSYMBOL_VALUE_ADDRESS (msymbol);
 
-      call_function_by_hand (value_from_pointer (type, addr), 0, NULL);
+      call_function_by_hand (value_from_pointer (type, addr), 0, NULL, NULL);
     }
 }
 
diff --git a/gdb/testsuite/gdb.cp/chained-calls.cc b/gdb/testsuite/gdb.cp/chained-calls.cc
new file mode 100644
index 0000000..e8f4c17
--- /dev/null
+++ b/gdb/testsuite/gdb.cp/chained-calls.cc
@@ -0,0 +1,132 @@ 
+/* 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/>.  */
+
+class S 
+{
+public:
+  S () { }
+  S (S &obj);
+
+  S operator+ (const S &s);
+
+  int a;
+};
+
+S::S (S &obj)
+{
+  a = obj.a;
+}
+
+S
+S::operator+ (const S &s)
+{
+  S res;
+
+  res.a = a + s.a;
+
+  return res;
+}
+
+S
+f (int i)
+{
+  S s;
+
+  s.a = i;
+
+  return s;
+}
+
+int
+g (const S &s)
+{
+  return s.a;
+}
+
+class A
+{
+public:
+  A operator+ (const A &);
+  int a;
+};
+
+A
+A::operator+ (const A &obj)
+{
+  A n;
+
+  n.a = a + obj.a;
+
+  return n;
+}
+
+A
+p ()
+{
+  A a;
+  a.a = 12345678;
+  return a;
+}
+
+A
+r ()
+{
+  A a;
+  a.a = 10000000;
+  return a;
+}
+
+A
+q (const A &a)
+{
+  return a;
+}
+
+class B
+{
+public:
+  int b[1024];
+};
+
+B
+makeb ()
+{
+  B b;
+  int i;
+
+  for (i = 0; i < 1024; i++)
+    b.b[i] = i;
+
+  return b;
+}
+
+int
+getb (const B &b, int i)
+{
+  return b.b[i];
+}
+
+int
+main ()
+{ 
+  int i = g(f(0));
+  A a = q(p() + r());
+
+  B b = makeb ();
+
+  return i + getb(b, 0);  /* Break here  */
+}
diff --git a/gdb/testsuite/gdb.cp/chained-calls.exp b/gdb/testsuite/gdb.cp/chained-calls.exp
new file mode 100644
index 0000000..b8ca775
--- /dev/null
+++ b/gdb/testsuite/gdb.cp/chained-calls.exp
@@ -0,0 +1,39 @@ 
+# 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
+
+if {[skip_cplus_tests]} { continue }
+
+standard_testfile .cc
+
+if {[prepare_for_testing $testfile.exp $testfile $srcfile {debug c++}]} {
+    return -1
+}
+
+if {![runto_main]} {
+    return -1
+}
+
+gdb_breakpoint [gdb_get_line_number "Break here"]
+gdb_continue_to_breakpoint "Break here"
+
+gdb_test "p g(f(12345))" ".* = 12345" "g(f())"
+gdb_test "p q(p())" ".* = {a = 12345678}" "q(p())"
+gdb_test "p p() + r()" ".* = {a = 22345678}" "p() + r()"
+gdb_test "p g(f(6700) + f(89))" ".* = 6789" "g(f() + f())"
+gdb_test "p g(f(g(f(300) + f(40))) + f(5))" ".* = 345" \
+    "g(f(g(f() + f())) + f())"
+gdb_test "p getb(makeb(), 789)" ".* = 789" "getb(makeb(), ...)"
diff --git a/gdb/testsuite/gdb.cp/smartp.exp b/gdb/testsuite/gdb.cp/smartp.exp
index 2a1028a..e3d271f 100644
--- a/gdb/testsuite/gdb.cp/smartp.exp
+++ b/gdb/testsuite/gdb.cp/smartp.exp
@@ -72,6 +72,5 @@  gdb_test "p b->foo()"         "= 66"
 gdb_test "p c->foo()"         "= 66"
 gdb_test "p c->inta"          "= 77"
 
-setup_kfail "gdb/11606" "*-*-*"
 gdb_test "p c2->inta"          "= 77"
 
diff --git a/gdb/valarith.c b/gdb/valarith.c
index 44673a1..e9b898c 100644
--- a/gdb/valarith.c
+++ b/gdb/valarith.c
@@ -340,11 +340,16 @@  value_user_defined_op (struct value **argp, struct value **args, char *name,
 
    OP is the operatore, and if it is BINOP_ASSIGN_MODIFY, then OTHEROP
    is the opcode saying how to modify it.  Otherwise, OTHEROP is
-   unused.  */
+   unused.  
+
+   EXP is the expression whose evaluation requires performing the binary
+   operation.  It is NULL if the operation is not being performed as part
+   of an expression evaluation.  */
 
 struct value *
 value_x_binop (struct value *arg1, struct value *arg2, enum exp_opcode op,
-	       enum exp_opcode otherop, enum noside noside)
+	       enum exp_opcode otherop, enum noside noside,
+	       struct expression *exp)
 {
   struct value **argvec;
   char *ptr;
@@ -500,12 +505,13 @@  value_x_binop (struct value *arg1, struct value *arg2, enum exp_opcode op,
 	}
       else
 	return call_function_by_hand (argvec[0], 2 - static_memfuncp,
-				      argvec + 1);
+				      argvec + 1, exp);
     }
   throw_error (NOT_FOUND_ERROR,
                _("member function %s not found"), tstr);
 #ifdef lint
-  return call_function_by_hand (argvec[0], 2 - static_memfuncp, argvec + 1);
+  return call_function_by_hand (argvec[0], 2 - static_memfuncp, argvec + 1,
+				exp);
 #endif
 }
 
@@ -513,10 +519,15 @@  value_x_binop (struct value *arg1, struct value *arg2, enum exp_opcode op,
    defined operator that matches the operator in question.
    Create an argument vector that calls arg1.operator @ (arg1)
    and return that value (where '@' is (almost) any unary operator which
-   is legal for GNU C++).  */
+   is legal for GNU C++).
+
+   EXP is the expression whose evaluation requires performing the unary
+   operation.  It is NULL if the operation is not being performed as part
+   of an expression evaluation.  */
 
 struct value *
-value_x_unop (struct value *arg1, enum exp_opcode op, enum noside noside)
+value_x_unop (struct value *arg1, enum exp_opcode op, enum noside noside,
+	      struct expression *exp)
 {
   struct gdbarch *gdbarch = get_type_arch (value_type (arg1));
   struct value **argvec;
@@ -610,7 +621,7 @@  value_x_unop (struct value *arg1, enum exp_opcode op, enum noside noside)
 	  return call_xmethod (argvec[0], 1, argvec + 1);
 	}
       else
-	return call_function_by_hand (argvec[0], nargs, argvec + 1);
+	return call_function_by_hand (argvec[0], nargs, argvec + 1, exp);
     }
   throw_error (NOT_FOUND_ERROR,
                _("member function %s not found"), tstr);
diff --git a/gdb/valops.c b/gdb/valops.c
index 564d282..b524385 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -192,7 +192,7 @@  value_allocate_space_in_inferior (int len)
   struct value *blocklen;
 
   blocklen = value_from_longest (builtin_type (gdbarch)->builtin_int, len);
-  val = call_function_by_hand (val, 1, &blocklen);
+  val = call_function_by_hand (val, 1, &blocklen, NULL);
   if (value_logical_not (val))
     {
       if (!target_has_execution)
diff --git a/gdb/value.h b/gdb/value.h
index 0ce3aa0..6171cd2 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -823,6 +823,12 @@  extern struct value *evaluate_subexp (struct type *expect_type,
 extern struct value *evaluate_subexpression_type (struct expression *exp,
 						  int subexp);
 
+extern void add_value_to_expression_stack (struct expression *exp,
+					   struct value *v);
+
+extern CORE_ADDR skip_current_expression_stack (struct expression *exp,
+						CORE_ADDR sp, int downward);
+
 extern void fetch_subexp_value (struct expression *exp, int *pc,
 				struct value **valp, struct value **resultp,
 				struct value **val_chain,
@@ -943,10 +949,11 @@  extern struct value *value_of_this_silent (const struct language_defn *lang);
 extern struct value *value_x_binop (struct value *arg1, struct value *arg2,
 				    enum exp_opcode op,
 				    enum exp_opcode otherop,
-				    enum noside noside);
+				    enum noside noside,
+				    struct expression *exp);
 
 extern struct value *value_x_unop (struct value *arg1, enum exp_opcode op,
-				   enum noside noside);
+				   enum noside noside, struct expression *exp);
 
 extern struct value *value_fn_field (struct value **arg1p, struct fn_field *f,
 				     int j, struct type *type, int offset);