From: Ulrich Weigand <uweigand@de.ibm.com>
References: ppc64le enablement
Patch-mainline: not yet

Signed-off-by: Ulrich Weigand <uweigand@de.ibm.com>
Signed-off-by: Petr Tesarik <ptesarik@suse.cz>

---
 gdb/auxv.c                                   |    1 
 gdb/configure.host                           |    4 
 gdb/configure.tgt                            |    2 
 gdb/doublest.c                               |   49 +-
 gdb/gdbarch.c                                |   33 +
 gdb/gdbarch.h                                |    6 
 gdb/gdbarch.sh                               |    1 
 gdb/gdbtypes.c                               |    4 
 gdb/infrun.c                                 |    4 
 gdb/ppc-linux-tdep.c                         |   60 ++-
 gdb/ppc-sysv-tdep.c                          |  534 ++++++++++++++++++++++++---
 gdb/ppc-tdep.h                               |   11 
 gdb/ppc64-tdep.c                             |    2 
 gdb/rs6000-tdep.c                            |   43 +-
 gdb/symtab.c                                 |    2 
 gdb/testsuite/gdb.arch/altivec-regs.exp      |    2 
 gdb/testsuite/gdb.arch/powerpc-d128-regs.exp |    2 
 gdb/testsuite/gdb.arch/vsx-regs.exp          |   39 +
 gdb/testsuite/gdb.base/sigbpt.exp            |    2 
 gdb/testsuite/gdb.base/step-bt.exp           |    2 
 include/elf/common.h                         |    1 
 include/elf/ppc64.h                          |   54 ++
 22 files changed, 752 insertions(+), 106 deletions(-)

--- a/gdb/ppc64-tdep.c
+++ b/gdb/ppc64-tdep.c
@@ -289,7 +289,7 @@ static struct ppc_insn_pattern ppc64_sta
 static struct ppc_insn_pattern ppc64_standard_linkage7[] =
   {
     /* std r2, 24(r1) <optional> */
-    { -1, insn_ds (62, 2, 1, 40, 0), 1 },
+    { -1, insn_ds (62, 2, 1, 24, 0), 1 },
 
     /* ld r12, <any>(r2) */
     { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 12, 2, 0, 0), 0 },
--- 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 @@ dfp_pseudo_register_read (struct gdbarch
   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 @@ dfp_pseudo_register_write (struct gdbarc
   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);
     }
 }
 
@@ -2781,7 +2782,8 @@ efpr_pseudo_register_read (struct gdbarc
   int reg_index = reg_nr - tdep->ppc_efpr0_regnum;
 
   /* Read the portion that overlaps the VMX register.  */
-  return regcache_raw_read_part (regcache, tdep->ppc_vr0_regnum + reg_index, 0,
+  int offset = gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG ? 0 : 8;
+  return regcache_raw_read_part (regcache, tdep->ppc_vr0_regnum + reg_index, offset,
 				 register_size (gdbarch, reg_nr), buffer);
 }
 
@@ -2794,7 +2796,8 @@ efpr_pseudo_register_write (struct gdbar
   int reg_index = reg_nr - tdep->ppc_efpr0_regnum;
 
   /* Write the portion that overlaps the VMX register.  */
-  regcache_raw_write_part (regcache, tdep->ppc_vr0_regnum + reg_index, 0,
+  int offset = gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG ? 0 : 8;
+  regcache_raw_write_part (regcache, tdep->ppc_vr0_regnum + reg_index, offset,
 			   register_size (gdbarch, reg_nr), buffer);
 }
 
@@ -3550,6 +3553,7 @@ rs6000_gdbarch_init (struct gdbarch_info
   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 +3860,21 @@ rs6000_gdbarch_init (struct gdbarch_info
     }
 
 #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 +3911,15 @@ rs6000_gdbarch_init (struct gdbarch_info
     }
 #endif
 
+  /* Default to ELFv2 ABI on 64-bit little-endian, and ELFv1 otherwise.  */
+  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 +3962,8 @@ rs6000_gdbarch_init (struct gdbarch_info
          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 +3986,7 @@ rs6000_gdbarch_init (struct gdbarch_info
 
   tdep = XCALLOC (1, struct gdbarch_tdep);
   tdep->wordsize = wordsize;
+  tdep->elf_abi = elf_abi;
   tdep->soft_float = soft_float;
   tdep->vector_abi = vector_abi;
 
--- a/gdb/auxv.c
+++ b/gdb/auxv.c
@@ -441,6 +441,7 @@ fprint_target_auxv (struct ui_file *file
 	  TAG (AT_IGNOREPPC, _("Entry should be ignored"), dec);
 	  TAG (AT_BASE_PLATFORM, _("String identifying base platform"), str);
 	  TAG (AT_RANDOM, _("Address of 16 random bytes"), hex);
+	  TAG (AT_HWCAP2, _("Extension of AT_HWCAP"), hex);
 	  TAG (AT_EXECFN, _("File name of executable"), str);
 	  TAG (AT_SECURE, _("Boolean, was exec setuid-like?"), dec);
 	  TAG (AT_SYSINFO, _("Special system info/entry points"), hex);
--- a/gdb/configure.host
+++ b/gdb/configure.host
@@ -129,18 +129,18 @@ mips64*-*-openbsd*)	gdb_host=obsd64 ;;
 powerpc-*-aix* | rs6000-*-*)
 			gdb_host=aix ;;
 powerpc*-*-freebsd*)	gdb_host=fbsd ;;
-powerpc-*-linux*)	gdb_host=linux ;;
 powerpc-*-netbsd* | powerpc-*-knetbsd*-gnu)
 			gdb_host=nbsd ;;
 powerpc-*-openbsd*)	gdb_host=obsd ;;
 
