[PATCH v4] Make chained function calls in expressions work

Siva Chandra
2014-10-25T14:24:17Z

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

This is a follow up to the thread here:
https://sourceware.org/ml/gdb-patches/2014-10/msg00000.html

I have made all the suggested changes which now eliminates the need
for two patches in this set. The single patch is attached.

gdb/ChangeLog:

2014-10-25 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.
* expression.h (struct expression): New field
'on_stack_temporaries_vec'.
* gdbtypes.c (class_or_union_p): New function.
* gdbtypes.h (class_or_union_p): Declare.
* infcall.c (call_function_by_hand): New argument EXP of type
struct expression *. Setup stack temporaries for return values of
class type.
(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 (write_value_to_memory): New function.
(value_fetch_lazy): Fix its description comment.
* value.h (add_value_to_expression_stack)
(skip_current_expression_stack, write_value_to_memory): Declare.
(value_x_binop, value_x_unop): Update signature and all callers.

gdb/testsuite/ChangeLog:

2014-10-25 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.

[-- Attachment #2: chained-calls-v4.txt --]
[-- Type: text/plain, Size: 39223 bytes --]

diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 5793cd2..32da705 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -10297,7 +10297,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 19aaed3..dee4ab9 100644
--- a/gdb/elfread.c
+++ b/gdb/elfread.c
@@ -955,7 +955,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 5906744..d1cc309 100644
--- a/gdb/eval.c
+++ b/gdb/eval.c
@@ -38,6 +38,7 @@
#include "valprint.h"
#include "gdb_obstack.h"
#include "objfiles.h"
+#include "common/vec.h"
#include <ctype.h>

/* This is defined in valops.c */
@@ -136,9 +137,72 @@ parse_to_comma_and_eval (const char **expp)
struct value *
evaluate_expression (struct expression *exp)
{
- int pc = 0;
+ int i, pc = 0;
+ struct value *res, *val;
+ struct cleanup *cleanups;
+ value_vec *vec = exp->on_stack_temporaries_vec;
+
+ cleanups = make_cleanup (VEC_cleanup (value_ptr),
+ &exp->on_stack_temporaries_vec);
+ res = evaluate_subexp (NULL_TYPE, exp, &pc, EVAL_NORMAL);
+ /* If the result is on the expression stack, fetch it and mark it as
+ not_lval. */
+ for (i = 0; VEC_iterate (value_ptr, vec, 1, val); i++)
+ {
+ if (res == val)
+ {
+ if (value_lazy (res))
+ value_fetch_lazy (res);
+ VALUE_LVAL (res) = not_lval;
+ break;
+ }
+ }
+ 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->on_stack_temporaries_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. */

- return evaluate_subexp (NULL_TYPE, exp, &pc, EVAL_NORMAL);
+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->on_stack_temporaries_vec))
+ {
+ struct value *v = VEC_last (value_ptr, exp->on_stack_temporaries_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
@@ -1143,12 +1207,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."));
@@ -1165,11 +1229,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. */
@@ -1311,10 +1375,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;
@@ -1431,7 +1495,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)
@@ -1734,7 +1798,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. */
@@ -1845,7 +1909,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)
@@ -1945,7 +2009,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);

@@ -1956,7 +2020,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);

