[Crosstoolchain-logs] [gdb] 01/03: d/p/ppc64le.diff: apply upstream patch for ppc64le support
Hector Oron
zumbi at moszumanska.debian.org
Thu May 8 10:12:14 UTC 2014
This is an automated email from the git hooks/post-receive script.
zumbi pushed a commit to branch master
in repository gdb.
commit f792ebf5e416cbefb2b134494fe0bf3a89e602ab
Author: Héctor Orón Martínez <zumbi at debian.org>
Date: Thu May 8 11:55:32 2014 +0200
d/p/ppc64le.diff: apply upstream patch for ppc64le support
Signed-off-by: Héctor Orón Martínez <zumbi at debian.org>
---
debian/patches/ppc64le.diff | 2300 +++++++++++++++++++++++++++++++++++++++++++
debian/patches/series | 1 +
2 files changed, 2301 insertions(+)
diff --git a/debian/patches/ppc64le.diff b/debian/patches/ppc64le.diff
new file mode 100644
index 0000000..db9cf78
--- /dev/null
+++ b/debian/patches/ppc64le.diff
@@ -0,0 +1,2300 @@
+gdb/
+
+2014-02-04 Ulrich Weigand <uweigand at de.ibm.com>
+
+ * gdbarch.sh (skip_entrypoint): New callback.
+ * gdbarch.c, gdbarch.h: Regenerate.
+ * symtab.c (skip_prologue_sal): Call gdbarch_skip_entrypoint.
+ * infrun.c (fill_in_stop_func): Likewise.
+ * ppc-linux-tdep.c: Include "elf/ppc64.h".
+ (ppc_elfv2_elf_make_msymbol_special): New function.
+ (ppc_elfv2_skip_entrypoint): Likewise.
+ (ppc_linux_init_abi): Install them for ELFv2.
+
+2014-02-04 Ulrich Weigand <uweigand at de.ibm.com>
+
+ * ppc-sysv-tdep.c (ppc64_aggregate_candidate): New routine.
+ (ppc64_elfv2_abi_homogeneous_aggregate): Likewise.
+ (ppc64_sysv_abi_push_param): Handle ELFv2 homogeneous structs.
+ (ppc64_sysv_abi_return_value): Likewise. Also, handle small
+ structures returned in GPRs.
+
+2014-02-04 Ulrich Weigand <uweigand at de.ibm.com>
+
+ * ppc-sysv-tdep.c (ppc64_sysv_abi_push_dummy_call): Use correct
+ offset to the stack parameter list for the ELFv2 ABI.
+
+2014-02-04 Ulrich Weigand <uweigand at de.ibm.com>
+
+ * ppc-linux-tdep.c (ppc_linux_init_abi): Only call
+ set_gdbarch_convert_from_func_ptr_addr and
+ set_gdbarch_elf_make_msymbol_special for ELFv1.
+ * ppc-sysv-tdep.c (ppc64_sysv_abi_push_param): Only handle
+ function descriptors on ELFv1.
+ (ppc64_sysv_abi_push_dummy_call): Likewise. On ELFv2,
+ set up r12 at function entry.
+
+2014-02-04 Ulrich Weigand <uweigand at de.ibm.com>
+
+ * ppc-tdep.h (enum powerpc_elf_abi): New data type.
+ (struct gdbarch_tdep): New member elf_abi.
+
+ * rs6000-tdep.c: Include "elf/ppc64.h".
+ (rs6000_gdbarch_init): Detect ELF ABI version.
+
+2014-02-04 Ulrich Weigand <uweigand at de.ibm.com>
+
+ * ppc-sysv-tdep.c (ppc64_sysv_abi_push_freg): Use correct order
+ within a register pair holding a DFP 128-bit value on little-endian.
+ (ppc64_sysv_abi_return_value_base): Likewise.
+ * rs6000-tdep.c (dfp_pseudo_register_read): Likewise.
+ (dfp_pseudo_register_write): Likewise.
+
+2014-02-04 Ulrich Weigand <uweigand at de.ibm.com>
+
+ * ppc-sysv-tdep.c (ppc64_sysv_abi_push_freg): Use correct
+ offset on little-endian when passing _Decimal32.
+ (ppc64_sysv_abi_return_value_base): Likewise for return values.
+
+2014-02-04 Ulrich Weigand <uweigand at de.ibm.com>
+
+ * rs6000-tdep.c (efpr_pseudo_register_read): Use correct offset
+ of the overlapped FP register within the VSX register on little-
+ endian platforms.
+ (efpr_pseudo_register_write): Likewise.
+
+2014-02-04 Ulrich Weigand <uweigand at de.ibm.com>
+
+ * ppc-sysv-tdep.c (ppc64_sysv_abi_push_val): Use correct
+ offset on little-endian when passing small structures.
+
+2014-02-04 Ulrich Weigand <uweigand at de.ibm.com>
+
+ * ppc-sysv-tdep.c (get_decimal_float_return_value): Update comment.
+ (struct ppc64_sysv_argpos): New data structure.
+ (ppc64_sysv_abi_push_float): Remove.
+ (ppc64_sysv_abi_push_val): New function.
+ (ppc64_sysv_abi_push_integer): Likewise.
+ (ppc64_sysv_abi_push_freg): Likewise.
+ (ppc64_sysv_abi_push_vreg): Likewise.
+ (ppc64_sysv_abi_push_param): Likewise.
+ (ppc64_sysv_abi_push_dummy_call): Refactor to use those new routines.
+ (ppc64_sysv_abi_return_value_base): New function.
+ (ppc64_sysv_abi_return_value): Refactor to use it.
+
+2014-02-04 Ulrich Weigand <uweigand at de.ibm.com>
+
+ * NEWS: Document new target powerpc64le-*-linux*.
+
+gdb/testsuite/
+
+2014-02-04 Ulrich Weigand <uweigand at de.ibm.com>
+
+ * gdb.base/sigbpt.exp: Do not use "*" when setting breakpoint
+ on a function.
+ * gdb.base/step-bt.c: Call hello via function pointer to make
+ sure its first instruction is executed on powerpc64le-linux.
+
+2014-02-04 Ulrich Weigand <uweigand at de.ibm.com>
+
+ * gdb.arch/powerpc-d128-regs.exp: Enable on powerpc64*-*.
+
+2014-02-04 Ulrich Weigand <uweigand at de.ibm.com>
+
+ * gdb.arch/vsx-regs.exp: Check target endianness. Provide variants
+ of the test patterns for use on little-endian systems.
+
+2014-02-04 Ulrich Weigand <uweigand at de.ibm.com>
+
+ * gdb.arch/altivec-regs.exp: Use gdb_test_multiple for endian test.
+ (decimal_vector): Fix for little-endian.
+
+Index: b/gdb/gdbarch.c
+===================================================================
+--- a/gdb/gdbarch.c
++++ b/gdb/gdbarch.c
+@@ -229,6 +229,7 @@
+ gdbarch_return_in_first_hidden_param_p_ftype *return_in_first_hidden_param_p;
+ gdbarch_skip_prologue_ftype *skip_prologue;
+ gdbarch_skip_main_prologue_ftype *skip_main_prologue;
++ gdbarch_skip_entrypoint_ftype *skip_entrypoint;
+ gdbarch_inner_than_ftype *inner_than;
+ gdbarch_breakpoint_from_pc_ftype *breakpoint_from_pc;
+ gdbarch_remote_breakpoint_from_pc_ftype *remote_breakpoint_from_pc;
+@@ -402,6 +403,7 @@
+ default_return_in_first_hidden_param_p, /* return_in_first_hidden_param_p */
+ 0, /* skip_prologue */
+ 0, /* skip_main_prologue */
++ 0, /* skip_entrypoint */
+ 0, /* inner_than */
+ 0, /* breakpoint_from_pc */
+ default_remote_breakpoint_from_pc, /* remote_breakpoint_from_pc */
+@@ -705,6 +707,7 @@
+ if (gdbarch->skip_prologue == 0)
+ fprintf_unfiltered (log, "\n\tskip_prologue");
+ /* Skip verify of skip_main_prologue, has predicate. */
++ /* Skip verify of skip_entrypoint, has predicate. */
+ if (gdbarch->inner_than == 0)
+ fprintf_unfiltered (log, "\n\tinner_than");
+ if (gdbarch->breakpoint_from_pc == 0)
+@@ -1332,6 +1335,12 @@
+ "gdbarch_dump: single_step_through_delay = <%s>\n",
+ host_address_to_string (gdbarch->single_step_through_delay));
+ fprintf_unfiltered (file,
++ "gdbarch_dump: gdbarch_skip_entrypoint_p() = %d\n",
++ gdbarch_skip_entrypoint_p (gdbarch));
++ fprintf_unfiltered (file,
++ "gdbarch_dump: skip_entrypoint = <%s>\n",
++ host_address_to_string (gdbarch->skip_entrypoint));
++ fprintf_unfiltered (file,
+ "gdbarch_dump: gdbarch_skip_main_prologue_p() = %d\n",
+ gdbarch_skip_main_prologue_p (gdbarch));
+ fprintf_unfiltered (file,
+@@ -2682,6 +2691,30 @@
+ }
+
+ int
++gdbarch_skip_entrypoint_p (struct gdbarch *gdbarch)
++{
++ gdb_assert (gdbarch != NULL);
++ return gdbarch->skip_entrypoint != NULL;
++}
++
++CORE_ADDR
++gdbarch_skip_entrypoint (struct gdbarch *gdbarch, CORE_ADDR ip)
++{
++ gdb_assert (gdbarch != NULL);
++ gdb_assert (gdbarch->skip_entrypoint != NULL);
++ if (gdbarch_debug >= 2)
++ fprintf_unfiltered (gdb_stdlog, "gdbarch_skip_entrypoint called\n");
++ return gdbarch->skip_entrypoint (gdbarch, ip);
++}
++
++void
++set_gdbarch_skip_entrypoint (struct gdbarch *gdbarch,
++ gdbarch_skip_entrypoint_ftype skip_entrypoint)
++{
++ gdbarch->skip_entrypoint = skip_entrypoint;
++}
++
++int
+ gdbarch_inner_than (struct gdbarch *gdbarch, CORE_ADDR lhs, CORE_ADDR rhs)
+ {
+ gdb_assert (gdbarch != NULL);
+Index: b/gdb/gdbarch.h
+===================================================================
+--- a/gdb/gdbarch.h
++++ b/gdb/gdbarch.h
+@@ -486,6 +486,24 @@
+ extern CORE_ADDR gdbarch_skip_main_prologue (struct gdbarch *gdbarch, CORE_ADDR ip);
+ extern void set_gdbarch_skip_main_prologue (struct gdbarch *gdbarch, gdbarch_skip_main_prologue_ftype *skip_main_prologue);
+
++/* On some platforms, a single function may provide multiple entry points,
++ e.g. one that is used for function-pointer calls and a different one
++ that is used for direct function calls.
++ In order to ensure that breakpoints set on the function will trigger
++ no matter via which entry point the function is entered, a platform
++ may provide the skip_entrypoint callback. It is called with IP set
++ to the main entry point of a function (as determined by the symbol table),
++ and should return the address of the innermost entry point, where the
++ actual breakpoint needs to be set. Note that skip_entrypoint is used
++ by GDB common code even when debugging optimized code, where skip_prologue
++ is not used. */
++
++extern int gdbarch_skip_entrypoint_p (struct gdbarch *gdbarch);
++
++typedef CORE_ADDR (gdbarch_skip_entrypoint_ftype) (struct gdbarch *gdbarch, CORE_ADDR ip);
++extern CORE_ADDR gdbarch_skip_entrypoint (struct gdbarch *gdbarch, CORE_ADDR ip);
++extern void set_gdbarch_skip_entrypoint (struct gdbarch *gdbarch, gdbarch_skip_entrypoint_ftype *skip_entrypoint);
++
+ typedef int (gdbarch_inner_than_ftype) (CORE_ADDR lhs, CORE_ADDR rhs);
+ extern int gdbarch_inner_than (struct gdbarch *gdbarch, CORE_ADDR lhs, CORE_ADDR rhs);
+ extern void set_gdbarch_inner_than (struct gdbarch *gdbarch, gdbarch_inner_than_ftype *inner_than);
+Index: b/gdb/gdbarch.sh
+===================================================================
+--- a/gdb/gdbarch.sh
++++ b/gdb/gdbarch.sh
+@@ -530,6 +530,19 @@
+
+ m:CORE_ADDR:skip_prologue:CORE_ADDR ip:ip:0:0
+ M:CORE_ADDR:skip_main_prologue:CORE_ADDR ip:ip
++# On some platforms, a single function may provide multiple entry points,
++# e.g. one that is used for function-pointer calls and a different one
++# that is used for direct function calls.
++# In order to ensure that breakpoints set on the function will trigger
++# no matter via which entry point the function is entered, a platform
++# may provide the skip_entrypoint callback. It is called with IP set
++# to the main entry point of a function (as determined by the symbol table),
++# and should return the address of the innermost entry point, where the
++# actual breakpoint needs to be set. Note that skip_entrypoint is used
++# by GDB common code even when debugging optimized code, where skip_prologue
++# is not used.
++M:CORE_ADDR:skip_entrypoint:CORE_ADDR ip:ip
++
+ f:int:inner_than:CORE_ADDR lhs, CORE_ADDR rhs:lhs, rhs:0:0
+ m:const gdb_byte *:breakpoint_from_pc:CORE_ADDR *pcptr, int *lenptr:pcptr, lenptr::0:
+ # Return the adjusted address and kind to use for Z0/Z1 packets.
+Index: b/gdb/infrun.c
+===================================================================
+--- a/gdb/infrun.c
++++ b/gdb/infrun.c
+@@ -3158,6 +3158,10 @@
+ ecs->stop_func_start
+ += gdbarch_deprecated_function_start_offset (gdbarch);
+
++ if (gdbarch_skip_entrypoint_p (gdbarch))
++ ecs->stop_func_start = gdbarch_skip_entrypoint (gdbarch,
++ ecs->stop_func_start);
++
+ ecs->stop_func_filled_in = 1;
+ }
+ }
+Index: b/gdb/ppc-linux-tdep.c
+===================================================================
+--- a/gdb/ppc-linux-tdep.c
++++ b/gdb/ppc-linux-tdep.c
+@@ -44,6 +44,7 @@
+ #include "observer.h"
+ #include "auxv.h"
+ #include "elf/common.h"
++#include "elf/ppc64.h"
+ #include "exceptions.h"
+ #include "arch-utils.h"
+ #include "spu-tdep.h"
+@@ -876,6 +877,55 @@
+ }
+ }
+
++
++/* Implementation of `gdbarch_elf_make_msymbol_special', as defined in
++ gdbarch.h. This implementation is used for the ELFv2 ABI only. */
++
++static void
++ppc_elfv2_elf_make_msymbol_special (asymbol *sym, struct minimal_symbol *msym)
++{
++ elf_symbol_type *elf_sym = (elf_symbol_type *)sym;
++
++ /* If the symbol is marked as having a local entry point, set a target
++ flag in the msymbol. We currently only support local entry point
++ offsets of 8 bytes, which is the only entry point offset ever used
++ by current compilers. If/when other offsets are ever used, we will
++ have to use additional target flag bits to store them. */
++ switch (PPC64_LOCAL_ENTRY_OFFSET (elf_sym->internal_elf_sym.st_other))
++ {
++ default:
++ break;
++ case 8:
++ MSYMBOL_TARGET_FLAG_1 (msym) = 1;
++ break;
++ }
++}
++
++/* Implementation of `gdbarch_skip_entrypoint', as defined in
++ gdbarch.h. This implementation is used for the ELFv2 ABI only. */
++
++static CORE_ADDR
++ppc_elfv2_skip_entrypoint (struct gdbarch *gdbarch, CORE_ADDR pc)
++{
++ struct bound_minimal_symbol fun;
++ int local_entry_offset = 0;
++
++ fun = lookup_minimal_symbol_by_pc (pc);
++ if (fun.minsym == NULL)
++ return pc;
++
++ /* See ppc_elfv2_elf_make_msymbol_special for how local entry point
++ offset values are encoded. */
++ if (MSYMBOL_TARGET_FLAG_1 (fun.minsym))
++ local_entry_offset = 8;
++
++ if (SYMBOL_VALUE_ADDRESS (fun.minsym) <= pc
++ && pc < SYMBOL_VALUE_ADDRESS (fun.minsym) + local_entry_offset)
++ return SYMBOL_VALUE_ADDRESS (fun.minsym) + local_entry_offset;
++
++ return pc;
++}
++
+ /* Implementation of `gdbarch_stap_is_single_operand', as defined in
+ gdbarch.h. */
+
+@@ -1339,13 +1389,23 @@
+
+ if (tdep->wordsize == 8)
+ {
+- /* Handle PPC GNU/Linux 64-bit function pointers (which are really
+- function descriptors). */
+- set_gdbarch_convert_from_func_ptr_addr
+- (gdbarch, ppc64_convert_from_func_ptr_addr);
++ if (tdep->elf_abi == POWERPC_ELF_V1)
++ {
++ /* Handle PPC GNU/Linux 64-bit function pointers (which are really
++ function descriptors). */
++ set_gdbarch_convert_from_func_ptr_addr
++ (gdbarch, ppc64_convert_from_func_ptr_addr);
++
++ set_gdbarch_elf_make_msymbol_special
++ (gdbarch, ppc64_elf_make_msymbol_special);
++ }
++ else
++ {
++ set_gdbarch_elf_make_msymbol_special
++ (gdbarch, ppc_elfv2_elf_make_msymbol_special);
+
+- set_gdbarch_elf_make_msymbol_special (gdbarch,
+- ppc64_elf_make_msymbol_special);
++ set_gdbarch_skip_entrypoint (gdbarch, ppc_elfv2_skip_entrypoint);
++ }
+
+ /* Shared library handling. */
+ set_gdbarch_skip_trampoline_code (gdbarch, ppc64_skip_trampoline_code);
+Index: b/gdb/ppc-sysv-tdep.c
+===================================================================
+--- a/gdb/ppc-sysv-tdep.c
++++ b/gdb/ppc-sysv-tdep.c
+@@ -609,8 +609,7 @@
+ return sp;
+ }
+
+-/* Handle the return-value conventions for Decimal Floating Point values
+- in both ppc32 and ppc64, which are the same. */
++/* Handle the return-value conventions for Decimal Floating Point values. */
+ static int
+ get_decimal_float_return_value (struct gdbarch *gdbarch, struct type *valtype,
+ struct regcache *regcache, gdb_byte *readbuf,
+@@ -1102,80 +1101,471 @@
+ return 1;
+ }
+
+-/* Push a float in either registers, or in the stack. Using the ppc 64 bit
+- SysV ABI.
++/* Walk down the type tree of TYPE counting consecutive base elements.
++ If *FIELD_TYPE is NULL, then set it to the first valid floating point
++ or vector type. If a non-floating point or vector type is found, or
++ if a floating point or vector type that doesn't match a non-NULL
++ *FIELD_TYPE is found, then return -1, otherwise return the count in the
++ sub-tree. */
++
++static LONGEST
++ppc64_aggregate_candidate (struct type *type,
++ struct type **field_type)
++{
++ type = check_typedef (type);
+
+- This implements a dumbed down version of the ABI. It always writes
+- values to memory, GPR and FPR, even when not necessary. Doing this
+- greatly simplifies the logic. */
++ switch (TYPE_CODE (type))
++ {
++ case TYPE_CODE_FLT:
++ case TYPE_CODE_DECFLOAT:
++ if (!*field_type)
++ *field_type = type;
++ if (TYPE_CODE (*field_type) == TYPE_CODE (type)
++ && TYPE_LENGTH (*field_type) == TYPE_LENGTH (type))
++ return 1;
++ break;
++
++ case TYPE_CODE_COMPLEX:
++ type = TYPE_TARGET_TYPE (type);
++ if (TYPE_CODE (type) == TYPE_CODE_FLT
++ || TYPE_CODE (type) == TYPE_CODE_DECFLOAT)
++ {
++ if (!*field_type)
++ *field_type = type;
++ if (TYPE_CODE (*field_type) == TYPE_CODE (type)
++ && TYPE_LENGTH (*field_type) == TYPE_LENGTH (type))
++ return 2;
++ }
++ break;
++
++ case TYPE_CODE_ARRAY:
++ if (TYPE_VECTOR (type))
++ {
++ if (!*field_type)
++ *field_type = type;
++ if (TYPE_CODE (*field_type) == TYPE_CODE (type)
++ && TYPE_LENGTH (*field_type) == TYPE_LENGTH (type))
++ return 1;
++ }
++ else
++ {
++ LONGEST count, low_bound, high_bound;
++
++ count = ppc64_aggregate_candidate
++ (TYPE_TARGET_TYPE (type), field_type);
++ if (count == -1)
++ return -1;
++
++ if (!get_array_bounds (type, &low_bound, &high_bound))
++ return -1;
++ count *= high_bound - low_bound;
++
++ /* There must be no padding. */
++ if (count == 0)
++ return TYPE_LENGTH (type) == 0 ? 0 : -1;
++ else if (TYPE_LENGTH (type) != count * TYPE_LENGTH (*field_type))
++ return -1;
++
++ return count;
++ }
++ break;
++
++ case TYPE_CODE_STRUCT:
++ case TYPE_CODE_UNION:
++ {
++ LONGEST count = 0;
++ int i;
++
++ for (i = 0; i < TYPE_NFIELDS (type); i++)
++ {
++ LONGEST sub_count;
++
++ if (field_is_static (&TYPE_FIELD (type, i)))
++ continue;
++
++ sub_count = ppc64_aggregate_candidate
++ (TYPE_FIELD_TYPE (type, i), field_type);
++ if (sub_count == -1)
++ return -1;
++
++ if (TYPE_CODE (type) == TYPE_CODE_STRUCT)
++ count += sub_count;
++ else
++ count = max (count, sub_count);
++ }
++
++ /* There must be no padding. */
++ if (count == 0)
++ return TYPE_LENGTH (type) == 0 ? 0 : -1;
++ else if (TYPE_LENGTH (type) != count * TYPE_LENGTH (*field_type))
++ return -1;
++
++ return count;
++ }
++ break;
++
++ default:
++ break;
++ }
++
++ return -1;
++}
++
++/* If an argument of type TYPE is a homogeneous float or vector aggregate
++ that shall be passed in FP/vector registers according to the ELFv2 ABI,
++ return the homogeneous element type in *ELT_TYPE and the number of
++ elements in *N_ELTS, and return non-zero. Otherwise, return zero. */
++
++static int
++ppc64_elfv2_abi_homogeneous_aggregate (struct type *type,
++ struct type **elt_type, int *n_elts)
++{
++ /* Complex types at the top level are treated separately. However,
++ complex types can be elements of homogeneous aggregates. */
++ if (TYPE_CODE (type) == TYPE_CODE_STRUCT
++ || TYPE_CODE (type) == TYPE_CODE_UNION
++ || (TYPE_CODE (type) == TYPE_CODE_ARRAY && !TYPE_VECTOR (type)))
++ {
++ struct type *field_type = NULL;
++ LONGEST field_count = ppc64_aggregate_candidate (type, &field_type);
++
++ if (field_count > 0)
++ {
++ int n_regs = ((TYPE_CODE (field_type) == TYPE_CODE_FLT
++ || TYPE_CODE (field_type) == TYPE_CODE_DECFLOAT)?
++ (TYPE_LENGTH (field_type) + 7) >> 3 : 1);
++
++ /* The ELFv2 ABI allows homogeneous aggregates to occupy
++ up to 8 registers. */
++ if (field_count * n_regs <= 8)
++ {
++ if (elt_type)
++ *elt_type = field_type;
++ if (n_elts)
++ *n_elts = (int) field_count;
++ /* Note that field_count is LONGEST since it may hold the size
++ of an array, while *n_elts is int since its value is bounded
++ by the number of registers used for argument passing. The
++ cast cannot overflow due to the bounds checking above. */
++ return 1;
++ }
++ }
++ }
++
++ return 0;
++}
++
++/* Structure holding the next argument position. */
++struct ppc64_sysv_argpos
++ {
++ /* Register cache holding argument registers. If this is NULL,
++ we only simulate argument processing without actually updating
++ any registers or memory. */
++ struct regcache *regcache;
++ /* Next available general-purpose argument register. */
++ int greg;
++ /* Next available floating-point argument register. */
++ int freg;
++ /* Next available vector argument register. */
++ int vreg;
++ /* The address, at which the next general purpose parameter
++ (integer, struct, float, vector, ...) should be saved. */
++ CORE_ADDR gparam;
++ /* The address, at which the next by-reference parameter
++ (non-Altivec vector, variably-sized type) should be saved. */
++ CORE_ADDR refparam;
++ };
++
++/* VAL is a value of length LEN. Store it into the argument area on the
++ stack and load it into the corresponding general-purpose registers
++ required by the ABI, and update ARGPOS.
++
++ If ALIGN is nonzero, it specifies the minimum alignment required
++ for the on-stack copy of the argument. */
+
+ static void
+-ppc64_sysv_abi_push_float (struct gdbarch *gdbarch, struct regcache *regcache,
+- struct gdbarch_tdep *tdep, struct type *type,
+- const bfd_byte *val, int freg, int greg,
+- CORE_ADDR gparam)
++ppc64_sysv_abi_push_val (struct gdbarch *gdbarch,
++ const bfd_byte *val, int len, int align,
++ struct ppc64_sysv_argpos *argpos)
+ {
+- gdb_byte regval[MAX_REGISTER_SIZE];
+- const gdb_byte *p;
++ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
++ int offset = 0;
+
+- if (TYPE_LENGTH (type) <= 8)
++ /* Enforce alignment of stack location, if requested. */
++ if (align > tdep->wordsize)
+ {
+- /* Version 1.7 of the 64-bit PowerPC ELF ABI says:
++ CORE_ADDR aligned_gparam = align_up (argpos->gparam, align);
++
++ argpos->greg += (aligned_gparam - argpos->gparam) / tdep->wordsize;
++ argpos->gparam = aligned_gparam;
++ }
+
+- "Single precision floating point values are mapped to
+- the first word in a single doubleword."
++ /* The ABI (version 1.9) specifies that values smaller than one
++ doubleword are right-aligned and those larger are left-aligned.
++ GCC versions before 3.4 implemented this incorrectly; see
++ <http://gcc.gnu.org/gcc-3.4/powerpc-abi.html>. */
++ if (len < tdep->wordsize
++ && gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
++ offset = tdep->wordsize - len;
+
+- And version 1.9 says:
++ if (argpos->regcache)
++ write_memory (argpos->gparam + offset, val, len);
++ argpos->gparam = align_up (argpos->gparam + len, tdep->wordsize);
+
+- "Single precision floating point values are mapped to
+- the second word in a single doubleword."
++ while (len >= tdep->wordsize)
++ {
++ if (argpos->regcache && argpos->greg <= 10)
++ regcache_cooked_write (argpos->regcache,
++ tdep->ppc_gp0_regnum + argpos->greg, val);
++ argpos->greg++;
++ len -= tdep->wordsize;
++ val += tdep->wordsize;
++ }
+
+- GDB then writes single precision floating point values
+- at both words in a doubleword, to support both ABIs. */
+- if (TYPE_LENGTH (type) == 4)
++ if (len > 0)
++ {
++ if (argpos->regcache && argpos->greg <= 10)
++ regcache_cooked_write_part (argpos->regcache,
++ tdep->ppc_gp0_regnum + argpos->greg,
++ offset, len, val);
++ argpos->greg++;
++ }
++}
++
++/* The same as ppc64_sysv_abi_push_val, but using a single-word integer
++ value VAL as argument. */
++
++static void
++ppc64_sysv_abi_push_integer (struct gdbarch *gdbarch, ULONGEST val,
++ struct ppc64_sysv_argpos *argpos)
++{
++ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
++ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
++ gdb_byte buf[MAX_REGISTER_SIZE];
++
++ if (argpos->regcache)
++ store_unsigned_integer (buf, tdep->wordsize, byte_order, val);
++ ppc64_sysv_abi_push_val (gdbarch, buf, tdep->wordsize, 0, argpos);
++}
++
++/* VAL is a value of TYPE, a (binary or decimal) floating-point type.
++ Load it into a floating-point register if required by the ABI,
++ and update ARGPOS. */
++
++static void
++ppc64_sysv_abi_push_freg (struct gdbarch *gdbarch,
++ struct type *type, const bfd_byte *val,
++ struct ppc64_sysv_argpos *argpos)
++{
++ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
++ if (tdep->soft_float)
++ return;
++
++ if (TYPE_LENGTH (type) <= 8
++ && TYPE_CODE (type) == TYPE_CODE_FLT)
++ {
++ /* Floats and doubles go in f1 .. f13. 32-bit floats are converted
++ to double first. */
++ if (argpos->regcache && argpos->freg <= 13)
+ {
+- memcpy (regval, val, 4);
+- memcpy (regval + 4, val, 4);
+- p = regval;
++ int regnum = tdep->ppc_fp0_regnum + argpos->freg;
++ struct type *regtype = register_type (gdbarch, regnum);
++ gdb_byte regval[MAX_REGISTER_SIZE];
++
++ convert_typed_floating (val, type, regval, regtype);
++ regcache_cooked_write (argpos->regcache, regnum, regval);
+ }
+- else
+- p = val;
+
+- /* Write value in the stack's parameter save area. */
+- write_memory (gparam, p, 8);
++ argpos->freg++;
++ }
++ else if (TYPE_LENGTH (type) <= 8
++ && TYPE_CODE (type) == TYPE_CODE_DECFLOAT)
++ {
++ /* Floats and doubles go in f1 .. f13. 32-bit decimal floats are
++ placed in the least significant word. */
++ if (argpos->regcache && argpos->freg <= 13)
++ {
++ int regnum = tdep->ppc_fp0_regnum + argpos->freg;
++ int offset = 0;
++
++ if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
++ offset = 8 - TYPE_LENGTH (type);
++
++ regcache_cooked_write_part (argpos->regcache, regnum,
++ offset, TYPE_LENGTH (type), val);
++ }
+
+- /* Floats and Doubles go in f1 .. f13. They also consume a left aligned
+- GREG, and can end up in memory. */
+- if (freg <= 13)
++ argpos->freg++;
++ }
++ else if (TYPE_LENGTH (type) == 16
++ && TYPE_CODE (type) == TYPE_CODE_FLT
++ && (gdbarch_long_double_format (gdbarch)
++ == floatformats_ibm_long_double))
++ {
++ /* IBM long double stored in two consecutive FPRs. */
++ if (argpos->regcache && argpos->freg <= 13)
+ {
+- struct type *regtype;
++ int regnum = tdep->ppc_fp0_regnum + argpos->freg;
+
+- regtype = register_type (gdbarch, tdep->ppc_fp0_regnum + freg);
+- convert_typed_floating (val, type, regval, regtype);
+- regcache_cooked_write (regcache, tdep->ppc_fp0_regnum + freg, regval);
++ regcache_cooked_write (argpos->regcache, regnum, val);
++ if (argpos->freg <= 12)
++ regcache_cooked_write (argpos->regcache, regnum + 1, val + 8);
++ }
++
++ argpos->freg += 2;
++ }
++ else if (TYPE_LENGTH (type) == 16
++ && TYPE_CODE (type) == TYPE_CODE_DECFLOAT)
++ {
++ /* 128-bit decimal floating-point values are stored in and even/odd
++ pair of FPRs, with the even FPR holding the most significant half. */
++ argpos->freg += argpos->freg & 1;
++
++ if (argpos->regcache && argpos->freg <= 12)
++ {
++ int regnum = tdep->ppc_fp0_regnum + argpos->freg;
++ int lopart = gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG ? 8 : 0;
++ int hipart = gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG ? 0 : 8;
++
++ regcache_cooked_write (argpos->regcache, regnum, val + hipart);
++ regcache_cooked_write (argpos->regcache, regnum + 1, val + lopart);
+ }
+- if (greg <= 10)
+- regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + greg, regval);
++
++ argpos->freg += 2;
++ }
++}
++
++/* VAL is a value of AltiVec vector type. Load it into a vector register
++ if required by the ABI, and update ARGPOS. */
++
++static void
++ppc64_sysv_abi_push_vreg (struct gdbarch *gdbarch, const bfd_byte *val,
++ struct ppc64_sysv_argpos *argpos)
++{
++ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
++
++ if (argpos->regcache && argpos->vreg <= 13)
++ regcache_cooked_write (argpos->regcache,
++ tdep->ppc_vr0_regnum + argpos->vreg, val);
++
++ argpos->vreg++;
++}
++
++/* VAL is a value of TYPE. Load it into memory and/or registers
++ as required by the ABI, and update ARGPOS. */
++
++static void
++ppc64_sysv_abi_push_param (struct gdbarch *gdbarch,
++ struct type *type, const bfd_byte *val,
++ struct ppc64_sysv_argpos *argpos)
++{
++ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
++
++ if (TYPE_CODE (type) == TYPE_CODE_FLT
++ || TYPE_CODE (type) == TYPE_CODE_DECFLOAT)
++ {
++ /* Floating-point scalars are passed in floating-point registers. */
++ ppc64_sysv_abi_push_val (gdbarch, val, TYPE_LENGTH (type), 0, argpos);
++ ppc64_sysv_abi_push_freg (gdbarch, type, val, argpos);
++ }
++ else if (TYPE_CODE (type) == TYPE_CODE_ARRAY && TYPE_VECTOR (type)
++ && tdep->vector_abi == POWERPC_VEC_ALTIVEC
++ && TYPE_LENGTH (type) == 16)
++ {
++ /* AltiVec vectors are passed aligned, and in vector registers. */
++ ppc64_sysv_abi_push_val (gdbarch, val, TYPE_LENGTH (type), 16, argpos);
++ ppc64_sysv_abi_push_vreg (gdbarch, val, argpos);
++ }
++ else if (TYPE_CODE (type) == TYPE_CODE_ARRAY && TYPE_VECTOR (type)
++ && TYPE_LENGTH (type) >= 16)
++ {
++ /* Non-Altivec vectors are passed by reference. */
++
++ /* Copy value onto the stack ... */
++ CORE_ADDR addr = align_up (argpos->refparam, 16);
++ if (argpos->regcache)
++ write_memory (addr, val, TYPE_LENGTH (type));
++ argpos->refparam = align_up (addr + TYPE_LENGTH (type), tdep->wordsize);
++
++ /* ... and pass a pointer to the copy as parameter. */
++ ppc64_sysv_abi_push_integer (gdbarch, addr, argpos);
++ }
++ else if ((TYPE_CODE (type) == TYPE_CODE_INT
++ || TYPE_CODE (type) == TYPE_CODE_ENUM
++ || TYPE_CODE (type) == TYPE_CODE_BOOL
++ || TYPE_CODE (type) == TYPE_CODE_CHAR
++ || TYPE_CODE (type) == TYPE_CODE_PTR
++ || TYPE_CODE (type) == TYPE_CODE_REF)
++ && TYPE_LENGTH (type) <= tdep->wordsize)
++ {
++ ULONGEST word = 0;
++
++ if (argpos->regcache)
++ {
++ /* Sign extend the value, then store it unsigned. */
++ word = unpack_long (type, val);
++
++ /* Convert any function code addresses into descriptors. */
++ if (tdep->elf_abi == POWERPC_ELF_V1
++ && (TYPE_CODE (type) == TYPE_CODE_PTR
++ || TYPE_CODE (type) == TYPE_CODE_REF))
++ {
++ struct type *target_type
++ = check_typedef (TYPE_TARGET_TYPE (type));
++
++ if (TYPE_CODE (target_type) == TYPE_CODE_FUNC
++ || TYPE_CODE (target_type) == TYPE_CODE_METHOD)
++ {
++ CORE_ADDR desc = word;
++
++ convert_code_addr_to_desc_addr (word, &desc);
++ word = desc;
++ }
++ }
++ }
++
++ ppc64_sysv_abi_push_integer (gdbarch, word, argpos);
+ }
+ else
+ {
+- /* IBM long double stored in two doublewords of the
+- parameter save area and corresponding registers. */
+- if (!tdep->soft_float && freg <= 13)
+- {
+- regcache_cooked_write (regcache, tdep->ppc_fp0_regnum + freg, val);
+- if (freg <= 12)
+- regcache_cooked_write (regcache, tdep->ppc_fp0_regnum + freg + 1,
+- val + 8);
+- }
+- if (greg <= 10)
+- {
+- regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + greg, val);
+- if (greg <= 9)
+- regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + greg + 1,
+- val + 8);
++ ppc64_sysv_abi_push_val (gdbarch, val, TYPE_LENGTH (type), 0, argpos);
++
++ /* The ABI (version 1.9) specifies that structs containing a
++ single floating-point value, at any level of nesting of
++ single-member structs, are passed in floating-point registers. */
++ if (TYPE_CODE (type) == TYPE_CODE_STRUCT
++ && TYPE_NFIELDS (type) == 1)
++ {
++ while (TYPE_CODE (type) == TYPE_CODE_STRUCT
++ && TYPE_NFIELDS (type) == 1)
++ type = check_typedef (TYPE_FIELD_TYPE (type, 0));
++
++ if (TYPE_CODE (type) == TYPE_CODE_FLT)
++ ppc64_sysv_abi_push_freg (gdbarch, type, val, argpos);
++ }
++
++ /* In the ELFv2 ABI, homogeneous floating-point or vector
++ aggregates are passed in a series of registers. */
++ if (tdep->elf_abi == POWERPC_ELF_V2)
++ {
++ struct type *eltype;
++ int i, nelt;
++
++ if (ppc64_elfv2_abi_homogeneous_aggregate (type, &eltype, &nelt))
++ for (i = 0; i < nelt; i++)
++ {
++ const gdb_byte *elval = val + i * TYPE_LENGTH (eltype);
++
++ if (TYPE_CODE (eltype) == TYPE_CODE_FLT
++ || TYPE_CODE (eltype) == TYPE_CODE_DECFLOAT)
++ ppc64_sysv_abi_push_freg (gdbarch, eltype, elval, argpos);
++ else if (TYPE_CODE (eltype) == TYPE_CODE_ARRAY
++ && TYPE_VECTOR (eltype)
++ && tdep->vector_abi == POWERPC_VEC_ALTIVEC
++ && TYPE_LENGTH (eltype) == 16)
++ ppc64_sysv_abi_push_vreg (gdbarch, elval, argpos);
++ }
+ }
+- write_memory (gparam, val, TYPE_LENGTH (type));
+ }
+ }
+
+@@ -1237,20 +1627,11 @@
+ for (write_pass = 0; write_pass < 2; write_pass++)
+ {
+ int argno;
+- /* Next available floating point register for float and double
+- arguments. */
+- int freg = 1;
+- /* Next available general register for non-vector (but possibly
+- float) arguments. */
+- int greg = 3;
+- /* Next available vector register for vector arguments. */
+- int vreg = 2;
+- /* The address, at which the next general purpose parameter
+- (integer, struct, float, vector, ...) should be saved. */
+- CORE_ADDR gparam;
+- /* The address, at which the next by-reference parameter
+- (non-Altivec vector, variably-sized type) should be saved. */
+- CORE_ADDR refparam;
++
++ struct ppc64_sysv_argpos argpos;
++ argpos.greg = 3;
++ argpos.freg = 1;
++ argpos.vreg = 2;
+
+ if (!write_pass)
+ {
+@@ -1258,19 +1639,25 @@
+ offsets (start address zero) than addresses. That way
+ they accumulate the total stack space each region
+ requires. */
+- gparam = 0;
+- refparam = 0;
++ argpos.regcache = NULL;
++ argpos.gparam = 0;
++ argpos.refparam = 0;
+ }
+ else
+ {
+ /* Decrement the stack pointer making space for the Altivec
+ and general on-stack parameters. Set refparam and gparam
+ to their corresponding regions. */
+- refparam = align_down (sp - refparam_size, 16);
+- gparam = align_down (refparam - gparam_size, 16);
+- /* Add in space for the TOC, link editor double word,
+- compiler double word, LR save area, CR save area. */
+- sp = align_down (gparam - 48, 16);
++ argpos.regcache = regcache;
++ argpos.refparam = align_down (sp - refparam_size, 16);
++ argpos.gparam = align_down (argpos.refparam - gparam_size, 16);
++ /* Add in space for the TOC, link editor double word (v1 only),
++ compiler double word (v1 only), LR save area, CR save area,
++ and backchain. */
++ if (tdep->elf_abi == POWERPC_ELF_V1)
++ sp = align_down (argpos.gparam - 48, 16);
++ else
++ sp = align_down (argpos.gparam - 32, 16);
+ }
+
+ /* If the function is returning a `struct', then there is an
+@@ -1279,14 +1666,7 @@
+ should advance one word and start from r4 register to copy
+ parameters. This also consumes one on-stack parameter slot. */
+ if (struct_return)
+- {
+- if (write_pass)
+- regcache_cooked_write_signed (regcache,
+- tdep->ppc_gp0_regnum + greg,
+- struct_addr);
+- greg++;
+- gparam = align_up (gparam + tdep->wordsize, tdep->wordsize);
+- }
++ ppc64_sysv_abi_push_integer (gdbarch, struct_addr, &argpos);
+
+ for (argno = 0; argno < nargs; argno++)
+ {
+@@ -1294,432 +1674,54 @@
+ struct type *type = check_typedef (value_type (arg));
+ const bfd_byte *val = value_contents (arg);
+
+- if (TYPE_CODE (type) == TYPE_CODE_FLT && TYPE_LENGTH (type) <= 8)
+- {
+- if (write_pass)
+- ppc64_sysv_abi_push_float (gdbarch, regcache, tdep, type,
+- val, freg, greg, gparam);
+-
+- freg++;
+- greg++;
+- /* Always consume parameter stack space. */
+- gparam = align_up (gparam + 8, tdep->wordsize);
+- }
+- else if (TYPE_CODE (type) == TYPE_CODE_FLT
+- && TYPE_LENGTH (type) == 16
+- && (gdbarch_long_double_format (gdbarch)
+- == floatformats_ibm_long_double))
+- {
+- if (write_pass)
+- ppc64_sysv_abi_push_float (gdbarch, regcache, tdep, type,
+- val, freg, greg, gparam);
+- freg += 2;
+- greg += 2;
+- gparam = align_up (gparam + TYPE_LENGTH (type), tdep->wordsize);
+- }
+- else if (TYPE_CODE (type) == TYPE_CODE_COMPLEX
+- && (TYPE_LENGTH (type) == 8 || TYPE_LENGTH (type) == 16))
+- {
+- int i;
+-
+- for (i = 0; i < 2; i++)
+- {
+- if (write_pass)
+- {
+- struct type *target_type;
+-
+- target_type = check_typedef (TYPE_TARGET_TYPE (type));
+- ppc64_sysv_abi_push_float (gdbarch, regcache, tdep,
+- target_type, val + i *
+- TYPE_LENGTH (target_type),
+- freg, greg, gparam);
+- }
+- freg++;
+- greg++;
+- /* Always consume parameter stack space. */
+- gparam = align_up (gparam + 8, tdep->wordsize);
+- }
+- }
+- else if (TYPE_CODE (type) == TYPE_CODE_COMPLEX
+- && TYPE_LENGTH (type) == 32
+- && (gdbarch_long_double_format (gdbarch)
+- == floatformats_ibm_long_double))
+- {
+- int i;
+-
+- for (i = 0; i < 2; i++)
+- {
+- struct type *target_type;
+-
+- target_type = check_typedef (TYPE_TARGET_TYPE (type));
+- if (write_pass)
+- ppc64_sysv_abi_push_float (gdbarch, regcache, tdep,
+- target_type, val + i *
+- TYPE_LENGTH (target_type),
+- freg, greg, gparam);
+- freg += 2;
+- greg += 2;
+- gparam = align_up (gparam + TYPE_LENGTH (target_type),
+- tdep->wordsize);
+- }
+- }
+- else if (TYPE_CODE (type) == TYPE_CODE_DECFLOAT
+- && TYPE_LENGTH (type) <= 8)
+- {
+- /* 32-bit and 64-bit decimal floats go in f1 .. f13. They can
+- end up in memory. */
+- if (write_pass)
+- {
+- gdb_byte regval[MAX_REGISTER_SIZE];
+- const gdb_byte *p;
+-
+- /* 32-bit decimal floats are right aligned in the
+- doubleword. */
+- if (TYPE_LENGTH (type) == 4)
+- {
+- memcpy (regval + 4, val, 4);
+- p = regval;
+- }
+- else
+- p = val;
+-
+- /* Write value in the stack's parameter save area. */
+- write_memory (gparam, p, 8);
+-
+- if (freg <= 13)
+- regcache_cooked_write (regcache,
+- tdep->ppc_fp0_regnum + freg, p);
+- }
+-
+- freg++;
+- greg++;
+- /* Always consume parameter stack space. */
+- gparam = align_up (gparam + 8, tdep->wordsize);
+- }
+- else if (TYPE_CODE (type) == TYPE_CODE_DECFLOAT &&
+- TYPE_LENGTH (type) == 16)
++ if (TYPE_CODE (type) == TYPE_CODE_COMPLEX)
+ {
+- /* 128-bit decimal floats go in f2 .. f12, always in even/odd
+- pairs. They can end up in memory, using two doublewords. */
+- if (write_pass)
+- {
+- if (freg <= 12)
+- {
+- /* Make sure freg is even. */
+- freg += freg & 1;
+- regcache_cooked_write (regcache,
+- tdep->ppc_fp0_regnum + freg, val);
+- regcache_cooked_write (regcache,
+- tdep->ppc_fp0_regnum + freg + 1, val + 8);
+- }
+-
+- write_memory (gparam, val, TYPE_LENGTH (type));
+- }
++ /* Complex types are passed as if two independent scalars. */
++ struct type *eltype = check_typedef (TYPE_TARGET_TYPE (type));
+
+- freg += 2;
+- greg += 2;
+- gparam = align_up (gparam + TYPE_LENGTH (type), tdep->wordsize);
++ ppc64_sysv_abi_push_param (gdbarch, eltype, val, &argpos);
++ ppc64_sysv_abi_push_param (gdbarch, eltype,
++ val + TYPE_LENGTH (eltype), &argpos);
+ }
+- else if (TYPE_LENGTH (type) < 16
+- && TYPE_CODE (type) == TYPE_CODE_ARRAY
+- && TYPE_VECTOR (type)
++ else if (TYPE_CODE (type) == TYPE_CODE_ARRAY && TYPE_VECTOR (type)
+ && opencl_abi)
+ {
+ /* OpenCL vectors shorter than 16 bytes are passed as if
+- a series of independent scalars. */
+- struct type *eltype = check_typedef (TYPE_TARGET_TYPE (type));
+- int i, nelt = TYPE_LENGTH (type) / TYPE_LENGTH (eltype);
++ a series of independent scalars; OpenCL vectors 16 bytes
++ or longer are passed as if a series of AltiVec vectors. */
++ struct type *eltype;
++ int i, nelt;
++
++ if (TYPE_LENGTH (type) < 16)
++ eltype = check_typedef (TYPE_TARGET_TYPE (type));
++ else
++ eltype = register_type (gdbarch, tdep->ppc_vr0_regnum);
+
++ nelt = TYPE_LENGTH (type) / TYPE_LENGTH (eltype);
+ for (i = 0; i < nelt; i++)
+ {
+ const gdb_byte *elval = val + i * TYPE_LENGTH (eltype);
+
+- if (TYPE_CODE (eltype) == TYPE_CODE_FLT)
+- {
+- if (write_pass)
+- {
+- gdb_byte regval[MAX_REGISTER_SIZE];
+- const gdb_byte *p;
+-
+- if (TYPE_LENGTH (eltype) == 4)
+- {
+- memcpy (regval, elval, 4);
+- memcpy (regval + 4, elval, 4);
+- p = regval;
+- }
+- else
+- p = elval;
+-
+- write_memory (gparam, p, 8);
+-
+- if (freg <= 13)
+- {
+- int regnum = tdep->ppc_fp0_regnum + freg;
+- struct type *regtype
+- = register_type (gdbarch, regnum);
+-
+- convert_typed_floating (elval, eltype,
+- regval, regtype);
+- regcache_cooked_write (regcache, regnum, regval);
+- }
+-
+- if (greg <= 10)
+- regcache_cooked_write (regcache,
+- tdep->ppc_gp0_regnum + greg,
+- regval);
+- }
+-
+- freg++;
+- greg++;
+- gparam = align_up (gparam + 8, tdep->wordsize);
+- }
+- else
+- {
+- if (write_pass)
+- {
+- ULONGEST word = unpack_long (eltype, elval);
+- if (greg <= 10)
+- regcache_cooked_write_unsigned
+- (regcache, tdep->ppc_gp0_regnum + greg, word);
+-
+- write_memory_unsigned_integer
+- (gparam, tdep->wordsize, byte_order, word);
+- }
+-
+- greg++;
+- gparam = align_up (gparam + TYPE_LENGTH (eltype),
+- tdep->wordsize);
+- }
+- }
+- }
+- else if (TYPE_LENGTH (type) >= 16
+- && TYPE_CODE (type) == TYPE_CODE_ARRAY
+- && TYPE_VECTOR (type)
+- && opencl_abi)
+- {
+- /* OpenCL vectors 16 bytes or longer are passed as if
+- a series of AltiVec vectors. */
+- int i;
+-
+- for (i = 0; i < TYPE_LENGTH (type) / 16; i++)
+- {
+- const gdb_byte *elval = val + i * 16;
+-
+- gparam = align_up (gparam, 16);
+- greg += greg & 1;
+-
+- if (write_pass)
+- {
+- if (vreg <= 13)
+- regcache_cooked_write (regcache,
+- tdep->ppc_vr0_regnum + vreg,
+- elval);
+-
+- write_memory (gparam, elval, 16);
+- }
+-
+- greg += 2;
+- vreg++;
+- gparam += 16;
+- }
+- }
+- else if (TYPE_LENGTH (type) == 16 && TYPE_VECTOR (type)
+- && TYPE_CODE (type) == TYPE_CODE_ARRAY
+- && tdep->vector_abi == POWERPC_VEC_ALTIVEC)
+- {
+- /* In the Altivec ABI, vectors go in the vector registers
+- v2 .. v13, as well as the parameter area -- always at
+- 16-byte aligned addresses. */
+-
+- gparam = align_up (gparam, 16);
+- greg += greg & 1;
+-
+- if (write_pass)
+- {
+- if (vreg <= 13)
+- regcache_cooked_write (regcache,
+- tdep->ppc_vr0_regnum + vreg, val);
+-
+- write_memory (gparam, val, TYPE_LENGTH (type));
+- }
+-
+- greg += 2;
+- vreg++;
+- gparam += 16;
+- }
+- else if (TYPE_LENGTH (type) >= 16 && TYPE_VECTOR (type)
+- && TYPE_CODE (type) == TYPE_CODE_ARRAY)
+- {
+- /* Non-Altivec vectors are passed by reference. */
+-
+- /* Copy value onto the stack ... */
+- refparam = align_up (refparam, 16);
+- if (write_pass)
+- write_memory (refparam, val, TYPE_LENGTH (type));
+-
+- /* ... and pass a pointer to the copy as parameter. */
+- if (write_pass)
+- {
+- if (greg <= 10)
+- regcache_cooked_write_unsigned (regcache,
+- tdep->ppc_gp0_regnum +
+- greg, refparam);
+- write_memory_unsigned_integer (gparam, tdep->wordsize,
+- byte_order, refparam);
++ ppc64_sysv_abi_push_param (gdbarch, eltype, elval, &argpos);
+ }
+- greg++;
+- gparam = align_up (gparam + tdep->wordsize, tdep->wordsize);
+- refparam = align_up (refparam + TYPE_LENGTH (type), tdep->wordsize);
+- }
+- else if ((TYPE_CODE (type) == TYPE_CODE_INT
+- || TYPE_CODE (type) == TYPE_CODE_ENUM
+- || TYPE_CODE (type) == TYPE_CODE_BOOL
+- || TYPE_CODE (type) == TYPE_CODE_CHAR
+- || TYPE_CODE (type) == TYPE_CODE_PTR
+- || TYPE_CODE (type) == TYPE_CODE_REF)
+- && TYPE_LENGTH (type) <= 8)
+- {
+- /* Scalars and Pointers get sign[un]extended and go in
+- gpr3 .. gpr10. They can also end up in memory. */
+- if (write_pass)
+- {
+- /* Sign extend the value, then store it unsigned. */
+- ULONGEST word = unpack_long (type, val);
+- /* Convert any function code addresses into
+- descriptors. */
+- if (TYPE_CODE (type) == TYPE_CODE_PTR
+- || TYPE_CODE (type) == TYPE_CODE_REF)
+- {
+- struct type *target_type;
+- target_type = check_typedef (TYPE_TARGET_TYPE (type));
+-
+- if (TYPE_CODE (target_type) == TYPE_CODE_FUNC
+- || TYPE_CODE (target_type) == TYPE_CODE_METHOD)
+- {
+- CORE_ADDR desc = word;
+- convert_code_addr_to_desc_addr (word, &desc);
+- word = desc;
+- }
+- }
+- if (greg <= 10)
+- regcache_cooked_write_unsigned (regcache,
+- tdep->ppc_gp0_regnum +
+- greg, word);
+- write_memory_unsigned_integer (gparam, tdep->wordsize,
+- byte_order, word);
+- }
+- greg++;
+- gparam = align_up (gparam + TYPE_LENGTH (type), tdep->wordsize);
+ }
+ else
+ {
+- int byte;
+- for (byte = 0; byte < TYPE_LENGTH (type);
+- byte += tdep->wordsize)
+- {
+- if (write_pass && greg <= 10)
+- {
+- gdb_byte regval[MAX_REGISTER_SIZE];
+- int len = TYPE_LENGTH (type) - byte;
+- if (len > tdep->wordsize)
+- len = tdep->wordsize;
+- memset (regval, 0, sizeof regval);
+- /* The ABI (version 1.9) specifies that values
+- smaller than one doubleword are right-aligned
+- and those larger are left-aligned. GCC
+- versions before 3.4 implemented this
+- incorrectly; see
+- <http://gcc.gnu.org/gcc-3.4/powerpc-abi.html>. */
+- if (byte == 0)
+- memcpy (regval + tdep->wordsize - len,
+- val + byte, len);
+- else
+- memcpy (regval, val + byte, len);
+- regcache_cooked_write (regcache, greg, regval);
+- }
+- greg++;
+- }
+- if (write_pass)
+- {
+- /* WARNING: cagney/2003-09-21: Strictly speaking, this
+- isn't necessary, unfortunately, GCC appears to get
+- "struct convention" parameter passing wrong putting
+- odd sized structures in memory instead of in a
+- register. Work around this by always writing the
+- value to memory. Fortunately, doing this
+- simplifies the code. */
+- int len = TYPE_LENGTH (type);
+- if (len < tdep->wordsize)
+- write_memory (gparam + tdep->wordsize - len, val, len);
+- else
+- write_memory (gparam, val, len);
+- }
+- if (freg <= 13
+- && TYPE_CODE (type) == TYPE_CODE_STRUCT
+- && TYPE_NFIELDS (type) == 1
+- && TYPE_LENGTH (type) <= 16)
+- {
+- /* The ABI (version 1.9) specifies that structs
+- containing a single floating-point value, at any
+- level of nesting of single-member structs, are
+- passed in floating-point registers. */
+- while (TYPE_CODE (type) == TYPE_CODE_STRUCT
+- && TYPE_NFIELDS (type) == 1)
+- type = check_typedef (TYPE_FIELD_TYPE (type, 0));
+- if (TYPE_CODE (type) == TYPE_CODE_FLT)
+- {
+- if (TYPE_LENGTH (type) <= 8)
+- {
+- if (write_pass)
+- {
+- gdb_byte regval[MAX_REGISTER_SIZE];
+- struct type *regtype
+- = register_type (gdbarch,
+- tdep->ppc_fp0_regnum);
+- convert_typed_floating (val, type, regval,
+- regtype);
+- regcache_cooked_write (regcache,
+- (tdep->ppc_fp0_regnum
+- + freg),
+- regval);
+- }
+- freg++;
+- }
+- else if (TYPE_LENGTH (type) == 16
+- && (gdbarch_long_double_format (gdbarch)
+- == floatformats_ibm_long_double))
+- {
+- if (write_pass)
+- {
+- regcache_cooked_write (regcache,
+- (tdep->ppc_fp0_regnum
+- + freg),
+- val);
+- if (freg <= 12)
+- regcache_cooked_write (regcache,
+- (tdep->ppc_fp0_regnum
+- + freg + 1),
+- val + 8);
+- }
+- freg += 2;
+- }
+- }
+- }
+- /* Always consume parameter stack space. */
+- gparam = align_up (gparam + TYPE_LENGTH (type), tdep->wordsize);
++ /* All other types are passed as single arguments. */
++ ppc64_sysv_abi_push_param (gdbarch, type, val, &argpos);
+ }
+ }
+
+ if (!write_pass)
+ {
+ /* Save the true region sizes ready for the second pass. */
+- refparam_size = refparam;
++ refparam_size = argpos.refparam;
+ /* Make certain that the general parameter save area is at
+ least the minimum 8 registers (or doublewords) in size. */
+- if (greg < 8)
++ if (argpos.greg < 8)
+ gparam_size = 8 * tdep->wordsize;
+ else
+- gparam_size = gparam;
++ gparam_size = argpos.gparam;
+ }
+ }
+
+@@ -1733,28 +1735,179 @@
+ breakpoint. */
+ regcache_cooked_write_signed (regcache, tdep->ppc_lr_regnum, bp_addr);
+
+- /* Use the func_addr to find the descriptor, and use that to find
+- the TOC. If we're calling via a function pointer, the pointer
+- itself identifies the descriptor. */
+- {
+- struct type *ftype = check_typedef (value_type (function));
+- CORE_ADDR desc_addr = value_as_address (function);
++ /* In the ELFv1 ABI, use the func_addr to find the descriptor, and use
++ that to find the TOC. If we're calling via a function pointer,
++ the pointer itself identifies the descriptor. */
++ if (tdep->elf_abi == POWERPC_ELF_V1)
++ {
++ struct type *ftype = check_typedef (value_type (function));
++ CORE_ADDR desc_addr = value_as_address (function);
+
+- if (TYPE_CODE (ftype) == TYPE_CODE_PTR
+- || convert_code_addr_to_desc_addr (func_addr, &desc_addr))
+- {
+- /* The TOC is the second double word in the descriptor. */
+- CORE_ADDR toc =
+- read_memory_unsigned_integer (desc_addr + tdep->wordsize,
+- tdep->wordsize, byte_order);
+- regcache_cooked_write_unsigned (regcache,
+- tdep->ppc_gp0_regnum + 2, toc);
+- }
+- }
++ if (TYPE_CODE (ftype) == TYPE_CODE_PTR
++ || convert_code_addr_to_desc_addr (func_addr, &desc_addr))
++ {
++ /* The TOC is the second double word in the descriptor. */
++ CORE_ADDR toc =
++ read_memory_unsigned_integer (desc_addr + tdep->wordsize,
++ tdep->wordsize, byte_order);
++
++ regcache_cooked_write_unsigned (regcache,
++ tdep->ppc_gp0_regnum + 2, toc);
++ }
++ }
++
++ /* In the ELFv2 ABI, we need to pass the target address in r12 since
++ we may be calling a global entry point. */
++ if (tdep->elf_abi == POWERPC_ELF_V2)
++ regcache_cooked_write_unsigned (regcache,
++ tdep->ppc_gp0_regnum + 12, func_addr);
+
+ return sp;
+ }
+
++/* Subroutine of ppc64_sysv_abi_return_value that handles "base" types:
++ integer, floating-point, and AltiVec vector types.
++
++ This routine also handles components of aggregate return types;
++ INDEX describes which part of the aggregate is to be handled.
++
++ Returns true if VALTYPE is some such base type that could be handled,
++ false otherwise. */
++static int
++ppc64_sysv_abi_return_value_base (struct gdbarch *gdbarch, struct type *valtype,
++ struct regcache *regcache, gdb_byte *readbuf,
++ const gdb_byte *writebuf, int index)
++{
++ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
++
++ /* Integers live in GPRs starting at r3. */
++ if ((TYPE_CODE (valtype) == TYPE_CODE_INT
++ || TYPE_CODE (valtype) == TYPE_CODE_ENUM
++ || TYPE_CODE (valtype) == TYPE_CODE_CHAR
++ || TYPE_CODE (valtype) == TYPE_CODE_BOOL)
++ && TYPE_LENGTH (valtype) <= 8)
++ {
++ int regnum = tdep->ppc_gp0_regnum + 3 + index;
++
++ if (writebuf != NULL)
++ {
++ /* Be careful to sign extend the value. */
++ regcache_cooked_write_unsigned (regcache, regnum,
++ unpack_long (valtype, writebuf));
++ }
++ if (readbuf != NULL)
++ {
++ /* Extract the integer from GPR. Since this is truncating the
++ value, there isn't a sign extension problem. */
++ ULONGEST regval;
++
++ regcache_cooked_read_unsigned (regcache, regnum, ®val);
++ store_unsigned_integer (readbuf, TYPE_LENGTH (valtype),
++ gdbarch_byte_order (gdbarch), regval);
++ }
++ return 1;
++ }
++
++ /* Floats and doubles go in f1 .. f13. 32-bit floats are converted
++ to double first. */
++ if (TYPE_LENGTH (valtype) <= 8
++ && TYPE_CODE (valtype) == TYPE_CODE_FLT)
++ {
++ int regnum = tdep->ppc_fp0_regnum + 1 + index;
++ struct type *regtype = register_type (gdbarch, regnum);
++ gdb_byte regval[MAX_REGISTER_SIZE];
++
++ if (writebuf != NULL)
++ {
++ convert_typed_floating (writebuf, valtype, regval, regtype);
++ regcache_cooked_write (regcache, regnum, regval);
++ }
++ if (readbuf != NULL)
++ {
++ regcache_cooked_read (regcache, regnum, regval);
++ convert_typed_floating (regval, regtype, readbuf, valtype);
++ }
++ return 1;
++ }
++
++ /* Floats and doubles go in f1 .. f13. 32-bit decimal floats are
++ placed in the least significant word. */
++ if (TYPE_LENGTH (valtype) <= 8
++ && TYPE_CODE (valtype) == TYPE_CODE_DECFLOAT)
++ {
++ int regnum = tdep->ppc_fp0_regnum + 1 + index;
++ int offset = 0;
++
++ if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
++ offset = 8 - TYPE_LENGTH (valtype);
++
++ if (writebuf != NULL)
++ regcache_cooked_write_part (regcache, regnum,
++ offset, TYPE_LENGTH (valtype), writebuf);
++ if (readbuf != NULL)
++ regcache_cooked_read_part (regcache, regnum,
++ offset, TYPE_LENGTH (valtype), readbuf);
++ return 1;
++ }
++
++ /* IBM long double stored in two consecutive FPRs. */
++ if (TYPE_LENGTH (valtype) == 16
++ && TYPE_CODE (valtype) == TYPE_CODE_FLT
++ && (gdbarch_long_double_format (gdbarch)
++ == floatformats_ibm_long_double))
++ {
++ int regnum = tdep->ppc_fp0_regnum + 1 + 2 * index;
++
++ if (writebuf != NULL)
++ {
++ regcache_cooked_write (regcache, regnum, writebuf);
++ regcache_cooked_write (regcache, regnum + 1, writebuf + 8);
++ }
++ if (readbuf != NULL)
++ {
++ regcache_cooked_read (regcache, regnum, readbuf);
++ regcache_cooked_read (regcache, regnum + 1, readbuf + 8);
++ }
++ return 1;
++ }
++
++ /* 128-bit decimal floating-point values are stored in an even/odd
++ pair of FPRs, with the even FPR holding the most significant half. */
++ if (TYPE_LENGTH (valtype) == 16
++ && TYPE_CODE (valtype) == TYPE_CODE_DECFLOAT)
++ {
++ int regnum = tdep->ppc_fp0_regnum + 2 + 2 * index;
++ int lopart = gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG ? 8 : 0;
++ int hipart = gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG ? 0 : 8;
++
++ if (writebuf != NULL)
++ {
++ regcache_cooked_write (regcache, regnum, writebuf + hipart);
++ regcache_cooked_write (regcache, regnum + 1, writebuf + lopart);
++ }
++ if (readbuf != NULL)
++ {
++ regcache_cooked_read (regcache, regnum, readbuf + hipart);
++ regcache_cooked_read (regcache, regnum + 1, readbuf + lopart);
++ }
++ return 1;
++ }
++
++ /* AltiVec vectors are returned in VRs starting at v2. */
++ if (TYPE_CODE (valtype) == TYPE_CODE_ARRAY && TYPE_VECTOR (valtype)
++ && tdep->vector_abi == POWERPC_VEC_ALTIVEC)
++ {
++ int regnum = tdep->ppc_vr0_regnum + 2 + index;
++
++ if (writebuf != NULL)
++ regcache_cooked_write (regcache, regnum, writebuf);
++ if (readbuf != NULL)
++ regcache_cooked_read (regcache, regnum, readbuf);
++ return 1;
++ }
++
++ return 0;
++}
+
+ /* The 64 bit ABI return value convention.
+
+@@ -1772,254 +1925,163 @@
+ gdb_byte *readbuf, const gdb_byte *writebuf)
+ {
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ struct type *func_type = function ? value_type (function) : NULL;
+ int opencl_abi = func_type? ppc_sysv_use_opencl_abi (func_type) : 0;
++ struct type *eltype;
++ int nelt, i, ok;
+
+ /* This function exists to support a calling convention that
+ requires floating-point registers. It shouldn't be used on
+ processors that lack them. */
+ gdb_assert (ppc_floating_point_unit_p (gdbarch));
+
+- /* Floats and doubles in F1. */
+- if (TYPE_CODE (valtype) == TYPE_CODE_FLT && TYPE_LENGTH (valtype) <= 8)
++ /* Complex types are returned as if two independent scalars. */
++ if (TYPE_CODE (valtype) == TYPE_CODE_COMPLEX)
+ {
+- gdb_byte regval[MAX_REGISTER_SIZE];
+- struct type *regtype = register_type (gdbarch, tdep->ppc_fp0_regnum);
+- if (writebuf != NULL)
+- {
+- convert_typed_floating (writebuf, valtype, regval, regtype);
+- regcache_cooked_write (regcache, tdep->ppc_fp0_regnum + 1, regval);
+- }
+- if (readbuf != NULL)
++ eltype = check_typedef (TYPE_TARGET_TYPE (valtype));
++
++ for (i = 0; i < 2; i++)
+ {
+- regcache_cooked_read (regcache, tdep->ppc_fp0_regnum + 1, regval);
+- convert_typed_floating (regval, regtype, readbuf, valtype);
++ ok = ppc64_sysv_abi_return_value_base (gdbarch, eltype, regcache,
++ readbuf, writebuf, i);
++ gdb_assert (ok);
++
++ if (readbuf)
++ readbuf += TYPE_LENGTH (eltype);
++ if (writebuf)
++ writebuf += TYPE_LENGTH (eltype);
+ }
+ return RETURN_VALUE_REGISTER_CONVENTION;
+ }
+- if (TYPE_CODE (valtype) == TYPE_CODE_DECFLOAT)
+- return get_decimal_float_return_value (gdbarch, valtype, regcache, readbuf,
+- writebuf);
+- /* Integers in r3. */
+- if ((TYPE_CODE (valtype) == TYPE_CODE_INT
+- || TYPE_CODE (valtype) == TYPE_CODE_ENUM
+- || TYPE_CODE (valtype) == TYPE_CODE_CHAR
+- || TYPE_CODE (valtype) == TYPE_CODE_BOOL)
+- && TYPE_LENGTH (valtype) <= 8)
++
++ /* OpenCL vectors shorter than 16 bytes are returned as if
++ a series of independent scalars; OpenCL vectors 16 bytes
++ or longer are returned as if a series of AltiVec vectors. */
++ if (TYPE_CODE (valtype) == TYPE_CODE_ARRAY && TYPE_VECTOR (valtype)
++ && opencl_abi)
+ {
+- if (writebuf != NULL)
+- {
+- /* Be careful to sign extend the value. */
+- regcache_cooked_write_unsigned (regcache, tdep->ppc_gp0_regnum + 3,
+- unpack_long (valtype, writebuf));
+- }
+- if (readbuf != NULL)
++ if (TYPE_LENGTH (valtype) < 16)
++ eltype = check_typedef (TYPE_TARGET_TYPE (valtype));
++ else
++ eltype = register_type (gdbarch, tdep->ppc_vr0_regnum);
++
++ nelt = TYPE_LENGTH (valtype) / TYPE_LENGTH (eltype);
++ for (i = 0; i < nelt; i++)
+ {
+- /* Extract the integer from r3. Since this is truncating the
+- value, there isn't a sign extension problem. */
+- ULONGEST regval;
+- regcache_cooked_read_unsigned (regcache, tdep->ppc_gp0_regnum + 3,
+- ®val);
+- store_unsigned_integer (readbuf, TYPE_LENGTH (valtype), byte_order,
+- regval);
++ ok = ppc64_sysv_abi_return_value_base (gdbarch, eltype, regcache,
++ readbuf, writebuf, i);
++ gdb_assert (ok);
++
++ if (readbuf)
++ readbuf += TYPE_LENGTH (eltype);
++ if (writebuf)
++ writebuf += TYPE_LENGTH (eltype);
+ }
+ return RETURN_VALUE_REGISTER_CONVENTION;
+ }
++
+ /* All pointers live in r3. */
+ if (TYPE_CODE (valtype) == TYPE_CODE_PTR
+ || TYPE_CODE (valtype) == TYPE_CODE_REF)
+ {
+- /* All pointers live in r3. */
++ int regnum = tdep->ppc_gp0_regnum + 3;
++
+ if (writebuf != NULL)
+- regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + 3, writebuf);
++ regcache_cooked_write (regcache, regnum, writebuf);
+ if (readbuf != NULL)
+- regcache_cooked_read (regcache, tdep->ppc_gp0_regnum + 3, readbuf);
++ regcache_cooked_read (regcache, regnum, readbuf);
+ return RETURN_VALUE_REGISTER_CONVENTION;
+ }
+- /* OpenCL vectors < 16 bytes are returned as distinct
+- scalars in f1..f2 or r3..r10. */
++
++ /* Small character arrays are returned, right justified, in r3. */
+ if (TYPE_CODE (valtype) == TYPE_CODE_ARRAY
+- && TYPE_VECTOR (valtype)
+- && TYPE_LENGTH (valtype) < 16
+- && opencl_abi)
++ && TYPE_LENGTH (valtype) <= 8
++ && TYPE_CODE (TYPE_TARGET_TYPE (valtype)) == TYPE_CODE_INT
++ && TYPE_LENGTH (TYPE_TARGET_TYPE (valtype)) == 1)
+ {
+- struct type *eltype = check_typedef (TYPE_TARGET_TYPE (valtype));
+- int i, nelt = TYPE_LENGTH (valtype) / TYPE_LENGTH (eltype);
++ int regnum = tdep->ppc_gp0_regnum + 3;
++ int offset = (register_size (gdbarch, regnum) - TYPE_LENGTH (valtype));
++
++ if (writebuf != NULL)
++ regcache_cooked_write_part (regcache, regnum,
++ offset, TYPE_LENGTH (valtype), writebuf);
++ if (readbuf != NULL)
++ regcache_cooked_read_part (regcache, regnum,
++ offset, TYPE_LENGTH (valtype), readbuf);
++ return RETURN_VALUE_REGISTER_CONVENTION;
++ }
+
++ /* In the ELFv2 ABI, homogeneous floating-point or vector
++ aggregates are returned in registers. */
++ if (tdep->elf_abi == POWERPC_ELF_V2
++ && ppc64_elfv2_abi_homogeneous_aggregate (valtype, &eltype, &nelt))
++ {
+ for (i = 0; i < nelt; i++)
+ {
+- int offset = i * TYPE_LENGTH (eltype);
+-
+- if (TYPE_CODE (eltype) == TYPE_CODE_FLT)
+- {
+- int regnum = tdep->ppc_fp0_regnum + 1 + i;
+- gdb_byte regval[MAX_REGISTER_SIZE];
+- struct type *regtype = register_type (gdbarch, regnum);
+-
+- if (writebuf != NULL)
+- {
+- convert_typed_floating (writebuf + offset, eltype,
+- regval, regtype);
+- regcache_cooked_write (regcache, regnum, regval);
+- }
+- if (readbuf != NULL)
+- {
+- regcache_cooked_read (regcache, regnum, regval);
+- convert_typed_floating (regval, regtype,
+- readbuf + offset, eltype);
+- }
+- }
+- else
+- {
+- int regnum = tdep->ppc_gp0_regnum + 3 + i;
+- ULONGEST regval;
+-
+- if (writebuf != NULL)
+- {
+- regval = unpack_long (eltype, writebuf + offset);
+- regcache_cooked_write_unsigned (regcache, regnum, regval);
+- }
+- if (readbuf != NULL)
+- {
+- regcache_cooked_read_unsigned (regcache, regnum, ®val);
+- store_unsigned_integer (readbuf + offset,
+- TYPE_LENGTH (eltype), byte_order,
+- regval);
+- }
+- }
++ ok = ppc64_sysv_abi_return_value_base (gdbarch, eltype, regcache,
++ readbuf, writebuf, i);
++ gdb_assert (ok);
++
++ if (readbuf)
++ readbuf += TYPE_LENGTH (eltype);
++ if (writebuf)
++ writebuf += TYPE_LENGTH (eltype);
+ }
+
+ return RETURN_VALUE_REGISTER_CONVENTION;
+ }
+- /* OpenCL vectors >= 16 bytes are returned in v2..v9. */
+- if (TYPE_CODE (valtype) == TYPE_CODE_ARRAY
+- && TYPE_VECTOR (valtype)
+- && TYPE_LENGTH (valtype) >= 16
+- && opencl_abi)
++
++ /* In the ELFv2 ABI, aggregate types of up to 16 bytes are
++ returned in registers r3:r4. */
++ if (tdep->elf_abi == POWERPC_ELF_V2
++ && TYPE_LENGTH (valtype) <= 16
++ && (TYPE_CODE (valtype) == TYPE_CODE_STRUCT
++ || TYPE_CODE (valtype) == TYPE_CODE_UNION
++ || (TYPE_CODE (valtype) == TYPE_CODE_ARRAY
++ && !TYPE_VECTOR (valtype))))
+ {
+- int n_regs = TYPE_LENGTH (valtype) / 16;
++ int n_regs = ((TYPE_LENGTH (valtype) + tdep->wordsize - 1)
++ / tdep->wordsize);
+ int i;
+
+ for (i = 0; i < n_regs; i++)
+ {
+- int offset = i * 16;
+- int regnum = tdep->ppc_vr0_regnum + 2 + i;
++ gdb_byte regval[MAX_REGISTER_SIZE];
++ int regnum = tdep->ppc_gp0_regnum + 3 + i;
++ int offset = i * tdep->wordsize;
++ int len = TYPE_LENGTH (valtype) - offset;
+
+- if (writebuf != NULL)
+- regcache_cooked_write (regcache, regnum, writebuf + offset);
+- if (readbuf != NULL)
+- regcache_cooked_read (regcache, regnum, readbuf + offset);
+- }
++ if (len > tdep->wordsize)
++ len = tdep->wordsize;
+
+- return RETURN_VALUE_REGISTER_CONVENTION;
+- }
+- /* Array type has more than one use. */
+- if (TYPE_CODE (valtype) == TYPE_CODE_ARRAY)
+- {
+- /* Small character arrays are returned, right justified, in r3. */
+- if (TYPE_LENGTH (valtype) <= 8
+- && TYPE_CODE (TYPE_TARGET_TYPE (valtype)) == TYPE_CODE_INT
+- && TYPE_LENGTH (TYPE_TARGET_TYPE (valtype)) == 1)
+- {
+- int offset = (register_size (gdbarch, tdep->ppc_gp0_regnum + 3)
+- - TYPE_LENGTH (valtype));
+- if (writebuf != NULL)
+- regcache_cooked_write_part (regcache, tdep->ppc_gp0_regnum + 3,
+- offset, TYPE_LENGTH (valtype), writebuf);
+- if (readbuf != NULL)
+- regcache_cooked_read_part (regcache, tdep->ppc_gp0_regnum + 3,
+- offset, TYPE_LENGTH (valtype), readbuf);
+- return RETURN_VALUE_REGISTER_CONVENTION;
+- }
+- /* A VMX vector is returned in v2. */
+- if (TYPE_CODE (valtype) == TYPE_CODE_ARRAY
+- && TYPE_VECTOR (valtype)
+- && tdep->vector_abi == POWERPC_VEC_ALTIVEC)
+- {
+- if (readbuf)
+- regcache_cooked_read (regcache, tdep->ppc_vr0_regnum + 2, readbuf);
+- if (writebuf)
+- regcache_cooked_write (regcache, tdep->ppc_vr0_regnum + 2,
+- writebuf);
+- return RETURN_VALUE_REGISTER_CONVENTION;
+- }
+- }
+- /* Big floating point values get stored in adjacent floating
+- point registers, starting with F1. */
+- if (TYPE_CODE (valtype) == TYPE_CODE_FLT
+- && (TYPE_LENGTH (valtype) == 16 || TYPE_LENGTH (valtype) == 32))
+- {
+- if (writebuf || readbuf != NULL)
+- {
+- int i;
+- for (i = 0; i < TYPE_LENGTH (valtype) / 8; i++)
+- {
+- if (writebuf != NULL)
+- regcache_cooked_write (regcache, tdep->ppc_fp0_regnum + 1 + i,
+- (const bfd_byte *) writebuf + i * 8);
+- if (readbuf != NULL)
+- regcache_cooked_read (regcache, tdep->ppc_fp0_regnum + 1 + i,
+- (bfd_byte *) readbuf + i * 8);
+- }
+- }
+- return RETURN_VALUE_REGISTER_CONVENTION;
+- }
+- /* Complex values get returned in f1:f2, need to convert. */
+- if (TYPE_CODE (valtype) == TYPE_CODE_COMPLEX
+- && (TYPE_LENGTH (valtype) == 8 || TYPE_LENGTH (valtype) == 16))
+- {
+- if (regcache != NULL)
+- {
+- int i;
+- for (i = 0; i < 2; i++)
++ if (writebuf != NULL)
+ {
+- gdb_byte regval[MAX_REGISTER_SIZE];
+- struct type *regtype =
+- register_type (gdbarch, tdep->ppc_fp0_regnum);
+- struct type *target_type;
+- target_type = check_typedef (TYPE_TARGET_TYPE (valtype));
+- if (writebuf != NULL)
+- {
+- convert_typed_floating ((const bfd_byte *) writebuf +
+- i * TYPE_LENGTH (target_type),
+- target_type, regval, regtype);
+- regcache_cooked_write (regcache,
+- tdep->ppc_fp0_regnum + 1 + i,
+- regval);
+- }
+- if (readbuf != NULL)
+- {
+- regcache_cooked_read (regcache,
+- tdep->ppc_fp0_regnum + 1 + i,
+- regval);
+- convert_typed_floating (regval, regtype,
+- (bfd_byte *) readbuf +
+- i * TYPE_LENGTH (target_type),
+- target_type);
+- }
++ memset (regval, 0, sizeof regval);
++ if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG
++ && offset == 0)
++ memcpy (regval + tdep->wordsize - len, writebuf, len);
++ else
++ memcpy (regval, writebuf + offset, len);
++ regcache_cooked_write (regcache, regnum, regval);
+ }
+- }
+- return RETURN_VALUE_REGISTER_CONVENTION;
+- }
+- /* Big complex values get stored in f1:f4. */
+- if (TYPE_CODE (valtype) == TYPE_CODE_COMPLEX && TYPE_LENGTH (valtype) == 32)
+- {
+- if (regcache != NULL)
+- {
+- int i;
+- for (i = 0; i < 4; i++)
++ if (readbuf != NULL)
+ {
+- if (writebuf != NULL)
+- regcache_cooked_write (regcache, tdep->ppc_fp0_regnum + 1 + i,
+- (const bfd_byte *) writebuf + i * 8);
+- if (readbuf != NULL)
+- regcache_cooked_read (regcache, tdep->ppc_fp0_regnum + 1 + i,
+- (bfd_byte *) readbuf + i * 8);
++ regcache_cooked_read (regcache, regnum, regval);
++ if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG
++ && offset == 0)
++ memcpy (readbuf, regval + tdep->wordsize - len, len);
++ else
++ memcpy (readbuf + offset, regval, len);
+ }
+ }
+ return RETURN_VALUE_REGISTER_CONVENTION;
+ }
++
++ /* Handle plain base types. */
++ if (ppc64_sysv_abi_return_value_base (gdbarch, valtype, regcache,
++ readbuf, writebuf, 0))
++ return RETURN_VALUE_REGISTER_CONVENTION;
++
+ return RETURN_VALUE_STRUCT_CONVENTION;
+ }
+
+Index: b/gdb/ppc-tdep.h
+===================================================================
+--- a/gdb/ppc-tdep.h
++++ b/gdb/ppc-tdep.h
+@@ -182,6 +182,15 @@
+
+ /* Private data that this module attaches to struct gdbarch. */
+
++/* ELF ABI version used by the inferior. */
++enum powerpc_elf_abi
++{
++ POWERPC_ELF_AUTO,
++ POWERPC_ELF_V1,
++ POWERPC_ELF_V2,
++ POWERPC_ELF_LAST
++};
++
+ /* Vector ABI used by the inferior. */
+ enum powerpc_vector_abi
+ {
+@@ -197,6 +206,8 @@
+ int wordsize; /* Size in bytes of fixed-point word. */
+ int soft_float; /* Avoid FP registers for arguments? */
+
++ enum powerpc_elf_abi elf_abi; /* ELF ABI version. */
++
+ /* How to pass vector arguments. Never set to AUTO or LAST. */
+ enum powerpc_vector_abi vector_abi;
+
+Index: b/gdb/rs6000-tdep.c
+===================================================================
+--- a/gdb/rs6000-tdep.c
++++ b/gdb/rs6000-tdep.c
+@@ -48,6 +48,7 @@
+
+ #include "elf-bfd.h"
+ #include "elf/ppc.h"
++#include "elf/ppc64.h"
+
+ #include "solib-svr4.h"
+ #include "ppc-tdep.h"
+@@ -2672,10 +2673,10 @@
+ else
+ {
+ status = regcache_raw_read (regcache, tdep->ppc_fp0_regnum +
+- 2 * reg_index + 1, buffer + 8);
++ 2 * reg_index + 1, buffer);
+ if (status == REG_VALID)
+ status = regcache_raw_read (regcache, tdep->ppc_fp0_regnum +
+- 2 * reg_index, buffer);
++ 2 * reg_index, buffer + 8);
+ }
+
+ return status;
+@@ -2701,9 +2702,9 @@
+ else
+ {
+ regcache_raw_write (regcache, tdep->ppc_fp0_regnum +
+- 2 * reg_index + 1, buffer + 8);
++ 2 * reg_index + 1, buffer);
+ regcache_raw_write (regcache, tdep->ppc_fp0_regnum +
+- 2 * reg_index, buffer);
++ 2 * reg_index, buffer + 8);
+ }
+ }
+
+@@ -2779,10 +2780,12 @@
+ {
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ int reg_index = reg_nr - tdep->ppc_efpr0_regnum;
++ int offset = gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG ? 0 : 8;
+
+ /* Read the portion that overlaps the VMX register. */
+- return regcache_raw_read_part (regcache, tdep->ppc_vr0_regnum + reg_index, 0,
+- register_size (gdbarch, reg_nr), buffer);
++ return regcache_raw_read_part (regcache, tdep->ppc_vr0_regnum + reg_index,
++ offset, register_size (gdbarch, reg_nr),
++ buffer);
+ }
+
+ /* Write method for POWER7 Extended FP pseudo-registers. */
+@@ -2792,10 +2795,12 @@
+ {
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ int reg_index = reg_nr - tdep->ppc_efpr0_regnum;
++ int offset = gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG ? 0 : 8;
+
+ /* Write the portion that overlaps the VMX register. */
+- regcache_raw_write_part (regcache, tdep->ppc_vr0_regnum + reg_index, 0,
+- register_size (gdbarch, reg_nr), buffer);
++ regcache_raw_write_part (regcache, tdep->ppc_vr0_regnum + reg_index,
++ offset, register_size (gdbarch, reg_nr),
++ buffer);
+ }
+
+ static enum register_status
+@@ -3550,6 +3555,7 @@
+ enum auto_boolean soft_float_flag = powerpc_soft_float_global;
+ int soft_float;
+ enum powerpc_vector_abi vector_abi = powerpc_vector_abi_global;
++ enum powerpc_elf_abi elf_abi = POWERPC_ELF_AUTO;
+ int have_fpu = 1, have_spe = 0, have_mq = 0, have_altivec = 0, have_dfp = 0,
+ have_vsx = 0;
+ int tdesc_wordsize = -1;
+@@ -3856,6 +3862,21 @@
+ }
+
+ #ifdef HAVE_ELF
++ if (from_elf_exec)
++ {
++ switch (elf_elfheader (info.abfd)->e_flags & EF_PPC64_ABI)
++ {
++ case 1:
++ elf_abi = POWERPC_ELF_V1;
++ break;
++ case 2:
++ elf_abi = POWERPC_ELF_V2;
++ break;
++ default:
++ break;
++ }
++ }
++
+ if (soft_float_flag == AUTO_BOOLEAN_AUTO && from_elf_exec)
+ {
+ switch (bfd_elf_get_obj_attr_int (info.abfd, OBJ_ATTR_GNU,
+@@ -3892,6 +3913,21 @@
+ }
+ #endif
+
++ /* At this point, the only supported ELF-based 64-bit little-endian
++ operating system is GNU/Linux, and this uses the ELFv2 ABI by
++ default. All other supported ELF-based operating systems use the
++ ELFv1 ABI by default. Therefore, if the ABI marker is missing,
++ e.g. because we run a legacy binary, or have attached to a process
++ and have not found any associated binary file, set the default
++ according to this heuristic. */
++ if (elf_abi == POWERPC_ELF_AUTO)
++ {
++ if (wordsize == 8 && info.byte_order == BFD_ENDIAN_LITTLE)
++ elf_abi = POWERPC_ELF_V2;
++ else
++ elf_abi = POWERPC_ELF_V1;
++ }
++
+ if (soft_float_flag == AUTO_BOOLEAN_TRUE)
+ soft_float = 1;
+ else if (soft_float_flag == AUTO_BOOLEAN_FALSE)
+@@ -3934,6 +3970,8 @@
+ meaningful, because 64-bit CPUs can run in 32-bit mode. So, perform
+ separate word size check. */
+ tdep = gdbarch_tdep (arches->gdbarch);
++ if (tdep && tdep->elf_abi != elf_abi)
++ continue;
+ if (tdep && tdep->soft_float != soft_float)
+ continue;
+ if (tdep && tdep->vector_abi != vector_abi)
+@@ -3956,6 +3994,7 @@
+
+ tdep = XCALLOC (1, struct gdbarch_tdep);
+ tdep->wordsize = wordsize;
++ tdep->elf_abi = elf_abi;
+ tdep->soft_float = soft_float;
+ tdep->vector_abi = vector_abi;
+
+Index: b/gdb/symtab.c
+===================================================================
+--- a/gdb/symtab.c
++++ b/gdb/symtab.c
+@@ -2934,6 +2934,8 @@
+
+ /* Skip "first line" of function (which is actually its prologue). */
+ pc += gdbarch_deprecated_function_start_offset (gdbarch);
++ if (gdbarch_skip_entrypoint_p (gdbarch))
++ pc = gdbarch_skip_entrypoint (gdbarch, pc);
+ if (skip)
+ pc = gdbarch_skip_prologue (gdbarch, pc);
+
+Index: b/gdb/testsuite/gdb.arch/altivec-regs.exp
+===================================================================
+--- a/gdb/testsuite/gdb.arch/altivec-regs.exp
++++ b/gdb/testsuite/gdb.arch/altivec-regs.exp
+@@ -79,17 +79,16 @@
+
+ gdb_test "next" "" ""
+
+-send_gdb "show endian\n"
+ set endianness ""
+-gdb_expect {
++set msg "detect endianness"
++gdb_test_multiple "show endian" "$msg" {
+ -re "(The target endianness is set automatically .currently )(big|little)( endian.*)$gdb_prompt $" {
+- pass "endianness"
+- set endianness $expect_out(2,string)
++ pass "$msg"
++ set endianness $expect_out(2,string)
+ }
+ -re ".*$gdb_prompt $" {
+- fail "couldn't get endianness"
++ fail "$msg"
+ }
+- timeout { fail "(timeout) endianness" }
+ }
+
+ # And then read the AltiVec registers back, to see that
+@@ -118,7 +117,7 @@
+ if {$endianness == "big"} {
+ set decimal_vector ".uint128 = 0x00000001000000010000000100000001, v4_float = .1.*e-45, 1.*e-45, 1.*e-45, 1.*e-45., v4_int32 = .1, 1, 1, 1., v8_int16 = .0, 1, 0, 1, 0, 1, 0, 1., v16_int8 = .0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1.."
+ } else {
+- set decimal_vector ".uint128 = 0x00000001000000010000000100000001, v4_float = .1.*e-45, 1.*e-45, 1.*e-45, 1.*e-45., v4_int32 = .1, 1, 1, 1., v8_int16 = .1, 0, 1, 0, 1, 0, 1, 0., v16_int8 = .1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.."
++ set decimal_vector ".uint128 = 0x00000001000000010000000100000001, v4_float = .1.*e-45, 1.*e-45, 1.*e-45, 1.*e-45., v4_int32 = .1, 1, 1, 1., v8_int16 = .1, 0, 1, 0, 1, 0, 1, 0., v16_int8 = .1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0.."
+ }
+
+ for {set i 0} {$i < 32} {incr i 1} {
+Index: b/gdb/testsuite/gdb.arch/powerpc-d128-regs.exp
+===================================================================
+--- a/gdb/testsuite/gdb.arch/powerpc-d128-regs.exp
++++ b/gdb/testsuite/gdb.arch/powerpc-d128-regs.exp
+@@ -20,7 +20,7 @@
+
+ # Testcase for ppc decimal128 pseudo-registers.
+
+-if ![istarget "powerpc64-*"] then {
++if ![istarget "powerpc64*-*"] then {
+ verbose "Skipping powerpc Decimal128 pseudo-registers testcase."
+ return
+ }
+Index: b/gdb/testsuite/gdb.arch/vsx-regs.exp
+===================================================================
+--- a/gdb/testsuite/gdb.arch/vsx-regs.exp
++++ b/gdb/testsuite/gdb.arch/vsx-regs.exp
+@@ -58,19 +58,45 @@
+ gdb_suppress_tests
+ }
+
++set endianness ""
++set msg "detect endianness"
++gdb_test_multiple "show endian" "$msg" {
++ -re "(The target endianness is set automatically .currently )(big|little)( endian.*)$gdb_prompt $" {
++ pass "$msg"
++ set endianness $expect_out(2,string)
++ }
++ -re ".*$gdb_prompt $" {
++ fail "$msg"
++ }
++}
++
+ # Data sets used throughout the test
+
+-set vector_register1 ".uint128 = 0x3ff4cccccccccccc0000000000000000, v2_double = .0x1, 0x0., v4_float = .0x1, 0xf99999a0, 0x0, 0x0., v4_int32 = .0x3ff4cccc, 0xcccccccc, 0x0, 0x0., v8_int16 = .0x3ff4, 0xcccc, 0xcccc, 0xcccc, 0x0, 0x0, 0x0, 0x0., v16_int8 = .0x3f, 0xf4, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0.."
++if {$endianness == "big"} {
++ set vector_register1 ".uint128 = 0x3ff4cccccccccccc0000000000000000, v2_double = .0x1, 0x0., v4_float = .0x1, 0xf99999a0, 0x0, 0x0., v4_int32 = .0x3ff4cccc, 0xcccccccc, 0x0, 0x0., v8_int16 = .0x3ff4, 0xcccc, 0xcccc, 0xcccc, 0x0, 0x0, 0x0, 0x0., v16_int8 = .0x3f, 0xf4, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0.."
++
++ set vector_register1_vr ".uint128 = 0x3ff4cccccccccccc0000000100000001, v4_float = .0x1, 0xf99999a0, 0x0, 0x0., v4_int32 = .0x3ff4cccc, 0xcccccccc, 0x1, 0x1., v8_int16 = .0x3ff4, 0xcccc, 0xcccc, 0xcccc, 0x0, 0x1, 0x0, 0x1., v16_int8 = .0x3f, 0xf4, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1.."
++
++ set vector_register2 "uint128 = 0xdeadbeefdeadbeefdeadbeefdeadbeef, v2_double = .0x1, 0x1., v4_float = .0x0, 0x0, 0x0, 0x0., v4_int32 = .0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef., v8_int16 = .0xdead, 0xbeef, 0xdead, 0xbeef, 0xdead, 0xbeef, 0xdead, 0xbeef., v16_int8 = .0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef.."
+
+-set vector_register1_vr ".uint128 = 0x3ff4cccccccccccc0000000100000001, v4_float = .0x1, 0xf99999a0, 0x0, 0x0., v4_int32 = .0x3ff4cccc, 0xcccccccc, 0x1, 0x1., v8_int16 = .0x3ff4, 0xcccc, 0xcccc, 0xcccc, 0x0, 0x1, 0x0, 0x1., v16_int8 = .0x3f, 0xf4, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1.."
++ set vector_register2_vr "uint128 = 0xdeadbeefdeadbeefdeadbeefdeadbeef, v4_float = .0x0, 0x0, 0x0, 0x0., v4_int32 = .0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef., v8_int16 = .0xdead, 0xbeef, 0xdead, 0xbeef, 0xdead, 0xbeef, 0xdead, 0xbeef., v16_int8 = .0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef.."
+
+-set vector_register2 "uint128 = 0xdeadbeefdeadbeefdeadbeefdeadbeef, v2_double = .0x1, 0x1., v4_float = .0x0, 0x0, 0x0, 0x0., v4_int32 = .0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef., v8_int16 = .0xdead, 0xbeef, 0xdead, 0xbeef, 0xdead, 0xbeef, 0xdead, 0xbeef., v16_int8 = .0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef.."
++ set vector_register3 ".uint128 = 0x00000001000000010000000100000001, v2_double = .0x0, 0x0., v4_float = .0x0, 0x0, 0x0, 0x0., v4_int32 = .0x1, 0x1, 0x1, 0x1., v8_int16 = .0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1., v16_int8 = .0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1.."
+
+-set vector_register2_vr "uint128 = 0xdeadbeefdeadbeefdeadbeefdeadbeef, v4_float = .0x0, 0x0, 0x0, 0x0., v4_int32 = .0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef., v8_int16 = .0xdead, 0xbeef, 0xdead, 0xbeef, 0xdead, 0xbeef, 0xdead, 0xbeef., v16_int8 = .0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef.."
++ set vector_register3_vr ".uint128 = 0x00000001000000010000000100000001, v4_float = .0x0, 0x0, 0x0, 0x0., v4_int32 = .0x1, 0x1, 0x1, 0x1., v8_int16 = .0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1., v16_int8 = .0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1.."
++} else {
++ set vector_register1 ".uint128 = 0x3ff4cccccccccccc0000000000000000, v2_double = .0x0, 0x1., v4_float = .0x0, 0x0, 0xf99999a0, 0x1., v4_int32 = .0x0, 0x0, 0xcccccccc, 0x3ff4cccc., v8_int16 = .0x0, 0x0, 0x0, 0x0, 0xcccc, 0xcccc, 0xcccc, 0x3ff4., v16_int8 = .0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xf4, 0x3f.."
+
+-set vector_register3 ".uint128 = 0x00000001000000010000000100000001, v2_double = .0x0, 0x0., v4_float = .0x0, 0x0, 0x0, 0x0., v4_int32 = .0x1, 0x1, 0x1, 0x1., v8_int16 = .0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1., v16_int8 = .0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1.."
++ set vector_register1_vr ".uint128 = 0x3ff4cccccccccccc0000000100000001, v4_float = .0x0, 0x0, 0xf99999a0, 0x1., v4_int32 = .0x1, 0x1, 0xcccccccc, 0x3ff4cccc., v8_int16 = .0x1, 0x0, 0x1, 0x0, 0xcccc, 0xcccc, 0xcccc, 0x3ff4., v16_int8 = .0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xf4, 0x3f.."
+
+-set vector_register3_vr ".uint128 = 0x00000001000000010000000100000001, v4_float = .0x0, 0x0, 0x0, 0x0., v4_int32 = .0x1, 0x1, 0x1, 0x1., v8_int16 = .0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1., v16_int8 = .0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1.."
++ set vector_register2 "uint128 = 0xdeadbeefdeadbeefdeadbeefdeadbeef, v2_double = .0x1, 0x1., v4_float = .0x0, 0x0, 0x0, 0x0., v4_int32 = .0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef., v8_int16 = .0xbeef, 0xdead, 0xbeef, 0xdead, 0xbeef, 0xdead, 0xbeef, 0xdead., v16_int8 = .0xef, 0xbe, 0xad, 0xde, 0xef, 0xbe, 0xad, 0xde, 0xef, 0xbe, 0xad, 0xde, 0xef, 0xbe, 0xad, 0xde.."
++
++ set vector_register2_vr "uint128 = 0xdeadbeefdeadbeefdeadbeefdeadbeef, v4_float = .0x0, 0x0, 0x0, 0x0., v4_int32 = .0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef., v8_int16 = .0xbeef, 0xdead, 0xbeef, 0xdead, 0xbeef, 0xdead, 0xbeef, 0xdead., v16_int8 = .0xef, 0xbe, 0xad, 0xde, 0xef, 0xbe, 0xad, 0xde, 0xef, 0xbe, 0xad, 0xde, 0xef, 0xbe, 0xad, 0xde.."
++
++ set vector_register3 ".uint128 = 0x00000001000000010000000100000001, v2_double = .0x0, 0x0., v4_float = .0x0, 0x0, 0x0, 0x0., v4_int32 = .0x1, 0x1, 0x1, 0x1., v8_int16 = .0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0., v16_int8 = .0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0.."
++
++ set vector_register3_vr ".uint128 = 0x00000001000000010000000100000001, v4_float = .0x0, 0x0, 0x0, 0x0., v4_int32 = .0x1, 0x1, 0x1, 0x1., v8_int16 = .0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0., v16_int8 = .0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0.."
++}
+
+ set float_register ".raw 0xdeadbeefdeadbeef."
+
+Index: b/gdb/testsuite/gdb.base/sigbpt.exp
+===================================================================
+--- a/gdb/testsuite/gdb.base/sigbpt.exp
++++ b/gdb/testsuite/gdb.base/sigbpt.exp
+@@ -76,7 +76,7 @@
+ set bowler_addrs bowler
+ set segv_addr none
+ gdb_test {display/i $pc}
+-gdb_test "advance *bowler" "bowler.*" "advance to the bowler"
++gdb_test "advance bowler" "bowler.*" "advance to the bowler"
+ set test "stepping to fault"
+ set signame "SIGSEGV"
+ gdb_test_multiple "stepi" "$test" {
+Index: b/gdb/testsuite/gdb.base/step-bt.c
+===================================================================
+--- a/gdb/testsuite/gdb.base/step-bt.c
++++ b/gdb/testsuite/gdb.base/step-bt.c
+@@ -23,10 +23,19 @@
+ printf ("Hello world.\n");
+ }
+
++/* The test case uses "break *hello" to make sure to step at the very
++ first instruction of the function. This causes a problem running
++ the test on powerpc64le-linux, since the first instruction belongs
++ to the global entry point prologue, which is skipped when doing a
++ local direct function call. To make sure that first instruction is
++ indeed being executed and the breakpoint hits, we make sure to call
++ the routine via an indirect call. */
++void (*ptr) (void) = hello;
++
+ int
+ main (void)
+ {
+- hello ();
++ ptr ();
+
+ return 0;
+ }
diff --git a/debian/patches/series b/debian/patches/series
index 3ffe3ab..67a787b 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -3,3 +3,4 @@ linuxthreads_signal_handling.patch
solve_PATH_MAX_issue.patch
gdb-6.5-bz185337-resolve-tls-without-debuginfo-v2.patch
python-config.patch
+ppc64le.diff
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-gdb/gdb.git
More information about the Crosstoolchain-logs
mailing list