-powerpc64-*-linux*)     gdb_host=ppc64-linux
+powerpc64*-*-linux*)	gdb_host=ppc64-linux
                         # Support 'pseudo-native' debugging on the Cell BE
                         if test "${target_cpu}" = "spu"; then
 				gdb_host=spu-linux
 				gdb_native=yes
                         fi
 			;;
+powerpc*-*-linux*)	gdb_host=linux ;;
 
 s390*-*-*)		gdb_host=s390 ;;
 
--- a/gdb/configure.tgt
+++ b/gdb/configure.tgt
@@ -421,7 +421,7 @@ powerpc-*-aix* | rs6000-*-*)
 			ppc-sysv-tdep.o solib-svr4.o \
 			ravenscar-thread.o ppc-ravenscar-thread.o"
 	;;
-powerpc-*-linux* | powerpc64-*-linux*)
+powerpc*-*-linux*)
 	# Target: PowerPC running Linux
 	gdb_target_obs="rs6000-tdep.o ppc-linux-tdep.o ppc-sysv-tdep.o \
 			ppc64-tdep.o solib-svr4.o solib-spu.o \
--- a/gdb/doublest.c
+++ b/gdb/doublest.c
@@ -190,7 +190,8 @@ convert_floatformat_to_doublest (const s
     {
       double dto;
 
-      floatformat_to_double (fmt, from, &dto);
+      floatformat_to_double (fmt->split_half ? fmt->split_half : fmt,
+			     from, &dto);
       *to = (DOUBLEST) dto;
       return;
     }
@@ -561,6 +562,11 @@ floatformat_is_negative (const struct fl
   gdb_assert (fmt->totalsize
 	      <= FLOATFORMAT_LARGEST_BYTES * FLOATFORMAT_CHAR_BIT);
 
+  /* An IBM long double (a two element array of double) always takes the
+     sign of the first double.  */
+  if (fmt->split_half)
+    fmt = fmt->split_half;
+
   order = floatformat_normalize_byteorder (fmt, uval, newfrom);
 
   if (order != fmt->byteorder)
@@ -587,6 +593,13 @@ floatformat_classify (const struct float
   gdb_assert (fmt->totalsize
 	      <= FLOATFORMAT_LARGEST_BYTES * FLOATFORMAT_CHAR_BIT);
 
+  /* An IBM long double (a two element array of double) can be classified
+     by looking at the first double.  inf and nan are specified as
+     ignoring the second double.  zero and subnormal will always have
+     the second double 0.0 if the long double is correctly rounded.  */
+  if (fmt->split_half)
+    fmt = fmt->split_half;
+
   order = floatformat_normalize_byteorder (fmt, uval, newfrom);
 
   if (order != fmt->byteorder)
@@ -669,6 +682,16 @@ floatformat_mantissa (const struct float
   gdb_assert (fmt->totalsize
 	      <= FLOATFORMAT_LARGEST_BYTES * FLOATFORMAT_CHAR_BIT);
 
+  /* For IBM long double (a two element array of double), return the
+     mantissa of the first double.  The problem with returning the
+     actual mantissa from both doubles is that there can be an
+     arbitrary number of implied 0's or 1's between the mantissas
+     of the first and second double.  In any case, this function
+     is only used for dumping out nans, and a nan is specified to
+     ignore the value in the second double.  */
+  if (fmt->split_half)
+    fmt = fmt->split_half;
+
   order = floatformat_normalize_byteorder (fmt, uval, newfrom);
 
   if (order != fmt->byteorder)
@@ -926,27 +949,3 @@ convert_typed_floating (const void *from
       floatformat_from_doublest (to_fmt, &d, to);
     }
 }
-
-const struct floatformat *floatformat_ieee_single[BFD_ENDIAN_UNKNOWN];
-const struct floatformat *floatformat_ieee_double[BFD_ENDIAN_UNKNOWN];
-const struct floatformat *floatformat_ieee_quad[BFD_ENDIAN_UNKNOWN];
-const struct floatformat *floatformat_arm_ext[BFD_ENDIAN_UNKNOWN];
-const struct floatformat *floatformat_ia64_spill[BFD_ENDIAN_UNKNOWN];
-
-extern void _initialize_doublest (void);
-
-extern void
-_initialize_doublest (void)
-{
-  floatformat_ieee_single[BFD_ENDIAN_LITTLE] = &floatformat_ieee_single_little;
-  floatformat_ieee_single[BFD_ENDIAN_BIG] = &floatformat_ieee_single_big;
-  floatformat_ieee_double[BFD_ENDIAN_LITTLE] = &floatformat_ieee_double_little;
-  floatformat_ieee_double[BFD_ENDIAN_BIG] = &floatformat_ieee_double_big;
-  floatformat_arm_ext[BFD_ENDIAN_LITTLE]
-    = &floatformat_arm_ext_littlebyte_bigword;
-  floatformat_arm_ext[BFD_ENDIAN_BIG] = &floatformat_arm_ext_big;
-  floatformat_ia64_spill[BFD_ENDIAN_LITTLE] = &floatformat_ia64_spill_little;
-  floatformat_ia64_spill[BFD_ENDIAN_BIG] = &floatformat_ia64_spill_big;
-  floatformat_ieee_quad[BFD_ENDIAN_LITTLE] = &floatformat_ia64_quad_little;
-  floatformat_ieee_quad[BFD_ENDIAN_BIG] = &floatformat_ia64_quad_big;
-}
--- a/gdb/gdbarch.c
+++ b/gdb/gdbarch.c
@@ -200,6 +200,7 @@ struct gdbarch
   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;
@@ -371,6 +372,7 @@ struct gdbarch startup_gdbarch =
   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 */
@@ -672,6 +674,7 @@ verify_gdbarch (struct gdbarch *gdbarch)
   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)
@@ -1285,6 +1288,12 @@ gdbarch_dump (struct gdbarch *gdbarch, s
                       "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,
@@ -2635,6 +2644,30 @@ set_gdbarch_skip_main_prologue (struct g
 }
 
 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);
--- a/gdb/gdbarch.h
+++ b/gdb/gdbarch.h
@@ -487,6 +487,12 @@ typedef CORE_ADDR (gdbarch_skip_main_pro
 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);
 
+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);
--- a/gdb/gdbarch.sh
+++ b/gdb/gdbarch.sh
@@ -527,6 +527,7 @@ m:int:return_in_first_hidden_param_p:str
 
 m:CORE_ADDR:skip_prologue:CORE_ADDR ip:ip:0:0
 M:CORE_ADDR:skip_main_prologue:CORE_ADDR ip:ip
+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.
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -107,8 +107,8 @@ const struct floatformat *floatformats_v
   &floatformat_vax_d
 };
 const struct floatformat *floatformats_ibm_long_double[BFD_ENDIAN_UNKNOWN] = {
-  &floatformat_ibm_long_double,
-  &floatformat_ibm_long_double
+  &floatformat_ibm_long_double_big,
+  &floatformat_ibm_long_double_little
 };
 
 /* Should opaque types be resolved?  */
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -3139,6 +3139,10 @@ fill_in_stop_func (struct gdbarch *gdbar
       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;
     }
 }
