* defs.h (enum return_value_convention): Add
authorMark Kettenis <kettenis@gnu.org>
Sat, 8 May 2004 23:02:10 +0000 (23:02 +0000)
committerMark Kettenis <kettenis@gnu.org>
Sat, 8 May 2004 23:02:10 +0000 (23:02 +0000)
RETURN_VALUE_ABI_RETURNS_ADDRESS and
RETURN_VALUE_ABI_PRESERVES_ADDRESS.
* infcmd.c (legacy_return_value): New function.
(print_return_value): Rwerite to implement
RETURN_VALUE_ABI_RETURNS_ADDRESS.
* values.c (using_struct_return): Check for inequality to
RETURN_VALUE_REGISTER_CONVENTION instead of equality to
RETURN_VALUE_STRUCT_CONVENTION.
* i386-tdep.c (i386_return_value): Implement
RETURN_VALUE_ABI_RETURNS_ADDRESS.

gdb/ChangeLog
gdb/defs.h
gdb/i386-tdep.c
gdb/infcmd.c
gdb/values.c

index 461e9f6d5390ca3c78eb6ff8e15f0275afacaa89..13e3a6ac0d0754f11fc782b78f3690e7bf14748b 100644 (file)
@@ -1,5 +1,17 @@
 2004-05-09  Mark Kettenis  <kettenis@gnu.org>
 
+       * defs.h (enum return_value_convention): Add
+       RETURN_VALUE_ABI_RETURNS_ADDRESS and
+       RETURN_VALUE_ABI_PRESERVES_ADDRESS.
+       * infcmd.c (legacy_return_value): New function.
+       (print_return_value): Rwerite to implement
+       RETURN_VALUE_ABI_RETURNS_ADDRESS.
+       * values.c (using_struct_return): Check for inequality to
+       RETURN_VALUE_REGISTER_CONVENTION instead of equality to
+       RETURN_VALUE_STRUCT_CONVENTION.
+       * i386-tdep.c (i386_return_value): Implement
+       RETURN_VALUE_ABI_RETURNS_ADDRESS.
+
        * vax-tdep.c: Tweak comments.  Reorder include files.  Don't
        include "symtab.h", "opcode/vax.h" and "inferior.h".
        (vax_skip_prologue): Replace calls to read_memory_integer by calls
index 362f4a773c8cbd31f0aacbb7ef481ca7d24c9d03..97714285224b0db85393c891ae8f70ca87b3e6b3 100644 (file)
@@ -250,7 +250,19 @@ enum return_value_convention
      should be stored.  While typically, and historically, used for
      large structs, this is convention is applied to values of many
      different types.  */
