From 6c659fc2c7cd2da6d2b9a3d7c38597ad3821832a Mon Sep 17 00:00:00 2001 From: Siva Chandra Date: Tue, 11 Nov 2014 05:43:03 -0800 Subject: Enable chained function calls in C++ expressions. gdb/ChangeLog: * eval.c: Include gdbthread.h. (evaluate_subexp): Enable thread stack temporaries before evaluating a complete expression and clean them up after the evaluation is complete. * gdbthread.h: Include common/vec.h. (value_ptr): New typedef. (VEC (value_ptr)): New vector type. (value_vec): New typedef. (struct thread_info): Add new fields stack_temporaries_enabled and stack_temporaries. (enable_thread_stack_temporaries) (thread_stack_temporaries_enabled_p, push_thread_stack_temporary) (get_last_thread_stack_temporary) (value_in_thread_stack_temporaries): Declare. * gdbtypes.c (class_or_union_p): New function. * gdbtypes.h (class_or_union_p): Declare. * infcall.c (call_function_by_hand): Store return values of class type as temporaries on stack. * thread.c (enable_thread_stack_temporaries): New function. (thread_stack_temporaries_enabled_p, push_thread_stack_temporary) (get_last_thread_stack_temporary): Likewise. (value_in_thread_stack_temporaries): Likewise. * value.c (value_force_lval): New function. * value.h (value_force_lval): Declare. gdb/testsuite/ChangeLog: * gdb.cp/chained-calls.cc: New file. * gdb.cp/chained-calls.exp: New file. * gdb.cp/smartp.exp: Remove KFAIL for "p c2->inta". --- gdb/infcall.c | 93 +++++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 71 insertions(+), 22 deletions(-) (limited to 'gdb/infcall.c') diff --git a/gdb/infcall.c b/gdb/infcall.c index bbac693..718393c 100644 --- a/gdb/infcall.c +++ b/gdb/infcall.c @@ -495,6 +495,7 @@ call_function_by_hand (struct value *function, int nargs, struct value **args) ptid_t call_thread_ptid; struct gdb_exception e; char name_buf[RAW_FUNCTION_ADDRESS_SIZE]; + int stack_temporaries = thread_stack_temporaries_enabled_p (inferior_ptid); if (TYPE_CODE (ftype) == TYPE_CODE_PTR) ftype = check_typedef (TYPE_TARGET_TYPE (ftype)); @@ -593,6 +594,33 @@ call_function_by_hand (struct value *function, int nargs, struct value **args) If the ABI specifies a "Red Zone" (see the doco) the code below will quietly trash it. */ sp = old_sp; + + /* Skip over the stack temporaries that might have been generated during + the evaluation of an expression. */ + if (stack_temporaries) + { + struct value *lastval; + + lastval = get_last_thread_stack_temporary (inferior_ptid); + if (lastval != NULL) + { + CORE_ADDR lastval_addr = value_address (lastval); + + if (gdbarch_inner_than (gdbarch, 1, 2)) + { + gdb_assert (sp >= lastval_addr); + sp = lastval_addr; + } + else + { + gdb_assert (sp <= lastval_addr); + sp = lastval_addr + TYPE_LENGTH (value_type (lastval)); + } + + if (gdbarch_frame_align_p (gdbarch)) + sp = gdbarch_frame_align (gdbarch, sp); + } + } } funaddr = find_function_addr (function, &values_type); @@ -719,9 +747,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. - if (struct_return || hidden_first_param_p) + 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 + || (stack_temporaries && class_or_union_p (values_type))) { if (gdbarch_inner_than (gdbarch, 1, 2)) { @@ -1059,31 +1099,40 @@ 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)); - else if (TYPE_CODE (target_values_type) != TYPE_CODE_VOID) + if (TYPE_CODE (values_type) == TYPE_CODE_VOID) + retval = allocate_value (values_type); + else if (struct_return || hidden_first_param_p) { - /* If the function returns void, don't bother fetching the - return value. */ - switch (gdbarch_return_value (gdbarch, function, target_values_type, - NULL, NULL, NULL)) + if (stack_temporaries) + { + retval = value_from_contents_and_address (values_type, NULL, + struct_addr); + push_thread_stack_temporary (inferior_ptid, retval); + } + else { - case RETURN_VALUE_REGISTER_CONVENTION: - case RETURN_VALUE_ABI_RETURNS_ADDRESS: - case RETURN_VALUE_ABI_PRESERVES_ADDRESS: - gdbarch_return_value (gdbarch, function, values_type, - retbuf, value_contents_raw (retval), NULL); - break; - case RETURN_VALUE_STRUCT_CONVENTION: + retval = allocate_value (values_type); read_value_memory (retval, 0, 1, struct_addr, value_contents_raw (retval), TYPE_LENGTH (values_type)); - break; + } + } + else + { + retval = allocate_value (values_type); + gdbarch_return_value (gdbarch, function, values_type, + retbuf, value_contents_raw (retval), NULL); + if (stack_temporaries && 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. */ + value_force_lval (retval, struct_addr); + push_thread_stack_temporary (inferior_ptid, retval); } } -- cgit v1.1