--- 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,43 @@ ppc_linux_core_read_description (struct
     }
 }
 
+/* If the ELF symbol has a local entry point, use it as SYMBOL_VALUE_ADDRESS
+   for the msymbol.  This matches the DWARF function start if present.  */
+
+static void
+ppc_elfv2_elf_make_msymbol_special (asymbol *sym, struct minimal_symbol *msym)
+{
+  elf_symbol_type *elf_sym = (elf_symbol_type *)sym;
+  switch (PPC64_LOCAL_ENTRY_OFFSET (elf_sym->internal_elf_sym.st_other))
+    {
+    default:
+      break;
+    case 8:
+      MSYMBOL_TARGET_FLAG_1 (msym) = 1;
+      break;
+    }
+}
+
+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;
+
+  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.  */
 
@@ -1332,13 +1370,23 @@ ppc_linux_init_abi (struct gdbarch_info
   
   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);
+	  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_skip_entrypoint (gdbarch, ppc_elfv2_skip_entrypoint);
+	}
 
       /* Shared library handling.  */
       set_gdbarch_skip_trampoline_code (gdbarch, ppc64_skip_trampoline_code);
--- a/gdb/ppc-sysv-tdep.c
+++ b/gdb/ppc-sysv-tdep.c
@@ -610,42 +610,48 @@ ppc_sysv_abi_push_dummy_call (struct gdb
 }
 
 /* Handle the return-value conventions for Decimal Floating Point values
-   in both ppc32 and ppc64, which are the same.  */
-static int
+   in both ppc32 and ppc64, which are the same.  INDEX specifies which
+   part of a multi-part return value is to be handled.  */
+static void
 get_decimal_float_return_value (struct gdbarch *gdbarch, struct type *valtype,
 				struct regcache *regcache, gdb_byte *readbuf,
-				const gdb_byte *writebuf)
+				const gdb_byte *writebuf, int index)
 {
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  int offset = index * TYPE_LENGTH (valtype);
 
   gdb_assert (TYPE_CODE (valtype) == TYPE_CODE_DECFLOAT);
 
   /* 32-bit and 64-bit decimal floats in f1.  */
   if (TYPE_LENGTH (valtype) <= 8)
     {
+      int regnum = tdep->ppc_fp0_regnum + 1 + index;
+
       if (writebuf != NULL)
 	{
 	  gdb_byte regval[MAX_REGISTER_SIZE];
 	  const gdb_byte *p;
 
 	  /* 32-bit decimal float is right aligned in the doubleword.  */
-	  if (TYPE_LENGTH (valtype) == 4)
+	  if (TYPE_LENGTH (valtype) == 4
+	      && gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
 	    {
-	      memcpy (regval + 4, writebuf, 4);
+	      memcpy (regval + 4, writebuf + offset, 4);
 	      p = regval;
 	    }
 	  else
-	    p = writebuf;
+	    p = writebuf + offset;
 
-	  regcache_cooked_write (regcache, tdep->ppc_fp0_regnum + 1, p);
+	  regcache_cooked_write (regcache, regnum, p);
 	}
       if (readbuf != NULL)
 	{
-	  regcache_cooked_read (regcache, tdep->ppc_fp0_regnum + 1, readbuf);
+	  regcache_cooked_read (regcache, regnum, readbuf);
 
 	  /* Left align 32-bit decimal float.  */
-	  if (TYPE_LENGTH (valtype) == 4)
-	    memcpy (readbuf, readbuf + 4, 4);
+	  if (TYPE_LENGTH (valtype) == 4
+	      && gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
+	    memcpy (readbuf + offset, readbuf + offset + 4, 4);
 	}
     }
   /* 128-bit decimal floats in f2,f3.  */
@@ -653,24 +659,27 @@ get_decimal_float_return_value (struct g
     {
       if (writebuf != NULL || readbuf != NULL)
 	{
-	  int i;
+	  int i, regnum;
 
 	  for (i = 0; i < 2; i++)
 	    {
+	      if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
+		regnum = tdep->ppc_fp0_regnum + 2 + i + 2 * index;
+	      else
+		regnum = tdep->ppc_fp0_regnum + 3 - i + 2 * index;
+
 	      if (writebuf != NULL)
-		regcache_cooked_write (regcache, tdep->ppc_fp0_regnum + 2 + i,
-				       writebuf + i * 8);
+		regcache_cooked_write (regcache, regnum,
+				       writebuf + offset + i * 8);
 	      if (readbuf != NULL)
-		regcache_cooked_read (regcache, tdep->ppc_fp0_regnum + 2 + i,
-				      readbuf + i * 8);
+		regcache_cooked_read (regcache, regnum,
+				      readbuf + offset + i * 8);
 	    }
 	}
     }
   else
     /* Can't happen.  */
     internal_error (__FILE__, __LINE__, _("Unknown decimal float size."));
-
-  return RETURN_VALUE_REGISTER_CONVENTION;
 }
 
 /* Handle the return-value conventions specified by the SysV 32-bit
@@ -802,8 +811,11 @@ do_ppc_sysv_return_value (struct gdbarch
       return RETURN_VALUE_REGISTER_CONVENTION;
     }
   if (TYPE_CODE (type) == TYPE_CODE_DECFLOAT && !tdep->soft_float)
-    return get_decimal_float_return_value (gdbarch, type, regcache, readbuf,
-					   writebuf);
+    {
+      get_decimal_float_return_value (gdbarch, type, regcache,
+				      readbuf, writebuf, 0);
+      return RETURN_VALUE_REGISTER_CONVENTION;
+    }
   else if ((TYPE_CODE (type) == TYPE_CODE_INT
 	    || TYPE_CODE (type) == TYPE_CODE_CHAR
 	    || TYPE_CODE (type) == TYPE_CODE_BOOL
@@ -1102,6 +1114,156 @@ convert_code_addr_to_desc_addr (CORE_ADD
   return 1;
 }
 
+/* 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);
+
+  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;
+	      return 1;
+	    }
+	}
+    }
+
+  return 0;
+}
+
 /* Push a float in either registers, or in the stack.  Using the ppc 64 bit
    SysV ABI.
 
@@ -1143,6 +1305,8 @@ ppc64_sysv_abi_push_float (struct gdbarc
 
       /* Write value in the stack's parameter save area.  */
       write_memory (gparam, p, 8);
+      if (greg <= 10)
+	regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + greg, p);
 
       /* Floats and Doubles go in f1 .. f13.  They also consume a left aligned
 	 GREG, and can end up in memory.  */
@@ -1154,8 +1318,6 @@ ppc64_sysv_abi_push_float (struct gdbarc
 	  convert_typed_floating (val, type, regval, regtype);
 	  regcache_cooked_write (regcache, tdep->ppc_fp0_regnum + freg, regval);
 	}
-      if (greg <= 10)
-	regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + greg, regval);
     }
   else
     {
@@ -1268,9 +1430,13 @@ ppc64_sysv_abi_push_dummy_call (struct g
 	     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);
+	  /* 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 (gparam - 48, 16);
+	  else
+	    sp = align_down (gparam - 32, 16);
 	}
 
       /* If the function is returning a `struct', then there is an
@@ -1375,7 +1541,8 @@ ppc64_sysv_abi_push_dummy_call (struct g
 
 		  /* 32-bit decimal floats are right aligned in the
 		     doubleword.  */
-		  if (TYPE_LENGTH (type) == 4)
+		  if (TYPE_LENGTH (type) == 4
+		      && byte_order == BFD_ENDIAN_BIG)
 		    {
 		      memcpy (regval + 4, val, 4);
 		      p = regval;
@@ -1407,10 +1574,21 @@ ppc64_sysv_abi_push_dummy_call (struct g
 		    {
 		      /* 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);
+
+		      if (byte_order == BFD_ENDIAN_BIG)
+			{
+			  regcache_cooked_write (regcache,
+						 tdep->ppc_fp0_regnum + freg, val);
+			  regcache_cooked_write (regcache,
+						 tdep->ppc_fp0_regnum + freg + 1, val + 8);
+			}
+		      else
+			{
+			  regcache_cooked_write (regcache,
+						 tdep->ppc_fp0_regnum + freg + 1, val);
+			  regcache_cooked_write (regcache,
+						 tdep->ppc_fp0_regnum + freg, val + 8);
+			}
 		    }
 
 		  write_memory (gparam, val, TYPE_LENGTH (type));
@@ -1587,8 +1765,9 @@ ppc64_sysv_abi_push_dummy_call (struct g
 		  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)
+		  if (tdep->elf_abi == POWERPC_ELF_V1
+		      && (TYPE_CODE (type) == TYPE_CODE_PTR
+			  || TYPE_CODE (type) == TYPE_CODE_REF))
 		    {
 		      struct type *target_type;
 		      target_type = check_typedef (TYPE_TARGET_TYPE (type));
@@ -1613,6 +1792,9 @@ ppc64_sysv_abi_push_dummy_call (struct g
 	    }
 	  else
 	    {
+	      struct type *elt_type;
+	      int n_elts;
+
 	      int byte;
 	      for (byte = 0; byte < TYPE_LENGTH (type);
 		   byte += tdep->wordsize)
@@ -1630,7 +1812,7 @@ ppc64_sysv_abi_push_dummy_call (struct g
 			 versions before 3.4 implemented this
 			 incorrectly; see
 			 <http://gcc.gnu.org/gcc-3.4/powerpc-abi.html>.  */
-		      if (byte == 0)
+		      if (byte_order == BFD_ENDIAN_BIG && byte == 0)
 			memcpy (regval + tdep->wordsize - len,
 				val + byte, len);
 		      else
@@ -1649,7 +1831,7 @@ ppc64_sysv_abi_push_dummy_call (struct g
 		     value to memory.  Fortunately, doing this
 		     simplifies the code.  */
 		  int len = TYPE_LENGTH (type);
-		  if (len < tdep->wordsize)
+		  if (byte_order == BFD_ENDIAN_BIG && len < tdep->wordsize)
 		    write_memory (gparam + tdep->wordsize - len, val, len);
 		  else
 		    write_memory (gparam, val, len);
@@ -1705,6 +1887,132 @@ ppc64_sysv_abi_push_dummy_call (struct g
 			}
 		    }
 		}
+	      /* In the ELFv2 ABI, homogeneous floating-point or vector
+		 aggregates are passed in registers.  */
+	      if (tdep->elf_abi == POWERPC_ELF_V2
+		  && ppc64_elfv2_abi_homogeneous_aggregate (type,
+							    &elt_type, &n_elts))
+		{
+		  int i;
+		  for (i = 0; i < n_elts; i++)
+		    {
+		      const gdb_byte *elt_val
+			= val + i * TYPE_LENGTH (elt_type);
+
+		      switch (TYPE_CODE (elt_type))
+			{
+			case TYPE_CODE_FLT:
+			  if (TYPE_LENGTH (elt_type) <= 8)
+			    {
+			      if (write_pass && freg <= 13)
+				{
+				  int fregnum = tdep->ppc_fp0_regnum + freg;
+				  gdb_byte regval[MAX_REGISTER_SIZE];
+				  struct type *regtype
+				    = register_type (gdbarch, fregnum);
+				  convert_typed_floating (elt_val, elt_type,
+							  regval, regtype);
+				  regcache_cooked_write (regcache,
+							 fregnum, regval);
+				}
+			      freg++;
+			    }
+			  else if (TYPE_LENGTH (elt_type) == 16
+				   && (gdbarch_long_double_format (gdbarch)
+				       == floatformats_ibm_long_double))
+			    {
+			      if (write_pass && freg <= 13)
+				{
+				  int fregnum = tdep->ppc_fp0_regnum + freg;
+				  regcache_cooked_write (regcache,
+							 fregnum, elt_val);
+				  if (freg <= 12)
+				    regcache_cooked_write (regcache,
+							   fregnum + 1,
+							   elt_val + 8);
+				}
+			      freg += 2;
+			    }
+			  break;
+
+			case TYPE_CODE_DECFLOAT:
+			  if (TYPE_LENGTH (elt_type) <= 8)
+			    {
+			      if (write_pass && freg <= 13)
+				{
+				  int fregnum = tdep->ppc_fp0_regnum + freg;
+				  gdb_byte regval[MAX_REGISTER_SIZE];
+				  const gdb_byte *p;
+
+				  /* 32-bit decimal floats are right aligned
+				     in the doubleword.  */
+				  if (TYPE_LENGTH (elt_type) == 4
+				      && byte_order == BFD_ENDIAN_BIG)
+				    {
+				      memcpy (regval + 4, elt_val, 4);
+				      p = regval;
+				    }
+				  else
+				    p = elt_val;
+
+				  regcache_cooked_write (regcache, fregnum, p);
+				}
+			      freg++;
+			    }
+			  else if (TYPE_LENGTH (elt_type) == 16)
+			    {
+			      /* Make sure freg is even.  */
+			      freg += freg & 1;
+
+			      if (write_pass && freg <= 12)
+				{
+				  int fregnum = tdep->ppc_fp0_regnum + freg;
+				  if (byte_order == BFD_ENDIAN_BIG)
+				    {
+				      regcache_cooked_write (regcache,
+							     fregnum,
+							     elt_val);
+				      regcache_cooked_write (regcache,
+							     fregnum + 1,
+							     elt_val + 8);
+				    }
+				  else
+				    {
+				      regcache_cooked_write (regcache,
+							     fregnum + 1,
+							     elt_val);
+				      regcache_cooked_write (regcache,
+							     fregnum,
+							     elt_val + 8);
+				    }
+				}
+			      freg += 2;
+			    }
+			  break;
+
+			case TYPE_CODE_ARRAY:
+			  gdb_assert (TYPE_VECTOR (type));
+
+			  if (tdep->vector_abi == POWERPC_VEC_ALTIVEC
+			      && TYPE_LENGTH (elt_type) == 16)
+			    {
+			      if (write_pass && vreg <= 13)
+				{
+				  int vregnum = tdep->ppc_vr0_regnum + vreg;
+				  regcache_cooked_write (regcache,
+							 vregnum, elt_val);
+				}
+			      vreg++;
+			    }
+			  break;
+
+			default:
+			  internal_error (__FILE__, __LINE__,
+					  _("Unknown element type."));
+			  break;
+			}
+		    }
+		}
 	      /* Always consume parameter stack space.  */
 	      gparam = align_up (gparam + TYPE_LENGTH (type), tdep->wordsize);
 	    }
@@ -1733,24 +2041,31 @@ ppc64_sysv_abi_push_dummy_call (struct g
      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);
-
-    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 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);
+	}
+    }
+
+  /* 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;
 }
@@ -1775,6 +2090,8 @@ ppc64_sysv_abi_return_value (struct gdba
   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 *elt_type;
+  int n_elts;
 
   /* This function exists to support a calling convention that
      requires floating-point registers.  It shouldn't be used on
@@ -1799,8 +2116,11 @@ ppc64_sysv_abi_return_value (struct gdba
       return RETURN_VALUE_REGISTER_CONVENTION;
     }
   if (TYPE_CODE (valtype) == TYPE_CODE_DECFLOAT)
-    return get_decimal_float_return_value (gdbarch, valtype, regcache, readbuf,
-					   writebuf);
+    {
+      get_decimal_float_return_value (gdbarch, valtype, regcache,
+				      readbuf, writebuf, 0);
+      return RETURN_VALUE_REGISTER_CONVENTION;
+    }
   /* Integers in r3.  */
   if ((TYPE_CODE (valtype) == TYPE_CODE_INT
        || TYPE_CODE (valtype) == TYPE_CODE_ENUM
@@ -2019,6 +2339,114 @@ ppc64_sysv_abi_return_value (struct gdba
 	    }
 	}
       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, &elt_type, &n_elts))
