[PATCH v4 0/3] Aarch64: Fix segfault when casting dummy calls

classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

[PATCH v4 0/3] Aarch64: Fix segfault when casting dummy calls

Alan Hayward
This version cleans up a few things and includes a very different testcase.

The following will segfault on aarch64 if foo is in another object,
was compiled as c++ and has no debug symbols:
(gdb) p (int)foo()

The fix is to remove a bunch of code from aarch64_push_dummy_call,
instead passing down the information from the caller.

Patch 1 removes two ints from call_function_by_hand_dummy, replacing
them with an enum.
Patch 2 passes that enum down to _push_dummy_call.
Patch 3 makes use of the enum in aarch64_push_dummy_call and adds a
test case.

Tested with make check on aarch64 and build with all targets on x86.
Patch 2 needs a careful scan to make sure it doesn't break any other
targets.


Alan Hayward (3):
  Use enum for return method for dummy calls
  Pass return_method to _push_dummy_call
  Aarch64: Fix segfault when casting dummy calls

 gdb/aarch64-tdep.c                            |  35 +----
 gdb/alpha-tdep.c                              |   7 +-
 gdb/amd64-tdep.c                              |  13 +-
 gdb/amd64-windows-tdep.c                      |  12 +-
 gdb/arc-tdep.c                                |   5 +-
 gdb/arm-tdep.c                                |   5 +-
 gdb/avr-tdep.c                                |   5 +-
 gdb/bfin-tdep.c                               |   4 +-
 gdb/cris-tdep.c                               |   9 +-
 gdb/csky-tdep.c                               |   5 +-
 gdb/frv-tdep.c                                |   5 +-
 gdb/gdbarch.c                                 |   4 +-
 gdb/gdbarch.h                                 |  27 +++-
 gdb/gdbarch.sh                                |  25 +++-
 gdb/h8300-tdep.c                              |   5 +-
 gdb/hppa-tdep.c                               |  10 +-
 gdb/i386-darwin-tdep.c                        |   5 +-
 gdb/i386-tdep.c                               |   5 +-
 gdb/ia64-tdep.c                               |  11 +-
 gdb/infcall.c                                 |  28 ++--
 gdb/iq2000-tdep.c                             |   9 +-
 gdb/lm32-tdep.c                               |   5 +-
 gdb/m32c-tdep.c                               |   5 +-
 gdb/m32r-tdep.c                               |   5 +-
 gdb/m68hc11-tdep.c                            |   9 +-
 gdb/m68k-tdep.c                               |   5 +-
 gdb/mep-tdep.c                                |   4 +-
 gdb/mips-tdep.c                               |  19 +--
 gdb/mn10300-tdep.c                            |   6 +-
 gdb/msp430-tdep.c                             |   5 +-
 gdb/nds32-tdep.c                              |   5 +-
 gdb/nios2-tdep.c                              |   5 +-
 gdb/or1k-tdep.c                               |   5 +-
 gdb/ppc-sysv-tdep.c                           |  10 +-
 gdb/ppc-tdep.h                                |  25 ++--
 gdb/riscv-tdep.c                              |   8 +-
 gdb/rl78-tdep.c                               |   5 +-
 gdb/rs6000-aix-tdep.c                         |   5 +-
 gdb/rs6000-lynx178-tdep.c                     |   5 +-
 gdb/rx-tdep.c                                 |   8 +-
 gdb/s390-tdep.c                               |   7 +-
 gdb/score-tdep.c                              |   5 +-
 gdb/sh-tdep.c                                 |   9 +-
 gdb/sparc-tdep.c                              |  15 +-
 gdb/sparc64-tdep.c                            |  14 +-
 gdb/spu-tdep.c                                |   5 +-
 .../gdb.base/infcall-across-obj-lib.c         |  22 +++
 .../gdb.base/infcall-across-obj-main.c        |  24 ++++
 gdb/testsuite/gdb.base/infcall-across-obj.exp | 134 ++++++++++++++++++
 gdb/tic6x-tdep.c                              |   5 +-
 gdb/tilegx-tdep.c                             |   4 +-
 gdb/v850-tdep.c                               |   4 +-
 gdb/vax-tdep.c                                |   5 +-
 gdb/xstormy16-tdep.c                          |   9 +-
 gdb/xtensa-tdep.c                             |  10 +-
 55 files changed, 442 insertions(+), 208 deletions(-)
 create mode 100644 gdb/testsuite/gdb.base/infcall-across-obj-lib.c
 create mode 100644 gdb/testsuite/gdb.base/infcall-across-obj-main.c
 create mode 100644 gdb/testsuite/gdb.base/infcall-across-obj.exp

--
2.17.1 (Apple Git-112)

Reply | Threaded
Open this post in threaded view
|

[PATCH v4 1/3] Use enum for return method for dummy calls

Alan Hayward
In call_function_by_hand_dummy, struct_return and hidden_first_param_p
are used to represent a single concept. Replace with an enum.

gdb/ChangeLog:

2018-10-31  Alan Hayward  <[hidden email]>

        * gdbarch.sh (enum function_call_return_method): Add enum.
        * gdbarch.h: Regenerate.
        * infcall.c (call_function_by_hand_dummy): Replace vars with enum.
---
 gdb/gdbarch.h  | 23 +++++++++++++++++++++++
 gdb/gdbarch.sh | 23 +++++++++++++++++++++++
 gdb/infcall.c  | 29 +++++++++++------------------
 3 files changed, 57 insertions(+), 18 deletions(-)

diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h
index 2cb6961083..e8e35fbd01 100644
--- a/gdb/gdbarch.h
+++ b/gdb/gdbarch.h
@@ -102,6 +102,29 @@ typedef void (iterate_over_regset_sections_cb)
   (const char *sect_name, int supply_size, int collect_size,
    const struct regset *regset, const char *human_name, void *cb_data);
 
+/* For a function call, does the function return a value using a
+   normal value return or a structure return - passing a hidden
+   argument pointing to storage.  For the latter, there are two
+   cases: language-mandated structure return and target ABI
+   structure return.  */
+
+enum function_call_return_method
+{
+  /* Standard value return.  */
+  return_method_normal = 0,
+
+  /* Language ABI structure return.  This is handled
+     by passing the return location as the first parameter to
+     the function, even preceding "this".  */
+  return_method_hidden_param,
+
+  /* Target ABI struct return.  This is target-specific; for instance,
+     on ia64 the first argument is passed in out0 but the hidden
+     structure return pointer would normally be passed in r8.  */
+  return_method_struct,
+};
+
+
 
 /* The following are pre-initialized by GDBARCH.  */
 
diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh
index bbfa8d2205..1e895c3b7a 100755
--- a/gdb/gdbarch.sh
+++ b/gdb/gdbarch.sh
@@ -1327,6 +1327,29 @@ typedef int (iterate_over_objfiles_in_search_order_cb_ftype)
 typedef void (iterate_over_regset_sections_cb)
   (const char *sect_name, int supply_size, int collect_size,
    const struct regset *regset, const char *human_name, void *cb_data);
+
+/* For a function call, does the function return a value using a
+   normal value return or a structure return - passing a hidden
+   argument pointing to storage.  For the latter, there are two
+   cases: language-mandated structure return and target ABI
+   structure return.  */
+
+enum function_call_return_method
+{
+  /* Standard value return.  */
+  return_method_normal = 0,
+
+  /* Language ABI structure return.  This is handled
+     by passing the return location as the first parameter to
+     the function, even preceding "this".  */
+  return_method_hidden_param,
+
+  /* Target ABI struct return.  This is target-specific; for instance,
+     on ia64 the first argument is passed in out0 but the hidden
+     structure return pointer would normally be passed in r8.  */
+  return_method_struct,
+};
+
 EOF
 
 # function typedef's
