Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* [RFA] MIPS16 FP manual call/return fixes
@ 2012-04-23 13:30 Maciej W. Rozycki
  2012-04-26 19:20 ` Tom Tromey
  2012-04-26 19:33 ` Tom Tromey
  0 siblings, 2 replies; 15+ messages in thread
From: Maciej W. Rozycki @ 2012-04-23 13:30 UTC (permalink / raw)
  To: gdb-patches

Hello,

 Here is a change that addresses a problem that we have with MIPS16 FP 
manual call/return handlers.  This only addresses the o32 and o64 ABIs as 
we currently do not support hard-float for new ABIs.

 As noted with the recent MIPS16 thunk fix submission, MIPS targets use a 
different calling convention for passing floating-point arguments and 
results in registers for standard ABI and MIPS16 code.  We currently 
handle it partially for manual calls in the push_dummy_call handlers (but 
then do not get it right for o32) and do not handle it at all in the 
return_value handlers.

 For the push_dummy_call handlers the fix is easy -- general register 
arguments always follow their memory order (i.e. the order they would be 
pushed on the stack if they were stack arguments), that is unlike with 
32-bit floating-point registers they hold opposite halves of the same FP 
values each for the two endiannesses possible.  This is fixed with this 
change, rather trivially.  These handlers always store arguments in 
floating-point and general-purpose registers both at a time -- that being 
safe owing to either of each being dead on function entry depending on the 
calling convention used.

 The handling of manual returns is a bit more difficult, it's not always 
safe to use both at a time, because the handlers are dual-purpose.  They 
are used to either retrieve the return value of the function called, from 
the result register(s), such as when:

(gdb) print foo()

is used, or to push the return value to the intended register(s), such as 
with:

(gdb) return foo

As with arguments, either of the respective floating-point and 
general-purpose registers are dead on function return, which means it is 
safe to write both in the latter case, however to handle the former, the 
right register(s) need to be read.  For this to work we need to know if 
the function called was standard ABI or MIPS16 code, something that is 
currently not known to the return handlers.

 Therefore I had to change the return handlers' internal API to take the 
value of the function being handled rather than its lone type, if 
available.  This has led to adjusting the whole infrastructure.  With this 
in place the return handler, if called to read registers, selects the 
appropriate set.  If called to write registers, it stores the return value 
to both sets.  The handler is called with no specific function selected in 
some cases -- it is assumed (and guarded by assertions) that it will never 
be called to read registers in this case (as presumably the function just 
called must have been known).

 I have tested it for the mips-sde-elf and mips-linux-gnu targets, 
o32/MIPS32, o32/MIPS16 and n64 multilibs, fixing numerous problems, like:

(gdb) FAIL: gdb.base/call-sc.exp: p/c L; call call-sc-tf
(gdb) FAIL: gdb.base/call-sc.exp: p/c L; call call-sc-td
(gdb) FAIL: gdb.base/call-sc.exp: p/c L; call call-sc-tld

The patch also fixes failures introduced by the change to 
return-nodebug.exp included here to cover some floating-point types that 
were not tested this way before -- this is an example where the value of 
the function returned from is not known.

 I have also tested it on i686-linux-gnu, powerpc-linux-gnu, and 
sh-linux-gnu, the former being the usual suspect and the latters being 
representative for some non-trival changes made to other targets here, no 
regressions.

 Finally, this change intentionally does not cover complex types which we 
currently do not handle at all for the MIPS target for any ABI -- one fix 
at a time.

 Is this change OK to commit?  Please have a look specifically at changes 
I made to support the IFUNC feature (elfread.c) and updates to Python 
support (py-finishbreakpoint.c) as these are not my usual areas of 
experience.

2012-04-23  Maciej W. Rozycki  <macro@codesourcery.com>
            Maciej W. Rozycki  <macro@mips.com>

	gdb/
	* inferior.h (get_return_value): Take a pointer to struct value
	instead of struct type for the function requested.
	* value.h (using_struct_return): Likewise.
	* gdbarch.sh (return_value): Take a pointer to struct value
	instead of struct type for the function requested.
	* elfread.c (elf_gnu_ifunc_resolver_return_stop): Pass the
	requested function's address to gdbarch_return_value.
	* eval.c (evaluate_subexp_standard): Pass the requested
	function's address to using_struct_return.
	* infcall.c (call_function_by_hand): Pass the requested
	function's address to using_struct_return and
	gdbarch_return_value.
	* infcmd.c (get_return_value): Take a pointer to struct value
	instead of struct type for the function requested.
	(print_return_value): Update accordingly.
	(finish_command_continuation): Likewise.
	* stack.c (return_command): Pass the requested function's
	address to using_struct_return and gdbarch_return_value.
	* value.c (using_struct_return): Take a pointer to struct value
	instead of struct type for the function requested.  Pass the
	requested function's address to gdbarch_return_value.
	* python/py-finishbreakpoint.c (finish_breakpoint_object):
	New function_value member, replacing function_type.
	(bpfinishpy_dealloc): Update accordingly.
	(bpfinishpy_pre_stop_hook): Likewise.
	(bpfinishpy_init): Likewise.  Record the requested function's
	address.
	* mips-tdep.c (mips_fval_reg): New enum.
	(mips_o32_push_dummy_call): For MIPS16 FP doubles do not swap
	words put in GP registers.
	(mips_o64_push_dummy_call): Update a comment.
	(mips_o32_return_value): Take a pointer to struct value instead
	of struct type for the function requested and use it to check if
	using the MIPS16 calling convention.  Return the designated
	general purpose registers for floating-point values returned in
	MIPS16 mode.
	(mips_o64_return_value): Likewise.
	* ppc-tdep.h (ppc_sysv_abi_return_value): Update prototype.
	(ppc_sysv_abi_broken_return_value): Likewise.
	(ppc64_sysv_abi_return_value): Likewise.
	* alpha-tdep.c (alpha_return_value): Take a pointer to struct
	value instead of struct type for the function requested.
	* amd64-tdep.c (amd64_return_value): Likewise.
	* amd64-windows-tdep.c (amd64_windows_return_value): Likewise.
	* arm-tdep.c (arm_return_value): Likewise.
	* avr-tdep.c (avr_return_value): Likewise.
	* cris-tdep.c (cris_return_value): Likewise.
	* frv-tdep.c (frv_return_value): Likewise.
	* h8300-tdep.c (h8300_return_value): Likewise.
	(h8300h_return_value): Likewise.
	* hppa-tdep.c (hppa32_return_value): Likewise.
	(hppa64_return_value): Likewise.
	* i386-tdep.c (i386_return_value): Likewise.
	* ia64-tdep.c (ia64_return_value): Likewise.
	* iq2000-tdep.c (iq2000_return_value): Likewise.
	* lm32-tdep.c (lm32_return_value): Likewise.
	* m32c-tdep.c (m32c_return_value): Likewise.
	* m32r-tdep.c (m32r_return_value): Likewise.
	* m68hc11-tdep.c (m68hc11_return_value): Likewise.
	* m68k-tdep.c (m68k_return_value): Likewise.
	(m68k_svr4_return_value): Likewise.
	* m88k-tdep.c (m88k_return_value): Likewise.
	* mep-tdep.c (mep_return_value): Likewise.
	* microblaze-tdep.c (microblaze_return_value): Likewise.
	* mn10300-tdep.c (mn10300_return_value): Likewise.
	* moxie-tdep.c (moxie_return_value): Likewise.
	* mt-tdep.c (mt_return_value): Likewise.
	* ppc-linux-tdep.c (ppc_linux_return_value): Likewise.
	* ppc-sysv-tdep.c (ppc_sysv_abi_return_value): Likewise.
	(ppc_sysv_abi_broken_return_value): Likewise.
	(ppc64_sysv_abi_return_value): Likewise.
	* ppcnbsd-tdep.c (ppcnbsd_return_value): Likewise.
	* rs6000-aix-tdep.c (rs6000_return_value): Likewise.
	* s390-tdep.c (s390_return_value): Likewise.
	* score-tdep.c (score_return_value): Likewise.
	* sh-tdep.c (sh_return_value_nofpu): Likewise.
	(sh_return_value_fpu): Likewise.
	* sh64-tdep.c (sh64_return_value): Likewise.
	* sparc-tdep.c (sparc32_return_value): Likewise.
	* sparc64-tdep.c (sparc64_return_value): Likewise.
	* spu-tdep.c (spu_return_value): Likewise.
	* tic6x-tdep.c (tic6x_return_value): Likewise.
	* v850-tdep.c (v850_return_value): Likewise.
	* vax-tdep.c (vax_return_value): Likewise.
	* xstormy16-tdep.c (xstormy16_return_value): Likewise.
	* xtensa-tdep.c (xtensa_return_value): Likewise.
	* gdbarch.c: Regenerate.
	* gdbarch.h: Regenerate.

2012-04-23  Maciej W. Rozycki  <macro@codesourcery.com>

	gdb/testsuite/
	* gdb.base/return-nodebug.exp: Also test float and double types.

  Maciej

Index: gdb-fsf-trunk-quilt/gdb/alpha-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/alpha-tdep.c	2012-04-23 14:11:35.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/alpha-tdep.c	2012-04-23 14:12:54.705579723 +0100
@@ -612,7 +612,7 @@ alpha_store_return_value (struct type *v
 }
 
 static enum return_value_convention
