From 6e0665a33c841cb72f25624655a40e62747390ed Mon Sep 17 00:00:00 2001 From: Jan Kratochvil Date: Fri, 9 May 2014 21:30:33 +0200 Subject: [PATCH] [ppc*] Import ppc64le support (BZ 1096303, Ulrich Weigand). --- gdb-rhbz795424-bitpos-23of25.patch | 256 +++-- gdb-upstream-ppc64le02of15.patch | 61 ++ gdb-upstream-ppc64le03of15.patch | 36 + gdb-upstream-ppc64le04of15.patch | 1413 ++++++++++++++++++++++++++++ gdb-upstream-ppc64le05of15.patch | 44 + gdb-upstream-ppc64le06of15.patch | 67 ++ gdb-upstream-ppc64le07of15.patch | 149 +++ gdb-upstream-ppc64le08of15.patch | 57 ++ gdb-upstream-ppc64le09of15.patch | 140 +++ gdb-upstream-ppc64le10of15.patch | 159 ++++ gdb-upstream-ppc64le11of15.patch | 132 +++ gdb-upstream-ppc64le12of15.patch | 48 + gdb-upstream-ppc64le13of15.patch | 309 ++++++ gdb-upstream-ppc64le14of15.patch | 375 ++++++++ gdb-upstream-ppc64le15of15.patch | 90 ++ gdb.spec | 47 +- 16 files changed, 3244 insertions(+), 139 deletions(-) create mode 100644 gdb-upstream-ppc64le02of15.patch create mode 100644 gdb-upstream-ppc64le03of15.patch create mode 100644 gdb-upstream-ppc64le04of15.patch create mode 100644 gdb-upstream-ppc64le05of15.patch create mode 100644 gdb-upstream-ppc64le06of15.patch create mode 100644 gdb-upstream-ppc64le07of15.patch create mode 100644 gdb-upstream-ppc64le08of15.patch create mode 100644 gdb-upstream-ppc64le09of15.patch create mode 100644 gdb-upstream-ppc64le10of15.patch create mode 100644 gdb-upstream-ppc64le11of15.patch create mode 100644 gdb-upstream-ppc64le12of15.patch create mode 100644 gdb-upstream-ppc64le13of15.patch create mode 100644 gdb-upstream-ppc64le14of15.patch create mode 100644 gdb-upstream-ppc64le15of15.patch diff --git a/gdb-rhbz795424-bitpos-23of25.patch b/gdb-rhbz795424-bitpos-23of25.patch index 0f829a7..e0e13b5 100644 --- a/gdb-rhbz795424-bitpos-23of25.patch +++ b/gdb-rhbz795424-bitpos-23of25.patch @@ -137,10 +137,10 @@ Content-Type: text/x-patch Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename=bitpos-tdep.patch -Index: gdb-7.6.90.20140127/gdb/alpha-tdep.c +Index: gdb-7.7.1/gdb/alpha-tdep.c =================================================================== ---- gdb-7.6.90.20140127.orig/gdb/alpha-tdep.c 2014-02-06 18:20:52.970747716 +0100 -+++ gdb-7.6.90.20140127/gdb/alpha-tdep.c 2014-02-06 18:20:57.294752362 +0100 +--- gdb-7.7.1.orig/gdb/alpha-tdep.c 2014-05-09 19:24:18.677252769 +0200 ++++ gdb-7.7.1/gdb/alpha-tdep.c 2014-05-09 20:02:09.620703767 +0200 @@ -299,18 +299,18 @@ alpha_push_dummy_call (struct gdbarch *g { enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); @@ -184,10 +184,10 @@ Index: gdb-7.6.90.20140127/gdb/alpha-tdep.c memcpy (arg_reg_buffer + offset, contents, tlen); offset += tlen; contents += tlen; -Index: gdb-7.6.90.20140127/gdb/amd64-tdep.c +Index: gdb-7.7.1/gdb/amd64-tdep.c =================================================================== ---- gdb-7.6.90.20140127.orig/gdb/amd64-tdep.c 2014-02-06 18:20:52.972747718 +0100 -+++ gdb-7.6.90.20140127/gdb/amd64-tdep.c 2014-02-06 18:21:51.106810814 +0100 +--- gdb-7.7.1.orig/gdb/amd64-tdep.c 2014-05-09 19:24:18.678252770 +0200 ++++ gdb-7.7.1/gdb/amd64-tdep.c 2014-05-09 20:02:09.620703767 +0200 @@ -633,7 +633,7 @@ amd64_return_value (struct gdbarch *gdba gdb_byte *readbuf, const gdb_byte *writebuf) { @@ -217,10 +217,10 @@ Index: gdb-7.6.90.20140127/gdb/amd64-tdep.c enum amd64_reg_class class[2]; int needed_integer_regs = 0; int needed_sse_regs = 0; -Index: gdb-7.6.90.20140127/gdb/amd64-windows-tdep.c +Index: gdb-7.7.1/gdb/amd64-windows-tdep.c =================================================================== ---- gdb-7.6.90.20140127.orig/gdb/amd64-windows-tdep.c 2014-02-06 18:20:52.973747720 +0100 -+++ gdb-7.6.90.20140127/gdb/amd64-windows-tdep.c 2014-02-06 18:20:57.296752364 +0100 +--- gdb-7.7.1.orig/gdb/amd64-windows-tdep.c 2014-05-09 19:24:18.679252770 +0200 ++++ gdb-7.7.1/gdb/amd64-windows-tdep.c 2014-05-09 20:02:09.620703767 +0200 @@ -288,7 +288,7 @@ amd64_windows_return_value (struct gdbar struct type *type, struct regcache *regcache, gdb_byte *readbuf, const gdb_byte *writebuf) @@ -230,10 +230,10 @@ Index: gdb-7.6.90.20140127/gdb/amd64-windows-tdep.c int regnum = -1; /* See if our value is returned through a register. If it is, then -Index: gdb-7.6.90.20140127/gdb/arm-tdep.c +Index: gdb-7.7.1/gdb/arm-tdep.c =================================================================== ---- gdb-7.6.90.20140127.orig/gdb/arm-tdep.c 2014-02-06 18:20:52.978747725 +0100 -+++ gdb-7.6.90.20140127/gdb/arm-tdep.c 2014-02-06 18:20:57.299752367 +0100 +--- gdb-7.7.1.orig/gdb/arm-tdep.c 2014-05-09 19:24:18.684252770 +0200 ++++ gdb-7.7.1/gdb/arm-tdep.c 2014-05-09 20:02:09.622703768 +0200 @@ -3498,7 +3498,7 @@ arm_vfp_cprc_reg_char (enum arm_vfp_cprc array). Vectors and complex types are not currently supported, matching the generic AAPCS support. */ @@ -308,10 +308,10 @@ Index: gdb-7.6.90.20140127/gdb/arm-tdep.c struct type *arg_type; struct type *target_type; enum type_code typecode; -Index: gdb-7.6.90.20140127/gdb/avr-tdep.c +Index: gdb-7.7.1/gdb/avr-tdep.c =================================================================== ---- gdb-7.6.90.20140127.orig/gdb/avr-tdep.c 2014-02-06 18:20:52.980747727 +0100 -+++ gdb-7.6.90.20140127/gdb/avr-tdep.c 2014-02-06 18:20:57.299752367 +0100 +--- gdb-7.7.1.orig/gdb/avr-tdep.c 2014-05-09 19:24:18.686252771 +0200 ++++ gdb-7.7.1/gdb/avr-tdep.c 2014-05-09 20:02:09.623703768 +0200 @@ -1167,13 +1167,14 @@ avr_dummy_id (struct gdbarch *gdbarch, s struct stack_item @@ -345,10 +345,10 @@ Index: gdb-7.6.90.20140127/gdb/avr-tdep.c /* Calculate the potential last register needed. */ last_regnum = regnum - (len + (len & 1)); -Index: gdb-7.6.90.20140127/gdb/bfin-tdep.c +Index: gdb-7.7.1/gdb/bfin-tdep.c =================================================================== ---- gdb-7.6.90.20140127.orig/gdb/bfin-tdep.c 2014-02-06 18:20:52.980747727 +0100 -+++ gdb-7.6.90.20140127/gdb/bfin-tdep.c 2014-02-06 18:20:57.300752368 +0100 +--- gdb-7.7.1.orig/gdb/bfin-tdep.c 2014-05-09 19:24:18.686252771 +0200 ++++ gdb-7.7.1/gdb/bfin-tdep.c 2014-05-09 20:02:09.623703768 +0200 @@ -506,7 +506,7 @@ bfin_push_dummy_call (struct gdbarch *gd gdb_byte buf[4]; int i; @@ -367,10 +367,10 @@ Index: gdb-7.6.90.20140127/gdb/bfin-tdep.c sp -= container_len; write_memory (sp, value_contents_writeable (args[i]), container_len); -Index: gdb-7.6.90.20140127/gdb/cris-tdep.c +Index: gdb-7.7.1/gdb/cris-tdep.c =================================================================== ---- gdb-7.6.90.20140127.orig/gdb/cris-tdep.c 2014-02-06 18:20:52.981747728 +0100 -+++ gdb-7.6.90.20140127/gdb/cris-tdep.c 2014-02-06 18:20:57.301752369 +0100 +--- gdb-7.7.1.orig/gdb/cris-tdep.c 2014-05-09 19:24:18.687252771 +0200 ++++ gdb-7.7.1/gdb/cris-tdep.c 2014-05-09 20:02:09.623703768 +0200 @@ -665,13 +665,13 @@ static CORE_ADDR cris_unwind_sp (struct struct stack_item @@ -405,10 +405,10 @@ Index: gdb-7.6.90.20140127/gdb/cris-tdep.c /* How may registers worth of storage do we need for this argument? */ reg_demand = (len / 4) + (len % 4 != 0 ? 1 : 0); -Index: gdb-7.6.90.20140127/gdb/h8300-tdep.c +Index: gdb-7.7.1/gdb/h8300-tdep.c =================================================================== ---- gdb-7.6.90.20140127.orig/gdb/h8300-tdep.c 2014-02-06 18:20:52.981747728 +0100 -+++ gdb-7.6.90.20140127/gdb/h8300-tdep.c 2014-02-06 18:20:57.301752369 +0100 +--- gdb-7.7.1.orig/gdb/h8300-tdep.c 2014-05-09 19:24:18.688252771 +0200 ++++ gdb-7.7.1/gdb/h8300-tdep.c 2014-05-09 20:02:09.624703768 +0200 @@ -640,7 +640,7 @@ h8300_push_dummy_call (struct gdbarch *g int struct_return, CORE_ADDR struct_addr) { @@ -441,10 +441,10 @@ Index: gdb-7.6.90.20140127/gdb/h8300-tdep.c for (offset = 0; offset < padded_len; offset += wordsize) { -Index: gdb-7.6.90.20140127/gdb/hppa-tdep.c +Index: gdb-7.7.1/gdb/hppa-tdep.c =================================================================== ---- gdb-7.6.90.20140127.orig/gdb/hppa-tdep.c 2014-02-06 18:20:52.982747729 +0100 -+++ gdb-7.6.90.20140127/gdb/hppa-tdep.c 2014-02-06 18:20:57.302752371 +0100 +--- gdb-7.7.1.orig/gdb/hppa-tdep.c 2014-05-09 19:24:18.690252771 +0200 ++++ gdb-7.7.1/gdb/hppa-tdep.c 2014-05-09 20:02:09.624703768 +0200 @@ -961,7 +961,7 @@ hppa64_push_dummy_call (struct gdbarch * { struct value *arg = args[i]; @@ -463,10 +463,10 @@ Index: gdb-7.6.90.20140127/gdb/hppa-tdep.c int regnum, offset; if (len > 16) -Index: gdb-7.6.90.20140127/gdb/i386-darwin-tdep.c +Index: gdb-7.7.1/gdb/i386-darwin-tdep.c =================================================================== ---- gdb-7.6.90.20140127.orig/gdb/i386-darwin-tdep.c 2014-02-06 18:20:52.982747729 +0100 -+++ gdb-7.6.90.20140127/gdb/i386-darwin-tdep.c 2014-02-06 18:20:57.302752371 +0100 +--- gdb-7.7.1.orig/gdb/i386-darwin-tdep.c 2014-05-09 19:24:18.690252771 +0200 ++++ gdb-7.7.1/gdb/i386-darwin-tdep.c 2014-05-09 20:02:09.624703768 +0200 @@ -164,7 +164,7 @@ i386_darwin_push_dummy_call (struct gdba for (write_pass = 0; write_pass < 2; write_pass++) @@ -476,10 +476,10 @@ Index: gdb-7.6.90.20140127/gdb/i386-darwin-tdep.c int num_m128 = 0; if (struct_return) -Index: gdb-7.6.90.20140127/gdb/i386-tdep.c +Index: gdb-7.7.1/gdb/i386-tdep.c =================================================================== ---- gdb-7.6.90.20140127.orig/gdb/i386-tdep.c 2014-02-06 18:20:52.985747732 +0100 -+++ gdb-7.6.90.20140127/gdb/i386-tdep.c 2014-02-06 18:20:57.303752372 +0100 +--- gdb-7.7.1.orig/gdb/i386-tdep.c 2014-05-09 19:24:18.692252771 +0200 ++++ gdb-7.7.1/gdb/i386-tdep.c 2014-05-09 20:02:09.625703769 +0200 @@ -2473,7 +2473,7 @@ i386_push_dummy_call (struct gdbarch *gd gdb_byte buf[4]; int i; @@ -543,10 +543,10 @@ Index: gdb-7.6.90.20140127/gdb/i386-tdep.c if (i386_fp_regnum_p (get_frame_arch (frame), regnum)) { -Index: gdb-7.6.90.20140127/gdb/ia64-tdep.c +Index: gdb-7.7.1/gdb/ia64-tdep.c =================================================================== ---- gdb-7.6.90.20140127.orig/gdb/ia64-tdep.c 2014-02-06 18:20:52.986747733 +0100 -+++ gdb-7.6.90.20140127/gdb/ia64-tdep.c 2014-02-06 18:20:57.304752373 +0100 +--- gdb-7.7.1.orig/gdb/ia64-tdep.c 2014-05-09 19:24:18.693252771 +0200 ++++ gdb-7.7.1/gdb/ia64-tdep.c 2014-05-09 20:02:09.626703769 +0200 @@ -3851,8 +3851,10 @@ ia64_push_dummy_call (struct gdbarch *gd int argno; struct value *arg; @@ -560,10 +560,10 @@ Index: gdb-7.6.90.20140127/gdb/ia64-tdep.c int floatreg; ULONGEST bsp; CORE_ADDR funcdescaddr, pc, global_pointer; -Index: gdb-7.6.90.20140127/gdb/iq2000-tdep.c +Index: gdb-7.7.1/gdb/iq2000-tdep.c =================================================================== ---- gdb-7.6.90.20140127.orig/gdb/iq2000-tdep.c 2014-02-06 18:20:52.986747733 +0100 -+++ gdb-7.6.90.20140127/gdb/iq2000-tdep.c 2014-02-06 18:20:57.304752373 +0100 +--- gdb-7.7.1.orig/gdb/iq2000-tdep.c 2014-05-09 19:24:18.693252771 +0200 ++++ gdb-7.7.1/gdb/iq2000-tdep.c 2014-05-09 20:02:09.626703769 +0200 @@ -654,8 +654,9 @@ iq2000_push_dummy_call (struct gdbarch * const bfd_byte *val; bfd_byte buf[4]; @@ -576,10 +576,10 @@ Index: gdb-7.6.90.20140127/gdb/iq2000-tdep.c /* Used to copy struct arguments into the stack. */ CORE_ADDR struct_ptr; -Index: gdb-7.6.90.20140127/gdb/m32r-tdep.c +Index: gdb-7.7.1/gdb/m32r-tdep.c =================================================================== ---- gdb-7.6.90.20140127.orig/gdb/m32r-tdep.c 2014-02-06 18:20:52.986747733 +0100 -+++ gdb-7.6.90.20140127/gdb/m32r-tdep.c 2014-02-06 18:20:57.304752373 +0100 +--- gdb-7.7.1.orig/gdb/m32r-tdep.c 2014-05-09 19:24:18.693252771 +0200 ++++ gdb-7.7.1/gdb/m32r-tdep.c 2014-05-09 20:02:09.626703769 +0200 @@ -689,7 +689,7 @@ m32r_push_dummy_call (struct gdbarch *gd CORE_ADDR regval; gdb_byte *val; @@ -589,10 +589,10 @@ Index: gdb-7.6.90.20140127/gdb/m32r-tdep.c /* First force sp to a 4-byte alignment. */ sp = sp & ~3; -Index: gdb-7.6.90.20140127/gdb/m68k-tdep.c +Index: gdb-7.7.1/gdb/m68k-tdep.c =================================================================== ---- gdb-7.6.90.20140127.orig/gdb/m68k-tdep.c 2014-02-06 18:20:52.987747735 +0100 -+++ gdb-7.6.90.20140127/gdb/m68k-tdep.c 2014-02-06 18:20:57.305752374 +0100 +--- gdb-7.7.1.orig/gdb/m68k-tdep.c 2014-05-09 19:24:18.694252771 +0200 ++++ gdb-7.7.1/gdb/m68k-tdep.c 2014-05-09 20:02:09.627703769 +0200 @@ -384,7 +384,7 @@ m68k_reg_struct_return_p (struct gdbarch { struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); @@ -615,10 +615,10 @@ Index: gdb-7.6.90.20140127/gdb/m68k-tdep.c /* Non-scalars bigger than 4 bytes are left aligned, others are right aligned. */ -Index: gdb-7.6.90.20140127/gdb/m88k-tdep.c +Index: gdb-7.7.1/gdb/m88k-tdep.c =================================================================== ---- gdb-7.6.90.20140127.orig/gdb/m88k-tdep.c 2014-02-06 18:20:52.987747735 +0100 -+++ gdb-7.6.90.20140127/gdb/m88k-tdep.c 2014-02-06 18:20:57.305752374 +0100 +--- gdb-7.7.1.orig/gdb/m88k-tdep.c 2014-05-09 19:24:18.694252771 +0200 ++++ gdb-7.7.1/gdb/m88k-tdep.c 2014-05-09 20:02:09.627703769 +0200 @@ -260,13 +260,13 @@ m88k_store_arguments (struct regcache *r { struct gdbarch *gdbarch = get_regcache_arch (regcache); @@ -646,10 +646,10 @@ Index: gdb-7.6.90.20140127/gdb/m88k-tdep.c if (m88k_in_register_p (type)) { -Index: gdb-7.6.90.20140127/gdb/mep-tdep.c +Index: gdb-7.7.1/gdb/mep-tdep.c =================================================================== ---- gdb-7.6.90.20140127.orig/gdb/mep-tdep.c 2014-02-06 18:20:52.987747735 +0100 -+++ gdb-7.6.90.20140127/gdb/mep-tdep.c 2014-02-06 18:20:57.306752375 +0100 +--- gdb-7.7.1.orig/gdb/mep-tdep.c 2014-05-09 19:24:18.695252772 +0200 ++++ gdb-7.7.1/gdb/mep-tdep.c 2014-05-09 20:02:09.627703769 +0200 @@ -2272,7 +2272,7 @@ push_large_arguments (CORE_ADDR sp, int for (i = 0; i < argc; i++) @@ -659,10 +659,10 @@ Index: gdb-7.6.90.20140127/gdb/mep-tdep.c if (arg_len > MEP_GPR_SIZE) { -Index: gdb-7.6.90.20140127/gdb/mips-tdep.c +Index: gdb-7.7.1/gdb/mips-tdep.c =================================================================== ---- gdb-7.6.90.20140127.orig/gdb/mips-tdep.c 2014-02-06 18:20:52.990747738 +0100 -+++ gdb-7.6.90.20140127/gdb/mips-tdep.c 2014-02-06 18:20:57.307752376 +0100 +--- gdb-7.7.1.orig/gdb/mips-tdep.c 2014-05-09 19:24:18.698252772 +0200 ++++ gdb-7.7.1/gdb/mips-tdep.c 2014-05-09 20:02:09.628703769 +0200 @@ -402,7 +402,7 @@ static void mips_xfer_register (struct gdbarch *gdbarch, struct regcache *regcache, int reg_num, int length, @@ -808,10 +808,10 @@ Index: gdb-7.6.90.20140127/gdb/mips-tdep.c val = value_contents (arg); -Index: gdb-7.6.90.20140127/gdb/mn10300-tdep.c +Index: gdb-7.7.1/gdb/mn10300-tdep.c =================================================================== ---- gdb-7.6.90.20140127.orig/gdb/mn10300-tdep.c 2014-02-06 18:20:52.991747739 +0100 -+++ gdb-7.6.90.20140127/gdb/mn10300-tdep.c 2014-02-06 18:20:57.308752377 +0100 +--- gdb-7.7.1.orig/gdb/mn10300-tdep.c 2014-05-09 19:24:18.698252772 +0200 ++++ gdb-7.7.1/gdb/mn10300-tdep.c 2014-05-09 20:02:09.629703770 +0200 @@ -1227,7 +1227,7 @@ mn10300_push_dummy_call (struct gdbarch enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); const int push_size = register_size (gdbarch, E_PC_REGNUM); @@ -821,10 +821,10 @@ Index: gdb-7.6.90.20140127/gdb/mn10300-tdep.c int stack_offset = 0; int argnum; const gdb_byte *val; -Index: gdb-7.6.90.20140127/gdb/mt-tdep.c +Index: gdb-7.7.1/gdb/mt-tdep.c =================================================================== ---- gdb-7.6.90.20140127.orig/gdb/mt-tdep.c 2014-02-06 18:20:52.991747739 +0100 -+++ gdb-7.6.90.20140127/gdb/mt-tdep.c 2014-02-06 18:20:57.308752377 +0100 +--- gdb-7.7.1.orig/gdb/mt-tdep.c 2014-05-09 19:24:18.699252772 +0200 ++++ gdb-7.7.1/gdb/mt-tdep.c 2014-05-09 20:02:09.629703770 +0200 @@ -783,9 +783,9 @@ mt_push_dummy_call (struct gdbarch *gdba gdb_byte buf[MT_MAX_STRUCT_SIZE]; int argreg = MT_1ST_ARGREG; @@ -837,10 +837,10 @@ Index: gdb-7.6.90.20140127/gdb/mt-tdep.c int i, j; /* First handle however many args we can fit into MT_1ST_ARGREG thru -Index: gdb-7.6.90.20140127/gdb/ppc-sysv-tdep.c +Index: gdb-7.7.1/gdb/ppc-sysv-tdep.c =================================================================== ---- gdb-7.6.90.20140127.orig/gdb/ppc-sysv-tdep.c 2014-02-06 18:20:52.992747740 +0100 -+++ gdb-7.6.90.20140127/gdb/ppc-sysv-tdep.c 2014-02-06 18:20:57.308752377 +0100 +--- gdb-7.7.1.orig/gdb/ppc-sysv-tdep.c 2014-05-09 19:24:18.699252772 +0200 ++++ gdb-7.7.1/gdb/ppc-sysv-tdep.c 2014-05-09 20:10:13.994807709 +0200 @@ -68,7 +68,7 @@ ppc_sysv_abi_push_dummy_call (struct gdb enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); int opencl_abi = ppc_sysv_use_opencl_abi (value_type (function)); @@ -871,36 +871,24 @@ Index: gdb-7.6.90.20140127/gdb/ppc-sysv-tdep.c const bfd_byte *val = value_contents (arg); if (TYPE_CODE (type) == TYPE_CODE_FLT && len <= 8 -@@ -1613,14 +1613,14 @@ ppc64_sysv_abi_push_dummy_call (struct g - } - else - { -- int byte; -+ ssize_t 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; -+ ssize_t len = TYPE_LENGTH (type) - byte; - if (len > tdep->wordsize) - len = tdep->wordsize; - memset (regval, 0, sizeof regval); -@@ -1648,7 +1648,7 @@ ppc64_sysv_abi_push_dummy_call (struct g - register. Work around this by always writing the - value to memory. Fortunately, doing this - simplifies the code. */ -- int len = TYPE_LENGTH (type); -+ ssize_t len = TYPE_LENGTH (type); - if (len < tdep->wordsize) - write_memory (gparam + tdep->wordsize - len, val, len); - else -Index: gdb-7.6.90.20140127/gdb/rl78-tdep.c +@@ -1285,11 +1285,11 @@ struct ppc64_sysv_argpos + + static void + ppc64_sysv_abi_push_val (struct gdbarch *gdbarch, +- const bfd_byte *val, int len, int align, ++ const bfd_byte *val, ssize_t len, int align, + struct ppc64_sysv_argpos *argpos) + { + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); +- int offset = 0; ++ ssize_t offset = 0; + + /* Enforce alignment of stack location, if requested. */ + if (align > tdep->wordsize) +Index: gdb-7.7.1/gdb/rl78-tdep.c =================================================================== ---- gdb-7.6.90.20140127.orig/gdb/rl78-tdep.c 2014-02-06 18:20:52.992747740 +0100 -+++ gdb-7.6.90.20140127/gdb/rl78-tdep.c 2014-02-06 18:20:57.309752378 +0100 +--- gdb-7.7.1.orig/gdb/rl78-tdep.c 2014-05-09 19:24:18.700252772 +0200 ++++ gdb-7.7.1/gdb/rl78-tdep.c 2014-05-09 20:02:09.630703770 +0200 @@ -1052,8 +1052,8 @@ rl78_push_dummy_call (struct gdbarch *gd for (i = nargs - 1; i >= 0; i--) { @@ -912,10 +900,10 @@ Index: gdb-7.6.90.20140127/gdb/rl78-tdep.c sp -= container_len; write_memory (rl78_make_data_address (sp), -Index: gdb-7.6.90.20140127/gdb/rs6000-aix-tdep.c +Index: gdb-7.7.1/gdb/rs6000-aix-tdep.c =================================================================== ---- gdb-7.6.90.20140127.orig/gdb/rs6000-aix-tdep.c 2014-02-06 18:20:52.993747741 +0100 -+++ gdb-7.6.90.20140127/gdb/rs6000-aix-tdep.c 2014-02-06 18:20:57.309752378 +0100 +--- gdb-7.7.1.orig/gdb/rs6000-aix-tdep.c 2014-05-09 19:24:18.700252772 +0200 ++++ gdb-7.7.1/gdb/rs6000-aix-tdep.c 2014-05-09 20:02:09.630703770 +0200 @@ -196,9 +196,9 @@ rs6000_push_dummy_call (struct gdbarch * struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); @@ -937,10 +925,10 @@ Index: gdb-7.6.90.20140127/gdb/rs6000-aix-tdep.c if (argbytes) { -Index: gdb-7.6.90.20140127/gdb/s390-linux-tdep.c +Index: gdb-7.7.1/gdb/s390-linux-tdep.c =================================================================== ---- gdb-7.6.90.20140127.orig/gdb/s390-linux-tdep.c 2014-02-06 18:20:52.993747741 +0100 -+++ gdb-7.6.90.20140127/gdb/s390-linux-tdep.c 2014-02-06 18:22:17.330838389 +0100 +--- gdb-7.7.1.orig/gdb/s390-linux-tdep.c 2014-05-09 19:24:18.701252772 +0200 ++++ gdb-7.7.1/gdb/s390-linux-tdep.c 2014-05-09 20:02:09.631703770 +0200 @@ -2526,7 +2526,7 @@ is_float_like (struct type *type) @@ -959,10 +947,10 @@ Index: gdb-7.6.90.20140127/gdb/s390-linux-tdep.c if (s390_function_arg_pass_by_reference (type)) { -Index: gdb-7.6.90.20140127/gdb/score-tdep.c +Index: gdb-7.7.1/gdb/score-tdep.c =================================================================== ---- gdb-7.6.90.20140127.orig/gdb/score-tdep.c 2014-02-06 18:20:52.994747742 +0100 -+++ gdb-7.6.90.20140127/gdb/score-tdep.c 2014-02-06 18:20:57.310752379 +0100 +--- gdb-7.7.1.orig/gdb/score-tdep.c 2014-05-09 19:24:18.701252772 +0200 ++++ gdb-7.7.1/gdb/score-tdep.c 2014-05-09 20:02:09.631703770 +0200 @@ -515,7 +515,7 @@ score_push_dummy_call (struct gdbarch *g enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); int argnum; @@ -972,10 +960,10 @@ Index: gdb-7.6.90.20140127/gdb/score-tdep.c CORE_ADDR stack_offset = 0; CORE_ADDR addr = 0; -Index: gdb-7.6.90.20140127/gdb/sh-tdep.c +Index: gdb-7.7.1/gdb/sh-tdep.c =================================================================== ---- gdb-7.6.90.20140127.orig/gdb/sh-tdep.c 2014-02-06 18:20:52.995747743 +0100 -+++ gdb-7.6.90.20140127/gdb/sh-tdep.c 2014-02-06 18:20:57.310752379 +0100 +--- gdb-7.7.1.orig/gdb/sh-tdep.c 2014-05-09 19:24:18.702252772 +0200 ++++ gdb-7.7.1/gdb/sh-tdep.c 2014-05-09 20:02:09.631703770 +0200 @@ -807,7 +807,7 @@ sh_skip_prologue (struct gdbarch *gdbarc static int sh_use_struct_convention (int renesas_abi, struct type *type) @@ -1014,10 +1002,10 @@ Index: gdb-7.6.90.20140127/gdb/sh-tdep.c int pass_on_stack = 0; int last_reg_arg = INT_MAX; -Index: gdb-7.6.90.20140127/gdb/sh64-tdep.c +Index: gdb-7.7.1/gdb/sh64-tdep.c =================================================================== ---- gdb-7.6.90.20140127.orig/gdb/sh64-tdep.c 2014-02-06 18:20:52.995747743 +0100 -+++ gdb-7.6.90.20140127/gdb/sh64-tdep.c 2014-02-06 18:20:57.311752380 +0100 +--- gdb-7.7.1.orig/gdb/sh64-tdep.c 2014-05-09 19:24:18.702252772 +0200 ++++ gdb-7.7.1/gdb/sh64-tdep.c 2014-05-09 20:02:09.632703771 +0200 @@ -1058,7 +1058,7 @@ sh64_push_dummy_call (struct gdbarch *gd CORE_ADDR struct_addr) { @@ -1036,10 +1024,10 @@ Index: gdb-7.6.90.20140127/gdb/sh64-tdep.c int argreg_size; int fp_args[12]; -Index: gdb-7.6.90.20140127/gdb/sparc-tdep.c +Index: gdb-7.7.1/gdb/sparc-tdep.c =================================================================== ---- gdb-7.6.90.20140127.orig/gdb/sparc-tdep.c 2014-02-06 18:20:52.996747744 +0100 -+++ gdb-7.6.90.20140127/gdb/sparc-tdep.c 2014-02-06 18:20:57.311752380 +0100 +--- gdb-7.7.1.orig/gdb/sparc-tdep.c 2014-05-09 19:24:18.703252772 +0200 ++++ gdb-7.7.1/gdb/sparc-tdep.c 2014-05-09 20:02:09.632703771 +0200 @@ -502,7 +502,7 @@ sparc32_store_arguments (struct regcache for (i = 0; i < nargs; i++) { @@ -1049,10 +1037,10 @@ Index: gdb-7.6.90.20140127/gdb/sparc-tdep.c if (sparc_structure_or_union_p (type) || (sparc_floating_p (type) && len == 16) -Index: gdb-7.6.90.20140127/gdb/sparc64-tdep.c +Index: gdb-7.7.1/gdb/sparc64-tdep.c =================================================================== ---- gdb-7.6.90.20140127.orig/gdb/sparc64-tdep.c 2014-02-06 18:20:52.996747744 +0100 -+++ gdb-7.6.90.20140127/gdb/sparc64-tdep.c 2014-02-06 18:20:57.311752380 +0100 +--- gdb-7.7.1.orig/gdb/sparc64-tdep.c 2014-05-09 19:24:18.704252773 +0200 ++++ gdb-7.7.1/gdb/sparc64-tdep.c 2014-05-09 20:02:09.632703771 +0200 @@ -639,7 +639,8 @@ sparc64_16_byte_align_p (struct type *ty static void @@ -1108,10 +1096,10 @@ Index: gdb-7.6.90.20140127/gdb/sparc64-tdep.c int regnum = -1; gdb_byte buf[16]; -Index: gdb-7.6.90.20140127/gdb/spu-tdep.c +Index: gdb-7.7.1/gdb/spu-tdep.c =================================================================== ---- gdb-7.6.90.20140127.orig/gdb/spu-tdep.c 2014-02-06 18:20:52.997747745 +0100 -+++ gdb-7.6.90.20140127/gdb/spu-tdep.c 2014-02-06 18:20:57.312752381 +0100 +--- gdb-7.7.1.orig/gdb/spu-tdep.c 2014-05-09 19:24:18.704252773 +0200 ++++ gdb-7.7.1/gdb/spu-tdep.c 2014-05-09 20:02:09.633703771 +0200 @@ -1376,7 +1376,7 @@ spu_push_dummy_call (struct gdbarch *gdb struct value *arg = args[i]; struct type *type = check_typedef (value_type (arg)); @@ -1130,10 +1118,10 @@ Index: gdb-7.6.90.20140127/gdb/spu-tdep.c int preferred_slot; if (spu_scalar_value_p (type)) -Index: gdb-7.6.90.20140127/gdb/tic6x-tdep.c +Index: gdb-7.7.1/gdb/tic6x-tdep.c =================================================================== ---- gdb-7.6.90.20140127.orig/gdb/tic6x-tdep.c 2014-02-06 18:20:52.997747745 +0100 -+++ gdb-7.6.90.20140127/gdb/tic6x-tdep.c 2014-02-06 18:20:57.312752381 +0100 +--- gdb-7.7.1.orig/gdb/tic6x-tdep.c 2014-05-09 19:24:18.705252773 +0200 ++++ gdb-7.7.1/gdb/tic6x-tdep.c 2014-05-09 20:02:09.633703771 +0200 @@ -896,7 +896,7 @@ tic6x_push_dummy_call (struct gdbarch *g int argreg = 0; int argnum; @@ -1171,10 +1159,10 @@ Index: gdb-7.6.90.20140127/gdb/tic6x-tdep.c addr = sp + stack_offset; write_memory (addr, val, len); -Index: gdb-7.6.90.20140127/gdb/tilegx-tdep.c +Index: gdb-7.7.1/gdb/tilegx-tdep.c =================================================================== ---- gdb-7.6.90.20140127.orig/gdb/tilegx-tdep.c 2014-02-06 18:20:52.998747746 +0100 -+++ gdb-7.6.90.20140127/gdb/tilegx-tdep.c 2014-02-06 18:20:57.312752381 +0100 +--- gdb-7.7.1.orig/gdb/tilegx-tdep.c 2014-05-09 19:24:18.705252773 +0200 ++++ gdb-7.7.1/gdb/tilegx-tdep.c 2014-05-09 20:02:09.633703771 +0200 @@ -290,7 +290,7 @@ tilegx_push_dummy_call (struct gdbarch * CORE_ADDR stack_dest = sp; int argreg = TILEGX_R0_REGNUM; @@ -1184,10 +1172,10 @@ Index: gdb-7.6.90.20140127/gdb/tilegx-tdep.c static const gdb_byte four_zero_words[16] = { 0 }; /* If struct_return is 1, then the struct return address will -Index: gdb-7.6.90.20140127/gdb/v850-tdep.c +Index: gdb-7.7.1/gdb/v850-tdep.c =================================================================== ---- gdb-7.6.90.20140127.orig/gdb/v850-tdep.c 2014-02-06 18:20:52.998747746 +0100 -+++ gdb-7.6.90.20140127/gdb/v850-tdep.c 2014-02-06 18:20:57.313752383 +0100 +--- gdb-7.7.1.orig/gdb/v850-tdep.c 2014-05-09 19:24:18.705252773 +0200 ++++ gdb-7.7.1/gdb/v850-tdep.c 2014-05-09 20:02:09.634703771 +0200 @@ -1021,7 +1021,7 @@ v850_push_dummy_call (struct gdbarch *gd enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); int argreg; @@ -1206,10 +1194,10 @@ Index: gdb-7.6.90.20140127/gdb/v850-tdep.c gdb_byte *val; gdb_byte valbuf[v850_reg_size]; -Index: gdb-7.6.90.20140127/gdb/vax-tdep.c +Index: gdb-7.7.1/gdb/vax-tdep.c =================================================================== ---- gdb-7.6.90.20140127.orig/gdb/vax-tdep.c 2014-02-06 18:20:52.998747746 +0100 -+++ gdb-7.6.90.20140127/gdb/vax-tdep.c 2014-02-06 18:20:57.313752383 +0100 +--- gdb-7.7.1.orig/gdb/vax-tdep.c 2014-05-09 19:24:18.706252773 +0200 ++++ gdb-7.7.1/gdb/vax-tdep.c 2014-05-09 20:02:09.634703771 +0200 @@ -115,7 +115,7 @@ vax_store_arguments (struct regcache *re struct gdbarch *gdbarch = get_regcache_arch (regcache); enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); @@ -1228,10 +1216,10 @@ Index: gdb-7.6.90.20140127/gdb/vax-tdep.c sp -= (len + 3) & ~3; count += (len + 3) / 4; -Index: gdb-7.6.90.20140127/gdb/xstormy16-tdep.c +Index: gdb-7.7.1/gdb/xstormy16-tdep.c =================================================================== ---- gdb-7.6.90.20140127.orig/gdb/xstormy16-tdep.c 2014-02-06 18:20:52.999747748 +0100 -+++ gdb-7.6.90.20140127/gdb/xstormy16-tdep.c 2014-02-06 18:20:57.313752383 +0100 +--- gdb-7.7.1.orig/gdb/xstormy16-tdep.c 2014-05-09 19:24:18.706252773 +0200 ++++ gdb-7.7.1/gdb/xstormy16-tdep.c 2014-05-09 20:02:09.634703771 +0200 @@ -235,8 +235,9 @@ xstormy16_push_dummy_call (struct gdbarc enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); CORE_ADDR stack_dest = sp; @@ -1244,10 +1232,10 @@ Index: gdb-7.6.90.20140127/gdb/xstormy16-tdep.c const gdb_byte *val; gdb_byte buf[xstormy16_pc_size]; -Index: gdb-7.6.90.20140127/gdb/xtensa-tdep.c +Index: gdb-7.7.1/gdb/xtensa-tdep.c =================================================================== ---- gdb-7.6.90.20140127.orig/gdb/xtensa-tdep.c 2014-02-06 18:20:53.000747749 +0100 -+++ gdb-7.6.90.20140127/gdb/xtensa-tdep.c 2014-02-06 18:20:57.314752384 +0100 +--- gdb-7.7.1.orig/gdb/xtensa-tdep.c 2014-05-09 19:24:18.707252773 +0200 ++++ gdb-7.7.1/gdb/xtensa-tdep.c 2014-05-09 20:02:09.634703771 +0200 @@ -1652,8 +1652,7 @@ xtensa_store_return_value (struct type * if (len > (callsize > 8 ? 8 : 16)) diff --git a/gdb-upstream-ppc64le02of15.patch b/gdb-upstream-ppc64le02of15.patch new file mode 100644 index 0000000..202e3f5 --- /dev/null +++ b/gdb-upstream-ppc64le02of15.patch @@ -0,0 +1,61 @@ +commit 718ee4dc9b09491707420ae403ad1ce8dfdb61b2 +Author: Ulrich Weigand +Date: Thu Jan 30 19:12:35 2014 +0100 + + Add support for AT_HWCAP2 auxv entry + + Recent ppc64 Linux kernels provide a new auxv entry AT_HWCAP2, + which is currently not recognized by GDB, causing every use of + "info auxv" to show an error. + + This commit adds the AT_HWCAP2 define to include/elf/common.h + and handles it in GDB. + + include/elf/ChangeLog: + + * common.h (AT_HWCAP2): Define. + + gdb/ChangeLog: + + * auxv.c (fprint_target_auxv): Handle AT_HWCAP2. + +### a/gdb/ChangeLog +### b/gdb/ChangeLog +## -1,3 +1,7 @@ ++2014-01-30 Ulrich Weigand  ++ ++ * auxv.c (fprint_target_auxv): Handle AT_HWCAP2. ++ + 2014-01-29 Jose E. Marchesi + + * sparc64-linux-tdep.c (sparc64_linux_step_trap): Get PC from +--- a/gdb/auxv.c ++++ b/gdb/auxv.c +@@ -442,6 +442,7 @@ fprint_target_auxv (struct ui_file *file, struct target_ops *ops) + 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/include/elf/ChangeLog +### b/include/elf/ChangeLog +## -1,3 +1,7 @@ ++2014-01-30 Ulrich Weigand ++ ++ * common.h (AT_HWCAP2): Define. ++ + 2013-12-13 Kuan-Lin Chen + Wei-Cheng Wang + +--- a/include/elf/common.h ++++ b/include/elf/common.h +@@ -959,6 +959,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. */ diff --git a/gdb-upstream-ppc64le03of15.patch b/gdb-upstream-ppc64le03of15.patch new file mode 100644 index 0000000..30b4fcf --- /dev/null +++ b/gdb-upstream-ppc64le03of15.patch @@ -0,0 +1,36 @@ +commit 36c24d95382572e9cf4095712a8613664d7165cc +Author: Ulrich Weigand +Date: Tue Feb 4 18:19:51 2014 +0100 + + Document support for powerpc64le-*-linux* target + + gdb/ChangeLog: + + * NEWS: Document new target powerpc64le-*-linux*. + +### a/gdb/ChangeLog +### b/gdb/ChangeLog +## -1,3 +1,7 @@ ++2014-02-04 Ulrich Weigand  ++ ++ * NEWS: Document new target powerpc64le-*-linux*. ++ + 2014-02-04 Mark Kettenis + + * sparc64obsd-tdep.c (sparc64obsd_gregset): New variable. +Index: gdb-7.7.1/gdb/NEWS +=================================================================== +--- gdb-7.7.1.orig/gdb/NEWS 2014-05-09 19:21:57.798235002 +0200 ++++ gdb-7.7.1/gdb/NEWS 2014-05-09 19:22:30.206239145 +0200 +@@ -1,6 +1,11 @@ + What has changed in GDB? + (Organized release by release) + ++*** Changes since GDB 7.7 ++ ++* New targets ++PowerPC64 GNU/Linux little-endian powerpc64le-*-linux* ++ + *** Changes in GDB 7.7 + + * GDB now supports SystemTap SDT probes on AArch64 GNU/Linux. diff --git a/gdb-upstream-ppc64le04of15.patch b/gdb-upstream-ppc64le04of15.patch new file mode 100644 index 0000000..1b6730f --- /dev/null +++ b/gdb-upstream-ppc64le04of15.patch @@ -0,0 +1,1413 @@ +commit e765b44c3853ed228506fc22c276becd63198238 +Author: Ulrich Weigand +Date: Tue Feb 4 18:24:42 2014 +0100 + + Refactor ppc64 function call and return value handling + + This patch refactors the ppc64 function call and return value handling code + in ppc-sysv-tdep.c. The main problem to be addressed by this refactoring + is the code duplication caused by certain aggregate types: + + According to the ABI, some types are to be decomposed into component types + for parameter and return value handling. For example, complex types are + to be passed as if the real and imaginary component were separate arguments. + Similarly, certain OpenCL vector types are passed as if they were multiple + separate arguments of the vector element type. With the new ELFv2 ABI, + there is another case: "homogeneous aggregates" (e.g. a struct containing + 4 floats) are passed in multiple floating point registers as well. + + Unfortunately, the current code is not structured to easily model these + ABI properties. For example, code to pass complex values re-implements + code to pass the underlying (floating-point) type. This has already + led to some unfortunate code duplication, and with the addition of + ELFv2 ABI support, I would have had to add yet more such duplication. + + To avoid that, I've decided to refactor the code in order to re-use + subroutines that handle the "base" types when handling those aggregate + types. This was not intended to cause any difference on current + (ELFv1) ABI code, but in fact it fixes a bug: + + FAIL: gdb.base/varargs.exp: print find_max_float_real(4, fc1, fc2, fc3, fc4) + + This was caused by the old code in ppc64_sysv_abi_push_float incorrectly + handling floating-point arguments to vararg routines, which just happens + to work out correctly automatically in the refactored code ... + + gdb/ChangeLog: + + * 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. + +### a/gdb/ChangeLog +### b/gdb/ChangeLog +## -1,5 +1,19 @@ + 2014-02-04 Ulrich Weigand  + ++ * 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  ++ + * NEWS: Document new target powerpc64le-*-linux*. + + 2014-02-04 Mark Kettenis +--- a/gdb/ppc-sysv-tdep.c ++++ b/gdb/ppc-sysv-tdep.c +@@ -609,8 +609,7 @@ ppc_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, struct value *function, + 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,287 @@ convert_code_addr_to_desc_addr (CORE_ADDR code_addr, CORE_ADDR *desc_addr) + return 1; + } + +-/* Push a float in either registers, or in the stack. Using the ppc 64 bit +- SysV ABI. ++/* 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. */ + +- 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. */ ++static void ++ppc64_sysv_abi_push_val (struct gdbarch *gdbarch, ++ const bfd_byte *val, int len, int align, ++ struct ppc64_sysv_argpos *argpos) ++{ ++ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); ++ int offset = 0; ++ ++ /* Enforce alignment of stack location, if requested. */ ++ if (align > tdep->wordsize) ++ { ++ CORE_ADDR aligned_gparam = align_up (argpos->gparam, align); ++ ++ argpos->greg += (aligned_gparam - argpos->gparam) / tdep->wordsize; ++ argpos->gparam = aligned_gparam; ++ } ++ ++ /* 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 ++ . */ ++ if (len < tdep->wordsize) ++ offset = tdep->wordsize - len; ++ ++ if (argpos->regcache) ++ write_memory (argpos->gparam + offset, val, len); ++ argpos->gparam = align_up (argpos->gparam + len, tdep->wordsize); ++ ++ 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; ++ } ++ ++ 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_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_integer (struct gdbarch *gdbarch, ULONGEST val, ++ struct ppc64_sysv_argpos *argpos) + { +- gdb_byte regval[MAX_REGISTER_SIZE]; +- const gdb_byte *p; ++ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); ++ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); ++ gdb_byte buf[MAX_REGISTER_SIZE]; + +- if (TYPE_LENGTH (type) <= 8) ++ 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) + { +- /* Version 1.7 of the 64-bit PowerPC ELF ABI says: ++ /* Floats and doubles go in f1 .. f13. 32-bit floats are converted ++ to double first. */ ++ if (argpos->regcache && argpos->freg <= 13) ++ { ++ int regnum = tdep->ppc_fp0_regnum + argpos->freg; ++ struct type *regtype = register_type (gdbarch, regnum); ++ gdb_byte regval[MAX_REGISTER_SIZE]; + +- "Single precision floating point values are mapped to +- the first word in a single doubleword." ++ convert_typed_floating (val, type, regval, regtype); ++ regcache_cooked_write (argpos->regcache, regnum, regval); ++ } + +- And version 1.9 says: ++ 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 = 8 - TYPE_LENGTH (type); + +- "Single precision floating point values are mapped to +- the second word in a single doubleword." ++ regcache_cooked_write_part (argpos->regcache, regnum, ++ offset, TYPE_LENGTH (type), val); ++ } + +- GDB then writes single precision floating point values +- at both words in a doubleword, to support both ABIs. */ +- if (TYPE_LENGTH (type) == 4) ++ 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) + { +- memcpy (regval, val, 4); +- memcpy (regval + 4, val, 4); +- p = regval; ++ int regnum = tdep->ppc_fp0_regnum + argpos->freg; ++ ++ regcache_cooked_write (argpos->regcache, regnum, val); ++ if (argpos->freg <= 12) ++ regcache_cooked_write (argpos->regcache, regnum + 1, val + 8); + } +- else +- p = val; + +- /* Write value in the stack's parameter save area. */ +- write_memory (gparam, p, 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; + +- /* Floats and Doubles go in f1 .. f13. They also consume a left aligned +- GREG, and can end up in memory. */ +- if (freg <= 13) ++ if (argpos->regcache && argpos->freg <= 12) + { +- 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); ++ regcache_cooked_write (argpos->regcache, regnum + 1, val + 8); + } +- if (greg <= 10) +- regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + greg, regval); ++ ++ argpos->freg += 2; + } +- else ++} ++ ++/* 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) + { +- /* IBM long double stored in two doublewords of the +- parameter save area and corresponding registers. */ +- if (!tdep->soft_float && freg <= 13) ++ /* 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) + { +- 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); ++ /* Sign extend the value, then store it unsigned. */ ++ 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 ++ = 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) ++ ++ ppc64_sysv_abi_push_integer (gdbarch, word, argpos); ++ } ++ else ++ { ++ 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) + { +- 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); ++ 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); + } +- write_memory (gparam, val, TYPE_LENGTH (type)); + } + } + +@@ -1237,20 +1443,11 @@ ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, + 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 +1455,21 @@ ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, + 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); ++ 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, + compiler double word, LR save area, CR save area. */ +- sp = align_down (gparam - 48, 16); ++ sp = align_down (argpos.gparam - 48, 16); + } + + /* If the function is returning a `struct', then there is an +@@ -1279,14 +1478,7 @@ ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, + 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 +1486,54 @@ ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, + 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 (TYPE_CODE (type) == TYPE_CODE_COMPLEX) + { +- 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) +- { +- /* 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); +- } +- 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); ++ ppc64_sysv_abi_push_param (gdbarch, eltype, elval, &argpos); + } +- 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 +- . */ +- 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; + } + } + +@@ -1755,271 +1569,252 @@ ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, + return sp; + } + ++/* Subroutine of ppc64_sysv_abi_return_value that handles "base" types: ++ integer, floating-point, and AltiVec vector types. + +-/* The 64 bit ABI return value convention. +- +- Return non-zero if the return-value is stored in a register, return +- 0 if the return-value is instead stored on the stack (a.k.a., +- struct return convention). ++ This routine also handles components of aggregate return types; ++ INDEX describes which part of the aggregate is to be handled. + +- For a return-value stored in a register: when WRITEBUF is non-NULL, +- copy the buffer to the corresponding register return-value location +- location; when READBUF is non-NULL, fill the buffer from the +- corresponding register return-value location. */ +-enum return_value_convention +-ppc64_sysv_abi_return_value (struct gdbarch *gdbarch, struct value *function, +- struct type *valtype, struct regcache *regcache, +- gdb_byte *readbuf, const gdb_byte *writebuf) ++ 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); +- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); +- struct type *func_type = function ? value_type (function) : NULL; +- int opencl_abi = func_type? ppc_sysv_use_opencl_abi (func_type) : 0; + +- /* This function exists to support a calling convention that +- 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) +- { +- 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) +- { +- regcache_cooked_read (regcache, tdep->ppc_fp0_regnum + 1, regval); +- convert_typed_floating (regval, regtype, readbuf, valtype); +- } +- 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. */ ++ /* 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, tdep->ppc_gp0_regnum + 3, ++ regcache_cooked_write_unsigned (regcache, regnum, + unpack_long (valtype, writebuf)); + } + if (readbuf != NULL) + { +- /* Extract the integer from r3. Since this is truncating the ++ /* 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, tdep->ppc_gp0_regnum + 3, +- ®val); +- store_unsigned_integer (readbuf, TYPE_LENGTH (valtype), byte_order, +- regval); ++ ++ regcache_cooked_read_unsigned (regcache, regnum, ®val); ++ store_unsigned_integer (readbuf, TYPE_LENGTH (valtype), ++ gdbarch_byte_order (gdbarch), regval); + } +- return RETURN_VALUE_REGISTER_CONVENTION; ++ return 1; + } +- /* All pointers live in r3. */ +- if (TYPE_CODE (valtype) == TYPE_CODE_PTR +- || TYPE_CODE (valtype) == TYPE_CODE_REF) ++ ++ /* 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) + { +- /* All pointers live in r3. */ ++ int regnum = tdep->ppc_fp0_regnum + 1 + index; ++ struct type *regtype = register_type (gdbarch, regnum); ++ gdb_byte regval[MAX_REGISTER_SIZE]; ++ + if (writebuf != NULL) +- regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + 3, writebuf); ++ { ++ convert_typed_floating (writebuf, valtype, regval, regtype); ++ regcache_cooked_write (regcache, regnum, regval); ++ } + if (readbuf != NULL) +- regcache_cooked_read (regcache, tdep->ppc_gp0_regnum + 3, readbuf); +- return RETURN_VALUE_REGISTER_CONVENTION; ++ { ++ regcache_cooked_read (regcache, regnum, regval); ++ convert_typed_floating (regval, regtype, readbuf, valtype); ++ } ++ return 1; + } +- /* OpenCL vectors < 16 bytes are returned as distinct +- scalars in f1..f2 or r3..r10. */ +- if (TYPE_CODE (valtype) == TYPE_CODE_ARRAY +- && TYPE_VECTOR (valtype) +- && TYPE_LENGTH (valtype) < 16 +- && opencl_abi) +- { +- struct type *eltype = check_typedef (TYPE_TARGET_TYPE (valtype)); +- int i, nelt = TYPE_LENGTH (valtype) / TYPE_LENGTH (eltype); + +- for (i = 0; i < nelt; i++) +- { +- int offset = i * TYPE_LENGTH (eltype); ++ /* 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 = 8 - TYPE_LENGTH (valtype); + +- 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) ++ 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; ++ } + +- 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; ++ /* 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) +- { +- 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); +- } +- } ++ if (writebuf != NULL) ++ { ++ regcache_cooked_write (regcache, regnum, writebuf); ++ regcache_cooked_write (regcache, regnum + 1, writebuf + 8); + } +- +- return RETURN_VALUE_REGISTER_CONVENTION; ++ if (readbuf != NULL) ++ { ++ regcache_cooked_read (regcache, regnum, readbuf); ++ regcache_cooked_read (regcache, regnum + 1, readbuf + 8); ++ } ++ return 1; + } +- /* 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) ++ ++ /* 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 n_regs = TYPE_LENGTH (valtype) / 16; +- int i; ++ int regnum = tdep->ppc_fp0_regnum + 2 + 2 * index; + +- for (i = 0; i < n_regs; i++) ++ if (writebuf != NULL) + { +- int offset = i * 16; +- int regnum = tdep->ppc_vr0_regnum + 2 + i; +- +- if (writebuf != NULL) +- regcache_cooked_write (regcache, regnum, writebuf + offset); +- if (readbuf != NULL) +- regcache_cooked_read (regcache, regnum, readbuf + offset); ++ regcache_cooked_write (regcache, regnum, writebuf); ++ regcache_cooked_write (regcache, regnum + 1, writebuf + 8); + } +- +- return RETURN_VALUE_REGISTER_CONVENTION; ++ if (readbuf != NULL) ++ { ++ regcache_cooked_read (regcache, regnum, readbuf); ++ regcache_cooked_read (regcache, regnum + 1, readbuf + 8); ++ } ++ return 1; + } +- /* Array type has more than one use. */ +- if (TYPE_CODE (valtype) == TYPE_CODE_ARRAY) ++ ++ /* 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) + { +- /* 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; +- } ++ 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; + } +- /* 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)) ++ ++ return 0; ++} ++ ++/* The 64 bit ABI return value convention. ++ ++ Return non-zero if the return-value is stored in a register, return ++ 0 if the return-value is instead stored on the stack (a.k.a., ++ struct return convention). ++ ++ For a return-value stored in a register: when WRITEBUF is non-NULL, ++ copy the buffer to the corresponding register return-value location ++ location; when READBUF is non-NULL, fill the buffer from the ++ corresponding register return-value location. */ ++enum return_value_convention ++ppc64_sysv_abi_return_value (struct gdbarch *gdbarch, struct value *function, ++ struct type *valtype, struct regcache *regcache, ++ gdb_byte *readbuf, const gdb_byte *writebuf) ++{ ++ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); ++ struct type *func_type = function ? value_type (function) : NULL; ++ 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)); ++ ++ /* Complex types are returned as if two independent scalars. */ ++ if (TYPE_CODE (valtype) == TYPE_CODE_COMPLEX) + { +- if (writebuf || readbuf != NULL) ++ eltype = check_typedef (TYPE_TARGET_TYPE (valtype)); ++ ++ for (i = 0; i < 2; i++) + { +- 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); +- } ++ 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; + } +- /* 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)) ++ ++ /* 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 (regcache != 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++) + { +- int i; +- for (i = 0; i < 2; i++) +- { +- 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); +- } +- } ++ 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; + } +- /* Big complex values get stored in f1:f4. */ +- if (TYPE_CODE (valtype) == TYPE_CODE_COMPLEX && TYPE_LENGTH (valtype) == 32) ++ ++ /* All pointers live in r3. */ ++ if (TYPE_CODE (valtype) == TYPE_CODE_PTR ++ || TYPE_CODE (valtype) == TYPE_CODE_REF) + { +- if (regcache != NULL) +- { +- int i; +- for (i = 0; i < 4; 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); +- } +- } ++ int regnum = tdep->ppc_gp0_regnum + 3; ++ ++ if (writebuf != NULL) ++ regcache_cooked_write (regcache, regnum, writebuf); ++ if (readbuf != NULL) ++ regcache_cooked_read (regcache, regnum, readbuf); + return RETURN_VALUE_REGISTER_CONVENTION; + } ++ ++ /* Small character arrays are returned, right justified, in r3. */ ++ if (TYPE_CODE (valtype) == TYPE_CODE_ARRAY ++ && TYPE_LENGTH (valtype) <= 8 ++ && TYPE_CODE (TYPE_TARGET_TYPE (valtype)) == TYPE_CODE_INT ++ && TYPE_LENGTH (TYPE_TARGET_TYPE (valtype)) == 1) ++ { ++ 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; ++ } ++ ++ /* 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; + } + diff --git a/gdb-upstream-ppc64le05of15.patch b/gdb-upstream-ppc64le05of15.patch new file mode 100644 index 0000000..fa3fda0 --- /dev/null +++ b/gdb-upstream-ppc64le05of15.patch @@ -0,0 +1,44 @@ +commit d63167affc2a56189e3ba2cc47dd9a3451208b59 +Author: Ulrich Weigand +Date: Tue Feb 4 18:26:26 2014 +0100 + + PowerPC64 little-endian fixes: structure passing + + When passing a small structure in a GPR, the ABI specifies that it + should be passed in the least-significant bytes of the register + (or stack slot). On big-endian systems, this means the value + needs to be stored at an offset, which is what current code does. + + However, on little-endian systems, the least-significant bytes are + addresses with offset 0. This patch fixes that. + + gdb/ChangeLog: + + * ppc-sysv-tdep.c (ppc64_sysv_abi_push_val): Use correct + offset on little-endian when passing small structures. + +### a/gdb/ChangeLog +### b/gdb/ChangeLog +## -1,5 +1,10 @@ + 2014-02-04 Ulrich Weigand  + ++ * ppc-sysv-tdep.c (ppc64_sysv_abi_push_val): Use correct ++ offset on little-endian when passing small structures. ++ ++2014-02-04 Ulrich Weigand  ++ + * ppc-sysv-tdep.c (get_decimal_float_return_value): Update comment. + (struct ppc64_sysv_argpos): New data structure. + (ppc64_sysv_abi_push_float): Remove. +--- a/gdb/ppc-sysv-tdep.c ++++ b/gdb/ppc-sysv-tdep.c +@@ -1150,7 +1150,8 @@ ppc64_sysv_abi_push_val (struct gdbarch *gdbarch, + doubleword are right-aligned and those larger are left-aligned. + GCC versions before 3.4 implemented this incorrectly; see + . */ +- if (len < tdep->wordsize) ++ if (len < tdep->wordsize ++ && gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG) + offset = tdep->wordsize - len; + + if (argpos->regcache) diff --git a/gdb-upstream-ppc64le06of15.patch b/gdb-upstream-ppc64le06of15.patch new file mode 100644 index 0000000..d03258d --- /dev/null +++ b/gdb-upstream-ppc64le06of15.patch @@ -0,0 +1,67 @@ +commit 6ed14ff33979bc48367c35b1b235fef8c5e2229b +Author: Ulrich Weigand +Date: Tue Feb 4 18:28:24 2014 +0100 + + PowerPC64 little-endian fixes: AltiVec tests + + A couple of AltiVec tests fail spuriously on powerpc64le-linux, because + they compare against an incorrect pattern. Note that those tests already + contain little-endian variants of the patterns, but those seem to have + bit-rotted a bit: when outputting a vector, GDB no longer omits trailing + zero elements (as it used to do in the past). + + This patch updates the pattern to the new GDB output behavior. + + In addition, the patch updates the endian test to use the new + gdb_test_multiple logic instead of gdb_expect. + + gdb/testsuite/ChangeLog: + + * gdb.arch/altivec-regs.exp: Use gdb_test_multiple for endian test. + (decimal_vector): Fix for little-endian. + +### a/gdb/testsuite/ChangeLog +### b/gdb/testsuite/ChangeLog +## -1,3 +1,8 @@ ++2014-02-04 Ulrich Weigand ++ ++ * gdb.arch/altivec-regs.exp: Use gdb_test_multiple for endian test. ++ (decimal_vector): Fix for little-endian. ++ + 2014-01-29 Jose E. Marchesi + + * gdb.arch/sparc-sysstep.exp: New file. +--- a/gdb/testsuite/gdb.arch/altivec-regs.exp ++++ b/gdb/testsuite/gdb.arch/altivec-regs.exp +@@ -79,17 +79,16 @@ gdb_test "set \$vrsave = 1" "" "" + + 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 @@ gdb_test "info reg vscr" "vscr.*0x1\t1" "info reg vscr" + 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} { diff --git a/gdb-upstream-ppc64le07of15.patch b/gdb-upstream-ppc64le07of15.patch new file mode 100644 index 0000000..c48d419 --- /dev/null +++ b/gdb-upstream-ppc64le07of15.patch @@ -0,0 +1,149 @@ +commit 084ee54552f6c35d740e8b9bc81a4fe8d8bb178b +Author: Ulrich Weigand +Date: Tue Feb 4 18:31:38 2014 +0100 + + PowerPC64 little-endian fixes: VSX tests and pseudo-regs + + Many VSX test were failing on powerpc64le-linux, since -as opposed to the + AltiVec tests- there never were little-endian versions of the test patterns. + + This patch adds such patterns, along the lines of altivec-regs.exp. + + In addition, there is an actual code change required: For those VSX + registers that overlap a floating-point register, the FP register + overlaps the most-significant half of the VSX register both on big- + and little-endian systems. However, on little-endian systems, that + half is stored at an offset of 8 bytes (not 0). This works already + for the "real" FP registers, but current code gets it wrong for + the "extended" pseudo FP register GDB generates for the second + half of the VSX register bank. + + This patch updates the corresponding pseudo read/write routines + to take the appropriate offset into consideration. + + gdb/ChangeLog: + + * 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. + + gdb/testsuite/ChangeLog: + + * gdb.arch/vsx-regs.exp: Check target endianness. Provide variants + of the test patterns for use on little-endian systems. + +### a/gdb/ChangeLog +### b/gdb/ChangeLog +## -1,5 +1,12 @@ + 2014-02-04 Ulrich Weigand  + ++ * 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  ++ + * ppc-sysv-tdep.c (ppc64_sysv_abi_push_val): Use correct + offset on little-endian when passing small structures. + +--- a/gdb/rs6000-tdep.c ++++ b/gdb/rs6000-tdep.c +@@ -2779,10 +2779,12 @@ efpr_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache, + { + 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 +2794,12 @@ efpr_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache, + { + 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 +### a/gdb/testsuite/ChangeLog +### b/gdb/testsuite/ChangeLog +## -1,5 +1,10 @@ + 2014-02-04 Ulrich Weigand + ++ * 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 ++ + * gdb.arch/altivec-regs.exp: Use gdb_test_multiple for endian test. + (decimal_vector): Fix for little-endian. + +--- a/gdb/testsuite/gdb.arch/vsx-regs.exp ++++ b/gdb/testsuite/gdb.arch/vsx-regs.exp +@@ -58,19 +58,45 @@ if ![runto_main] then { + 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_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_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_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_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 ".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_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." + diff --git a/gdb-upstream-ppc64le08of15.patch b/gdb-upstream-ppc64le08of15.patch new file mode 100644 index 0000000..292ff3b --- /dev/null +++ b/gdb-upstream-ppc64le08of15.patch @@ -0,0 +1,57 @@ +commit 5b757e5ddbd9ad252d9c51103f1aa52b41c2e947 +Author: Ulrich Weigand +Date: Tue Feb 4 18:33:04 2014 +0100 + + PowerPC64 little-endian fixes: 32-bit DFP parameters + + Passing a 32-bit DFP in register needs to use the least-significant part + of the register. Like with a previous patch that addressed the same + issue for small structs, this patch makes sure the appropriate offset + is used on little-endian systems. + + gdb/ChangeLog: + + * 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. + +### a/gdb/ChangeLog +### b/gdb/ChangeLog +## -1,5 +1,11 @@ + 2014-02-04 Ulrich Weigand  + ++ * 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  ++ + * rs6000-tdep.c (efpr_pseudo_register_read): Use correct offset + of the overlapped FP register within the VSX register on little- + endian platforms. +--- a/gdb/ppc-sysv-tdep.c ++++ b/gdb/ppc-sysv-tdep.c +@@ -1232,7 +1232,10 @@ ppc64_sysv_abi_push_freg (struct gdbarch *gdbarch, + if (argpos->regcache && argpos->freg <= 13) + { + int regnum = tdep->ppc_fp0_regnum + argpos->freg; +- int offset = 8 - TYPE_LENGTH (type); ++ 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); +@@ -1641,7 +1644,10 @@ ppc64_sysv_abi_return_value_base (struct gdbarch *gdbarch, struct type *valtype, + && TYPE_CODE (valtype) == TYPE_CODE_DECFLOAT) + { + int regnum = tdep->ppc_fp0_regnum + 1 + index; +- int offset = 8 - TYPE_LENGTH (valtype); ++ 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, diff --git a/gdb-upstream-ppc64le09of15.patch b/gdb-upstream-ppc64le09of15.patch new file mode 100644 index 0000000..94f7edd --- /dev/null +++ b/gdb-upstream-ppc64le09of15.patch @@ -0,0 +1,140 @@ +commit 0ff3e01fdc67a3842ee54224cf197e9a55f0a750 +Author: Ulrich Weigand +Date: Tue Feb 4 18:34:19 2014 +0100 + + PowerPC64 little-endian fixes: 128-bit DFP parameters / registers + + The powerpc64le-linux ABI specifies that when a 128-bit DFP value is + passed in a pair of floating-point registers, the first register holds + the most-significant part of the value. This is as opposed to the + usual rule on little-endian systems, where the first register would + hold the least-significant part. + + This affects two places in GDB, the read/write routines for the + 128-bit DFP pseudo-registers, and the function call / return + sequence. For the former, current code already distinguishes + between big- and little-endian targets, but gets the latter + wrong. This is presumably because *GCC* also got it wrong, + and GDB matches the old GCC behavior. But GCC is now fixed: + http://gcc.gnu.org/ml/gcc-patches/2013-11/msg02145.html + so GDB needs to be fixed too. (Old code shouldn't really be + an issue since there is no code "out there" so far that uses + dfp128 on little-endian ...) + + gdb/ChangeLog: + + * 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. + + gdb/testsuite/ChangeLog: + + * gdb.arch/powerpc-d128-regs.exp: Enable on powerpc64*-*. + +### a/gdb/ChangeLog +### b/gdb/ChangeLog +## -1,5 +1,13 @@ + 2014-02-04 Ulrich Weigand  + ++ * 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  ++ + * 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. +--- a/gdb/ppc-sysv-tdep.c ++++ b/gdb/ppc-sysv-tdep.c +@@ -1270,9 +1270,11 @@ ppc64_sysv_abi_push_freg (struct gdbarch *gdbarch, + 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); +- regcache_cooked_write (argpos->regcache, regnum + 1, val + 8); ++ regcache_cooked_write (argpos->regcache, regnum, val + hipart); ++ regcache_cooked_write (argpos->regcache, regnum + 1, val + lopart); + } + + argpos->freg += 2; +@@ -1685,16 +1687,18 @@ ppc64_sysv_abi_return_value_base (struct gdbarch *gdbarch, struct type *valtype, + && 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); +- regcache_cooked_write (regcache, regnum + 1, writebuf + 8); ++ regcache_cooked_write (regcache, regnum, writebuf + hipart); ++ regcache_cooked_write (regcache, regnum + 1, writebuf + lopart); + } + if (readbuf != NULL) + { +- regcache_cooked_read (regcache, regnum, readbuf); +- regcache_cooked_read (regcache, regnum + 1, readbuf + 8); ++ regcache_cooked_read (regcache, regnum, readbuf + hipart); ++ regcache_cooked_read (regcache, regnum + 1, readbuf + lopart); + } + return 1; + } +--- a/gdb/rs6000-tdep.c ++++ b/gdb/rs6000-tdep.c +@@ -2672,10 +2672,10 @@ dfp_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache, + 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 +2701,9 @@ dfp_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache, + 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); + } + } + +### a/gdb/testsuite/ChangeLog +### b/gdb/testsuite/ChangeLog +## -1,5 +1,9 @@ + 2014-02-04 Ulrich Weigand + ++ * gdb.arch/powerpc-d128-regs.exp: Enable on powerpc64*-*. ++ ++2014-02-04 Ulrich Weigand ++ + * gdb.arch/vsx-regs.exp: Check target endianness. Provide variants + of the test patterns for use on little-endian systems. + +--- 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 + } diff --git a/gdb-upstream-ppc64le10of15.patch b/gdb-upstream-ppc64le10of15.patch new file mode 100644 index 0000000..2e307d9 --- /dev/null +++ b/gdb-upstream-ppc64le10of15.patch @@ -0,0 +1,159 @@ +commit cd453cd072004d26ede355b850b3831acffaeddd +Author: Ulrich Weigand +Date: Tue Feb 4 18:38:56 2014 +0100 + + PowerPC64 ELFv2 ABI: base support + + This is the first patch of a series to implement support for the + PowerPC ELFv2 ABI. While powerpc64le-linux will use ELFv2, and + the existing powerpc64-linux code will continue to use ELFv1, + in theory ELFv2 is also defined for big-endian systems (and + ELFv1 was also defined for little-endian systems). + + Therefore this patch adds a new tdep->elf_abi variable to decide + which ABI version to use. This is detected from the ELF header + e_flags value; if this is not present, we default to ELFv2 on + little-endian and ELFv1 otherwise. + + This patch does not yet introduce any actual difference in GDB's + handling of the two ABIs. Those will be added by the remainder + of this patch series. + + For an overview of the changes in ELFv2, have a look at the + comments in the patch series that added ELFv2 to GCC, starting at: + http://gcc.gnu.org/ml/gcc-patches/2013-11/msg01144.html + + gdb/ChangeLog: + + * 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. + +### a/gdb/ChangeLog +### b/gdb/ChangeLog +## -1,5 +1,13 @@ + 2014-02-04 Ulrich Weigand  + ++ * 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  ++ + * 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. +Index: gdb-7.7.1/gdb/ppc-tdep.h +=================================================================== +--- gdb-7.7.1.orig/gdb/ppc-tdep.h 2014-05-09 19:23:40.892248064 +0200 ++++ gdb-7.7.1/gdb/ppc-tdep.h 2014-05-09 19:23:42.346248246 +0200 +@@ -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; + +Index: gdb-7.7.1/gdb/rs6000-tdep.c +=================================================================== +--- gdb-7.7.1.orig/gdb/rs6000-tdep.c 2014-05-09 19:23:40.894248064 +0200 ++++ gdb-7.7.1/gdb/rs6000-tdep.c 2014-05-09 19:23:57.974250197 +0200 +@@ -48,6 +48,7 @@ + + #include "elf-bfd.h" + #include "elf/ppc.h" ++#include "elf/ppc64.h" + + #include "solib-svr4.h" + #include "ppc-tdep.h" +@@ -3554,6 +3555,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; +@@ -3860,6 +3862,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, +@@ -3896,6 +3913,21 @@ rs6000_gdbarch_init (struct gdbarch_info + } + #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) +@@ -3938,6 +3970,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) +@@ -3960,6 +3994,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; + diff --git a/gdb-upstream-ppc64le11of15.patch b/gdb-upstream-ppc64le11of15.patch new file mode 100644 index 0000000..fdbd7ab --- /dev/null +++ b/gdb-upstream-ppc64le11of15.patch @@ -0,0 +1,132 @@ +commit d4094b6a8883ae481c7644c5a210254efe92e9ad +Author: Ulrich Weigand +Date: Tue Feb 4 18:40:16 2014 +0100 + + PowerPC64 ELFv2 ABI: no function descriptors + + This implements the most significant difference with the ELFv2 ABI: + we no longer use function descriptors. The patch consists mostly + of switching off code to deal with descriptors :-) + + In addition, when calling an inferior function, we no longer need + to provide its TOC in r2. Instead, ELFv2 code expects to be called + with r12 pointing to the code address itself. + + gdb/ChangeLog: + + * 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. + +### a/gdb/ChangeLog +### b/gdb/ChangeLog +## -1,5 +1,15 @@ + 2014-02-04 Ulrich Weigand  + ++ * 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  ++ + * ppc-tdep.h (enum powerpc_elf_abi): New data type. + (struct gdbarch_tdep): New member elf_abi. + +--- a/gdb/ppc-linux-tdep.c ++++ b/gdb/ppc-linux-tdep.c +@@ -1339,13 +1339,16 @@ ppc_linux_init_abi (struct gdbarch_info 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); ++ } + + /* 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 +@@ -1352,8 +1352,9 @@ ppc64_sysv_abi_push_param (struct gdbarch *gdbarch, + 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 + = check_typedef (TYPE_TARGET_TYPE (type)); +@@ -1553,24 +1554,32 @@ ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, + 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; + } diff --git a/gdb-upstream-ppc64le12of15.patch b/gdb-upstream-ppc64le12of15.patch new file mode 100644 index 0000000..3b38682 --- /dev/null +++ b/gdb-upstream-ppc64le12of15.patch @@ -0,0 +1,48 @@ +commit 52f548e41f085550d7740c350c1c8a239532af77 +Author: Ulrich Weigand +Date: Tue Feb 4 18:41:36 2014 +0100 + + PowerPC64 ELFv2 ABI: stack frame layout changes + + This implementes another change in ELFv2: the stack frame no longer + contains the reserved double words for linker and compiler use + (which weren't really used for much of anything anyway). This + affects placement of on-stack parameters in inferior calls. + + gdb/ChangeLog: + + * ppc-sysv-tdep.c (ppc64_sysv_abi_push_dummy_call): Use correct + offset to the stack parameter list for the ELFv2 ABI. + +### a/gdb/ChangeLog +### b/gdb/ChangeLog +## -1,5 +1,10 @@ + 2014-02-04 Ulrich Weigand  + ++ * 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  ++ + * 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. +--- a/gdb/ppc-sysv-tdep.c ++++ b/gdb/ppc-sysv-tdep.c +@@ -1474,9 +1474,13 @@ ppc64_sysv_abi_push_dummy_call (struct gdbarch *gdbarch, + 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, +- compiler double word, LR save area, CR save area. */ +- sp = align_down (argpos.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 (argpos.gparam - 48, 16); ++ else ++ sp = align_down (argpos.gparam - 32, 16); + } + + /* If the function is returning a `struct', then there is an diff --git a/gdb-upstream-ppc64le13of15.patch b/gdb-upstream-ppc64le13of15.patch new file mode 100644 index 0000000..79ce599 --- /dev/null +++ b/gdb-upstream-ppc64le13of15.patch @@ -0,0 +1,309 @@ +commit cc0e89c519912e0e4e75a2fc0d836f715cdc6806 +Author: Ulrich Weigand +Date: Tue Feb 4 18:42:35 2014 +0100 + + PowerPC64 ELFv2 ABI: structure passing / return + + Another significant difference in the ELFv2 ABI is that "homogeneous" + floating-point and vector aggregates, i.e. aggregates the consist + (recursively) only of members of the same floating-point or vector type, + are passed in a series of floating-point / vector registers, as if they + were seperate parameters. (This is similar to the ARM ABI.) This + applies to both calls and returns. + + In addition when returning any aggregate of up to 16 bytes, ELFv2 now + used general-purpose registers. + + This patch adds support for these aspects of the ABI, which is relatively + straightforward after the refactoring patch to ppc-sysv-tdep.c. + + gdb/ChangeLog: + + * 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. + +### a/gdb/ChangeLog +### b/gdb/ChangeLog +## -1,5 +1,13 @@ + 2014-02-04 Ulrich Weigand  + ++ * 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  ++ + * ppc-sysv-tdep.c (ppc64_sysv_abi_push_dummy_call): Use correct + offset to the stack parameter list for the ELFv2 ABI. + +--- a/gdb/ppc-sysv-tdep.c ++++ b/gdb/ppc-sysv-tdep.c +@@ -1101,6 +1101,160 @@ convert_code_addr_to_desc_addr (CORE_ADDR code_addr, CORE_ADDR *desc_addr) + 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; ++ /* 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 + { +@@ -1389,6 +1543,29 @@ ppc64_sysv_abi_push_param (struct gdbarch *gdbarch, + 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); ++ } ++ } + } + } + +@@ -1834,6 +2011,72 @@ ppc64_sysv_abi_return_value (struct gdbarch *gdbarch, struct value *function, + 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++) ++ { ++ 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; ++ } ++ ++ /* 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 (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); ++ } ++ if (readbuf != NULL) ++ { ++ 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)) diff --git a/gdb-upstream-ppc64le14of15.patch b/gdb-upstream-ppc64le14of15.patch new file mode 100644 index 0000000..abee983 --- /dev/null +++ b/gdb-upstream-ppc64le14of15.patch @@ -0,0 +1,375 @@ +commit 591a12a1d4c8843343eb999145d8bcc1efedf408 +Author: Ulrich Weigand +Date: Tue Feb 4 18:44:14 2014 +0100 + + PowerPC64 ELFv2 ABI: skip global entry point code + + This patch handles another aspect of the ELFv2 ABI, which unfortunately + requires common code changes. + + In ELFv2, functions may provide both a global and a local entry point. + The global entry point (where the function symbol points to) is intended + to be used for function-pointer or cross-module (PLT) calls, and requires + r12 to be set up to the entry point address itself. The local entry + point (which is found at a fixed offset after the global entry point, + as defined by bits in the symbol table entries' st_other field), instead + expects r2 to be set up to the current TOC. + + Now, when setting a breakpoint on a function by name, you really want + that breakpoint to trigger either way, no matter whether the function + is called via its local or global entry point. Since the global entry + point will always fall through into the local entry point, the way to + achieve that is to simply set the breakpoint at the local entry point. + + One way to do that would be to have prologue parsing skip the code + sequence that makes up the global entry point. Unfortunately, this + does not work reliably, since -for optimized code- GDB these days + will not actuall invoke the prologue parsing code but instead just + set the breakpoint at the symbol address and rely on DWARF being + correct at any point throughout the function ... + + Unfortunately, I don't really see any way to express the notion of + local entry points with the current set of gdbarch callbacks. + + Thus this patch adds a new callback, skip_entrypoint, that is + somewhat analogous to skip_prologue, but is called every time + GDB needs to determine a function start address, even in those + cases where GDB decides to not call skip_prologue. + + As a side effect, the skip_entrypoint implementation on ppc64 + does not need to perform any instruction parsing; it can simply + rely on the local entry point flags in the symbol table entry. + + With this implemented, two test cases would still fail to set + the breakpoint correctly, but that's because they use the construct: + + gdb_test "break *hello" + + Now, using "*hello" explicitly instructs GDB to set the breakpoint + at the numerical value of "hello" treated as function pointer, so + it will by definition only hit the global entry point. + + I think this behaviour is unavoidable, but acceptable -- most people + do not use this construct, and if they do, they get what they + asked for ... + + In one of those two test cases, use of this construct is really + not appropriate. I think this was added way back when as a means + to work around prologue skipping problems on some platforms. These + days that shouldn't really be necessary any more ... + + For the other (step-bt), we really want to make sure backtracing + works on the very first instruction of the routine. To enable that + test also on powerpc64le-linux, we can modify the code to call the + test function via function pointer (which makes it use the global + entry point in the ELFv2 ABI). + + gdb/ChangeLog: + + * 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. + + gdb/testsuite/ChangeLog: + + * 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. + +### a/gdb/ChangeLog +### b/gdb/ChangeLog +## -1,5 +1,16 @@ + 2014-02-04 Ulrich Weigand  + ++ * 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  ++ + * ppc-sysv-tdep.c (ppc64_aggregate_candidate): New routine. + (ppc64_elfv2_abi_homogeneous_aggregate): Likewise. + (ppc64_sysv_abi_push_param): Handle ELFv2 homogeneous structs. +--- a/gdb/gdbarch.c ++++ b/gdb/gdbarch.c +@@ -229,6 +229,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; +@@ -405,6 +406,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 */ +@@ -714,6 +716,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) +@@ -1353,6 +1356,12 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file) + "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, +@@ -2703,6 +2712,30 @@ set_gdbarch_skip_main_prologue (struct gdbarch *gdbarch, + } + + 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 +@@ -486,6 +486,24 @@ typedef CORE_ADDR (gdbarch_skip_main_prologue_ftype) (struct gdbarch *gdbarch, C + 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); +--- a/gdb/gdbarch.sh ++++ b/gdb/gdbarch.sh +@@ -530,6 +530,19 @@ m:int:return_in_first_hidden_param_p:struct type *type:type::default_return_in_f + + 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. +--- a/gdb/infrun.c ++++ b/gdb/infrun.c +@@ -3159,6 +3159,10 @@ fill_in_stop_func (struct gdbarch *gdbarch, + 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,55 @@ ppc_linux_core_read_description (struct gdbarch *gdbarch, + } + } + ++ ++/* 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. */ + +@@ -1349,6 +1399,13 @@ ppc_linux_init_abi (struct gdbarch_info info, + 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/symtab.c ++++ b/gdb/symtab.c +@@ -2950,6 +2950,8 @@ skip_prologue_sal (struct symtab_and_line *sal) + + /* 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/ChangeLog +### b/gdb/testsuite/ChangeLog +## -1,5 +1,12 @@ + 2014-02-04 Ulrich Weigand + ++ * 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 ++ + * gdb.arch/powerpc-d128-regs.exp: Enable on powerpc64*-*. + + 2014-02-04 Ulrich Weigand +--- a/gdb/testsuite/gdb.base/sigbpt.exp ++++ b/gdb/testsuite/gdb.base/sigbpt.exp +@@ -76,7 +76,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.c ++++ b/gdb/testsuite/gdb.base/step-bt.c +@@ -23,10 +23,19 @@ hello (void) + 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/gdb-upstream-ppc64le15of15.patch b/gdb-upstream-ppc64le15of15.patch new file mode 100644 index 0000000..961bf68 --- /dev/null +++ b/gdb-upstream-ppc64le15of15.patch @@ -0,0 +1,90 @@ +commit bc9a55253ed7122cfeee90cd23d964f44c8b0e6a +Author: Ulrich Weigand +Date: Tue Mar 25 15:39:32 2014 +0100 + + Support gdb.asm/asm-source.exp on powerpc64le + + Add new powerpc64le.inc file appropriate for the ELFv2 ABI and + use it to support the asm-source.exp test case on powerpc64le. + + gdb/testsuite/ + 2014-03-25 Ulrich Weigand + + * gdb.asm/asm-source.exp: Handle powerpc64le-* targets. + * gdb.asm/powerpc64le.inc: New file. + +### a/gdb/testsuite/ChangeLog +### b/gdb/testsuite/ChangeLog +## -1,3 +1,8 @@ ++2014-03-25 Ulrich Weigand ++ ++ * gdb.asm/asm-source.exp: Handle powerpc64le-* targets. ++ * gdb.asm/powerpc64le.inc: New file. ++ + 2014-03-25 Pedro Alves + Doug Evans + +--- a/gdb/testsuite/gdb.asm/asm-source.exp ++++ b/gdb/testsuite/gdb.asm/asm-source.exp +@@ -97,6 +97,11 @@ switch -glob -- [istarget] { + "mips*-*" { + set asm-arch mips + } ++ "powerpc64le-*" { ++ set asm-arch powerpc64le ++ set asm-flags "-a64 -I${srcdir}/${subdir} $obj_include" ++ append link-flags " -m elf64lppc" ++ } + "powerpc*-*" { + if { [is_lp64_target] } { + set asm-arch powerpc64 +--- /dev/null ++++ b/gdb/testsuite/gdb.asm/powerpc64le.inc +@@ -0,0 +1,47 @@ ++ comment "subroutine prologue" ++ .macro gdbasm_enter ++ stdu 1, -32(1) ++ mflr 0 ++ std 0, 48(1) ++ .endm ++ ++ comment "subroutine epilogue" ++ .macro gdbasm_leave ++ ld 0, 48(1) ++ mtlr 0 ++ ld 1, 0(1) ++ blr ++ .endm ++ ++ .macro gdbasm_call subr ++ bl \subr ++ nop ++ .endm ++ ++ .macro gdbasm_several_nops ++ nop ++ nop ++ nop ++ nop ++ .endm ++ ++ comment "exit (0)" ++ .macro gdbasm_exit0 ++ comment "sys_exit" ++ li 0, 1 ++ sc ++ .endm ++ ++ comment "crt0 startup" ++ .macro gdbasm_startup ++ .abiversion 2 ++ .p2align 2 ++ .endm ++ ++ comment "Declare a data variable" ++ .purgem gdbasm_datavar ++ .macro gdbasm_datavar name value ++ .section ".data" ++\name: ++ .long \value ++ .endm diff --git a/gdb.spec b/gdb.spec index 86cfade..fb43891 100644 --- a/gdb.spec +++ b/gdb.spec @@ -39,7 +39,7 @@ Version: 7.7.1 # The release always contains a leading reserved number, start it at 1. # `upstream' is not a part of `name' to stay fully rpm dependencies compatible for the testing. -Release: 10%{?dist} +Release: 11%{?dist} License: GPLv3+ and GPLv3+ with exceptions and GPLv2+ and GPLv2+ with exceptions and GPL+ and LGPLv2+ and BSD and Public Domain and GFDL Group: Development/Debuggers @@ -237,6 +237,20 @@ Patch231: gdb-6.3-bz202689-exec-from-pthread-test.patch # Backported fixups post the source tarball. #Xdrop: Just backports. Patch232: gdb-upstream.patch +Patch868: gdb-upstream-ppc64le02of15.patch +Patch869: gdb-upstream-ppc64le03of15.patch +Patch870: gdb-upstream-ppc64le04of15.patch +Patch871: gdb-upstream-ppc64le05of15.patch +Patch872: gdb-upstream-ppc64le06of15.patch +Patch873: gdb-upstream-ppc64le07of15.patch +Patch874: gdb-upstream-ppc64le08of15.patch +Patch875: gdb-upstream-ppc64le09of15.patch +Patch876: gdb-upstream-ppc64le10of15.patch +Patch877: gdb-upstream-ppc64le11of15.patch +Patch878: gdb-upstream-ppc64le12of15.patch +Patch879: gdb-upstream-ppc64le13of15.patch +Patch880: gdb-upstream-ppc64le14of15.patch +Patch881: gdb-upstream-ppc64le15of15.patch # Testcase for PPC Power6/DFP instructions disassembly (BZ 230000). #=fedoratest+ppc @@ -609,8 +623,11 @@ BuildRequires: gcc gcc-c++ gcc-gfortran gcc-objc BuildRequires: gcc-java libgcj%{bits_local} libgcj%{bits_other} %endif %if 0%{!?rhel:1} || 0%{?rhel} > 6 +# Fedora ppc64le does not yet have gcc-go built. +%ifnarch ppc64le BuildRequires: gcc-go %endif +%endif # archer-sergiodj-stap-patch-split BuildRequires: systemtap-sdt-devel # Copied from prelink-0.4.2-3.fc13. @@ -621,8 +638,8 @@ BuildRequires: prelink %endif %endif %if 0%{!?rhel:1} -# Fedora arm does not yet have fpc built. -%ifnarch %{arm} +# Fedora arm+ppc64le do not yet have fpc built. +%ifnarch %{arm} ppc64le BuildRequires: fpc %endif %endif @@ -639,8 +656,11 @@ BuildRequires: libgcc%{bits_local} libgcc%{bits_other} # libstdc++-devel of matching bits is required only for g++ -static. BuildRequires: libstdc++%{bits_local} libstdc++%{bits_other} %if 0%{!?rhel:1} || 0%{?rhel} > 6 +# Fedora ppc64le does not yet have gcc-go built. +%ifnarch ppc64le BuildRequires: libgo-devel%{bits_local} libgo-devel%{bits_other} %endif +%endif %if 0%{!?el5:1} BuildRequires: glibc-static%{bits_local} %endif @@ -736,6 +756,20 @@ find -name "*.info*"|xargs rm -f %patch349 -p1 %patch232 -p1 +%patch868 -p1 +%patch869 -p1 +%patch870 -p1 +%patch871 -p1 +%patch872 -p1 +%patch873 -p1 +%patch874 -p1 +%patch875 -p1 +%patch876 -p1 +%patch877 -p1 +%patch878 -p1 +%patch879 -p1 +%patch880 -p1 +%patch881 -p1 %patch1 -p1 %patch105 -p1 @@ -921,7 +955,7 @@ export LDFLAGS="%{?__global_ldflags} %{?_with_asan:-fsanitize=address}" --with-system-gdbinit=%{_sysconfdir}/gdbinit \ --with-gdb-datadir=%{_datadir}/gdb \ --enable-gdb-build-warnings=,-Wno-unused \ -%ifnarch %{ix86} alpha ppc s390 s390x x86_64 ppc64 sparc sparcv9 sparc64 +%ifnarch %{ix86} alpha ppc s390 s390x x86_64 ppc64 ppc64le sparc sparcv9 sparc64 --disable-werror \ %else --enable-werror \ @@ -1370,7 +1404,10 @@ fi %endif # 0%{!?el5:1} || "%{_target_cpu}" == "noarch" %changelog -* Tue May 6 2014 Sergio Durigan Junior - 7.7.1-10.fc21 +* Fri May 9 2014 Jan Kratochvil - 7.7.1-11.fc21 +- [ppc*] Import ppc64le support (BZ 1096303, Ulrich Weigand). + +* Tue May 6 2014 Jan Kratochvil - 7.7.1-10.fc21 - Rebase to FSF GDB 7.7.1. * Mon May 5 2014 Sergio Durigan Junior - 7.7-9.fc21