@@ -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 */
@@ -60,6 +61,12 @@ static LONGEST init_array_element (struct value *, struct value *,
struct expression *, int *, enum noside,
LONGEST, LONGEST);
+typedef struct value *value_ptr;
+DEF_VEC_P (value_ptr);
+typedef VEC (value_ptr) value_vec;
+
+static value_vec *expr_stack_mirror_vec = NULL;
+
struct value *
evaluate_subexp (struct type *expect_type, struct expression *exp,
int *pos, enum noside noside)
@@ -138,8 +145,60 @@ struct value *
evaluate_expression (struct expression *exp)
{
int pc = 0;
+ struct value *res;
+ struct cleanup *cleanups;
+
+ expr_stack_mirror_vec = VEC_alloc (value_ptr, 5);
+ cleanups = make_cleanup (VEC_cleanup (value_ptr), &expr_stack_mirror_vec);
+
+ res = evaluate_subexp (NULL_TYPE, exp, &pc, EVAL_NORMAL);
+ do_cleanups (cleanups);
+
+ return res;
+
+}
+
+/* Add value V to the expression stack. */
+
+void
+add_value_to_expression_stack (struct value *v)
+{
+ if (expr_stack_mirror_vec == NULL)
+ return;
+
+ VEC_safe_push (value_ptr, expr_stack_mirror_vec, v);
+}
+
+/* Return an address after skipping over the current values on the expression
+ stack. 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 (CORE_ADDR sp, int downward)
+{
+ CORE_ADDR addr = sp;
+
+ if (!VEC_empty (value_ptr, expr_stack_mirror_vec))
+ {
+ struct value *v = VEC_last (value_ptr, expr_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
@@ -533,6 +533,13 @@ 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 (gdbarch_inner_than (gdbarch, 1, 2))
+ old_sp = skip_current_expression_stack (old_sp, 1);
+ else
+ old_sp = skip_current_expression_stack (old_sp, 0);
+
if (gdbarch_frame_align_p (gdbarch))
{
sp = gdbarch_frame_align (gdbarch, old_sp);
@@ -719,10 +726,16 @@ 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 unless the return type is void. Make certain that the value is
+ correctly aligned.
+
+ We reserve space on the stack 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)
+ if (TYPE_CODE (values_type) != TYPE_CODE_VOID)
{
if (gdbarch_inner_than (gdbarch, 1, 2))
{
@@ -1060,13 +1073,18 @@ 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));
+ {
+ struct value *mirror;
+
+ mirror = value_from_contents_and_address (values_type, NULL,
+ struct_addr);
+ add_value_to_expression_stack (mirror);
+ retval = allocate_value_mirrored_on_stack (mirror);
+ read_value_memory (retval, 0, 1, struct_addr,
+ value_contents_raw (retval),
+ TYPE_LENGTH (values_type));
+ }
else if (TYPE_CODE (target_values_type) != TYPE_CODE_VOID)
{
/* If the function returns void, don't bother fetching the
@@ -1077,16 +1095,28 @@ 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);
+ setup_stack_mirror (retval, struct_addr);
break;
case RETURN_VALUE_STRUCT_CONVENTION:
- read_value_memory (retval, 0, 1, struct_addr,
- value_contents_raw (retval),
- TYPE_LENGTH (values_type));
+ {
+ struct value *mirror;
+
+ mirror = value_from_contents_and_address (values_type, NULL,
+ struct_addr);
+ retval = allocate_value_mirrored_on_stack (mirror);
+ add_value_to_expression_stack (mirror);
+ read_value_memory (retval, 0, 1, struct_addr,
+ value_contents_raw (retval),
+ TYPE_LENGTH (values_type));
+ }
break;
}
}
+ else
+ retval = allocate_value (values_type);
do_cleanups (retbuf_cleanup);
new file mode 100644
@@ -0,0 +1,113 @@
+/* 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:
+ int a;
+};
+
+A
+p ()
+{
+ A a;
+ a.a = 12345678;
+ 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());
+
+ B b = makeb ();
+
+ return i + getb(b, 0); /* Break here */
+}
new file mode 100644
@@ -0,0 +1,37 @@
+# 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())" ".*12345678.*" "q(p())"
+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(), ...)"
@@ -823,6 +823,10 @@ 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 value *v);
+
+extern CORE_ADDR skip_current_expression_stack (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,