diff options
author | Siva Chandra <sivachandra@chromium.org> | 2014-11-11 05:43:03 -0800 |
---|---|---|
committer | Siva Chandra <sivachandra@chromium.org> | 2014-11-28 16:01:16 -0800 |
commit | 6c659fc2c7cd2da6d2b9a3d7c38597ad3821832a (patch) | |
tree | 4d45593c088252f07a928ff05ba96e79ea629daf /gdb/infcall.c | |
parent | f4f855e84b45eb41987641b4a26037c7444dda33 (diff) | |
download | gdb-6c659fc2c7cd2da6d2b9a3d7c38597ad3821832a.zip gdb-6c659fc2c7cd2da6d2b9a3d7c38597ad3821832a.tar.gz gdb-6c659fc2c7cd2da6d2b9a3d7c38597ad3821832a.tar.bz2 |
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".
Diffstat (limited to 'gdb/infcall.c')
-rw-r--r-- | gdb/infcall.c | 93 |
1 files changed, 71 insertions, 22 deletions
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); } } |