aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/ChangeLog10
-rw-r--r--gdb/sparc-tdep.c12
-rw-r--r--gdb/stack.c25
-rw-r--r--gdb/value.c28
-rw-r--r--gdb/value.h4
5 files changed, 57 insertions, 22 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 3c49f96..32f0c49 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,13 @@
+2013-02-06 David S. Miller <davem@davemloft.net>
+
+ * sparc-tdep.c (sparc32_return_value): Handle writing return value when
+ using RETURN_VALUE_ABI_PRESERVES_ADDRESS.
+ * value.c (struct_return_convention): New function.
+ (using_struct_return): Implement in terms of struct_return_convention.
+ * value.h (struct_return_convention): Declare.
+ * stack.c (return_command): Allow successful overriding of the return
+ value when RETURN_VALUE_ABI_PRESERVES_ADDRESS.
+
2013-02-06 Tom Tromey <tromey@redhat.com>
* python/py-type.c (typy_strip_typedefs): Don't call check_typedef
diff --git a/gdb/sparc-tdep.c b/gdb/sparc-tdep.c
index 3ae7395..2b38521 100644
--- a/gdb/sparc-tdep.c
+++ b/gdb/sparc-tdep.c
@@ -1370,15 +1370,21 @@ sparc32_return_value (struct gdbarch *gdbarch, struct value *function,
if (sparc_structure_or_union_p (type)
|| (sparc_floating_p (type) && TYPE_LENGTH (type) == 16))
{
+ ULONGEST sp;
+ CORE_ADDR addr;
+
if (readbuf)
{
- ULONGEST sp;
- CORE_ADDR addr;
-
regcache_cooked_read_unsigned (regcache, SPARC_SP_REGNUM, &sp);
addr = read_memory_unsigned_integer (sp + 64, 4, byte_order);
read_memory (addr, readbuf, TYPE_LENGTH (type));
}
+ if (writebuf)
+ {
+ regcache_cooked_read_unsigned (regcache, SPARC_SP_REGNUM, &sp);
+ addr = read_memory_unsigned_integer (sp + 64, 4, byte_order);
+ write_memory (addr, writebuf, TYPE_LENGTH (type));
+ }
return RETURN_VALUE_ABI_PRESERVES_ADDRESS;
}
diff --git a/gdb/stack.c b/gdb/stack.c
index bfec1b8..9f4aafc 100644
--- a/gdb/stack.c
+++ b/gdb/stack.c
@@ -2278,6 +2278,7 @@ down_command (char *count_exp, int from_tty)
void
return_command (char *retval_exp, int from_tty)
{
+ enum return_value_convention rv_conv;
struct frame_info *thisframe;
struct gdbarch *gdbarch;
struct symbol *thisfun;
@@ -2331,6 +2332,7 @@ return_command (char *retval_exp, int from_tty)
if (thisfun != NULL)
function = read_var_value (thisfun, thisframe);
+ rv_conv = RETURN_VALUE_REGISTER_CONVENTION;
if (TYPE_CODE (return_type) == TYPE_CODE_VOID)
/* If the return-type is "void", don't try to find the
return-value's location. However, do still evaluate the
@@ -2338,14 +2340,18 @@ return_command (char *retval_exp, int from_tty)
is discarded, side effects such as "return i++" still
occur. */
return_value = NULL;
- else if (thisfun != NULL
- && using_struct_return (gdbarch, function, return_type))
+ else if (thisfun != NULL)
{
- query_prefix = "The location at which to store the "
- "function's return value is unknown.\n"
- "If you continue, the return value "
- "that you specified will be ignored.\n";
- return_value = NULL;
+ rv_conv = struct_return_convention (gdbarch, function, return_type);
+ if (rv_conv == RETURN_VALUE_STRUCT_CONVENTION
+ || rv_conv == RETURN_VALUE_ABI_RETURNS_ADDRESS)
+ {
+ query_prefix = "The location at which to store the "
+ "function's return value is unknown.\n"
+ "If you continue, the return value "
+ "that you specified will be ignored.\n";
+ return_value = NULL;
+ }
}
}
@@ -2375,9 +2381,8 @@ return_command (char *retval_exp, int from_tty)
struct type *return_type = value_type (return_value);
struct gdbarch *gdbarch = get_regcache_arch (get_current_regcache ());
- gdb_assert (gdbarch_return_value (gdbarch, function, return_type, NULL,
- NULL, NULL)
- == RETURN_VALUE_REGISTER_CONVENTION);
+ gdb_assert (rv_conv != RETURN_VALUE_STRUCT_CONVENTION
+ && rv_conv != RETURN_VALUE_ABI_RETURNS_ADDRESS);
gdbarch_return_value (gdbarch, function, return_type,
get_current_regcache (), NULL /*read*/,
value_contents (return_value) /*write*/);
diff --git a/gdb/value.c b/gdb/value.c
index dbf1c37..4b70ece 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -3323,6 +3323,23 @@ coerce_array (struct value *arg)
}
+/* Return the return value convention that will be used for the
+ specified type. */
+
+enum return_value_convention
+struct_return_convention (struct gdbarch *gdbarch,
+ struct value *function, struct type *value_type)
+{
+ enum type_code code = TYPE_CODE (value_type);
+
+ if (code == TYPE_CODE_ERROR)
+ error (_("Function return type unknown."));
+
+ /* Probe the architecture for the return-value convention. */
+ return gdbarch_return_value (gdbarch, function, value_type,
+ NULL, NULL, NULL);
+}
+
/* Return true if the function returning the specified type is using
the convention of returning structures in memory (passing in the
address as a hidden first parameter). */
@@ -3331,19 +3348,12 @@ int
using_struct_return (struct gdbarch *gdbarch,
struct value *function, struct type *value_type)
{
- enum type_code code = TYPE_CODE (value_type);
-
- if (code == TYPE_CODE_ERROR)
- error (_("Function return type unknown."));
-
- if (code == TYPE_CODE_VOID)
+ if (TYPE_CODE (value_type) == TYPE_CODE_VOID)
/* A void return value is never in memory. See also corresponding
code in "print_return_value". */
return 0;
- /* Probe the architecture for the return-value convention. */
- return (gdbarch_return_value (gdbarch, function, value_type,
- NULL, NULL, NULL)
+ return (struct_return_convention (gdbarch, function, value_type)
!= RETURN_VALUE_REGISTER_CONVENTION);
}
diff --git a/gdb/value.h b/gdb/value.h
index b9013fd..c10c3ec 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -696,6 +696,10 @@ extern int value_in (struct value *element, struct value *set);
extern int value_bit_index (struct type *type, const gdb_byte *addr,
int index);
+extern enum return_value_convention
+struct_return_convention (struct gdbarch *gdbarch, struct value *function,
+ struct type *value_type);
+
extern int using_struct_return (struct gdbarch *gdbarch,
struct value *function,
struct type *value_type);