diff --git a/gdb/infcall.c b/gdb/infcall.c
index 96d43704fa..0c875ea4b9 100644
--- a/gdb/infcall.c
+++ b/gdb/infcall.c
@@ -719,7 +719,7 @@ call_function_by_hand_dummy (struct value *function,
 {
   CORE_ADDR sp;
   struct type *target_values_type;
-  unsigned char struct_return = 0, hidden_first_param_p = 0;
+  function_call_return_method return_method = return_method_normal;
   CORE_ADDR struct_addr = 0;
   CORE_ADDR real_pc;
   CORE_ADDR bp_addr;
@@ -876,20 +876,11 @@ call_function_by_hand_dummy (struct value *function,
 
   values_type = check_typedef (values_type);
 
-  /* Are we returning a value using a structure return (passing a
-     hidden argument pointing to storage) or a normal value return?
-     There are two cases: language-mandated structure return and
-     target ABI structure return.  The variable STRUCT_RETURN only
-     describes the latter.  The language version is handled by passing
-     the return location as the first parameter to the function,
-     even preceding "this".  This is different from the target
-     ABI version, which is target-specific; for instance, on ia64
-     the first argument is passed in out0 but the hidden structure
-     return pointer would normally be passed in r8.  */
+  /* Are we returning a value using a structure return?  */
 
   if (gdbarch_return_in_first_hidden_param_p (gdbarch, values_type))
     {
-      hidden_first_param_p = 1;
+      return_method = return_method_hidden_param;
 
       /* Tell the target specific argument pushing routine not to
  expect a value.  */
@@ -897,7 +888,8 @@ call_function_by_hand_dummy (struct value *function,
     }
   else
     {
-      struct_return = using_struct_return (gdbarch, function, values_type);
+      if (using_struct_return (gdbarch, function, values_type))
+ return_method = return_method_struct;
       target_values_type = values_type;
     }
 
@@ -1020,7 +1012,7 @@ call_function_by_hand_dummy (struct value *function,
      is being evaluated is OK because the thread is stopped until the
      expression is completely evaluated.  */
 
-  if (struct_return || hidden_first_param_p
+  if (return_method != return_method_normal
       || (stack_temporaries && class_or_union_p (values_type)))
     {
       if (gdbarch_inner_than (gdbarch, 1, 2))
@@ -1046,7 +1038,7 @@ call_function_by_hand_dummy (struct value *function,
     }
 
   std::vector<struct value *> new_args;
-  if (hidden_first_param_p)
+  if (return_method == return_method_hidden_param)
     {
       /* Add the new argument to the front of the argument list.  */
       new_args.push_back
@@ -1060,8 +1052,9 @@ call_function_by_hand_dummy (struct value *function,
      presumably, the ABI code knows where, in the call dummy, the
      return address should be pointed.  */
   sp = gdbarch_push_dummy_call (gdbarch, function, get_current_regcache (),
- bp_addr, nargs, args,
- sp, struct_return, struct_addr);
+ bp_addr, nargs, args, sp,
+ (return_method == return_method_struct),
+ struct_addr);
 
   /* Set up a frame ID for the dummy frame so we can pass it to
      set_momentary_breakpoint.  We need to give the breakpoint a frame
@@ -1157,7 +1150,7 @@ call_function_by_hand_dummy (struct value *function,
     sm = new_call_thread_fsm (current_ui, command_interp (),
       gdbarch, function,
       values_type,
-      struct_return || hidden_first_param_p,
+      return_method != return_method_normal,
       struct_addr);
 
     e = run_inferior_call (sm, call_thread.get (), real_pc);
--
2.17.1 (Apple Git-112)

Reply | Threaded
Open this post in threaded view
|

[PATCH v4 2/3] Pass return_method to _push_dummy_call

Alan Hayward
In reply to this post by Alan Hayward
gdb/ChangeLog:

2018-10-31  Alan Hayward  <[hidden email]>

        * aarch64-tdep.c (aarch64_push_dummy_call): Replace arg with
        return_method.
        * alpha-tdep.c (alpha_push_dummy_call): Likewise.
        * amd64-tdep.c (amd64_push_arguments): Likewise.
        (amd64_push_dummy_call): Likewise.
        * amd64-windows-tdep.c (amd64_windows_push_arguments): Likewise.
        * arc-tdep.c (arc_push_dummy_call): Likewise.
        * arm-tdep.c (arm_push_dummy_call): Likewise.
        * avr-tdep.c (avr_push_dummy_call): Likewise.
        * bfin-tdep.c (bfin_push_dummy_call): Likewise.
        * cris-tdep.c (cris_push_dummy_call): Likewise.
        * csky-tdep.c (csky_push_dummy_call): Likewise.
        * frv-tdep.c (frv_push_dummy_call): Likewise.
        * gdbarch.c: Regenerate.
        * gdbarch.h: Regenerate.
        * gdbarch.sh (gdbarch_push_dummy_call): Replace arg with
        return_method.
        * h8300-tdep.c (h8300_push_dummy_call): Likewise.
        * hppa-tdep.c (hppa32_push_dummy_call): Likewise.
        (hppa64_push_dummy_call): Likewise.
        * i386-darwin-tdep.c (i386_darwin_push_dummy_call): Likewise.
        * i386-tdep.c (i386_push_dummy_call): Likewise.
        * ia64-tdep.c (ia64_push_dummy_call): Likewise.
        * infcall.c (call_function_by_hand_dummy): Likewise.
        * iq2000-tdep.c (iq2000_push_dummy_call): Likewise.
        * lm32-tdep.c (lm32_push_dummy_call): Likewise.
        * m32c-tdep.c (m32c_push_dummy_call): Likewise.
        * m32r-tdep.c (m32r_push_dummy_call): Likewise.
        * m68hc11-tdep.c (m68hc11_push_dummy_call): Likewise.
        * m68k-tdep.c (m68k_push_dummy_call): Likewise.
        * mep-tdep.c (mep_push_dummy_call): Likewise.
        * mips-tdep.c (mips_eabi_push_dummy_call): Likewise.
        (mips_n32n64_push_dummy_call): Likewise.
        (mips_o32_push_dummy_call): Likewise.
        (mips_o64_push_dummy_call): Likewise.
        * mn10300-tdep.c (mn10300_push_dummy_call): Likewise.
        * msp430-tdep.c (msp430_push_dummy_call): Likewise.
        * nds32-tdep.c (nds32_push_dummy_call): Likewise.
        * nios2-tdep.c (nios2_push_dummy_call): Likewise.
        * or1k-tdep.c (or1k_push_dummy_call): Likewise.
        * ppc-sysv-tdep.c (ppc_sysv_abi_push_dummy_call): Likewise.
        (ppc64_sysv_abi_push_dummy_call): Likewise.
        * ppc-tdep.h (ppc_sysv_abi_push_dummy_call): Likewise.
        (ppc64_sysv_abi_push_dummy_call): Likewise.
        * riscv-tdep.c (riscv_push_dummy_call): Likewise.
        * rl78-tdep.c (rl78_push_dummy_call): Likewise.
        * rs6000-aix-tdep.c (rs6000_push_dummy_call): Likewise.
        * rs6000-lynx178-tdep.c (rs6000_lynx178_push_dummy_call): Likewise.
        * rx-tdep.c (rx_push_dummy_call): Likewise.
        * s390-tdep.c (s390_push_dummy_call): Likewise.
        * score-tdep.c (score_push_dummy_call): Likewise.
        * sh-tdep.c (sh_push_dummy_call_fpu): Likewise.
        (sh_push_dummy_call_nofpu): Likewise.
        * sparc-tdep.c (sparc32_store_arguments): Likewise.
        (sparc32_push_dummy_call): Likewise.
        * sparc64-tdep.c (sparc64_store_arguments): Likewise.
        (sparc64_push_dummy_call): Likewise.
        * spu-tdep.c (spu_push_dummy_call): Likewise.
        * tic6x-tdep.c (tic6x_push_dummy_call): Likewise.
        * tilegx-tdep.c (tilegx_push_dummy_call): Likewise.
        * v850-tdep.c (v850_push_dummy_call): Likewise.
        * vax-tdep.c (vax_push_dummy_call): Likewise.
        * xstormy16-tdep.c (xstormy16_push_dummy_call): Likewise.
        * xtensa-tdep.c (xtensa_push_dummy_call): Likewise.
---
 gdb/aarch64-tdep.c        |  5 +++--
 gdb/alpha-tdep.c          |  7 ++++---
 gdb/amd64-tdep.c          | 13 +++++++------
 gdb/amd64-windows-tdep.c  | 12 ++++++------
 gdb/arc-tdep.c            |  5 +++--
 gdb/arm-tdep.c            |  5 +++--
 gdb/avr-tdep.c            |  5 +++--
 gdb/bfin-tdep.c           |  4 ++--
 gdb/cris-tdep.c           |  9 ++++-----
 gdb/csky-tdep.c           |  5 +++--
 gdb/frv-tdep.c            |  5 +++--
 gdb/gdbarch.c             |  4 ++--
 gdb/gdbarch.h             |  4 ++--
 gdb/gdbarch.sh            |  2 +-
 gdb/h8300-tdep.c          |  5 +++--
 gdb/hppa-tdep.c           | 10 ++++++----
 gdb/i386-darwin-tdep.c    |  5 +++--
 gdb/i386-tdep.c           |  5 +++--
 gdb/ia64-tdep.c           | 11 +++++------
 gdb/infcall.c             |  3 +--
 gdb/iq2000-tdep.c         |  9 ++++++---
 gdb/lm32-tdep.c           |  5 +++--
 gdb/m32c-tdep.c           |  5 +++--
 gdb/m32r-tdep.c           |  5 +++--
 gdb/m68hc11-tdep.c        |  9 ++++-----
 gdb/m68k-tdep.c           |  5 +++--
 gdb/mep-tdep.c            |  4 ++--
 gdb/mips-tdep.c           | 19 +++++++++++--------
 gdb/mn10300-tdep.c        |  6 +++---
 gdb/msp430-tdep.c         |  5 +++--
 gdb/nds32-tdep.c          |  5 +++--
 gdb/nios2-tdep.c          |  5 +++--
 gdb/or1k-tdep.c           |  5 +++--
 gdb/ppc-sysv-tdep.c       | 10 ++++++----
 gdb/ppc-tdep.h            | 25 +++++++++++--------------
 gdb/riscv-tdep.c          |  8 ++++----
 gdb/rl78-tdep.c           |  5 +++--
 gdb/rs6000-aix-tdep.c     |  5 +++--
 gdb/rs6000-lynx178-tdep.c |  5 +++--
 gdb/rx-tdep.c             |  8 +++++---
 gdb/s390-tdep.c           |  7 ++++---
 gdb/score-tdep.c          |  5 +++--
 gdb/sh-tdep.c             |  9 +++++----
 gdb/sparc-tdep.c          | 15 +++++++++------
 gdb/sparc64-tdep.c        | 14 ++++++++------
 gdb/spu-tdep.c            |  5 +++--
 gdb/tic6x-tdep.c          |  5 +++--
 gdb/tilegx-tdep.c         |  4 ++--
 gdb/v850-tdep.c           |  4 ++--
 gdb/vax-tdep.c            |  5 +++--
 gdb/xstormy16-tdep.c      |  9 +++++----
 gdb/xtensa-tdep.c         | 10 +++++-----
 52 files changed, 204 insertions(+), 165 deletions(-)

diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c
index 023e8eb453..efab925067 100644
--- a/gdb/aarch64-tdep.c
+++ b/gdb/aarch64-tdep.c
@@ -1513,7 +1513,8 @@ static CORE_ADDR
 aarch64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
  struct regcache *regcache, CORE_ADDR bp_addr,
  int nargs,
- struct value **args, CORE_ADDR sp, int struct_return,
+ struct value **args, CORE_ADDR sp,
+ function_call_return_method return_method,
  CORE_ADDR struct_addr)
 {
   int argnum;
@@ -1577,7 +1578,7 @@ aarch64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
     }
 
   /* The struct_return pointer occupies X8.  */
-  if (struct_return || lang_struct_return)
+  if (return_method == return_method_struct || lang_struct_return)
     {
       if (aarch64_debug)
  {
diff --git a/gdb/alpha-tdep.c b/gdb/alpha-tdep.c
index e649bd2102..91bbe06ebf 100644
--- a/gdb/alpha-tdep.c
+++ b/gdb/alpha-tdep.c
@@ -295,11 +295,12 @@ static CORE_ADDR
 alpha_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
        struct regcache *regcache, CORE_ADDR bp_addr,
        int nargs, struct value **args, CORE_ADDR sp,
-       int struct_return, CORE_ADDR struct_addr)
+       function_call_return_method return_method,
+       CORE_ADDR struct_addr)
 {
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
   int i;
-  int accumulate_size = struct_return ? 8 : 0;
+  int accumulate_size = (return_method == return_method_struct) ? 8 : 0;
   struct alpha_arg
     {
       const gdb_byte *contents;
@@ -446,7 +447,7 @@ alpha_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
       /* Everything else goes to the stack.  */
       write_memory (sp + offset - sizeof(arg_reg_buffer), contents, len);
     }
-  if (struct_return)
+  if (return_method == return_method_struct)
     store_unsigned_integer (arg_reg_buffer, ALPHA_REGISTER_SIZE,
     byte_order, struct_addr);
 
diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c
index abf3e4d919..614b6fdd07 100644
--- a/gdb/amd64-tdep.c
+++ b/gdb/amd64-tdep.c
@@ -861,8 +861,8 @@ amd64_return_value (struct gdbarch *gdbarch, struct value *function,
 
 
 static CORE_ADDR
-amd64_push_arguments (struct regcache *regcache, int nargs,
-      struct value **args, CORE_ADDR sp, int struct_return)
+amd64_push_arguments (struct regcache *regcache, int nargs, struct value **args,
+      CORE_ADDR sp, function_call_return_method return_method)
 {
   static int integer_regnum[] =
   {
@@ -890,7 +890,7 @@ amd64_push_arguments (struct regcache *regcache, int nargs,
   int i;
 
   /* Reserve a register for the "hidden" argument.  */
-  if (struct_return)
+if (return_method == return_method_struct)
     integer_reg++;
 
   for (i = 0; i < nargs; i++)
@@ -996,7 +996,8 @@ static CORE_ADDR
 amd64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
        struct regcache *regcache, CORE_ADDR bp_addr,
        int nargs, struct value **args, CORE_ADDR sp,
-       int struct_return, CORE_ADDR struct_addr)
+       function_call_return_method return_method,
+       CORE_ADDR struct_addr)
 {
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
   gdb_byte buf[8];
@@ -1009,10 +1010,10 @@ amd64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
   i387_reset_bnd_regs (gdbarch, regcache);
 
   /* Pass arguments.  */
-  sp = amd64_push_arguments (regcache, nargs, args, sp, struct_return);
+  sp = amd64_push_arguments (regcache, nargs, args, sp, return_method);
 
   /* Pass "hidden" argument".  */
-  if (struct_return)
+  if (return_method == return_method_struct)
     {
       store_unsigned_integer (buf, 8, byte_order, struct_addr);
       regcache->cooked_write (AMD64_RDI_REGNUM, buf);
diff --git a/gdb/amd64-windows-tdep.c b/gdb/amd64-windows-tdep.c
index 904875bacc..9eedbde17d 100644
--- a/gdb/amd64-windows-tdep.c
+++ b/gdb/amd64-windows-tdep.c
@@ -157,7 +157,7 @@ amd64_windows_store_arg_in_reg (struct regcache *regcache,
 static CORE_ADDR
 amd64_windows_push_arguments (struct regcache *regcache, int nargs,
       struct value **args, CORE_ADDR sp,
-      int struct_return)
+      function_call_return_method return_method)
 {
   int reg_idx = 0;
   int i;
@@ -180,7 +180,7 @@ amd64_windows_push_arguments (struct regcache *regcache, int nargs,
   }
 
   /* Reserve a register for the "hidden" argument.  */
-  if (struct_return)
+  if (return_method == return_method_struct)
     reg_idx++;
 
   for (i = 0; i < nargs; i++)
@@ -244,18 +244,18 @@ static CORE_ADDR
 amd64_windows_push_dummy_call
   (struct gdbarch *gdbarch, struct value *function,
    struct regcache *regcache, CORE_ADDR bp_addr,
-   int nargs, struct value **args,
-   CORE_ADDR sp, int struct_return, CORE_ADDR struct_addr)
+   int nargs, struct value **args, CORE_ADDR sp,
+   function_call_return_method return_method, CORE_ADDR struct_addr)
 {
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
   gdb_byte buf[8];
 
   /* Pass arguments.  */
   sp = amd64_windows_push_arguments (regcache, nargs, args, sp,
-     struct_return);
+     return_method);
 
   /* Pass "hidden" argument".  */
-  if (struct_return)
+  if (return_method == return_method_struct)
     {
       /* The "hidden" argument is passed throught the first argument
          register.  */
diff --git a/gdb/arc-tdep.c b/gdb/arc-tdep.c
index b9dcbbc1e5..c3c7839520 100644
--- a/gdb/arc-tdep.c
+++ b/gdb/arc-tdep.c
@@ -592,7 +592,8 @@ arc_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
 static CORE_ADDR
 arc_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
      struct regcache *regcache, CORE_ADDR bp_addr, int nargs,
-     struct value **args, CORE_ADDR sp, int struct_return,
+     struct value **args, CORE_ADDR sp,
+     function_call_return_method return_method,
      CORE_ADDR struct_addr)
 {
   if (arc_debug)
@@ -607,7 +608,7 @@ arc_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
      value return?  If so, struct_addr is the address of the reserved space for
      the return structure to be written on the stack, and that address is
      passed to that function as a hidden first argument.  */
-  if (struct_return)
+  if (return_method == return_method_struct)
     {
       /* Pass the return address in the first argument register.  */
       regcache_cooked_write_unsigned (regcache, arg_reg, struct_addr);
diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c
index 53eee76926..c8d96498e7 100644
--- a/gdb/arm-tdep.c
+++ b/gdb/arm-tdep.c
@@ -3679,7 +3679,8 @@ arm_vfp_abi_for_function (struct gdbarch *gdbarch, struct type *func_type)
 static CORE_ADDR
 arm_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
      struct regcache *regcache, CORE_ADDR bp_addr, int nargs,
-     struct value **args, CORE_ADDR sp, int struct_return,
+     struct value **args, CORE_ADDR sp,
+     function_call_return_method return_method,
      CORE_ADDR struct_addr)
 {
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
@@ -3714,7 +3715,7 @@ arm_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
 
   /* The struct_return pointer occupies the first parameter
      passing register.  */
-  if (struct_return)
+  if (return_method == return_method_struct)
     {
       if (arm_debug)
  fprintf_unfiltered (gdb_stdlog, "struct return in %s = %s\n",
diff --git a/gdb/avr-tdep.c b/gdb/avr-tdep.c
index 9e14007fc0..b70f06e27a 100644
--- a/gdb/avr-tdep.c
+++ b/gdb/avr-tdep.c
@@ -1263,7 +1263,8 @@ static CORE_ADDR
 avr_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
                      struct regcache *regcache, CORE_ADDR bp_addr,
                      int nargs, struct value **args, CORE_ADDR sp,
-                     int struct_return, CORE_ADDR struct_addr)
+     function_call_return_method return_method,
+     CORE_ADDR struct_addr)
 {
   int i;
   gdb_byte buf[3];
@@ -1272,7 +1273,7 @@ avr_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
   int regnum = AVR_ARGN_REGNUM;
   struct stack_item *si = NULL;
 
-  if (struct_return)
+  if (return_method == return_method_struct)
     {
       regcache_cooked_write_unsigned
         (regcache, regnum--, (struct_addr >> 8) & 0xff);
diff --git a/gdb/bfin-tdep.c b/gdb/bfin-tdep.c
index c84625c894..b064a6cef9 100644
--- a/gdb/bfin-tdep.c
+++ b/gdb/bfin-tdep.c
@@ -498,7 +498,7 @@ bfin_push_dummy_call (struct gdbarch *gdbarch,
       int nargs,
       struct value **args,
       CORE_ADDR sp,
-      int struct_return,
+      function_call_return_method return_method,
       CORE_ADDR struct_addr)
 {
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
@@ -543,7 +543,7 @@ bfin_push_dummy_call (struct gdbarch *gdbarch,
 
   /* Store struct value address.  */
 
-  if (struct_return)
+  if (return_method == return_method_struct)
     regcache_cooked_write_unsigned (regcache, BFIN_P0_REGNUM, struct_addr);
 
   /* Set the dummy return value to bp_addr.
diff --git a/gdb/cris-tdep.c b/gdb/cris-tdep.c
index e0371a2a28..f9fdd86a3c 100644
--- a/gdb/cris-tdep.c
+++ b/gdb/cris-tdep.c
@@ -808,7 +808,8 @@ static CORE_ADDR
 cris_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
       struct regcache *regcache, CORE_ADDR bp_addr,
       int nargs, struct value **args, CORE_ADDR sp,
-      int struct_return, CORE_ADDR struct_addr)
+      function_call_return_method return_method,
+      CORE_ADDR struct_addr)
 {
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
   int argreg;
@@ -822,10 +823,8 @@ cris_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
   /* Are we returning a value using a structure return or a normal value
      return?  struct_addr is the address of the reserved space for the return
      structure to be written on the stack.  */
-  if (struct_return)
-    {
-      regcache_cooked_write_unsigned (regcache, STR_REGNUM, struct_addr);
-    }
+  if (return_method == return_method_struct)
+    regcache_cooked_write_unsigned (regcache, STR_REGNUM, struct_addr);
 
   /* Now load as many as possible of the first arguments into registers,
      and push the rest onto the stack.  */
diff --git a/gdb/csky-tdep.c b/gdb/csky-tdep.c
index f843732310..ed56aed97a 100644
--- a/gdb/csky-tdep.c
+++ b/gdb/csky-tdep.c
@@ -336,7 +336,8 @@ static CORE_ADDR
 csky_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
       struct regcache *regcache, CORE_ADDR bp_addr,
       int nargs, struct value **args, CORE_ADDR sp,
-      int struct_return, CORE_ADDR struct_addr)
+      function_call_return_method return_method,
+      CORE_ADDR struct_addr)
 {
   int argnum;
   int argreg = CSKY_ABI_A0_REGNUM;
@@ -351,7 +352,7 @@ csky_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
 
   /* The struct_return pointer occupies the first parameter
      passing register.  */
-  if (struct_return)
+  if (return_method == return_method_struct)
     {
       if (csky_debug)
  {
diff --git a/gdb/frv-tdep.c b/gdb/frv-tdep.c
index dafab75654..f5c70007b2 100644
--- a/gdb/frv-tdep.c
+++ b/gdb/frv-tdep.c
@@ -1193,7 +1193,8 @@ static CORE_ADDR
 frv_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
                      struct regcache *regcache, CORE_ADDR bp_addr,
                      int nargs, struct value **args, CORE_ADDR sp,
-     int struct_return, CORE_ADDR struct_addr)
+     function_call_return_method return_method,
+     CORE_ADDR struct_addr)
 {
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
   int argreg;
@@ -1230,7 +1231,7 @@ frv_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
 
   argreg = 8;
 
-  if (struct_return)
+  if (return_method == return_method_struct)
     regcache_cooked_write_unsigned (regcache, struct_return_regnum,
                                     struct_addr);
 
diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c
index e2abf263b3..bc4f786501 100644
--- a/gdb/gdbarch.c
+++ b/gdb/gdbarch.c
@@ -2356,13 +2356,13 @@ gdbarch_push_dummy_call_p (struct gdbarch *gdbarch)
 }
 
 CORE_ADDR
-gdbarch_push_dummy_call (struct gdbarch *gdbarch, struct value *function, struct regcache *regcache, CORE_ADDR bp_addr, int nargs, struct value **args, CORE_ADDR sp, int struct_return, CORE_ADDR struct_addr)
+gdbarch_push_dummy_call (struct gdbarch *gdbarch, struct value *function, struct regcache *regcache, CORE_ADDR bp_addr, int nargs, struct value **args, CORE_ADDR sp, function_call_return_method return_method, CORE_ADDR struct_addr)
 {
   gdb_assert (gdbarch != NULL);
   gdb_assert (gdbarch->push_dummy_call != NULL);
   if (gdbarch_debug >= 2)
     fprintf_unfiltered (gdb_stdlog, "gdbarch_push_dummy_call called\n");
-  return gdbarch->push_dummy_call (gdbarch, function, regcache, bp_addr, nargs, args, sp, struct_return, struct_addr);
+  return gdbarch->push_dummy_call (gdbarch, function, regcache, bp_addr, nargs, args, sp, return_method, struct_addr);
 }
 
 void
diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h
index e8e35fbd01..8356e6e7b4 100644
--- a/gdb/gdbarch.h
+++ b/gdb/gdbarch.h
@@ -417,8 +417,8 @@ extern void set_gdbarch_deprecated_fp_regnum (struct gdbarch *gdbarch, int depre
 
 extern int gdbarch_push_dummy_call_p (struct gdbarch *gdbarch);
 
-typedef CORE_ADDR (gdbarch_push_dummy_call_ftype) (struct gdbarch *gdbarch, struct value *function, struct regcache *regcache, CORE_ADDR bp_addr, int nargs, struct value **args, CORE_ADDR sp, int struct_return, CORE_ADDR struct_addr);
-extern CORE_ADDR gdbarch_push_dummy_call (struct gdbarch *gdbarch, struct value *function, struct regcache *regcache, CORE_ADDR bp_addr, int nargs, struct value **args, CORE_ADDR sp, int struct_return, CORE_ADDR struct_addr);
+typedef CORE_ADDR (gdbarch_push_dummy_call_ftype) (struct gdbarch *gdbarch, struct value *function, struct regcache *regcache, CORE_ADDR bp_addr, int nargs, struct value **args, CORE_ADDR sp, function_call_return_method return_method, CORE_ADDR struct_addr);
+extern CORE_ADDR gdbarch_push_dummy_call (struct gdbarch *gdbarch, struct value *function, struct regcache *regcache, CORE_ADDR bp_addr, int nargs, struct value **args, CORE_ADDR sp, function_call_return_method return_method, CORE_ADDR struct_addr);
 extern void set_gdbarch_push_dummy_call (struct gdbarch *gdbarch, gdbarch_push_dummy_call_ftype *push_dummy_call);
 
 extern int gdbarch_call_dummy_location (struct gdbarch *gdbarch);
diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh
index 1e895c3b7a..ddd93c2717 100755
--- a/gdb/gdbarch.sh
+++ b/gdb/gdbarch.sh
@@ -485,7 +485,7 @@ M;struct frame_id;dummy_id;struct frame_info *this_frame;this_frame
 # deprecated_fp_regnum.
 v;int;deprecated_fp_regnum;;;-1;-1;;0
 
-M;CORE_ADDR;push_dummy_call;struct value *function, struct regcache *regcache, CORE_ADDR bp_addr, int nargs, struct value **args, CORE_ADDR sp, int struct_return, CORE_ADDR struct_addr;function, regcache, bp_addr, nargs, args, sp, struct_return, struct_addr
+M;CORE_ADDR;push_dummy_call;struct value *function, struct regcache *regcache, CORE_ADDR bp_addr, int nargs, struct value **args, CORE_ADDR sp, function_call_return_method return_method, CORE_ADDR struct_addr;function, regcache, bp_addr, nargs, args, sp, return_method, struct_addr
 v;int;call_dummy_location;;;;AT_ENTRY_POINT;;0
 M;CORE_ADDR;push_dummy_code;CORE_ADDR sp, CORE_ADDR funaddr, struct value **args, int nargs, struct type *value_type, CORE_ADDR *real_pc, CORE_ADDR *bp_addr, struct regcache *regcache;sp, funaddr, args, nargs, value_type, real_pc, bp_addr, regcache
 
diff --git a/gdb/h8300-tdep.c b/gdb/h8300-tdep.c
index 2334582260..eb4efd9efa 100644
--- a/gdb/h8300-tdep.c
+++ b/gdb/h8300-tdep.c
@@ -634,7 +634,8 @@ static CORE_ADDR
 h8300_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
        struct regcache *regcache, CORE_ADDR bp_addr,
        int nargs, struct value **args, CORE_ADDR sp,
-       int struct_return, CORE_ADDR struct_addr)
+       function_call_return_method return_method,
+       CORE_ADDR struct_addr)
 {
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
   int stack_alloc = 0, stack_offset = 0;
@@ -657,7 +658,7 @@ h8300_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
      If we're returning a structure by value, then we must pass a
      pointer to the buffer for the return value as an invisible first
      argument.  */
-  if (struct_return)
+  if (return_method == return_method_struct)
     regcache_cooked_write_unsigned (regcache, reg++, struct_addr);
 
   for (argument = 0; argument < nargs; argument++)
diff --git a/gdb/hppa-tdep.c b/gdb/hppa-tdep.c
index 319096e056..d22b2cf5d2 100644
--- a/gdb/hppa-tdep.c
+++ b/gdb/hppa-tdep.c
@@ -714,7 +714,8 @@ static CORE_ADDR
 hppa32_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
  struct regcache *regcache, CORE_ADDR bp_addr,
  int nargs, struct value **args, CORE_ADDR sp,
- int struct_return, CORE_ADDR struct_addr)
+ function_call_return_method return_method,
+ CORE_ADDR struct_addr)
 {
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
 
@@ -849,7 +850,7 @@ hppa32_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
 
   /* If a structure has to be returned, set up register 28 to hold its
      address.  */
-  if (struct_return)
+  if (return_method == return_method_struct)
     regcache_cooked_write_unsigned (regcache, 28, struct_addr);
 
   gp = tdep->find_global_pointer (gdbarch, function);
@@ -969,7 +970,8 @@ static CORE_ADDR
 hppa64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
  struct regcache *regcache, CORE_ADDR bp_addr,
  int nargs, struct value **args, CORE_ADDR sp,
- int struct_return, CORE_ADDR struct_addr)
+ function_call_return_method return_method,
+ CORE_ADDR struct_addr)
 {
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
@@ -1113,7 +1115,7 @@ hppa64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
 
   /* If a structure has to be returned, set up GR 28 (%ret0) to hold
      its address.  */
-  if (struct_return)
+  if (return_method == return_method_struct)
     regcache_cooked_write_unsigned (regcache, HPPA_RET0_REGNUM, struct_addr);
 
   /* Set up GR27 (%dp) to hold the global pointer (gp).  */
diff --git a/gdb/i386-darwin-tdep.c b/gdb/i386-darwin-tdep.c
index 5a1807ae4d..65aed998b6 100644
--- a/gdb/i386-darwin-tdep.c
+++ b/gdb/i386-darwin-tdep.c
@@ -153,7 +153,8 @@ static CORE_ADDR
 i386_darwin_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
      struct regcache *regcache, CORE_ADDR bp_addr,
      int nargs, struct value **args, CORE_ADDR sp,
-     int struct_return, CORE_ADDR struct_addr)
+     function_call_return_method return_method,
+     CORE_ADDR struct_addr)
 {
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
@@ -169,7 +170,7 @@ i386_darwin_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
       int args_space = 0;
       int num_m128 = 0;
 
-      if (struct_return)
+      if (return_method == return_method_struct)
  {
   if (write_pass)
     {
diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c
index a34a3374a4..10f26ad976 100644
--- a/gdb/i386-tdep.c
+++ b/gdb/i386-tdep.c
@@ -2671,7 +2671,8 @@ i386_push_dummy_code (struct gdbarch *gdbarch, CORE_ADDR sp, CORE_ADDR funaddr,
 static CORE_ADDR
 i386_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
       struct regcache *regcache, CORE_ADDR bp_addr, int nargs,
-      struct value **args, CORE_ADDR sp, int struct_return,
+      struct value **args, CORE_ADDR sp,
+      function_call_return_method return_method,
       CORE_ADDR struct_addr)
 {
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
@@ -2695,7 +2696,7 @@ i386_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
     {
       int args_space_used = 0;
 
-      if (struct_return)
+      if (return_method == return_method_struct)
  {
   if (write_pass)
     {
diff --git a/gdb/ia64-tdep.c b/gdb/ia64-tdep.c
index d381ecc74f..6cacb2acac 100644
--- a/gdb/ia64-tdep.c
+++ b/gdb/ia64-tdep.c
@@ -3673,7 +3673,8 @@ static CORE_ADDR
 ia64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
       struct regcache *regcache, CORE_ADDR bp_addr,
       int nargs, struct value **args, CORE_ADDR sp,
-      int struct_return, CORE_ADDR struct_addr)
+      function_call_return_method return_method,
+      CORE_ADDR struct_addr)
 {
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
@@ -3828,11 +3829,9 @@ ia64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
     }
 
   /* Store the struct return value in r8 if necessary.  */
-  if (struct_return)
-    {
-      regcache_cooked_write_unsigned (regcache, IA64_GR8_REGNUM,
-      (ULONGEST) struct_addr);
-    }
+  if (return_method == return_method_struct)
+    regcache_cooked_write_unsigned (regcache, IA64_GR8_REGNUM,
+    (ULONGEST) struct_addr);
 
   global_pointer = ia64_find_global_pointer (gdbarch, func_addr);
 
diff --git a/gdb/infcall.c b/gdb/infcall.c
index 0c875ea4b9..1b1e7daf7a 100644
--- a/gdb/infcall.c
+++ b/gdb/infcall.c
@@ -1052,8 +1052,7 @@ call_function_by_hand_dummy (struct value *function,
      presumably, the ABI code knows where, in the call dummy, the
      return address should be pointed.  */
   sp = gdbarch_push_dummy_call (gdbarch, function, get_current_regcache (),
- bp_addr, nargs, args, sp,
- (return_method == return_method_struct),
+ bp_addr, nargs, args, sp, return_method,
  struct_addr);
 
   /* Set up a frame ID for the dummy frame so we can pass it to
diff --git a/gdb/iq2000-tdep.c b/gdb/iq2000-tdep.c
index 9f7f35d287..fce0a2d268 100644
--- a/gdb/iq2000-tdep.c
+++ b/gdb/iq2000-tdep.c
@@ -645,7 +645,8 @@ static CORE_ADDR
 iq2000_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
         struct regcache *regcache, CORE_ADDR bp_addr,
         int nargs, struct value **args, CORE_ADDR sp,
-        int struct_return, CORE_ADDR struct_addr)
+ function_call_return_method return_method,
+ CORE_ADDR struct_addr)
 {
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
   const bfd_byte *val;
@@ -657,7 +658,9 @@ iq2000_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
   CORE_ADDR struct_ptr;
 
   /* First determine how much stack space we will need.  */
-  for (i = 0, argreg = E_1ST_ARGREG + (struct_return != 0); i < nargs; i++)
+  for (i = 0, argreg = E_1ST_ARGREG + (return_method == return_method_struct);
+       i < nargs;
+       i++)
     {
       type = value_type (args[i]);
       typelen = TYPE_LENGTH (type);
@@ -716,7 +719,7 @@ iq2000_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
   stackspace = 0;
 
   argreg = E_1ST_ARGREG;
-  if (struct_return)
+  if (return_method == return_method_struct)
     {
       /* A function that returns a struct will consume one argreg to do so.
        */
diff --git a/gdb/lm32-tdep.c b/gdb/lm32-tdep.c
index 694d30ee1c..609839d340 100644
--- a/gdb/lm32-tdep.c
+++ b/gdb/lm32-tdep.c
@@ -228,7 +228,8 @@ static CORE_ADDR
 lm32_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
       struct regcache *regcache, CORE_ADDR bp_addr,
       int nargs, struct value **args, CORE_ADDR sp,
-      int struct_return, CORE_ADDR struct_addr)
+      function_call_return_method return_method,
+      CORE_ADDR struct_addr)
 {
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
   int first_arg_reg = SIM_LM32_R1_REGNUM;
@@ -240,7 +241,7 @@ lm32_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
 
   /* If we're returning a large struct, a pointer to the address to
      store it at is passed as a first hidden parameter.  */
-  if (struct_return)
+  if (return_method == return_method_struct)
     {
       regcache_cooked_write_unsigned (regcache, first_arg_reg, struct_addr);
       first_arg_reg++;
diff --git a/gdb/m32c-tdep.c b/gdb/m32c-tdep.c
index 6fa24452da..841801dae5 100644
--- a/gdb/m32c-tdep.c
+++ b/gdb/m32c-tdep.c
@@ -2016,7 +2016,8 @@ m32c_reg_arg_type (struct type *type)
 static CORE_ADDR
 m32c_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
       struct regcache *regcache, CORE_ADDR bp_addr, int nargs,
-      struct value **args, CORE_ADDR sp, int struct_return,
+      struct value **args, CORE_ADDR sp,
+      function_call_return_method return_method,
       CORE_ADDR struct_addr)
 {
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
@@ -2054,7 +2055,7 @@ m32c_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
   /* First, if the function returns an aggregate by value, push a
      pointer to a buffer for it.  This doesn't affect the way
      subsequent arguments are allocated to registers.  */
-  if (struct_return)
+  if (return_method == return_method_struct)
     {
       int ptr_len = TYPE_LENGTH (tdep->ptr_voyd);
       sp -= ptr_len;
diff --git a/gdb/m32r-tdep.c b/gdb/m32r-tdep.c
index fd79f3f4cd..fda35bd4af 100644
--- a/gdb/m32r-tdep.c
+++ b/gdb/m32r-tdep.c
@@ -659,7 +659,8 @@ m32r_unwind_sp (struct gdbarch *gdbarch, struct frame_info *next_frame)
 static CORE_ADDR
 m32r_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
       struct regcache *regcache, CORE_ADDR bp_addr, int nargs,
-      struct value **args, CORE_ADDR sp, int struct_return,
+      struct value **args, CORE_ADDR sp,
+      function_call_return_method return_method,
       CORE_ADDR struct_addr)
 {
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
@@ -683,7 +684,7 @@ m32r_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
   /* If STRUCT_RETURN is true, then the struct return address (in
      STRUCT_ADDR) will consume the first argument-passing register.
      Both adjust the register count and store that value.  */
-  if (struct_return)
+  if (return_method == return_method_struct)
     {
       regcache_cooked_write_unsigned (regcache, argreg, struct_addr);
       argreg++;
diff --git a/gdb/m68hc11-tdep.c b/gdb/m68hc11-tdep.c
index b6e8f00a0b..09839ff1da 100644
--- a/gdb/m68hc11-tdep.c
+++ b/gdb/m68hc11-tdep.c
@@ -1154,7 +1154,8 @@ static CORE_ADDR
 m68hc11_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
                          struct regcache *regcache, CORE_ADDR bp_addr,
                          int nargs, struct value **args, CORE_ADDR sp,
-                         int struct_return, CORE_ADDR struct_addr)
+ function_call_return_method return_method,
+ CORE_ADDR struct_addr)
 {
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
   int argnum;
@@ -1164,10 +1165,8 @@ m68hc11_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
   gdb_byte buf[2];
   
   first_stack_argnum = 0;
-  if (struct_return)
-    {
-      regcache_cooked_write_unsigned (regcache, HARD_D_REGNUM, struct_addr);
-    }
+  if (return_method == return_method_struct)
+    regcache_cooked_write_unsigned (regcache, HARD_D_REGNUM, struct_addr);
   else if (nargs > 0)
     {
       type = value_type (args[0]);
diff --git a/gdb/m68k-tdep.c b/gdb/m68k-tdep.c
index a6e9b58a7d..4134c1a6a3 100644
--- a/gdb/m68k-tdep.c
+++ b/gdb/m68k-tdep.c
@@ -492,7 +492,8 @@ m68k_frame_align (struct gdbarch *gdbarch, CORE_ADDR sp)
 static CORE_ADDR
 m68k_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
       struct regcache *regcache, CORE_ADDR bp_addr, int nargs,
-      struct value **args, CORE_ADDR sp, int struct_return,
+      struct value **args, CORE_ADDR sp,
+      function_call_return_method return_method,
       CORE_ADDR struct_addr)
 {
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
@@ -522,7 +523,7 @@ m68k_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
     }
 
   /* Store struct value address.  */
-  if (struct_return)
+  if (return_method == return_method_struct)
     {
       store_unsigned_integer (buf, 4, byte_order, struct_addr);
       regcache->cooked_write (tdep->struct_value_regnum, buf);
diff --git a/gdb/mep-tdep.c b/gdb/mep-tdep.c
index ae9c4debca..b0c73f6c92 100644
--- a/gdb/mep-tdep.c
+++ b/gdb/mep-tdep.c
@@ -2258,7 +2258,7 @@ static CORE_ADDR
 mep_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
                      struct regcache *regcache, CORE_ADDR bp_addr,
                      int argc, struct value **argv, CORE_ADDR sp,
-                     int struct_return,
+     function_call_return_method return_method,
                      CORE_ADDR struct_addr)
 {
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
@@ -2287,7 +2287,7 @@ mep_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
 
   /* If we're returning a structure by value, push the pointer to the
      buffer as the first argument.  */
-  if (struct_return)
+  if (return_method == return_method_struct)
     {
       regcache_cooked_write_unsigned (regcache, arg_reg, struct_addr);
       arg_reg++;
diff --git a/gdb/mips-tdep.c b/gdb/mips-tdep.c
index 2c8726214f..dfff36678d 100644
--- a/gdb/mips-tdep.c
+++ b/gdb/mips-tdep.c
@@ -4495,7 +4495,8 @@ static CORE_ADDR
 mips_eabi_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
    struct regcache *regcache, CORE_ADDR bp_addr,
    int nargs, struct value **args, CORE_ADDR sp,
-   int struct_return, CORE_ADDR struct_addr)
+   function_call_return_method return_method,
+   CORE_ADDR struct_addr)
 {
   int argreg;
   int float_argreg;
@@ -4541,7 +4542,7 @@ mips_eabi_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
   float_argreg = mips_fpa0_regnum (gdbarch);
 
   /* The struct_return pointer occupies the first parameter-passing reg.  */
-  if (struct_return)
+  if (return_method == return_method_struct)
     {
       if (mips_debug)
  fprintf_unfiltered (gdb_stdlog,
@@ -4890,7 +4891,8 @@ static CORE_ADDR
 mips_n32n64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
      struct regcache *regcache, CORE_ADDR bp_addr,
      int nargs, struct value **args, CORE_ADDR sp,
-     int struct_return, CORE_ADDR struct_addr)
+     function_call_return_method return_method,
+     CORE_ADDR struct_addr)
 {
   int argreg;
   int float_argreg;
@@ -4933,7 +4935,7 @@ mips_n32n64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
   float_argreg = mips_fpa0_regnum (gdbarch);
 
   /* The struct_return pointer occupies the first parameter-passing reg.  */
-  if (struct_return)
+  if (return_method == return_method_struct)
     {
       if (mips_debug)
  fprintf_unfiltered (gdb_stdlog,
@@ -5347,7 +5349,8 @@ static CORE_ADDR
 mips_o32_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
   struct regcache *regcache, CORE_ADDR bp_addr,
   int nargs, struct value **args, CORE_ADDR sp,
-  int struct_return, CORE_ADDR struct_addr)
+  function_call_return_method return_method,
+  CORE_ADDR struct_addr)
 {
   int argreg;
   int float_argreg;
@@ -5398,7 +5401,7 @@ mips_o32_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
   float_argreg = mips_fpa0_regnum (gdbarch);
 
   /* The struct_return pointer occupies the first parameter-passing reg.  */
-  if (struct_return)
+  if (return_method == return_method_struct)
     {
       if (mips_debug)
  fprintf_unfiltered (gdb_stdlog,
@@ -5872,7 +5875,7 @@ mips_o64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
   struct regcache *regcache, CORE_ADDR bp_addr,
   int nargs,
   struct value **args, CORE_ADDR sp,
-  int struct_return, CORE_ADDR struct_addr)
+  function_call_return_method return_method, CORE_ADDR struct_addr)
 {
   int argreg;
   int float_argreg;
@@ -5920,7 +5923,7 @@ mips_o64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
   float_argreg = mips_fpa0_regnum (gdbarch);
 
   /* The struct_return pointer occupies the first parameter-passing reg.  */
-  if (struct_return)
+  if (return_method == return_method_struct)
     {
       if (mips_debug)
  fprintf_unfiltered (gdb_stdlog,
diff --git a/gdb/mn10300-tdep.c b/gdb/mn10300-tdep.c
index edc99a2fab..25d73c0156 100644
--- a/gdb/mn10300-tdep.c
+++ b/gdb/mn10300-tdep.c
@@ -1191,7 +1191,7 @@ mn10300_push_dummy_call (struct gdbarch *gdbarch,
  CORE_ADDR bp_addr,
  int nargs, struct value **args,
  CORE_ADDR sp,
- int struct_return,
+ function_call_return_method return_method,
  CORE_ADDR struct_addr)
 {
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
@@ -1211,7 +1211,7 @@ mn10300_push_dummy_call (struct gdbarch *gdbarch,
 
      XXX This doesn't appear to handle pass-by-invisible reference
      arguments.  */
-  regs_used = struct_return ? 1 : 0;
+  regs_used = (return_method == return_method_struct) ? 1 : 0;
   for (len = 0, argnum = 0; argnum < nargs; argnum++)
     {
       arg_len = (TYPE_LENGTH (value_type (args[argnum])) + 3) & ~3;
@@ -1226,7 +1226,7 @@ mn10300_push_dummy_call (struct gdbarch *gdbarch,
   /* Allocate stack space.  */
   sp -= len;
 
-  if (struct_return)
+  if (return_method == return_method_struct)
     {
       regs_used = 1;
       regcache_cooked_write_unsigned (regcache, E_D0_REGNUM, struct_addr);
diff --git a/gdb/msp430-tdep.c b/gdb/msp430-tdep.c
index 427f58c0ed..e034713025 100644
--- a/gdb/msp430-tdep.c
+++ b/gdb/msp430-tdep.c
@@ -669,7 +669,8 @@ static CORE_ADDR
 msp430_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
  struct regcache *regcache, CORE_ADDR bp_addr,
  int nargs, struct value **args, CORE_ADDR sp,
- int struct_return, CORE_ADDR struct_addr)
+ function_call_return_method return_method,
+ CORE_ADDR struct_addr)
 {
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
   int write_pass;
@@ -699,7 +700,7 @@ msp430_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
  sp = align_down (sp - sp_off, 4);
       sp_off = 0;
 
-      if (struct_return)
+      if (return_method == return_method_struct)
  {
   if (write_pass)
     regcache_cooked_write_unsigned (regcache, arg_reg, struct_addr);
diff --git a/gdb/nds32-tdep.c b/gdb/nds32-tdep.c
index 05b82def02..9e5ad6a033 100644
--- a/gdb/nds32-tdep.c
+++ b/gdb/nds32-tdep.c
@@ -1490,7 +1490,8 @@ static CORE_ADDR
 nds32_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
        struct regcache *regcache, CORE_ADDR bp_addr,
        int nargs, struct value **args, CORE_ADDR sp,
-       int struct_return, CORE_ADDR struct_addr)
+       function_call_return_method return_method,
+       CORE_ADDR struct_addr)
 {
   const int REND = 6; /* End for register offset.  */
   int goff = 0; /* Current gpr offset for argument.  */
@@ -1511,7 +1512,7 @@ nds32_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
   /* If STRUCT_RETURN is true, then the struct return address (in
      STRUCT_ADDR) will consume the first argument-passing register.
      Both adjust the register count and store that value.  */
-  if (struct_return)
+  if (return_method == return_method_struct)
     {
       regcache_cooked_write_unsigned (regcache, NDS32_R0_REGNUM, struct_addr);
       goff++;
diff --git a/gdb/nios2-tdep.c b/gdb/nios2-tdep.c
index c972b4bae3..d6de7e8be5 100644
--- a/gdb/nios2-tdep.c
+++ b/gdb/nios2-tdep.c
@@ -1811,7 +1811,8 @@ static CORE_ADDR
 nios2_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
                        struct regcache *regcache, CORE_ADDR bp_addr,
                        int nargs, struct value **args, CORE_ADDR sp,
-                       int struct_return, CORE_ADDR struct_addr)
+       function_call_return_method return_method,
+       CORE_ADDR struct_addr)
 {
   int argreg;
   int argnum;
@@ -1833,7 +1834,7 @@ nios2_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
 
   /* The struct_return pointer occupies the first parameter-passing
      register.  */
-  if (struct_return)
+  if (return_method == return_method_struct)
     regcache_cooked_write_unsigned (regcache, argreg++, struct_addr);
 
   /* Now load as many as possible of the first arguments into
diff --git a/gdb/or1k-tdep.c b/gdb/or1k-tdep.c
index c5104e3959..a9ef44baac 100644
--- a/gdb/or1k-tdep.c
+++ b/gdb/or1k-tdep.c
@@ -595,7 +595,8 @@ static CORE_ADDR
 or1k_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
       struct regcache *regcache, CORE_ADDR bp_addr,
       int nargs, struct value **args, CORE_ADDR sp,
-      int struct_return, CORE_ADDR struct_addr)
+      function_call_return_method return_method,
+      CORE_ADDR struct_addr)
 {
 
   int argreg;
@@ -617,7 +618,7 @@ or1k_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
 
   /* Location for a returned structure.  This is passed as a silent first
      argument.  */
-  if (struct_return)
+  if (return_method == return_method_struct)
     {
       regcache_cooked_write_unsigned (regcache, OR1K_FIRST_ARG_REGNUM,
       struct_addr);
diff --git a/gdb/ppc-sysv-tdep.c b/gdb/ppc-sysv-tdep.c
index ede666ab62..aeef8d8223 100644
--- a/gdb/ppc-sysv-tdep.c
+++ b/gdb/ppc-sysv-tdep.c
@@ -62,7 +62,8 @@ CORE_ADDR
 ppc_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
       struct regcache *regcache, CORE_ADDR bp_addr,
       int nargs, struct value **args, CORE_ADDR sp,
-      int struct_return, CORE_ADDR struct_addr)
+      function_call_return_method return_method,
+      CORE_ADDR struct_addr)
 {
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
@@ -107,7 +108,7 @@ ppc_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
          (which will be passed in r3) is used for struct return
          address.  In that case we should advance one word and start
          from r4 register to copy parameters.  */
-      if (struct_return)
+      if (return_method == return_method_struct)
  {
   if (write_pass)
     regcache_cooked_write_signed (regcache,
@@ -1540,7 +1541,8 @@ ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch,
  struct value *function,
  struct regcache *regcache, CORE_ADDR bp_addr,
  int nargs, struct value **args, CORE_ADDR sp,
- int struct_return, CORE_ADDR struct_addr)
+ function_call_return_method return_method,
+ CORE_ADDR struct_addr)
 {
   CORE_ADDR func_addr = find_function_addr (function, NULL);
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
@@ -1624,7 +1626,7 @@ ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch,
          containing the address of that struct..  In that case we
          should advance one word and start from r4 register to copy
          parameters.  This also consumes one on-stack parameter slot.  */
-      if (struct_return)
+      if (return_method == return_method_struct)
  ppc64_sysv_abi_push_integer (gdbarch, struct_addr, &argpos);
 
       for (argno = 0; argno < nargs; argno++)
diff --git a/gdb/ppc-tdep.h b/gdb/ppc-tdep.h
index dbafe2232d..dbfa695b4b 100644
--- a/gdb/ppc-tdep.h
+++ b/gdb/ppc-tdep.h
@@ -39,20 +39,17 @@ enum return_value_convention ppc_sysv_abi_broken_return_value (struct gdbarch *g
        struct regcache *regcache,
        gdb_byte *readbuf,
        const gdb_byte *writebuf);
-CORE_ADDR ppc_sysv_abi_push_dummy_call (struct gdbarch *gdbarch,
- struct value *function,
- struct regcache *regcache,
- CORE_ADDR bp_addr, int nargs,
- struct value **args, CORE_ADDR sp,
- int struct_return,
- CORE_ADDR struct_addr);
-CORE_ADDR ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch,
-  struct value *function,
-  struct regcache *regcache,
-  CORE_ADDR bp_addr, int nargs,
-  struct value **args, CORE_ADDR sp,
-  int struct_return,
-  CORE_ADDR struct_addr);
+
+CORE_ADDR ppc_sysv_abi_push_dummy_call
+  (struct gdbarch *gdbarch, struct value *function, struct regcache *regcache,
+   CORE_ADDR bp_addr, int nargs, struct value **args, CORE_ADDR sp,
+   function_call_return_method return_method, CORE_ADDR struct_addr);
+
+CORE_ADDR ppc64_sysv_abi_push_dummy_call
+  (struct gdbarch *gdbarch, struct value *function, struct regcache *regcache,
+   CORE_ADDR bp_addr, int nargs, struct value **args, CORE_ADDR sp,
+   function_call_return_method return_method, CORE_ADDR struct_addr);
+
 enum return_value_convention ppc64_sysv_abi_return_value (struct gdbarch *gdbarch,
   struct value *function,
   struct type *valtype,
diff --git a/gdb/riscv-tdep.c b/gdb/riscv-tdep.c
index 4b5f38a877..ad7f2e4168 100644
--- a/gdb/riscv-tdep.c
+++ b/gdb/riscv-tdep.c
@@ -2336,7 +2336,7 @@ riscv_push_dummy_call (struct gdbarch *gdbarch,
        int nargs,
        struct value **args,
        CORE_ADDR sp,
-       int struct_return,
+       function_call_return_method return_method,
        CORE_ADDR struct_addr)
 {
   int i;
@@ -2351,7 +2351,7 @@ riscv_push_dummy_call (struct gdbarch *gdbarch,
   CORE_ADDR osp = sp;
 
   /* We'll use register $a0 if we're returning a struct.  */
-  if (struct_return)
+  if (return_method == return_method_struct)
     ++call_info.int_regs.next_regnum;
 
   for (i = 0; i < nargs; ++i)
@@ -2381,7 +2381,7 @@ riscv_push_dummy_call (struct gdbarch *gdbarch,
        (riscv_has_fp_abi (gdbarch) ? "is" : "is not"));
       fprintf_unfiltered (gdb_stdlog, ": xlen: %d\n: flen: %d\n",
        call_info.xlen, call_info.flen);
-      if (struct_return)
+      if (return_method == return_method_struct)
  fprintf_unfiltered (gdb_stdlog,
     "[*] struct return pointer in register $A0\n");
       for (i = 0; i < nargs; ++i)
@@ -2408,7 +2408,7 @@ riscv_push_dummy_call (struct gdbarch *gdbarch,
 
   /* Now load the argument into registers, or onto the stack.  */
 
-  if (struct_return)
+  if (return_method == return_method_struct)
     {
       gdb_byte buf[sizeof (LONGEST)];
 
diff --git a/gdb/rl78-tdep.c b/gdb/rl78-tdep.c
index ace01b1171..fe8c2de8e2 100644
--- a/gdb/rl78-tdep.c
+++ b/gdb/rl78-tdep.c
@@ -1336,7 +1336,8 @@ static CORE_ADDR
 rl78_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
       struct regcache *regcache, CORE_ADDR bp_addr,
       int nargs, struct value **args, CORE_ADDR sp,
-      int struct_return, CORE_ADDR struct_addr)
+      function_call_return_method return_method,
+      CORE_ADDR struct_addr)
 {
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
   gdb_byte buf[4];
@@ -1355,7 +1356,7 @@ rl78_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
     }
 
   /* Store struct value address.  */
-  if (struct_return)
+  if (return_method == return_method_struct)
     {
       store_unsigned_integer (buf, 2, byte_order, struct_addr);
       sp -= 2;
diff --git a/gdb/rs6000-aix-tdep.c b/gdb/rs6000-aix-tdep.c
index 50a146a4f0..5cd5cdf9df 100644
--- a/gdb/rs6000-aix-tdep.c
+++ b/gdb/rs6000-aix-tdep.c
@@ -172,7 +172,8 @@ static CORE_ADDR
 rs6000_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
  struct regcache *regcache, CORE_ADDR bp_addr,
  int nargs, struct value **args, CORE_ADDR sp,
- int struct_return, CORE_ADDR struct_addr)
+ function_call_return_method return_method,
+ CORE_ADDR struct_addr)
 {
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
@@ -203,7 +204,7 @@ rs6000_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
      (which will be passed in r3) is used for struct return address.
      In that case we should advance one word and start from r4
      register to copy parameters.  */
-  if (struct_return)
+  if (return_method == return_method_struct)
     {
       regcache_raw_write_unsigned (regcache, tdep->ppc_gp0_regnum + 3,
    struct_addr);
diff --git a/gdb/rs6000-lynx178-tdep.c b/gdb/rs6000-lynx178-tdep.c
index 44cd0d013d..85d80b9292 100644
--- a/gdb/rs6000-lynx178-tdep.c
+++ b/gdb/rs6000-lynx178-tdep.c
@@ -33,7 +33,8 @@ rs6000_lynx178_push_dummy_call (struct gdbarch *gdbarch,
  struct value *function,
  struct regcache *regcache, CORE_ADDR bp_addr,
  int nargs, struct value **args, CORE_ADDR sp,
- int struct_return, CORE_ADDR struct_addr)
+ function_call_return_method return_method,
+ CORE_ADDR struct_addr)
 {
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
@@ -63,7 +64,7 @@ rs6000_lynx178_push_dummy_call (struct gdbarch *gdbarch,
      (which will be passed in r3) is used for struct return address.
      In that case we should advance one word and start from r4
      register to copy parameters.  */
-  if (struct_return)
+  if (return_method == return_method_struct)
     {
       regcache_raw_write_unsigned (regcache, tdep->ppc_gp0_regnum + 3,
    struct_addr);
diff --git a/gdb/rx-tdep.c b/gdb/rx-tdep.c
index 94d57913a3..2f797b168a 100644
--- a/gdb/rx-tdep.c
+++ b/gdb/rx-tdep.c
@@ -784,7 +784,8 @@ rx_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
 static CORE_ADDR
 rx_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
     struct regcache *regcache, CORE_ADDR bp_addr, int nargs,
-    struct value **args, CORE_ADDR sp, int struct_return,
+    struct value **args, CORE_ADDR sp,
+    function_call_return_method return_method,
     CORE_ADDR struct_addr)
 {
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
@@ -830,7 +831,7 @@ rx_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
  sp = align_down (sp - sp_off, 4);
       sp_off = 0;
 
-      if (struct_return)
+      if (return_method == return_method_struct)
  {
   struct type *return_type = TYPE_TARGET_TYPE (func_type);
 
@@ -854,7 +855,8 @@ rx_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
   struct type *arg_type = check_typedef (value_type (arg));
   ULONGEST arg_size = TYPE_LENGTH (arg_type);
 
-  if (i == 0 && struct_addr != 0 && !struct_return
+  if (i == 0 && struct_addr != 0
+      && return_method != return_method_struct
       && TYPE_CODE (arg_type) == TYPE_CODE_PTR
       && extract_unsigned_integer (arg_bits, 4,
    byte_order) == struct_addr)
diff --git a/gdb/s390-tdep.c b/gdb/s390-tdep.c
index 23689aa71a..33bec5770a 100644
--- a/gdb/s390-tdep.c
+++ b/gdb/s390-tdep.c
@@ -1865,7 +1865,8 @@ static CORE_ADDR
 s390_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
       struct regcache *regcache, CORE_ADDR bp_addr,
       int nargs, struct value **args, CORE_ADDR sp,
-      int struct_return, CORE_ADDR struct_addr)
+      function_call_return_method return_method,
+      CORE_ADDR struct_addr)
 {
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
   int word_size = gdbarch_ptr_bit (gdbarch) / 8;
@@ -1879,7 +1880,7 @@ s390_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
     ftype = check_typedef (TYPE_TARGET_TYPE (ftype));
 
   arg_prep.copy = sp;
-  arg_prep.gr = struct_return ? 3 : 2;
+  arg_prep.gr = (return_method == return_method_struct) ? 3 : 2;
   arg_prep.fr = 0;
   arg_prep.vr = 0;
   arg_prep.argp = 0;
@@ -1908,7 +1909,7 @@ s390_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
     error (_("Stack overflow"));
 
   /* Pass the structure return address in general register 2.  */
-  if (struct_return)
+  if (return_method == return_method_struct)
     regcache_cooked_write_unsigned (regcache, S390_R2_REGNUM, struct_addr);
 
   /* Initialize arg_state for "write mode".  */
diff --git a/gdb/score-tdep.c b/gdb/score-tdep.c
index b2887c5eae..77299fc96d 100644
--- a/gdb/score-tdep.c
+++ b/gdb/score-tdep.c
@@ -511,7 +511,8 @@ static CORE_ADDR
 score_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
                        struct regcache *regcache, CORE_ADDR bp_addr,
                        int nargs, struct value **args, CORE_ADDR sp,
-                       int struct_return, CORE_ADDR struct_addr)
+       function_call_return_method return_method,
+       CORE_ADDR struct_addr)
 {
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
   int argnum;
@@ -535,7 +536,7 @@ score_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
 
   /* Step 3, Check if struct return then save the struct address to
      r4 and increase the stack_offset by 4.  */
-  if (struct_return)
+  if (return_method == return_method_struct)
     {
       regcache_cooked_write_unsigned (regcache, argreg++, struct_addr);
       stack_offset += SCORE_REGSIZE;
diff --git a/gdb/sh-tdep.c b/gdb/sh-tdep.c
index fe64cf979a..7a6a09e997 100644
--- a/gdb/sh-tdep.c
+++ b/gdb/sh-tdep.c
@@ -1062,7 +1062,7 @@ sh_push_dummy_call_fpu (struct gdbarch *gdbarch,
  struct regcache *regcache,
  CORE_ADDR bp_addr, int nargs,
  struct value **args,
- CORE_ADDR sp, int struct_return,
+ CORE_ADDR sp, function_call_return_method return_method,
  CORE_ADDR struct_addr)
 {
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
@@ -1175,7 +1175,7 @@ sh_push_dummy_call_fpu (struct gdbarch *gdbarch,
  }
     }
 
-  if (struct_return)
+  if (return_method == return_method_struct)
     {
       if (sh_is_renesas_calling_convention (func_type))
  /* If the function uses the Renesas ABI, subtract another 4 bytes from
@@ -1204,7 +1204,8 @@ sh_push_dummy_call_nofpu (struct gdbarch *gdbarch,
   struct regcache *regcache,
   CORE_ADDR bp_addr,
   int nargs, struct value **args,
-  CORE_ADDR sp, int struct_return,
+  CORE_ADDR sp,
+  function_call_return_method return_method,
   CORE_ADDR struct_addr)
 {
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
@@ -1278,7 +1279,7 @@ sh_push_dummy_call_nofpu (struct gdbarch *gdbarch,
  }
     }
 
-  if (struct_return)
+  if (return_method == return_method_struct)
     {
       if (sh_is_renesas_calling_convention (func_type))
  /* If the function uses the Renesas ABI, subtract another 4 bytes from
diff --git a/gdb/sparc-tdep.c b/gdb/sparc-tdep.c
index 7a50a8d4a9..fae037cfe8 100644
--- a/gdb/sparc-tdep.c
+++ b/gdb/sparc-tdep.c
@@ -612,7 +612,8 @@ sparc32_push_dummy_code (struct gdbarch *gdbarch, CORE_ADDR sp,
 static CORE_ADDR
 sparc32_store_arguments (struct regcache *regcache, int nargs,
  struct value **args, CORE_ADDR sp,
- int struct_return, CORE_ADDR struct_addr)
+ function_call_return_method return_method,
+ CORE_ADDR struct_addr)
 {
   struct gdbarch *gdbarch = regcache->arch ();
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
@@ -697,7 +698,7 @@ sparc32_store_arguments (struct regcache *regcache, int nargs,
 
   gdb_assert (element == num_elements);
 
-  if (struct_return)
+  if (return_method == return_method_struct)
     {
       gdb_byte buf[4];
 
@@ -712,16 +713,18 @@ static CORE_ADDR
 sparc32_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
  struct regcache *regcache, CORE_ADDR bp_addr,
  int nargs, struct value **args, CORE_ADDR sp,
- int struct_return, CORE_ADDR struct_addr)
+ function_call_return_method return_method,
+ CORE_ADDR struct_addr)
 {
-  CORE_ADDR call_pc = (struct_return ? (bp_addr - 12) : (bp_addr - 8));
+  CORE_ADDR call_pc = (return_method == return_method_struct
+       ? (bp_addr - 12) : (bp_addr - 8));
 
   /* Set return address.  */
   regcache_cooked_write_unsigned (regcache, SPARC_O7_REGNUM, call_pc);
 
   /* Set up function arguments.  */
-  sp = sparc32_store_arguments (regcache, nargs, args, sp,
- struct_return, struct_addr);
+  sp = sparc32_store_arguments (regcache, nargs, args, sp, return_method,
+ struct_addr);
 
   /* Allocate the 16-word window save area.  */
   sp -= 16 * 4;
diff --git a/gdb/sparc64-tdep.c b/gdb/sparc64-tdep.c
index b1ee6c1b57..26e37394fc 100644
--- a/gdb/sparc64-tdep.c
+++ b/gdb/sparc64-tdep.c
@@ -1367,7 +1367,8 @@ sparc64_extract_floating_fields (struct regcache *regcache, struct type *type,
 static CORE_ADDR
 sparc64_store_arguments (struct regcache *regcache, int nargs,
  struct value **args, CORE_ADDR sp,
- int struct_return, CORE_ADDR struct_addr)
+ function_call_return_method return_method,
+ CORE_ADDR struct_addr)
 {
   struct gdbarch *gdbarch = regcache->arch ();
   /* Number of extended words in the "parameter array".  */
@@ -1381,7 +1382,7 @@ sparc64_store_arguments (struct regcache *regcache, int nargs,
   /* First we calculate the number of extended words in the "parameter
      array".  While doing so we also convert some of the arguments.  */
 
-  if (struct_return)
+  if (return_method == return_method_struct)
     num_elements++;
 
   for (i = 0; i < nargs; i++)
@@ -1477,7 +1478,7 @@ sparc64_store_arguments (struct regcache *regcache, int nargs,
      contents of any unused memory or registers in the "parameter
      array" are undefined.  */
 
-  if (struct_return)
+  if (return_method == return_method_struct)
     {
       regcache_cooked_write_unsigned (regcache, SPARC_O0_REGNUM, struct_addr);
       element++;
@@ -1621,14 +1622,15 @@ static CORE_ADDR
 sparc64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
  struct regcache *regcache, CORE_ADDR bp_addr,
  int nargs, struct value **args, CORE_ADDR sp,
- int struct_return, CORE_ADDR struct_addr)
+ function_call_return_method return_method,
+ CORE_ADDR struct_addr)
 {
   /* Set return address.  */
   regcache_cooked_write_unsigned (regcache, SPARC_O7_REGNUM, bp_addr - 8);
 
   /* Set up function arguments.  */
-  sp = sparc64_store_arguments (regcache, nargs, args, sp,
- struct_return, struct_addr);
+  sp = sparc64_store_arguments (regcache, nargs, args, sp, return_method,
+ struct_addr);
 
   /* Allocate the register save area.  */
   sp -= 16 * 8;
diff --git a/gdb/spu-tdep.c b/gdb/spu-tdep.c
index 6ae37f58c7..1020167757 100644
--- a/gdb/spu-tdep.c
+++ b/gdb/spu-tdep.c
@@ -1401,7 +1401,8 @@ static CORE_ADDR
 spu_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
      struct regcache *regcache, CORE_ADDR bp_addr,
      int nargs, struct value **args, CORE_ADDR sp,
-     int struct_return, CORE_ADDR struct_addr)
+     function_call_return_method return_method,
+     CORE_ADDR struct_addr)
 {
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
   CORE_ADDR sp_delta;
@@ -1418,7 +1419,7 @@ spu_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
   /* If STRUCT_RETURN is true, then the struct return address (in
      STRUCT_ADDR) will consume the first argument-passing register.
      Both adjust the register count and store that value.  */
-  if (struct_return)
+  if (return_method == return_method_struct)
     {
       memset (buf, 0, sizeof buf);
       store_unsigned_integer (buf, 4, byte_order, SPUADDR_ADDR (struct_addr));
diff --git a/gdb/tic6x-tdep.c b/gdb/tic6x-tdep.c
index 13ad67f974..b83074aa23 100644
--- a/gdb/tic6x-tdep.c
+++ b/gdb/tic6x-tdep.c
@@ -875,7 +875,8 @@ static CORE_ADDR
 tic6x_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
        struct regcache *regcache, CORE_ADDR bp_addr,
        int nargs, struct value **args, CORE_ADDR sp,
-       int struct_return, CORE_ADDR struct_addr)
+       function_call_return_method return_method,
+       CORE_ADDR struct_addr)
 {
   int argreg = 0;
   int argnum;
@@ -894,7 +895,7 @@ tic6x_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
   /* The caller must pass an argument in A3 containing a destination address
      for the returned value.  The callee returns the object by copying it to
      the address in A3.  */
-  if (struct_return)
+  if (return_method == return_method_struct)
     regcache_cooked_write_unsigned (regcache, 3, struct_addr);
 
   /* Determine the type of this function.  */
diff --git a/gdb/tilegx-tdep.c b/gdb/tilegx-tdep.c
index 9ed696630e..e2e844bc02 100644
--- a/gdb/tilegx-tdep.c
+++ b/gdb/tilegx-tdep.c
@@ -281,7 +281,7 @@ tilegx_push_dummy_call (struct gdbarch *gdbarch,
  struct regcache *regcache,
  CORE_ADDR bp_addr, int nargs,
  struct value **args,
- CORE_ADDR sp, int struct_return,
+ CORE_ADDR sp, function_call_return_method return_method,
  CORE_ADDR struct_addr)
 {
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
@@ -293,7 +293,7 @@ tilegx_push_dummy_call (struct gdbarch *gdbarch,
 
   /* If struct_return is 1, then the struct return address will
      consume one argument-passing register.  */
-  if (struct_return)
+  if (return_method == return_method_struct)
     regcache_cooked_write_unsigned (regcache, argreg++, struct_addr);
 
   /* Arguments are passed in R0 - R9, and as soon as an argument
diff --git a/gdb/v850-tdep.c b/gdb/v850-tdep.c
index 119fb6d6bd..cc582ca54d 100644
--- a/gdb/v850-tdep.c
+++ b/gdb/v850-tdep.c
@@ -1013,7 +1013,7 @@ v850_push_dummy_call (struct gdbarch *gdbarch,
       int nargs,
       struct value **args,
       CORE_ADDR sp,
-      int struct_return,
+      function_call_return_method return_method,
       CORE_ADDR struct_addr)
 {
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
@@ -1039,7 +1039,7 @@ v850_push_dummy_call (struct gdbarch *gdbarch,
 
   argreg = E_ARG0_REGNUM;
   /* The struct_return pointer occupies the first parameter register.  */
-  if (struct_return)
+  if (return_method == return_method_struct)
     regcache_cooked_write_unsigned (regcache, argreg++, struct_addr);
 
   /* Now load as many as possible of the first arguments into
diff --git a/gdb/vax-tdep.c b/gdb/vax-tdep.c
index 21f2066da2..797758b21a 100644
--- a/gdb/vax-tdep.c
+++ b/gdb/vax-tdep.c
@@ -141,7 +141,8 @@ vax_store_arguments (struct regcache *regcache, int nargs,
 static CORE_ADDR
 vax_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
      struct regcache *regcache, CORE_ADDR bp_addr, int nargs,
-     struct value **args, CORE_ADDR sp, int struct_return,
+     struct value **args, CORE_ADDR sp,
+     function_call_return_method return_method,
      CORE_ADDR struct_addr)
 {
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
@@ -152,7 +153,7 @@ vax_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
   sp = vax_store_arguments (regcache, nargs, args, sp);
 
   /* Store return value address.  */
-  if (struct_return)
+  if (return_method == return_method_struct)
     regcache_cooked_write_unsigned (regcache, VAX_R1_REGNUM, struct_addr);
 
   /* Store return address in the PC slot.  */
diff --git a/gdb/xstormy16-tdep.c b/gdb/xstormy16-tdep.c
index b3c2ba649c..82ce0256bb 100644
--- a/gdb/xstormy16-tdep.c
+++ b/gdb/xstormy16-tdep.c
@@ -226,7 +226,8 @@ xstormy16_push_dummy_call (struct gdbarch *gdbarch,
    struct regcache *regcache,
    CORE_ADDR bp_addr, int nargs,
    struct value **args,
-   CORE_ADDR sp, int struct_return,
+   CORE_ADDR sp,
+   function_call_return_method return_method,
    CORE_ADDR struct_addr)
 {
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
@@ -236,9 +237,9 @@ xstormy16_push_dummy_call (struct gdbarch *gdbarch,
   int typelen, slacklen;
   gdb_byte buf[xstormy16_pc_size];
 
-  /* If struct_return is true, then the struct return address will
-     consume one argument-passing register.  */
-  if (struct_return)
+  /* If returning a struct using target ABI method, then the struct return
+     address will consume one argument-passing register.  */
+  if (return_method == return_method_struct)
     {
       regcache_cooked_write_unsigned (regcache, E_PTR_RET_REGNUM, struct_addr);
       argreg++;
diff --git a/gdb/xtensa-tdep.c b/gdb/xtensa-tdep.c
index 4f29557fbf..af8b8c382b 100644
--- a/gdb/xtensa-tdep.c
+++ b/gdb/xtensa-tdep.c
@@ -1685,7 +1685,7 @@ xtensa_push_dummy_call (struct gdbarch *gdbarch,
  int nargs,
  struct value **args,
  CORE_ADDR sp,
- int struct_return,
+ function_call_return_method return_method,
  CORE_ADDR struct_addr)
 {
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
@@ -1715,9 +1715,9 @@ xtensa_push_dummy_call (struct gdbarch *gdbarch,
   if (xtensa_debug_level > 3)
     {
       DEBUGINFO ("[xtensa_push_dummy_call] nargs = %d\n", nargs);
-      DEBUGINFO ("[xtensa_push_dummy_call] sp=0x%x, struct_return=%d, "
+      DEBUGINFO ("[xtensa_push_dummy_call] sp=0x%x, return_method=%d, "
  "struct_addr=0x%x\n",
- (int) sp, (int) struct_return, (int) struct_addr);
+ (int) sp, (int) return_method, (int) struct_addr);
 
       for (int i = 0; i < nargs; i++)
         {
@@ -1751,7 +1751,7 @@ xtensa_push_dummy_call (struct gdbarch *gdbarch,
   size = 0;
   onstack_size = 0;
 
-  if (struct_return)
+  if (return_method == return_method_struct)
     size = REGISTER_SIZE;
 
   for (int i = 0; i < nargs; i++)
@@ -1828,7 +1828,7 @@ xtensa_push_dummy_call (struct gdbarch *gdbarch,
 
   /* Second Loop: Load arguments.  */
 
-  if (struct_return)
+  if (return_method == return_method_struct)
     {
       store_unsigned_integer (buf, REGISTER_SIZE, byte_order, struct_addr);
       regcache->cooked_write (ARG_1ST (gdbarch), buf);
--
2.17.1 (Apple Git-112)

Reply | Threaded
Open this post in threaded view
|

[PATCH v4 3/3] Aarch64: Fix segfault when casting dummy calls

Alan Hayward
In reply to this post by Alan Hayward
The following will segfault on aarch64 if foo is in another object,
was compiled as c++ and has no debug symbols:
(gdb) p (int)foo()

This is because to aarch64_push_dummy_call determines the return
type of the function and then does not check for null pointer.

A null pointer for the return type means the call has no debug
information.  For the code to get here, then the call must have
been cast, otherwise we'd error out sooner.  In the case of a
no-debug-info call cast, the return type is the type the user
had cast the call to, but we do not have that information
available here.

However, aarch64_push_dummy_call only requires the return type in
order to calculate lang_struct_return. This information is available
in the return_method enum. The fix is to simply use this instead.

Adds testcase to check calls across objects, with all combinations
of c, c++, debug and no debug.

gdb/ChangeLog:

2018-10-31  Alan Hayward  <[hidden email]>

        PR gdb/22736:
        * aarch64-tdep.c (aarch64_push_dummy_call): Remove
        lang_struct_return code.

gdb/testsuite/ChangeLog:

2018-10-31  Alan Hayward  <[hidden email]>

        PR gdb/22736:
        * gdb.base/infcall-across-obj-lib.c: New test.
        * gdb.base/infcall-across-obj-main.c: New test.
        * gdb.base/infcall-across-obj.exp: New file.
---
 gdb/aarch64-tdep.c                            |  32 +----
 .../gdb.base/infcall-across-obj-lib.c         |  22 +++
 .../gdb.base/infcall-across-obj-main.c        |  24 ++++
 gdb/testsuite/gdb.base/infcall-across-obj.exp | 134 ++++++++++++++++++
 4 files changed, 184 insertions(+), 28 deletions(-)
 create mode 100644 gdb/testsuite/gdb.base/infcall-across-obj-lib.c
 create mode 100644 gdb/testsuite/gdb.base/infcall-across-obj-main.c
 create mode 100644 gdb/testsuite/gdb.base/infcall-across-obj.exp

diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c
index efab925067..e541e45f61 100644
--- a/gdb/aarch64-tdep.c
+++ b/gdb/aarch64-tdep.c
@@ -1519,9 +1519,6 @@ aarch64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
 {
   int argnum;
   struct aarch64_call_info info;
-  struct type *func_type;
-  struct type *return_type;
-  int lang_struct_return;
 
   memset (&info, 0, sizeof (info));
 
@@ -1543,42 +1540,21 @@ aarch64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
      If the language code decides to pass in memory we want to move
      the pointer inserted as the initial argument from the argument
      list and into X8, the conventional AArch64 struct return pointer
-     register.
-
-     This is slightly awkward, ideally the flag "lang_struct_return"
-     would be passed to the targets implementation of push_dummy_call.
-     Rather that change the target interface we call the language code
-     directly ourselves.  */
-
-  func_type = check_typedef (value_type (function));
-
-  /* Dereference function pointer types.  */
-  if (TYPE_CODE (func_type) == TYPE_CODE_PTR)
-    func_type = TYPE_TARGET_TYPE (func_type);
-
-  gdb_assert (TYPE_CODE (func_type) == TYPE_CODE_FUNC
-      || TYPE_CODE (func_type) == TYPE_CODE_METHOD);
-
-  /* If language_pass_by_reference () returned true we will have been
-     given an additional initial argument, a hidden pointer to the
-     return slot in memory.  */
-  return_type = TYPE_TARGET_TYPE (func_type);
-  lang_struct_return = language_pass_by_reference (return_type);
+     register.  */
 
   /* Set the return address.  For the AArch64, the return breakpoint
      is always at BP_ADDR.  */
   regcache_cooked_write_unsigned (regcache, AARCH64_LR_REGNUM, bp_addr);
 
-  /* If we were given an initial argument for the return slot because
-     lang_struct_return was true, lose it.  */
-  if (lang_struct_return)
+  /* If we were given an initial argument for the return slot, lose it.  */
+  if (return_method == return_method_hidden_param)
     {
       args++;
       nargs--;
     }
 
   /* The struct_return pointer occupies X8.  */
-  if (return_method == return_method_struct || lang_struct_return)
+  if (return_method != return_method_normal)
     {
       if (aarch64_debug)
  {
diff --git a/gdb/testsuite/gdb.base/infcall-across-obj-lib.c b/gdb/testsuite/gdb.base/infcall-across-obj-lib.c
new file mode 100644
index 0000000000..92746f2563
--- /dev/null
+++ b/gdb/testsuite/gdb.base/infcall-across-obj-lib.c
@@ -0,0 +1,22 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2018 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+int
+foo (void)
+{
+  return 1;
+}
diff --git a/gdb/testsuite/gdb.base/infcall-across-obj-main.c b/gdb/testsuite/gdb.base/infcall-across-obj-main.c
new file mode 100644
index 0000000000..b623a4a55f
--- /dev/null
+++ b/gdb/testsuite/gdb.base/infcall-across-obj-main.c
@@ -0,0 +1,24 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2018 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+extern int foo (void);
+
+int
+main (void)
+{
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.base/infcall-across-obj.exp b/gdb/testsuite/gdb.base/infcall-across-obj.exp
new file mode 100644
index 0000000000..6d31249d8c
--- /dev/null
+++ b/gdb/testsuite/gdb.base/infcall-across-obj.exp
@@ -0,0 +1,134 @@
+# This testcase is part of GDB, the GNU debugger.
+# Copyright 2018 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Test function calls on functions in another object.
+# See gdb/22736
+
+if [target_info exists gdb,cannot_call_functions] {
+    unsupported "this target can not call functions"
+    continue
+}
+
+# Only test c++ if we are able. Always use c
+if { [skip_cplus_tests] || [get_compiler_info "c++"] } {
+    set lang {c}
+} else {
+    set lang {c c++}
+}
+
+set main_basename infcall-across-obj-main
+set lib_basename infcall-across-obj-lib
+standard_testfile ${main_basename}.c ${lib_basename}.c
+
+set mainsrc "${srcdir}/${subdir}/${srcfile}"
+set libsrc "${srcdir}/${subdir}/${srcfile2}"
+
+# Build both source files to objects using language LANG. Use SYMBOLS to build
+# the with either debug symbols or without - but always build the main file
+# with debug. Then make function calls across the files.
+
+proc build_and_run_test { lang symbols } {
+
+    global main_basename lib_basename mainsrc libsrc binfile testfile
+    global gdb_prompt
+
+    if { $symbols == "debug" } {
+     set debug_flags "debug"
+    } else {
+        set debug_flags ""
+    }
+
+    # Setup directory.
+
+    set dir "$lang-$symbols"
+    remote_exec build "rm -rf [standard_output_file ${dir}]"
+    remote_exec build "mkdir -p [standard_output_file ${dir}]"
+
+    # Compile both files to objects, then link together.
+
+    set main_flags "$lang debug"
+    set lib_flags "$lang $debug_flags"
+    set main_o [standard_output_file ${dir}/${main_basename}.o]
+    set lib_o [standard_output_file ${dir}/${lib_basename}.o]
+    set binfile [standard_output_file ${dir}/${testfile}]
+
+    if { [gdb_compile $mainsrc $main_o object ${main_flags}] != "" } {
+        untested "failed to compile main file to object"
+        return -1
+    }
+
+    if { [gdb_compile $libsrc $lib_o object ${lib_flags}] != "" } {
+        untested "failed to compile secondary file to object"
+        return -1
+    }
+
+    if { [gdb_compile "$main_o $lib_o" ${binfile} executable ""] != "" } {
+        untested "failed to compile"
+        return -1
+    }
+
+    # Startup and run to main.
+
+    clean_restart $binfile
+
+    if ![runto_main] then {
+        fail "can't run to main"
+        return
+    }
+
+    # Function call with cast.
+
+    set test "p (int)foo()"
+    gdb_test_multiple $test $test {
+        -re " = 1\r\n$gdb_prompt " {
+    pass $test
+        }
+ default {
+    fail $test
+ }
+    }
+
+    # Function call without cast. Will error if there are no debug symbols.
+
+    set test "p foo()"
+    gdb_test_multiple $test $test {
+        -re " = 1\r\n$gdb_prompt " {
+    if { $symbols == "debug" } {
+        pass $test
+    } else {
+     fail $test
+    }
+        }
+        -re "has unknown return type; cast the call to its declared return type\r\n$gdb_prompt " {
+    if { $symbols != "debug" } {
+        pass $test
+    } else {
+     fail $test
+    }
+        }
+ default {
+    fail $test
+ }
+    }
+
+}
+
+foreach_with_prefix l $lang {
+    foreach_with_prefix s {debug nodebug} {
+        build_and_run_test $l $s
+    }
+}
+
--
2.17.1 (Apple Git-112)


Reply | Threaded
Open this post in threaded view
|

[PING][PATCH v4 0/3] Aarch64: Fix segfault when casting dummy calls

Alan Hayward
In reply to this post by Alan Hayward
Ping.

Begin forwarded message:

From: Alan Hayward <[hidden email]<mailto:[hidden email]>>
Subject: [PATCH v4 0/3] Aarch64: Fix segfault when casting dummy calls
Date: 31 October 2018 at 11:18:04 GMT
To: "[hidden email]<mailto:[hidden email]>" <[hidden email]<mailto:[hidden email]>>
Cc: nd <[hidden email]<mailto:[hidden email]>>, Alan Hayward <[hidden email]<mailto:[hidden email]>>

This version cleans up a few things and includes a very different testcase.

The following will segfault on aarch64 if foo is in another object,
was compiled as c++ and has no debug symbols:
(gdb) p (int)foo()

The fix is to remove a bunch of code from aarch64_push_dummy_call,
instead passing down the information from the caller.

Patch 1 removes two ints from call_function_by_hand_dummy, replacing
them with an enum.
Patch 2 passes that enum down to _push_dummy_call.
Patch 3 makes use of the enum in aarch64_push_dummy_call and adds a
test case.

Tested with make check on aarch64 and build with all targets on x86.
Patch 2 needs a careful scan to make sure it doesn't break any other
targets.


Alan Hayward (3):
 Use enum for return method for dummy calls
 Pass return_method to _push_dummy_call
 Aarch64: Fix segfault when casting dummy calls

gdb/aarch64-tdep.c                            |  35 +----
gdb/alpha-tdep.c                              |   7 +-
gdb/amd64-tdep.c                              |  13 +-
gdb/amd64-windows-tdep.c                      |  12 +-
gdb/arc-tdep.c                                |   5 +-
gdb/arm-tdep.c                                |   5 +-
gdb/avr-tdep.c                                |   5 +-
gdb/bfin-tdep.c                               |   4 +-
gdb/cris-tdep.c                               |   9 +-
gdb/csky-tdep.c                               |   5 +-
gdb/frv-tdep.c                                |   5 +-
gdb/gdbarch.c                                 |   4 +-
gdb/gdbarch.h                                 |  27 +++-
gdb/gdbarch.sh                                |  25 +++-
gdb/h8300-tdep.c                              |   5 +-
gdb/hppa-tdep.c                               |  10 +-
gdb/i386-darwin-tdep.c                        |   5 +-
gdb/i386-tdep.c                               |   5 +-
gdb/ia64-tdep.c                               |  11 +-
gdb/infcall.c                                 |  28 ++--
gdb/iq2000-tdep.c                             |   9 +-
gdb/lm32-tdep.c                               |   5 +-
gdb/m32c-tdep.c                               |   5 +-
gdb/m32r-tdep.c                               |   5 +-
gdb/m68hc11-tdep.c                            |   9 +-
gdb/m68k-tdep.c                               |   5 +-
gdb/mep-tdep.c                                |   4 +-
gdb/mips-tdep.c                               |  19 +--
gdb/mn10300-tdep.c                            |   6 +-
gdb/msp430-tdep.c                             |   5 +-
gdb/nds32-tdep.c                              |   5 +-
gdb/nios2-tdep.c                              |   5 +-
gdb/or1k-tdep.c                               |   5 +-
gdb/ppc-sysv-tdep.c                           |  10 +-
gdb/ppc-tdep.h                                |  25 ++--
gdb/riscv-tdep.c                              |   8 +-
gdb/rl78-tdep.c                               |   5 +-
gdb/rs6000-aix-tdep.c                         |   5 +-
gdb/rs6000-lynx178-tdep.c                     |   5 +-
gdb/rx-tdep.c                                 |   8 +-
gdb/s390-tdep.c                               |   7 +-
gdb/score-tdep.c                              |   5 +-
gdb/sh-tdep.c                                 |   9 +-
gdb/sparc-tdep.c                              |  15 +-
gdb/sparc64-tdep.c                            |  14 +-
gdb/spu-tdep.c                                |   5 +-
.../gdb.base/infcall-across-obj-lib.c         |  22 +++
.../gdb.base/infcall-across-obj-main.c        |  24 ++++
gdb/testsuite/gdb.base/infcall-across-obj.exp | 134 ++++++++++++++++++
gdb/tic6x-tdep.c                              |   5 +-
gdb/tilegx-tdep.c                             |   4 +-
gdb/v850-tdep.c                               |   4 +-
gdb/vax-tdep.c                                |   5 +-
gdb/xstormy16-tdep.c                          |   9 +-
gdb/xtensa-tdep.c                             |  10 +-
55 files changed, 442 insertions(+), 208 deletions(-)
create mode 100644 gdb/testsuite/gdb.base/infcall-across-obj-lib.c
create mode 100644 gdb/testsuite/gdb.base/infcall-across-obj-main.c
create mode 100644 gdb/testsuite/gdb.base/infcall-across-obj.exp

--
2.17.1 (Apple Git-112)


Reply | Threaded
Open this post in threaded view
|

Re: [PATCH v4 3/3] Aarch64: Fix segfault when casting dummy calls

Pedro Alves-7
In reply to this post by Alan Hayward
On 10/31/2018 11:18 AM, Alan Hayward wrote:

> +++ b/gdb/testsuite/gdb.base/infcall-across-obj.exp
> @@ -0,0 +1,134 @@
> +# This testcase is part of GDB, the GNU debugger.
> +# Copyright 2018 Free Software Foundation, Inc.
> +
> +# This program is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation; either version 3 of the License, or
> +# (at your option) any later version.
> +#
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
> +
> +# Test function calls on functions in another object.
> +# See gdb/22736

Add missing period.

This comment misses the most important aspect of the testcase/bugfix,
which is to call a C++ function with no debug info.  Please extend the
comment to stress that.

The "in another object" thing is really a red herring; there's nothing
special about it, and there are other tests that cover that already.
Putting the called-function in a separate object is just so that the
main objfile is always compiled with debug info, so that GDB knows the
program is a C++ program.

(The only reason the infcall tests in gdb.base/nodebug.exp don't exercise
this is that that testcase is C.  That's why I had suggested
gdb.cp/nodebug-infcall.exp previously.  Anyway, naming not that important,
I guess.)

> +
> +if [target_info exists gdb,cannot_call_functions] {
> +    unsupported "this target can not call functions"
> +    continue
> +}
> +
> +# Only test c++ if we are able. Always use c

Double space after period.  Add missing period in second
sentence.

> +if { [skip_cplus_tests] || [get_compiler_info "c++"] } {
> +    set lang {c}
> +} else {
> +    set lang {c c++}
> +}
> +
> +set main_basename infcall-across-obj-main
> +set lib_basename infcall-across-obj-lib
> +standard_testfile ${main_basename}.c ${lib_basename}.c
> +
> +set mainsrc "${srcdir}/${subdir}/${srcfile}"
> +set libsrc "${srcdir}/${subdir}/${srcfile2}"
> +
> +# Build both source files to objects using language LANG. Use SYMBOLS to build
> +# the with either debug symbols or without - but always build the main file

"build the with" is missing a word?

> +# with debug. Then make function calls across the files.

Double space after periods please, twice.

> +
> +proc build_and_run_test { lang symbols } {
> +
> +    global main_basename lib_basename mainsrc libsrc binfile testfile
> +    global gdb_prompt
> +
> +    if { $symbols == "debug" } {
> +     set debug_flags "debug"
> +    } else {
> +        set debug_flags ""
> +    }

Mind space vs tabs above.  Double check the rest of the patch too, please.

> +
> +    # Setup directory.
> +
> +    set dir "$lang-$symbols"
> +    remote_exec build "rm -rf [standard_output_file ${dir}]"
> +    remote_exec build "mkdir -p [standard_output_file ${dir}]"
> +
> +    # Compile both files to objects, then link together.
> +
> +    set main_flags "$lang debug"
> +    set lib_flags "$lang $debug_flags"
> +    set main_o [standard_output_file ${dir}/${main_basename}.o]
> +    set lib_o [standard_output_file ${dir}/${lib_basename}.o]
> +    set binfile [standard_output_file ${dir}/${testfile}]
> +
> +    if { [gdb_compile $mainsrc $main_o object ${main_flags}] != "" } {
> +        untested "failed to compile main file to object"
> +        return -1
> +    }
> +
> +    if { [gdb_compile $libsrc $lib_o object ${lib_flags}] != "" } {
> +        untested "failed to compile secondary file to object"
> +        return -1
> +    }
> +
> +    if { [gdb_compile "$main_o $lib_o" ${binfile} executable ""] != "" } {
> +        untested "failed to compile"
> +        return -1
> +    }
> +
> +    # Startup and run to main.
> +
> +    clean_restart $binfile
> +
> +    if ![runto_main] then {
> +        fail "can't run to main"
> +        return
> +    }
> +
> +    # Function call with cast.
> +
> +    set test "p (int)foo()"
> +    gdb_test_multiple $test $test {
> +        -re " = 1\r\n$gdb_prompt " {
> +    pass $test
> +        }
> + default {
> +    fail $test
> + }
> +    }

No need for the "default" case.  gdb_test_multiple already
issues a FAIL in that case.  And if you remove that, a
plain gdb_test instead should work:

    gdb_test "p (int)foo()" " = 1"

Unless the missing $ anchor was on purpose?

> +
> +    # Function call without cast. Will error if there are no debug symbols.

Double-space after periods.

> +
> +    set test "p foo()"
> +    gdb_test_multiple $test $test {
> +        -re " = 1\r\n$gdb_prompt " {
> +    if { $symbols == "debug" } {
> +        pass $test
> +    } else {
> +     fail $test
> +    }

You can write

  gdb_assert { $symbols == "debug" }

instead of the if/else.

> +        }
> +        -re "has unknown return type; cast the call to its declared return type\r\n$gdb_prompt " {
> +    if { $symbols != "debug" } {
> +        pass $test
> +    } else {
> +     fail $test
> +    }

Ditto.

> +        }
> + default {
> +    fail $test
> + }

Drop the default case.

> +    }
> +
> +}
> +
> +foreach_with_prefix l $lang {
> +    foreach_with_prefix s {debug nodebug} {
> +        build_and_run_test $l $s
> +    }
> +}
> +
>

OK with those fixed.  Please post what you end up pushing.

Thanks,
Pedro Alves