+    {
+      int i;
+      for (i = 0; i < n_elts; i++)
+	{
+	  int offset = i * TYPE_LENGTH (elt_type);
+
+	  switch (TYPE_CODE (elt_type))
+	    {
+	    case TYPE_CODE_FLT:
+	      if (TYPE_LENGTH (elt_type) <= 8)
+		{
+		  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, elt_type,
+					      regval, regtype);
+		      regcache_cooked_write (regcache, regnum, regval);
+		    }
+		  if (readbuf != NULL)
+		    {
+		      regcache_cooked_read (regcache, regnum, regval);
+		      convert_typed_floating (regval, regtype,
+					      readbuf + offset, elt_type);
+		    }
+		}
+	      else
+		{
+		  int j, nregs = (TYPE_LENGTH (elt_type) + 7) / 8;
+		  for (j = 0; j < nregs; j++)
+		    {
+		      int regnum = tdep->ppc_fp0_regnum + 1 + nregs * i + j;
+
+		      if (writebuf != NULL)
+			regcache_cooked_write (regcache, regnum,
+					       writebuf + offset + j * 8);
+		      if (readbuf != NULL)
+			regcache_cooked_read (regcache, regnum,
+					      readbuf + offset + j * 8);
+		    }
+		}
+	      break;
+
+	    case TYPE_CODE_DECFLOAT:
+	      get_decimal_float_return_value (gdbarch, elt_type, regcache,
+					      readbuf, writebuf, i);
+	      break;
+
+	    case TYPE_CODE_ARRAY:
+	      {
+		int regnum = tdep->ppc_vr0_regnum + 2 + i;
+		gdb_assert (TYPE_VECTOR (elt_type));
+
+		if (writebuf != NULL)
+		  regcache_cooked_write (regcache, regnum, writebuf + offset);
+		if (readbuf != NULL)
+		  regcache_cooked_read (regcache, regnum, readbuf + offset);
+	      }
+	      break;
+	    }
+	}
+      return RETURN_VALUE_REGISTER_CONVENTION;
+    }
+  /* 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) + tdep->wordsize - 1) / tdep->wordsize;
+      int i;
+
+      for (i = 0; i < n_regs; 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 (len > tdep->wordsize)
+	    len = tdep->wordsize;
+
+	  if (writebuf != NULL)
+	    {
+	      memset (regval, 0, sizeof regval);
+	      if (byte_order == BFD_ENDIAN_BIG && offset == 0)
+		memcpy (regval + tdep->wordsize - len, writebuf, len);
+	      else
+		memcpy (regval, writebuf + offset, len);
+	      regcache_cooked_write (regcache, regnum, regval);
+	    }
+	  if (readbuf != NULL)
+	    {
+	      regcache_cooked_read (regcache, regnum, regval);
+	      if (byte_order == BFD_ENDIAN_BIG && offset == 0)
+		memcpy (readbuf, regval + tdep->wordsize - len, len);
+	      else
+		memcpy (readbuf + offset, regval, len);
+	    }
+	}
+      return RETURN_VALUE_REGISTER_CONVENTION;
     }
   return RETURN_VALUE_STRUCT_CONVENTION;
 }
--- a/gdb/ppc-tdep.h
+++ b/gdb/ppc-tdep.h
@@ -182,6 +182,15 @@ extern void ppc_collect_vsxregset (const
 
 /* 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 @@ struct gdbarch_tdep
     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;
 
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -2881,6 +2881,8 @@ skip_prologue_sal (struct symtab_and_lin
 
       /* 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);
 
--- a/gdb/testsuite/gdb.arch/altivec-regs.exp
+++ b/gdb/testsuite/gdb.arch/altivec-regs.exp
@@ -118,7 +118,7 @@ gdb_test "info reg vscr" "vscr.*0x1\t1"
 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} {
--- 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
 }
--- a/gdb/testsuite/gdb.arch/vsx-regs.exp
+++ b/gdb/testsuite/gdb.arch/vsx-regs.exp
@@ -58,19 +58,46 @@ if ![runto_main] then {
     gdb_suppress_tests
 }
 
+send_gdb "show endian\n"
+set endianness ""
+gdb_expect {
+    -re "(The target endianness is set automatically .currently )(big|little)( endian.*)$gdb_prompt $" {
+        pass "endianness"
+        set endianness $expect_out(2,string)
+    }
+    -re ".*$gdb_prompt $" {
+        fail "couldn't get endianness"
+    }
+    timeout             { fail "(timeout) endianness" }
+}
+
 # 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."
 
--- a/gdb/testsuite/gdb.base/sigbpt.exp
+++ b/gdb/testsuite/gdb.base/sigbpt.exp
@@ -82,7 +82,7 @@ gdb_test "break keeper"
 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" {
--- a/gdb/testsuite/gdb.base/step-bt.exp
+++ b/gdb/testsuite/gdb.base/step-bt.exp
@@ -32,7 +32,7 @@ gdb_start
 gdb_reinitialize_dir $srcdir/$subdir
 gdb_load ${binfile}
 
-gdb_test "break *hello" \
+gdb_test "break hello" \
          "Breakpoint.*at.* file .*$srcfile, line .*" \
          "breakpoint at first instruction of hello()"
 
--- a/include/elf/common.h
+++ b/include/elf/common.h
@@ -954,6 +954,7 @@
 #define AT_BASE_PLATFORM 24		/* String identifying real platform,
 					   may differ from AT_PLATFORM.  */
 #define AT_RANDOM	25		/* Address of 16 random bytes.  */