-  RETURN_VALUE_STRUCT_CONVENTION
+  RETURN_VALUE_STRUCT_CONVENTION,
+  /* Like the "struct return convention" above, but where the ABI
+     guarantees that the called function stores the address at which
+     the value being returned is stored in a well-defined location,
+     such as a register or memory slot in the stack frame.  Don't use
+     this if the ABI doesn't explicitly guarantees this.  */
+  RETURN_VALUE_ABI_RETURNS_ADDRESS,
+  /* Like the "struct return convention" above, but where the ABI
+     guarantees that the address at which the value being returned is
+     stored will be available in a well-defined location, such as a
+     register or memory slot in the stack frame.  Don't use this if
+     the ABI doesn't explicitly guarantees this.  */
+  RETURN_VALUE_ABI_PRESERVES_ADDRESS,
 };
 
 /* the cleanup list records things that have to be undone
index 8542ef9f763fbdf661fc06210e8f0b660903e467..5f3952931fe31e22f2dc142737385229d7f95eef 100644 (file)
@@ -1352,7 +1352,28 @@ i386_return_value (struct gdbarch *gdbarch, struct type *type,
 
   if ((code == TYPE_CODE_STRUCT || code == TYPE_CODE_UNION)
       && !i386_reg_struct_return_p (gdbarch, type))
-    return RETURN_VALUE_STRUCT_CONVENTION;
+    {
+      /* The System V ABI says that:
+
+        "A function that returns a structure or union also sets %eax
+        to the value of the original address of the caller's area
+        before it returns.  Thus when the caller receives control
+        again, the address of the returned object resides in register
+        %eax and can be used to access the object."
+
+        So the ABI guarantees that we can always find the return
+        value just after the function has returned.  */
+
+      if (readbuf)
+       {
+         ULONGEST addr;
+
+         regcache_raw_read_unsigned (regcache, I386_EAX_REGNUM, &addr);
+         read_memory (addr, readbuf, TYPE_LENGTH (type));
+       }
+
+      return RETURN_VALUE_ABI_RETURNS_ADDRESS;
+    }
 
   /* This special case is for structures consisting of a single
      `float' or `double' member.  These structures are returned in
index bedc5a541e8e17bec5805df8338ee431dcfa19a8..2cbfce3c38a87ff48b8daf0b6308e2fd74f8c4dd 100644 (file)
@@ -1047,79 +1047,97 @@ advance_command (char *arg, int from_tty)
 }
 \f
 
+static struct value *
+legacy_return_value (int struct_return, struct type *value_type)
+{
+  struct value *value;
+
+  if (!struct_return)
+    {
+      /* The return value can be found in the inferior's registers.  */
+      return register_value_being_returned (value_type, stop_registers);
+    }
+
+  if (DEPRECATED_EXTRACT_STRUCT_VALUE_ADDRESS_P ())
+    {
+      CORE_ADDR addr;
+
+      addr = DEPRECATED_EXTRACT_STRUCT_VALUE_ADDRESS (stop_registers);
+      if (!addr)
+       error ("Function return value unknown.");
+      return value_at (value_type, addr, NULL);
+    }
+
+  /* It is "struct return" yet the value is being extracted,
+     presumably from registers, using EXTRACT_RETURN_VALUE.  This
+     doesn't make sense.  Unfortunately, the legacy interfaces allowed
+     this behavior.  Sigh!  */
+  value = allocate_value (value_type);
+  CHECK_TYPEDEF (value_type);
+  /* If the function returns void, don't bother fetching the return
+     value.  */
+  EXTRACT_RETURN_VALUE (value_type, stop_registers,
+                       VALUE_CONTENTS_RAW (value));
+  return value;
+}
+
 /* Print the result of a function at the end of a 'finish' command.  */
 
 static void
 print_return_value (int struct_return, struct type *value_type)
 {
+  struct gdbarch *gdbarch = current_gdbarch;
   struct cleanup *old_chain;
   struct ui_stream *stb;
-  struct value *value;
+  struct value *value = NULL;
 
-  if (!struct_return)
-    {
-      /* The return value can be found in the inferior's registers.  */
-      value = register_value_being_returned (value_type, stop_registers);
-    }
-  /* FIXME: cagney/2004-01-17: When both return_value and
-     extract_returned_value_address are available, should use that to
-     find the address of and then extract the returned value.  */
   /* FIXME: 2003-09-27: When returning from a nested inferior function
      call, it's possible (with no help from the architecture vector)
      to locate and return/print a "struct return" value.  This is just
      a more complicated case of what is already being done in in the
      inferior function call code.  In fact, when inferior function
      calls are made async, this will likely be made the norm.  */
-  else if (gdbarch_return_value_p (current_gdbarch))
-    /* We cannot determine the contents of the structure because it is
-       on the stack, and we don't know where, since we did not
-       initiate the call, as opposed to the call_function_by_hand
-       case.  */
-    {
-      gdb_assert (gdbarch_return_value (current_gdbarch, value_type,
-                                       NULL, NULL, NULL)
-                 == RETURN_VALUE_STRUCT_CONVENTION);
-      ui_out_text (uiout, "Value returned has type: ");
-      ui_out_field_string (uiout, "return-type", TYPE_NAME (value_type));
-      ui_out_text (uiout, ".");
-      ui_out_text (uiout, " Cannot determine contents\n");
-      return;
-    }
-  else
+
+  if (gdbarch_return_value_p (gdbarch))
     {
-      if (DEPRECATED_EXTRACT_STRUCT_VALUE_ADDRESS_P ())
+      switch (gdbarch_return_value (gdbarch, value_type, NULL, NULL, NULL))
        {
-         CORE_ADDR addr = DEPRECATED_EXTRACT_STRUCT_VALUE_ADDRESS (stop_registers);
-         if (!addr)
-           error ("Function return value unknown.");
-         value = value_at (value_type, addr, NULL);
-       }
-      else
-       {
-         /* It is "struct return" yet the value is being extracted,
-             presumably from registers, using EXTRACT_RETURN_VALUE.
-             This doesn't make sense.  Unfortunately, the legacy
-             interfaces allowed this behavior.  Sigh!  */
+       case RETURN_VALUE_REGISTER_CONVENTION:
+       case RETURN_VALUE_ABI_RETURNS_ADDRESS:
          value = allocate_value (value_type);
          CHECK_TYPEDEF (value_type);
-         /* If the function returns void, don't bother fetching the
-            return value.  */
-         EXTRACT_RETURN_VALUE (value_type, stop_registers,
-                               VALUE_CONTENTS_RAW (value));
+         gdbarch_return_value (current_gdbarch, value_type, stop_registers,
+                               VALUE_CONTENTS_RAW (value), NULL);
+         break;
+
+       case RETURN_VALUE_STRUCT_CONVENTION:
+         break;
        }
     }
+  else
+    value = legacy_return_value (struct_return, value_type);
 
-  /* Print it.  */
-  stb = ui_out_stream_new (uiout);
-  old_chain = make_cleanup_ui_out_stream_delete (stb);
-  ui_out_text (uiout, "Value returned is ");
-  ui_out_field_fmt (uiout, "gdb-result-var", "$%d",
-                   record_latest_value (value));
-  ui_out_text (uiout, " = ");
-  value_print (value, stb->stream, 0, Val_no_prettyprint);
-  ui_out_field_stream (uiout, "return-value", stb);
-  ui_out_text (uiout, "\n");
-  do_cleanups (old_chain);
+  if (value)
+    {
+      /* Print it.  */
+      stb = ui_out_stream_new (uiout);
+      old_chain = make_cleanup_ui_out_stream_delete (stb);
+      ui_out_text (uiout, "Value returned is ");
+      ui_out_field_fmt (uiout, "gdb-result-var", "$%d",
+                       record_latest_value (value));
+      ui_out_text (uiout, " = ");
+      value_print (value, stb->stream, 0, Val_no_prettyprint);
+      ui_out_field_stream (uiout, "return-value", stb);
+      ui_out_text (uiout, "\n");
+      do_cleanups (old_chain);
+    }
+  else
+    {
+      ui_out_text (uiout, "Value returned has type: ");
+      ui_out_field_string (uiout, "return-type", TYPE_NAME (value_type));
+      ui_out_text (uiout, ".");
+      ui_out_text (uiout, " Cannot determine contents\n");
+    }
 }
 
 /* Stuff that needs to be done by the finish command after the target
index 87baf2144b9ef41d10892428ab6c50ca1b9231a0..f468ff8abf7d6c1c0582caf7dff2b5516970b8f6 100644 (file)
@@ -1308,7 +1308,7 @@ using_struct_return (struct type *value_type, int gcc_p)
   /* Probe the architecture for the return-value convention.  */
   return (gdbarch_return_value (current_gdbarch, value_type,
                                NULL, NULL, NULL)
-         == RETURN_VALUE_STRUCT_CONVENTION);
+         != RETURN_VALUE_REGISTER_CONVENTION);
 }
 
 void