@@ -1968,7 +2032,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)))
@@ -1999,7 +2064,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));
@@ -2018,7 +2083,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)))
{
@@ -2051,7 +2116,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,
@@ -2094,7 +2159,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
@@ -2160,7 +2225,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
{
@@ -2244,7 +2309,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
{
@@ -2271,7 +2336,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
{
@@ -2290,7 +2355,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
{
@@ -2307,7 +2372,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
{
@@ -2324,7 +2389,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
{
@@ -2341,7 +2406,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
{
@@ -2358,7 +2423,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
{
@@ -2375,7 +2440,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
{
@@ -2410,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);
@@ -2422,7 +2487,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);
@@ -2437,7 +2502,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);
@@ -2449,7 +2514,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);
@@ -2468,7 +2533,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));
@@ -2602,7 +2667,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
{
@@ -2626,7 +2691,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
{
@@ -2650,7 +2715,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
{
@@ -2677,7 +2742,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
{
@@ -2827,7 +2892,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..05242b6 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 *on_stack_temporaries_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/gdbtypes.c b/gdb/gdbtypes.c
index ee33d77..5388612 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -2501,6 +2501,15 @@ is_scalar_type_recursive (struct type *t)
return 0;
}

+/* Return true is T is a class or a union. False otherwise. */
+
+int
+class_or_union_p (const struct type *t)
+{
+ return (TYPE_CODE (t) == TYPE_CODE_STRUCT
+ || TYPE_CODE (t) == TYPE_CODE_UNION);
+}
+
/* A helper function which returns true if types A and B represent the
"same" class type. This is true if the types have the same main
type, or the same name. */
diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h
index bd1a0ab..f9d2986 100644
--- a/gdb/gdbtypes.h
+++ b/gdb/gdbtypes.h
@@ -1751,6 +1751,8 @@ extern int get_array_bounds (struct type *type, LONGEST *low_bound,

extern int class_types_same_p (const struct type *, const struct type *);

+extern int class_or_union_p (const struct type *);
+
extern int is_ancestor (struct type *, struct type *);

extern int is_public_ancestor (struct type *, struct type *);
diff --git a/gdb/infcall.c b/gdb/infcall.c
index bbac693..241ec2e 100644
--- a/gdb/infcall.c
+++ b/gdb/infcall.c
@@ -455,6 +455,33 @@ 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)
+ {
+ retval = value_from_contents_and_address (type, NULL, addr);
+ add_value_to_expression_stack (exp, retval);
+ }
+ 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
@@ -471,10 +498,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;
@@ -532,6 +563,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,9 +760,21 @@ 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. */
+ aligned.
+
+ While evaluating expressions, we reserve space on the stack for
+ return values of class type even if the language ABI and the target
+ ABI do not require that the return value be passed as a hidden first
+ argument. This is because we want to store the return value as an
+ on-stack temporary while the expression is being evaluated. This
+ enables us to have chained function calls in expressions.
+
+ Keeping the return values as on-stack temporaries while the expression
+ is being evaluated is OK because the thread is stopped until the
+ expression is completely evaluated. */

- if (struct_return || hidden_first_param_p)
+ if (struct_return || hidden_first_param_p
+ || (exp != NULL && class_or_union_p (values_type)))
{
if (gdbarch_inner_than (gdbarch, 1, 2))
{
@@ -1059,13 +1112,8 @@ 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
@@ -1076,16 +1124,30 @@ When the function is done executing, GDB will silently stop."),
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 && class_or_union_p (values_type))
+ {
+ /* Values of class type returned in registers are copied onto
+ the stack and their lval_type set to lval_memory. This is
+ required because further evaluation of the expression
+ could potentially invoke methods on the return value
+ requiring GDB to evaluate the "this" pointer. To evaluate
+ the this pointer, GDB needs the memory address of the
+ value. */
+ write_value_to_memory (retval, struct_addr);
+ add_value_to_expression_stack (exp, retval);
+ }
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 8a3d21e..10194f0 100644
--- a/gdb/objc-lang.c
+++ b/gdb/objc-lang.c
@@ -131,7 +131,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
@@ -160,7 +160,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 *
@@ -181,12 +181,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)
{
@@ -198,7 +198,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"));
@@ -1194,7 +1194,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 27947e7..a03c266 100644
--- a/gdb/parse.c
+++ b/gdb/parse.c
@@ -193,6 +193,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->on_stack_temporaries_vec = NULL;
}

/* See definition in parser-defs.h. */
diff --git a/gdb/python/py-value.c b/gdb/python/py-value.c
index 4313170..0d65b48 100644
--- a/gdb/python/py-value.c
+++ b/gdb/python/py-value.c
@@ -795,7 +795,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);
}
@@ -1039,7 +1039,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 032f5de..f3bd6c7 100644
--- a/gdb/spu-tdep.c
+++ b/gdb/spu-tdep.c
@@ -2058,7 +2058,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..a30ec3b
--- /dev/null
+++ b/gdb/testsuite/gdb.cp/chained-calls.cc
@@ -0,0 +1,203 @@
+/* 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];
+}
+
+class C
+{
+public:
+ C ();
+ ~C ();
+
+ A operator* ();
+
+ A *a_ptr;
+};
+
+C::C ()
+{
+ a_ptr = new A;
+ a_ptr->a = 5678;
+}
+
+C::~C ()
+{
+ delete a_ptr;
+}
+
+A
+C::operator* ()
+{
+ return *a_ptr;
+}
+
+#define TYPE_INDEX 1
+
+enum type
+{
+ INT,
+ CHAR
+};
+
+union U
+{
+public:
+ U (type t);
+ type get_type ();
+
+ int a;
+ char c;
+ type tp[2];
+};
+
+U::U (type t)
+{
+ tp[TYPE_INDEX] = t;
+}
+
+U
+make_int ()
+{
+ return U (INT);
+}
+
+U
+make_char ()
+{
+ return U (CHAR);
+}
+
+type
+U::get_type ()
+{
+ return tp[TYPE_INDEX];
+}
+
+int
+main ()
+{
+ int i = g(f(0));
+ A a = q(p() + r());
+
+ B b = makeb ();
+ C c;
+
+ 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..c903bea
--- /dev/null
+++ b/gdb/testsuite/gdb.cp/chained-calls.exp
@@ -0,0 +1,44 @@
+# 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 q(p() + r())" ".* = {a = 22345678}" "q(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(), ...)"
+gdb_test "p *c" ".* = {a = 5678}" "*c"
+gdb_test "p *c + *c" ".* = {a = 11356}" "*c + *c"
+gdb_test "P q(*c + *c)" ".* = {a = 11356}" "q(*c + *c)"
+gdb_test "p make_int().get_type ()" ".* = INT" "make_int().get_type ()"
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 154629b..d80cf62 100644
--- a/gdb/valarith.c
+++ b/gdb/valarith.c
@@ -339,11 +339,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;
@@ -499,12 +504,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
}

@@ -512,10 +518,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;
@@ -609,7 +620,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 7f3e4f5..5fcefc2 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -191,7 +191,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.c b/gdb/value.c
index ecfb154..058d04f 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -1080,6 +1080,20 @@ set_value_parent (struct value *value, struct value *parent)
value_free (old);
}

+/* Write contents of V at ADDR. Also, set lval_type of V to lval_memory.
+ It is as error if V's lval_type is anything other than not_lval. */
+
+void
+write_value_to_memory (struct value *v, CORE_ADDR addr)
+{
+ gdb_assert (VALUE_LVAL (v) == not_lval);
+
+ write_memory (addr, value_contents_raw (v), TYPE_LENGTH (value_type (v)));
+ VALUE_LVAL (v) = lval_memory;
+ v->location.address = addr;
+ v->lazy = 0;
+}
+
gdb_byte *
value_contents_raw (struct value *value)
{
@@ -3730,11 +3744,8 @@ value_initialized (struct value *val)
return val->initialized;
}

-/* Called only from the value_contents and value_contents_all()
- macros, if the current data for a variable needs to be loaded into
- value_contents(VAL). Fetches the data from the user's process, and
- clears the lazy flag to indicate that the data in the buffer is
- valid.
+/* Fetches the data from the user's process, and clears the lazy flag
+ to indicate that the data in the buffer is valid.

If the value is zero-length, we avoid calling read_memory, which
would abort. We mark the value as fetched anyway -- all 0 bytes of
diff --git a/gdb/value.h b/gdb/value.h
index e3603c3..1e0efee 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -363,6 +363,8 @@ extern const gdb_byte *

extern int value_fetch_lazy (struct value *val);

+extern void write_value_to_memory (struct value *v, CORE_ADDR addr);
+
/* If nonzero, this is the value of a variable which does not actually
exist in the program, at least partially. If the value is lazy,
this may fetch it now. */
@@ -819,6 +821,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,
@@ -939,10 +947,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);