+#define AT_HWCAP2	26		/* Extension of AT_HWCAP.  */
 #define AT_EXECFN	31		/* Filename of executable.  */
 /* Pointer to the global system page used for system calls and other
    nice things.  */
--- a/include/elf/ppc64.h
+++ b/include/elf/ppc64.h
@@ -164,6 +164,60 @@ END_RELOC_NUMBERS (R_PPC64_max)
 #define IS_PPC64_TLS_RELOC(R) \
   ((R) >= R_PPC64_TLS && (R) <= R_PPC64_DTPREL16_HIGHESTA)
 
+
+/* e_flags bits specifying ABI.
+   1 for original function descriptor using ABI,
+   2 for revised ABI without function descriptors,
+   0 for unspecified or not using any features affected by the differences.  */
+#define EF_PPC64_ABI	3
+
+/* The ELFv2 ABI uses three bits in the symbol st_other field of a
+   function definition to specify the number of instructions between a
+   function's global entry point and local entry point.
+   The global entry point is used when it is necessary to set up the
+   toc pointer (r2) for the function.  Callers must enter the global
+   entry point with r12 set to the global entry point address.  On
+   return from the function, r2 may have a different value to that
+   which it had on entry.
+   The local entry point is used when r2 is known to already be valid
+   for the function.  There is no requirement on r12 when using the
+   local entry point, and on return r2 will contain the same value as
+   at entry.
+   A value of zero in these bits means that the function has a single
+   entry point with no requirement on r12 or r2, and that on return r2
+   will contain the same value as at entry.
+   Values of one and seven are reserved.  */
+#define STO_PPC64_LOCAL_BIT		5
+#define STO_PPC64_LOCAL_MASK		(7 << STO_PPC64_LOCAL_BIT)
+
+// 3 bit other field to bytes.
+static inline unsigned int
+ppc64_decode_local_entry(unsigned int other)
+{
+  return ((1 << other) >> 2) << 2;
+}
+
+// bytes to field value.
+static inline unsigned int
+ppc64_encode_local_entry(unsigned int val)
+{
+  return (val >= 4 * 4
+	  ? (val >= 8 * 4
+	     ? (val >= 16 * 4 ? 6 : 5)
+	     : 4)
+	  : (val >= 2 * 4
+	     ? 3
+	     : (val >= 1 * 4 ? 2 : 0)));
+}
+
+/* st_other to number of bytes.  */
+#define PPC64_LOCAL_ENTRY_OFFSET(other)				\
+  ppc64_decode_local_entry (((other) & STO_PPC64_LOCAL_MASK)	\
+			    >> STO_PPC64_LOCAL_BIT)
+/* number of bytes to st_other.  */
+#define PPC64_SET_LOCAL_ENTRY_OFFSET(val)		\
+  ppc64_encode_local_entry (val) << STO_PPC64_LOCAL_BIT
+
 /* Specify the start of the .glink section.  */
 #define DT_PPC64_GLINK		DT_LOPROC
 