-alpha_return_value (struct gdbarch *gdbarch, struct type *func_type,
+alpha_return_value (struct gdbarch *gdbarch, struct value *function,
 		    struct type *type, struct regcache *regcache,
 		    gdb_byte *readbuf, const gdb_byte *writebuf)
 {
Index: gdb-fsf-trunk-quilt/gdb/amd64-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/amd64-tdep.c	2012-04-23 14:11:35.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/amd64-tdep.c	2012-04-23 14:12:54.705579723 +0100
@@ -592,7 +592,7 @@ amd64_classify (struct type *type, enum 
 }
 
 static enum return_value_convention
-amd64_return_value (struct gdbarch *gdbarch, struct type *func_type,
+amd64_return_value (struct gdbarch *gdbarch, struct value *function,
 		    struct type *type, struct regcache *regcache,
 		    gdb_byte *readbuf, const gdb_byte *writebuf)
 {
Index: gdb-fsf-trunk-quilt/gdb/arm-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/arm-tdep.c	2012-04-23 14:11:35.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/arm-tdep.c	2012-04-23 14:12:54.715571159 +0100
@@ -9010,11 +9010,12 @@ arm_store_return_value (struct type *typ
 /* Handle function return values.  */
 
 static enum return_value_convention
-arm_return_value (struct gdbarch *gdbarch, struct type *func_type,
+arm_return_value (struct gdbarch *gdbarch, struct value *function,
 		  struct type *valtype, struct regcache *regcache,
 		  gdb_byte *readbuf, const gdb_byte *writebuf)
 {
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  struct type *func_type = function ? value_type (function) : NULL;
   enum arm_vfp_cprc_base_type vfp_base_type;
   int vfp_base_count;
 
Index: gdb-fsf-trunk-quilt/gdb/cris-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/cris-tdep.c	2012-04-23 14:11:35.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/cris-tdep.c	2012-04-23 14:12:54.735579761 +0100
@@ -1863,7 +1863,7 @@ cris_extract_return_value (struct type *
 /* Handle the CRIS return value convention.  */
 
 static enum return_value_convention
-cris_return_value (struct gdbarch *gdbarch, struct type *func_type,
+cris_return_value (struct gdbarch *gdbarch, struct value *function,
 		   struct type *type, struct regcache *regcache,
 		   gdb_byte *readbuf, const gdb_byte *writebuf)
 {
Index: gdb-fsf-trunk-quilt/gdb/eval.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/eval.c	2012-04-23 14:11:35.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/eval.c	2012-04-23 14:12:54.945578942 +0100
@@ -1358,8 +1358,7 @@ evaluate_subexp_standard (struct type *e
 		  val_type = expect_type;
 	      }
 
-	    struct_return = using_struct_return (exp->gdbarch,
-						 value_type (method),
+	    struct_return = using_struct_return (exp->gdbarch, method,
 						 val_type);
 	  }
 	else if (expect_type != NULL)
Index: gdb-fsf-trunk-quilt/gdb/frv-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/frv-tdep.c	2012-04-23 14:11:35.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/frv-tdep.c	2012-04-23 14:12:55.115577291 +0100
@@ -1351,7 +1351,7 @@ frv_store_return_value (struct type *typ
 }
 
 static enum return_value_convention
-frv_return_value (struct gdbarch *gdbarch, struct type *func_type,
+frv_return_value (struct gdbarch *gdbarch, struct value *function,
 		  struct type *valtype, struct regcache *regcache,
 		  gdb_byte *readbuf, const gdb_byte *writebuf)
 {
Index: gdb-fsf-trunk-quilt/gdb/gdbarch.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/gdbarch.c	2012-04-23 14:12:53.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/gdbarch.c	2012-04-23 14:12:55.415581296 +0100
@@ -2477,13 +2477,13 @@ gdbarch_return_value_p (struct gdbarch *
 }
 
 enum return_value_convention
-gdbarch_return_value (struct gdbarch *gdbarch, struct type *functype, struct type *valtype, struct regcache *regcache, gdb_byte *readbuf, const gdb_byte *writebuf)
+gdbarch_return_value (struct gdbarch *gdbarch, struct value *function, struct type *valtype, struct regcache *regcache, gdb_byte *readbuf, const gdb_byte *writebuf)
 {
   gdb_assert (gdbarch != NULL);
   gdb_assert (gdbarch->return_value != NULL);
   if (gdbarch_debug >= 2)
     fprintf_unfiltered (gdb_stdlog, "gdbarch_return_value called\n");
-  return gdbarch->return_value (gdbarch, functype, valtype, regcache, readbuf, writebuf);
+  return gdbarch->return_value (gdbarch, function, valtype, regcache, readbuf, writebuf);
 }
 
 void
Index: gdb-fsf-trunk-quilt/gdb/gdbarch.h
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/gdbarch.h	2012-04-23 14:12:53.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/gdbarch.h	2012-04-23 14:12:55.675579269 +0100
@@ -448,8 +448,8 @@ extern void set_gdbarch_integer_to_addre
 
 extern int gdbarch_return_value_p (struct gdbarch *gdbarch);
 
-typedef enum return_value_convention (gdbarch_return_value_ftype) (struct gdbarch *gdbarch, struct type *functype, struct type *valtype, struct regcache *regcache, gdb_byte *readbuf, const gdb_byte *writebuf);
-extern enum return_value_convention gdbarch_return_value (struct gdbarch *gdbarch, struct type *functype, struct type *valtype, struct regcache *regcache, gdb_byte *readbuf, const gdb_byte *writebuf);
+typedef enum return_value_convention (gdbarch_return_value_ftype) (struct gdbarch *gdbarch, struct value *function, struct type *valtype, struct regcache *regcache, gdb_byte *readbuf, const gdb_byte *writebuf);
+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);
 
 typedef CORE_ADDR (gdbarch_skip_prologue_ftype) (struct gdbarch *gdbarch, CORE_ADDR ip);
Index: gdb-fsf-trunk-quilt/gdb/gdbarch.sh
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/gdbarch.sh	2012-04-23 14:12:53.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/gdbarch.sh	2012-04-23 14:12:55.935577511 +0100
@@ -513,7 +513,7 @@ M:CORE_ADDR:integer_to_address:struct ty
 # stored into the appropriate register.  This can be used when we want
 # to force the value returned by a function (see the "return" command
 # for instance).
-M:enum return_value_convention:return_value:struct type *functype, struct type *valtype, struct regcache *regcache, gdb_byte *readbuf, const gdb_byte *writebuf:functype, valtype, regcache, readbuf, writebuf
+M:enum return_value_convention:return_value:struct value *function, struct type *valtype, struct regcache *regcache, gdb_byte *readbuf, const gdb_byte *writebuf:functype, valtype, regcache, readbuf, writebuf
 
 m:CORE_ADDR:skip_prologue:CORE_ADDR ip:ip:0:0
 M:CORE_ADDR:skip_main_prologue:CORE_ADDR ip:ip
Index: gdb-fsf-trunk-quilt/gdb/h8300-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/h8300-tdep.c	2012-04-23 14:11:35.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/h8300-tdep.c	2012-04-23 14:12:56.005575376 +0100
@@ -901,7 +901,7 @@ h8300h_store_return_value (struct type *
 }
 
 static enum return_value_convention
-h8300_return_value (struct gdbarch *gdbarch, struct type *func_type,
+h8300_return_value (struct gdbarch *gdbarch, struct value *function,
 		    struct type *type, struct regcache *regcache,
 		    gdb_byte *readbuf, const gdb_byte *writebuf)
 {
@@ -915,7 +915,7 @@ h8300_return_value (struct gdbarch *gdba
 }
 
 static enum return_value_convention
-h8300h_return_value (struct gdbarch *gdbarch, struct type *func_type,
+h8300h_return_value (struct gdbarch *gdbarch, struct value *function,
 		     struct type *type, struct regcache *regcache,
 		     gdb_byte *readbuf, const gdb_byte *writebuf)
 {
Index: gdb-fsf-trunk-quilt/gdb/hppa-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/hppa-tdep.c	2012-04-23 14:11:35.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/hppa-tdep.c	2012-04-23 14:12:56.235578496 +0100
@@ -1114,7 +1114,7 @@ hppa64_push_dummy_call (struct gdbarch *
 /* Handle 32/64-bit struct return conventions.  */
 
 static enum return_value_convention
-hppa32_return_value (struct gdbarch *gdbarch, struct type *func_type,
+hppa32_return_value (struct gdbarch *gdbarch, struct value *function,
 		     struct type *type, struct regcache *regcache,
 		     gdb_byte *readbuf, const gdb_byte *writebuf)
 {
@@ -1154,7 +1154,7 @@ hppa32_return_value (struct gdbarch *gdb
 }
 
 static enum return_value_convention
-hppa64_return_value (struct gdbarch *gdbarch, struct type *func_type,
+hppa64_return_value (struct gdbarch *gdbarch, struct value *function,
 		     struct type *type, struct regcache *regcache,
 		     gdb_byte *readbuf, const gdb_byte *writebuf)
 {
Index: gdb-fsf-trunk-quilt/gdb/i386-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/i386-tdep.c	2012-04-23 14:12:41.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/i386-tdep.c	2012-04-23 14:12:56.695574486 +0100
@@ -2598,7 +2598,7 @@ i386_reg_struct_return_p (struct gdbarch
    from WRITEBUF into REGCACHE.  */
 
 static enum return_value_convention
-i386_return_value (struct gdbarch *gdbarch, struct type *func_type,
+i386_return_value (struct gdbarch *gdbarch, struct value *function,
 		   struct type *type, struct regcache *regcache,
 		   gdb_byte *readbuf, const gdb_byte *writebuf)
 {
@@ -2649,7 +2649,7 @@ i386_return_value (struct gdbarch *gdbar
   if (code == TYPE_CODE_STRUCT && TYPE_NFIELDS (type) == 1)
     {
       type = check_typedef (TYPE_FIELD_TYPE (type, 0));
-      return i386_return_value (gdbarch, func_type, type, regcache,
+      return i386_return_value (gdbarch, function, type, regcache,
 				readbuf, writebuf);
     }
 
Index: gdb-fsf-trunk-quilt/gdb/ia64-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/ia64-tdep.c	2012-04-23 14:11:35.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/ia64-tdep.c	2012-04-23 14:12:56.995579166 +0100
@@ -3340,7 +3340,7 @@ ia64_store_return_value (struct type *ty
 }
   
 static enum return_value_convention
-ia64_return_value (struct gdbarch *gdbarch, struct type *func_type,
+ia64_return_value (struct gdbarch *gdbarch, struct value *function,
 		   struct type *valtype, struct regcache *regcache,
 		   gdb_byte *readbuf, const gdb_byte *writebuf)
 {
Index: gdb-fsf-trunk-quilt/gdb/infcall.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/infcall.c	2012-04-23 14:11:35.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/infcall.c	2012-04-23 14:12:57.135577338 +0100
@@ -608,8 +608,7 @@ call_function_by_hand (struct value *fun
     }
   else
     {
-      struct_return = using_struct_return (gdbarch,
-					   value_type (function), values_type);
+      struct_return = using_struct_return (gdbarch, function, values_type);
       target_values_type = values_type;
     }
 
@@ -1048,13 +1047,13 @@ When the function is done executing, GDB
       {
 	/* If the function returns void, don't bother fetching the
 	   return value.  */
-	switch (gdbarch_return_value (gdbarch, value_type (function),
-				      target_values_type, NULL, NULL, NULL))
+	switch (gdbarch_return_value (gdbarch, function, target_values_type,
+				      NULL, NULL, NULL))
 	  {
 	  case RETURN_VALUE_REGISTER_CONVENTION:
 	  case RETURN_VALUE_ABI_RETURNS_ADDRESS:
 	  case RETURN_VALUE_ABI_PRESERVES_ADDRESS:
-	    gdbarch_return_value (gdbarch, value_type (function), values_type,
+	    gdbarch_return_value (gdbarch, function, values_type,
 				  retbuf, value_contents_raw (retval), NULL);
 	    break;
 	  case RETURN_VALUE_STRUCT_CONVENTION:
Index: gdb-fsf-trunk-quilt/gdb/infcmd.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/infcmd.c	2012-04-23 14:11:35.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/infcmd.c	2012-04-23 14:12:57.395577550 +0100
@@ -75,7 +75,7 @@ void interrupt_target_command (char *arg
 
 static void nofp_registers_info (char *, int);
 
-static void print_return_value (struct type *func_type,
+static void print_return_value (struct value *function,
 				struct type *value_type);
 
 static void until_next_command (int);
@@ -1416,7 +1416,7 @@ advance_command (char *arg, int from_tty
    command/BP.  */
 
 struct value *
-get_return_value (struct type *func_type, struct type *value_type)
+get_return_value (struct value *function, struct type *value_type)
 {
   struct regcache *stop_regs = stop_registers;
   struct gdbarch *gdbarch;
@@ -1443,14 +1443,14 @@ get_return_value (struct type *func_type
      inferior function call code.  In fact, when inferior function
      calls are made async, this will likely be made the norm.  */
 
-  switch (gdbarch_return_value (gdbarch, func_type, value_type,
+  switch (gdbarch_return_value (gdbarch, function, value_type,
   				NULL, NULL, NULL))
     {
     case RETURN_VALUE_REGISTER_CONVENTION:
     case RETURN_VALUE_ABI_RETURNS_ADDRESS:
     case RETURN_VALUE_ABI_PRESERVES_ADDRESS:
       value = allocate_value (value_type);
-      gdbarch_return_value (gdbarch, func_type, value_type, stop_regs,
+      gdbarch_return_value (gdbarch, function, value_type, stop_regs,
 			    value_contents_raw (value), NULL);
       break;
     case RETURN_VALUE_STRUCT_CONVENTION:
@@ -1468,9 +1468,9 @@ get_return_value (struct type *func_type
 /* Print the result of a function at the end of a 'finish' command.  */
 
 static void
-print_return_value (struct type *func_type, struct type *value_type)
+print_return_value (struct value *function, struct type *value_type)
 {
-  struct value *value = get_return_value (func_type, value_type);
+  struct value *value = get_return_value (function, value_type);
   struct ui_out *uiout = current_uiout;
 
   if (value)
@@ -1547,14 +1547,17 @@ finish_command_continuation (void *arg, 
 
 	  if (TYPE_CODE (value_type) != TYPE_CODE_VOID)
 	    {
+	      CORE_ADDR faddr = BLOCK_START (SYMBOL_BLOCK_VALUE (a->function));
+	      struct value *func = allocate_value (SYMBOL_TYPE (a->function));
 	      volatile struct gdb_exception ex;
 
+	      set_value_address (func, faddr);
 	      TRY_CATCH (ex, RETURN_MASK_ALL)
 		{
 		  /* print_return_value can throw an exception in some
 		     circumstances.  We need to catch this so that we still
 		     delete the breakpoint.  */
-		  print_return_value (SYMBOL_TYPE (a->function), value_type);
+		  print_return_value (func, value_type);
 		}
 	      if (ex.reason < 0)
 		exception_print (gdb_stdout, ex);
Index: gdb-fsf-trunk-quilt/gdb/iq2000-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/iq2000-tdep.c	2012-04-23 14:11:35.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/iq2000-tdep.c	2012-04-23 14:12:57.545576783 +0100
@@ -583,7 +583,7 @@ iq2000_extract_return_value (struct type
 }
 
 static enum return_value_convention
-iq2000_return_value (struct gdbarch *gdbarch, struct type *func_type,
+iq2000_return_value (struct gdbarch *gdbarch, struct value *function,
 		     struct type *type, struct regcache *regcache,
 		     gdb_byte *readbuf, const gdb_byte *writebuf)
 {
Index: gdb-fsf-trunk-quilt/gdb/lm32-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/lm32-tdep.c	2012-04-23 14:11:35.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/lm32-tdep.c	2012-04-23 14:12:57.575576872 +0100
@@ -374,7 +374,7 @@ lm32_store_return_value (struct type *ty
 
 /* Determine whether a functions return value is in a register or memory.  */
 static enum return_value_convention
-lm32_return_value (struct gdbarch *gdbarch, struct type *func_type,
+lm32_return_value (struct gdbarch *gdbarch, struct value *function,
 		   struct type *valtype, struct regcache *regcache,
 		   gdb_byte *readbuf, const gdb_byte *writebuf)
 {
Index: gdb-fsf-trunk-quilt/gdb/m32c-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/m32c-tdep.c	2012-04-23 14:11:35.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/m32c-tdep.c	2012-04-23 14:12:58.105573784 +0100
@@ -2206,7 +2206,7 @@ m32c_return_by_passed_buf (struct type *
 
 static enum return_value_convention
 m32c_return_value (struct gdbarch *gdbarch,
-		   struct type *func_type,
+		   struct value *function,
 		   struct type *valtype,
 		   struct regcache *regcache,
 		   gdb_byte *readbuf,
Index: gdb-fsf-trunk-quilt/gdb/m32r-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/m32r-tdep.c	2012-04-23 14:11:35.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/m32r-tdep.c	2012-04-23 14:12:58.105573784 +0100
@@ -809,7 +809,7 @@ m32r_extract_return_value (struct type *
 }
 
 static enum return_value_convention
-m32r_return_value (struct gdbarch *gdbarch, struct type *func_type,
+m32r_return_value (struct gdbarch *gdbarch, struct value *function,
 		   struct type *valtype, struct regcache *regcache,
 		   gdb_byte *readbuf, const gdb_byte *writebuf)
 {
Index: gdb-fsf-trunk-quilt/gdb/m68hc11-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/m68hc11-tdep.c	2012-04-23 14:11:35.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/m68hc11-tdep.c	2012-04-23 14:12:58.105573784 +0100
@@ -1323,8 +1323,8 @@ m68hc11_extract_return_value (struct typ
 }
 
 static enum return_value_convention
-m68hc11_return_value (struct gdbarch *gdbarch, struct type *func_type,
-		      struct type *valtype, struct regcache *regcache,
+m68hc11_return_value (struct gdbarch *gdbarch, struct value *function,
+		      struct value *function, struct regcache *regcache,
 		      gdb_byte *readbuf, const gdb_byte *writebuf)
 {
   if (TYPE_CODE (valtype) == TYPE_CODE_STRUCT
Index: gdb-fsf-trunk-quilt/gdb/m68k-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/m68k-tdep.c	2012-04-23 14:11:35.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/m68k-tdep.c	2012-04-23 14:12:58.115574547 +0100
@@ -403,7 +403,7 @@ m68k_reg_struct_return_p (struct gdbarch
    from WRITEBUF into REGCACHE.  */
 
 static enum return_value_convention
-m68k_return_value (struct gdbarch *gdbarch, struct type *func_type,
+m68k_return_value (struct gdbarch *gdbarch, struct value *function,
 		   struct type *type, struct regcache *regcache,
 		   gdb_byte *readbuf, const gdb_byte *writebuf)
 {
@@ -438,7 +438,7 @@ m68k_return_value (struct gdbarch *gdbar
 }
 
 static enum return_value_convention
-m68k_svr4_return_value (struct gdbarch *gdbarch, struct type *func_type,
+m68k_svr4_return_value (struct gdbarch *gdbarch, struct value *function,
 			struct type *type, struct regcache *regcache,
 			gdb_byte *readbuf, const gdb_byte *writebuf)
 {
@@ -477,7 +477,7 @@ m68k_svr4_return_value (struct gdbarch *
   if (code == TYPE_CODE_STRUCT && TYPE_NFIELDS (type) == 1)
     {
       type = check_typedef (TYPE_FIELD_TYPE (type, 0));
-      return m68k_svr4_return_value (gdbarch, func_type, type, regcache,
+      return m68k_svr4_return_value (gdbarch, function, type, regcache,
 				     readbuf, writebuf);
     }
 
Index: gdb-fsf-trunk-quilt/gdb/m88k-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/m88k-tdep.c	2012-04-23 14:11:35.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/m88k-tdep.c	2012-04-23 14:12:58.115574547 +0100
@@ -383,7 +383,7 @@ m88k_dummy_id (struct gdbarch *arch, str
    from WRITEBUF into REGCACHE.  */
 
 static enum return_value_convention
-m88k_return_value (struct gdbarch *gdbarch, struct type *func_type,
+m88k_return_value (struct gdbarch *gdbarch, struct value *function,
 		   struct type *type, struct regcache *regcache,
 		   gdb_byte *readbuf, const gdb_byte *writebuf)
 {
Index: gdb-fsf-trunk-quilt/gdb/mep-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/mep-tdep.c	2012-04-23 14:11:35.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/mep-tdep.c	2012-04-23 14:12:58.115574547 +0100
@@ -2194,7 +2194,7 @@ Try using the 'return' command with no a
 }
 
 static enum return_value_convention
-mep_return_value (struct gdbarch *gdbarch, struct type *func_type,
+mep_return_value (struct gdbarch *gdbarch, struct value *function,
 		  struct type *type, struct regcache *regcache,
 		  gdb_byte *readbuf, const gdb_byte *writebuf)
 {
Index: gdb-fsf-trunk-quilt/gdb/mips-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/mips-tdep.c	2012-04-23 14:12:54.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/mips-tdep.c	2012-04-23 14:12:58.115574547 +0100
@@ -3290,7 +3290,7 @@ mips_eabi_push_dummy_call (struct gdbarc
 /* Determine the return value convention being used.  */
 
 static enum return_value_convention
-mips_eabi_return_value (struct gdbarch *gdbarch, struct type *func_type,
+mips_eabi_return_value (struct gdbarch *gdbarch, struct value *function,
 			struct type *type, struct regcache *regcache,
 			gdb_byte *readbuf, const gdb_byte *writebuf)
 {
@@ -3680,7 +3680,7 @@ mips_n32n64_push_dummy_call (struct gdba
 }
 
 static enum return_value_convention
-mips_n32n64_return_value (struct gdbarch *gdbarch, struct type *func_type,
+mips_n32n64_return_value (struct gdbarch *gdbarch, struct value *function,
 			  struct type *type, struct regcache *regcache,
 			  gdb_byte *readbuf, const gdb_byte *writebuf)
 {
@@ -3848,6 +3848,20 @@ mips_n32n64_return_value (struct gdbarch
     }
 }
 
+/* Which registers to use for passing floating-point values between
+   function calls, one of floating-point, general and both kinds of
+   registers.  O32 and O64 use different register kinds for standard
+   MIPS and MIPS16 code; to make the handling of cases where we may
+   not know what kind of code is being used (e.g. no debug information)
+   easier we sometimes use both kinds.  */
+
+enum mips_fval_reg
+{
+  mips_fval_fpr,
+  mips_fval_gpr,
+  mips_fval_both
+};
+
 /* O32 ABI stuff.  */
 
 static CORE_ADDR
@@ -3938,8 +3952,8 @@ mips_o32_push_dummy_call (struct gdbarch
       /* 32-bit ABIs always start floating point arguments in an
          even-numbered floating point register.  Round the FP register
          up before the check to see if there are any FP registers
-         left.  O32/O64 targets also pass the FP in the integer
-         registers so also round up normal registers.  */
+         left.  O32 targets also pass the FP in the integer registers
+         so also round up normal registers.  */
       if (fp_register_arg_p (gdbarch, typecode, arg_type))
 	{
 	  if ((float_argreg & 1))
@@ -3947,46 +3961,48 @@ mips_o32_push_dummy_call (struct gdbarch
 	}
 
       /* Floating point arguments passed in registers have to be
-         treated specially.  On 32-bit architectures, doubles
-         are passed in register pairs; the even register gets
-         the low word, and the odd register gets the high word.
-         On O32/O64, the first two floating point arguments are
-         also copied to general registers, because MIPS16 functions
-         don't use float registers for arguments.  This duplication of
-         arguments in general registers can't hurt non-MIPS16 functions
-         because those registers are normally skipped.  */
+         treated specially.  On 32-bit architectures, doubles are
+         passed in register pairs; the even FP register gets the
+         low word, and the odd FP register gets the high word.
+         On O32, the first two floating point arguments are also
+         copied to general registers, following their memory order,
+         because MIPS16 functions don't use float registers for
+         arguments.  This duplication of arguments in general
+         registers can't hurt non-MIPS16 functions, because those
+         registers are normally skipped.  */
 
       if (fp_register_arg_p (gdbarch, typecode, arg_type)
 	  && float_argreg <= MIPS_LAST_FP_ARG_REGNUM (gdbarch))
 	{
 	  if (register_size (gdbarch, float_argreg) < 8 && len == 8)
 	    {
-	      int low_offset = gdbarch_byte_order (gdbarch)
-			       == BFD_ENDIAN_BIG ? 4 : 0;
+	      int freg_offset = gdbarch_byte_order (gdbarch)
+				== BFD_ENDIAN_BIG ? 1 : 0;
 	      unsigned long regval;
 
-	      /* Write the low word of the double to the even register(s).  */
-	      regval = extract_unsigned_integer (val + low_offset,
-						 4, byte_order);
+	      /* First word.  */
+	      regval = extract_unsigned_integer (val, 4, byte_order);
 	      if (mips_debug)
 		fprintf_unfiltered (gdb_stdlog, " - fpreg=%d val=%s",
-				    float_argreg, phex (regval, 4));
+				    float_argreg + freg_offset,
+				    phex (regval, 4));
 	      regcache_cooked_write_unsigned (regcache,
-					      float_argreg++, regval);
+					      float_argreg++ + freg_offset,
+					      regval);
 	      if (mips_debug)
 		fprintf_unfiltered (gdb_stdlog, " - reg=%d val=%s",
 				    argreg, phex (regval, 4));
 	      regcache_cooked_write_unsigned (regcache, argreg++, regval);
 
-	      /* Write the high word of the double to the odd register(s).  */
-	      regval = extract_unsigned_integer (val + 4 - low_offset,
-						 4, byte_order);
+	      /* Second word.  */
+	      regval = extract_unsigned_integer (val + 4, 4, byte_order);
 	      if (mips_debug)
 		fprintf_unfiltered (gdb_stdlog, " - fpreg=%d val=%s",
-				    float_argreg, phex (regval, 4));
+				    float_argreg - freg_offset,
+				    phex (regval, 4));
 	      regcache_cooked_write_unsigned (regcache,
-					      float_argreg++, regval);
-
+					      float_argreg++ - freg_offset,
+					      regval);
 	      if (mips_debug)
 		fprintf_unfiltered (gdb_stdlog, " - reg=%d val=%s",
 				    argreg, phex (regval, 4));
@@ -4161,12 +4177,16 @@ mips_o32_push_dummy_call (struct gdbarch
 }
 
 static enum return_value_convention
-mips_o32_return_value (struct gdbarch *gdbarch, struct type *func_type,
+mips_o32_return_value (struct gdbarch *gdbarch, struct value *function,
 		       struct type *type, struct regcache *regcache,
 		       gdb_byte *readbuf, const gdb_byte *writebuf)
 {
+  CORE_ADDR func_addr = function ? find_function_addr (function, NULL) : 0;
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  int mips16 = mips_pc_is_mips16 (func_addr);
+  enum mips_fval_reg fval_reg;
 
+  fval_reg = readbuf ? mips16 ? mips_fval_gpr : mips_fval_fpr : mips_fval_both;
   if (TYPE_CODE (type) == TYPE_CODE_STRUCT
       || TYPE_CODE (type) == TYPE_CODE_UNION
       || TYPE_CODE (type) == TYPE_CODE_ARRAY)
@@ -4174,54 +4194,110 @@ mips_o32_return_value (struct gdbarch *g
   else if (TYPE_CODE (type) == TYPE_CODE_FLT
 	   && TYPE_LENGTH (type) == 4 && tdep->mips_fpu_type != MIPS_FPU_NONE)
     {
-      /* A single-precision floating-point value.  It fits in the
-         least significant part of FP0.  */
+      /* A single-precision floating-point value.  If reading in or copying,
+         then we get it from/put it to FP0 for standard MIPS code or GPR2
+         for MIPS16 code.  If writing out only, then we put it to both FP0
+         and GPR2.  We do not support reading in with no function known, if
+         this safety check ever triggers, then we'll have to try harder.  */
+      gdb_assert (function || !readbuf);
       if (mips_debug)
-	fprintf_unfiltered (gdb_stderr, "Return float in $fp0\n");
-      mips_xfer_register (gdbarch, regcache,
-			  (gdbarch_num_regs (gdbarch)
-			   + mips_regnum (gdbarch)->fp0),
-			  TYPE_LENGTH (type),
-			  gdbarch_byte_order (gdbarch),
-			  readbuf, writebuf, 0);
+	switch (fval_reg)
+	  {
+	  case mips_fval_fpr:
+	    fprintf_unfiltered (gdb_stderr, "Return float in $fp0\n");
+	    break;
+	  case mips_fval_gpr:
+	    fprintf_unfiltered (gdb_stderr, "Return float in $2\n");
+	    break;
+	  case mips_fval_both:
+	    fprintf_unfiltered (gdb_stderr, "Return float in $fp0 and $2\n");
+	    break;
+	  }
+      if (fval_reg != mips_fval_gpr)
+	mips_xfer_register (gdbarch, regcache,
+			    (gdbarch_num_regs (gdbarch)
+			     + mips_regnum (gdbarch)->fp0),
+			    TYPE_LENGTH (type),
+			    gdbarch_byte_order (gdbarch),
+			    readbuf, writebuf, 0);
+      if (fval_reg != mips_fval_fpr)
+	mips_xfer_register (gdbarch, regcache,
+			    gdbarch_num_regs (gdbarch) + 2,
+			    TYPE_LENGTH (type),
+			    gdbarch_byte_order (gdbarch),
+			    readbuf, writebuf, 0);
       return RETURN_VALUE_REGISTER_CONVENTION;
     }
   else if (TYPE_CODE (type) == TYPE_CODE_FLT
 	   && TYPE_LENGTH (type) == 8 && tdep->mips_fpu_type != MIPS_FPU_NONE)
     {
-      /* A double-precision floating-point value.  The most
-         significant part goes in FP1, and the least significant in
-         FP0.  */
+      /* A double-precision floating-point value.  If reading in or copying,
+         then we get it from/put it to FP1 and FP0 for standard MIPS code or
+         GPR2 and GPR3 for MIPS16 code.  If writing out only, then we put it
+         to both FP1/FP0 and GPR2/GPR3.  We do not support reading in with
+         no function known, if this safety check ever triggers, then we'll
+         have to try harder.  */
+      gdb_assert (function || !readbuf);
       if (mips_debug)
-	fprintf_unfiltered (gdb_stderr, "Return float in $fp1/$fp0\n");
-      switch (gdbarch_byte_order (gdbarch))
+	switch (fval_reg)
+	  {
+	  case mips_fval_fpr:
+	    fprintf_unfiltered (gdb_stderr, "Return float in $fp1/$fp0\n");
+	    break;
+	  case mips_fval_gpr:
+	    fprintf_unfiltered (gdb_stderr, "Return float in $2/$3\n");
+	    break;
+	  case mips_fval_both:
+	    fprintf_unfiltered (gdb_stderr,
+				"Return float in $fp1/$fp0 and $2/$3\n");
+	    break;
+	  }
+      if (fval_reg != mips_fval_gpr)
 	{
-	case BFD_ENDIAN_LITTLE:
-	  mips_xfer_register (gdbarch, regcache,
-			      (gdbarch_num_regs (gdbarch)
-			       + mips_regnum (gdbarch)->fp0 + 0),
-			      4, gdbarch_byte_order (gdbarch),
-			      readbuf, writebuf, 0);
-	  mips_xfer_register (gdbarch, regcache,
-			      (gdbarch_num_regs (gdbarch)
-			       + mips_regnum (gdbarch)->fp0 + 1),
-			      4, gdbarch_byte_order (gdbarch),
-			      readbuf, writebuf, 4);
-	  break;
-	case BFD_ENDIAN_BIG:
+	  /* The most significant part goes in FP1, and the least significant
+	     in FP0.  */
+	  switch (gdbarch_byte_order (gdbarch))
+	    {
+	    case BFD_ENDIAN_LITTLE:
+	      mips_xfer_register (gdbarch, regcache,
+				  (gdbarch_num_regs (gdbarch)
+				   + mips_regnum (gdbarch)->fp0 + 0),
+				  4, gdbarch_byte_order (gdbarch),
+				  readbuf, writebuf, 0);
+	      mips_xfer_register (gdbarch, regcache,
+				  (gdbarch_num_regs (gdbarch)
+				   + mips_regnum (gdbarch)->fp0 + 1),
+				  4, gdbarch_byte_order (gdbarch),
+				  readbuf, writebuf, 4);
+	      break;
+	    case BFD_ENDIAN_BIG:
+	      mips_xfer_register (gdbarch, regcache,
+				  (gdbarch_num_regs (gdbarch)
+				   + mips_regnum (gdbarch)->fp0 + 1),
+				  4, gdbarch_byte_order (gdbarch),
+				  readbuf, writebuf, 0);
+	      mips_xfer_register (gdbarch, regcache,
+				  (gdbarch_num_regs (gdbarch)
+				   + mips_regnum (gdbarch)->fp0 + 0),
+				  4, gdbarch_byte_order (gdbarch),
+				  readbuf, writebuf, 4);
+	      break;
+	    default:
+	      internal_error (__FILE__, __LINE__, _("bad switch"));
+	    }
+	}
+      if (fval_reg != mips_fval_fpr)
+	{
+	  /* The two 32-bit parts are always placed in GPR2 and GPR3
+	     following these registers' memory order.  */
 	  mips_xfer_register (gdbarch, regcache,
-			      (gdbarch_num_regs (gdbarch)
-			       + mips_regnum (gdbarch)->fp0 + 1),
+			      gdbarch_num_regs (gdbarch) + 2,
 			      4, gdbarch_byte_order (gdbarch),
 			      readbuf, writebuf, 0);
 	  mips_xfer_register (gdbarch, regcache,
-			      (gdbarch_num_regs (gdbarch)
-			       + mips_regnum (gdbarch)->fp0 + 0),
+			      gdbarch_num_regs (gdbarch) + 3,
 			      4, gdbarch_byte_order (gdbarch),
 			      readbuf, writebuf, 4);
-	  break;
-	default:
-	  internal_error (__FILE__, __LINE__, _("bad switch"));
 	}
       return RETURN_VALUE_REGISTER_CONVENTION;
     }
@@ -4401,14 +4477,14 @@ mips_o64_push_dummy_call (struct gdbarch
       val = value_contents (arg);
 
       /* Floating point arguments passed in registers have to be
-         treated specially.  On 32-bit architectures, doubles
-         are passed in register pairs; the even register gets
-         the low word, and the odd register gets the high word.
-         On O32/O64, the first two floating point arguments are
-         also copied to general registers, because MIPS16 functions
-         don't use float registers for arguments.  This duplication of
-         arguments in general registers can't hurt non-MIPS16 functions
-         because those registers are normally skipped.  */
+         treated specially.  On 32-bit architectures, doubles are
+         passed in register pairs; the even FP register gets the
+         low word, and the odd FP register gets the high word.
+         On O64, the first two floating point arguments are also
+         copied to general registers, because MIPS16 functions
+         don't use float registers for arguments.  This duplication
+         of arguments in general registers can't hurt non-MIPS16
+         functions because those registers are normally skipped.  */
 
       if (fp_register_arg_p (gdbarch, typecode, arg_type)
 	  && float_argreg <= MIPS_LAST_FP_ARG_REGNUM (gdbarch))
@@ -4553,28 +4629,54 @@ mips_o64_push_dummy_call (struct gdbarch
 }
 
 static enum return_value_convention
-mips_o64_return_value (struct gdbarch *gdbarch, struct type *func_type,
+mips_o64_return_value (struct gdbarch *gdbarch, struct value *function,
 		       struct type *type, struct regcache *regcache,
 		       gdb_byte *readbuf, const gdb_byte *writebuf)
 {
+  CORE_ADDR func_addr = function ? find_function_addr (function, NULL) : 0;
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  int mips16 = mips_pc_is_mips16 (func_addr);
+  enum mips_fval_reg fval_reg;
 
+  fval_reg = readbuf ? mips16 ? mips_fval_gpr : mips_fval_fpr : mips_fval_both;
   if (TYPE_CODE (type) == TYPE_CODE_STRUCT
       || TYPE_CODE (type) == TYPE_CODE_UNION
       || TYPE_CODE (type) == TYPE_CODE_ARRAY)
     return RETURN_VALUE_STRUCT_CONVENTION;
   else if (fp_register_arg_p (gdbarch, TYPE_CODE (type), type))
     {
-      /* A floating-point value.  It fits in the least significant
-         part of FP0.  */
+      /* A floating-point value.  If reading in or copying, then we get it
+         from/put it to FP0 for standard MIPS code or GPR2 for MIPS16 code.
+         If writing out only, then we put it to both FP0 and GPR2.  We do
+         not support reading in with no function known, if this safety
+         check ever triggers, then we'll have to try harder.  */
+      gdb_assert (function || !readbuf);
       if (mips_debug)
-	fprintf_unfiltered (gdb_stderr, "Return float in $fp0\n");
-      mips_xfer_register (gdbarch, regcache,
-			  (gdbarch_num_regs (gdbarch)
-			   + mips_regnum (gdbarch)->fp0),
-			  TYPE_LENGTH (type),
-			  gdbarch_byte_order (gdbarch),
-			  readbuf, writebuf, 0);
+	switch (fval_reg)
+	  {
+	  case mips_fval_fpr:
+	    fprintf_unfiltered (gdb_stderr, "Return float in $fp0\n");
+	    break;
+	  case mips_fval_gpr:
+	    fprintf_unfiltered (gdb_stderr, "Return float in $2\n");
+	    break;
+	  case mips_fval_both:
+	    fprintf_unfiltered (gdb_stderr, "Return float in $fp0 and $2\n");
+	    break;
+	  }
+      if (fval_reg != mips_fval_gpr)
+	mips_xfer_register (gdbarch, regcache,
+			    (gdbarch_num_regs (gdbarch)
+			     + mips_regnum (gdbarch)->fp0),
+			    TYPE_LENGTH (type),
+			    gdbarch_byte_order (gdbarch),
+			    readbuf, writebuf, 0);
+      if (fval_reg != mips_fval_fpr)
+	mips_xfer_register (gdbarch, regcache,
+			    gdbarch_num_regs (gdbarch) + 2,
+			    TYPE_LENGTH (type),
+			    gdbarch_byte_order (gdbarch),
+			    readbuf, writebuf, 0);
       return RETURN_VALUE_REGISTER_CONVENTION;
     }
   else
Index: gdb-fsf-trunk-quilt/gdb/mn10300-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/mn10300-tdep.c	2012-04-23 14:11:35.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/mn10300-tdep.c	2012-04-23 14:12:58.115574547 +0100
@@ -233,7 +233,7 @@ mn10300_extract_return_value (struct gdb
    from WRITEBUF into REGCACHE.  */
 
 static enum return_value_convention
-mn10300_return_value (struct gdbarch *gdbarch, struct type *func_type,
+mn10300_return_value (struct gdbarch *gdbarch, struct value *function,
 		      struct type *type, struct regcache *regcache,
 		      gdb_byte *readbuf, const gdb_byte *writebuf)
 {
Index: gdb-fsf-trunk-quilt/gdb/moxie-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/moxie-tdep.c	2012-04-23 14:11:35.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/moxie-tdep.c	2012-04-23 14:12:58.115574547 +0100
@@ -341,7 +341,7 @@ moxie_extract_return_value (struct type 
 /* Implement the "return_value" gdbarch method.  */
 
 static enum return_value_convention
-moxie_return_value (struct gdbarch *gdbarch, struct type *func_type,
+moxie_return_value (struct gdbarch *gdbarch, struct value *function,
 		   struct type *valtype, struct regcache *regcache,
 		   gdb_byte *readbuf, const gdb_byte *writebuf)
 {
Index: gdb-fsf-trunk-quilt/gdb/mt-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/mt-tdep.c	2012-04-23 14:11:35.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/mt-tdep.c	2012-04-23 14:12:58.115574547 +0100
@@ -335,7 +335,7 @@ mt_register_reggroup_p (struct gdbarch *
    values.  */
 
 static enum return_value_convention
-mt_return_value (struct gdbarch *gdbarch, struct type *func_type,
+mt_return_value (struct gdbarch *gdbarch, struct value *function,
 		 struct type *type, struct regcache *regcache,
 		 gdb_byte *readbuf, const gdb_byte *writebuf)
 {
Index: gdb-fsf-trunk-quilt/gdb/ppc-linux-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/ppc-linux-tdep.c	2012-04-23 14:11:35.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/ppc-linux-tdep.c	2012-04-23 14:12:58.115574547 +0100
@@ -233,7 +233,7 @@ ppc_linux_memory_remove_breakpoint (stru
    which were added later, do get returned in a register though.  */
 
 static enum return_value_convention
-ppc_linux_return_value (struct gdbarch *gdbarch, struct type *func_type,
+ppc_linux_return_value (struct gdbarch *gdbarch, struct value *function,
 			struct type *valtype, struct regcache *regcache,
 			gdb_byte *readbuf, const gdb_byte *writebuf)
 {  
@@ -243,7 +243,7 @@ ppc_linux_return_value (struct gdbarch *
 	   && TYPE_VECTOR (valtype)))
     return RETURN_VALUE_STRUCT_CONVENTION;
   else
-    return ppc_sysv_abi_return_value (gdbarch, func_type, valtype, regcache,
+    return ppc_sysv_abi_return_value (gdbarch, function, valtype, regcache,
 				      readbuf, writebuf);
 }
 
Index: gdb-fsf-trunk-quilt/gdb/ppc-sysv-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/ppc-sysv-tdep.c	2012-04-23 14:11:35.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/ppc-sysv-tdep.c	2012-04-23 14:12:58.125568419 +0100
@@ -1041,23 +1041,25 @@ do_ppc_sysv_return_value (struct gdbarch
 }
 
 enum return_value_convention
-ppc_sysv_abi_return_value (struct gdbarch *gdbarch, struct type *func_type,
+ppc_sysv_abi_return_value (struct gdbarch *gdbarch, struct value *function,
 			   struct type *valtype, struct regcache *regcache,
 			   gdb_byte *readbuf, const gdb_byte *writebuf)
 {
-  return do_ppc_sysv_return_value (gdbarch, func_type, valtype, regcache,
-				   readbuf, writebuf, 0);
+  return do_ppc_sysv_return_value (gdbarch,
+				   function ? value_type (function) : NULL,
+				   valtype, regcache, readbuf, writebuf, 0);
 }
 
 enum return_value_convention
 ppc_sysv_abi_broken_return_value (struct gdbarch *gdbarch,
-				  struct type *func_type,
+				  struct value *function,
 				  struct type *valtype,
 				  struct regcache *regcache,
 				  gdb_byte *readbuf, const gdb_byte *writebuf)
 {
-  return do_ppc_sysv_return_value (gdbarch, func_type, valtype, regcache,
-				   readbuf, writebuf, 1);
+  return do_ppc_sysv_return_value (gdbarch,
+				   function ? value_type (function) : NULL,
+				   valtype, regcache, readbuf, writebuf, 1);
 }
 
 /* The helper function for 64-bit SYSV push_dummy_call.  Converts the
@@ -1710,12 +1712,13 @@ ppc64_sysv_abi_push_dummy_call (struct g
    location; when READBUF is non-NULL, fill the buffer from the
    corresponding register return-value location.  */
 enum return_value_convention
-ppc64_sysv_abi_return_value (struct gdbarch *gdbarch, struct type *func_type,
+ppc64_sysv_abi_return_value (struct gdbarch *gdbarch, struct value *function,
 			     struct type *valtype, struct regcache *regcache,
 			     gdb_byte *readbuf, const gdb_byte *writebuf)
 {
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  struct type *func_type = function ? value_type (function) : NULL;
   int opencl_abi = func_type? ppc_sysv_use_opencl_abi (func_type) : 0;
 
   /* This function exists to support a calling convention that
Index: gdb-fsf-trunk-quilt/gdb/ppc-tdep.h
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/ppc-tdep.h	2012-04-23 14:11:35.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/ppc-tdep.h	2012-04-23 14:12:58.135579487 +0100
@@ -28,13 +28,13 @@ struct type;
 
 /* From ppc-sysv-tdep.c ...  */
 enum return_value_convention ppc_sysv_abi_return_value (struct gdbarch *gdbarch,
-							struct type *func_type,
+							struct value *function,
 							struct type *valtype,
 							struct regcache *regcache,
 							gdb_byte *readbuf,
 							const gdb_byte *writebuf);
 enum return_value_convention ppc_sysv_abi_broken_return_value (struct gdbarch *gdbarch,
-							       struct type *func_type,
+							       struct value *function,
 							       struct type *valtype,
 							       struct regcache *regcache,
 							       gdb_byte *readbuf,
@@ -54,7 +54,7 @@ CORE_ADDR ppc64_sysv_abi_push_dummy_call
 					  int struct_return,
 					  CORE_ADDR struct_addr);
 enum return_value_convention ppc64_sysv_abi_return_value (struct gdbarch *gdbarch,
-							  struct type *func_type,
+							  struct value *function,
 							  struct type *valtype,
 							  struct regcache *regcache,
 							  gdb_byte *readbuf,
Index: gdb-fsf-trunk-quilt/gdb/ppcnbsd-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/ppcnbsd-tdep.c	2012-04-23 14:11:35.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/ppcnbsd-tdep.c	2012-04-23 14:12:58.135579487 +0100
@@ -76,7 +76,7 @@ ppcnbsd_regset_from_core_section (struct
    the moment use the broken convention.  Ulgh!  */
 
 static enum return_value_convention
-ppcnbsd_return_value (struct gdbarch *gdbarch, struct type *func_type,
+ppcnbsd_return_value (struct gdbarch *gdbarch, struct value *function,
 		      struct type *valtype, struct regcache *regcache,
 		      gdb_byte *readbuf, const gdb_byte *writebuf)
 {
@@ -92,7 +92,7 @@ ppcnbsd_return_value (struct gdbarch *gd
     return RETURN_VALUE_STRUCT_CONVENTION;
   else
 #endif
-    return ppc_sysv_abi_broken_return_value (gdbarch, func_type, valtype,
+    return ppc_sysv_abi_broken_return_value (gdbarch, function, valtype,
 					     regcache, readbuf, writebuf);
 }
 \f
Index: gdb-fsf-trunk-quilt/gdb/rs6000-aix-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/rs6000-aix-tdep.c	2012-04-23 14:11:35.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/rs6000-aix-tdep.c	2012-04-23 14:12:58.135579487 +0100
@@ -424,7 +424,7 @@ rs6000_push_dummy_call (struct gdbarch *
 }
 
 static enum return_value_convention
-rs6000_return_value (struct gdbarch *gdbarch, struct type *func_type,
+rs6000_return_value (struct gdbarch *gdbarch, struct value *function,
 		     struct type *valtype, struct regcache *regcache,
 		     gdb_byte *readbuf, const gdb_byte *writebuf)
 {
Index: gdb-fsf-trunk-quilt/gdb/s390-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/s390-tdep.c	2012-04-23 14:11:35.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/s390-tdep.c	2012-04-23 14:12:58.135579487 +0100
@@ -2812,7 +2812,7 @@ s390_return_value_convention (struct gdb
 }
 
 static enum return_value_convention
-s390_return_value (struct gdbarch *gdbarch, struct type *func_type,
+s390_return_value (struct gdbarch *gdbarch, struct value *function,
 		   struct type *type, struct regcache *regcache,
 		   gdb_byte *out, const gdb_byte *in)
 {
Index: gdb-fsf-trunk-quilt/gdb/score-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/score-tdep.c	2012-04-23 14:11:35.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/score-tdep.c	2012-04-23 14:12:58.135579487 +0100
@@ -450,7 +450,7 @@ score_xfer_register (struct regcache *re
 }
 
 static enum return_value_convention
-score_return_value (struct gdbarch *gdbarch, struct type *func_type,
+score_return_value (struct gdbarch *gdbarch, struct value *function,
                     struct type *type, struct regcache *regcache,
                     gdb_byte * readbuf, const gdb_byte * writebuf)
 {
Index: gdb-fsf-trunk-quilt/gdb/sh-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/sh-tdep.c	2012-04-23 14:11:35.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/sh-tdep.c	2012-04-23 14:12:58.135579487 +0100
@@ -1398,10 +1398,12 @@ sh_store_return_value_fpu (struct type *
 }
 
 static enum return_value_convention
-sh_return_value_nofpu (struct gdbarch *gdbarch, struct type *func_type,
+sh_return_value_nofpu (struct gdbarch *gdbarch, struct value *function,
 		       struct type *type, struct regcache *regcache,
 		       gdb_byte *readbuf, const gdb_byte *writebuf)
 {
+  struct type *func_type = function ? value_type (function) : NULL;
+
   if (sh_use_struct_convention_nofpu (
   	sh_is_renesas_calling_convention (func_type), type))
     return RETURN_VALUE_STRUCT_CONVENTION;
@@ -1413,10 +1415,12 @@ sh_return_value_nofpu (struct gdbarch *g
 }
 
 static enum return_value_convention
-sh_return_value_fpu (struct gdbarch *gdbarch, struct type *func_type,
+sh_return_value_fpu (struct gdbarch *gdbarch, struct value *function,
 		     struct type *type, struct regcache *regcache,
 		     gdb_byte *readbuf, const gdb_byte *writebuf)
 {
+  struct type *func_type = function ? value_type (function) : NULL;
+
   if (sh_use_struct_convention (
 	sh_is_renesas_calling_convention (func_type), type))
     return RETURN_VALUE_STRUCT_CONVENTION;
Index: gdb-fsf-trunk-quilt/gdb/sh64-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/sh64-tdep.c	2012-04-23 14:11:35.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/sh64-tdep.c	2012-04-23 14:12:58.135579487 +0100
@@ -1328,7 +1328,7 @@ sh64_store_return_value (struct type *ty
 }
 
 static enum return_value_convention
-sh64_return_value (struct gdbarch *gdbarch, struct type *func_type,
+sh64_return_value (struct gdbarch *gdbarch, struct value *function,
 		   struct type *type, struct regcache *regcache,
 		   gdb_byte *readbuf, const gdb_byte *writebuf)
 {
Index: gdb-fsf-trunk-quilt/gdb/sparc-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/sparc-tdep.c	2012-04-23 14:11:35.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/sparc-tdep.c	2012-04-23 14:12:58.135579487 +0100
@@ -1353,7 +1353,7 @@ sparc32_store_return_value (struct type 
 }
 
 static enum return_value_convention
-sparc32_return_value (struct gdbarch *gdbarch, struct type *func_type,
+sparc32_return_value (struct gdbarch *gdbarch, struct value *function,
 		      struct type *type, struct regcache *regcache,
 		      gdb_byte *readbuf, const gdb_byte *writebuf)
 {
Index: gdb-fsf-trunk-quilt/gdb/sparc64-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/sparc64-tdep.c	2012-04-23 14:11:35.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/sparc64-tdep.c	2012-04-23 14:12:58.135579487 +0100
@@ -1119,7 +1119,7 @@ sparc64_store_return_value (struct type 
 }
 
 static enum return_value_convention
-sparc64_return_value (struct gdbarch *gdbarch, struct type *func_type,
+sparc64_return_value (struct gdbarch *gdbarch, struct value *function,
 		      struct type *type, struct regcache *regcache,
 		      gdb_byte *readbuf, const gdb_byte *writebuf)
 {
Index: gdb-fsf-trunk-quilt/gdb/spu-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/spu-tdep.c	2012-04-23 14:11:35.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/spu-tdep.c	2012-04-23 14:12:58.135579487 +0100
@@ -1450,10 +1450,11 @@ spu_dummy_id (struct gdbarch *gdbarch, s
 /* Function return value access.  */
 
 static enum return_value_convention
-spu_return_value (struct gdbarch *gdbarch, struct type *func_type,
+spu_return_value (struct gdbarch *gdbarch, struct value *function,
 		  struct type *type, struct regcache *regcache,
 		  gdb_byte *out, const gdb_byte *in)
 {
+  struct type *func_type = function ? value_type (function) : NULL;
   enum return_value_convention rvc;
   int opencl_vector = 0;
 
Index: gdb-fsf-trunk-quilt/gdb/stack.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/stack.c	2012-04-23 14:11:35.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/stack.c	2012-04-23 14:12:58.145564425 +0100
@@ -2238,6 +2238,7 @@ return_command (char *retval_exp, int fr
   struct gdbarch *gdbarch;
   struct symbol *thisfun;
   struct value *return_value = NULL;
+  struct value *function = NULL;
   const char *query_prefix = "";
 
   thisframe = get_selected_frame ("No selected frame.");
@@ -2282,6 +2283,13 @@ return_command (char *retval_exp, int fr
       if (value_lazy (return_value))
 	value_fetch_lazy (return_value);
 
+      if (thisfun != NULL)
+	{
+	  function = allocate_value (SYMBOL_TYPE (thisfun));
+	  set_value_address (function,
+			     BLOCK_START (SYMBOL_BLOCK_VALUE (thisfun)));
+	}
+
       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
@@ -2290,8 +2298,7 @@ return_command (char *retval_exp, int fr
            occur.  */
 	return_value = NULL;
       else if (thisfun != NULL
-	       && using_struct_return (gdbarch,
-				       SYMBOL_TYPE (thisfun), return_type))
+	       && using_struct_return (gdbarch, function, return_type))
 	{
 	  query_prefix = "The location at which to store the "
 	    "function's return value is unknown.\n"
@@ -2326,12 +2333,11 @@ return_command (char *retval_exp, int fr
     {
       struct type *return_type = value_type (return_value);
       struct gdbarch *gdbarch = get_regcache_arch (get_current_regcache ());
-      struct type *func_type = thisfun == NULL ? NULL : SYMBOL_TYPE (thisfun);
 
-      gdb_assert (gdbarch_return_value (gdbarch, func_type, return_type, NULL,
+      gdb_assert (gdbarch_return_value (gdbarch, function, return_type, NULL,
 					NULL, NULL)
 		  == RETURN_VALUE_REGISTER_CONVENTION);
-      gdbarch_return_value (gdbarch, func_type, return_type,
+      gdbarch_return_value (gdbarch, function, return_type,
 			    get_current_regcache (), NULL /*read*/,
 			    value_contents (return_value) /*write*/);
     }
Index: gdb-fsf-trunk-quilt/gdb/v850-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/v850-tdep.c	2012-04-23 14:11:35.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/v850-tdep.c	2012-04-23 14:12:58.145564425 +0100
@@ -933,7 +933,7 @@ v850_store_return_value (struct type *ty
 }
 
 static enum return_value_convention
-v850_return_value (struct gdbarch *gdbarch, struct type *func_type,
+v850_return_value (struct gdbarch *gdbarch, struct value *function,
 		   struct type *type, struct regcache *regcache,
 		   gdb_byte *readbuf, const gdb_byte *writebuf)
 {
Index: gdb-fsf-trunk-quilt/gdb/value.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/value.c	2012-04-23 14:11:35.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/value.c	2012-04-23 14:12:58.145564425 +0100
@@ -3269,7 +3269,7 @@ coerce_array (struct value *arg)
 
 int
 using_struct_return (struct gdbarch *gdbarch,
-		     struct type *func_type, struct type *value_type)
+		     struct value *function, struct type *value_type)
 {
   enum type_code code = TYPE_CODE (value_type);
 
@@ -3282,7 +3282,7 @@ using_struct_return (struct gdbarch *gdb
     return 0;
 
   /* Probe the architecture for the return-value convention.  */
-  return (gdbarch_return_value (gdbarch, func_type, value_type,
+  return (gdbarch_return_value (gdbarch, function, value_type,
 				NULL, NULL, NULL)
 	  != RETURN_VALUE_REGISTER_CONVENTION);
 }
Index: gdb-fsf-trunk-quilt/gdb/value.h
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/value.h	2012-04-23 14:11:35.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/value.h	2012-04-23 14:12:58.145564425 +0100
@@ -698,7 +698,7 @@ extern int value_bit_index (struct type 
 			    int index);
 
 extern int using_struct_return (struct gdbarch *gdbarch,
-				struct type *func_type,
+				struct value *function,
 				struct type *value_type);
 
 extern struct value *evaluate_expression (struct expression *exp);
Index: gdb-fsf-trunk-quilt/gdb/vax-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/vax-tdep.c	2012-04-23 14:11:35.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/vax-tdep.c	2012-04-23 14:12:58.145564425 +0100
@@ -204,7 +204,7 @@ vax_dummy_id (struct gdbarch *gdbarch, s
 \f
 
 static enum return_value_convention
-vax_return_value (struct gdbarch *gdbarch, struct type *func_type,
+vax_return_value (struct gdbarch *gdbarch, struct value *function,
 		  struct type *type, struct regcache *regcache,
 		  gdb_byte *readbuf, const gdb_byte *writebuf)
 {
Index: gdb-fsf-trunk-quilt/gdb/xstormy16-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/xstormy16-tdep.c	2012-04-23 14:11:35.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/xstormy16-tdep.c	2012-04-23 14:12:58.145564425 +0100
@@ -197,7 +197,7 @@ xstormy16_store_return_value (struct typ
 }
 
 static enum return_value_convention
-xstormy16_return_value (struct gdbarch *gdbarch, struct type *func_type,
+xstormy16_return_value (struct gdbarch *gdbarch, struct value *function,
 			struct type *type, struct regcache *regcache,
 			gdb_byte *readbuf, const gdb_byte *writebuf)
 {
Index: gdb-fsf-trunk-quilt/gdb/xtensa-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/xtensa-tdep.c	2012-04-23 14:11:35.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/xtensa-tdep.c	2012-04-23 14:12:58.145564425 +0100
@@ -1682,7 +1682,7 @@ xtensa_store_return_value (struct type *
 
 static enum return_value_convention
 xtensa_return_value (struct gdbarch *gdbarch,
-		     struct type *func_type,
+		     struct value *function,
 		     struct type *valtype,
 		     struct regcache *regcache,
 		     gdb_byte *readbuf,
Index: gdb-fsf-trunk-quilt/gdb/elfread.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/elfread.c	2012-04-23 14:12:54.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/elfread.c	2012-04-23 14:12:58.145564425 +0100
@@ -1020,21 +1020,16 @@ elf_gnu_ifunc_resolver_return_stop (stru
   struct type *func_func_type = builtin_type (gdbarch)->builtin_func_func;
   struct type *value_type = TYPE_TARGET_TYPE (func_func_type);
   struct regcache *regcache = get_thread_regcache (inferior_ptid);
+  struct value *func_func;
   struct value *value;
   CORE_ADDR resolved_address, resolved_pc;
   struct symtab_and_line sal;
   struct symtabs_and_lines sals, sals_end;
+  CORE_ADDR func_func_addr;
+  int is_gnu_ifunc;
 
   gdb_assert (b->type == bp_gnu_ifunc_resolver_return);
 
-  value = allocate_value (value_type);
-  gdbarch_return_value (gdbarch, func_func_type, value_type, regcache,
-			value_contents_raw (value), NULL);
-  resolved_address = value_as_address (value);
-  resolved_pc = gdbarch_convert_from_func_ptr_addr (gdbarch,
-						    resolved_address,
-						    &current_target);
-
   while (b->related_breakpoint != b)
     {
       struct breakpoint *b_next = b->related_breakpoint;
@@ -1055,6 +1050,21 @@ elf_gnu_ifunc_resolver_return_stop (stru
       b = b_next;
     }
   gdb_assert (b->type == bp_gnu_ifunc_resolver);
+  gdb_assert (b->loc->next == NULL);
+
+  find_pc_partial_function_gnu_ifunc (b->loc->address, NULL,
+				      &func_func_addr, NULL, &is_gnu_ifunc);
+  gdb_assert (is_gnu_ifunc);
+  func_func = allocate_value (func_func_type);
+  set_value_address (func_func, func_func_addr);
+
+  value = allocate_value (value_type);
+  gdbarch_return_value (gdbarch, func_func, value_type, regcache,
+			value_contents_raw (value), NULL);
+  resolved_address = value_as_address (value);
+  resolved_pc = gdbarch_convert_from_func_ptr_addr (gdbarch,
+						    resolved_address,
+						    &current_target);
 
   gdb_assert (current_program_space == b->pspace || b->pspace == NULL);
   elf_gnu_ifunc_record_cache (b->addr_string, resolved_pc);
Index: gdb-fsf-trunk-quilt/gdb/inferior.h
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/inferior.h	2012-04-23 14:11:35.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/inferior.h	2012-04-23 14:12:58.145564425 +0100
@@ -266,7 +266,7 @@ extern void detach_command (char *, int)
 
 extern void notice_new_inferior (ptid_t, int, int);
 
-extern struct value *get_return_value (struct type *func_type,
+extern struct value *get_return_value (struct value *function,
                                        struct type *value_type);
 
 /* Address at which inferior stopped.  */
Index: gdb-fsf-trunk-quilt/gdb/python/py-finishbreakpoint.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/python/py-finishbreakpoint.c	2012-04-23 14:11:35.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/python/py-finishbreakpoint.c	2012-04-23 14:12:58.145564425 +0100
@@ -29,6 +29,7 @@
 #include "language.h"
 #include "observer.h"
 #include "inferior.h"
+#include "block.h"
 
 static PyTypeObject finish_breakpoint_object_type;
 
@@ -45,9 +46,9 @@ struct finish_breakpoint_object
      May be NULL if no debug information was available or return type
      was VOID.  */
   PyObject *return_type;
-  /* gdb.Type object of the function finished by this breakpoint.  Will be
+  /* gdb.Value object of the function finished by this breakpoint.  Will be
      NULL if return_type is NULL.  */
-  PyObject *function_type;
+  PyObject *function_value;
   /* When stopped at this FinishBreakpoint, gdb.Value object returned by
      the function; Py_None if the value is not computable; NULL if GDB is
      not stopped at a FinishBreakpoint.  */
@@ -78,7 +79,7 @@ bpfinishpy_dealloc (PyObject *self)
   struct finish_breakpoint_object *self_bpfinish =
         (struct finish_breakpoint_object *) self;
 
-  Py_XDECREF (self_bpfinish->function_type);
+  Py_XDECREF (self_bpfinish->function_value);
   Py_XDECREF (self_bpfinish->return_type);
   Py_XDECREF (self_bpfinish->return_value);
 }
@@ -102,9 +103,11 @@ bpfinishpy_pre_stop_hook (struct breakpo
 
   TRY_CATCH (except, RETURN_MASK_ALL)
     {
-      struct value *ret =
-          get_return_value (type_object_to_type (self_finishbp->function_type),
-                            type_object_to_type (self_finishbp->return_type));
+      struct value *function =
+        value_object_to_value (self_finishbp->function_value);
+      struct type *value_type =
+        type_object_to_type (self_finishbp->return_type);
+      struct value *ret = get_return_value (function, value_type);
 
       if (ret)
         {
@@ -233,7 +236,7 @@ bpfinishpy_init (PyObject *self, PyObjec
 
   /* Find the function we will return from.  */
   self_bpfinish->return_type = NULL;
-  self_bpfinish->function_type = NULL;
+  self_bpfinish->function_value = NULL;
 
   TRY_CATCH (except, RETURN_MASK_ALL)
     {
@@ -248,25 +251,31 @@ bpfinishpy_init (PyObject *self, PyObjec
               /* Remember only non-void return types.  */
               if (TYPE_CODE (ret_type) != TYPE_CODE_VOID)
                 {
+                  struct value *func_value;
+                  CORE_ADDR func_addr;
+
                   /* Ignore Python errors at this stage.  */
                   self_bpfinish->return_type = type_to_type_object (ret_type);
                   PyErr_Clear ();
-                  self_bpfinish->function_type =
-                      type_to_type_object (SYMBOL_TYPE (function));
+                  func_value = allocate_value (SYMBOL_TYPE (function));
+                  func_addr = BLOCK_START (SYMBOL_BLOCK_VALUE (function));
+                  set_value_address (func_value, func_addr);
+                  self_bpfinish->function_value =
+                      value_to_value_object (func_value);
                   PyErr_Clear ();
                 }
             }
         }
     }
   if (except.reason < 0
-      || !self_bpfinish->return_type || !self_bpfinish->function_type)
+      || !self_bpfinish->return_type || !self_bpfinish->function_value)
     {
       /* Won't be able to compute return value.  */
       Py_XDECREF (self_bpfinish->return_type);
-      Py_XDECREF (self_bpfinish->function_type);
+      Py_XDECREF (self_bpfinish->function_value);
 
       self_bpfinish->return_type = NULL;
-      self_bpfinish->function_type = NULL;
+      self_bpfinish->function_value = NULL;
     }
 
   bppy_pending_object = &self_bpfinish->py_bp;
Index: gdb-fsf-trunk-quilt/gdb/testsuite/gdb.base/return-nodebug.exp
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/testsuite/gdb.base/return-nodebug.exp	2012-04-23 14:11:35.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/testsuite/gdb.base/return-nodebug.exp	2012-04-23 14:12:58.165575931 +0100
@@ -41,7 +41,7 @@ proc do_test {type} {
     }
 }
 
-foreach type {{signed char} {short} {int} {long} {long long}} {
+foreach type {{signed char} {short} {int} {long} {long long} {float} {double}} {
     set typeesc [string map {{ } {\ }} $type]
     set typenospace [string map {{ } -} $type]
 
Index: gdb-fsf-trunk-quilt/gdb/amd64-windows-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/amd64-windows-tdep.c	2012-04-23 14:11:35.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/amd64-windows-tdep.c	2012-04-23 14:12:58.175573499 +0100
@@ -73,7 +73,7 @@ amd64_windows_classify (struct type *typ
 /* Implement the "return_value" gdbarch method for amd64-windows.  */
 
 static enum return_value_convention
-amd64_windows_return_value (struct gdbarch *gdbarch, struct type *func_type,
+amd64_windows_return_value (struct gdbarch *gdbarch, struct value *function,
 			    struct type *type, struct regcache *regcache,
 			    gdb_byte *readbuf, const gdb_byte *writebuf)
 {
Index: gdb-fsf-trunk-quilt/gdb/avr-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/avr-tdep.c	2012-04-23 14:11:35.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/avr-tdep.c	2012-04-23 14:12:58.175573499 +0100
@@ -902,7 +902,7 @@ avr_breakpoint_from_pc (struct gdbarch *
    from WRITEBUF into REGCACHE.  */
 
 static enum return_value_convention
-avr_return_value (struct gdbarch *gdbarch, struct type *func_type,
+avr_return_value (struct gdbarch *gdbarch, struct value *function,
 		  struct type *valtype, struct regcache *regcache,
 		  gdb_byte *readbuf, const gdb_byte *writebuf)
 {
Index: gdb-fsf-trunk-quilt/gdb/microblaze-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/microblaze-tdep.c	2012-04-23 14:12:25.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/microblaze-tdep.c	2012-04-23 14:09:21.505559981 +0100
@@ -612,7 +612,7 @@ microblaze_store_return_value (struct ty
 }
 
 static enum return_value_convention
-microblaze_return_value (struct gdbarch *gdbarch, struct type *func_type,
+microblaze_return_value (struct gdbarch *gdbarch, struct value *function,
 			 struct type *type, struct regcache *regcache,
 			 gdb_byte *readbuf, const gdb_byte *writebuf)
 {
Index: gdb-fsf-trunk-quilt/gdb/tic6x-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/tic6x-tdep.c	2012-04-23 14:12:25.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/tic6x-tdep.c	2012-04-23 14:10:21.975575691 +0100
@@ -821,7 +821,7 @@ tic6x_store_return_value (struct type *v
 /* This is the implementation of gdbarch method return_value.  */
 
 static enum return_value_convention
-tic6x_return_value (struct gdbarch *gdbarch, struct type *func_type,
+tic6x_return_value (struct gdbarch *gdbarch, struct value *function,
 		    struct type *type, struct regcache *regcache,
 		    gdb_byte *readbuf, const gdb_byte *writebuf)
 {


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFA] MIPS16 FP manual call/return fixes
  2012-04-23 13:30 [RFA] MIPS16 FP manual call/return fixes Maciej W. Rozycki
@ 2012-04-26 19:20 ` Tom Tromey
  2012-04-26 22:23   ` Maciej W. Rozycki
  2012-04-26 19:33 ` Tom Tromey
  1 sibling, 1 reply; 15+ messages in thread
From: Tom Tromey @ 2012-04-26 19:20 UTC (permalink / raw)
  To: Maciej W. Rozycki; +Cc: gdb-patches

>>>>> "Maciej" == Maciej W Rozycki <macro@codesourcery.com> writes:

Maciej> 	* value.h (using_struct_return): Likewise.

I noticed that sparc-tdep.c calls this, but your patch doesn't update
it.

Tom


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFA] MIPS16 FP manual call/return fixes
  2012-04-23 13:30 [RFA] MIPS16 FP manual call/return fixes Maciej W. Rozycki
  2012-04-26 19:20 ` Tom Tromey
@ 2012-04-26 19:33 ` Tom Tromey
  2012-04-30 23:45   ` Maciej W. Rozycki
  1 sibling, 1 reply; 15+ messages in thread
From: Tom Tromey @ 2012-04-26 19:33 UTC (permalink / raw)
  To: Maciej W. Rozycki; +Cc: gdb-patches

>>>>> "Maciej" == Maciej W Rozycki <macro@codesourcery.com> writes:

Maciej>  Therefore I had to change the return handlers' internal API to
Maciej> take the value of the function being handled rather than its
Maciej> lone type, if available.  This has led to adjusting the whole
Maciej> infrastructure.

It seems reasonable to me.

I didn't try to read the MIPS part of the patch.

Maybe Jan could read the ifunc change in elfread.c.

Maciej>  # stored into the appropriate register.  This can be used when we want
Maciej>  # to force the value returned by a function (see the "return" command
Maciej>  # for instance).
Maciej> -M:enum return_value_convention:return_value:struct type *functype, struct type *valtype, struct regcache *regcache, gdb_byte *readbuf, const gdb_byte *writebuf:functype, valtype, regcache, readbuf, writebuf
Maciej> +M:enum return_value_convention:return_value:struct value *function, struct type *valtype, struct regcache *regcache, gdb_byte *readbuf, const gdb_byte *writebuf:functype, valtype, regcache, readbuf, writebuf

A couple of nits here:

Update the introductory comment to refer to FUNCTION, not FUNCTYPE.

Also, please s/functype/function/ in the list of argument names (at the
end of the line).

Maciej> +	      CORE_ADDR faddr = BLOCK_START (SYMBOL_BLOCK_VALUE (a->function));
Maciej> +	      struct value *func = allocate_value (SYMBOL_TYPE (a->function));

I think read_var_value would be better here.

Maciej> +      if (thisfun != NULL)
Maciej> +	{
Maciej> +	  function = allocate_value (SYMBOL_TYPE (thisfun));
Maciej> +	  set_value_address (function,
Maciej> +			     BLOCK_START (SYMBOL_BLOCK_VALUE (thisfun)));

Here too.

Maciej> +                  func_value = allocate_value (SYMBOL_TYPE (function));
Maciej> +                  func_addr = BLOCK_START (SYMBOL_BLOCK_VALUE (function));
Maciej> +                  set_value_address (func_value, func_addr);
Maciej> +                  self_bpfinish->function_value =
Maciej> +                      value_to_value_object (func_value);

Here too.

The rest looked good to me.

Tom


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFA] MIPS16 FP manual call/return fixes
  2012-04-26 19:20 ` Tom Tromey
@ 2012-04-26 22:23   ` Maciej W. Rozycki
  2012-04-27 15:16     ` Maciej W. Rozycki
  0 siblings, 1 reply; 15+ messages in thread
From: Maciej W. Rozycki @ 2012-04-26 22:23 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

On Thu, 26 Apr 2012, Tom Tromey wrote:

> Maciej> 	* value.h (using_struct_return): Likewise.
> 
> I noticed that sparc-tdep.c calls this, but your patch doesn't update
> it.

 Good catch, thanks!  I'll see how I can deal with that.  It seems to me I 
may be able to regression-test it too, let me see...

  Maciej


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFA] MIPS16 FP manual call/return fixes
  2012-04-26 22:23   ` Maciej W. Rozycki
@ 2012-04-27 15:16     ` Maciej W. Rozycki
  2012-04-27 15:28       ` Tom Tromey
  0 siblings, 1 reply; 15+ messages in thread
From: Maciej W. Rozycki @ 2012-04-27 15:16 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

On Thu, 26 Apr 2012, Maciej W. Rozycki wrote:

> > Maciej> 	* value.h (using_struct_return): Likewise.
> > 
> > I noticed that sparc-tdep.c calls this, but your patch doesn't update
> > it.
> 
>  Good catch, thanks!  I'll see how I can deal with that.  It seems to me I 
> may be able to regression-test it too, let me see...

 So this was a red herring after all, the argument in question is NULL 
here, so the type does not matter as in some other places touched by the 
patch.  Chances are I already considered it and disregarded before (by 
proofreading only, though) -- this patch is long-lived enough this may 
well have been many years ago, so I don't remember anymore.

 There are no regression for the sparc-solaris2.8 native target, GCC, 
using 32-bit and 64-bit (-m64) multilibs -- with the patch as is.

 However while attempting to do this I hit two problems for which I'll 
post patches separately: program name transformation breakage in 
gdb/configure and function prototype breakage in /proc services.

  Maciej


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFA] MIPS16 FP manual call/return fixes
  2012-04-27 15:16     ` Maciej W. Rozycki
@ 2012-04-27 15:28       ` Tom Tromey
  0 siblings, 0 replies; 15+ messages in thread
From: Tom Tromey @ 2012-04-27 15:28 UTC (permalink / raw)
  To: Maciej W. Rozycki; +Cc: gdb-patches

>>>>> "Maciej" == Maciej W Rozycki <macro@codesourcery.com> writes:

Maciej>  So this was a red herring after all, the argument in question
Maciej> is NULL here,

Ok, thanks.  I'm sorry I didn't notice this.

Tom


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFA] MIPS16 FP manual call/return fixes
  2012-04-26 19:33 ` Tom Tromey
@ 2012-04-30 23:45   ` Maciej W. Rozycki
  2012-05-01 14:05     ` Jan Kratochvil
  0 siblings, 1 reply; 15+ messages in thread
From: Maciej W. Rozycki @ 2012-04-30 23:45 UTC (permalink / raw)
  To: Tom Tromey, Jan Kratochvil; +Cc: gdb-patches

On Thu, 26 Apr 2012, Tom Tromey wrote:

> Maciej>  Therefore I had to change the return handlers' internal API to
> Maciej> take the value of the function being handled rather than its
> Maciej> lone type, if available.  This has led to adjusting the whole
> Maciej> infrastructure.
> 
> It seems reasonable to me.
> 
> I didn't try to read the MIPS part of the patch.
> 
> Maybe Jan could read the ifunc change in elfread.c.

 Jan, would you please find a spare minute to look?  The changes are meant 
to be straightforward, we don't need resolved_pc before we have tracked 
down the ifunc resolver breakpoint, at which point we can use its location 
to track down the function actually called.  Then we can use its address 
with gdbarch_return_value for the backend to determine the actual ABI 
used.

 That said (and as noted before, I am not terribly familiar with the IFUNC 
feature), I suspect that any such function has to be treated as a regular 
indirect function call and therefore be reached via one of the MIPS16 
call/return (as applicable) stubs concerned recently, so the standard ABI 
can probably be assumed.

 Then again, maybe not, in a pure-MIPS16 executable (or maybe really just 
a mixed-mode one that happens to call the function in question from MIPS16 
code only -- there's really no sense to use hard-FP with pure-MIPS16 code 
as there's no access to the FPU in the MIPS16 mode) the resolver could 
optimise IFUNC lookup to the proper MIPS16 entry point.

 Anyway, any thunks used only copy registers and do not clobber the 
originals, so fetching the return value from the original registers is 
going to work as expected.  Besides, the design is meant to be generic and 
work for any other platforms/ABIs that may suffer from such peculiarities 
(i.e. a different calling convention on an externally determined 
case-by-case basis).

 The extra assertion verifies that we only have a single resolver 
breakpoint assigned with this call; my understanding of the concept and 
code is this must always be the case.

> Maciej>  # stored into the appropriate register.  This can be used when we want
> Maciej>  # to force the value returned by a function (see the "return" command
> Maciej>  # for instance).
> Maciej> -M:enum return_value_convention:return_value:struct type *functype, struct type *valtype, struct regcache *regcache, gdb_byte *readbuf, const gdb_byte *writebuf:functype, valtype, regcache, readbuf, writebuf
> Maciej> +M:enum return_value_convention:return_value:struct value *function, struct type *valtype, struct regcache *regcache, gdb_byte *readbuf, const gdb_byte *writebuf:functype, valtype, regcache, readbuf, writebuf
> 
> A couple of nits here:
> 
> Update the introductory comment to refer to FUNCTION, not FUNCTYPE.
> 
> Also, please s/functype/function/ in the list of argument names (at the
> end of the line).

 Ugh, I must have obviously messed up something here at one point as I got 
gdbarch.c right but not gdbarch.h or gdbarch.sh.

> Maciej> +	      CORE_ADDR faddr = BLOCK_START (SYMBOL_BLOCK_VALUE (a->function));
> Maciej> +	      struct value *func = allocate_value (SYMBOL_TYPE (a->function));
> 
> I think read_var_value would be better here.

 Thanks for the pointer, I tend to agree and regression testing looks good 
after these changes.  From the context I think it's safe and appropriate 
to call get_current_frame from finish_command_continuation (not sure if 
the frame chosen should ever matter for the calculation of any function's 
address -- perhaps for nested functions?), the other places already have 
a frame available.

> The rest looked good to me.

 Thanks for the review, here's the resulting update.  Any other comments, 
anyone?

  Maciej

gdb-mips16-calls-ret-val-func-fix.diff
Index: gdb-fsf-trunk-quilt/gdb/gdbarch.h
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/gdbarch.h	2012-04-27 21:31:50.085560611 +0100
+++ gdb-fsf-trunk-quilt/gdb/gdbarch.h	2012-04-27 19:50:02.965563474 +0100
@@ -433,8 +433,8 @@ typedef CORE_ADDR (gdbarch_integer_to_ad
 extern CORE_ADDR gdbarch_integer_to_address (struct gdbarch *gdbarch, struct type *type, const gdb_byte *buf);
 extern void set_gdbarch_integer_to_address (struct gdbarch *gdbarch, gdbarch_integer_to_address_ftype *integer_to_address);
 
-/* Return the return-value convention that will be used by FUNCTYPE
-   to return a value of type VALTYPE.  FUNCTYPE may be NULL in which
+/* Return the return-value convention that will be used by FUNCTION
+   to return a value of type VALTYPE.  FUNCTION may be NULL in which
    case the return convention is computed based only on VALTYPE.
   
    If READBUF is not NULL, extract the return value and save it in this buffer.
Index: gdb-fsf-trunk-quilt/gdb/gdbarch.sh
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/gdbarch.sh	2012-04-27 21:31:50.085560611 +0100
+++ gdb-fsf-trunk-quilt/gdb/gdbarch.sh	2012-04-27 19:42:02.335573553 +0100
@@ -503,8 +503,8 @@ m:CORE_ADDR:pointer_to_address:struct ty
 m:void:address_to_pointer:struct type *type, gdb_byte *buf, CORE_ADDR addr:type, buf, addr::unsigned_address_to_pointer::0
 M:CORE_ADDR:integer_to_address:struct type *type, const gdb_byte *buf:type, buf
 
-# Return the return-value convention that will be used by FUNCTYPE
-# to return a value of type VALTYPE.  FUNCTYPE may be NULL in which
+# Return the return-value convention that will be used by FUNCTION
+# to return a value of type VALTYPE.  FUNCTION may be NULL in which
 # case the return convention is computed based only on VALTYPE.
 #
 # If READBUF is not NULL, extract the return value and save it in this buffer.
@@ -513,7 +513,7 @@ M:CORE_ADDR:integer_to_address:struct ty
 # stored into the appropriate register.  This can be used when we want
 # to force the value returned by a function (see the "return" command
 # for instance).
-M:enum return_value_convention:return_value:struct value *function, struct type *valtype, struct regcache *regcache, gdb_byte *readbuf, const gdb_byte *writebuf:functype, valtype, regcache, readbuf, writebuf
+M:enum return_value_convention:return_value:struct value *function, struct type *valtype, struct regcache *regcache, gdb_byte *readbuf, const gdb_byte *writebuf:function, valtype, regcache, readbuf, writebuf
 
 m:CORE_ADDR:skip_prologue:CORE_ADDR ip:ip:0:0
 M:CORE_ADDR:skip_main_prologue:CORE_ADDR ip:ip
Index: gdb-fsf-trunk-quilt/gdb/infcmd.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/infcmd.c	2012-04-27 21:31:50.085560611 +0100
+++ gdb-fsf-trunk-quilt/gdb/infcmd.c	2012-04-27 20:08:31.935596617 +0100
@@ -1547,11 +1547,10 @@ finish_command_continuation (void *arg, 
 
 	  if (TYPE_CODE (value_type) != TYPE_CODE_VOID)
 	    {
-	      CORE_ADDR faddr = BLOCK_START (SYMBOL_BLOCK_VALUE (a->function));
-	      struct value *func = allocate_value (SYMBOL_TYPE (a->function));
 	      volatile struct gdb_exception ex;
+	      struct value *func;
 
-	      set_value_address (func, faddr);
+	      func = read_var_value (a->function, get_current_frame ());
 	      TRY_CATCH (ex, RETURN_MASK_ALL)
 		{
 		  /* print_return_value can throw an exception in some
Index: gdb-fsf-trunk-quilt/gdb/stack.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/stack.c	2012-04-27 21:31:50.155559621 +0100
+++ gdb-fsf-trunk-quilt/gdb/stack.c	2012-04-27 20:11:06.425607247 +0100
@@ -2284,11 +2284,7 @@ return_command (char *retval_exp, int fr
 	value_fetch_lazy (return_value);
 
       if (thisfun != NULL)
-	{
-	  function = allocate_value (SYMBOL_TYPE (thisfun));
-	  set_value_address (function,
-			     BLOCK_START (SYMBOL_BLOCK_VALUE (thisfun)));
-	}
+	function = read_var_value (thisfun, thisframe);
 
       if (TYPE_CODE (return_type) == TYPE_CODE_VOID)
 	/* If the return-type is "void", don't try to find the
Index: gdb-fsf-trunk-quilt/gdb/python/py-finishbreakpoint.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/python/py-finishbreakpoint.c	2012-04-27 21:31:50.195565239 +0100
+++ gdb-fsf-trunk-quilt/gdb/python/py-finishbreakpoint.c	2012-04-27 20:18:47.945561048 +0100
@@ -252,14 +252,11 @@ bpfinishpy_init (PyObject *self, PyObjec
               if (TYPE_CODE (ret_type) != TYPE_CODE_VOID)
                 {
                   struct value *func_value;
-                  CORE_ADDR func_addr;
 
                   /* Ignore Python errors at this stage.  */
                   self_bpfinish->return_type = type_to_type_object (ret_type);
                   PyErr_Clear ();
-                  func_value = allocate_value (SYMBOL_TYPE (function));
-                  func_addr = BLOCK_START (SYMBOL_BLOCK_VALUE (function));
-                  set_value_address (func_value, func_addr);
+                  func_value = read_var_value (function, frame);
                   self_bpfinish->function_value =
                       value_to_value_object (func_value);
                   PyErr_Clear ();


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFA] MIPS16 FP manual call/return fixes
  2012-04-30 23:45   ` Maciej W. Rozycki
@ 2012-05-01 14:05     ` Jan Kratochvil
  2012-05-01 17:22       ` Maciej W. Rozycki
  0 siblings, 1 reply; 15+ messages in thread
From: Jan Kratochvil @ 2012-05-01 14:05 UTC (permalink / raw)
  To: Maciej W. Rozycki; +Cc: Tom Tromey, gdb-patches

On Mon, 30 Apr 2012 23:42:44 +0200, Maciej W. Rozycki wrote:
> +  find_pc_partial_function_gnu_ifunc (b->loc->address, NULL,
> +                                     &func_func_addr, NULL, &is_gnu_ifunc);
> +  gdb_assert (is_gnu_ifunc);

Please remove that gdb_assert and fall back somehow, IMO just pass FUNCTION as
NULL in such case.  Any resolving ADDRESS->SYMBOL can be ambiguous with weird
symbol files and it may find some overlapping non-IFUNC symbol instead.
Also user may have unloaded symbol files in the middle of the debugging etc.

Otherwise OK from me for the IFUNC part.

FYI getting with your original patch:

bfin-tdep.c: In function 'bfin_gdbarch_init':
bfin-tdep.c:841:3: error: passing argument 2 of 'set_gdbarch_return_value' from incompatible pointer type [-Werror]
In file included from defs.h:945:0,
                 from bfin-tdep.c:22:
gdbarch.h:452:13: note: expected 'enum return_value_convention (*)(struct gdbarch *, struct value *, struct type *, struct regcache *, gdb_byte *, const gdb_byte *)' but argument is of type 'enum return_value_convention (*)(struct gdbarch *, struct type *, struct type *, struct regcache *, gdb_byte *, const gdb_byte *)'

So maybe your patch I used is already obsolete or be sure you run with
"--enable-64-bit-bfd --enable-targets=all".


Thanks,
Jan


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFA] MIPS16 FP manual call/return fixes
  2012-05-01 14:05     ` Jan Kratochvil
@ 2012-05-01 17:22       ` Maciej W. Rozycki
  2012-05-02 21:28         ` Jan Kratochvil
  0 siblings, 1 reply; 15+ messages in thread
From: Maciej W. Rozycki @ 2012-05-01 17:22 UTC (permalink / raw)
  To: Jan Kratochvil; +Cc: Tom Tromey, gdb-patches

On Tue, 1 May 2012, Jan Kratochvil wrote:

> > +  find_pc_partial_function_gnu_ifunc (b->loc->address, NULL,
> > +                                     &func_func_addr, NULL, &is_gnu_ifunc);
> > +  gdb_assert (is_gnu_ifunc);
> 
> Please remove that gdb_assert and fall back somehow, IMO just pass 
> FUNCTION as NULL in such case.

 It may not matter for most platforms, but if that ever happens for one of 
the MIPS ABIs affected, then this will fail an assertion in the backend 
instead.  It is invalid to call any of these backends with NULL FUNCTION 
and non-NULL READBUF both at a time, because the handler needs to retrieve 
the return value from the correct registers and it can only do that when 
it knows the address of the function called.

>  Any resolving ADDRESS->SYMBOL can be ambiguous with weird symbol files 
> and it may find some overlapping non-IFUNC symbol instead. Also user may 
> have unloaded symbol files in the middle of the debugging etc.

 OK, so let me put this another way.  Here we have just returned from a 
function that we called.  Obviously that function does exist somewhere no 
matter if symbol tables have been unloaded or whatever.  How can we 
determine the address of that function? -- in a different way, presumably.  
We must have somehow established its address previously or we couldn't 
have called it.  Is it possible to cache it somehow for example?

 Thanks for raising the issue of unloading symbol tables, that's an 
important point as to how MIPS16 and microMIPS symbols should be treated 
in general -- here I think it will only matter in the asynchronous mode. 
This is because in the synchronous if a function is called manually and it 
traps, then my observation is that any return value previously requested 
is ignored, the evaluation of any expression requested is abandoned and 
execution just stops when the function returns, without retrieving the 
return value.  And obviously there is no way for the user to unload a 
symbol table while the target is running in the synchronous mode.

> FYI getting with your original patch:
> 
> bfin-tdep.c: In function 'bfin_gdbarch_init':
> bfin-tdep.c:841:3: error: passing argument 2 of 'set_gdbarch_return_value' from incompatible pointer type [-Werror]
> In file included from defs.h:945:0,
>                  from bfin-tdep.c:22:
> gdbarch.h:452:13: note: expected 'enum return_value_convention (*)(struct gdbarch *, struct value *, struct type *, struct regcache *, gdb_byte *, const gdb_byte *)' but argument is of type 'enum return_value_convention (*)(struct gdbarch *, struct type *, struct type *, struct regcache *, gdb_byte *, const gdb_byte *)'
> 
> So maybe your patch I used is already obsolete or be sure you run with
> "--enable-64-bit-bfd --enable-targets=all".

 I thought I've caught all the newly-added targets, it looks like I missed 
this one.  Sorry about that, and thanks for taking time to check it.  And 
for the hint -- I'll check that all the targets at least build this way.

  Maciej


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFA] MIPS16 FP manual call/return fixes
  2012-05-01 17:22       ` Maciej W. Rozycki
@ 2012-05-02 21:28         ` Jan Kratochvil
  2012-05-08 14:30           ` Maciej W. Rozycki
  0 siblings, 1 reply; 15+ messages in thread
From: Jan Kratochvil @ 2012-05-02 21:28 UTC (permalink / raw)
  To: Maciej W. Rozycki; +Cc: Tom Tromey, gdb-patches

On Tue, 01 May 2012 19:21:20 +0200, Maciej W. Rozycki wrote:
>  OK, so let me put this another way.  Here we have just returned from a 
> function that we called.  Obviously that function does exist somewhere no 
> matter if symbol tables have been unloaded or whatever.  How can we 
> determine the address of that function?

We can no longer reliably do so.


> -- in a different way, presumably.  
> We must have somehow established its address previously or we couldn't 
> have called it.  Is it possible to cache it somehow for example?

Yes, we could.  In set_breakpoint_location_function is created
bp_gnu_ifunc_resolver, so cache it into 'struct bp_location' there (or even
into 'struct breakpoint', I do not see too much difference there)..

Then transfer this info when bp_gnu_ifunc_resolver_return is created from that
bp_gnu_ifunc_resolver.

I would be fine also with just some error there.


>  Thanks for raising the issue of unloading symbol tables, that's an 
> important point as to how MIPS16 and microMIPS symbols should be treated 
> in general -- here I think it will only matter in the asynchronous mode. 

No, even in synchronous mode.  If you still do "stepi", "stepi", "stepi"...
you will get something like:

(gdb) start
(gdb) b strcmp
Breakpoint 2 at gnu-indirect-function resolver at 0x7ffff7aaa3d0: file ../sysdeps/x86_64/multiarch/strcmp.S, line 87.
(gdb) b *strcmp
Note: breakpoint 2 also set at pc 0x7ffff7aaa3d0.
Breakpoint 3 at 0x7ffff7aaa3d0: file ../sysdeps/x86_64/multiarch/strcmp.S, line 87.
(gdb) c
Continuing.
warning: Breakpoint 2 address previously adjusted from 0x004003c6 to 0x7ffff7aaa3d0.
Breakpoint 2, strcmp () at ../sysdeps/x86_64/multiarch/strcmp.S:87
87		cmpl	$0, __cpu_features+KIND_OFFSET(%rip)
(gdb) maintenance info breakpoints 
Num     Type                          Disp Enb Address            What
[...]
2       STT_GNU_IFUNC resolver        keep y   0x00007ffff7aaa3d0 ../sysdeps/x86_64/multiarch/strcmp.S:87 inf 1
	breakpoint already hit 1 time
3       breakpoint                    keep y   0x00007ffff7aaa3d0 ../sysdeps/x86_64/multiarch/strcmp.S:87 inf 1
	breakpoint already hit 1 time
0       STT_GNU_IFUNC resolver return keep y   0x00007ffff7deb3be <_dl_fixup+446> inf 1 thread 1
	stop only in thread 1

So you can see anything can happen now before we hit that breakpoint #0.
I can for example unload the glibc symbol file by 'nosharedlibrary' (which has
led to unrelated PR 14054 now).


Thanks,
Jan


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFA] MIPS16 FP manual call/return fixes
  2012-05-02 21:28         ` Jan Kratochvil
@ 2012-05-08 14:30           ` Maciej W. Rozycki
  2012-05-12 19:38             ` Jan Kratochvil
  0 siblings, 1 reply; 15+ messages in thread
From: Maciej W. Rozycki @ 2012-05-08 14:30 UTC (permalink / raw)
  To: Jan Kratochvil; +Cc: Tom Tromey, gdb-patches

Jan,

> > We must have somehow established its address previously or we couldn't 
> > have called it.  Is it possible to cache it somehow for example?
> 
> Yes, we could.  In set_breakpoint_location_function is created
> bp_gnu_ifunc_resolver, so cache it into 'struct bp_location' there (or even
> into 'struct breakpoint', I do not see too much difference there)..

 Well, it's associated with a specific location really, so...

> Then transfer this info when bp_gnu_ifunc_resolver_return is created from that
> bp_gnu_ifunc_resolver.

 Given that we rely on having a reference to bp_gnu_ifunc_resolver from 
bp_gnu_ifunc_resolver_return I've decided that we don't really have to 
transfer anything here.

> I would be fine also with just some error there.

 I'm not sure what you mean, we do need to return something here.

> >  Thanks for raising the issue of unloading symbol tables, that's an 
> > important point as to how MIPS16 and microMIPS symbols should be treated 
> > in general -- here I think it will only matter in the asynchronous mode. 
> 
> No, even in synchronous mode.  If you still do "stepi", "stepi", "stepi"...
> you will get something like:
> 
> (gdb) start
> (gdb) b strcmp
> Breakpoint 2 at gnu-indirect-function resolver at 0x7ffff7aaa3d0: file ../sysdeps/x86_64/multiarch/strcmp.S, line 87.
> (gdb) b *strcmp
> Note: breakpoint 2 also set at pc 0x7ffff7aaa3d0.
> Breakpoint 3 at 0x7ffff7aaa3d0: file ../sysdeps/x86_64/multiarch/strcmp.S, line 87.
> (gdb) c
> Continuing.
> warning: Breakpoint 2 address previously adjusted from 0x004003c6 to 0x7ffff7aaa3d0.
> Breakpoint 2, strcmp () at ../sysdeps/x86_64/multiarch/strcmp.S:87
> 87		cmpl	$0, __cpu_features+KIND_OFFSET(%rip)
> (gdb) maintenance info breakpoints 
> Num     Type                          Disp Enb Address            What
> [...]
> 2       STT_GNU_IFUNC resolver        keep y   0x00007ffff7aaa3d0 ../sysdeps/x86_64/multiarch/strcmp.S:87 inf 1
> 	breakpoint already hit 1 time
> 3       breakpoint                    keep y   0x00007ffff7aaa3d0 ../sysdeps/x86_64/multiarch/strcmp.S:87 inf 1
> 	breakpoint already hit 1 time
> 0       STT_GNU_IFUNC resolver return keep y   0x00007ffff7deb3be <_dl_fixup+446> inf 1 thread 1
> 	stop only in thread 1
> 
> So you can see anything can happen now before we hit that breakpoint #0.
> I can for example unload the glibc symbol file by 'nosharedlibrary' (which has
> led to unrelated PR 14054 now).

 Good point, it's turned out I was confused what the use case of this code 
exactly is.

 So here's the new proposal, comprising only the relevant bits (I keep it 
all with the rest of the patch really, but decided not to clutter the list 
with), it doesn't cause any regressions compared to the original.

 I have decided to add a related_address field to bp_location; this could 
get converted to an opaque member in the future in case some other 
breakpoints need to carry other auxiliary information (just as we do with 
some other structures).  It's set to the address of the resolver as 
set_breakpoint_location_function sets up a bp_gnu_ifunc_resolver 
breakpoint; conveniently it already looks up the function, just did not 
request its address before.

 I have decided to keep the assertion you had concerns about after all.  
The reason is as set_breakpoint_location_function will never create a 
bp_gnu_ifunc_resolver breakpoint with more than one location assigned 
anyway, see the condition enclosing:

 	      b->type = bp_gnu_ifunc_resolver;

-- it already requires loc->next to be NULL or it doesn't select this 
special breakpoint type at all (the intent to avoid such breakpoints is 
commented on too; the comment even qualified for context of the patch 
below, so you can just read it here).  Is it ever possible for this 
breakpoint to be updated later on with additional locations?  What would 
the conditions be if so? -- I'd like to be able to reproduce them in the 
lab then.

 I have tested this change with the mips-sde-elf target observing no 
regressions compared to the previous proposal.  I did some manual checks 
running GDB under GDB to see the expected flow of changes is correct here, 
using the test program used by gdb.base/gnu-ifunc.exp; this was with the 
x86_64-linux-gnu target.  It worked exactly as expected.

 OK for this update?  I believe this is the last part of the whole change 
there are unresolved concerns about.

2012-05-08  Maciej W. Rozycki  <macro@codesourcery.com>

	gdb/
	* breakpoint.h (bp_location): Add related_address member.
	* breakpoint.c (set_breakpoint_location_function): Initialize it 
	for bp_gnu_ifunc_resolver breakpoints.
	* elfread.c (elf_gnu_ifunc_resolver_return_stop): Pass the
	requested function's address to gdbarch_return_value.

  Maciej

gdb-mips16-calls-ifunc-new.diff
Index: gdb-fsf-trunk-quilt/gdb/elfread.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/elfread.c	2012-05-08 08:25:37.795639727 +0100
+++ gdb-fsf-trunk-quilt/gdb/elfread.c	2012-05-08 09:42:32.075560588 +0100
@@ -1020,21 +1020,15 @@ elf_gnu_ifunc_resolver_return_stop (stru
   struct type *func_func_type = builtin_type (gdbarch)->builtin_func_func;
   struct type *value_type = TYPE_TARGET_TYPE (func_func_type);
   struct regcache *regcache = get_thread_regcache (inferior_ptid);
+  struct value *func_func;
   struct value *value;
   CORE_ADDR resolved_address, resolved_pc;
   struct symtab_and_line sal;
   struct symtabs_and_lines sals, sals_end;
+  CORE_ADDR func_func_addr;
 
   gdb_assert (b->type == bp_gnu_ifunc_resolver_return);
 
-  value = allocate_value (value_type);
-  gdbarch_return_value (gdbarch, func_func_type, value_type, regcache,
-			value_contents_raw (value), NULL);
-  resolved_address = value_as_address (value);
-  resolved_pc = gdbarch_convert_from_func_ptr_addr (gdbarch,
-						    resolved_address,
-						    &current_target);
-
   while (b->related_breakpoint != b)
     {
       struct breakpoint *b_next = b->related_breakpoint;
@@ -1055,6 +1049,18 @@ elf_gnu_ifunc_resolver_return_stop (stru
       b = b_next;
     }
   gdb_assert (b->type == bp_gnu_ifunc_resolver);
+  gdb_assert (b->loc->next == NULL);
+
+  func_func = allocate_value (func_func_type);
+  set_value_address (func_func, b->loc->related_address);
+
+  value = allocate_value (value_type);
+  gdbarch_return_value (gdbarch, func_func, value_type, regcache,
+			value_contents_raw (value), NULL);
+  resolved_address = value_as_address (value);
+  resolved_pc = gdbarch_convert_from_func_ptr_addr (gdbarch,
+						    resolved_address,
+						    &current_target);
 
   gdb_assert (current_program_space == b->pspace || b->pspace == NULL);
   elf_gnu_ifunc_record_cache (b->addr_string, resolved_pc);
Index: gdb-fsf-trunk-quilt/gdb/breakpoint.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/breakpoint.c	2012-05-04 19:26:24.845606346 +0100
+++ gdb-fsf-trunk-quilt/gdb/breakpoint.c	2012-05-08 08:26:49.855603092 +0100
@@ -6586,9 +6586,10 @@ set_breakpoint_location_function (struct
     {
       int is_gnu_ifunc;
       const char *function_name;
+      CORE_ADDR func_addr;
 
       find_pc_partial_function_gnu_ifunc (loc->address, &function_name,
-					  NULL, NULL, &is_gnu_ifunc);
+					  &func_addr, NULL, &is_gnu_ifunc);
 
       if (is_gnu_ifunc && !explicit_loc)
 	{
@@ -6609,6 +6610,9 @@ set_breakpoint_location_function (struct
 	      /* Create only the whole new breakpoint of this type but do not
 		 mess more complicated breakpoints with multiple locations.  */
 	      b->type = bp_gnu_ifunc_resolver;
+	      /* Remember the resolver's address for use by the return
+	         breakpoint.  */
+	      loc->related_address = func_addr;
 	    }
 	}
 
Index: gdb-fsf-trunk-quilt/gdb/breakpoint.h
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/breakpoint.h	2012-05-04 19:26:24.845606346 +0100
+++ gdb-fsf-trunk-quilt/gdb/breakpoint.h	2012-05-08 08:26:49.875618479 +0100
@@ -418,6 +418,11 @@ struct bp_location
      processor's architectual constraints.  */
   CORE_ADDR requested_address;
 
+  /* An additional address assigned with this location.  This is currently
+     only used by STT_GNU_IFUNC resolver breakpoints to hold the address
+     of the resolver function.  */
+  CORE_ADDR related_address;
+
   /* If the location comes from a probe point, this is the probe associated
      with it.  */
   struct probe *probe;


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFA] MIPS16 FP manual call/return fixes
  2012-05-08 14:30           ` Maciej W. Rozycki
@ 2012-05-12 19:38             ` Jan Kratochvil
  2012-05-14  9:12               ` Maciej W. Rozycki
  0 siblings, 1 reply; 15+ messages in thread
From: Jan Kratochvil @ 2012-05-12 19:38 UTC (permalink / raw)
  To: Maciej W. Rozycki; +Cc: Tom Tromey, gdb-patches

On Tue, 08 May 2012 16:29:44 +0200, Maciej W. Rozycki wrote:
>  I have decided to add a related_address field to bp_location; this could 
> get converted to an opaque member in the future in case some other 
> breakpoints need to carry other auxiliary information

[ Mostly unrelated to this patch:  ]

This should be C++ inherited class field; or in C it should be
bp_location-type driven union.

While I would find it cleaner with the union I do not request this as
mandatory for check-in, it could also start some new GDB coding style
discussions.


> (just as we do with some other structures).

[ Mostly unrelated to this patch:  ]

Unfortunately we do but we do not / no longer have to.


>  I have decided to keep the assertion you had concerns about after all.  

I meant that 'gdb_assert (is_gnu_ifunc);', that is gone now.


>  	      b->type = bp_gnu_ifunc_resolver;
[...]
> Is it ever possible for this breakpoint to be updated later on with
> additional locations?

I am not aware of.


> --- gdb-fsf-trunk-quilt.orig/gdb/elfread.c	2012-05-08 08:25:37.795639727 +0100
> +++ gdb-fsf-trunk-quilt/gdb/elfread.c	2012-05-08 09:42:32.075560588 +0100
> @@ -1020,21 +1020,15 @@ elf_gnu_ifunc_resolver_return_stop (stru
[...]
> +  CORE_ADDR func_func_addr;

This variable is unused now.


[...]
> --- gdb-fsf-trunk-quilt.orig/gdb/breakpoint.c	2012-05-04 19:26:24.845606346 +0100
> +++ gdb-fsf-trunk-quilt/gdb/breakpoint.c	2012-05-08 08:26:49.855603092 +0100
[...]
> @@ -6609,6 +6610,9 @@ set_breakpoint_location_function (struct
>  	      /* Create only the whole new breakpoint of this type but do not
>  		 mess more complicated breakpoints with multiple locations.  */
>  	      b->type = bp_gnu_ifunc_resolver;

Empty line before a comment according to GDB Coding Standards.

> +	      /* Remember the resolver's address for use by the return
> +	         breakpoint.  */
> +	      loc->related_address = func_addr;
>  	    }
>  	}
>  
[...]


OK for the IFUNC part from me.


Thanks,
Jan


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFA] MIPS16 FP manual call/return fixes
  2012-05-12 19:38             ` Jan Kratochvil
@ 2012-05-14  9:12               ` Maciej W. Rozycki
  2012-05-14 11:54                 ` Jan Kratochvil
  0 siblings, 1 reply; 15+ messages in thread
From: Maciej W. Rozycki @ 2012-05-14  9:12 UTC (permalink / raw)
  To: Jan Kratochvil; +Cc: Tom Tromey, gdb-patches

Jan,

> >  I have decided to add a related_address field to bp_location; this could 
> > get converted to an opaque member in the future in case some other 
> > breakpoints need to carry other auxiliary information
> 
> [ Mostly unrelated to this patch:  ]
> 
> This should be C++ inherited class field; or in C it should be
> bp_location-type driven union.
> 
> While I would find it cleaner with the union I do not request this as
> mandatory for check-in, it could also start some new GDB coding style
> discussions.

 Since we're not switching to C++ anytime soon this would normally be 
either a union or a pointer to an additional dynamically allocated 
structure or a combination of the two.  This is mostly about memory space 
conservation anyway; strictly speaking we can keep the structure flat if 
we decide that complicating it is not worth the saving.

> >  I have decided to keep the assertion you had concerns about after all.  
> 
> I meant that 'gdb_assert (is_gnu_ifunc);', that is gone now.
> 
> 
> >  	      b->type = bp_gnu_ifunc_resolver;
> [...]
> > Is it ever possible for this breakpoint to be updated later on with
> > additional locations?
> 
> I am not aware of.

 OK, I see.  I'm glad we agree.

> > --- gdb-fsf-trunk-quilt.orig/gdb/elfread.c	2012-05-08 08:25:37.795639727 +0100
> > +++ gdb-fsf-trunk-quilt/gdb/elfread.c	2012-05-08 09:42:32.075560588 +0100
> > @@ -1020,21 +1020,15 @@ elf_gnu_ifunc_resolver_return_stop (stru
> [...]
> > +  CORE_ADDR func_func_addr;
> 
> This variable is unused now.

 Thanks, removed.

 Actually, I relied on the lack of compilation errors so far; it seems 
that while we do have -Wall -Werror, we have -Wno-unused as well which 
implies -Wno-unused-variable and has defeated my assumptions.  Any 
particular reason why we disable this warning?  Perhaps this should be per 
file if problematic somewhere.  We have likely grown a number of unused 
variables already and will grow more if this stays disabled.

> > --- gdb-fsf-trunk-quilt.orig/gdb/breakpoint.c	2012-05-04 19:26:24.845606346 +0100
> > +++ gdb-fsf-trunk-quilt/gdb/breakpoint.c	2012-05-08 08:26:49.855603092 +0100
> [...]
> > @@ -6609,6 +6610,9 @@ set_breakpoint_location_function (struct
> >  	      /* Create only the whole new breakpoint of this type but do not
> >  		 mess more complicated breakpoints with multiple locations.  */
> >  	      b->type = bp_gnu_ifunc_resolver;
> 
> Empty line before a comment according to GDB Coding Standards.
> 
> > +	      /* Remember the resolver's address for use by the return
> > +	         breakpoint.  */
> > +	      loc->related_address = func_addr;
> >  	    }
> >  	}
> >  
> [...]

 I believe this requirement applies to function and variable/type/etc. 
definitions only and I haven't seen this style applied inline in many 
places (including the original comment above, actually).  Are you sure?

> OK for the IFUNC part from me.

 Thanks for your review.  This is the final version I'll be committing 
shortly unless I hear any objections.

  Maciej

2012-05-14  Maciej W. Rozycki  <macro@codesourcery.com>
            Maciej W. Rozycki  <macro@mips.com>

	gdb/
        * breakpoint.h (bp_location): Add related_address member.
	* inferior.h (get_return_value): Take a pointer to struct value
	instead of struct type for the function requested.
	* value.h (using_struct_return): Likewise.
	* gdbarch.sh (return_value): Take a pointer to struct value
	instead of struct type for the function requested.
        * breakpoint.c (set_breakpoint_location_function): Initialize
        related_address for bp_gnu_ifunc_resolver breakpoints.
	* elfread.c (elf_gnu_ifunc_resolver_return_stop): Pass the
	requested function's address to gdbarch_return_value.
	* eval.c (evaluate_subexp_standard): Pass the requested
	function's address to using_struct_return.
	* infcall.c (call_function_by_hand): Pass the requested
	function's address to using_struct_return and
	gdbarch_return_value.
	* infcmd.c (get_return_value): Take a pointer to struct value
	instead of struct type for the function requested.
	(print_return_value): Update accordingly.
	(finish_command_continuation): Likewise.
	* stack.c (return_command): Pass the requested function's
	address to using_struct_return and gdbarch_return_value.
	* value.c (using_struct_return): Take a pointer to struct value
	instead of struct type for the function requested.  Pass the
	requested function's address to gdbarch_return_value.
	* python/py-finishbreakpoint.c (finish_breakpoint_object):
	New function_value member, replacing function_type.
	(bpfinishpy_dealloc): Update accordingly.
	(bpfinishpy_pre_stop_hook): Likewise.
	(bpfinishpy_init): Likewise.  Record the requested function's
	address.
	* mips-tdep.c (mips_fval_reg): New enum.
	(mips_o32_push_dummy_call): For MIPS16 FP doubles do not swap
	words put in GP registers.
	(mips_o64_push_dummy_call): Update a comment.
	(mips_o32_return_value): Take a pointer to struct value instead
	of struct type for the function requested and use it to check if
	using the MIPS16 calling convention.  Return the designated
	general purpose registers for floating-point values returned in
	MIPS16 mode.
	(mips_o64_return_value): Likewise.
	* ppc-tdep.h (ppc_sysv_abi_return_value): Update prototype.
	(ppc_sysv_abi_broken_return_value): Likewise.
	(ppc64_sysv_abi_return_value): Likewise.
	* alpha-tdep.c (alpha_return_value): Take a pointer to struct
	value instead of struct type for the function requested.
	* amd64-tdep.c (amd64_return_value): Likewise.
	* amd64-windows-tdep.c (amd64_windows_return_value): Likewise.
	* arm-tdep.c (arm_return_value): Likewise.
	* avr-tdep.c (avr_return_value): Likewise.
	* bfin-tdep.c (bfin_return_value): Likewise.
	* cris-tdep.c (cris_return_value): Likewise.
	* frv-tdep.c (frv_return_value): Likewise.
	* h8300-tdep.c (h8300_return_value): Likewise.
	(h8300h_return_value): Likewise.
	* hppa-tdep.c (hppa32_return_value): Likewise.
	(hppa64_return_value): Likewise.
	* i386-tdep.c (i386_return_value): Likewise.
	* ia64-tdep.c (ia64_return_value): Likewise.
	* iq2000-tdep.c (iq2000_return_value): Likewise.
	* lm32-tdep.c (lm32_return_value): Likewise.
	* m32c-tdep.c (m32c_return_value): Likewise.
	* m32r-tdep.c (m32r_return_value): Likewise.
	* m68hc11-tdep.c (m68hc11_return_value): Likewise.
	* m68k-tdep.c (m68k_return_value): Likewise.
	(m68k_svr4_return_value): Likewise.
	* m88k-tdep.c (m88k_return_value): Likewise.
	* mep-tdep.c (mep_return_value): Likewise.
	* microblaze-tdep.c (microblaze_return_value): Likewise.
	* mn10300-tdep.c (mn10300_return_value): Likewise.
	* moxie-tdep.c (moxie_return_value): Likewise.
	* mt-tdep.c (mt_return_value): Likewise.
	* ppc-linux-tdep.c (ppc_linux_return_value): Likewise.
	* ppc-sysv-tdep.c (ppc_sysv_abi_return_value): Likewise.
	(ppc_sysv_abi_broken_return_value): Likewise.
	(ppc64_sysv_abi_return_value): Likewise.
	* ppcnbsd-tdep.c (ppcnbsd_return_value): Likewise.
	* rl78-tdep.c (rl78_return_value): Likewise.
	* rs6000-aix-tdep.c (rs6000_return_value): Likewise.
	* rx-tdep.c (rx_return_value): Likewise.
	* s390-tdep.c (s390_return_value): Likewise.
	* score-tdep.c (score_return_value): Likewise.
	* sh-tdep.c (sh_return_value_nofpu): Likewise.
	(sh_return_value_fpu): Likewise.
	* sh64-tdep.c (sh64_return_value): Likewise.
	* sparc-tdep.c (sparc32_return_value): Likewise.
	* sparc64-tdep.c (sparc64_return_value): Likewise.
	* spu-tdep.c (spu_return_value): Likewise.
	* tic6x-tdep.c (tic6x_return_value): Likewise.
	* v850-tdep.c (v850_return_value): Likewise.
	* vax-tdep.c (vax_return_value): Likewise.
	* xstormy16-tdep.c (xstormy16_return_value): Likewise.
	* xtensa-tdep.c (xtensa_return_value): Likewise.
	* gdbarch.c: Regenerate.
	* gdbarch.h: Regenerate.

2012-04-23  Maciej W. Rozycki  <macro@codesourcery.com>

	gdb/testsuite/
	* gdb.base/return-nodebug.exp: Also test float and double types.

gdb-mips16-calls.diff
Index: gdb-fsf-trunk-quilt/gdb/alpha-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/alpha-tdep.c	2012-05-12 16:35:27.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/alpha-tdep.c	2012-05-12 20:47:29.735638412 +0100
@@ -612,7 +612,7 @@ alpha_store_return_value (struct type *v
 }
 
 static enum return_value_convention
-alpha_return_value (struct gdbarch *gdbarch, struct type *func_type,
+alpha_return_value (struct gdbarch *gdbarch, struct value *function,
 		    struct type *type, struct regcache *regcache,
 		    gdb_byte *readbuf, const gdb_byte *writebuf)
 {
Index: gdb-fsf-trunk-quilt/gdb/amd64-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/amd64-tdep.c	2012-05-12 16:35:27.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/amd64-tdep.c	2012-05-12 20:47:29.735638412 +0100
@@ -592,7 +592,7 @@ amd64_classify (struct type *type, enum 
 }
 
 static enum return_value_convention
-amd64_return_value (struct gdbarch *gdbarch, struct type *func_type,
+amd64_return_value (struct gdbarch *gdbarch, struct value *function,
 		    struct type *type, struct regcache *regcache,
 		    gdb_byte *readbuf, const gdb_byte *writebuf)
 {
Index: gdb-fsf-trunk-quilt/gdb/arm-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/arm-tdep.c	2012-05-12 16:35:27.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/arm-tdep.c	2012-05-12 20:47:29.735638412 +0100
@@ -9011,11 +9011,12 @@ arm_store_return_value (struct type *typ
 /* Handle function return values.  */
 
 static enum return_value_convention
-arm_return_value (struct gdbarch *gdbarch, struct type *func_type,
+arm_return_value (struct gdbarch *gdbarch, struct value *function,
 		  struct type *valtype, struct regcache *regcache,
 		  gdb_byte *readbuf, const gdb_byte *writebuf)
 {
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  struct type *func_type = function ? value_type (function) : NULL;
   enum arm_vfp_cprc_base_type vfp_base_type;
   int vfp_base_count;
 
Index: gdb-fsf-trunk-quilt/gdb/cris-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/cris-tdep.c	2012-05-12 16:35:27.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/cris-tdep.c	2012-05-12 20:47:29.735638412 +0100
@@ -1863,7 +1863,7 @@ cris_extract_return_value (struct type *
 /* Handle the CRIS return value convention.  */
 
 static enum return_value_convention
-cris_return_value (struct gdbarch *gdbarch, struct type *func_type,
+cris_return_value (struct gdbarch *gdbarch, struct value *function,
 		   struct type *type, struct regcache *regcache,
 		   gdb_byte *readbuf, const gdb_byte *writebuf)
 {
Index: gdb-fsf-trunk-quilt/gdb/eval.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/eval.c	2012-05-12 16:35:27.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/eval.c	2012-05-12 20:47:29.745623748 +0100
@@ -1358,8 +1358,7 @@ evaluate_subexp_standard (struct type *e
 		  val_type = expect_type;
 	      }
 
-	    struct_return = using_struct_return (exp->gdbarch,
-						 value_type (method),
+	    struct_return = using_struct_return (exp->gdbarch, method,
 						 val_type);
 	  }
 	else if (expect_type != NULL)
Index: gdb-fsf-trunk-quilt/gdb/frv-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/frv-tdep.c	2012-05-12 16:35:27.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/frv-tdep.c	2012-05-12 20:47:29.745623748 +0100
@@ -1351,7 +1351,7 @@ frv_store_return_value (struct type *typ
 }
 
 static enum return_value_convention
-frv_return_value (struct gdbarch *gdbarch, struct type *func_type,
+frv_return_value (struct gdbarch *gdbarch, struct value *function,
 		  struct type *valtype, struct regcache *regcache,
 		  gdb_byte *readbuf, const gdb_byte *writebuf)
 {
Index: gdb-fsf-trunk-quilt/gdb/gdbarch.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/gdbarch.c	2012-05-12 16:35:27.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/gdbarch.c	2012-05-12 20:47:29.745623748 +0100
@@ -2536,13 +2536,13 @@ gdbarch_return_value_p (struct gdbarch *
 }
 
 enum return_value_convention
-gdbarch_return_value (struct gdbarch *gdbarch, struct type *functype, struct type *valtype, struct regcache *regcache, gdb_byte *readbuf, const gdb_byte *writebuf)
+gdbarch_return_value (struct gdbarch *gdbarch, struct value *function, struct type *valtype, struct regcache *regcache, gdb_byte *readbuf, const gdb_byte *writebuf)
 {
   gdb_assert (gdbarch != NULL);
   gdb_assert (gdbarch->return_value != NULL);
   if (gdbarch_debug >= 2)
     fprintf_unfiltered (gdb_stdlog, "gdbarch_return_value called\n");
-  return gdbarch->return_value (gdbarch, functype, valtype, regcache, readbuf, writebuf);
+  return gdbarch->return_value (gdbarch, function, valtype, regcache, readbuf, writebuf);
 }
 
 void
Index: gdb-fsf-trunk-quilt/gdb/gdbarch.h
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/gdbarch.h	2012-05-12 16:35:27.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/gdbarch.h	2012-05-12 20:47:29.745623748 +0100
@@ -434,8 +434,8 @@ typedef CORE_ADDR (gdbarch_integer_to_ad
 extern CORE_ADDR gdbarch_integer_to_address (struct gdbarch *gdbarch, struct type *type, const gdb_byte *buf);
 extern void set_gdbarch_integer_to_address (struct gdbarch *gdbarch, gdbarch_integer_to_address_ftype *integer_to_address);
 
-/* Return the return-value convention that will be used by FUNCTYPE
-   to return a value of type VALTYPE.  FUNCTYPE may be NULL in which
+/* Return the return-value convention that will be used by FUNCTION
+   to return a value of type VALTYPE.  FUNCTION may be NULL in which
    case the return convention is computed based only on VALTYPE.
   
    If READBUF is not NULL, extract the return value and save it in this buffer.
@@ -447,8 +447,8 @@ extern void set_gdbarch_integer_to_addre
 
 extern int gdbarch_return_value_p (struct gdbarch *gdbarch);
 
-typedef enum return_value_convention (gdbarch_return_value_ftype) (struct gdbarch *gdbarch, struct type *functype, struct type *valtype, struct regcache *regcache, gdb_byte *readbuf, const gdb_byte *writebuf);
-extern enum return_value_convention gdbarch_return_value (struct gdbarch *gdbarch, struct type *functype, struct type *valtype, struct regcache *regcache, gdb_byte *readbuf, const gdb_byte *writebuf);
+typedef enum return_value_convention (gdbarch_return_value_ftype) (struct gdbarch *gdbarch, struct value *function, struct type *valtype, struct regcache *regcache, gdb_byte *readbuf, const gdb_byte *writebuf);
+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);
 
 typedef CORE_ADDR (gdbarch_skip_prologue_ftype) (struct gdbarch *gdbarch, CORE_ADDR ip);
Index: gdb-fsf-trunk-quilt/gdb/gdbarch.sh
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/gdbarch.sh	2012-05-12 16:35:27.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/gdbarch.sh	2012-05-12 20:47:29.745623748 +0100
@@ -503,8 +503,8 @@ m:CORE_ADDR:pointer_to_address:struct ty
 m:void:address_to_pointer:struct type *type, gdb_byte *buf, CORE_ADDR addr:type, buf, addr::unsigned_address_to_pointer::0
 M:CORE_ADDR:integer_to_address:struct type *type, const gdb_byte *buf:type, buf
 
-# Return the return-value convention that will be used by FUNCTYPE
-# to return a value of type VALTYPE.  FUNCTYPE may be NULL in which
+# Return the return-value convention that will be used by FUNCTION
+# to return a value of type VALTYPE.  FUNCTION may be NULL in which
 # case the return convention is computed based only on VALTYPE.
 #
 # If READBUF is not NULL, extract the return value and save it in this buffer.
@@ -513,7 +513,7 @@ M:CORE_ADDR:integer_to_address:struct ty
 # stored into the appropriate register.  This can be used when we want
 # to force the value returned by a function (see the "return" command
 # for instance).
-M:enum return_value_convention:return_value:struct type *functype, struct type *valtype, struct regcache *regcache, gdb_byte *readbuf, const gdb_byte *writebuf:functype, valtype, regcache, readbuf, writebuf
+M:enum return_value_convention:return_value:struct value *function, struct type *valtype, struct regcache *regcache, gdb_byte *readbuf, const gdb_byte *writebuf:function, valtype, regcache, readbuf, writebuf
 
 m:CORE_ADDR:skip_prologue:CORE_ADDR ip:ip:0:0
 M:CORE_ADDR:skip_main_prologue:CORE_ADDR ip:ip
Index: gdb-fsf-trunk-quilt/gdb/h8300-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/h8300-tdep.c	2012-05-12 16:35:27.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/h8300-tdep.c	2012-05-12 20:47:29.745623748 +0100
@@ -901,7 +901,7 @@ h8300h_store_return_value (struct type *
 }
 
 static enum return_value_convention
-h8300_return_value (struct gdbarch *gdbarch, struct type *func_type,
+h8300_return_value (struct gdbarch *gdbarch, struct value *function,
 		    struct type *type, struct regcache *regcache,
 		    gdb_byte *readbuf, const gdb_byte *writebuf)
 {
@@ -915,7 +915,7 @@ h8300_return_value (struct gdbarch *gdba
 }
 
 static enum return_value_convention
-h8300h_return_value (struct gdbarch *gdbarch, struct type *func_type,
+h8300h_return_value (struct gdbarch *gdbarch, struct value *function,
 		     struct type *type, struct regcache *regcache,
 		     gdb_byte *readbuf, const gdb_byte *writebuf)
 {
Index: gdb-fsf-trunk-quilt/gdb/hppa-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/hppa-tdep.c	2012-05-12 16:35:27.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/hppa-tdep.c	2012-05-12 20:47:29.745623748 +0100
@@ -1114,7 +1114,7 @@ hppa64_push_dummy_call (struct gdbarch *
 /* Handle 32/64-bit struct return conventions.  */
 
 static enum return_value_convention
-hppa32_return_value (struct gdbarch *gdbarch, struct type *func_type,
+hppa32_return_value (struct gdbarch *gdbarch, struct value *function,
 		     struct type *type, struct regcache *regcache,
 		     gdb_byte *readbuf, const gdb_byte *writebuf)
 {
@@ -1154,7 +1154,7 @@ hppa32_return_value (struct gdbarch *gdb
 }
 
 static enum return_value_convention
-hppa64_return_value (struct gdbarch *gdbarch, struct type *func_type,
+hppa64_return_value (struct gdbarch *gdbarch, struct value *function,
 		     struct type *type, struct regcache *regcache,
 		     gdb_byte *readbuf, const gdb_byte *writebuf)
 {
Index: gdb-fsf-trunk-quilt/gdb/i386-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/i386-tdep.c	2012-05-12 20:47:21.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/i386-tdep.c	2012-05-12 20:47:29.745623748 +0100
@@ -2605,7 +2605,7 @@ i386_reg_struct_return_p (struct gdbarch
    from WRITEBUF into REGCACHE.  */
 
 static enum return_value_convention
-i386_return_value (struct gdbarch *gdbarch, struct type *func_type,
+i386_return_value (struct gdbarch *gdbarch, struct value *function,
 		   struct type *type, struct regcache *regcache,
 		   gdb_byte *readbuf, const gdb_byte *writebuf)
 {
@@ -2656,7 +2656,7 @@ i386_return_value (struct gdbarch *gdbar
   if (code == TYPE_CODE_STRUCT && TYPE_NFIELDS (type) == 1)
     {
       type = check_typedef (TYPE_FIELD_TYPE (type, 0));
-      return i386_return_value (gdbarch, func_type, type, regcache,
+      return i386_return_value (gdbarch, function, type, regcache,
 				readbuf, writebuf);
     }
 
Index: gdb-fsf-trunk-quilt/gdb/ia64-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/ia64-tdep.c	2012-05-12 16:35:27.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/ia64-tdep.c	2012-05-12 20:47:29.755650929 +0100
@@ -3340,7 +3340,7 @@ ia64_store_return_value (struct type *ty
 }
   
 static enum return_value_convention
-ia64_return_value (struct gdbarch *gdbarch, struct type *func_type,
+ia64_return_value (struct gdbarch *gdbarch, struct value *function,
 		   struct type *valtype, struct regcache *regcache,
 		   gdb_byte *readbuf, const gdb_byte *writebuf)
 {
Index: gdb-fsf-trunk-quilt/gdb/infcall.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/infcall.c	2012-05-12 20:47:15.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/infcall.c	2012-05-12 20:47:29.755650929 +0100
@@ -608,8 +608,7 @@ call_function_by_hand (struct value *fun
     }
   else
     {
-      struct_return = using_struct_return (gdbarch,
-					   value_type (function), values_type);
+      struct_return = using_struct_return (gdbarch, function, values_type);
       target_values_type = values_type;
     }
 
@@ -1021,13 +1020,13 @@ When the function is done executing, GDB
       {
 	/* If the function returns void, don't bother fetching the
 	   return value.  */
-	switch (gdbarch_return_value (gdbarch, value_type (function),
-				      target_values_type, NULL, NULL, NULL))
+	switch (gdbarch_return_value (gdbarch, function, target_values_type,
+				      NULL, NULL, NULL))
 	  {
 	  case RETURN_VALUE_REGISTER_CONVENTION:
 	  case RETURN_VALUE_ABI_RETURNS_ADDRESS:
 	  case RETURN_VALUE_ABI_PRESERVES_ADDRESS:
-	    gdbarch_return_value (gdbarch, value_type (function), values_type,
+	    gdbarch_return_value (gdbarch, function, values_type,
 				  retbuf, value_contents_raw (retval), NULL);
 	    break;
 	  case RETURN_VALUE_STRUCT_CONVENTION:
Index: gdb-fsf-trunk-quilt/gdb/infcmd.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/infcmd.c	2012-05-12 16:35:27.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/infcmd.c	2012-05-12 20:47:29.755650929 +0100
@@ -75,7 +75,7 @@ void interrupt_target_command (char *arg
 
 static void nofp_registers_info (char *, int);
 
-static void print_return_value (struct type *func_type,
+static void print_return_value (struct value *function,
 				struct type *value_type);
 
 static void until_next_command (int);
@@ -1416,7 +1416,7 @@ advance_command (char *arg, int from_tty
    command/BP.  */
 
 struct value *
-get_return_value (struct type *func_type, struct type *value_type)
+get_return_value (struct value *function, struct type *value_type)
 {
   struct regcache *stop_regs = stop_registers;
   struct gdbarch *gdbarch;
@@ -1443,14 +1443,14 @@ get_return_value (struct type *func_type
      inferior function call code.  In fact, when inferior function
      calls are made async, this will likely be made the norm.  */
 
-  switch (gdbarch_return_value (gdbarch, func_type, value_type,
+  switch (gdbarch_return_value (gdbarch, function, value_type,
   				NULL, NULL, NULL))
     {
     case RETURN_VALUE_REGISTER_CONVENTION:
     case RETURN_VALUE_ABI_RETURNS_ADDRESS:
     case RETURN_VALUE_ABI_PRESERVES_ADDRESS:
       value = allocate_value (value_type);
-      gdbarch_return_value (gdbarch, func_type, value_type, stop_regs,
+      gdbarch_return_value (gdbarch, function, value_type, stop_regs,
 			    value_contents_raw (value), NULL);
       break;
     case RETURN_VALUE_STRUCT_CONVENTION:
@@ -1468,9 +1468,9 @@ get_return_value (struct type *func_type
 /* Print the result of a function at the end of a 'finish' command.  */
 
 static void
-print_return_value (struct type *func_type, struct type *value_type)
+print_return_value (struct value *function, struct type *value_type)
 {
-  struct value *value = get_return_value (func_type, value_type);
+  struct value *value = get_return_value (function, value_type);
   struct ui_out *uiout = current_uiout;
 
   if (value)
@@ -1548,13 +1548,15 @@ finish_command_continuation (void *arg, 
 	  if (TYPE_CODE (value_type) != TYPE_CODE_VOID)
 	    {
 	      volatile struct gdb_exception ex;
+	      struct value *func;
 
+	      func = read_var_value (a->function, get_current_frame ());
 	      TRY_CATCH (ex, RETURN_MASK_ALL)
 		{
 		  /* print_return_value can throw an exception in some
 		     circumstances.  We need to catch this so that we still
 		     delete the breakpoint.  */
-		  print_return_value (SYMBOL_TYPE (a->function), value_type);
+		  print_return_value (func, value_type);
 		}
 	      if (ex.reason < 0)
 		exception_print (gdb_stdout, ex);
Index: gdb-fsf-trunk-quilt/gdb/iq2000-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/iq2000-tdep.c	2012-05-12 16:35:27.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/iq2000-tdep.c	2012-05-12 20:47:29.755650929 +0100
@@ -583,7 +583,7 @@ iq2000_extract_return_value (struct type
 }
 
 static enum return_value_convention
-iq2000_return_value (struct gdbarch *gdbarch, struct type *func_type,
+iq2000_return_value (struct gdbarch *gdbarch, struct value *function,
 		     struct type *type, struct regcache *regcache,
 		     gdb_byte *readbuf, const gdb_byte *writebuf)
 {
Index: gdb-fsf-trunk-quilt/gdb/lm32-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/lm32-tdep.c	2012-05-12 16:35:27.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/lm32-tdep.c	2012-05-12 20:47:29.755650929 +0100
@@ -374,7 +374,7 @@ lm32_store_return_value (struct type *ty
 
 /* Determine whether a functions return value is in a register or memory.  */
 static enum return_value_convention
-lm32_return_value (struct gdbarch *gdbarch, struct type *func_type,
+lm32_return_value (struct gdbarch *gdbarch, struct value *function,
 		   struct type *valtype, struct regcache *regcache,
 		   gdb_byte *readbuf, const gdb_byte *writebuf)
 {
Index: gdb-fsf-trunk-quilt/gdb/m32c-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/m32c-tdep.c	2012-05-12 16:35:27.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/m32c-tdep.c	2012-05-12 20:47:29.755650929 +0100
@@ -2206,7 +2206,7 @@ m32c_return_by_passed_buf (struct type *
 
 static enum return_value_convention
 m32c_return_value (struct gdbarch *gdbarch,
-		   struct type *func_type,
+		   struct value *function,
 		   struct type *valtype,
 		   struct regcache *regcache,
 		   gdb_byte *readbuf,
Index: gdb-fsf-trunk-quilt/gdb/m32r-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/m32r-tdep.c	2012-05-12 16:35:27.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/m32r-tdep.c	2012-05-12 20:47:29.755650929 +0100
@@ -809,7 +809,7 @@ m32r_extract_return_value (struct type *
 }
 
 static enum return_value_convention
-m32r_return_value (struct gdbarch *gdbarch, struct type *func_type,
+m32r_return_value (struct gdbarch *gdbarch, struct value *function,
 		   struct type *valtype, struct regcache *regcache,
 		   gdb_byte *readbuf, const gdb_byte *writebuf)
 {
Index: gdb-fsf-trunk-quilt/gdb/m68hc11-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/m68hc11-tdep.c	2012-05-12 16:35:27.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/m68hc11-tdep.c	2012-05-12 20:47:29.755650929 +0100
@@ -1323,7 +1323,7 @@ m68hc11_extract_return_value (struct typ
 }
 
 static enum return_value_convention
-m68hc11_return_value (struct gdbarch *gdbarch, struct type *func_type,
+m68hc11_return_value (struct gdbarch *gdbarch, struct value *function,
 		      struct type *valtype, struct regcache *regcache,
 		      gdb_byte *readbuf, const gdb_byte *writebuf)
 {
Index: gdb-fsf-trunk-quilt/gdb/m68k-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/m68k-tdep.c	2012-05-12 16:35:27.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/m68k-tdep.c	2012-05-12 20:47:29.755650929 +0100
@@ -403,7 +403,7 @@ m68k_reg_struct_return_p (struct gdbarch
    from WRITEBUF into REGCACHE.  */
 
 static enum return_value_convention
-m68k_return_value (struct gdbarch *gdbarch, struct type *func_type,
+m68k_return_value (struct gdbarch *gdbarch, struct value *function,
 		   struct type *type, struct regcache *regcache,
 		   gdb_byte *readbuf, const gdb_byte *writebuf)
 {
@@ -438,7 +438,7 @@ m68k_return_value (struct gdbarch *gdbar
 }
 
 static enum return_value_convention
-m68k_svr4_return_value (struct gdbarch *gdbarch, struct type *func_type,
+m68k_svr4_return_value (struct gdbarch *gdbarch, struct value *function,
 			struct type *type, struct regcache *regcache,
 			gdb_byte *readbuf, const gdb_byte *writebuf)
 {
@@ -477,7 +477,7 @@ m68k_svr4_return_value (struct gdbarch *
   if (code == TYPE_CODE_STRUCT && TYPE_NFIELDS (type) == 1)
     {
       type = check_typedef (TYPE_FIELD_TYPE (type, 0));
-      return m68k_svr4_return_value (gdbarch, func_type, type, regcache,
+      return m68k_svr4_return_value (gdbarch, function, type, regcache,
 				     readbuf, writebuf);
     }
 
Index: gdb-fsf-trunk-quilt/gdb/m88k-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/m88k-tdep.c	2012-05-12 16:35:27.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/m88k-tdep.c	2012-05-12 20:47:29.755650929 +0100
@@ -383,7 +383,7 @@ m88k_dummy_id (struct gdbarch *arch, str
    from WRITEBUF into REGCACHE.  */
 
 static enum return_value_convention
-m88k_return_value (struct gdbarch *gdbarch, struct type *func_type,
+m88k_return_value (struct gdbarch *gdbarch, struct value *function,
 		   struct type *type, struct regcache *regcache,
 		   gdb_byte *readbuf, const gdb_byte *writebuf)
 {
Index: gdb-fsf-trunk-quilt/gdb/mep-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/mep-tdep.c	2012-05-12 16:35:27.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/mep-tdep.c	2012-05-12 20:47:29.755650929 +0100
@@ -2194,7 +2194,7 @@ Try using the 'return' command with no a
 }
 
 static enum return_value_convention
-mep_return_value (struct gdbarch *gdbarch, struct type *func_type,
+mep_return_value (struct gdbarch *gdbarch, struct value *function,
 		  struct type *type, struct regcache *regcache,
 		  gdb_byte *readbuf, const gdb_byte *writebuf)
 {
Index: gdb-fsf-trunk-quilt/gdb/mips-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/mips-tdep.c	2012-05-12 20:47:15.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/mips-tdep.c	2012-05-12 20:47:29.765606101 +0100
@@ -3332,7 +3332,7 @@ mips_eabi_push_dummy_call (struct gdbarc
 /* Determine the return value convention being used.  */
 
 static enum return_value_convention
-mips_eabi_return_value (struct gdbarch *gdbarch, struct type *func_type,
+mips_eabi_return_value (struct gdbarch *gdbarch, struct value *function,
 			struct type *type, struct regcache *regcache,
 			gdb_byte *readbuf, const gdb_byte *writebuf)
 {
@@ -3722,7 +3722,7 @@ mips_n32n64_push_dummy_call (struct gdba
 }
 
 static enum return_value_convention
-mips_n32n64_return_value (struct gdbarch *gdbarch, struct type *func_type,
+mips_n32n64_return_value (struct gdbarch *gdbarch, struct value *function,
 			  struct type *type, struct regcache *regcache,
 			  gdb_byte *readbuf, const gdb_byte *writebuf)
 {
@@ -3890,6 +3890,20 @@ mips_n32n64_return_value (struct gdbarch
     }
 }
 
+/* Which registers to use for passing floating-point values between
+   function calls, one of floating-point, general and both kinds of
+   registers.  O32 and O64 use different register kinds for standard
+   MIPS and MIPS16 code; to make the handling of cases where we may
+   not know what kind of code is being used (e.g. no debug information)
+   easier we sometimes use both kinds.  */
+
+enum mips_fval_reg
+{
+  mips_fval_fpr,
+  mips_fval_gpr,
+  mips_fval_both
+};
+
 /* O32 ABI stuff.  */
 
 static CORE_ADDR
@@ -3980,8 +3994,8 @@ mips_o32_push_dummy_call (struct gdbarch
       /* 32-bit ABIs always start floating point arguments in an
          even-numbered floating point register.  Round the FP register
          up before the check to see if there are any FP registers
-         left.  O32/O64 targets also pass the FP in the integer
-         registers so also round up normal registers.  */
+         left.  O32 targets also pass the FP in the integer registers
+         so also round up normal registers.  */
       if (fp_register_arg_p (gdbarch, typecode, arg_type))
 	{
 	  if ((float_argreg & 1))
@@ -3989,46 +4003,48 @@ mips_o32_push_dummy_call (struct gdbarch
 	}
 
       /* Floating point arguments passed in registers have to be
-         treated specially.  On 32-bit architectures, doubles
-         are passed in register pairs; the even register gets
-         the low word, and the odd register gets the high word.
-         On O32/O64, the first two floating point arguments are
-         also copied to general registers, because MIPS16 functions
-         don't use float registers for arguments.  This duplication of
-         arguments in general registers can't hurt non-MIPS16 functions
-         because those registers are normally skipped.  */
+         treated specially.  On 32-bit architectures, doubles are
+         passed in register pairs; the even FP register gets the
+         low word, and the odd FP register gets the high word.
+         On O32, the first two floating point arguments are also
+         copied to general registers, following their memory order,
+         because MIPS16 functions don't use float registers for
+         arguments.  This duplication of arguments in general
+         registers can't hurt non-MIPS16 functions, because those
+         registers are normally skipped.  */
 
       if (fp_register_arg_p (gdbarch, typecode, arg_type)
 	  && float_argreg <= MIPS_LAST_FP_ARG_REGNUM (gdbarch))
 	{
 	  if (register_size (gdbarch, float_argreg) < 8 && len == 8)
 	    {
-	      int low_offset = gdbarch_byte_order (gdbarch)
-			       == BFD_ENDIAN_BIG ? 4 : 0;
+	      int freg_offset = gdbarch_byte_order (gdbarch)
+				== BFD_ENDIAN_BIG ? 1 : 0;
 	      unsigned long regval;
 
-	      /* Write the low word of the double to the even register(s).  */
-	      regval = extract_unsigned_integer (val + low_offset,
-						 4, byte_order);
+	      /* First word.  */
+	      regval = extract_unsigned_integer (val, 4, byte_order);
 	      if (mips_debug)
 		fprintf_unfiltered (gdb_stdlog, " - fpreg=%d val=%s",
-				    float_argreg, phex (regval, 4));
+				    float_argreg + freg_offset,
+				    phex (regval, 4));
 	      regcache_cooked_write_unsigned (regcache,
-					      float_argreg++, regval);
+					      float_argreg++ + freg_offset,
+					      regval);
 	      if (mips_debug)
 		fprintf_unfiltered (gdb_stdlog, " - reg=%d val=%s",
 				    argreg, phex (regval, 4));
 	      regcache_cooked_write_unsigned (regcache, argreg++, regval);
 
-	      /* Write the high word of the double to the odd register(s).  */
-	      regval = extract_unsigned_integer (val + 4 - low_offset,
-						 4, byte_order);
+	      /* Second word.  */
+	      regval = extract_unsigned_integer (val + 4, 4, byte_order);
 	      if (mips_debug)
 		fprintf_unfiltered (gdb_stdlog, " - fpreg=%d val=%s",
-				    float_argreg, phex (regval, 4));
+				    float_argreg - freg_offset,
+				    phex (regval, 4));
 	      regcache_cooked_write_unsigned (regcache,
-					      float_argreg++, regval);
-
+					      float_argreg++ - freg_offset,
+					      regval);
 	      if (mips_debug)
 		fprintf_unfiltered (gdb_stdlog, " - reg=%d val=%s",
 				    argreg, phex (regval, 4));
@@ -4203,12 +4219,16 @@ mips_o32_push_dummy_call (struct gdbarch
 }
 
 static enum return_value_convention
-mips_o32_return_value (struct gdbarch *gdbarch, struct type *func_type,
+mips_o32_return_value (struct gdbarch *gdbarch, struct value *function,
 		       struct type *type, struct regcache *regcache,
 		       gdb_byte *readbuf, const gdb_byte *writebuf)
 {
+  CORE_ADDR func_addr = function ? find_function_addr (function, NULL) : 0;
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  int mips16 = mips_pc_is_mips16 (func_addr);
+  enum mips_fval_reg fval_reg;
 
+  fval_reg = readbuf ? mips16 ? mips_fval_gpr : mips_fval_fpr : mips_fval_both;
   if (TYPE_CODE (type) == TYPE_CODE_STRUCT
       || TYPE_CODE (type) == TYPE_CODE_UNION
       || TYPE_CODE (type) == TYPE_CODE_ARRAY)
@@ -4216,54 +4236,110 @@ mips_o32_return_value (struct gdbarch *g
   else if (TYPE_CODE (type) == TYPE_CODE_FLT
 	   && TYPE_LENGTH (type) == 4 && tdep->mips_fpu_type != MIPS_FPU_NONE)
     {
-      /* A single-precision floating-point value.  It fits in the
-         least significant part of FP0.  */
+      /* A single-precision floating-point value.  If reading in or copying,
+         then we get it from/put it to FP0 for standard MIPS code or GPR2
+         for MIPS16 code.  If writing out only, then we put it to both FP0
+         and GPR2.  We do not support reading in with no function known, if
+         this safety check ever triggers, then we'll have to try harder.  */
+      gdb_assert (function || !readbuf);
       if (mips_debug)
-	fprintf_unfiltered (gdb_stderr, "Return float in $fp0\n");
-      mips_xfer_register (gdbarch, regcache,
-			  (gdbarch_num_regs (gdbarch)
-			   + mips_regnum (gdbarch)->fp0),
-			  TYPE_LENGTH (type),
-			  gdbarch_byte_order (gdbarch),
-			  readbuf, writebuf, 0);
+	switch (fval_reg)
+	  {
+	  case mips_fval_fpr:
+	    fprintf_unfiltered (gdb_stderr, "Return float in $fp0\n");
+	    break;
+	  case mips_fval_gpr:
+	    fprintf_unfiltered (gdb_stderr, "Return float in $2\n");
+	    break;
+	  case mips_fval_both:
+	    fprintf_unfiltered (gdb_stderr, "Return float in $fp0 and $2\n");
+	    break;
+	  }
+      if (fval_reg != mips_fval_gpr)
+	mips_xfer_register (gdbarch, regcache,
+			    (gdbarch_num_regs (gdbarch)
+			     + mips_regnum (gdbarch)->fp0),
+			    TYPE_LENGTH (type),
+			    gdbarch_byte_order (gdbarch),
+			    readbuf, writebuf, 0);
+      if (fval_reg != mips_fval_fpr)
+	mips_xfer_register (gdbarch, regcache,
+			    gdbarch_num_regs (gdbarch) + 2,
+			    TYPE_LENGTH (type),
+			    gdbarch_byte_order (gdbarch),
+			    readbuf, writebuf, 0);
       return RETURN_VALUE_REGISTER_CONVENTION;
     }
   else if (TYPE_CODE (type) == TYPE_CODE_FLT
 	   && TYPE_LENGTH (type) == 8 && tdep->mips_fpu_type != MIPS_FPU_NONE)
     {
-      /* A double-precision floating-point value.  The most
-         significant part goes in FP1, and the least significant in
-         FP0.  */
+      /* A double-precision floating-point value.  If reading in or copying,
+         then we get it from/put it to FP1 and FP0 for standard MIPS code or
+         GPR2 and GPR3 for MIPS16 code.  If writing out only, then we put it
+         to both FP1/FP0 and GPR2/GPR3.  We do not support reading in with
+         no function known, if this safety check ever triggers, then we'll
+         have to try harder.  */
+      gdb_assert (function || !readbuf);
       if (mips_debug)
-	fprintf_unfiltered (gdb_stderr, "Return float in $fp1/$fp0\n");
-      switch (gdbarch_byte_order (gdbarch))
+	switch (fval_reg)
+	  {
+	  case mips_fval_fpr:
+	    fprintf_unfiltered (gdb_stderr, "Return float in $fp1/$fp0\n");
+	    break;
+	  case mips_fval_gpr:
+	    fprintf_unfiltered (gdb_stderr, "Return float in $2/$3\n");
+	    break;
+	  case mips_fval_both:
+	    fprintf_unfiltered (gdb_stderr,
+				"Return float in $fp1/$fp0 and $2/$3\n");
+	    break;
+	  }
+      if (fval_reg != mips_fval_gpr)
 	{
-	case BFD_ENDIAN_LITTLE:
-	  mips_xfer_register (gdbarch, regcache,
-			      (gdbarch_num_regs (gdbarch)
-			       + mips_regnum (gdbarch)->fp0 + 0),
-			      4, gdbarch_byte_order (gdbarch),
-			      readbuf, writebuf, 0);
-	  mips_xfer_register (gdbarch, regcache,
-			      (gdbarch_num_regs (gdbarch)
-			       + mips_regnum (gdbarch)->fp0 + 1),
-			      4, gdbarch_byte_order (gdbarch),
-			      readbuf, writebuf, 4);
-	  break;
-	case BFD_ENDIAN_BIG:
+	  /* The most significant part goes in FP1, and the least significant
+	     in FP0.  */
+	  switch (gdbarch_byte_order (gdbarch))
+	    {
+	    case BFD_ENDIAN_LITTLE:
+	      mips_xfer_register (gdbarch, regcache,
+				  (gdbarch_num_regs (gdbarch)
+				   + mips_regnum (gdbarch)->fp0 + 0),
+				  4, gdbarch_byte_order (gdbarch),
+				  readbuf, writebuf, 0);
+	      mips_xfer_register (gdbarch, regcache,
+				  (gdbarch_num_regs (gdbarch)
+				   + mips_regnum (gdbarch)->fp0 + 1),
+				  4, gdbarch_byte_order (gdbarch),
+				  readbuf, writebuf, 4);
+	      break;
+	    case BFD_ENDIAN_BIG:
+	      mips_xfer_register (gdbarch, regcache,
+				  (gdbarch_num_regs (gdbarch)
+				   + mips_regnum (gdbarch)->fp0 + 1),
+				  4, gdbarch_byte_order (gdbarch),
+				  readbuf, writebuf, 0);
+	      mips_xfer_register (gdbarch, regcache,
+				  (gdbarch_num_regs (gdbarch)
+				   + mips_regnum (gdbarch)->fp0 + 0),
+				  4, gdbarch_byte_order (gdbarch),
+				  readbuf, writebuf, 4);
+	      break;
+	    default:
+	      internal_error (__FILE__, __LINE__, _("bad switch"));
+	    }
+	}
+      if (fval_reg != mips_fval_fpr)
+	{
+	  /* The two 32-bit parts are always placed in GPR2 and GPR3
+	     following these registers' memory order.  */
 	  mips_xfer_register (gdbarch, regcache,
-			      (gdbarch_num_regs (gdbarch)
-			       + mips_regnum (gdbarch)->fp0 + 1),
+			      gdbarch_num_regs (gdbarch) + 2,
 			      4, gdbarch_byte_order (gdbarch),
 			      readbuf, writebuf, 0);
 	  mips_xfer_register (gdbarch, regcache,
-			      (gdbarch_num_regs (gdbarch)
-			       + mips_regnum (gdbarch)->fp0 + 0),
+			      gdbarch_num_regs (gdbarch) + 3,
 			      4, gdbarch_byte_order (gdbarch),
 			      readbuf, writebuf, 4);
-	  break;
-	default:
-	  internal_error (__FILE__, __LINE__, _("bad switch"));
 	}
       return RETURN_VALUE_REGISTER_CONVENTION;
     }
@@ -4459,14 +4535,14 @@ mips_o64_push_dummy_call (struct gdbarch
 	}
 
       /* Floating point arguments passed in registers have to be
-         treated specially.  On 32-bit architectures, doubles
-         are passed in register pairs; the even register gets
-         the low word, and the odd register gets the high word.
-         On O32/O64, the first two floating point arguments are
-         also copied to general registers, because MIPS16 functions
-         don't use float registers for arguments.  This duplication of
-         arguments in general registers can't hurt non-MIPS16 functions
-         because those registers are normally skipped.  */
+         treated specially.  On 32-bit architectures, doubles are
+         passed in register pairs; the even FP register gets the
+         low word, and the odd FP register gets the high word.
+         On O64, the first two floating point arguments are also
+         copied to general registers, because MIPS16 functions
+         don't use float registers for arguments.  This duplication
+         of arguments in general registers can't hurt non-MIPS16
+         functions because those registers are normally skipped.  */
 
       if (fp_register_arg_p (gdbarch, typecode, arg_type)
 	  && float_argreg <= MIPS_LAST_FP_ARG_REGNUM (gdbarch))
@@ -4611,28 +4687,54 @@ mips_o64_push_dummy_call (struct gdbarch
 }
 
 static enum return_value_convention
-mips_o64_return_value (struct gdbarch *gdbarch, struct type *func_type,
+mips_o64_return_value (struct gdbarch *gdbarch, struct value *function,
 		       struct type *type, struct regcache *regcache,
 		       gdb_byte *readbuf, const gdb_byte *writebuf)
 {
+  CORE_ADDR func_addr = function ? find_function_addr (function, NULL) : 0;
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  int mips16 = mips_pc_is_mips16 (func_addr);
+  enum mips_fval_reg fval_reg;
 
+  fval_reg = readbuf ? mips16 ? mips_fval_gpr : mips_fval_fpr : mips_fval_both;
   if (TYPE_CODE (type) == TYPE_CODE_STRUCT
       || TYPE_CODE (type) == TYPE_CODE_UNION
       || TYPE_CODE (type) == TYPE_CODE_ARRAY)
     return RETURN_VALUE_STRUCT_CONVENTION;
   else if (fp_register_arg_p (gdbarch, TYPE_CODE (type), type))
     {
-      /* A floating-point value.  It fits in the least significant
-         part of FP0.  */
+      /* A floating-point value.  If reading in or copying, then we get it
+         from/put it to FP0 for standard MIPS code or GPR2 for MIPS16 code.
+         If writing out only, then we put it to both FP0 and GPR2.  We do
+         not support reading in with no function known, if this safety
+         check ever triggers, then we'll have to try harder.  */
+      gdb_assert (function || !readbuf);
       if (mips_debug)
-	fprintf_unfiltered (gdb_stderr, "Return float in $fp0\n");
-      mips_xfer_register (gdbarch, regcache,
-			  (gdbarch_num_regs (gdbarch)
-			   + mips_regnum (gdbarch)->fp0),
-			  TYPE_LENGTH (type),
-			  gdbarch_byte_order (gdbarch),
-			  readbuf, writebuf, 0);
+	switch (fval_reg)
+	  {
+	  case mips_fval_fpr:
+	    fprintf_unfiltered (gdb_stderr, "Return float in $fp0\n");
+	    break;
+	  case mips_fval_gpr:
+	    fprintf_unfiltered (gdb_stderr, "Return float in $2\n");
+	    break;
+	  case mips_fval_both:
+	    fprintf_unfiltered (gdb_stderr, "Return float in $fp0 and $2\n");
+	    break;
+	  }
+      if (fval_reg != mips_fval_gpr)
+	mips_xfer_register (gdbarch, regcache,
+			    (gdbarch_num_regs (gdbarch)
+			     + mips_regnum (gdbarch)->fp0),
+			    TYPE_LENGTH (type),
+			    gdbarch_byte_order (gdbarch),
+			    readbuf, writebuf, 0);
+      if (fval_reg != mips_fval_fpr)
+	mips_xfer_register (gdbarch, regcache,
+			    gdbarch_num_regs (gdbarch) + 2,
+			    TYPE_LENGTH (type),
+			    gdbarch_byte_order (gdbarch),
+			    readbuf, writebuf, 0);
       return RETURN_VALUE_REGISTER_CONVENTION;
     }
   else
Index: gdb-fsf-trunk-quilt/gdb/mn10300-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/mn10300-tdep.c	2012-05-12 16:35:27.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/mn10300-tdep.c	2012-05-12 20:47:29.765606101 +0100
@@ -233,7 +233,7 @@ mn10300_extract_return_value (struct gdb
    from WRITEBUF into REGCACHE.  */
 
 static enum return_value_convention
-mn10300_return_value (struct gdbarch *gdbarch, struct type *func_type,
+mn10300_return_value (struct gdbarch *gdbarch, struct value *function,
 		      struct type *type, struct regcache *regcache,
 		      gdb_byte *readbuf, const gdb_byte *writebuf)
 {
Index: gdb-fsf-trunk-quilt/gdb/moxie-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/moxie-tdep.c	2012-05-12 16:35:27.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/moxie-tdep.c	2012-05-12 20:47:29.765606101 +0100
@@ -341,7 +341,7 @@ moxie_extract_return_value (struct type 
 /* Implement the "return_value" gdbarch method.  */
 
 static enum return_value_convention
-moxie_return_value (struct gdbarch *gdbarch, struct type *func_type,
+moxie_return_value (struct gdbarch *gdbarch, struct value *function,
 		   struct type *valtype, struct regcache *regcache,
 		   gdb_byte *readbuf, const gdb_byte *writebuf)
 {
Index: gdb-fsf-trunk-quilt/gdb/mt-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/mt-tdep.c	2012-05-12 16:35:27.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/mt-tdep.c	2012-05-12 20:47:29.765606101 +0100
@@ -335,7 +335,7 @@ mt_register_reggroup_p (struct gdbarch *
    values.  */
 
 static enum return_value_convention
-mt_return_value (struct gdbarch *gdbarch, struct type *func_type,
+mt_return_value (struct gdbarch *gdbarch, struct value *function,
 		 struct type *type, struct regcache *regcache,
 		 gdb_byte *readbuf, const gdb_byte *writebuf)
 {
Index: gdb-fsf-trunk-quilt/gdb/ppc-linux-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/ppc-linux-tdep.c	2012-05-12 16:35:27.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/ppc-linux-tdep.c	2012-05-12 20:47:29.765606101 +0100
@@ -241,7 +241,7 @@ ppc_linux_memory_remove_breakpoint (stru
    which were added later, do get returned in a register though.  */
 
 static enum return_value_convention
-ppc_linux_return_value (struct gdbarch *gdbarch, struct type *func_type,
+ppc_linux_return_value (struct gdbarch *gdbarch, struct value *function,
 			struct type *valtype, struct regcache *regcache,
 			gdb_byte *readbuf, const gdb_byte *writebuf)
 {  
@@ -251,7 +251,7 @@ ppc_linux_return_value (struct gdbarch *
 	   && TYPE_VECTOR (valtype)))
     return RETURN_VALUE_STRUCT_CONVENTION;
   else
-    return ppc_sysv_abi_return_value (gdbarch, func_type, valtype, regcache,
+    return ppc_sysv_abi_return_value (gdbarch, function, valtype, regcache,
 				      readbuf, writebuf);
 }
 
Index: gdb-fsf-trunk-quilt/gdb/ppc-sysv-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/ppc-sysv-tdep.c	2012-05-12 16:35:27.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/ppc-sysv-tdep.c	2012-05-12 20:47:29.765606101 +0100
@@ -1041,23 +1041,25 @@ do_ppc_sysv_return_value (struct gdbarch
 }
 
 enum return_value_convention
-ppc_sysv_abi_return_value (struct gdbarch *gdbarch, struct type *func_type,
+ppc_sysv_abi_return_value (struct gdbarch *gdbarch, struct value *function,
 			   struct type *valtype, struct regcache *regcache,
 			   gdb_byte *readbuf, const gdb_byte *writebuf)
 {
-  return do_ppc_sysv_return_value (gdbarch, func_type, valtype, regcache,
-				   readbuf, writebuf, 0);
+  return do_ppc_sysv_return_value (gdbarch,
+				   function ? value_type (function) : NULL,
+				   valtype, regcache, readbuf, writebuf, 0);
 }
 
 enum return_value_convention
 ppc_sysv_abi_broken_return_value (struct gdbarch *gdbarch,
-				  struct type *func_type,
+				  struct value *function,
 				  struct type *valtype,
 				  struct regcache *regcache,
 				  gdb_byte *readbuf, const gdb_byte *writebuf)
 {
-  return do_ppc_sysv_return_value (gdbarch, func_type, valtype, regcache,
-				   readbuf, writebuf, 1);
+  return do_ppc_sysv_return_value (gdbarch,
+				   function ? value_type (function) : NULL,
+				   valtype, regcache, readbuf, writebuf, 1);
 }
 
 /* The helper function for 64-bit SYSV push_dummy_call.  Converts the
@@ -1710,12 +1712,13 @@ ppc64_sysv_abi_push_dummy_call (struct g
    location; when READBUF is non-NULL, fill the buffer from the
    corresponding register return-value location.  */
 enum return_value_convention
-ppc64_sysv_abi_return_value (struct gdbarch *gdbarch, struct type *func_type,
+ppc64_sysv_abi_return_value (struct gdbarch *gdbarch, struct value *function,
 			     struct type *valtype, struct regcache *regcache,
 			     gdb_byte *readbuf, const gdb_byte *writebuf)
 {
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  struct type *func_type = function ? value_type (function) : NULL;
   int opencl_abi = func_type? ppc_sysv_use_opencl_abi (func_type) : 0;
 
   /* This function exists to support a calling convention that
Index: gdb-fsf-trunk-quilt/gdb/ppc-tdep.h
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/ppc-tdep.h	2012-05-12 16:35:27.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/ppc-tdep.h	2012-05-12 20:47:29.765606101 +0100
@@ -28,13 +28,13 @@ struct type;
 
 /* From ppc-sysv-tdep.c ...  */
 enum return_value_convention ppc_sysv_abi_return_value (struct gdbarch *gdbarch,
-							struct type *func_type,
+							struct value *function,
 							struct type *valtype,
 							struct regcache *regcache,
 							gdb_byte *readbuf,
 							const gdb_byte *writebuf);
 enum return_value_convention ppc_sysv_abi_broken_return_value (struct gdbarch *gdbarch,
-							       struct type *func_type,
+							       struct value *function,
 							       struct type *valtype,
 							       struct regcache *regcache,
 							       gdb_byte *readbuf,
@@ -54,7 +54,7 @@ CORE_ADDR ppc64_sysv_abi_push_dummy_call
 					  int struct_return,
 					  CORE_ADDR struct_addr);
 enum return_value_convention ppc64_sysv_abi_return_value (struct gdbarch *gdbarch,
-							  struct type *func_type,
+							  struct value *function,
 							  struct type *valtype,
 							  struct regcache *regcache,
 							  gdb_byte *readbuf,
Index: gdb-fsf-trunk-quilt/gdb/ppcnbsd-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/ppcnbsd-tdep.c	2012-05-12 16:35:27.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/ppcnbsd-tdep.c	2012-05-12 20:47:29.765606101 +0100
@@ -76,7 +76,7 @@ ppcnbsd_regset_from_core_section (struct
    the moment use the broken convention.  Ulgh!  */
 
 static enum return_value_convention
-ppcnbsd_return_value (struct gdbarch *gdbarch, struct type *func_type,
+ppcnbsd_return_value (struct gdbarch *gdbarch, struct value *function,
 		      struct type *valtype, struct regcache *regcache,
 		      gdb_byte *readbuf, const gdb_byte *writebuf)
 {
@@ -92,7 +92,7 @@ ppcnbsd_return_value (struct gdbarch *gd
     return RETURN_VALUE_STRUCT_CONVENTION;
   else
 #endif
-    return ppc_sysv_abi_broken_return_value (gdbarch, func_type, valtype,
+    return ppc_sysv_abi_broken_return_value (gdbarch, function, valtype,
 					     regcache, readbuf, writebuf);
 }
 \f
Index: gdb-fsf-trunk-quilt/gdb/rs6000-aix-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/rs6000-aix-tdep.c	2012-05-12 16:35:27.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/rs6000-aix-tdep.c	2012-05-12 20:47:29.765606101 +0100
@@ -424,7 +424,7 @@ rs6000_push_dummy_call (struct gdbarch *
 }
 
 static enum return_value_convention
-rs6000_return_value (struct gdbarch *gdbarch, struct type *func_type,
+rs6000_return_value (struct gdbarch *gdbarch, struct value *function,
 		     struct type *valtype, struct regcache *regcache,
 		     gdb_byte *readbuf, const gdb_byte *writebuf)
 {
Index: gdb-fsf-trunk-quilt/gdb/s390-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/s390-tdep.c	2012-05-12 16:35:27.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/s390-tdep.c	2012-05-12 20:47:29.765606101 +0100
@@ -2818,7 +2818,7 @@ s390_return_value_convention (struct gdb
 }
 
 static enum return_value_convention
-s390_return_value (struct gdbarch *gdbarch, struct type *func_type,
+s390_return_value (struct gdbarch *gdbarch, struct value *function,
 		   struct type *type, struct regcache *regcache,
 		   gdb_byte *out, const gdb_byte *in)
 {
Index: gdb-fsf-trunk-quilt/gdb/score-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/score-tdep.c	2012-05-12 16:35:27.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/score-tdep.c	2012-05-12 20:47:29.765606101 +0100
@@ -450,7 +450,7 @@ score_xfer_register (struct regcache *re
 }
 
 static enum return_value_convention
-score_return_value (struct gdbarch *gdbarch, struct type *func_type,
+score_return_value (struct gdbarch *gdbarch, struct value *function,
                     struct type *type, struct regcache *regcache,
                     gdb_byte * readbuf, const gdb_byte * writebuf)
 {
Index: gdb-fsf-trunk-quilt/gdb/sh-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/sh-tdep.c	2012-05-12 16:35:27.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/sh-tdep.c	2012-05-12 20:47:29.765606101 +0100
@@ -1398,10 +1398,12 @@ sh_store_return_value_fpu (struct type *
 }
 
 static enum return_value_convention
-sh_return_value_nofpu (struct gdbarch *gdbarch, struct type *func_type,
+sh_return_value_nofpu (struct gdbarch *gdbarch, struct value *function,
 		       struct type *type, struct regcache *regcache,
 		       gdb_byte *readbuf, const gdb_byte *writebuf)
 {
+  struct type *func_type = function ? value_type (function) : NULL;
+
   if (sh_use_struct_convention_nofpu (
   	sh_is_renesas_calling_convention (func_type), type))
     return RETURN_VALUE_STRUCT_CONVENTION;
@@ -1413,10 +1415,12 @@ sh_return_value_nofpu (struct gdbarch *g
 }
 
 static enum return_value_convention
-sh_return_value_fpu (struct gdbarch *gdbarch, struct type *func_type,
+sh_return_value_fpu (struct gdbarch *gdbarch, struct value *function,
 		     struct type *type, struct regcache *regcache,
 		     gdb_byte *readbuf, const gdb_byte *writebuf)
 {
+  struct type *func_type = function ? value_type (function) : NULL;
+
   if (sh_use_struct_convention (
 	sh_is_renesas_calling_convention (func_type), type))
     return RETURN_VALUE_STRUCT_CONVENTION;
Index: gdb-fsf-trunk-quilt/gdb/sh64-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/sh64-tdep.c	2012-05-12 16:35:27.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/sh64-tdep.c	2012-05-12 20:47:29.775609171 +0100
@@ -1328,7 +1328,7 @@ sh64_store_return_value (struct type *ty
 }
 
 static enum return_value_convention
-sh64_return_value (struct gdbarch *gdbarch, struct type *func_type,
+sh64_return_value (struct gdbarch *gdbarch, struct value *function,
 		   struct type *type, struct regcache *regcache,
 		   gdb_byte *readbuf, const gdb_byte *writebuf)
 {
Index: gdb-fsf-trunk-quilt/gdb/sparc-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/sparc-tdep.c	2012-05-12 16:35:27.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/sparc-tdep.c	2012-05-12 20:47:29.775609171 +0100
@@ -1354,7 +1354,7 @@ sparc32_store_return_value (struct type 
 }
 
 static enum return_value_convention
-sparc32_return_value (struct gdbarch *gdbarch, struct type *func_type,
+sparc32_return_value (struct gdbarch *gdbarch, struct value *function,
 		      struct type *type, struct regcache *regcache,
 		      gdb_byte *readbuf, const gdb_byte *writebuf)
 {
Index: gdb-fsf-trunk-quilt/gdb/sparc64-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/sparc64-tdep.c	2012-05-12 16:35:27.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/sparc64-tdep.c	2012-05-12 20:47:29.775609171 +0100
@@ -1119,7 +1119,7 @@ sparc64_store_return_value (struct type 
 }
 
 static enum return_value_convention
-sparc64_return_value (struct gdbarch *gdbarch, struct type *func_type,
+sparc64_return_value (struct gdbarch *gdbarch, struct value *function,
 		      struct type *type, struct regcache *regcache,
 		      gdb_byte *readbuf, const gdb_byte *writebuf)
 {
Index: gdb-fsf-trunk-quilt/gdb/spu-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/spu-tdep.c	2012-05-12 16:35:27.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/spu-tdep.c	2012-05-12 20:47:29.775609171 +0100
@@ -1450,10 +1450,11 @@ spu_dummy_id (struct gdbarch *gdbarch, s
 /* Function return value access.  */
 
 static enum return_value_convention
-spu_return_value (struct gdbarch *gdbarch, struct type *func_type,
+spu_return_value (struct gdbarch *gdbarch, struct value *function,
 		  struct type *type, struct regcache *regcache,
 		  gdb_byte *out, const gdb_byte *in)
 {
+  struct type *func_type = function ? value_type (function) : NULL;
   enum return_value_convention rvc;
   int opencl_vector = 0;
 
Index: gdb-fsf-trunk-quilt/gdb/stack.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/stack.c	2012-05-12 20:47:15.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/stack.c	2012-05-12 20:47:29.775609171 +0100
@@ -2238,6 +2238,7 @@ return_command (char *retval_exp, int fr
   struct gdbarch *gdbarch;
   struct symbol *thisfun;
   struct value *return_value = NULL;
+  struct value *function = NULL;
   const char *query_prefix = "";
 
   thisframe = get_selected_frame ("No selected frame.");
@@ -2282,6 +2283,9 @@ return_command (char *retval_exp, int fr
       if (value_lazy (return_value))
 	value_fetch_lazy (return_value);
 
+      if (thisfun != NULL)
+	function = read_var_value (thisfun, thisframe);
+
       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
@@ -2290,8 +2294,7 @@ return_command (char *retval_exp, int fr
            occur.  */
 	return_value = NULL;
       else if (thisfun != NULL
-	       && using_struct_return (gdbarch,
-				       SYMBOL_TYPE (thisfun), return_type))
+	       && using_struct_return (gdbarch, function, return_type))
 	{
 	  query_prefix = "The location at which to store the "
 	    "function's return value is unknown.\n"
@@ -2326,12 +2329,11 @@ return_command (char *retval_exp, int fr
     {
       struct type *return_type = value_type (return_value);
       struct gdbarch *gdbarch = get_regcache_arch (get_current_regcache ());
-      struct type *func_type = thisfun == NULL ? NULL : SYMBOL_TYPE (thisfun);
 
-      gdb_assert (gdbarch_return_value (gdbarch, func_type, return_type, NULL,
+      gdb_assert (gdbarch_return_value (gdbarch, function, return_type, NULL,
 					NULL, NULL)
 		  == RETURN_VALUE_REGISTER_CONVENTION);
-      gdbarch_return_value (gdbarch, func_type, return_type,
+      gdbarch_return_value (gdbarch, function, return_type,
 			    get_current_regcache (), NULL /*read*/,
 			    value_contents (return_value) /*write*/);
     }
Index: gdb-fsf-trunk-quilt/gdb/v850-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/v850-tdep.c	2012-05-12 16:35:27.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/v850-tdep.c	2012-05-12 20:47:29.775609171 +0100
@@ -933,7 +933,7 @@ v850_store_return_value (struct type *ty
 }
 
 static enum return_value_convention
-v850_return_value (struct gdbarch *gdbarch, struct type *func_type,
+v850_return_value (struct gdbarch *gdbarch, struct value *function,
 		   struct type *type, struct regcache *regcache,
 		   gdb_byte *readbuf, const gdb_byte *writebuf)
 {
Index: gdb-fsf-trunk-quilt/gdb/value.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/value.c	2012-05-12 16:35:27.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/value.c	2012-05-12 20:47:29.775609171 +0100
@@ -3303,7 +3303,7 @@ coerce_array (struct value *arg)
 
 int
 using_struct_return (struct gdbarch *gdbarch,
-		     struct type *func_type, struct type *value_type)
+		     struct value *function, struct type *value_type)
 {
   enum type_code code = TYPE_CODE (value_type);
 
@@ -3316,7 +3316,7 @@ using_struct_return (struct gdbarch *gdb
     return 0;
 
   /* Probe the architecture for the return-value convention.  */
-  return (gdbarch_return_value (gdbarch, func_type, value_type,
+  return (gdbarch_return_value (gdbarch, function, value_type,
 				NULL, NULL, NULL)
 	  != RETURN_VALUE_REGISTER_CONVENTION);
 }
Index: gdb-fsf-trunk-quilt/gdb/value.h
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/value.h	2012-05-12 16:35:27.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/value.h	2012-05-12 20:47:29.775609171 +0100
@@ -698,7 +698,7 @@ extern int value_bit_index (struct type 
 			    int index);
 
 extern int using_struct_return (struct gdbarch *gdbarch,
-				struct type *func_type,
+				struct value *function,
 				struct type *value_type);
 
 extern struct value *evaluate_expression (struct expression *exp);
Index: gdb-fsf-trunk-quilt/gdb/vax-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/vax-tdep.c	2012-05-12 16:35:27.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/vax-tdep.c	2012-05-12 20:47:29.775609171 +0100
@@ -204,7 +204,7 @@ vax_dummy_id (struct gdbarch *gdbarch, s
 \f
 
 static enum return_value_convention
-vax_return_value (struct gdbarch *gdbarch, struct type *func_type,
+vax_return_value (struct gdbarch *gdbarch, struct value *function,
 		  struct type *type, struct regcache *regcache,
 		  gdb_byte *readbuf, const gdb_byte *writebuf)
 {
Index: gdb-fsf-trunk-quilt/gdb/xstormy16-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/xstormy16-tdep.c	2012-05-12 16:35:27.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/xstormy16-tdep.c	2012-05-12 20:47:29.775609171 +0100
@@ -197,7 +197,7 @@ xstormy16_store_return_value (struct typ
 }
 
 static enum return_value_convention
-xstormy16_return_value (struct gdbarch *gdbarch, struct type *func_type,
+xstormy16_return_value (struct gdbarch *gdbarch, struct value *function,
 			struct type *type, struct regcache *regcache,
 			gdb_byte *readbuf, const gdb_byte *writebuf)
 {
Index: gdb-fsf-trunk-quilt/gdb/xtensa-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/xtensa-tdep.c	2012-05-12 16:35:27.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/xtensa-tdep.c	2012-05-12 20:47:29.775609171 +0100
@@ -1682,7 +1682,7 @@ xtensa_store_return_value (struct type *
 
 static enum return_value_convention
 xtensa_return_value (struct gdbarch *gdbarch,
-		     struct type *func_type,
+		     struct value *function,
 		     struct type *valtype,
 		     struct regcache *regcache,
 		     gdb_byte *readbuf,
Index: gdb-fsf-trunk-quilt/gdb/elfread.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/elfread.c	2012-05-12 16:35:27.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/elfread.c	2012-05-12 20:57:28.105618667 +0100
@@ -1020,6 +1020,7 @@ elf_gnu_ifunc_resolver_return_stop (stru
   struct type *func_func_type = builtin_type (gdbarch)->builtin_func_func;
   struct type *value_type = TYPE_TARGET_TYPE (func_func_type);
   struct regcache *regcache = get_thread_regcache (inferior_ptid);
+  struct value *func_func;
   struct value *value;
   CORE_ADDR resolved_address, resolved_pc;
   struct symtab_and_line sal;
@@ -1027,14 +1028,6 @@ elf_gnu_ifunc_resolver_return_stop (stru
 
   gdb_assert (b->type == bp_gnu_ifunc_resolver_return);
 
-  value = allocate_value (value_type);
-  gdbarch_return_value (gdbarch, func_func_type, value_type, regcache,
-			value_contents_raw (value), NULL);
-  resolved_address = value_as_address (value);
-  resolved_pc = gdbarch_convert_from_func_ptr_addr (gdbarch,
-						    resolved_address,
-						    &current_target);
-
   while (b->related_breakpoint != b)
     {
       struct breakpoint *b_next = b->related_breakpoint;
@@ -1055,6 +1048,18 @@ elf_gnu_ifunc_resolver_return_stop (stru
       b = b_next;
     }
   gdb_assert (b->type == bp_gnu_ifunc_resolver);
+  gdb_assert (b->loc->next == NULL);
+
+  func_func = allocate_value (func_func_type);
+  set_value_address (func_func, b->loc->related_address);
+
+  value = allocate_value (value_type);
+  gdbarch_return_value (gdbarch, func_func, value_type, regcache,
+			value_contents_raw (value), NULL);
+  resolved_address = value_as_address (value);
+  resolved_pc = gdbarch_convert_from_func_ptr_addr (gdbarch,
+						    resolved_address,
+						    &current_target);
 
   gdb_assert (current_program_space == b->pspace || b->pspace == NULL);
   elf_gnu_ifunc_record_cache (b->addr_string, resolved_pc);
Index: gdb-fsf-trunk-quilt/gdb/inferior.h
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/inferior.h	2012-05-12 20:47:15.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/inferior.h	2012-05-12 20:47:29.785624940 +0100
@@ -266,7 +266,7 @@ extern void detach_command (char *, int)
 
 extern void notice_new_inferior (ptid_t, int, int);
 
-extern struct value *get_return_value (struct type *func_type,
+extern struct value *get_return_value (struct value *function,
                                        struct type *value_type);
 
 /* Address at which inferior stopped.  */
Index: gdb-fsf-trunk-quilt/gdb/python/py-finishbreakpoint.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/python/py-finishbreakpoint.c	2012-05-12 16:35:27.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/python/py-finishbreakpoint.c	2012-05-12 20:47:29.785624940 +0100
@@ -29,6 +29,7 @@
 #include "language.h"
 #include "observer.h"
 #include "inferior.h"
+#include "block.h"
 
 static PyTypeObject finish_breakpoint_object_type;
 
@@ -45,9 +46,9 @@ struct finish_breakpoint_object
      May be NULL if no debug information was available or return type
      was VOID.  */
   PyObject *return_type;
-  /* gdb.Type object of the function finished by this breakpoint.  Will be
+  /* gdb.Value object of the function finished by this breakpoint.  Will be
      NULL if return_type is NULL.  */
-  PyObject *function_type;
+  PyObject *function_value;
   /* When stopped at this FinishBreakpoint, gdb.Value object returned by
      the function; Py_None if the value is not computable; NULL if GDB is
      not stopped at a FinishBreakpoint.  */
@@ -78,7 +79,7 @@ bpfinishpy_dealloc (PyObject *self)
   struct finish_breakpoint_object *self_bpfinish =
         (struct finish_breakpoint_object *) self;
 
-  Py_XDECREF (self_bpfinish->function_type);
+  Py_XDECREF (self_bpfinish->function_value);
   Py_XDECREF (self_bpfinish->return_type);
   Py_XDECREF (self_bpfinish->return_value);
 }
@@ -102,9 +103,11 @@ bpfinishpy_pre_stop_hook (struct breakpo
 
   TRY_CATCH (except, RETURN_MASK_ALL)
     {
-      struct value *ret =
-          get_return_value (type_object_to_type (self_finishbp->function_type),
-                            type_object_to_type (self_finishbp->return_type));
+      struct value *function =
+        value_object_to_value (self_finishbp->function_value);
+      struct type *value_type =
+        type_object_to_type (self_finishbp->return_type);
+      struct value *ret = get_return_value (function, value_type);
 
       if (ret)
         {
@@ -233,7 +236,7 @@ bpfinishpy_init (PyObject *self, PyObjec
 
   /* Find the function we will return from.  */
   self_bpfinish->return_type = NULL;
-  self_bpfinish->function_type = NULL;
+  self_bpfinish->function_value = NULL;
 
   TRY_CATCH (except, RETURN_MASK_ALL)
     {
@@ -248,25 +251,28 @@ bpfinishpy_init (PyObject *self, PyObjec
               /* Remember only non-void return types.  */
               if (TYPE_CODE (ret_type) != TYPE_CODE_VOID)
                 {
+                  struct value *func_value;
+
                   /* Ignore Python errors at this stage.  */
                   self_bpfinish->return_type = type_to_type_object (ret_type);
                   PyErr_Clear ();
-                  self_bpfinish->function_type =
-                      type_to_type_object (SYMBOL_TYPE (function));
+                  func_value = read_var_value (function, frame);
+                  self_bpfinish->function_value =
+                      value_to_value_object (func_value);
                   PyErr_Clear ();
                 }
             }
         }
     }
   if (except.reason < 0
-      || !self_bpfinish->return_type || !self_bpfinish->function_type)
+      || !self_bpfinish->return_type || !self_bpfinish->function_value)
     {
       /* Won't be able to compute return value.  */
       Py_XDECREF (self_bpfinish->return_type);
-      Py_XDECREF (self_bpfinish->function_type);
+      Py_XDECREF (self_bpfinish->function_value);
 
       self_bpfinish->return_type = NULL;
-      self_bpfinish->function_type = NULL;
+      self_bpfinish->function_value = NULL;
     }
 
   bppy_pending_object = &self_bpfinish->py_bp;
Index: gdb-fsf-trunk-quilt/gdb/testsuite/gdb.base/return-nodebug.exp
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/testsuite/gdb.base/return-nodebug.exp	2012-05-12 16:35:27.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/testsuite/gdb.base/return-nodebug.exp	2012-05-12 20:47:29.785624940 +0100
@@ -41,7 +41,7 @@ proc do_test {type} {
     }
 }
 
-foreach type {{signed char} {short} {int} {long} {long long}} {
+foreach type {{signed char} {short} {int} {long} {long long} {float} {double}} {
     set typeesc [string map {{ } {\ }} $type]
     set typenospace [string map {{ } -} $type]
 
Index: gdb-fsf-trunk-quilt/gdb/amd64-windows-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/amd64-windows-tdep.c	2012-05-12 16:35:27.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/amd64-windows-tdep.c	2012-05-12 20:47:29.785624940 +0100
@@ -73,7 +73,7 @@ amd64_windows_classify (struct type *typ
 /* Implement the "return_value" gdbarch method for amd64-windows.  */
 
 static enum return_value_convention
-amd64_windows_return_value (struct gdbarch *gdbarch, struct type *func_type,
+amd64_windows_return_value (struct gdbarch *gdbarch, struct value *function,
 			    struct type *type, struct regcache *regcache,
 			    gdb_byte *readbuf, const gdb_byte *writebuf)
 {
Index: gdb-fsf-trunk-quilt/gdb/avr-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/avr-tdep.c	2012-05-12 16:35:27.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/avr-tdep.c	2012-05-12 20:47:29.785624940 +0100
@@ -902,7 +902,7 @@ avr_breakpoint_from_pc (struct gdbarch *
    from WRITEBUF into REGCACHE.  */
 
 static enum return_value_convention
-avr_return_value (struct gdbarch *gdbarch, struct type *func_type,
+avr_return_value (struct gdbarch *gdbarch, struct value *function,
 		  struct type *valtype, struct regcache *regcache,
 		  gdb_byte *readbuf, const gdb_byte *writebuf)
 {
Index: gdb-fsf-trunk-quilt/gdb/microblaze-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/microblaze-tdep.c	2012-05-12 16:35:27.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/microblaze-tdep.c	2012-05-12 20:47:29.785624940 +0100
@@ -612,7 +612,7 @@ microblaze_store_return_value (struct ty
 }
 
 static enum return_value_convention
-microblaze_return_value (struct gdbarch *gdbarch, struct type *func_type,
+microblaze_return_value (struct gdbarch *gdbarch, struct value *function,
 			 struct type *type, struct regcache *regcache,
 			 gdb_byte *readbuf, const gdb_byte *writebuf)
 {
Index: gdb-fsf-trunk-quilt/gdb/tic6x-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/tic6x-tdep.c	2012-05-12 16:35:27.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/tic6x-tdep.c	2012-05-12 20:47:29.785624940 +0100
@@ -821,7 +821,7 @@ tic6x_store_return_value (struct type *v
 /* This is the implementation of gdbarch method return_value.  */
 
 static enum return_value_convention
-tic6x_return_value (struct gdbarch *gdbarch, struct type *func_type,
+tic6x_return_value (struct gdbarch *gdbarch, struct value *function,
 		    struct type *type, struct regcache *regcache,
 		    gdb_byte *readbuf, const gdb_byte *writebuf)
 {
Index: gdb-fsf-trunk-quilt/gdb/bfin-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/bfin-tdep.c	2012-05-12 16:35:27.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/bfin-tdep.c	2012-05-12 20:47:29.785624940 +0100
@@ -663,7 +663,7 @@ bfin_store_return_value (struct type *ty
 
 static enum return_value_convention
 bfin_return_value (struct gdbarch *gdbarch,
-		   struct type *func_type,
+		   struct value *function,
 		   struct type *type,
 		   struct regcache *regcache,
 		   gdb_byte *readbuf,
Index: gdb-fsf-trunk-quilt/gdb/rl78-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/rl78-tdep.c	2012-05-12 16:35:27.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/rl78-tdep.c	2012-05-12 20:47:29.785624940 +0100
@@ -934,7 +934,7 @@ rl78_register_sim_regno (struct gdbarch 
 
 static enum return_value_convention
 rl78_return_value (struct gdbarch *gdbarch,
-		   struct type *func_type,
+		   struct value *function,
 		   struct type *valtype,
 		   struct regcache *regcache,
 		   gdb_byte *readbuf, const gdb_byte *writebuf)
Index: gdb-fsf-trunk-quilt/gdb/rx-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/rx-tdep.c	2012-05-12 16:35:27.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/rx-tdep.c	2012-05-12 20:47:29.785624940 +0100
@@ -702,7 +702,7 @@ rx_push_dummy_call (struct gdbarch *gdba
 /* Implement the "return_value" gdbarch method.  */
 static enum return_value_convention
 rx_return_value (struct gdbarch *gdbarch,
-		 struct type *func_type,
+		 struct value *function,
 		 struct type *valtype,
 		 struct regcache *regcache,
 		 gdb_byte *readbuf, const gdb_byte *writebuf)
Index: gdb-fsf-trunk-quilt/gdb/breakpoint.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/breakpoint.c	2012-05-12 16:35:27.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/breakpoint.c	2012-05-12 20:47:29.795624408 +0100
@@ -6586,9 +6586,10 @@ set_breakpoint_location_function (struct
     {
       int is_gnu_ifunc;
       const char *function_name;
+      CORE_ADDR func_addr;
 
       find_pc_partial_function_gnu_ifunc (loc->address, &function_name,
-					  NULL, NULL, &is_gnu_ifunc);
+					  &func_addr, NULL, &is_gnu_ifunc);
 
       if (is_gnu_ifunc && !explicit_loc)
 	{
@@ -6609,6 +6610,9 @@ set_breakpoint_location_function (struct
 	      /* Create only the whole new breakpoint of this type but do not
 		 mess more complicated breakpoints with multiple locations.  */
 	      b->type = bp_gnu_ifunc_resolver;
+	      /* Remember the resolver's address for use by the return
+	         breakpoint.  */
+	      loc->related_address = func_addr;
 	    }
 	}
 
Index: gdb-fsf-trunk-quilt/gdb/breakpoint.h
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/breakpoint.h	2012-05-12 16:35:27.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/breakpoint.h	2012-05-12 20:47:29.795624408 +0100
@@ -418,6 +418,11 @@ struct bp_location
      processor's architectual constraints.  */
   CORE_ADDR requested_address;
 
+  /* An additional address assigned with this location.  This is currently
+     only used by STT_GNU_IFUNC resolver breakpoints to hold the address
+     of the resolver function.  */
+  CORE_ADDR related_address;
+
   /* If the location comes from a probe point, this is the probe associated
      with it.  */
   struct probe *probe;


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFA] MIPS16 FP manual call/return fixes
  2012-05-14  9:12               ` Maciej W. Rozycki
@ 2012-05-14 11:54                 ` Jan Kratochvil
  2012-05-16 14:45                   ` Maciej W. Rozycki
  0 siblings, 1 reply; 15+ messages in thread
From: Jan Kratochvil @ 2012-05-14 11:54 UTC (permalink / raw)
  To: Maciej W. Rozycki; +Cc: Tom Tromey, gdb-patches, Sergio Durigan

On Mon, 14 May 2012 11:11:14 +0200, Maciej W. Rozycki wrote:
[ Mostly unrelated to this patch:  ]

> strictly speaking we can keep the structure flat if 
> we decide that complicating it is not worth the saving.

Technically yes but it is more readable to know this field is valid/used only
with this subclass.  And it is better not just to rely on unstructured
comments content.  And to give the field name its real meaning ("func_addr")
and not just a generic name of overload ("related").  A good example of these
overloaded generic fields without subclassing is main_type which is such as
mess I still have problems to fully understand it.


>  Actually, I relied on the lack of compilation errors so far; it seems 
> that while we do have -Wall -Werror, we have -Wno-unused as well which 
> implies -Wno-unused-variable and has defeated my assumptions.  Any 
> particular reason why we disable this warning?

Because there are now many such unused-variable cases needing to be fixed,
there were recent threads about it (see subject /unused/) by Sergio.
It looks still not all the cases are fixed to enable the warnings.


> > >  	      b->type = bp_gnu_ifunc_resolver;
> > 
> > Empty line before a comment according to GDB Coding Standards.
> > 
> > > +	      /* Remember the resolver's address for use by the return
[...]
>  I believe this requirement applies to function and variable/type/etc. 
> definitions only and I haven't seen this style applied inline in many 
> places (including the original comment above, actually).  Are you sure?

I find it more readable with the empty line even in this case.
You are right there are too many of such cases without empty line in GDB.
Therefore I do not mind, check it in either way.


Thanks,
Jan


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFA] MIPS16 FP manual call/return fixes
  2012-05-14 11:54                 ` Jan Kratochvil
@ 2012-05-16 14:45                   ` Maciej W. Rozycki
  0 siblings, 0 replies; 15+ messages in thread
From: Maciej W. Rozycki @ 2012-05-16 14:45 UTC (permalink / raw)
  To: Jan Kratochvil; +Cc: Tom Tromey, gdb-patches, Sergio Durigan

On Mon, 14 May 2012, Jan Kratochvil wrote:

> > strictly speaking we can keep the structure flat if 
> > we decide that complicating it is not worth the saving.
> 
> Technically yes but it is more readable to know this field is valid/used only
> with this subclass.  And it is better not just to rely on unstructured
> comments content.  And to give the field name its real meaning ("func_addr")
> and not just a generic name of overload ("related").  A good example of these
> overloaded generic fields without subclassing is main_type which is such as
> mess I still have problems to fully understand it.

 Yes, I can't disagree, common sense applies.

> >  Actually, I relied on the lack of compilation errors so far; it seems 
> > that while we do have -Wall -Werror, we have -Wno-unused as well which 
> > implies -Wno-unused-variable and has defeated my assumptions.  Any 
> > particular reason why we disable this warning?
> 
> Because there are now many such unused-variable cases needing to be fixed,
> there were recent threads about it (see subject /unused/) by Sergio.
> It looks still not all the cases are fixed to enable the warnings.

 Hmm, fair enough, I wonder if we could take -Wno-unused out in the 
maintainer's mode so as to prompt people to fix their bugs?

> > > >  	      b->type = bp_gnu_ifunc_resolver;
> > > 
> > > Empty line before a comment according to GDB Coding Standards.
> > > 
> > > > +	      /* Remember the resolver's address for use by the return
> [...]
> >  I believe this requirement applies to function and variable/type/etc. 
> > definitions only and I haven't seen this style applied inline in many 
> > places (including the original comment above, actually).  Are you sure?
> 
> I find it more readable with the empty line even in this case.
> You are right there are too many of such cases without empty line in GDB.
> Therefore I do not mind, check it in either way.

 I think common sense applies again, I often find these extra empty lines 
disturbing with small comments, but larger ones definitely do need this 
extra space so that they do not obscure actual code.

 Anyway, 48 hours have passed with no further comments, so I have 
committed this change now, as posted.  If anything that was missed by 
chance pops out, then we can address it with a follow-up change.

 Thanks to everybody involved.

  Maciej


^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2012-05-16 14:45 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-04-23 13:30 [RFA] MIPS16 FP manual call/return fixes Maciej W. Rozycki
2012-04-26 19:20 ` Tom Tromey
2012-04-26 22:23   ` Maciej W. Rozycki
2012-04-27 15:16     ` Maciej W. Rozycki
2012-04-27 15:28       ` Tom Tromey
2012-04-26 19:33 ` Tom Tromey
2012-04-30 23:45   ` Maciej W. Rozycki
2012-05-01 14:05     ` Jan Kratochvil
2012-05-01 17:22       ` Maciej W. Rozycki
2012-05-02 21:28         ` Jan Kratochvil
2012-05-08 14:30           ` Maciej W. Rozycki
2012-05-12 19:38             ` Jan Kratochvil
2012-05-14  9:12               ` Maciej W. Rozycki
2012-05-14 11:54                 ` Jan Kratochvil
2012-05-16 14:45                   ` Maciej W. Rozycki

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox