{
}
+CORE_ADDR
+default_get_return_buf_addr (struct type *val_type, frame_info_ptr cur_frame)
+{
+ return 0;
+}
+
/* Non-zero if we want to trace architecture code. */
#ifndef GDBARCH_DEBUG
struct bfd *cbfd,
read_core_file_mappings_pre_loop_ftype pre_loop_cb,
read_core_file_mappings_loop_ftype loop_cb);
+
+/* Default implementation of gdbarch default_get_return_buf_addr method. */
+extern CORE_ADDR default_get_return_buf_addr (struct type *val_typegdbarch,
+ frame_info_ptr cur_frame);
#endif /* ARCH_UTILS_H */
entry_data_value_free_closure
};
-/* Read parameter of TYPE at (callee) FRAME's function entry. KIND and KIND_U
- are used to match DW_AT_location at the caller's
- DW_TAG_call_site_parameter.
-
- Function always returns non-NULL value. It throws NO_ENTRY_VALUE_ERROR if it
- cannot resolve the parameter for any reason. */
-
-static struct value *
+/* See dwarf2/loc.h. */
+struct value *
value_of_dwarf_reg_entry (struct type *type, frame_info_ptr frame,
enum call_site_parameter_kind kind,
union call_site_parameter_u kind_u)
dwarf2_per_objfile *per_objfile, frame_info_ptr frame,
struct type *type, bool resolve_abstract_p = false);
+/* Read parameter of TYPE at (callee) FRAME's function entry. KIND and KIND_U
+ are used to match DW_AT_location at the caller's
+ DW_TAG_call_site_parameter.
+
+ Function always returns non-NULL value. It throws NO_ENTRY_VALUE_ERROR if
+ it cannot resolve the parameter for any reason. */
+
+extern struct value *value_of_dwarf_reg_entry (struct type *type,
+ struct frame_info_ptr frame,
+ enum call_site_parameter_kind kind,
+ union call_site_parameter_u kind_u);
#endif /* DWARF2LOC_H */
invalid=True,
)
+Function(
+ comment="""
+Return the address at which the value being returned from
+the current function will be stored. This routine is only
+called if the current function uses the the "struct return
+convention".
+
+May return 0 when unable to determine that address.""",
+ type="CORE_ADDR",
+ name="get_return_buf_addr",
+ params=[("struct type *", "val_type"), ("frame_info_ptr", "cur_frame")],
+ predefault="default_get_return_buf_addr",
+ invalid=False,
+)
+
Method(
comment="""
Return true if the return value of function is stored in the first hidden
extern enum return_value_convention gdbarch_return_value (struct gdbarch *gdbarch, struct value *function, struct type *valtype, struct regcache *regcache, gdb_byte *readbuf, const gdb_byte *writebuf);
extern void set_gdbarch_return_value (struct gdbarch *gdbarch, gdbarch_return_value_ftype *return_value);
+/* Return the address at which the value being returned from
+ the current function will be stored. This routine is only
+ called if the current function uses the the "struct return
+ convention".
+
+ May return 0 when unable to determine that address. */
+
+typedef CORE_ADDR (gdbarch_get_return_buf_addr_ftype) (struct type *val_type, frame_info_ptr cur_frame);
+extern CORE_ADDR gdbarch_get_return_buf_addr (struct gdbarch *gdbarch, struct type *val_type, frame_info_ptr cur_frame);
+extern void set_gdbarch_get_return_buf_addr (struct gdbarch *gdbarch, gdbarch_get_return_buf_addr_ftype *get_return_buf_addr);
+
/* Return true if the return value of function is stored in the first hidden
parameter. In theory, this feature should be language-dependent, specified
by language and its ABI, such as C++. Unfortunately, compiler may
gdbarch_address_to_pointer_ftype *address_to_pointer = unsigned_address_to_pointer;
gdbarch_integer_to_address_ftype *integer_to_address = nullptr;
gdbarch_return_value_ftype *return_value = nullptr;
+ gdbarch_get_return_buf_addr_ftype *get_return_buf_addr = default_get_return_buf_addr;
gdbarch_return_in_first_hidden_param_p_ftype *return_in_first_hidden_param_p = default_return_in_first_hidden_param_p;
gdbarch_skip_prologue_ftype *skip_prologue = 0;
gdbarch_skip_main_prologue_ftype *skip_main_prologue = nullptr;
/* Skip verify of address_to_pointer, invalid_p == 0 */
/* Skip verify of integer_to_address, has predicate. */
/* Skip verify of return_value, has predicate. */
+ /* Skip verify of get_return_buf_addr, invalid_p == 0 */
/* Skip verify of return_in_first_hidden_param_p, invalid_p == 0 */
if (gdbarch->skip_prologue == 0)
log.puts ("\n\tskip_prologue");
gdb_printf (file,
"gdbarch_dump: return_value = <%s>\n",
host_address_to_string (gdbarch->return_value));
+ gdb_printf (file,
+ "gdbarch_dump: get_return_buf_addr = <%s>\n",
+ host_address_to_string (gdbarch->get_return_buf_addr));
gdb_printf (file,
"gdbarch_dump: return_in_first_hidden_param_p = <%s>\n",
host_address_to_string (gdbarch->return_in_first_hidden_param_p));
gdbarch->return_value = return_value;
}
+CORE_ADDR
+gdbarch_get_return_buf_addr (struct gdbarch *gdbarch, struct type *val_type, frame_info_ptr cur_frame)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->get_return_buf_addr != NULL);
+ if (gdbarch_debug >= 2)
+ gdb_printf (gdb_stdlog, "gdbarch_get_return_buf_addr called\n");
+ return gdbarch->get_return_buf_addr (val_type, cur_frame);
+}
+
+void
+set_gdbarch_get_return_buf_addr (struct gdbarch *gdbarch,
+ gdbarch_get_return_buf_addr_ftype get_return_buf_addr)
+{
+ gdbarch->get_return_buf_addr = get_return_buf_addr;
+}
+
int
gdbarch_return_in_first_hidden_param_p (struct gdbarch *gdbarch, struct type *type)
{
#include "gdbsupport/gdb_optional.h"
#include "source.h"
#include "cli/cli-style.h"
+#include "dwarf2/loc.h"
/* Local functions: */
return value. */
struct return_value_info return_value_info {};
+ /* If the current function uses the "struct return convention",
+ this holds the address at which the value being returned will
+ be stored, or zero if that address could not be determined or
+ the "struct return convention" is not being used. */
+ CORE_ADDR return_buf;
+
explicit finish_command_fsm (struct interp *cmd_interp)
: thread_fsm (cmd_interp)
{
struct value *func;
func = read_var_value (function, NULL, get_current_frame ());
- rv->value = get_return_value (function, func);
+
+ if (return_buf != 0)
+ /* Retrieve return value from the buffer where it was saved. */
+ rv->value = value_at (rv->type, return_buf);
+ else
+ rv->value = get_return_value (function, func);
+
if (rv->value != NULL)
rv->value_history_index = record_latest_value (rv->value);
}
}
/* Find the function we will return from. */
-
- sm->function = find_pc_function (get_frame_pc (get_selected_frame (NULL)));
+ frame_info_ptr callee_frame = get_selected_frame (NULL);
+ sm->function = find_pc_function (get_frame_pc (callee_frame));
+
+ /* Determine the return convention. If it is RETURN_VALUE_STRUCT_CONVENTION,
+ attempt to determine the address of the return buffer. */
+ enum return_value_convention return_value;
+ struct gdbarch *gdbarch = get_frame_arch (callee_frame);
+
+ struct type * val_type
+ = check_typedef (sm->function->type ()->target_type ());
+
+ return_value = gdbarch_return_value (gdbarch,
+ read_var_value (sm->function, NULL,
+ callee_frame),
+ val_type, NULL, NULL, NULL);
+
+ if (return_value == RETURN_VALUE_STRUCT_CONVENTION
+ && val_type->code () != TYPE_CODE_VOID)
+ sm->return_buf = gdbarch_get_return_buf_addr (gdbarch, val_type,
+ callee_frame);
+ else
+ sm->return_buf = 0;
/* Print info on the selected frame, including level number but not
source. */
gdb_printf (_("Run till exit from "));
}
- print_stack_frame (get_selected_frame (NULL), 1, LOCATION, 0);
+ print_stack_frame (callee_frame, 1, LOCATION, 0);
}
frame.reinflate ();
#include "objfiles.h"
#include "infcall.h"
#include "dwarf2.h"
+#include "dwarf2/loc.h"
#include "target-float.h"
#include <algorithm>
return RETURN_VALUE_STRUCT_CONVENTION;
}
+CORE_ADDR ppc64_sysv_get_return_buf_addr (struct type *val_type,
+ frame_info_ptr cur_frame)
+{
+ /* The PowerPC ABI specifies aggregates that are not returned by value
+ are returned in a storage buffer provided by the caller. The
+ address of the storage buffer is provided as a hidden first input
+ arguement in register r3. The PowerPC ABI does not guarantee that
+ register r3 will not be changed while executing the function. Hence, it
+ cannot be assumed that r3 will still contain the address of the storage
+ buffer when execution reaches the end of the function.
+
+ This function attempts to determine the value of r3 on entry to the
+ function using the DW_OP_entry_value DWARF entries. This requires
+ compiling the user program with -fvar-tracking to resolve the
+ DW_TAG_call_sites in the binary file. */
+
+ union call_site_parameter_u kind_u;
+ enum call_site_parameter_kind kind;
+ CORE_ADDR return_val = 0;
+
+ kind_u.dwarf_reg = 3; /* First passed arg/return value is in r3. */
+ kind = CALL_SITE_PARAMETER_DWARF_REG;
+
+ /* val_type is the type of the return value. Need the pointer type
+ to the return value. */
+ val_type = lookup_pointer_type (val_type);
+
+ try
+ {
+ return_val = value_as_address (value_of_dwarf_reg_entry (val_type,
+ cur_frame,
+ kind, kind_u));
+ }
+ catch (const gdb_exception_error &e)
+ {
+ warning ("Cannot determine the function return value.\n"
+ "Try compiling with -fvar-tracking.");
+ }
+ return return_val;
+}
const struct regcache *regcache,
int regnum, void *vsxregs, size_t len);
+extern CORE_ADDR ppc64_sysv_get_return_buf_addr (type*, frame_info_ptr);
+
/* Private data that this module attaches to struct gdbarch. */
/* ELF ABI version used by the inferior. */
set_gdbarch_ps_regnum (gdbarch, tdep->ppc_ps_regnum);
if (wordsize == 8)
- set_gdbarch_return_value (gdbarch, ppc64_sysv_abi_return_value);
+ {
+ set_gdbarch_return_value (gdbarch, ppc64_sysv_abi_return_value);
+ set_gdbarch_get_return_buf_addr (gdbarch,
+ ppc64_sysv_get_return_buf_addr);
+ }
else
set_gdbarch_return_value (gdbarch, ppc_sysv_abi_return_value);
# This file is part of the gdb testsuite
+set additional_flags ""
+
if {[skip_cplus_tests]} { continue }
standard_testfile .cc
-if {[prepare_for_testing "failed to prepare" $testfile $srcfile {debug c++}]} {
+if {[have_fvar_tracking]} {
+ set additional_flags "additional_flags= -fvar-tracking"
+}
+
+if {[prepare_for_testing "failed to prepare" $testfile $srcfile [list debug c++ $additional_flags]]} {
+
return -1
}
return [gdb_simple_compile $me $src executable $flags]
}
+# Return 1 if compiler supports fvar-tracking, otherwise return 0.
+gdb_caching_proc have_fvar_tracking {
+ set me "have_fvar_tracking"
+ set flags "additional_flags=-fvar-tracking"
+ set src { int main() { return 0; } }
+ return [gdb_simple_compile $me $src executable $flags]
+}
+
# Return 1 if linker supports -Ttext-segment, otherwise return 0.
gdb_caching_proc linker_supports_Ttext_segment_flag {
set me "linker_supports_Ttext_segment_flag"