diff --git a/SOURCES/gdb-6.5-bz185337-resolve-tls-without-debuginfo-v2.patch b/SOURCES/gdb-6.5-bz185337-resolve-tls-without-debuginfo-v2.patch index fa2f4ed..e81b664 100644 --- a/SOURCES/gdb-6.5-bz185337-resolve-tls-without-debuginfo-v2.patch +++ b/SOURCES/gdb-6.5-bz185337-resolve-tls-without-debuginfo-v2.patch @@ -22,6 +22,8 @@ for the most common under-ggdb3 compiled programs. Original patch hooked into target_translate_tls_address. But its inferior call invalidates `struct frame *' in the callers - RH BZ 690908. +https://bugzilla.redhat.com/show_bug.cgi?id=1166549 + 2007-11-03 Jan Kratochvil @@ -32,21 +34,25 @@ glibc-debuginfo-2.7-2.x86_64: /usr/lib/debug/lib64/libc.so.6.debug: <81a2> DW_AT_name : (indirect string, offset: 0x280e): __errno_location <81a8> DW_AT_MIPS_linkage_name: (indirect string, offset: 0x2808): *__GI___errno_location ---- a/gdb/printcmd.c -+++ b/gdb/printcmd.c -@@ -967,6 +967,8 @@ print_command_1 (char *exp, int inspect, int voidprint) +Index: gdb-7.8.1/gdb/printcmd.c +=================================================================== +--- gdb-7.8.1.orig/gdb/printcmd.c 2014-11-21 19:05:44.699959209 +0100 ++++ gdb-7.8.1/gdb/printcmd.c 2014-11-21 19:05:44.868959291 +0100 +@@ -968,6 +968,10 @@ print_command_1 (char *exp, int voidprin if (exp && *exp) { -+ if (strcmp (exp, "errno") == 0) -+ exp = "*((int *(*) (void)) __errno_location) ()"; ++ /* '*((int *(*) (void)) __errno_location) ()' is incompatible with ++ function descriptors. */ ++ if (target_has_execution && strcmp (exp, "errno") == 0) ++ exp = "*(*(int *(*)(void)) __errno_location) ()"; expr = parse_expression (exp); old_chain = make_cleanup (free_current_contents, &expr); cleanup = 1; -Index: gdb-7.2/gdb/testsuite/gdb.dwarf2/dw2-errno.c +Index: gdb-7.8.1/gdb/testsuite/gdb.dwarf2/dw2-errno.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ gdb-7.2/gdb/testsuite/gdb.dwarf2/dw2-errno.c 2011-03-29 10:55:35.000000000 +0200 ++++ gdb-7.8.1/gdb/testsuite/gdb.dwarf2/dw2-errno.c 2014-11-21 19:05:44.869959291 +0100 @@ -0,0 +1,28 @@ +/* This testcase is part of GDB, the GNU debugger. + @@ -76,10 +82,10 @@ Index: gdb-7.2/gdb/testsuite/gdb.dwarf2/dw2-errno.c + + return 0; /* breakpoint */ +} -Index: gdb-7.2/gdb/testsuite/gdb.dwarf2/dw2-errno.exp +Index: gdb-7.8.1/gdb/testsuite/gdb.dwarf2/dw2-errno.exp =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ gdb-7.2/gdb/testsuite/gdb.dwarf2/dw2-errno.exp 2011-03-29 10:55:35.000000000 +0200 ++++ gdb-7.8.1/gdb/testsuite/gdb.dwarf2/dw2-errno.exp 2014-11-21 19:05:44.869959291 +0100 @@ -0,0 +1,60 @@ +# Copyright 2007 Free Software Foundation, Inc. + @@ -141,3 +147,112 @@ Index: gdb-7.2/gdb/testsuite/gdb.dwarf2/dw2-errno.exp + +# TODO: Test the error on resolving ERRNO with only libc loaded. +# Just how to find the current libc filename? +Index: gdb-7.8.1/gdb/testsuite/gdb.dwarf2/dw2-errno2.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-7.8.1/gdb/testsuite/gdb.dwarf2/dw2-errno2.c 2014-11-21 19:05:44.869959291 +0100 +@@ -0,0 +1,28 @@ ++/* This testcase is part of GDB, the GNU debugger. ++ ++ Copyright 2005, 2007 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++ Please email any bugs, comments, and/or additions to this file to: ++ bug-gdb@prep.ai.mit.edu */ ++ ++#include ++ ++int main() ++{ ++ errno = 42; ++ ++ return 0; /* breakpoint */ ++} +Index: gdb-7.8.1/gdb/testsuite/gdb.dwarf2/dw2-errno2.exp +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gdb-7.8.1/gdb/testsuite/gdb.dwarf2/dw2-errno2.exp 2014-11-21 19:13:01.553171326 +0100 +@@ -0,0 +1,71 @@ ++# Copyright 2007 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++set testfile dw2-errno2 ++set srcfile ${testfile}.c ++set binfile ${objdir}/${subdir}/${testfile} ++ ++proc prep { message {do_xfail 0} } { with_test_prefix $message { ++ global srcdir subdir binfile variant ++ gdb_exit ++ gdb_start ++ gdb_reinitialize_dir $srcdir/$subdir ++ gdb_load ${binfile}${variant} ++ ++ runto_main ++ ++ gdb_breakpoint [gdb_get_line_number "breakpoint"] ++ gdb_continue_to_breakpoint "breakpoint" ++ ++ gdb_test "gcore ${binfile}${variant}.core" "\r\nSaved corefile .*" "gcore $variant" ++ ++ gdb_test "print errno" ".* = 42" ++ ++ gdb_test "kill" ".*" "kill" {Kill the program being debugged\? \(y or n\) } "y" ++ gdb_test "core-file ${binfile}${variant}.core" "\r\nCore was generated by .*" "core-file" ++ if $do_xfail { ++ setup_xfail "*-*-*" ++ } ++ gdb_test "print errno" ".* = 42" "print errno for core" ++}} ++ ++set variant g2thrN ++if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}${variant}" executable "additional_flags=-g2"] != "" } { ++ untested "Couldn't compile test program" ++ return -1 ++} ++prep "macros=N threads=N" 1 ++ ++set variant g3thrN ++if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}${variant}" executable "additional_flags=-g3"] != "" } { ++ untested "Couldn't compile test program" ++ return -1 ++} ++prep "macros=Y threads=N" 1 ++ ++set variant g2thrY ++if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}${variant}" executable "additional_flags=-g2"] != "" } { ++ return -1 ++} ++prep "macros=N threads=Y" ++ ++set variant g3thrY ++if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}${variant}" executable "additional_flags=-g3"] != "" } { ++ return -1 ++} ++prep "macros=Y threads=Y" 1 ++ ++# TODO: Test the error on resolving ERRNO with only libc loaded. ++# Just how to find the current libc filename? diff --git a/SOURCES/gdb-gdb-add-index-script.patch b/SOURCES/gdb-gdb-add-index-script.patch index 966cd6c..c81078f 100644 --- a/SOURCES/gdb-gdb-add-index-script.patch +++ b/SOURCES/gdb-gdb-add-index-script.patch @@ -40,10 +40,10 @@ Subject: [PATCH 4/4] add gdb-add-index 5 files changed, 57 insertions(+), 1 deletions(-) create mode 100755 gdb/gdb-add-index -Index: gdb-7.5.91.20130407/gdb/Makefile.in +Index: gdb-7.6.1/gdb/Makefile.in =================================================================== ---- gdb-7.5.91.20130407.orig/gdb/Makefile.in 2013-04-11 16:52:51.000000000 +0200 -+++ gdb-7.5.91.20130407/gdb/Makefile.in 2013-04-11 16:53:59.199279388 +0200 +--- gdb-7.6.1.orig/gdb/Makefile.in ++++ gdb-7.6.1/gdb/Makefile.in @@ -1053,6 +1053,15 @@ install-only: install-gstack $(CONFIG_IN $(INSTALL_PROGRAM) gcore \ $(DESTDIR)$(bindir)/$$transformed_name; \ @@ -60,10 +60,10 @@ Index: gdb-7.5.91.20130407/gdb/Makefile.in @$(MAKE) DO=install "DODIRS=$(SUBDIRS)" $(FLAGS_TO_PASS) subdir_do install-python: -Index: gdb-7.5.91.20130407/gdb/doc/gdb.texinfo +Index: gdb-7.6.1/gdb/doc/gdb.texinfo =================================================================== ---- gdb-7.5.91.20130407.orig/gdb/doc/gdb.texinfo 2013-04-11 16:53:00.000000000 +0200 -+++ gdb-7.5.91.20130407/gdb/doc/gdb.texinfo 2013-04-11 16:55:07.004278842 +0200 +--- gdb-7.6.1.orig/gdb/doc/gdb.texinfo ++++ gdb-7.6.1/gdb/doc/gdb.texinfo @@ -17159,6 +17159,14 @@ There are currently some limitation on i for DWARF debugging information, not stabs. And, they do not currently work for programs using Ada. @@ -79,7 +79,7 @@ Index: gdb-7.5.91.20130407/gdb/doc/gdb.texinfo @node Symbol Errors @section Errors Reading Symbol Files -@@ -41730,6 +41738,7 @@ switch (die->tag) +@@ -41738,6 +41746,7 @@ switch (die->tag) * gdbserver man:: Remote Server for the GNU Debugger man page * gcore man:: Generate a core file of a running program * gdbinit man:: gdbinit scripts @@ -87,7 +87,7 @@ Index: gdb-7.5.91.20130407/gdb/doc/gdb.texinfo @end menu @node gdb man -@@ -42382,6 +42391,54 @@ gdb(1), @code{info -f gdb -n Startup} +@@ -42390,6 +42399,54 @@ gdb(1), @code{info -f gdb -n Startup} The full documentation for @value{GDBN} is maintained as a Texinfo manual. If the @code{info} and @code{gdb} programs and @value{GDBN}'s Texinfo documentation are properly installed at your site, the command @@ -142,11 +142,11 @@ Index: gdb-7.5.91.20130407/gdb/doc/gdb.texinfo @smallexample info gdb -Index: gdb-7.5.91.20130407/gdb/gdb-add-index +Index: gdb-7.6.1/gdb/gdb-add-index =================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ gdb-7.5.91.20130407/gdb/gdb-add-index 2013-04-11 16:53:21.524279909 +0200 -@@ -0,0 +1,30 @@ +--- /dev/null ++++ gdb-7.6.1/gdb/gdb-add-index +@@ -0,0 +1,31 @@ +#! /bin/sh + +# Add a .gdb_index section to a file. @@ -167,6 +167,7 @@ Index: gdb-7.5.91.20130407/gdb/gdb-add-index + +file="$1" +dir="${file%/*}" ++test "$dir" = "$file" && dir="." + +# We don't care if gdb gives an error. +gdb -nx -iex 'set auto-load no' --batch-silent -ex "file $file" -ex "save gdb-index $dir" @@ -177,10 +178,10 @@ Index: gdb-7.5.91.20130407/gdb/gdb-add-index +fi + +exit 0 -Index: gdb-7.5.91.20130407/gdb/doc/Makefile.in +Index: gdb-7.6.1/gdb/doc/Makefile.in =================================================================== ---- gdb-7.5.91.20130407.orig/gdb/doc/Makefile.in 2013-04-11 16:50:33.202286928 +0200 -+++ gdb-7.5.91.20130407/gdb/doc/Makefile.in 2013-04-11 16:55:06.993279304 +0200 +--- gdb-7.6.1.orig/gdb/doc/Makefile.in ++++ gdb-7.6.1/gdb/doc/Makefile.in @@ -177,7 +177,7 @@ POD2MAN5 = pod2man --center="GNU Develop --release="gdb-`sed q $(srcdir)/../version.in`" --section=5 diff --git a/SOURCES/gdb-rhbz1080657-tls-variable-static-linked-binary-1of3.patch b/SOURCES/gdb-rhbz1080657-tls-variable-static-linked-binary-1of3.patch new file mode 100644 index 0000000..cb5de26 --- /dev/null +++ b/SOURCES/gdb-rhbz1080657-tls-variable-static-linked-binary-1of3.patch @@ -0,0 +1,69 @@ +commit 9e0aa64f5510861b2517c5841b59adde8e423540 +Author: Jan Kratochvil +Date: Mon May 19 20:20:27 2014 +0200 + + Fix gdbserver qGetTLSAddr for x86_64 -m32 + + gdbserver makes libthread_db to access uninitialized memory. Surprisingly it + does not harm normally, even -fsanitize=address works with current gdbserver. + I have found just valgrind detects it as a very first warning for gdbserver: + + Syscall param ptrace(addr) contains uninitialised byte(s) + at 0x3721EECEBE: ptrace (ptrace.c:45) + by 0x436EE5: ps_get_thread_area (linux-x86-low.c:252) + by 0x5559D02: __td_ta_lookup_th_unique (td_ta_map_lwp2thr.c:157) + by 0x5559EC3: td_ta_map_lwp2thr (td_ta_map_lwp2thr.c:207) + by 0x43F87D: find_one_thread (thread-db.c:281) + by 0x440038: thread_db_get_tls_address (thread-db.c:505) + by 0x40F6D0: handle_query (server.c:2004) + by 0x4124CF: process_serial_event (server.c:3445) + by 0x4136B6: handle_serial_event (server.c:3889) + by 0x419571: handle_file_event (event-loop.c:434) + by 0x418D38: process_event (event-loop.c:189) + by 0x419AB7: start_event_loop (event-loop.c:552) + + Reproducible with: + cd gdb/testsuite + g++ -o gdb.threads/tls gdb.threads/tls{,2}.c -m32 -pthread + ../gdbserver/gdbserver :1234 gdb.threads/tls + ../gdb -batch gdb.threads/tls -ex 'target remote :1234' -ex 'b spin' -ex c -ex 'p a_thread_local' + + It is more easily reproducible even without valgrind using s/0x00/0xff/ in the + attached patch. It will then turn the output of reproducer above: + $1 = 0 + -> + Cannot find thread-local storage for Thread 29044, executable file .../gdb/testsuite/gdb.threads/tls: + Remote target failed to process qGetTLSAddr request + + gdb/gdbserver/ + 2014-05-19 Jan Kratochvil + + Fix gdbserver qGetTLSAddr for x86_64 -m32. + * linux-x86-low.c (X86_64_USER_REGS): New. + (x86_fill_gregset): Call memset for BUF first in x86_64 -m32 case. + + Message-ID: <20140410114901.GA16411@host2.jankratochvil.net> + +Index: gdb-7.6.1/gdb/gdbserver/linux-x86-low.c +=================================================================== +--- gdb-7.6.1.orig/gdb/gdbserver/linux-x86-low.c ++++ gdb-7.6.1/gdb/gdbserver/linux-x86-low.c +@@ -144,6 +144,7 @@ static const int x86_64_regmap[] = + }; + + #define X86_64_NUM_REGS (sizeof (x86_64_regmap) / sizeof (x86_64_regmap[0])) ++#define X86_64_USER_REGS (GS + 1) + + #else /* ! __x86_64__ */ + +@@ -275,6 +276,10 @@ x86_fill_gregset (struct regcache *regca + collect_register (regcache, i, ((char *) buf) + x86_64_regmap[i]); + return; + } ++ ++ /* 32-bit inferior registers need to be zero-extended. ++ Callers would read uninitialized memory otherwise. */ ++ memset (buf, 0x00, X86_64_USER_REGS * 8); + #endif + + for (i = 0; i < I386_NUM_REGS; i++) diff --git a/SOURCES/gdb-rhbz1080657-tls-variable-static-linked-binary-2of3.patch b/SOURCES/gdb-rhbz1080657-tls-variable-static-linked-binary-2of3.patch new file mode 100644 index 0000000..970a82d --- /dev/null +++ b/SOURCES/gdb-rhbz1080657-tls-variable-static-linked-binary-2of3.patch @@ -0,0 +1,311 @@ +commit 5876f5032f60c45c4bd19e7ea7d0c14d0346b93e +Author: Jan Kratochvil +Date: Wed May 21 16:25:53 2014 +0200 + + Fix TLS access for -static -pthread + + I have posted: + TLS variables access for -static -lpthread executables + https://sourceware.org/ml/libc-help/2014-03/msg00024.html + and the GDB patch below has been confirmed as OK for current glibcs. + + Further work should be done for newer glibcs: + Improve TLS variables glibc compatibility + https://sourceware.org/bugzilla/show_bug.cgi?id=16954 + + Still the patch below implements the feature in a fully functional way backward + compatible with current glibcs, it depends on the following glibc source line: + csu/libc-tls.c + main_map->l_tls_modid = 1; + + gdb/ + 2014-05-21 Jan Kratochvil + + Fix TLS access for -static -pthread. + * linux-thread-db.c (struct thread_db_info): Add td_thr_tlsbase_p. + (try_thread_db_load_1): Initialize it. + (thread_db_get_thread_local_address): Call it if LM is zero. + * target.c (target_translate_tls_address): Remove LM_ADDR zero check. + * target.h (struct target_ops) (to_get_thread_local_address): Add + load_module_addr comment. + + gdb/gdbserver/ + 2014-05-21 Jan Kratochvil + + Fix TLS access for -static -pthread. + * gdbserver/thread-db.c (struct thread_db): Add td_thr_tlsbase_p. + (thread_db_get_tls_address): Call it if LOAD_MODULE is zero. + (thread_db_load_search, try_thread_db_load_1): Initialize it. + + gdb/testsuite/ + 2014-05-21 Jan Kratochvil + + Fix TLS access for -static -pthread. + * gdb.threads/staticthreads.c (tlsvar): New. + (thread_function, main): Initialize it. + * gdb.threads/staticthreads.exp: Try gdb_compile_pthreads for $have_tls. + Add clean_restart. + <$have_tls != "">: Check TLSVAR. + + Message-ID: <20140410115204.GB16411@host2.jankratochvil.net> + +Index: gdb-7.6.1/gdb/gdbserver/thread-db.c +=================================================================== +--- gdb-7.6.1.orig/gdb/gdbserver/thread-db.c ++++ gdb-7.6.1/gdb/gdbserver/thread-db.c +@@ -88,6 +88,9 @@ struct thread_db + td_err_e (*td_thr_tls_get_addr_p) (const td_thrhandle_t *th, + psaddr_t map_address, + size_t offset, psaddr_t *address); ++ td_err_e (*td_thr_tlsbase_p) (const td_thrhandle_t *th, ++ unsigned long int modid, ++ psaddr_t *base); + const char ** (*td_symbol_list_p) (void); + }; + +@@ -497,7 +500,10 @@ thread_db_get_tls_address (struct thread + if (thread_db == NULL || !thread_db->all_symbols_looked_up) + return TD_ERR; + +- if (thread_db->td_thr_tls_get_addr_p == NULL) ++ /* If td_thr_tls_get_addr is missing rather do not expect td_thr_tlsbase ++ could work. */ ++ if (thread_db->td_thr_tls_get_addr_p == NULL ++ || (load_module == 0 && thread_db->td_thr_tlsbase_p == NULL)) + return -1; + + lwp = get_thread_lwp (thread); +@@ -508,12 +514,28 @@ thread_db_get_tls_address (struct thread + + saved_inferior = current_inferior; + current_inferior = thread; +- /* Note the cast through uintptr_t: this interface only works if +- a target address fits in a psaddr_t, which is a host pointer. +- So a 32-bit debugger can not access 64-bit TLS through this. */ +- err = thread_db->td_thr_tls_get_addr_p (&lwp->th, +- (psaddr_t) (uintptr_t) load_module, +- offset, &addr); ++ ++ if (load_module != 0) ++ { ++ /* Note the cast through uintptr_t: this interface only works if ++ a target address fits in a psaddr_t, which is a host pointer. ++ So a 32-bit debugger can not access 64-bit TLS through this. */ ++ err = thread_db->td_thr_tls_get_addr_p (&lwp->th, ++ (psaddr_t) (uintptr_t) load_module, ++ offset, &addr); ++ } ++ else ++ { ++ /* This code path handles the case of -static -pthread executables: ++ https://sourceware.org/ml/libc-help/2014-03/msg00024.html ++ For older GNU libc r_debug.r_map is NULL. For GNU libc after ++ PR libc/16831 due to GDB PR threads/16954 LOAD_MODULE is also NULL. ++ The constant number 1 depends on GNU __libc_setup_tls ++ initialization of l_tls_modid to 1. */ ++ err = thread_db->td_thr_tlsbase_p (&lwp->th, 1, &addr); ++ addr = (char *) addr + offset; ++ } ++ + current_inferior = saved_inferior; + if (err == TD_OK) + { +@@ -565,6 +587,7 @@ thread_db_load_search (void) + tdb->td_ta_set_event_p = &td_ta_set_event; + tdb->td_ta_event_getmsg_p = &td_ta_event_getmsg; + tdb->td_thr_tls_get_addr_p = &td_thr_tls_get_addr; ++ tdb->td_thr_tlsbase_p = &td_thr_tlsbase; + + return 1; + } +@@ -633,6 +656,7 @@ try_thread_db_load_1 (void *handle) + CHK (0, tdb->td_ta_set_event_p = dlsym (handle, "td_ta_set_event")); + CHK (0, tdb->td_ta_event_getmsg_p = dlsym (handle, "td_ta_event_getmsg")); + CHK (0, tdb->td_thr_tls_get_addr_p = dlsym (handle, "td_thr_tls_get_addr")); ++ CHK (0, tdb->td_thr_tlsbase_p = dlsym (handle, "td_thr_tlsbase")); + + #undef CHK + +Index: gdb-7.6.1/gdb/linux-thread-db.c +=================================================================== +--- gdb-7.6.1.orig/gdb/linux-thread-db.c ++++ gdb-7.6.1/gdb/linux-thread-db.c +@@ -196,6 +196,9 @@ struct thread_db_info + td_err_e (*td_thr_tls_get_addr_p) (const td_thrhandle_t *th, + psaddr_t map_address, + size_t offset, psaddr_t *address); ++ td_err_e (*td_thr_tlsbase_p) (const td_thrhandle_t *th, ++ unsigned long int modid, ++ psaddr_t *base); + }; + + /* List of known processes using thread_db, and the required +@@ -797,6 +800,7 @@ try_thread_db_load_1 (struct thread_db_i + info->td_ta_event_getmsg_p = dlsym (info->handle, "td_ta_event_getmsg"); + info->td_thr_event_enable_p = dlsym (info->handle, "td_thr_event_enable"); + info->td_thr_tls_get_addr_p = dlsym (info->handle, "td_thr_tls_get_addr"); ++ info->td_thr_tlsbase_p = dlsym (info->handle, "td_thr_tlsbase"); + + if (thread_db_find_new_threads_silently (inferior_ptid) != 0) + { +@@ -1798,21 +1802,39 @@ thread_db_get_thread_local_address (stru + + info = get_thread_db_info (GET_PID (ptid)); + +- /* glibc doesn't provide the needed interface. */ +- if (!info->td_thr_tls_get_addr_p) +- throw_error (TLS_NO_LIBRARY_SUPPORT_ERROR, +- _("No TLS library support")); +- +- /* Caller should have verified that lm != 0. */ +- gdb_assert (lm != 0); +- + /* Finally, get the address of the variable. */ +- /* Note the cast through uintptr_t: this interface only works if +- a target address fits in a psaddr_t, which is a host pointer. +- So a 32-bit debugger can not access 64-bit TLS through this. */ +- err = info->td_thr_tls_get_addr_p (&thread_info->private->th, +- (psaddr_t)(uintptr_t) lm, +- offset, &address); ++ if (lm != 0) ++ { ++ /* glibc doesn't provide the needed interface. */ ++ if (!info->td_thr_tls_get_addr_p) ++ throw_error (TLS_NO_LIBRARY_SUPPORT_ERROR, ++ _("No TLS library support")); ++ ++ /* Note the cast through uintptr_t: this interface only works if ++ a target address fits in a psaddr_t, which is a host pointer. ++ So a 32-bit debugger can not access 64-bit TLS through this. */ ++ err = info->td_thr_tls_get_addr_p (&thread_info->private->th, ++ (psaddr_t)(uintptr_t) lm, ++ offset, &address); ++ } ++ else ++ { ++ /* If glibc doesn't provide the needed interface throw an error ++ that LM is zero - normally cases it should not be. */ ++ if (!info->td_thr_tlsbase_p) ++ throw_error (TLS_LOAD_MODULE_NOT_FOUND_ERROR, ++ _("TLS load module not found")); ++ ++ /* This code path handles the case of -static -pthread executables: ++ https://sourceware.org/ml/libc-help/2014-03/msg00024.html ++ For older GNU libc r_debug.r_map is NULL. For GNU libc after ++ PR libc/16831 due to GDB PR threads/16954 LOAD_MODULE is also NULL. ++ The constant number 1 depends on GNU __libc_setup_tls ++ initialization of l_tls_modid to 1. */ ++ err = info->td_thr_tlsbase_p (&thread_info->private->th, ++ 1, &address); ++ address = (char *) address + offset; ++ } + + #ifdef THREAD_DB_HAS_TD_NOTALLOC + /* The memory hasn't been allocated, yet. */ +Index: gdb-7.6.1/gdb/target.c +=================================================================== +--- gdb-7.6.1.orig/gdb/target.c ++++ gdb-7.6.1/gdb/target.c +@@ -1165,10 +1165,6 @@ target_translate_tls_address (struct obj + /* Fetch the load module address for this objfile. */ + lm_addr = gdbarch_fetch_tls_load_module_address (target_gdbarch (), + objfile); +- /* If it's 0, throw the appropriate exception. */ +- if (lm_addr == 0) +- throw_error (TLS_LOAD_MODULE_NOT_FOUND_ERROR, +- _("TLS load module not found")); + + addr = target->to_get_thread_local_address (target, ptid, + lm_addr, offset); +Index: gdb-7.6.1/gdb/target.h +=================================================================== +--- gdb-7.6.1.orig/gdb/target.h ++++ gdb-7.6.1/gdb/target.h +@@ -557,7 +557,8 @@ struct target_ops + thread-local storage for the thread PTID and the shared library + or executable file given by OBJFILE. If that block of + thread-local storage hasn't been allocated yet, this function +- may return an error. */ ++ may return an error. LOAD_MODULE_ADDR may be zero for statically ++ linked multithreaded inferiors. */ + CORE_ADDR (*to_get_thread_local_address) (struct target_ops *ops, + ptid_t ptid, + CORE_ADDR load_module_addr, +Index: gdb-7.6.1/gdb/testsuite/gdb.threads/staticthreads.c +=================================================================== +--- gdb-7.6.1.orig/gdb/testsuite/gdb.threads/staticthreads.c ++++ gdb-7.6.1/gdb/testsuite/gdb.threads/staticthreads.c +@@ -28,10 +28,17 @@ + + sem_t semaphore; + ++#ifdef HAVE_TLS ++__thread int tlsvar; ++#endif ++ + void * + thread_function (void *arg) + { +- printf ("Thread executing\n"); ++#ifdef HAVE_TLS ++ tlsvar = 2; ++#endif ++ printf ("Thread executing\n"); /* tlsvar-is-set */ + while (sem_wait (&semaphore) != 0) + { + if (errno != EINTR) +@@ -57,6 +64,9 @@ main (int argc, char **argv) + return -1; + } + ++#ifdef HAVE_TLS ++ tlsvar = 1; ++#endif + + /* Create a thread, wait for it to complete. */ + { +Index: gdb-7.6.1/gdb/testsuite/gdb.threads/staticthreads.exp +=================================================================== +--- gdb-7.6.1.orig/gdb/testsuite/gdb.threads/staticthreads.exp ++++ gdb-7.6.1/gdb/testsuite/gdb.threads/staticthreads.exp +@@ -22,11 +22,16 @@ + standard_testfile + set static_flag "-static" + +-if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" \ +- executable \ +- [list debug "additional_flags=${static_flag}" \ +- ]] != "" } { +- return -1 ++foreach have_tls { "-DHAVE_TLS" "" } { ++ if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" \ ++ executable \ ++ [list debug "additional_flags=${static_flag} ${have_tls}" \ ++ ]] == "" } { ++ break ++ } ++ if { $have_tls == "" } { ++ return -1 ++ } + } + + clean_restart ${binfile} +@@ -96,3 +101,18 @@ gdb_test_multiple "quit" "$test" { + pass "$test" + } + } ++clean_restart ${binfile} ++ ++ ++if { "$have_tls" != "" } { ++ if ![runto_main] { ++ return -1 ++ } ++ gdb_breakpoint [gdb_get_line_number "tlsvar-is-set"] ++ gdb_continue_to_breakpoint "tlsvar-is-set" ".* tlsvar-is-set .*" ++ gdb_test "p tlsvar" " = 2" "tlsvar in thread" ++ gdb_test "thread 1" ".*" ++ # Unwind from pthread_join. ++ gdb_test "up 10" " in main .*" ++ gdb_test "p tlsvar" " = 1" "tlsvar in main" ++} diff --git a/SOURCES/gdb-rhbz1080657-tls-variable-static-linked-binary-3of3.patch b/SOURCES/gdb-rhbz1080657-tls-variable-static-linked-binary-3of3.patch new file mode 100644 index 0000000..5b5b13b --- /dev/null +++ b/SOURCES/gdb-rhbz1080657-tls-variable-static-linked-binary-3of3.patch @@ -0,0 +1,60 @@ +commit b8b91e982ec3235a24ce052cbd8bb0e4fe1464e0 +Author: Yao Qi +Date: Thu Jun 5 15:07:47 2014 +0800 + + Fix the race in gdb.threads/staticthreads.exp + + The code in gdb.threads/staticthreads.exp about checking the value of + tlsvar in main thread is racy, because when child thread hits + breakpoint, the main thread may not go into pthread_join yet, and + may not be unwind to main. + + This patch is to move the line setting breakpoint on after sem_wait, + so that the child thread will hit breakpoint after main thread calls + sem_post. IOW, when child thread hits breakpoint, the main thread is + in either sem_post or pthread_join. "up 10" can unwind main thread to + main. + + gdb/testsuite: + + 2014-06-06 Yao Qi + + * gdb.threads/staticthreads.c (thread_function): Move the line + setting breakpoint on forward. + * gdb.threads/staticthreads.exp: Update comments. + + Message-ID: <5390387C.7050308@codesourcery.com> + +Index: gdb-7.6.1/gdb/testsuite/gdb.threads/staticthreads.c +=================================================================== +--- gdb-7.6.1.orig/gdb/testsuite/gdb.threads/staticthreads.c ++++ gdb-7.6.1/gdb/testsuite/gdb.threads/staticthreads.c +@@ -38,7 +38,6 @@ thread_function (void *arg) + #ifdef HAVE_TLS + tlsvar = 2; + #endif +- printf ("Thread executing\n"); /* tlsvar-is-set */ + while (sem_wait (&semaphore) != 0) + { + if (errno != EINTR) +@@ -47,6 +46,7 @@ thread_function (void *arg) + return; + } + } ++ printf ("Thread executing\n"); /* tlsvar-is-set */ + return NULL; + } + +Index: gdb-7.6.1/gdb/testsuite/gdb.threads/staticthreads.exp +=================================================================== +--- gdb-7.6.1.orig/gdb/testsuite/gdb.threads/staticthreads.exp ++++ gdb-7.6.1/gdb/testsuite/gdb.threads/staticthreads.exp +@@ -112,7 +112,7 @@ if { "$have_tls" != "" } { + gdb_continue_to_breakpoint "tlsvar-is-set" ".* tlsvar-is-set .*" + gdb_test "p tlsvar" " = 2" "tlsvar in thread" + gdb_test "thread 1" ".*" +- # Unwind from pthread_join. ++ # Unwind to main. + gdb_test "up 10" " in main .*" + gdb_test "p tlsvar" " = 1" "tlsvar in main" + } diff --git a/SOURCES/gdb-rhbz1086894-incomplete-bt-coredump-signal-handler.patch b/SOURCES/gdb-rhbz1086894-incomplete-bt-coredump-signal-handler.patch new file mode 100644 index 0000000..a14fb06 --- /dev/null +++ b/SOURCES/gdb-rhbz1086894-incomplete-bt-coredump-signal-handler.patch @@ -0,0 +1,254 @@ +commit f2205de0080d999c9b67872c9db471c31b53e378 +Author: Hui Zhu +Date: Tue May 20 13:19:06 2014 +0800 + + Fix issue #15778: GDB Aarch64 signal frame unwinder issue + + The root cause of this issue is unwinder of "#3 " + doesn't supply right values of registers. + When GDB want to get the previous frame of "#3 ", + it will call cache init function of unwinder "aarch64_linux_sigframe_init". + The address or the value of the registers is get from this function. + So the bug is inside thie function. + + I check the asm code of "#3 ": + (gdb) frame 3 + (gdb) p $pc + $1 = (void (*)()) 0x7f931fa4d0 + (gdb) disassemble $pc, +10 + Dump of assembler code from 0x7f931fa4d0 to 0x7f931fa4da: + => 0x0000007f931fa4d0: mov x8, #0x8b // #139 + 0x0000007f931fa4d4: svc #0x0 + 0x0000007f931fa4d8: nop + + This is the syscall sys_rt_sigreturn, Linux kernel function "restore_sigframe" + will set the frame: + for (i = 0; i < 31; i++) + __get_user_error(regs->regs[i], &sf->uc.uc_mcontext.regs[i], + err); + __get_user_error(regs->sp, &sf->uc.uc_mcontext.sp, err); + __get_user_error(regs->pc, &sf->uc.uc_mcontext.pc, err); + The struct of uc_mcontext is: + struct sigcontext { + __u64 fault_address; + /* AArch64 registers */ + __u64 regs[31]; + __u64 sp; + __u64 pc; + __u64 pstate; + /* 4K reserved for FP/SIMD state and future expansion */ + __u8 __reserved[4096] __attribute__((__aligned__(16))); + }; + + But in GDB function "aarch64_linux_sigframe_init", the code the get address + of registers is: + for (i = 0; i < 31; i++) + { + trad_frame_set_reg_addr (this_cache, + AARCH64_X0_REGNUM + i, + sigcontext_addr + AARCH64_SIGCONTEXT_XO_OFFSET + + i * AARCH64_SIGCONTEXT_REG_SIZE); + } + + trad_frame_set_reg_addr (this_cache, AARCH64_FP_REGNUM, fp); + trad_frame_set_reg_addr (this_cache, AARCH64_LR_REGNUM, fp + 8); + trad_frame_set_reg_addr (this_cache, AARCH64_PC_REGNUM, fp + 8); + + The code that get pc and sp is not right, so I change the code according + to Linux kernel code: + trad_frame_set_reg_addr (this_cache, AARCH64_SP_REGNUM, + sigcontext_addr + AARCH64_SIGCONTEXT_XO_OFFSET + + 31 * AARCH64_SIGCONTEXT_REG_SIZE); + trad_frame_set_reg_addr (this_cache, AARCH64_PC_REGNUM, + sigcontext_addr + AARCH64_SIGCONTEXT_XO_OFFSET + + 32 * AARCH64_SIGCONTEXT_REG_SIZE); + + The issue was fixed by this change, and I did the regression test. It + also fixed a lot of other XFAIL and FAIL. + + 2014-05-20 Hui Zhu + Yao Qi + + PR backtrace/16558 + * aarch64-linux-tdep.c (aarch64_linux_sigframe_init): Update comments + and change address of sp and pc. + +Index: gdb-7.6.1/gdb/aarch64-linux-tdep.c +=================================================================== +--- gdb-7.6.1.orig/gdb/aarch64-linux-tdep.c ++++ gdb-7.6.1/gdb/aarch64-linux-tdep.c +@@ -47,28 +47,30 @@ + + /* Signal frame handling. + +- +----------+ ^ +- | saved lr | | +- +->| saved fp |--+ +- | | | +- | | | +- | +----------+ +- | | saved lr | +- +--| saved fp | +- ^ | | +- | | | +- | +----------+ +- ^ | | +- | | signal | +- | | | +- | | saved lr |-->interrupted_function_pc +- +--| saved fp | +- | +----------+ +- | | saved lr |--> default_restorer (movz x8, NR_sys_rt_sigreturn; svc 0) +- +--| saved fp |<- FP +- | | +- | |<- SP +- +----------+ ++ +------------+ ^ ++ | saved lr | | ++ +->| saved fp |--+ ++ | | | ++ | | | ++ | +------------+ ++ | | saved lr | ++ +--| saved fp | ++ ^ | | ++ | | | ++ | +------------+ ++ ^ | | ++ | | signal | ++ | | | SIGTRAMP_FRAME (struct rt_sigframe) ++ | | saved regs | ++ +--| saved sp |--> interrupted_sp ++ | | saved pc |--> interrupted_pc ++ | | | ++ | +------------+ ++ | | saved lr |--> default_restorer (movz x8, NR_sys_rt_sigreturn; svc 0) ++ +--| saved fp |<- FP ++ | | NORMAL_FRAME ++ | |<- SP ++ +------------+ + + On signal delivery, the kernel will create a signal handler stack + frame and setup the return address in LR to point at restorer stub. +@@ -117,6 +119,8 @@ + d28015a8 movz x8, #0xad + d4000001 svc #0x0 + ++ This is a system call sys_rt_sigreturn. ++ + We detect signal frames by snooping the return code for the restorer + instruction sequence. + +@@ -140,7 +144,6 @@ aarch64_linux_sigframe_init (const struc + { + struct gdbarch *gdbarch = get_frame_arch (this_frame); + CORE_ADDR sp = get_frame_register_unsigned (this_frame, AARCH64_SP_REGNUM); +- CORE_ADDR fp = get_frame_register_unsigned (this_frame, AARCH64_FP_REGNUM); + CORE_ADDR sigcontext_addr = + sp + + AARCH64_RT_SIGFRAME_UCONTEXT_OFFSET +@@ -154,12 +157,14 @@ aarch64_linux_sigframe_init (const struc + sigcontext_addr + AARCH64_SIGCONTEXT_XO_OFFSET + + i * AARCH64_SIGCONTEXT_REG_SIZE); + } ++ trad_frame_set_reg_addr (this_cache, AARCH64_SP_REGNUM, ++ sigcontext_addr + AARCH64_SIGCONTEXT_XO_OFFSET ++ + 31 * AARCH64_SIGCONTEXT_REG_SIZE); ++ trad_frame_set_reg_addr (this_cache, AARCH64_PC_REGNUM, ++ sigcontext_addr + AARCH64_SIGCONTEXT_XO_OFFSET ++ + 32 * AARCH64_SIGCONTEXT_REG_SIZE); + +- trad_frame_set_reg_addr (this_cache, AARCH64_FP_REGNUM, fp); +- trad_frame_set_reg_addr (this_cache, AARCH64_LR_REGNUM, fp + 8); +- trad_frame_set_reg_addr (this_cache, AARCH64_PC_REGNUM, fp + 8); +- +- trad_frame_set_id (this_cache, frame_id_build (fp, func)); ++ trad_frame_set_id (this_cache, frame_id_build (sp, func)); + } + + static const struct tramp_frame aarch64_linux_rt_sigframe = +Index: gdb-7.6.1/gdb/testsuite/gdb.arch/aarch64-rhbz1086894-bt-signal-handler.exp +=================================================================== +--- /dev/null ++++ gdb-7.6.1/gdb/testsuite/gdb.arch/aarch64-rhbz1086894-bt-signal-handler.exp +@@ -0,0 +1,35 @@ ++# Copyright (C) 2014 Free Software Foundation, Inc. ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++# Internal testing for RHEL-7.1. ++ ++standard_testfile ++ ++if { ![istarget "aarch64*"] } { ++ verbose "Skipping $testfile" ++ return ++} ++ ++if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile}] } { ++ return -1 ++} ++ ++if ![runto_main] { ++ return -1 ++} ++ ++gdb_test "continue" "Continuing.\r\n\r\nProgram received signal SIGSEGV.*" "run until SIGSEGV" ++ ++gdb_test "backtrace" "#$decimal\\s+$hex in pause .*from.*" "backtrace on signal handler" +Index: gdb-7.6.1/gdb/testsuite/gdb.arch/aarch64-rhbz1086894-bt-signal-handler.c +=================================================================== +--- /dev/null ++++ gdb-7.6.1/gdb/testsuite/gdb.arch/aarch64-rhbz1086894-bt-signal-handler.c +@@ -0,0 +1,40 @@ ++/* Copyright 2014 Free Software Foundation, Inc. ++ ++ This file is part of GDB. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . */ ++ ++/* Internal test for RHEL-7.1. */ ++ ++#include ++#include ++#include ++#include ++ ++static void ++handle_alrm(int signo) ++{ ++ kill (getpid (), SIGSEGV); ++ assert (0); ++} ++ ++int ++main (int argc, char *argv[]) ++{ ++ signal (SIGALRM, handle_alrm); ++ alarm (1); ++ pause (); ++ assert (0); ++ return 0; ++} diff --git a/SOURCES/gdb-rhbz1093259-aarch64-single-step-atomic-seq.patch b/SOURCES/gdb-rhbz1093259-aarch64-single-step-atomic-seq.patch new file mode 100644 index 0000000..b5fcb5e --- /dev/null +++ b/SOURCES/gdb-rhbz1093259-aarch64-single-step-atomic-seq.patch @@ -0,0 +1,258 @@ +All attempts: + + - + Message-ID: <20140324161056.GB23291@redacted.bos.redhat.com> + + - + Message-ID: <20140327015125.GE3075@redacted.bos.redhat.com> + (see below) + + - + Message-ID: <20140422165542.GA748@redacted.bos.redhat.com> + + - + Message-ID: <20140424183510.GI7588@redacted.bos.redhat.com> + + - + Message-ID: <20140430160450.GE2148@redacted.bos.redhat.com> + (last version, applied) + + +Second message from Kyle, which seems complete enough. + + Date: Wed, 26 Mar 2014 21:51:26 -0400 + From: Kyle McMartin + To: gdb-patches at sourceware dot org + Subject: [PATCHv2] aarch64: detect atomic sequences like other ll/sc architectures + Message-ID: <20140327015125.GE3075@redacted.bos.redhat.com> + + Add similar single-stepping over atomic sequences support like other + load-locked/store-conditional architectures (alpha, powerpc, arm, etc.) + do. Verified the decode_masked_match, and decode_bcond works against the + atomic sequences used in the Linux kernel atomic.h, and also gcc + libatomic. Thanks to Richard Henderson for feedback on my initial + attempt at this patch, and for the feedback from gdb-patches, which I + hope I've addressed... + + + +commit 9404b58f46328b3b171b0d5eeb0691bd685bc4f5 +Author: Kyle McMartin +Date: Wed Apr 30 12:04:50 2014 -0400 + + aarch64: detect atomic sequences like other ll/sc architectures + + gdb/Changelog: + + * aarch64-tdep.c (aarch64_software_single_step): New function. + (aarch64_gdbarch_init): Handle single stepping of atomic sequences + with aarch64_software_single_step. + + gdb/testsuite/ChangeLog: + + * gdb.arch/aarch64-atomic-inst.c: New file. + * gdb.arch/aarch64-atomic-inst.exp: New file. + +Index: gdb-7.6.1/gdb/aarch64-tdep.c +=================================================================== +--- gdb-7.6.1.orig/gdb/aarch64-tdep.c ++++ gdb-7.6.1/gdb/aarch64-tdep.c +@@ -2518,6 +2518,84 @@ value_of_aarch64_user_reg (struct frame_ + } + + ++/* Implement the "software_single_step" gdbarch method, needed to ++ single step through atomic sequences on AArch64. */ ++ ++static int ++aarch64_software_single_step (struct frame_info *frame) ++{ ++ struct gdbarch *gdbarch = get_frame_arch (frame); ++ struct address_space *aspace = get_frame_address_space (frame); ++ enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch); ++ const int insn_size = 4; ++ const int atomic_sequence_length = 16; /* Instruction sequence length. */ ++ CORE_ADDR pc = get_frame_pc (frame); ++ CORE_ADDR breaks[2] = { -1, -1 }; ++ CORE_ADDR loc = pc; ++ CORE_ADDR closing_insn = 0; ++ uint32_t insn = read_memory_unsigned_integer (loc, insn_size, ++ byte_order_for_code); ++ int index; ++ int insn_count; ++ int bc_insn_count = 0; /* Conditional branch instruction count. */ ++ int last_breakpoint = 0; /* Defaults to 0 (no breakpoints placed). */ ++ ++ /* Look for a Load Exclusive instruction which begins the sequence. */ ++ if (!decode_masked_match (insn, 0x3fc00000, 0x08400000)) ++ return 0; ++ ++ for (insn_count = 0; insn_count < atomic_sequence_length; ++insn_count) ++ { ++ int32_t offset; ++ unsigned cond; ++ ++ loc += insn_size; ++ insn = read_memory_unsigned_integer (loc, insn_size, ++ byte_order_for_code); ++ ++ /* Check if the instruction is a conditional branch. */ ++ if (decode_bcond (loc, insn, &cond, &offset)) ++ { ++ if (bc_insn_count >= 1) ++ return 0; ++ ++ /* It is, so we'll try to set a breakpoint at the destination. */ ++ breaks[1] = loc + offset; ++ ++ bc_insn_count++; ++ last_breakpoint++; ++ } ++ ++ /* Look for the Store Exclusive which closes the atomic sequence. */ ++ if (decode_masked_match (insn, 0x3fc00000, 0x08000000)) ++ { ++ closing_insn = loc; ++ break; ++ } ++ } ++ ++ /* We didn't find a closing Store Exclusive instruction, fall back. */ ++ if (!closing_insn) ++ return 0; ++ ++ /* Insert breakpoint after the end of the atomic sequence. */ ++ breaks[0] = loc + insn_size; ++ ++ /* Check for duplicated breakpoints, and also check that the second ++ breakpoint is not within the atomic sequence. */ ++ if (last_breakpoint ++ && (breaks[1] == breaks[0] ++ || (breaks[1] >= pc && breaks[1] <= closing_insn))) ++ last_breakpoint = 0; ++ ++ /* Insert the breakpoint at the end of the sequence, and one at the ++ destination of the conditional branch, if it exists. */ ++ for (index = 0; index <= last_breakpoint; index++) ++ insert_single_step_breakpoint (gdbarch, aspace, breaks[index]); ++ ++ return 1; ++} ++ + /* Initialize the current architecture based on INFO. If possible, + re-use an architecture from ARCHES, which is a list of + architectures already created during this debugging session. +@@ -2635,6 +2713,7 @@ aarch64_gdbarch_init (struct gdbarch_inf + set_gdbarch_breakpoint_from_pc (gdbarch, aarch64_breakpoint_from_pc); + set_gdbarch_cannot_step_breakpoint (gdbarch, 1); + set_gdbarch_have_nonsteppable_watchpoint (gdbarch, 1); ++ set_gdbarch_software_single_step (gdbarch, aarch64_software_single_step); + + /* Information about registers, etc. */ + set_gdbarch_sp_regnum (gdbarch, AARCH64_SP_REGNUM); +Index: gdb-7.6.1/gdb/testsuite/gdb.arch/aarch64-atomic-inst.c +=================================================================== +--- /dev/null ++++ gdb-7.6.1/gdb/testsuite/gdb.arch/aarch64-atomic-inst.c +@@ -0,0 +1,48 @@ ++/* This file is part of GDB, the GNU debugger. ++ ++ Copyright 2008-2014 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . */ ++ ++int main(void) ++{ ++ unsigned long tmp, cond; ++ unsigned long dword = 0; ++ ++ /* Test that we can step over ldxr/stxr. This sequence should step from ++ ldxr to the following __asm __volatile. */ ++ __asm __volatile ("1: ldxr %0,%2\n" \ ++ " cmp %0,#1\n" \ ++ " b.eq out\n" \ ++ " add %0,%0,1\n" \ ++ " stxr %w1,%0,%2\n" \ ++ " cbnz %w1,1b" \ ++ : "=&r" (tmp), "=&r" (cond), "+Q" (dword) \ ++ : : "memory"); ++ ++ /* This sequence should take the conditional branch and step from ldxr ++ to the return dword line. */ ++ __asm __volatile ("1: ldxr %0,%2\n" \ ++ " cmp %0,#1\n" \ ++ " b.eq out\n" \ ++ " add %0,%0,1\n" \ ++ " stxr %w1,%0,%2\n" \ ++ " cbnz %w1,1b\n" \ ++ : "=&r" (tmp), "=&r" (cond), "+Q" (dword) \ ++ : : "memory"); ++ ++ dword = -1; ++__asm __volatile ("out:\n"); ++ return dword; ++} +Index: gdb-7.6.1/gdb/testsuite/gdb.arch/aarch64-atomic-inst.exp +=================================================================== +--- /dev/null ++++ gdb-7.6.1/gdb/testsuite/gdb.arch/aarch64-atomic-inst.exp +@@ -0,0 +1,48 @@ ++# Copyright 2008-2014 Free Software Foundation, Inc. ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++# ++# This file is part of the gdb testsuite. ++ ++# Test single stepping through atomic sequences beginning with ++# a ldxr instruction and ending with a stxr instruction. ++ ++if {![istarget "aarch64*"]} { ++ verbose "Skipping ${gdb_test_file_name}." ++ return ++} ++ ++standard_testfile ++if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile}] } { ++ return -1 ++} ++ ++if ![runto_main] { ++ untested "could not run to main" ++ return -1 ++} ++ ++gdb_breakpoint "[gdb_get_line_number "ldxr"]" \ ++ "Breakpoint $decimal at $hex" \ ++ "Set the breakpoint at the start of the sequence" ++ ++gdb_test "continue" "Continuing.*Breakpoint $decimal.*" \ ++ "Continue until breakpoint" ++ ++gdb_test "next" ".*__asm __volatile.*" \ ++ "Step through the ldxr/stxr sequence" ++ ++gdb_test "next" ".*return dword.*" \ ++ "Stepped through sequence through conditional branch" diff --git a/SOURCES/gdb-rhbz1103894-slow-gstack-performance.patch b/SOURCES/gdb-rhbz1103894-slow-gstack-performance.patch new file mode 100644 index 0000000..a3e75c8 --- /dev/null +++ b/SOURCES/gdb-rhbz1103894-slow-gstack-performance.patch @@ -0,0 +1,352 @@ + + +Date: Thu, 2 Oct 2014 17:56:53 +0200 +From: Jan Kratochvil +To: Doug Evans +Cc: gdb-patches at sourceware dot org +Subject: [patchv2] Fix 100x slowdown regression on DWZ files +Message-ID: <20141002155653.GA9001@host2.jankratochvil.net> + + +--cNdxnHkX5QqsyA0e +Content-Type: text/plain; charset=us-ascii +Content-Disposition: inline + +On Thu, 02 Oct 2014 01:51:38 +0200, Doug Evans wrote: +> I tested this patch with --target_board=dwarf4-gdb-index +> and got a failure in m-static.exp: + +That is particularly with -fdebug-types-section. + + +> Type units read the line table in a separate path, + +OK, therefore I dropped that separate struct dwarf2_lineinfo +and reused struct line_header instead. + + +> OTOH, I do want to avoid any confusion that this patch may inadvertently +> introduce. For example, IIUC with your patch as is, +> if we read a partial_unit first, before a compile_unit +> that has the same stmt_list value, we'll do more processing in +> dwarf_decode_lines than we really need to since we only need a file +> number to symtab mapping. And if we later read in a compile_unit +> with the same stmt_value we'll call dwarf_decode_lines again, +> and this time we need the pc/line mapping it computes. +> Whereas if we process these in the opposite order we'll only call +> dwarf_decode_lines once. I'm sure this will be confusing at first +> to some later developer going through this code. +> [I could be missing something of course, and I'm happy for any corrections.] + +Implemented (omitting some story why I did not include it before). + + +> The code that processes stmt_list for type_units is in setup_type_unit_groups. +> Note that this code goes to the trouble of re-initializing the buildsym +> machinery (see the calls to restart_symtab in dwarf2read.c) when we process +> the second and subsequent type units that share a stmt_list value. +> This is something that used to be done before your patch and will no +> longer be done with your patch (since if we get a cache hit we exit). +> It may be that the type_unit support is doing this unnecessarily, +> which would be great because we can then simplify it. + +I hope this patch should no longer break -fdebug-types-section. +If it additionally enables some future optimization for -fdebug-types-section +the better. + + +> > + /* Offset of line number information in .debug_line section. */ +> > + sect_offset offset; +> > + unsigned offset_in_dwz : 1; +> +> IWBN to document why offset_in_dwz is here. +> It's not obvious why it's needed. ++ +On Thu, 02 Oct 2014 01:57:03 +0200, Doug Evans wrote: +> Ah, I guess the offset_in_dwz flag will ensure dwarf_decode_lines gets called +> twice regardless of order. But is that the only reason for the flag? + +I have added there now: ++ /* OFFSET is for struct dwz_file associated with dwarf2_per_objfile. */ + +If one removes it regressions really happen. What happens is that this +line_header_hash (former lineinfo_hash) is in struct dwarf2_per_objfile which +is common for both objfile and its objfile.dwz (that one is normally in +/usr/lib/debug/.dwz/ - common for multiple objfiles). And there are two +different DIEs at offset 0xb - one in objfile and one in objfile.dwz - which +would match single line_header if offset_in_dwz was not there. + +Also existing dwarf2read.c code usually transfers "dwz flag" together with DIE +offset, such as: + dwarf2_find_containing_comp_unit (sect_offset offset, + unsigned int offset_in_dwz, + struct objfile *objfile) +This reminds me - why doesn't similar ambiguity happen also for dwp_file? +I am unfortunately not much aware of the dwp implementation details. + + +> > - struct line_header *line_header +> > - = dwarf_decode_line_header (line_offset, cu); +> > + dwarf2_per_objfile->lineinfo_hash = +> +> As much as I prefer "=" going here, convention says to put it on the +> next line. + +I have changed it but this was just blind copy from existing line 21818. + + +> > + htab_create_alloc_ex (127, dwarf2_lineinfo_hash, dwarf2_lineinfo_eq, +> +> I don't have any data, but 127 seems high. + +I have not changed it but this was just blind copy from existing line 21818. + + +> I wouldn't change it, I just wanted to ask if you have any data +> guiding this choice. + +Tuning some constants really makes no sense when GDB has missing + insanely +complicated data structures and in consequence GDB is using inappropriate data +structures with bad algorithmic complexity. One needs to switch GDB to C++ +and its STL before one can start talking about data structures performance. + + +No regressions on {x86_64,x86_64-m32,i686}-fedora20-linux-gnu in DWZ mode and +in -fdebug-types-section mode. + + +Thanks, +Jan + +--cNdxnHkX5QqsyA0e +Content-Type: text/plain; charset=us-ascii +Content-Disposition: inline; filename="partialunit5.patch" + +gdb/ +2014-10-02 Jan Kratochvil + + Fix 100x slowdown regression on DWZ files. + * dwarf2read.c (struct dwarf2_per_objfile): Add line_header_hash. + (struct line_header): Add offset and offset_in_dwz. + (dwarf_decode_lines): Add parameter decode_mapping to the declaration. + (free_line_header_voidp): New declaration. + (line_header_hash, line_header_eq): New functions. + (dwarf2_build_include_psymtabs): Update dwarf_decode_lines caller. + (handle_DW_AT_stmt_list): Use dwarf2_per_objfile->line_header_hash. + (free_line_header_voidp): New function. + (dwarf_decode_line_header): Initialize offset and offset_in_dwz. + (dwarf_decode_lines): New parameter decode_mapping, use it. + +Index: gdb-7.6.1/gdb/dwarf2read.c +=================================================================== +--- gdb-7.6.1.orig/gdb/dwarf2read.c ++++ gdb-7.6.1/gdb/dwarf2read.c +@@ -272,6 +272,9 @@ struct dwarf2_per_objfile + + /* The CUs we recently read. */ + VEC (dwarf2_per_cu_ptr) *just_read_cus; ++ ++ /* Table containing line_header indexed by offset and offset_in_dwz. */ ++ htab_t line_header_hash; + }; + + static struct dwarf2_per_objfile *dwarf2_per_objfile; +@@ -861,6 +864,12 @@ typedef void (die_reader_func_ftype) (co + which contains the following information. */ + struct line_header + { ++ /* Offset of line number information in .debug_line section. */ ++ sect_offset offset; ++ ++ /* OFFSET is for struct dwz_file associated with dwarf2_per_objfile. */ ++ unsigned offset_in_dwz : 1; ++ + unsigned int total_length; + unsigned short version; + unsigned int header_length; +@@ -1413,7 +1422,7 @@ static struct line_header *dwarf_decode_ + + static void dwarf_decode_lines (struct line_header *, const char *, + struct dwarf2_cu *, struct partial_symtab *, +- int); ++ int, int decode_mapping); + + static void dwarf2_start_subfile (char *, const char *, const char *); + +@@ -1746,6 +1755,8 @@ static void process_cu_includes (void); + + static void check_producer (struct dwarf2_cu *cu); + ++static void free_line_header_voidp (void *arg); ++ + #if WORDS_BIGENDIAN + + /* Convert VALUE between big- and little-endian. */ +@@ -2141,6 +2152,29 @@ dwarf2_get_dwz_file (void) + dwarf2_per_objfile->dwz_file = result; + return result; + } ++ ++/* Hash function for line_header_hash. */ ++ ++static hashval_t ++line_header_hash (const void *item) ++{ ++ const struct line_header *ofs = item; ++ ++ return ofs->offset.sect_off ^ ofs->offset_in_dwz; ++} ++ ++/* Equality function for line_header_hash. */ ++ ++static int ++line_header_eq (const void *item_lhs, const void *item_rhs) ++{ ++ const struct line_header *ofs_lhs = item_lhs; ++ const struct line_header *ofs_rhs = item_rhs; ++ ++ return (ofs_lhs->offset.sect_off == ofs_rhs->offset.sect_off ++ && ofs_lhs->offset_in_dwz == ofs_rhs->offset_in_dwz); ++} ++ + + /* DWARF quick_symbols_functions support. */ + +@@ -4139,7 +4173,7 @@ dwarf2_build_include_psymtabs (struct dw + return; /* No linetable, so no includes. */ + + /* NOTE: pst->dirname is DW_AT_comp_dir (if present). */ +- dwarf_decode_lines (lh, pst->dirname, cu, pst, 1); ++ dwarf_decode_lines (lh, pst->dirname, cu, pst, 1, 1); + + free_line_header (lh); + } +@@ -7969,24 +8003,64 @@ static void + handle_DW_AT_stmt_list (struct die_info *die, struct dwarf2_cu *cu, + const char *comp_dir) + { ++ struct objfile *objfile = dwarf2_per_objfile->objfile; + struct attribute *attr; ++ unsigned int line_offset; ++ struct line_header *line_header, line_header_local; ++ unsigned u; ++ void **slot; ++ int decode_mapping; + + gdb_assert (! cu->per_cu->is_debug_types); + + attr = dwarf2_attr (die, DW_AT_stmt_list, cu); +- if (attr) ++ if (attr == NULL) ++ return; ++ ++ line_offset = DW_UNSND (attr); ++ ++ if (dwarf2_per_objfile->line_header_hash == NULL) + { +- unsigned int line_offset = DW_UNSND (attr); +- struct line_header *line_header +- = dwarf_decode_line_header (line_offset, cu); +- +- if (line_header) +- { +- cu->line_header = line_header; +- make_cleanup (free_cu_line_header, cu); +- dwarf_decode_lines (line_header, comp_dir, cu, NULL, 1); +- } ++ dwarf2_per_objfile->line_header_hash ++ = htab_create_alloc_ex (127, line_header_hash, line_header_eq, ++ free_line_header_voidp, ++ &objfile->objfile_obstack, ++ hashtab_obstack_allocate, ++ dummy_obstack_deallocate); ++ } ++ ++ line_header_local.offset.sect_off = line_offset; ++ line_header_local.offset_in_dwz = cu->per_cu->is_dwz; ++ slot = htab_find_slot (dwarf2_per_objfile->line_header_hash, ++ &line_header_local, NO_INSERT); ++ ++ /* For DW_TAG_compile_unit we need info like symtab::linetable which ++ is not present in *SLOT. */ ++ if (die->tag == DW_TAG_partial_unit && slot != NULL) ++ { ++ gdb_assert (*slot != NULL); ++ cu->line_header = *slot; ++ return; ++ } ++ ++ line_header = dwarf_decode_line_header (line_offset, cu); ++ if (line_header == NULL) ++ return; ++ cu->line_header = line_header; ++ ++ slot = htab_find_slot (dwarf2_per_objfile->line_header_hash, ++ &line_header_local, INSERT); ++ gdb_assert (slot != NULL); ++ if (*slot == NULL) ++ *slot = line_header; ++ else ++ { ++ gdb_assert (die->tag != DW_TAG_partial_unit); ++ make_cleanup (free_cu_line_header, cu); + } ++ decode_mapping = (die->tag != DW_TAG_partial_unit); ++ dwarf_decode_lines (line_header, comp_dir, cu, NULL, 1, ++ decode_mapping); + } + + /* Process DW_TAG_compile_unit or DW_TAG_partial_unit. */ +@@ -15203,6 +15277,16 @@ free_line_header (struct line_header *lh + xfree (lh); + } + ++/* Stub for free_line_header to match void * callback types. */ ++ ++static void ++free_line_header_voidp (void *arg) ++{ ++ struct line_header *lh = arg; ++ ++ free_line_header (lh); ++} ++ + /* Add an entry to LH's include directory table. */ + + static void +@@ -15333,6 +15417,9 @@ dwarf_decode_line_header (unsigned int o + back_to = make_cleanup ((make_cleanup_ftype *) free_line_header, + (void *) lh); + ++ lh->offset.sect_off = offset; ++ lh->offset_in_dwz = cu->per_cu->is_dwz; ++ + line_ptr = section->buffer + offset; + + /* Read in the header. */ +@@ -15826,18 +15913,22 @@ dwarf_decode_lines_1 (struct line_header + as the corresponding symtab. Since COMP_DIR is not used in the name of the + symtab we don't use it in the name of the psymtabs we create. + E.g. expand_line_sal requires this when finding psymtabs to expand. +- A good testcase for this is mb-inline.exp. */ ++ A good testcase for this is mb-inline.exp. ++ ++ Boolean DECODE_MAPPING specifies we need to fully decode .debug_line ++ for its PC<->lines mapping information. Otherwise only filenames ++ tables is read in. */ + + static void + dwarf_decode_lines (struct line_header *lh, const char *comp_dir, + struct dwarf2_cu *cu, struct partial_symtab *pst, +- int want_line_info) ++ int want_line_info, int decode_mapping) + { + struct objfile *objfile = cu->objfile; + const int decode_for_pst_p = (pst != NULL); + struct subfile *first_subfile = current_subfile; + +- if (want_line_info) ++ if (want_line_info && decode_mapping) + dwarf_decode_lines_1 (lh, comp_dir, cu, pst); + + if (decode_for_pst_p) diff --git a/SOURCES/gdb-rhbz1125820-ppc64le-enablement-01of37.patch b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-01of37.patch new file mode 100644 index 0000000..6474d6b --- /dev/null +++ b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-01of37.patch @@ -0,0 +1,237 @@ +commit d81e75c0756f21d2c3d45ce86d8b45c65f01ef67 +Author: Tiago Daitx +Date: Mon Apr 1 04:05:35 2013 +0000 + + gdb/ChangeLog + 2013-03-01 Tiago Stürmer Daitx + + * ppc-sysv-tdep.c (ppc64_sysv_abi_push_float): New function. + (ppc64_sysv_abi_push_dummy_call): Handle complex arguments. + +Index: gdb-7.6.1/gdb/ppc-sysv-tdep.c +=================================================================== +--- gdb-7.6.1.orig/gdb/ppc-sysv-tdep.c ++++ gdb-7.6.1/gdb/ppc-sysv-tdep.c +@@ -1101,6 +1101,83 @@ convert_code_addr_to_desc_addr (CORE_ADD + return 1; + } + ++/* Push a float in either registers, or in the stack. Using the ppc 64 bit ++ SysV ABI. ++ ++ 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_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) ++{ ++ gdb_byte regval[MAX_REGISTER_SIZE]; ++ const gdb_byte *p; ++ ++ if (TYPE_LENGTH (type) <= 8) ++ { ++ /* Version 1.7 of the 64-bit PowerPC ELF ABI says: ++ ++ "Single precision floating point values are mapped to ++ the first word in a single doubleword." ++ ++ And version 1.9 says: ++ ++ "Single precision floating point values are mapped to ++ the second word in a single doubleword." ++ ++ GDB then writes single precision floating point values ++ at both words in a doubleword, to support both ABIs. */ ++ if (TYPE_LENGTH (type) == 4) ++ { ++ memcpy (regval, val, 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); ++ ++ /* Floats and Doubles go in f1 .. f13. They also consume a left aligned ++ GREG, and can end up in memory. */ ++ if (freg <= 13) ++ { ++ struct type *regtype; ++ ++ 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); ++ } ++ if (greg <= 10) ++ regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + greg, regval); ++ } ++ else ++ { ++ /* IBM long double stored in two doublewords of the ++ parameter save area and corresponding registers. */ ++ if (!tdep->soft_float && freg <= 13) ++ { ++ regcache_cooked_write (regcache, tdep->ppc_fp0_regnum + freg, val); ++ if (freg <= 12) ++ regcache_cooked_write (regcache, tdep->ppc_fp0_regnum + freg + 1, ++ val + 8); ++ } ++ if (greg <= 10) ++ { ++ regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + greg, val); ++ if (greg <= 9) ++ regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + greg + 1, ++ val + 8); ++ } ++ write_memory (gparam, val, TYPE_LENGTH (type)); ++ } ++} ++ + /* Pass the arguments in either registers, or in the stack. Using the + ppc 64 bit SysV ABI. + +@@ -1218,53 +1295,9 @@ ppc64_sysv_abi_push_dummy_call (struct g + + if (TYPE_CODE (type) == TYPE_CODE_FLT && TYPE_LENGTH (type) <= 8) + { +- /* Floats and Doubles go in f1 .. f13. They also +- consume a left aligned GREG,, and can end up in +- memory. */ + if (write_pass) +- { +- gdb_byte regval[MAX_REGISTER_SIZE]; +- const gdb_byte *p; +- +- /* Version 1.7 of the 64-bit PowerPC ELF ABI says: +- +- "Single precision floating point values are mapped to +- the first word in a single doubleword." +- +- And version 1.9 says: +- +- "Single precision floating point values are mapped to +- the second word in a single doubleword." +- +- GDB then writes single precision floating point values +- at both words in a doubleword, to support both ABIs. */ +- if (TYPE_LENGTH (type) == 4) +- { +- memcpy (regval, val, 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) +- { +- 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); +- } +- if (greg <= 10) +- regcache_cooked_write (regcache, +- tdep->ppc_gp0_regnum + greg, +- regval); +- } ++ ppc64_sysv_abi_push_float (gdbarch, regcache, tdep, type, ++ val, freg, greg, gparam); + + freg++; + greg++; +@@ -1276,35 +1309,58 @@ ppc64_sysv_abi_push_dummy_call (struct g + && (gdbarch_long_double_format (gdbarch) + == floatformats_ibm_long_double)) + { +- /* IBM long double stored in two doublewords of the +- parameter save area and corresponding registers. */ + 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 (!tdep->soft_float && freg <= 13) +- { +- regcache_cooked_write (regcache, +- tdep->ppc_fp0_regnum + freg, +- val); +- if (freg <= 12) +- regcache_cooked_write (regcache, +- tdep->ppc_fp0_regnum + freg + 1, +- val + 8); +- } +- if (greg <= 10) ++ if (write_pass) + { +- 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); ++ 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); + } +- write_memory (gparam, val, TYPE_LENGTH (type)); ++ 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); + } +- freg += 2; +- greg += 2; +- gparam = align_up (gparam + TYPE_LENGTH (type), tdep->wordsize); + } + else if (TYPE_CODE (type) == TYPE_CODE_DECFLOAT + && TYPE_LENGTH (type) <= 8) diff --git a/SOURCES/gdb-rhbz1125820-ppc64le-enablement-02of37.patch b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-02of37.patch new file mode 100644 index 0000000..319a85e --- /dev/null +++ b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-02of37.patch @@ -0,0 +1,34 @@ +commit 49926cd0c84887c581110fb2a471b21ff19048d2 +Author: Alan Modra +Date: Thu Apr 25 13:22:52 2013 +0000 + + bfd/ + * config.bfd: Add powerpc64le-linux. + gas/ + * configure.in: Allow little-endian linux. + * configure: Regenerate. + gold/ + * configure.tgt: Add powerpcle and powerpc64le. + ld/ + * Makefile.am (ALL_EMULATION_SOURCES): Add eelf32lppclinux.c. + (eelf32lppclinux.c): New rule. + * Makefile.in: Regenerate. + * configure.tgt: Merge powerpc-linux and other powerpc-elf targets + with corresponding little-endian targets. + * emulparams/elf32lppc.sh: Update comment. + * emulparams/elf32lppclinux.sh: New. + +Index: gdb-7.6.1/bfd/config.bfd +=================================================================== +--- gdb-7.6.1.orig/bfd/config.bfd ++++ gdb-7.6.1/bfd/config.bfd +@@ -1242,7 +1242,8 @@ case "${targ}" in + targ_selvecs="bfd_elf64_powerpcle_vec bfd_elf32_powerpc_vec bfd_elf32_powerpcle_vec rs6000coff_vec rs6000coff64_vec aix5coff64_vec" + want64=true + ;; +- powerpc64le-*-elf* | powerpcle-*-elf64*) ++ powerpc64le-*-elf* | powerpcle-*-elf64* | powerpc64le-*-linux* | \ ++ powerpc64le-*-*bsd*) + targ_defvec=bfd_elf64_powerpcle_vec + targ_selvecs="bfd_elf64_powerpc_vec bfd_elf32_powerpcle_vec bfd_elf32_powerpc_vec rs6000coff_vec rs6000coff64_vec aix5coff64_vec" + want64=true diff --git a/SOURCES/gdb-rhbz1125820-ppc64le-enablement-03of37.patch b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-03of37.patch new file mode 100644 index 0000000..b8639e3 --- /dev/null +++ b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-03of37.patch @@ -0,0 +1,64 @@ +commit 21290977cbdd41c6f4e7b297e63901ad491acadd +Author: DJ Delorie +Date: Tue Aug 20 06:02:53 2013 +0000 + + merge from gcc + +diff --git a/include/dwarf2.def b/include/dwarf2.def +index 7fe2df1..71a37b3 100644 +--- a/include/dwarf2.def ++++ b/include/dwarf2.def +@@ -390,6 +390,9 @@ DW_AT (DW_AT_GNU_ranges_base, 0x2132) + DW_AT (DW_AT_GNU_addr_base, 0x2133) + DW_AT (DW_AT_GNU_pubnames, 0x2134) + DW_AT (DW_AT_GNU_pubtypes, 0x2135) ++/* Attribute for discriminator. ++ See http://gcc.gnu.org/wiki/Discriminator */ ++DW_AT (DW_AT_GNU_discriminator, 0x2136) + /* VMS extensions. */ + DW_AT (DW_AT_VMS_rtnbeg_pd_address, 0x2201) + /* GNAT extensions. */ +diff --git a/include/floatformat.h b/include/floatformat.h +index b595164..04db61a 100644 +--- a/include/floatformat.h ++++ b/include/floatformat.h +@@ -128,7 +128,8 @@ extern const struct floatformat floatformat_ia64_spill_little; + extern const struct floatformat floatformat_ia64_quad_big; + extern const struct floatformat floatformat_ia64_quad_little; + /* IBM long double (double+double). */ +-extern const struct floatformat floatformat_ibm_long_double; ++extern const struct floatformat floatformat_ibm_long_double_big; ++extern const struct floatformat floatformat_ibm_long_double_little; + + /* Convert from FMT to a double. + FROM is the address of the extended float. +diff --git a/libiberty/floatformat.c b/libiberty/floatformat.c +index c58ab01..789fa05 100644 +--- a/libiberty/floatformat.c ++++ b/libiberty/floatformat.c +@@ -371,14 +371,23 @@ floatformat_ibm_long_double_is_valid (const struct floatformat *fmt, + } + } + +-const struct floatformat floatformat_ibm_long_double = ++const struct floatformat floatformat_ibm_long_double_big = + { + floatformat_big, 128, 0, 1, 11, 1023, 2047, 12, 52, + floatformat_intbit_no, +- "floatformat_ibm_long_double", ++ "floatformat_ibm_long_double_big", + floatformat_ibm_long_double_is_valid, + &floatformat_ieee_double_big + }; ++ ++const struct floatformat floatformat_ibm_long_double_little = ++{ ++ floatformat_little, 128, 0, 1, 11, 1023, 2047, 12, 52, ++ floatformat_intbit_no, ++ "floatformat_ibm_long_double_little", ++ floatformat_ibm_long_double_is_valid, ++ &floatformat_ieee_double_little ++}; + + + #ifndef min diff --git a/SOURCES/gdb-rhbz1125820-ppc64le-enablement-04of37.patch b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-04of37.patch new file mode 100644 index 0000000..57b9992 --- /dev/null +++ b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-04of37.patch @@ -0,0 +1,348 @@ +commit 845d47080b7d7e068e4ec3d11fe6e27b403ac6e3 +Author: Alan Modra +Date: Tue Jun 4 02:44:35 2013 +0000 + + * ppc-tdep.h (ppc_insns_match_pattern): Update prototype. + * rs6000-tdep.c (read_insn): Add frame param, don't assume big-endian. + (ppc_insns_match_pattern): Add frame param. Avoid multiple + target mem reads on optional insns. + * ppc-linux-tdep.c (ppc_skip_trampoline_code): Update + ppc_insns_match_pattern calls. + * ppc64-tdep.c (ppc64_standard_linkage2, ppc64_standard_linkage3): + Add match for power7 thread safety insns, and new order of + std 2,40(1) insn. Correct code shown for _dl_runtime_resolve + invocation in comment, and update rest of comment. + (PPC64_STANDARD_LINKAGE1_LEN, PPC64_STANDARD_LINKAGE2_LEN, + PPC64_STANDARD_LINKAGE3_LEN): Delete. + (ppc64_standard_linkage2_target): Update insn offsets. + (ppc64_skip_trampoline_code): Use a single insn buffer. Match newer + stubs first. Update calls. + +Index: gdb-7.6.1/gdb/ppc-linux-tdep.c +=================================================================== +--- gdb-7.6.1.orig/gdb/ppc-linux-tdep.c ++++ gdb-7.6.1/gdb/ppc-linux-tdep.c +@@ -360,7 +360,7 @@ ppc_skip_trampoline_code (struct frame_i + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + CORE_ADDR target = 0; + +- if (ppc_insns_match_pattern (pc, powerpc32_plt_stub, insnbuf)) ++ if (ppc_insns_match_pattern (frame, pc, powerpc32_plt_stub, insnbuf)) + { + /* Insn pattern is + lis r11, xxxx +@@ -372,7 +372,7 @@ ppc_skip_trampoline_code (struct frame_i + target = read_memory_unsigned_integer (target, 4, byte_order); + } + +- if (ppc_insns_match_pattern (pc, powerpc32_plt_stub_so, insnbuf)) ++ if (ppc_insns_match_pattern (frame, pc, powerpc32_plt_stub_so, insnbuf)) + { + /* Insn pattern is + lwz r11, xxxx(r30) +Index: gdb-7.6.1/gdb/ppc-tdep.h +=================================================================== +--- gdb-7.6.1.orig/gdb/ppc-tdep.h ++++ gdb-7.6.1/gdb/ppc-tdep.h +@@ -300,9 +300,9 @@ struct ppc_insn_pattern + int optional; /* If non-zero, this insn may be absent. */ + }; + +-extern int ppc_insns_match_pattern (CORE_ADDR pc, ++extern int ppc_insns_match_pattern (struct frame_info *frame, CORE_ADDR pc, + struct ppc_insn_pattern *pattern, +- unsigned int *insn); ++ unsigned int *insns); + extern CORE_ADDR ppc_insn_d_field (unsigned int insn); + + extern CORE_ADDR ppc_insn_ds_field (unsigned int insn); +Index: gdb-7.6.1/gdb/ppc64-tdep.c +=================================================================== +--- gdb-7.6.1.orig/gdb/ppc64-tdep.c ++++ gdb-7.6.1/gdb/ppc64-tdep.c +@@ -59,9 +59,10 @@ ppc64_desc_entry_point (struct gdbarch * + return (CORE_ADDR) read_memory_unsigned_integer (desc, 8, byte_order); + } + +-/* Pattern for the standard linkage function. These are built by +- build_plt_stub in elf64-ppc.c, whose GLINK argument is always +- zero. */ ++/* Patterns for the standard linkage functions. These are built by ++ build_plt_stub in bfd/elf64-ppc.c. */ ++ ++/* Old PLT call stub. */ + + static struct ppc_insn_pattern ppc64_standard_linkage1[] = + { +@@ -95,15 +96,23 @@ static struct ppc_insn_pattern ppc64_sta + { 0, 0, 0 } + }; + +-#define PPC64_STANDARD_LINKAGE1_LEN ARRAY_SIZE (ppc64_standard_linkage1) ++/* Current PLT call stub to access PLT entries more than +/- 32k from r2. ++ Also supports older stub with different placement of std 2,40(1), ++ a stub that omits the std 2,40(1), and both versions of power7 ++ thread safety read barriers. Note that there are actually two more ++ instructions following "cmpldi r2, 0", "bnectr+" and "b ", ++ but there isn't any need to match them. */ + + static struct ppc_insn_pattern ppc64_standard_linkage2[] = + { ++ /* std r2, 40(r1) */ ++ { -1, insn_ds (62, 2, 1, 40, 0), 1 }, ++ + /* addis r12, r2, */ + { insn_d (-1, -1, -1, 0), insn_d (15, 12, 2, 0), 0 }, + +- /* std r2, 40(r1) */ +- { -1, insn_ds (62, 2, 1, 40, 0), 0 }, ++ /* std r2, 40(r1) */ ++ { -1, insn_ds (62, 2, 1, 40, 0), 1 }, + + /* ld r11, (r12) */ + { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 12, 0, 0), 0 }, +@@ -114,24 +123,33 @@ static struct ppc_insn_pattern ppc64_sta + /* mtctr r11 */ + { insn_xfx (-1, -1, -1, -1), insn_xfx (31, 11, 9, 467), 0 }, + ++ /* xor r11, r11, r11 */ ++ { -1, 0x7d6b5a78, 1 }, ++ ++ /* add r12, r12, r11 */ ++ { -1, 0x7d8c5a14, 1 }, ++ + /* ld r2, (r12) */ + { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 2, 12, 0, 0), 0 }, + + /* ld r11, (r12) */ + { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 12, 0, 0), 1 }, + +- /* bctr */ +- { -1, 0x4e800420, 0 }, ++ /* bctr */ ++ { -1, 0x4e800420, 1 }, ++ ++ /* cmpldi r2, 0 */ ++ { -1, 0x28220000, 1 }, + + { 0, 0, 0 } + }; + +-#define PPC64_STANDARD_LINKAGE2_LEN ARRAY_SIZE (ppc64_standard_linkage2) ++/* Current PLT call stub to access PLT entries within +/- 32k of r2. */ + + static struct ppc_insn_pattern ppc64_standard_linkage3[] = + { +- /* std r2, 40(r1) */ +- { -1, insn_ds (62, 2, 1, 40, 0), 0 }, ++ /* std r2, 40(r1) */ ++ { -1, insn_ds (62, 2, 1, 40, 0), 1 }, + + /* ld r11, (r2) */ + { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 2, 0, 0), 0 }, +@@ -142,56 +160,71 @@ static struct ppc_insn_pattern ppc64_sta + /* mtctr r11 */ + { insn_xfx (-1, -1, -1, -1), insn_xfx (31, 11, 9, 467), 0 }, + ++ /* xor r11, r11, r11 */ ++ { -1, 0x7d6b5a78, 1 }, ++ ++ /* add r2, r2, r11 */ ++ { -1, 0x7c425a14, 1 }, ++ + /* ld r11, (r2) */ + { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 2, 0, 0), 1 }, + + /* ld r2, (r2) */ + { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 2, 2, 0, 0), 0 }, + +- /* bctr */ +- { -1, 0x4e800420, 0 }, ++ /* bctr */ ++ { -1, 0x4e800420, 1 }, ++ ++ /* cmpldi r2, 0 */ ++ { -1, 0x28220000, 1 }, + + { 0, 0, 0 } + }; + +-#define PPC64_STANDARD_LINKAGE3_LEN ARRAY_SIZE (ppc64_standard_linkage3) +- + /* When the dynamic linker is doing lazy symbol resolution, the first + call to a function in another object will go like this: + + - The user's function calls the linkage function: + +- 100007c4: 4b ff fc d5 bl 10000498 +- 100007c8: e8 41 00 28 ld r2,40(r1) ++ 100003d4: 4b ff ff ad bl 10000380 ++ 100003d8: e8 41 00 28 ld r2,40(r1) + +- - The linkage function loads the entry point (and other stuff) from +- the function descriptor in the PLT, and jumps to it: ++ - The linkage function loads the entry point and toc pointer from ++ the function descriptor in the PLT, and jumps to it: + +- 10000498: 3d 82 00 00 addis r12,r2,0 +- 1000049c: f8 41 00 28 std r2,40(r1) +- 100004a0: e9 6c 80 98 ld r11,-32616(r12) +- 100004a4: e8 4c 80 a0 ld r2,-32608(r12) +- 100004a8: 7d 69 03 a6 mtctr r11 +- 100004ac: e9 6c 80 a8 ld r11,-32600(r12) +- 100004b0: 4e 80 04 20 bctr ++ : ++ 10000380: f8 41 00 28 std r2,40(r1) ++ 10000384: e9 62 80 78 ld r11,-32648(r2) ++ 10000388: 7d 69 03 a6 mtctr r11 ++ 1000038c: e8 42 80 80 ld r2,-32640(r2) ++ 10000390: 28 22 00 00 cmpldi r2,0 ++ 10000394: 4c e2 04 20 bnectr+ ++ 10000398: 48 00 03 a0 b 10000738 + + - But since this is the first time that PLT entry has been used, it +- sends control to its glink entry. That loads the number of the +- PLT entry and jumps to the common glink0 code: ++ sends control to its glink entry. That loads the number of the ++ PLT entry and jumps to the common glink0 code: + +- 10000c98: 38 00 00 00 li r0,0 +- 10000c9c: 4b ff ff dc b 10000c78 ++ : ++ 10000738: 38 00 00 01 li r0,1 ++ 1000073c: 4b ff ff bc b 100006f8 <__glink_PLTresolve> + + - The common glink0 code then transfers control to the dynamic +- linker's fixup code: ++ linker's fixup code: + +- 10000c78: e8 41 00 28 ld r2,40(r1) +- 10000c7c: 3d 82 00 00 addis r12,r2,0 +- 10000c80: e9 6c 80 80 ld r11,-32640(r12) +- 10000c84: e8 4c 80 88 ld r2,-32632(r12) +- 10000c88: 7d 69 03 a6 mtctr r11 +- 10000c8c: e9 6c 80 90 ld r11,-32624(r12) +- 10000c90: 4e 80 04 20 bctr ++ 100006f0: 0000000000010440 .quad plt0 - (. + 16) ++ <__glink_PLTresolve>: ++ 100006f8: 7d 88 02 a6 mflr r12 ++ 100006fc: 42 9f 00 05 bcl 20,4*cr7+so,10000700 ++ 10000700: 7d 68 02 a6 mflr r11 ++ 10000704: e8 4b ff f0 ld r2,-16(r11) ++ 10000708: 7d 88 03 a6 mtlr r12 ++ 1000070c: 7d 82 5a 14 add r12,r2,r11 ++ 10000710: e9 6c 00 00 ld r11,0(r12) ++ 10000714: e8 4c 00 08 ld r2,8(r12) ++ 10000718: 7d 69 03 a6 mtctr r11 ++ 1000071c: e9 6c 00 10 ld r11,16(r12) ++ 10000720: 4e 80 04 20 bctr + + Eventually, this code will figure out how to skip all of this, + including the dynamic linker. At the moment, we just get through +@@ -234,8 +267,8 @@ ppc64_standard_linkage2_target (struct f + CORE_ADDR desc + = ((CORE_ADDR) get_frame_register_unsigned (frame, + tdep->ppc_gp0_regnum + 2) +- + (ppc_insn_d_field (insn[0]) << 16) +- + ppc_insn_ds_field (insn[2])); ++ + (ppc_insn_d_field (insn[1]) << 16) ++ + ppc_insn_ds_field (insn[3])); + + /* The first word of the descriptor is the entry point. Return that. */ + return ppc64_desc_entry_point (gdbarch, desc); +@@ -266,23 +299,20 @@ ppc64_standard_linkage3_target (struct f + CORE_ADDR + ppc64_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc) + { +- unsigned int ppc64_standard_linkage1_insn[PPC64_STANDARD_LINKAGE1_LEN]; +- unsigned int ppc64_standard_linkage2_insn[PPC64_STANDARD_LINKAGE2_LEN]; +- unsigned int ppc64_standard_linkage3_insn[PPC64_STANDARD_LINKAGE3_LEN]; ++#define MAX(a,b) ((a) > (b) ? (a) : (b)) ++ unsigned int insns[MAX (MAX (ARRAY_SIZE (ppc64_standard_linkage1), ++ ARRAY_SIZE (ppc64_standard_linkage2)), ++ ARRAY_SIZE (ppc64_standard_linkage3)) - 1]; + CORE_ADDR target; + +- if (ppc_insns_match_pattern (pc, ppc64_standard_linkage1, +- ppc64_standard_linkage1_insn)) +- pc = ppc64_standard_linkage1_target (frame, pc, +- ppc64_standard_linkage1_insn); +- else if (ppc_insns_match_pattern (pc, ppc64_standard_linkage2, +- ppc64_standard_linkage2_insn)) +- pc = ppc64_standard_linkage2_target (frame, pc, +- ppc64_standard_linkage2_insn); +- else if (ppc_insns_match_pattern (pc, ppc64_standard_linkage3, +- ppc64_standard_linkage3_insn)) +- pc = ppc64_standard_linkage3_target (frame, pc, +- ppc64_standard_linkage3_insn); ++ if (ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage3, insns) ++ && (insns[8] != 0 || insns[9] != 0)) ++ pc = ppc64_standard_linkage3_target (frame, pc, insns); ++ else if (ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage2, insns) ++ && (insns[10] != 0 || insns[11] != 0)) ++ pc = ppc64_standard_linkage2_target (frame, pc, insns); ++ else if (ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage1, insns)) ++ pc = ppc64_standard_linkage1_target (frame, pc, insns); + else + return 0; + +Index: gdb-7.6.1/gdb/rs6000-tdep.c +=================================================================== +--- gdb-7.6.1.orig/gdb/rs6000-tdep.c ++++ gdb-7.6.1/gdb/rs6000-tdep.c +@@ -4289,14 +4289,15 @@ show_powerpc_exact_watchpoints (struct u + fprintf_filtered (file, _("Use of exact watchpoints is %s.\n"), value); + } + +-/* Read a PPC instruction from memory. PPC instructions are always +- big-endian, no matter what endianness the program is running in, so +- we can hardcode BFD_ENDIAN_BIG for read_memory_unsigned_integer. */ ++/* Read a PPC instruction from memory. */ + + static unsigned int +-read_insn (CORE_ADDR pc) ++read_insn (struct frame_info *frame, CORE_ADDR pc) + { +- return read_memory_unsigned_integer (pc, 4, BFD_ENDIAN_BIG); ++ struct gdbarch *gdbarch = get_frame_arch (frame); ++ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); ++ ++ return read_memory_unsigned_integer (pc, 4, byte_order); + } + + /* Return non-zero if the instructions at PC match the series +@@ -4313,19 +4314,25 @@ read_insn (CORE_ADDR pc) + i'th instruction in memory. */ + + int +-ppc_insns_match_pattern (CORE_ADDR pc, struct ppc_insn_pattern *pattern, +- unsigned int *insn) ++ppc_insns_match_pattern (struct frame_info *frame, CORE_ADDR pc, ++ struct ppc_insn_pattern *pattern, ++ unsigned int *insns) + { + int i; ++ unsigned int insn; + +- for (i = 0; pattern[i].mask; i++) ++ for (i = 0, insn = 0; pattern[i].mask; i++) + { +- insn[i] = read_insn (pc); +- if ((insn[i] & pattern[i].mask) == pattern[i].data) +- pc += 4; +- else if (pattern[i].optional) +- insn[i] = 0; +- else ++ if (insn == 0) ++ insn = read_insn (frame, pc); ++ insns[i] = 0; ++ if ((insn & pattern[i].mask) == pattern[i].data) ++ { ++ insns[i] = insn; ++ pc += 4; ++ insn = 0; ++ } ++ else if (!pattern[i].optional) + return 0; + } + diff --git a/SOURCES/gdb-rhbz1125820-ppc64le-enablement-05of37.patch b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-05of37.patch new file mode 100644 index 0000000..6e7e3ec --- /dev/null +++ b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-05of37.patch @@ -0,0 +1,115 @@ +commit f5aee5eeb88a99a8fb9d2b57971b0bda035ebc65 +Author: Alan Modra +Date: Tue Aug 20 06:42:19 2013 +0000 + + * doublest.c (convert_floatformat_to_doublest): Use fmt->split_half + for IBM long double nan and inf. + (floatformat_is_negative, floatformat_classify, + floatformat_mantissa): Similarly. + (floatformat_ieee_single, floatformat_ieee_double, + floatformat_ieee_quad, floatformat_arm_ext, + floatformat_ia64_spill): Delete unused vars. + (_initialize_doublest): Delete unused function. + * gdbtypes.c (floatformats_ibm_long_double): Use new big- and + little-endian variants of floatformat_ibm_long_double. + +Index: gdb-7.6.1/gdb/doublest.c +=================================================================== +--- gdb-7.6.1.orig/gdb/doublest.c ++++ gdb-7.6.1/gdb/doublest.c +@@ -190,7 +190,8 @@ convert_floatformat_to_doublest (const s + { + double dto; + +- floatformat_to_double (fmt, from, &dto); ++ floatformat_to_double (fmt->split_half ? fmt->split_half : fmt, ++ from, &dto); + *to = (DOUBLEST) dto; + return; + } +@@ -561,6 +562,11 @@ floatformat_is_negative (const struct fl + gdb_assert (fmt->totalsize + <= FLOATFORMAT_LARGEST_BYTES * FLOATFORMAT_CHAR_BIT); + ++ /* An IBM long double (a two element array of double) always takes the ++ sign of the first double. */ ++ if (fmt->split_half) ++ fmt = fmt->split_half; ++ + order = floatformat_normalize_byteorder (fmt, uval, newfrom); + + if (order != fmt->byteorder) +@@ -587,6 +593,13 @@ floatformat_classify (const struct float + gdb_assert (fmt->totalsize + <= FLOATFORMAT_LARGEST_BYTES * FLOATFORMAT_CHAR_BIT); + ++ /* An IBM long double (a two element array of double) can be classified ++ by looking at the first double. inf and nan are specified as ++ ignoring the second double. zero and subnormal will always have ++ the second double 0.0 if the long double is correctly rounded. */ ++ if (fmt->split_half) ++ fmt = fmt->split_half; ++ + order = floatformat_normalize_byteorder (fmt, uval, newfrom); + + if (order != fmt->byteorder) +@@ -669,6 +682,16 @@ floatformat_mantissa (const struct float + gdb_assert (fmt->totalsize + <= FLOATFORMAT_LARGEST_BYTES * FLOATFORMAT_CHAR_BIT); + ++ /* For IBM long double (a two element array of double), return the ++ mantissa of the first double. The problem with returning the ++ actual mantissa from both doubles is that there can be an ++ arbitrary number of implied 0's or 1's between the mantissas ++ of the first and second double. In any case, this function ++ is only used for dumping out nans, and a nan is specified to ++ ignore the value in the second double. */ ++ if (fmt->split_half) ++ fmt = fmt->split_half; ++ + order = floatformat_normalize_byteorder (fmt, uval, newfrom); + + if (order != fmt->byteorder) +@@ -926,27 +949,3 @@ convert_typed_floating (const void *from + floatformat_from_doublest (to_fmt, &d, to); + } + } +- +-const struct floatformat *floatformat_ieee_single[BFD_ENDIAN_UNKNOWN]; +-const struct floatformat *floatformat_ieee_double[BFD_ENDIAN_UNKNOWN]; +-const struct floatformat *floatformat_ieee_quad[BFD_ENDIAN_UNKNOWN]; +-const struct floatformat *floatformat_arm_ext[BFD_ENDIAN_UNKNOWN]; +-const struct floatformat *floatformat_ia64_spill[BFD_ENDIAN_UNKNOWN]; +- +-extern void _initialize_doublest (void); +- +-extern void +-_initialize_doublest (void) +-{ +- floatformat_ieee_single[BFD_ENDIAN_LITTLE] = &floatformat_ieee_single_little; +- floatformat_ieee_single[BFD_ENDIAN_BIG] = &floatformat_ieee_single_big; +- floatformat_ieee_double[BFD_ENDIAN_LITTLE] = &floatformat_ieee_double_little; +- floatformat_ieee_double[BFD_ENDIAN_BIG] = &floatformat_ieee_double_big; +- floatformat_arm_ext[BFD_ENDIAN_LITTLE] +- = &floatformat_arm_ext_littlebyte_bigword; +- floatformat_arm_ext[BFD_ENDIAN_BIG] = &floatformat_arm_ext_big; +- floatformat_ia64_spill[BFD_ENDIAN_LITTLE] = &floatformat_ia64_spill_little; +- floatformat_ia64_spill[BFD_ENDIAN_BIG] = &floatformat_ia64_spill_big; +- floatformat_ieee_quad[BFD_ENDIAN_LITTLE] = &floatformat_ia64_quad_little; +- floatformat_ieee_quad[BFD_ENDIAN_BIG] = &floatformat_ia64_quad_big; +-} +Index: gdb-7.6.1/gdb/gdbtypes.c +=================================================================== +--- gdb-7.6.1.orig/gdb/gdbtypes.c ++++ gdb-7.6.1/gdb/gdbtypes.c +@@ -110,8 +110,8 @@ const struct floatformat *floatformats_v + &floatformat_vax_d + }; + const struct floatformat *floatformats_ibm_long_double[BFD_ENDIAN_UNKNOWN] = { +- &floatformat_ibm_long_double, +- &floatformat_ibm_long_double ++ &floatformat_ibm_long_double_big, ++ &floatformat_ibm_long_double_little + }; + + /* Should opaque types be resolved? */ diff --git a/SOURCES/gdb-rhbz1125820-ppc64le-enablement-06of37.patch b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-06of37.patch new file mode 100644 index 0000000..c2c410b --- /dev/null +++ b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-06of37.patch @@ -0,0 +1,45 @@ +commit bcbec14ee2e2d060dec534fe9a608f64d1bfa632 +Author: Alan Modra +Date: Thu Aug 22 01:01:32 2013 +0000 + + * configure.host: Support powerpc64le-linux and powerpcle-linux hosts. + * configure.tgt: Likewise as targets. + +Index: gdb-7.6.1/gdb/configure.host +=================================================================== +--- gdb-7.6.1.orig/gdb/configure.host ++++ gdb-7.6.1/gdb/configure.host +@@ -129,18 +129,18 @@ mips64*-*-openbsd*) gdb_host=obsd64 ;; + powerpc-*-aix* | rs6000-*-*) + gdb_host=aix ;; + powerpc*-*-freebsd*) gdb_host=fbsd ;; +-powerpc-*-linux*) gdb_host=linux ;; + powerpc-*-netbsd* | powerpc-*-knetbsd*-gnu) + gdb_host=nbsd ;; + powerpc-*-openbsd*) gdb_host=obsd ;; + +-powerpc64-*-linux*) gdb_host=ppc64-linux ++powerpc64*-*-linux*) gdb_host=ppc64-linux + # Support 'pseudo-native' debugging on the Cell BE + if test "${target_cpu}" = "spu"; then + gdb_host=spu-linux + gdb_native=yes + fi + ;; ++powerpc*-*-linux*) gdb_host=linux ;; + + s390*-*-*) gdb_host=s390 ;; + +Index: gdb-7.6.1/gdb/configure.tgt +=================================================================== +--- gdb-7.6.1.orig/gdb/configure.tgt ++++ gdb-7.6.1/gdb/configure.tgt +@@ -422,7 +422,7 @@ powerpc-*-aix* | rs6000-*-*) + ppc-sysv-tdep.o solib-svr4.o \ + ravenscar-thread.o ppc-ravenscar-thread.o" + ;; +-powerpc-*-linux* | powerpc64-*-linux*) ++powerpc*-*-linux*) + # Target: PowerPC running Linux + gdb_target_obs="rs6000-tdep.o ppc-linux-tdep.o ppc-sysv-tdep.o \ + ppc64-tdep.o solib-svr4.o solib-spu.o \ diff --git a/SOURCES/gdb-rhbz1125820-ppc64le-enablement-07of37.patch b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-07of37.patch new file mode 100644 index 0000000..a187e52 --- /dev/null +++ b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-07of37.patch @@ -0,0 +1,302 @@ +commit 71a39c98f8bedad54818c62ab2d567b0e2de546b +Author: Alan Modra +Date: Tue Oct 29 12:39:30 2013 +1030 + + Change plt stubs to have destination in r12. + + This change is to support the new ELFv2 ABI, which uses the value in + r12 on function entry to calculate the got/toc pointer. + + bfd/ + * elf64-ppc.c (build_plt_stub): Switch stubs to use r11 as base + reg and r12 as destination. + (ppc_build_one_stub): Likewise. + (ppc64_elf_build_stubs): Likewise for glink. + ld/testsuite/ + * ld-powerpc/tls.s: Add proper .opd entry for _start. + * ld-powerpc/tlstoc.s: Likewise. + * ld-powerpc/relbrlt.d: Update for changed stubs. + * ld-powerpc/tls.d: Update for changed stubs and _start .opd entry. + * ld-powerpc/tls.g: Likewise. + * ld-powerpc/tlsexe.d: Likewise. + * ld-powerpc/tlsexe.g: Likewise. + * ld-powerpc/tlsexe.r: Likewise. + * ld-powerpc/tlsexetoc.d: Likewise. + * ld-powerpc/tlsexetoc.g: Likewise. + * ld-powerpc/tlsexetoc.r: Likewise. + * ld-powerpc/tlsso.d: Likewise. + * ld-powerpc/tlsso.g: Likewise. + * ld-powerpc/tlsso.r: Likewise. + * ld-powerpc/tlstoc.d: Likewise. + * ld-powerpc/tlstoc.g: Likewise. + * ld-powerpc/tlstocso.d: Likewise. + * ld-powerpc/tlstocso.g: Likewise. + * ld-powerpc/tlstocso.r: Likewise. + +Index: gdb-7.6.1/bfd/elf64-ppc.c +=================================================================== +--- gdb-7.6.1.orig/bfd/elf64-ppc.c ++++ gdb-7.6.1/bfd/elf64-ppc.c +@@ -137,29 +137,29 @@ static bfd_vma opd_entry_value + + /* .plt call stub instructions. The normal stub is like this, but + sometimes the .plt entry crosses a 64k boundary and we need to +- insert an addi to adjust r12. */ ++ insert an addi to adjust r11. */ + #define PLT_CALL_STUB_SIZE (7*4) +-#define ADDIS_R12_R2 0x3d820000 /* addis %r12,%r2,xxx@ha */ + #define STD_R2_40R1 0xf8410028 /* std %r2,40(%r1) */ +-#define LD_R11_0R12 0xe96c0000 /* ld %r11,xxx+0@l(%r12) */ +-#define MTCTR_R11 0x7d6903a6 /* mtctr %r11 */ +-#define LD_R2_0R12 0xe84c0000 /* ld %r2,xxx+8@l(%r12) */ +- /* ld %r11,xxx+16@l(%r12) */ ++#define ADDIS_R11_R2 0x3d620000 /* addis %r11,%r2,xxx@ha */ ++#define LD_R12_0R11 0xe98b0000 /* ld %r12,xxx+0@l(%r11) */ ++#define MTCTR_R12 0x7d8903a6 /* mtctr %r12 */ ++#define LD_R2_0R11 0xe84b0000 /* ld %r2,xxx+8@l(%r11) */ ++#define LD_R11_0R11 0xe96b0000 /* ld %r11,xxx+16@l(%r11) */ + #define BCTR 0x4e800420 /* bctr */ + +- +-#define ADDIS_R12_R12 0x3d8c0000 /* addis %r12,%r12,off@ha */ +-#define ADDI_R12_R12 0x398c0000 /* addi %r12,%r12,off@l */ ++#define ADDI_R11_R11 0x396b0000 /* addi %r11,%r11,off@l */ + #define ADDIS_R2_R2 0x3c420000 /* addis %r2,%r2,off@ha */ + #define ADDI_R2_R2 0x38420000 /* addi %r2,%r2,off@l */ + +-#define XOR_R11_R11_R11 0x7d6b5a78 /* xor %r11,%r11,%r11 */ +-#define ADD_R12_R12_R11 0x7d8c5a14 /* add %r12,%r12,%r11 */ ++#define XOR_R2_R12_R12 0x7d826278 /* xor %r2,%r12,%r12 */ ++#define ADD_R11_R11_R2 0x7d6b1214 /* add %r11,%r11,%r2 */ ++#define XOR_R11_R12_R12 0x7d8b6278 /* xor %r11,%r12,%r12 */ + #define ADD_R2_R2_R11 0x7c425a14 /* add %r2,%r2,%r11 */ + #define CMPLDI_R2_0 0x28220000 /* cmpldi %r2,0 */ + #define BNECTR 0x4ca20420 /* bnectr+ */ + #define BNECTR_P4 0x4ce20420 /* bnectr+ */ + ++#define LD_R12_0R2 0xe9820000 /* ld %r12,xxx+0(%r2) */ + #define LD_R11_0R2 0xe9620000 /* ld %r11,xxx+0(%r2) */ + #define LD_R2_0R2 0xe8420000 /* ld %r2,xxx+0(%r2) */ + +@@ -174,13 +174,13 @@ static bfd_vma opd_entry_value + #define BCL_20_31 0x429f0005 /* bcl 20,31,1f */ + /* 1: */ + #define MFLR_R11 0x7d6802a6 /* mflr %11 */ +-#define LD_R2_M16R11 0xe84bfff0 /* ld %2,(0b-1b)(%11) */ ++ /* ld %2,(0b-1b)(%11) */ + #define MTLR_R12 0x7d8803a6 /* mtlr %12 */ +-#define ADD_R12_R2_R11 0x7d825a14 /* add %12,%2,%11 */ +- /* ld %11,0(%12) */ +- /* ld %2,8(%12) */ +- /* mtctr %11 */ +- /* ld %11,16(%12) */ ++#define ADD_R11_R2_R11 0x7d625a14 /* add %11,%2,%11 */ ++ /* ld %12,0(%11) */ ++ /* ld %2,8(%11) */ ++ /* mtctr %12 */ ++ /* ld %11,16(%11) */ + /* bctr */ + + /* Pad with this. */ +@@ -3452,13 +3452,13 @@ ppc64_elf_get_synthetic_symtab (bfd *abf + . + . + . .foo_stub: +- . addis 12,2,Lfoo@toc@ha # in practice, the call stub +- . addi 12,12,Lfoo@toc@l # is slightly optimized, but +- . std 2,40(1) # this is the general idea +- . ld 11,0(12) +- . ld 2,8(12) +- . mtctr 11 +- . ld 11,16(12) ++ . std 2,40(1) # in practice, the call stub ++ . addis 11,2,Lfoo@toc@ha # is slightly optimized, but ++ . addi 11,11,Lfoo@toc@l # this is the general idea ++ . ld 12,0(11) ++ . ld 2,8(11) ++ . mtctr 12 ++ . ld 11,16(11) + . bctr + . + . .section .plt +@@ -3548,21 +3548,21 @@ must_be_dyn_reloc (struct bfd_link_info + ppc_stub_plt_branch: + Similar to the above, but a 24 bit branch in the stub section won't + reach its destination. +- . addis %r12,%r2,xxx@toc@ha +- . ld %r11,xxx@toc@l(%r12) +- . mtctr %r11 ++ . addis %r11,%r2,xxx@toc@ha ++ . ld %r12,xxx@toc@l(%r11) ++ . mtctr %r12 + . bctr + + ppc_stub_plt_call: + Used to call a function in a shared library. If it so happens that + the plt entry referenced crosses a 64k boundary, then an extra +- "addi %r12,%r12,xxx@toc@l" will be inserted before the "mtctr". +- . addis %r12,%r2,xxx@toc@ha ++ "addi %r11,%r11,xxx@toc@l" will be inserted before the "mtctr". + . std %r2,40(%r1) +- . ld %r11,xxx+0@toc@l(%r12) +- . mtctr %r11 +- . ld %r2,xxx+8@toc@l(%r12) +- . ld %r11,xxx+16@toc@l(%r12) ++ . addis %r11,%r2,xxx@toc@ha ++ . ld %r12,xxx+0@toc@l(%r11) ++ . mtctr %r12 ++ . ld %r2,xxx+8@toc@l(%r11) ++ . ld %r11,xxx+16@toc@l(%r11) + . bctr + + ppc_stub_long_branch and ppc_stub_plt_branch may also have additional +@@ -3575,11 +3575,11 @@ must_be_dyn_reloc (struct bfd_link_info + + A ppc_stub_plt_branch with an r2 offset looks like: + . std %r2,40(%r1) +- . addis %r12,%r2,xxx@toc@ha +- . ld %r11,xxx@toc@l(%r12) ++ . addis %r11,%r2,xxx@toc@ha ++ . ld %r12,xxx@toc@l(%r11) + . addis %r2,%r2,off@ha + . addi %r2,%r2,off@l +- . mtctr %r11 ++ . mtctr %r12 + . bctr + + In cases where the "addis" instruction would add zero, the "addis" is +@@ -9569,9 +9569,9 @@ ppc_type_of_stub (asection *input_sec, + the appropriate glink entry if so. + + . fake dep barrier compare +- . ld 11,xxx(2) ld 11,xxx(2) +- . mtctr 11 mtctr 11 +- . xor 11,11,11 ld 2,xxx+8(2) ++ . ld 12,xxx(2) ld 12,xxx(2) ++ . mtctr 12 mtctr 12 ++ . xor 11,12,12 ld 2,xxx+8(2) + . add 2,2,11 cmpldi 2,0 + . ld 2,xxx+8(2) bnectr+ + . bctr b +@@ -9706,22 +9706,22 @@ build_plt_stub (struct ppc_link_hash_tab + if (ALWAYS_EMIT_R2SAVE + || stub_entry->stub_type == ppc_stub_plt_call_r2save) + bfd_put_32 (obfd, STD_R2_40R1, p), p += 4; +- bfd_put_32 (obfd, ADDIS_R12_R2 | PPC_HA (offset), p), p += 4; +- bfd_put_32 (obfd, LD_R11_0R12 | PPC_LO (offset), p), p += 4; ++ bfd_put_32 (obfd, ADDIS_R11_R2 | PPC_HA (offset), p), p += 4; ++ bfd_put_32 (obfd, LD_R12_0R11 | PPC_LO (offset), p), p += 4; + if (PPC_HA (offset + 8 + 8 * plt_static_chain) != PPC_HA (offset)) + { +- bfd_put_32 (obfd, ADDI_R12_R12 | PPC_LO (offset), p), p += 4; ++ bfd_put_32 (obfd, ADDI_R11_R11 | PPC_LO (offset), p), p += 4; + offset = 0; + } +- bfd_put_32 (obfd, MTCTR_R11, p), p += 4; ++ bfd_put_32 (obfd, MTCTR_R12, p), p += 4; + if (use_fake_dep) + { +- bfd_put_32 (obfd, XOR_R11_R11_R11, p), p += 4; +- bfd_put_32 (obfd, ADD_R12_R12_R11, p), p += 4; ++ bfd_put_32 (obfd, XOR_R2_R12_R12, p), p += 4; ++ bfd_put_32 (obfd, ADD_R11_R11_R2, p), p += 4; + } +- bfd_put_32 (obfd, LD_R2_0R12 | PPC_LO (offset + 8), p), p += 4; ++ bfd_put_32 (obfd, LD_R2_0R11 | PPC_LO (offset + 8), p), p += 4; + if (plt_static_chain) +- bfd_put_32 (obfd, LD_R11_0R12 | PPC_LO (offset + 16), p), p += 4; ++ bfd_put_32 (obfd, LD_R11_0R11 | PPC_LO (offset + 16), p), p += 4; + } + else + { +@@ -9753,16 +9753,16 @@ build_plt_stub (struct ppc_link_hash_tab + if (ALWAYS_EMIT_R2SAVE + || stub_entry->stub_type == ppc_stub_plt_call_r2save) + bfd_put_32 (obfd, STD_R2_40R1, p), p += 4; +- bfd_put_32 (obfd, LD_R11_0R2 | PPC_LO (offset), p), p += 4; ++ bfd_put_32 (obfd, LD_R12_0R2 | PPC_LO (offset), p), p += 4; + if (PPC_HA (offset + 8 + 8 * plt_static_chain) != PPC_HA (offset)) + { + bfd_put_32 (obfd, ADDI_R2_R2 | PPC_LO (offset), p), p += 4; + offset = 0; + } +- bfd_put_32 (obfd, MTCTR_R11, p), p += 4; ++ bfd_put_32 (obfd, MTCTR_R12, p), p += 4; + if (use_fake_dep) + { +- bfd_put_32 (obfd, XOR_R11_R11_R11, p), p += 4; ++ bfd_put_32 (obfd, XOR_R11_R12_R12, p), p += 4; + bfd_put_32 (obfd, ADD_R2_R2_R11, p), p += 4; + } + if (plt_static_chain) +@@ -10111,14 +10111,14 @@ ppc_build_one_stub (struct bfd_hash_entr + if (PPC_HA (off) != 0) + { + size = 16; +- bfd_put_32 (htab->stub_bfd, ADDIS_R12_R2 | PPC_HA (off), loc); ++ bfd_put_32 (htab->stub_bfd, ADDIS_R11_R2 | PPC_HA (off), loc); + loc += 4; +- bfd_put_32 (htab->stub_bfd, LD_R11_0R12 | PPC_LO (off), loc); ++ bfd_put_32 (htab->stub_bfd, LD_R12_0R11 | PPC_LO (off), loc); + } + else + { + size = 12; +- bfd_put_32 (htab->stub_bfd, LD_R11_0R2 | PPC_LO (off), loc); ++ bfd_put_32 (htab->stub_bfd, LD_R12_0R2 | PPC_LO (off), loc); + } + } + else +@@ -10137,14 +10137,14 @@ ppc_build_one_stub (struct bfd_hash_entr + if (PPC_HA (off) != 0) + { + size += 4; +- bfd_put_32 (htab->stub_bfd, ADDIS_R12_R2 | PPC_HA (off), loc); ++ bfd_put_32 (htab->stub_bfd, ADDIS_R11_R2 | PPC_HA (off), loc); + loc += 4; +- bfd_put_32 (htab->stub_bfd, LD_R11_0R12 | PPC_LO (off), loc); ++ bfd_put_32 (htab->stub_bfd, LD_R12_0R11 | PPC_LO (off), loc); + loc += 4; + } + else + { +- bfd_put_32 (htab->stub_bfd, LD_R11_0R2 | PPC_LO (off), loc); ++ bfd_put_32 (htab->stub_bfd, LD_R12_0R2 | PPC_LO (off), loc); + loc += 4; + } + +@@ -10157,7 +10157,7 @@ ppc_build_one_stub (struct bfd_hash_entr + bfd_put_32 (htab->stub_bfd, ADDI_R2_R2 | PPC_LO (r2off), loc); + } + loc += 4; +- bfd_put_32 (htab->stub_bfd, MTCTR_R11, loc); ++ bfd_put_32 (htab->stub_bfd, MTCTR_R12, loc); + loc += 4; + bfd_put_32 (htab->stub_bfd, BCTR, loc); + break; +@@ -11909,19 +11909,19 @@ ppc64_elf_build_stubs (bfd_boolean emit_ + p += 4; + bfd_put_32 (htab->glink->owner, MFLR_R11, p); + p += 4; +- bfd_put_32 (htab->glink->owner, LD_R2_M16R11, p); ++ bfd_put_32 (htab->glink->owner, LD_R2_0R11 | (-16 & 0xfffc), p); + p += 4; + bfd_put_32 (htab->glink->owner, MTLR_R12, p); + p += 4; +- bfd_put_32 (htab->glink->owner, ADD_R12_R2_R11, p); ++ bfd_put_32 (htab->glink->owner, ADD_R11_R2_R11, p); + p += 4; +- bfd_put_32 (htab->glink->owner, LD_R11_0R12, p); ++ bfd_put_32 (htab->glink->owner, LD_R12_0R11, p); + p += 4; +- bfd_put_32 (htab->glink->owner, LD_R2_0R12 | 8, p); ++ bfd_put_32 (htab->glink->owner, LD_R2_0R11 | 8, p); + p += 4; +- bfd_put_32 (htab->glink->owner, MTCTR_R11, p); ++ bfd_put_32 (htab->glink->owner, MTCTR_R12, p); + p += 4; +- bfd_put_32 (htab->glink->owner, LD_R11_0R12 | 16, p); ++ bfd_put_32 (htab->glink->owner, LD_R11_0R11 | 16, p); + p += 4; + bfd_put_32 (htab->glink->owner, BCTR, p); + p += 4; diff --git a/SOURCES/gdb-rhbz1125820-ppc64le-enablement-08of37.patch b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-08of37.patch new file mode 100644 index 0000000..9e4c14a --- /dev/null +++ b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-08of37.patch @@ -0,0 +1,291 @@ +commit ee67d69a3ff0eed25d98c5e97ed6c3ede8069edc +Author: Alan Modra +Date: Tue Oct 29 15:06:09 2013 +1030 + + Add .abiversion related support for ELFv2 + + Defines bits in ELF e_flags to differentiate ELFv2 objects from ELFv2, + adds .abiversion directive to explicitly choose the ABI, and code to + check and automatically select ABI. + + include/elf/ + * ppc64.h (EF_PPC64_ABI): Define. + bfd/ + * elf64-ppc.c (abiversion, set_abiversion): New functions. + (ppc64_elf_get_synthetic_symtab): Handle ELFv2 objects without .opd. + (struct ppc_link_hash_table): Add opd_abi. + (ppc64_elf_check_relocs): Check no .opd with ELFv2. + (ppc64_elf_merge_private_bfd_data): New function. + (ppc64_elf_print_private_bfd_data): New function. + (ppc64_elf_tls_setup): Set htab->opd_abi. + (ppc64_elf_size_dynamic_sections): Don't emit OPD related dynamic + tags for ELFv2. + (ppc_build_one_stub): Use R_PPC64_IRELATIVE for ELFv2 ifunc. + (ppc64_elf_finish_dynamic_symbol): Likewise + binutils/ + * readelf.c (get_machine_flags): Display ABI version for EM_PPC64. + gas/ + * config/tc-ppc.c: Include elf/ppc64.h. + (ppc_abiversion): New variable. + (md_pseudo_table): Add .abiversion. + (ppc_elf_abiversion, ppc_elf_end): New functions. + * config/tc-ppc.h (md_end): Define. + +Index: gdb-7.6.1/bfd/elf64-ppc.c +=================================================================== +--- gdb-7.6.1.orig/bfd/elf64-ppc.c ++++ gdb-7.6.1/bfd/elf64-ppc.c +@@ -81,7 +81,8 @@ static bfd_vma opd_entry_value + #define bfd_elf64_mkobject ppc64_elf_mkobject + #define bfd_elf64_bfd_reloc_type_lookup ppc64_elf_reloc_type_lookup + #define bfd_elf64_bfd_reloc_name_lookup ppc64_elf_reloc_name_lookup +-#define bfd_elf64_bfd_merge_private_bfd_data _bfd_generic_verify_endian_match ++#define bfd_elf64_bfd_merge_private_bfd_data ppc64_elf_merge_private_bfd_data ++#define bfd_elf64_bfd_print_private_bfd_data ppc64_elf_print_private_bfd_data + #define bfd_elf64_new_section_hook ppc64_elf_new_section_hook + #define bfd_elf64_bfd_link_hash_table_create ppc64_elf_link_hash_table_create + #define bfd_elf64_bfd_link_hash_table_free ppc64_elf_link_hash_table_free +@@ -2836,6 +2837,19 @@ get_opd_info (asection * sec) + return &ppc64_elf_section_data (sec)->u.opd; + return NULL; + } ++ ++static inline int ++abiversion (bfd *abfd) ++{ ++ return elf_elfheader (abfd)->e_flags & EF_PPC64_ABI; ++} ++ ++static inline void ++set_abiversion (bfd *abfd, int ver) ++{ ++ elf_elfheader (abfd)->e_flags &= ~EF_PPC64_ABI; ++ elf_elfheader (abfd)->e_flags |= ver & EF_PPC64_ABI; ++} + + /* Parameters for the qsort hook. */ + static bfd_boolean synthetic_relocatable; +@@ -2982,15 +2996,19 @@ ppc64_elf_get_synthetic_symtab (bfd *abf + long count; + char *names; + long symcount, codesecsym, codesecsymend, secsymend, opdsymend; +- asection *opd; ++ asection *opd = NULL; + bfd_boolean relocatable = (abfd->flags & (EXEC_P | DYNAMIC)) == 0; + asymbol **syms; ++ int abi = abiversion (abfd); + + *ret = NULL; + +- opd = bfd_get_section_by_name (abfd, ".opd"); +- if (opd == NULL) +- return 0; ++ if (abi < 2) ++ { ++ opd = bfd_get_section_by_name (abfd, ".opd"); ++ if (opd == NULL && abi == 1) ++ return 0; ++ } + + symcount = static_count; + if (!relocatable) +@@ -3159,20 +3177,18 @@ ppc64_elf_get_synthetic_symtab (bfd *abf + else + { + bfd_boolean (*slurp_relocs) (bfd *, asection *, asymbol **, bfd_boolean); +- bfd_byte *contents; ++ bfd_byte *contents = NULL; + size_t size; + long plt_count = 0; + bfd_vma glink_vma = 0, resolv_vma = 0; + asection *dynamic, *glink = NULL, *relplt = NULL; + arelent *p; + +- if (!bfd_malloc_and_get_section (abfd, opd, &contents)) ++ if (opd != NULL && !bfd_malloc_and_get_section (abfd, opd, &contents)) + { ++ free_contents_and_exit: + if (contents) +- { +- free_contents_and_exit: +- free (contents); +- } ++ free (contents); + count = -1; + goto done; + } +@@ -3772,6 +3788,9 @@ struct ppc_link_hash_table + /* Alignment of PLT call stubs. */ + unsigned int plt_stub_align:4; + ++ /* Set if we're linking code with function descriptors. */ ++ unsigned int opd_abi:1; ++ + /* Set if PLT call stubs should load r11. */ + unsigned int plt_static_chain:1; + +@@ -4959,6 +4978,15 @@ ppc64_elf_check_relocs (bfd *abfd, struc + information about the associated function section. */ + bfd_size_type amt; + ++ if (abiversion (abfd) == 0) ++ set_abiversion (abfd, 1); ++ else if (abiversion (abfd) == 2) ++ { ++ info->callbacks->einfo (_("%P: .opd not allowed in ABI version %d\n"), ++ abiversion (abfd)); ++ bfd_set_error (bfd_error_bad_value); ++ return FALSE; ++ } + amt = sec->size * sizeof (*opd_sym_map) / 8; + opd_sym_map = bfd_zalloc (abfd, amt); + if (opd_sym_map == NULL) +@@ -5518,6 +5546,78 @@ ppc64_elf_check_relocs (bfd *abfd, struc + return TRUE; + } + ++/* Merge backend specific data from an object file to the output ++ object file when linking. */ ++ ++static bfd_boolean ++ppc64_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd) ++{ ++ unsigned long iflags, oflags; ++ ++ if ((ibfd->flags & BFD_LINKER_CREATED) != 0) ++ return TRUE; ++ ++ if (!is_ppc64_elf (ibfd) || !is_ppc64_elf (obfd)) ++ return TRUE; ++ ++ if (!_bfd_generic_verify_endian_match (ibfd, obfd)) ++ return FALSE; ++ ++ iflags = elf_elfheader (ibfd)->e_flags; ++ oflags = elf_elfheader (obfd)->e_flags; ++ ++ if (!elf_flags_init (obfd) || oflags == 0) ++ { ++ elf_flags_init (obfd) = TRUE; ++ elf_elfheader (obfd)->e_flags = iflags; ++ } ++ else if (iflags == oflags || iflags == 0) ++ ; ++ else if (iflags & ~EF_PPC64_ABI) ++ { ++ (*_bfd_error_handler) ++ (_("%B uses unknown e_flags 0x%lx"), ibfd, iflags); ++ bfd_set_error (bfd_error_bad_value); ++ return FALSE; ++ } ++ else ++ { ++ (*_bfd_error_handler) ++ (_("%B: ABI version %ld is not compatible with ABI version %ld output"), ++ ibfd, iflags, oflags); ++ bfd_set_error (bfd_error_bad_value); ++ return FALSE; ++ } ++ ++ /* Merge Tag_compatibility attributes and any common GNU ones. */ ++ _bfd_elf_merge_object_attributes (ibfd, obfd); ++ ++ return TRUE; ++} ++ ++static bfd_boolean ++ppc64_elf_print_private_bfd_data (bfd *abfd, void *ptr) ++{ ++ /* Print normal ELF private data. */ ++ _bfd_elf_print_private_bfd_data (abfd, ptr); ++ ++ if (elf_elfheader (abfd)->e_flags != 0) ++ { ++ FILE *file = ptr; ++ ++ /* xgettext:c-format */ ++ fprintf (file, _("private flags = 0x%lx:"), ++ elf_elfheader (abfd)->e_flags); ++ ++ if ((elf_elfheader (abfd)->e_flags & EF_PPC64_ABI) != 0) ++ fprintf (file, _(" [abiv%ld]"), ++ elf_elfheader (abfd)->e_flags & EF_PPC64_ABI); ++ fputc ('\n', file); ++ } ++ ++ return TRUE; ++} ++ + /* OFFSET in OPD_SEC specifies a function descriptor. Return the address + of the code entry point, and its section. */ + +@@ -7504,6 +7604,9 @@ ppc64_elf_tls_setup (struct bfd_link_inf + if (htab == NULL) + return NULL; + ++ if (abiversion (info->output_bfd) == 1) ++ htab->opd_abi = 1; ++ + if (*no_multi_toc) + htab->do_multi_toc = 0; + else if (!htab->do_multi_toc) +@@ -9127,7 +9230,7 @@ readonly_dynrelocs (struct elf_link_hash + /* Set the sizes of the dynamic sections. */ + + static bfd_boolean +-ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, ++ppc64_elf_size_dynamic_sections (bfd *output_bfd, + struct bfd_link_info *info) + { + struct ppc_link_hash_table *htab; +@@ -9439,7 +9542,7 @@ ppc64_elf_size_dynamic_sections (bfd *ou + return FALSE; + } + +- if (NO_OPD_RELOCS) ++ if (NO_OPD_RELOCS && abiversion (output_bfd) <= 1) + { + if (!add_dynamic_entry (DT_PPC64_OPD, 0) + || !add_dynamic_entry (DT_PPC64_OPDSZ, 0)) +@@ -10202,7 +10305,10 @@ ppc_build_one_stub (struct bfd_hash_entr + bfd_byte *rl; + + rela.r_offset = dest; +- rela.r_info = ELF64_R_INFO (0, R_PPC64_JMP_IREL); ++ if (htab->opd_abi) ++ rela.r_info = ELF64_R_INFO (0, R_PPC64_JMP_IREL); ++ else ++ rela.r_info = ELF64_R_INFO (0, R_PPC64_IRELATIVE); + rela.r_addend = (stub_entry->target_value + + stub_entry->target_section->output_offset + + stub_entry->target_section->output_section->vma); +@@ -14012,7 +14118,10 @@ ppc64_elf_finish_dynamic_symbol (bfd *ou + rela.r_offset = (htab->iplt->output_section->vma + + htab->iplt->output_offset + + ent->plt.offset); +- rela.r_info = ELF64_R_INFO (0, R_PPC64_JMP_IREL); ++ if (htab->opd_abi) ++ rela.r_info = ELF64_R_INFO (0, R_PPC64_JMP_IREL); ++ else ++ rela.r_info = ELF64_R_INFO (0, R_PPC64_IRELATIVE); + rela.r_addend = (h->root.u.def.value + + h->root.u.def.section->output_offset + + h->root.u.def.section->output_section->vma +Index: gdb-7.6.1/include/elf/ppc64.h +=================================================================== +--- gdb-7.6.1.orig/include/elf/ppc64.h ++++ gdb-7.6.1/include/elf/ppc64.h +@@ -164,6 +164,13 @@ END_RELOC_NUMBERS (R_PPC64_max) + #define IS_PPC64_TLS_RELOC(R) \ + ((R) >= R_PPC64_TLS && (R) <= R_PPC64_DTPREL16_HIGHESTA) + ++ ++/* e_flags bits specifying ABI. ++ 1 for original function descriptor using ABI, ++ 2 for revised ABI without function descriptors, ++ 0 for unspecified or not using any features affected by the differences. */ ++#define EF_PPC64_ABI 3 ++ + /* Specify the start of the .glink section. */ + #define DT_PPC64_GLINK DT_LOPROC + diff --git a/SOURCES/gdb-rhbz1125820-ppc64le-enablement-09of37.patch b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-09of37.patch new file mode 100644 index 0000000..180a223 --- /dev/null +++ b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-09of37.patch @@ -0,0 +1,302 @@ +commit 6911b7dcb8ea17f8b811578dd4ac1ab7bb675e7b +Author: Alan Modra +Date: Tue Oct 29 15:37:43 2013 +1030 + + Add ELFv2 .localentry support. + + This defines the ELF symbol st_other field used to encode the number + of instructions between a function "global entry" and its "local entry", + and adds support related to the local entry offset. + + include/elf/ + * ppc64.h (STO_PPC64_LOCAL_BIT, STO_PPC64_LOCAL_MASK): Define. + (ppc64_decode_local_entry, ppc64_encode_local_entry): New functions. + (PPC64_LOCAL_ENTRY_OFFSET, PPC64_SET_LOCAL_ENTRY_OFFSET): Define. + bfd/ + * elf64-ppc.c (struct ppc_stub_hash_entry): Add "other". + (stub_hash_newfunc): Init new ppc_stub_hash_entry field, and one + we forgot, "plt_ent". + (ppc64_elf_add_symbol_hook): Check ELFv1 objects don't have + st_other bits only valid in ELFv2. + (ppc64_elf_merge_symbol_attribute): New function. + (ppc_type_of_stub): Add local_off param to test branch range. + (ppc_build_one_stub): Adjust destinations for ELFv2 locals. + (ppc_size_one_stub, toc_adjusting_stub_needed): Similarly. + (ppc64_elf_size_stubs): Pass local_off to ppc_type_of_stub. + Set "other" field. + (ppc64_elf_relocate_section): Adjust destination for ELFv2 local + calls. + gas/ + * config/tc-ppc.c (md_pseudo_table): Add .localentry. + (ppc_elf_localentry): New function. + (ppc_force_relocation): Force relocs on all branches to localenty + symbols. + (ppc_fix_adjustable): Don't reduce such symbols to section+offset. + binutils/ + * readelf.c (get_ppc64_symbol_other): New function. + (get_symbol_other): Use it for EM_PPC64. + +Index: gdb-7.6.1/bfd/elf64-ppc.c +=================================================================== +--- gdb-7.6.1.orig/bfd/elf64-ppc.c ++++ gdb-7.6.1/bfd/elf64-ppc.c +@@ -118,6 +118,7 @@ static bfd_vma opd_entry_value + #define elf_backend_link_output_symbol_hook ppc64_elf_output_symbol_hook + #define elf_backend_special_sections ppc64_elf_special_sections + #define elf_backend_post_process_headers _bfd_elf_set_osabi ++#define elf_backend_merge_symbol_attribute ppc64_elf_merge_symbol_attribute + + /* The name of the dynamic interpreter. This is put in the .interp + section. */ +@@ -3640,6 +3641,9 @@ struct ppc_stub_hash_entry { + /* Where this stub is being called from, or, in the case of combined + stub sections, the first input section in the group. */ + asection *id_sec; ++ ++ /* Symbol st_other. */ ++ unsigned char other; + }; + + struct ppc_branch_hash_entry { +@@ -3886,7 +3890,9 @@ stub_hash_newfunc (struct bfd_hash_entry + eh->target_value = 0; + eh->target_section = NULL; + eh->h = NULL; ++ eh->plt_ent = NULL; + eh->id_sec = NULL; ++ eh->other = 0; + } + + return entry; +@@ -4629,7 +4635,7 @@ static bfd_boolean + ppc64_elf_add_symbol_hook (bfd *ibfd, + struct bfd_link_info *info, + Elf_Internal_Sym *isym, +- const char **name ATTRIBUTE_UNUSED, ++ const char **name, + flagword *flags ATTRIBUTE_UNUSED, + asection **sec, + bfd_vma *value ATTRIBUTE_UNUSED) +@@ -4649,9 +4655,35 @@ ppc64_elf_add_symbol_hook (bfd *ibfd, + && strcmp ((*sec)->name, ".opd") == 0) + isym->st_info = ELF_ST_INFO (ELF_ST_BIND (isym->st_info), STT_FUNC); + ++ if ((STO_PPC64_LOCAL_MASK & isym->st_other) != 0) ++ { ++ if (abiversion (ibfd) == 0) ++ set_abiversion (ibfd, 2); ++ else if (abiversion (ibfd) == 1) ++ { ++ info->callbacks->einfo (_("%P: symbol '%s' has invalid st_other" ++ " for ABI version 1\n"), name); ++ bfd_set_error (bfd_error_bad_value); ++ return FALSE; ++ } ++ } ++ + return TRUE; + } + ++/* Merge non-visibility st_other attributes: local entry point. */ ++ ++static void ++ppc64_elf_merge_symbol_attribute (struct elf_link_hash_entry *h, ++ const Elf_Internal_Sym *isym, ++ bfd_boolean definition, ++ bfd_boolean dynamic) ++{ ++ if (definition && !dynamic) ++ h->other = ((isym->st_other & ~ELF_ST_VISIBILITY (-1)) ++ | ELF_ST_VISIBILITY (h->other)); ++} ++ + /* This function makes an old ABI object reference to ".bar" cause the + inclusion of a new ABI object archive that defines "bar". + NAME is a symbol defined in an archive. Return a symbol in the hash +@@ -9586,7 +9618,8 @@ ppc_type_of_stub (asection *input_sec, + const Elf_Internal_Rela *rel, + struct ppc_link_hash_entry **hash, + struct plt_entry **plt_ent, +- bfd_vma destination) ++ bfd_vma destination, ++ unsigned long local_off) + { + struct ppc_link_hash_entry *h = *hash; + bfd_vma location; +@@ -9655,7 +9688,7 @@ ppc_type_of_stub (asection *input_sec, + if (r_type != R_PPC64_REL24) + max_branch_offset = 1 << 15; + +- if (branch_offset + max_branch_offset >= 2 * max_branch_offset) ++ if (branch_offset + max_branch_offset >= 2 * max_branch_offset - local_off) + /* We need a stub. Figure out whether a long_branch or plt_branch + is needed later. */ + return ppc_stub_long_branch; +@@ -10023,9 +10056,11 @@ ppc_build_one_stub (struct bfd_hash_entr + case ppc_stub_long_branch: + case ppc_stub_long_branch_r2off: + /* Branches are relative. This is where we are going to. */ +- off = dest = (stub_entry->target_value +- + stub_entry->target_section->output_offset +- + stub_entry->target_section->output_section->vma); ++ dest = (stub_entry->target_value ++ + stub_entry->target_section->output_offset ++ + stub_entry->target_section->output_section->vma); ++ dest += PPC64_LOCAL_ENTRY_OFFSET (stub_entry->other); ++ off = dest; + + /* And this is where we are coming from. */ + off -= (stub_entry->stub_offset +@@ -10128,6 +10163,8 @@ ppc_build_one_stub (struct bfd_hash_entr + dest = (stub_entry->target_value + + stub_entry->target_section->output_offset + + stub_entry->target_section->output_section->vma); ++ if (stub_entry->stub_type != ppc_stub_plt_branch_r2off) ++ dest += PPC64_LOCAL_ENTRY_OFFSET (stub_entry->other); + + bfd_put_64 (htab->brlt->owner, dest, + htab->brlt->contents + br_entry->offset); +@@ -10472,6 +10509,7 @@ ppc_size_one_stub (struct bfd_hash_entry + /* ppc_stub_long_branch or ppc_stub_plt_branch, or their r2off + variants. */ + bfd_vma r2off = 0; ++ bfd_vma local_off = 0; + + off = (stub_entry->target_value + + stub_entry->target_section->output_offset +@@ -10500,8 +10538,10 @@ ppc_size_one_stub (struct bfd_hash_entry + off -= size - 4; + } + ++ local_off = PPC64_LOCAL_ENTRY_OFFSET (stub_entry->other); ++ + /* If the branch offset if too big, use a ppc_stub_plt_branch. */ +- if (off + (1 << 25) >= (bfd_vma) (1 << 26)) ++ if (off + (1 << 25) >= (bfd_vma) (1 << 26) - local_off) + { + struct ppc_branch_hash_entry *br_entry; + +@@ -11097,7 +11137,10 @@ toc_adjusting_stub_needed (struct bfd_li + need a plt_branch stub. A plt_branch stub uses r2. */ + else if (dest - (isec->output_offset + + isec->output_section->vma +- + rel->r_offset) + (1 << 25) >= (2 << 25)) ++ + rel->r_offset) + (1 << 25) ++ >= (2u << 25) - PPC64_LOCAL_ENTRY_OFFSET (h ++ ? h->other ++ : sym->st_other)) + { + ret = 1; + break; +@@ -11553,6 +11596,7 @@ ppc64_elf_size_stubs (struct bfd_link_in + asection *sym_sec, *code_sec; + bfd_vma sym_value, code_value; + bfd_vma destination; ++ unsigned long local_off; + bfd_boolean ok_dest; + struct ppc_link_hash_entry *hash; + struct ppc_link_hash_entry *fdh; +@@ -11629,12 +11673,16 @@ ppc64_elf_size_stubs (struct bfd_link_in + } + + destination = 0; ++ local_off = 0; + if (ok_dest) + { + sym_value += irela->r_addend; + destination = (sym_value + + sym_sec->output_offset + + sym_sec->output_section->vma); ++ local_off = PPC64_LOCAL_ENTRY_OFFSET (hash ++ ? hash->elf.other ++ : sym->st_other); + } + + code_sec = sym_sec; +@@ -11671,7 +11719,8 @@ ppc64_elf_size_stubs (struct bfd_link_in + /* Determine what (if any) linker stub is needed. */ + plt_ent = NULL; + stub_type = ppc_type_of_stub (section, irela, &hash, +- &plt_ent, destination); ++ &plt_ent, destination, ++ local_off); + + if (stub_type != ppc_stub_plt_call) + { +@@ -11771,6 +11820,7 @@ ppc64_elf_size_stubs (struct bfd_link_in + } + stub_entry->h = hash; + stub_entry->plt_ent = plt_ent; ++ stub_entry->other = hash ? hash->elf.other : sym->st_other; + stub_entry->addend = irela->r_addend; + + if (stub_entry->h != NULL) +@@ -13105,6 +13155,10 @@ ppc64_elf_relocate_section (bfd *output_ + + input_section->output_offset + + input_section->output_section->vma); + ++ relocation += PPC64_LOCAL_ENTRY_OFFSET (fdh ++ ? fdh->elf.other ++ : sym->st_other); ++ + if (stub_entry != NULL + && (stub_entry->stub_type == ppc_stub_long_branch + || stub_entry->stub_type == ppc_stub_plt_branch) +Index: gdb-7.6.1/include/elf/ppc64.h +=================================================================== +--- gdb-7.6.1.orig/include/elf/ppc64.h ++++ gdb-7.6.1/include/elf/ppc64.h +@@ -171,6 +171,53 @@ END_RELOC_NUMBERS (R_PPC64_max) + 0 for unspecified or not using any features affected by the differences. */ + #define EF_PPC64_ABI 3 + ++/* The ELFv2 ABI uses three bits in the symbol st_other field of a ++ function definition to specify the number of instructions between a ++ function's global entry point and local entry point. ++ The global entry point is used when it is necessary to set up the ++ toc pointer (r2) for the function. Callers must enter the global ++ entry point with r12 set to the global entry point address. On ++ return from the function, r2 may have a different value to that ++ which it had on entry. ++ The local entry point is used when r2 is known to already be valid ++ for the function. There is no requirement on r12 when using the ++ local entry point, and on return r2 will contain the same value as ++ at entry. ++ A value of zero in these bits means that the function has a single ++ entry point with no requirement on r12 or r2, and that on return r2 ++ will contain the same value as at entry. ++ Values of one and seven are reserved. */ ++#define STO_PPC64_LOCAL_BIT 5 ++#define STO_PPC64_LOCAL_MASK (7 << STO_PPC64_LOCAL_BIT) ++ ++// 3 bit other field to bytes. ++static inline unsigned int ++ppc64_decode_local_entry(unsigned int other) ++{ ++ return ((1 << other) >> 2) << 2; ++} ++ ++// bytes to field value. ++static inline unsigned int ++ppc64_encode_local_entry(unsigned int val) ++{ ++ return (val >= 4 * 4 ++ ? (val >= 8 * 4 ++ ? (val >= 16 * 4 ? 6 : 5) ++ : 4) ++ : (val >= 2 * 4 ++ ? 3 ++ : (val >= 1 * 4 ? 2 : 0))); ++} ++ ++/* st_other to number of bytes. */ ++#define PPC64_LOCAL_ENTRY_OFFSET(other) \ ++ ppc64_decode_local_entry (((other) & STO_PPC64_LOCAL_MASK) \ ++ >> STO_PPC64_LOCAL_BIT) ++/* number of bytes to st_other. */ ++#define PPC64_SET_LOCAL_ENTRY_OFFSET(val) \ ++ ppc64_encode_local_entry (val) << STO_PPC64_LOCAL_BIT ++ + /* Specify the start of the .glink section. */ + #define DT_PPC64_GLINK DT_LOPROC + diff --git a/SOURCES/gdb-rhbz1125820-ppc64le-enablement-10of37.patch b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-10of37.patch new file mode 100644 index 0000000..c743a84 --- /dev/null +++ b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-10of37.patch @@ -0,0 +1,599 @@ +commit b9e5796b0d6ebc355e4a6d06791b7366939d10f2 +Author: Alan Modra +Date: Tue Oct 29 15:58:05 2013 +1030 + + ELFv2 stub, plt and glink changes + + An ELFv2 PLT entry is simply the address of the target function rather + than three (or two) words to specify entry, toc and static chain. PLT + call stubs are correspondingly simpler and need no thread safety + barrier. The glink resolver stub and branch table also is simplified, + a change that could be applied to ELFv1 too, but isn't as yet. + + * elf64-ppc.c (PLT_ENTRY_SIZE, PLT_INITIAL_ENTRY_SIZE): Add htab + parameter and adjust for ELFv2. Update all uses. + (PLT_CALL_STUB_SIZE): Delete. + (ppc64_elf_get_synthetic_symtab): Support new glink layout. + (allocate_dynrelocs): Likewise. + (plt_stub_size, build_plt_stub): Adjust for ELFv2. + (get_r2off): Return 0 for ELFv2 -R. + (ppc_build_one_stub, ppc_size_one_stub): Adjust for ELFv2. + (ppc64_elf_size_stubs): Likewise. + (ppc64_elf_build_stubs): Add new ELFv2 glink. + +Index: gdb-7.6.1/bfd/elf64-ppc.c +=================================================================== +--- gdb-7.6.1.orig/bfd/elf64-ppc.c ++++ gdb-7.6.1/bfd/elf64-ppc.c +@@ -125,10 +125,10 @@ static bfd_vma opd_entry_value + #define ELF_DYNAMIC_INTERPRETER "/usr/lib/ld.so.1" + + /* The size in bytes of an entry in the procedure linkage table. */ +-#define PLT_ENTRY_SIZE 24 ++#define PLT_ENTRY_SIZE(htab) (htab->opd_abi ? 24 : 8) + + /* The initial size of the plt reserved for the dynamic linker. */ +-#define PLT_INITIAL_ENTRY_SIZE PLT_ENTRY_SIZE ++#define PLT_INITIAL_ENTRY_SIZE(htab) (htab->opd_abi ? 24 : 16) + + /* TOC base pointers offset from start of TOC. */ + #define TOC_BASE_OFF 0x8000 +@@ -140,7 +140,6 @@ static bfd_vma opd_entry_value + /* .plt call stub instructions. The normal stub is like this, but + sometimes the .plt entry crosses a 64k boundary and we need to + insert an addi to adjust r11. */ +-#define PLT_CALL_STUB_SIZE (7*4) + #define STD_R2_40R1 0xf8410028 /* std %r2,40(%r1) */ + #define ADDIS_R11_R2 0x3d620000 /* addis %r11,%r2,xxx@ha */ + #define LD_R12_0R11 0xe98b0000 /* ld %r12,xxx+0@l(%r11) */ +@@ -184,6 +183,11 @@ static bfd_vma opd_entry_value + /* mtctr %12 */ + /* ld %11,16(%11) */ + /* bctr */ ++#define MFLR_R0 0x7c0802a6 /* mflr %r0 */ ++#define MTLR_R0 0x7c0803a6 /* mtlr %r0 */ ++#define SUB_R12_R12_R11 0x7d8b6050 /* subf %r12,%r11,%r12 */ ++#define ADDI_R0_R12 0x380c0000 /* addi %r0,%r12,0 */ ++#define SRDI_R0_R0_2 0x7800f082 /* rldicl %r0,%r0,62,2 */ + + /* Pad with this. */ + #define NOP 0x60000000 +@@ -3238,9 +3242,9 @@ ppc64_elf_get_synthetic_symtab (bfd *abf + + if (dyn.d_tag == DT_PPC64_GLINK) + { +- /* The first glink stub starts at offset 32; see comment in +- ppc64_elf_finish_dynamic_sections. */ +- glink_vma = dyn.d_un.d_val + 32; ++ /* The first glink stub starts at offset 32; see ++ comment in ppc64_elf_finish_dynamic_sections. */ ++ glink_vma = dyn.d_un.d_val + GLINK_CALL_STUB_SIZE - 8 * 4; + /* The .glink section usually does not survive the final + link; search for the section (usually .text) where the + glink stubs now reside. */ +@@ -3258,13 +3262,21 @@ ppc64_elf_get_synthetic_symtab (bfd *abf + /* Determine __glink trampoline by reading the relative branch + from the first glink stub. */ + bfd_byte buf[4]; +- if (bfd_get_section_contents (abfd, glink, buf, +- glink_vma + 4 - glink->vma, 4)) ++ unsigned int off = 0; ++ ++ while (bfd_get_section_contents (abfd, glink, buf, ++ glink_vma + off - glink->vma, 4)) + { + unsigned int insn = bfd_get_32 (abfd, buf); + insn ^= B_DOT; + if ((insn & ~0x3fffffc) == 0) +- resolv_vma = glink_vma + 4 + (insn ^ 0x2000000) - 0x2000000; ++ { ++ resolv_vma = glink_vma + off + (insn ^ 0x2000000) - 0x2000000; ++ break; ++ } ++ off += 4; ++ if (off > 4) ++ break; + } + + if (resolv_vma) +@@ -3417,8 +3429,13 @@ ppc64_elf_get_synthetic_symtab (bfd *abf + memcpy (names, "@plt", sizeof ("@plt")); + names += sizeof ("@plt"); + s++; +- glink_vma += 8; +- if (i >= 0x8000) ++ if (abi < 2) ++ { ++ glink_vma += 8; ++ if (i >= 0x8000) ++ glink_vma += 4; ++ } ++ else + glink_vma += 4; + } + count += plt_count; +@@ -9021,7 +9038,7 @@ allocate_dynrelocs (struct elf_link_hash + { + s = htab->iplt; + pent->plt.offset = s->size; +- s->size += PLT_ENTRY_SIZE; ++ s->size += PLT_ENTRY_SIZE (htab); + s = htab->reliplt; + } + else +@@ -9030,21 +9047,26 @@ allocate_dynrelocs (struct elf_link_hash + first entry. */ + s = htab->plt; + if (s->size == 0) +- s->size += PLT_INITIAL_ENTRY_SIZE; ++ s->size += PLT_INITIAL_ENTRY_SIZE (htab); + + pent->plt.offset = s->size; + + /* Make room for this entry. */ +- s->size += PLT_ENTRY_SIZE; ++ s->size += PLT_ENTRY_SIZE (htab); + + /* Make room for the .glink code. */ + s = htab->glink; + if (s->size == 0) + s->size += GLINK_CALL_STUB_SIZE; +- /* We need bigger stubs past index 32767. */ +- if (s->size >= GLINK_CALL_STUB_SIZE + 32768*2*4) ++ if (htab->opd_abi) ++ { ++ /* We need bigger stubs past index 32767. */ ++ if (s->size >= GLINK_CALL_STUB_SIZE + 32768*2*4) ++ s->size += 4; ++ s->size += 2*4; ++ } ++ else + s->size += 4; +- s->size += 2*4; + + /* We also need to make an entry in the .rela.plt section. */ + s = htab->relplt; +@@ -9393,7 +9415,7 @@ ppc64_elf_size_dynamic_sections (bfd *ou + { + s = htab->iplt; + ent->plt.offset = s->size; +- s->size += PLT_ENTRY_SIZE; ++ s->size += PLT_ENTRY_SIZE (htab); + + htab->reliplt->size += sizeof (Elf64_External_Rela); + } +@@ -9727,19 +9749,23 @@ plt_stub_size (struct ppc_link_hash_tabl + struct ppc_stub_hash_entry *stub_entry, + bfd_vma off) + { +- unsigned size = PLT_CALL_STUB_SIZE; ++ unsigned size = 12; + +- if (!(ALWAYS_EMIT_R2SAVE +- || stub_entry->stub_type == ppc_stub_plt_call_r2save)) +- size -= 4; +- if (!htab->plt_static_chain) +- size -= 4; +- if (htab->plt_thread_safe) +- size += 8; +- if (PPC_HA (off) == 0) +- size -= 4; +- if (PPC_HA (off + 8 + 8 * htab->plt_static_chain) != PPC_HA (off)) ++ if (ALWAYS_EMIT_R2SAVE ++ || stub_entry->stub_type == ppc_stub_plt_call_r2save) + size += 4; ++ if (PPC_HA (off) != 0) ++ size += 4; ++ if (htab->opd_abi) ++ { ++ size += 4; ++ if (htab->plt_static_chain) ++ size += 4; ++ if (htab->plt_thread_safe) ++ size += 8; ++ if (PPC_HA (off + 8 + 8 * htab->plt_static_chain) != PPC_HA (off)) ++ size += 4; ++ } + if (stub_entry->h != NULL + && (stub_entry->h == htab->tls_get_addr_fd + || stub_entry->h == htab->tls_get_addr) +@@ -9773,12 +9799,14 @@ build_plt_stub (struct ppc_link_hash_tab + bfd_byte *p, bfd_vma offset, Elf_Internal_Rela *r) + { + bfd *obfd = htab->stub_bfd; ++ bfd_boolean plt_load_toc = htab->opd_abi; + bfd_boolean plt_static_chain = htab->plt_static_chain; + bfd_boolean plt_thread_safe = htab->plt_thread_safe; + bfd_boolean use_fake_dep = plt_thread_safe; + bfd_vma cmp_branch_off = 0; + + if (!ALWAYS_USE_FAKE_DEP ++ && plt_load_toc + && plt_thread_safe + && !(stub_entry->h != NULL + && (stub_entry->h == htab->tls_get_addr_fd +@@ -9786,7 +9814,8 @@ build_plt_stub (struct ppc_link_hash_tab + && !htab->no_tls_get_addr_opt)) + { + bfd_vma pltoff = stub_entry->plt_ent->plt.offset & ~1; +- bfd_vma pltindex = (pltoff - PLT_INITIAL_ENTRY_SIZE) / PLT_ENTRY_SIZE; ++ bfd_vma pltindex = ((pltoff - PLT_INITIAL_ENTRY_SIZE (htab)) ++ / PLT_ENTRY_SIZE (htab)); + bfd_vma glinkoff = GLINK_CALL_STUB_SIZE + pltindex * 8; + bfd_vma to, from; + +@@ -9820,22 +9849,25 @@ build_plt_stub (struct ppc_link_hash_tab + r[1].r_offset = r[0].r_offset + 4; + r[1].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO_DS); + r[1].r_addend = r[0].r_addend; +- if (PPC_HA (offset + 8 + 8 * plt_static_chain) != PPC_HA (offset)) +- { +- r[2].r_offset = r[1].r_offset + 4; +- r[2].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO); +- r[2].r_addend = r[0].r_addend; +- } +- else ++ if (plt_load_toc) + { +- r[2].r_offset = r[1].r_offset + 8 + 8 * use_fake_dep; +- r[2].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO_DS); +- r[2].r_addend = r[0].r_addend + 8; +- if (plt_static_chain) +- { +- r[3].r_offset = r[2].r_offset + 4; +- r[3].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO_DS); +- r[3].r_addend = r[0].r_addend + 16; ++ if (PPC_HA (offset + 8 + 8 * plt_static_chain) != PPC_HA (offset)) ++ { ++ r[2].r_offset = r[1].r_offset + 4; ++ r[2].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO); ++ r[2].r_addend = r[0].r_addend; ++ } ++ else ++ { ++ r[2].r_offset = r[1].r_offset + 8 + 8 * use_fake_dep; ++ r[2].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO_DS); ++ r[2].r_addend = r[0].r_addend + 8; ++ if (plt_static_chain) ++ { ++ r[3].r_offset = r[2].r_offset + 4; ++ r[3].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO_DS); ++ r[3].r_addend = r[0].r_addend + 16; ++ } + } + } + } +@@ -9844,20 +9876,24 @@ build_plt_stub (struct ppc_link_hash_tab + bfd_put_32 (obfd, STD_R2_40R1, p), p += 4; + bfd_put_32 (obfd, ADDIS_R11_R2 | PPC_HA (offset), p), p += 4; + bfd_put_32 (obfd, LD_R12_0R11 | PPC_LO (offset), p), p += 4; +- if (PPC_HA (offset + 8 + 8 * plt_static_chain) != PPC_HA (offset)) ++ if (plt_load_toc ++ && PPC_HA (offset + 8 + 8 * plt_static_chain) != PPC_HA (offset)) + { + bfd_put_32 (obfd, ADDI_R11_R11 | PPC_LO (offset), p), p += 4; + offset = 0; + } + bfd_put_32 (obfd, MTCTR_R12, p), p += 4; +- if (use_fake_dep) ++ if (plt_load_toc) + { +- bfd_put_32 (obfd, XOR_R2_R12_R12, p), p += 4; +- bfd_put_32 (obfd, ADD_R11_R11_R2, p), p += 4; ++ if (use_fake_dep) ++ { ++ bfd_put_32 (obfd, XOR_R2_R12_R12, p), p += 4; ++ bfd_put_32 (obfd, ADD_R11_R11_R2, p), p += 4; ++ } ++ bfd_put_32 (obfd, LD_R2_0R11 | PPC_LO (offset + 8), p), p += 4; ++ if (plt_static_chain) ++ bfd_put_32 (obfd, LD_R11_0R11 | PPC_LO (offset + 16), p), p += 4; + } +- bfd_put_32 (obfd, LD_R2_0R11 | PPC_LO (offset + 8), p), p += 4; +- if (plt_static_chain) +- bfd_put_32 (obfd, LD_R11_0R11 | PPC_LO (offset + 16), p), p += 4; + } + else + { +@@ -9867,22 +9903,25 @@ build_plt_stub (struct ppc_link_hash_tab + || stub_entry->stub_type == ppc_stub_plt_call_r2save) + r[0].r_offset += 4; + r[0].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS); +- if (PPC_HA (offset + 8 + 8 * plt_static_chain) != PPC_HA (offset)) ++ if (plt_load_toc) + { +- r[1].r_offset = r[0].r_offset + 4; +- r[1].r_info = ELF64_R_INFO (0, R_PPC64_TOC16); +- r[1].r_addend = r[0].r_addend; +- } +- else +- { +- r[1].r_offset = r[0].r_offset + 8 + 8 * use_fake_dep; +- r[1].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS); +- r[1].r_addend = r[0].r_addend + 8 + 8 * plt_static_chain; +- if (plt_static_chain) ++ if (PPC_HA (offset + 8 + 8 * plt_static_chain) != PPC_HA (offset)) + { +- r[2].r_offset = r[1].r_offset + 4; +- r[2].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS); +- r[2].r_addend = r[0].r_addend + 8; ++ r[1].r_offset = r[0].r_offset + 4; ++ r[1].r_info = ELF64_R_INFO (0, R_PPC64_TOC16); ++ r[1].r_addend = r[0].r_addend; ++ } ++ else ++ { ++ r[1].r_offset = r[0].r_offset + 8 + 8 * use_fake_dep; ++ r[1].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS); ++ r[1].r_addend = r[0].r_addend + 8 + 8 * plt_static_chain; ++ if (plt_static_chain) ++ { ++ r[2].r_offset = r[1].r_offset + 4; ++ r[2].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS); ++ r[2].r_addend = r[0].r_addend + 8; ++ } + } + } + } +@@ -9890,22 +9929,26 @@ build_plt_stub (struct ppc_link_hash_tab + || stub_entry->stub_type == ppc_stub_plt_call_r2save) + bfd_put_32 (obfd, STD_R2_40R1, p), p += 4; + bfd_put_32 (obfd, LD_R12_0R2 | PPC_LO (offset), p), p += 4; +- if (PPC_HA (offset + 8 + 8 * plt_static_chain) != PPC_HA (offset)) ++ if (plt_load_toc ++ && PPC_HA (offset + 8 + 8 * plt_static_chain) != PPC_HA (offset)) + { + bfd_put_32 (obfd, ADDI_R2_R2 | PPC_LO (offset), p), p += 4; + offset = 0; + } + bfd_put_32 (obfd, MTCTR_R12, p), p += 4; +- if (use_fake_dep) ++ if (plt_load_toc) + { +- bfd_put_32 (obfd, XOR_R11_R12_R12, p), p += 4; +- bfd_put_32 (obfd, ADD_R2_R2_R11, p), p += 4; ++ if (use_fake_dep) ++ { ++ bfd_put_32 (obfd, XOR_R11_R12_R12, p), p += 4; ++ bfd_put_32 (obfd, ADD_R2_R2_R11, p), p += 4; ++ } ++ if (plt_static_chain) ++ bfd_put_32 (obfd, LD_R11_0R2 | PPC_LO (offset + 16), p), p += 4; ++ bfd_put_32 (obfd, LD_R2_0R2 | PPC_LO (offset + 8), p), p += 4; + } +- if (plt_static_chain) +- bfd_put_32 (obfd, LD_R11_0R2 | PPC_LO (offset + 16), p), p += 4; +- bfd_put_32 (obfd, LD_R2_0R2 | PPC_LO (offset + 8), p), p += 4; + } +- if (plt_thread_safe && !use_fake_dep) ++ if (plt_load_toc && plt_thread_safe && !use_fake_dep) + { + bfd_put_32 (obfd, CMPLDI_R2_0, p), p += 4; + bfd_put_32 (obfd, BNECTR_P4, p), p += 4; +@@ -10004,6 +10047,8 @@ get_r2off (struct bfd_link_info *info, + /* Support linking -R objects. Get the toc pointer from the + opd entry. */ + char buf[8]; ++ if (!htab->opd_abi) ++ return r2off; + asection *opd = stub_entry->h->elf.root.u.def.section; + bfd_vma opd_off = stub_entry->h->elf.root.u.def.value; + +@@ -10233,7 +10278,8 @@ ppc_build_one_stub (struct bfd_hash_entr + r[0].r_offset = loc - stub_entry->stub_sec->contents; + if (bfd_big_endian (info->output_bfd)) + r[0].r_offset += 2; +- if (stub_entry->stub_type == ppc_stub_plt_branch_r2off) ++ if (stub_entry->stub_type == ppc_stub_plt_branch_r2off ++ && htab->opd_abi) + r[0].r_offset += 4; + r[0].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS); + r[0].r_addend = dest; +@@ -10246,7 +10292,8 @@ ppc_build_one_stub (struct bfd_hash_entr + } + } + +- if (stub_entry->stub_type != ppc_stub_plt_branch_r2off) ++ if (stub_entry->stub_type != ppc_stub_plt_branch_r2off ++ || !htab->opd_abi) + { + if (PPC_HA (off) != 0) + { +@@ -10497,10 +10544,11 @@ ppc_size_one_stub (struct bfd_hash_entry + if (info->emitrelocations) + { + stub_entry->stub_sec->reloc_count +- += (2 +- + (PPC_HA (off) != 0) +- + (htab->plt_static_chain +- && PPC_HA (off + 16) == PPC_HA (off))); ++ += ((PPC_HA (off) != 0) ++ + (htab->opd_abi ++ ? 2 + (htab->plt_static_chain ++ && PPC_HA (off + 16) == PPC_HA (off)) ++ : 1)); + stub_entry->stub_sec->flags |= SEC_RELOC; + } + } +@@ -10527,7 +10575,7 @@ ppc_size_one_stub (struct bfd_hash_entry + if (stub_entry->stub_type == ppc_stub_long_branch_r2off) + { + r2off = get_r2off (info, stub_entry); +- if (r2off == 0) ++ if (r2off == 0 && htab->opd_abi) + { + htab->stub_error = TRUE; + return FALSE; +@@ -10540,8 +10588,11 @@ ppc_size_one_stub (struct bfd_hash_entry + + local_off = PPC64_LOCAL_ENTRY_OFFSET (stub_entry->other); + +- /* If the branch offset if too big, use a ppc_stub_plt_branch. */ +- if (off + (1 << 25) >= (bfd_vma) (1 << 26) - local_off) ++ /* If the branch offset if too big, use a ppc_stub_plt_branch. ++ Do the same for -R objects without function descriptors. */ ++ if (off + (1 << 25) >= (bfd_vma) (1 << 26) - local_off ++ || (stub_entry->stub_type == ppc_stub_long_branch_r2off ++ && r2off == 0)) + { + struct ppc_branch_hash_entry *br_entry; + +@@ -10584,7 +10635,8 @@ ppc_size_one_stub (struct bfd_hash_entry + stub_entry->stub_sec->flags |= SEC_RELOC; + } + +- if (stub_entry->stub_type != ppc_stub_plt_branch_r2off) ++ if (stub_entry->stub_type != ppc_stub_plt_branch_r2off ++ || !htab->opd_abi) + { + size = 12; + if (PPC_HA (off) != 0) +@@ -11487,7 +11539,9 @@ ppc64_elf_size_stubs (struct bfd_link_in + htab->plt_stub_align = plt_stub_align; + if (plt_thread_safe == -1 && !info->executable) + plt_thread_safe = 1; +- if (plt_thread_safe == -1) ++ if (!htab->opd_abi) ++ plt_thread_safe = 0; ++ else if (plt_thread_safe == -1) + { + static const char *const thread_starter[] = + { +@@ -12059,26 +12113,56 @@ ppc64_elf_build_stubs (bfd_boolean emit_ + plt0 -= htab->glink->output_section->vma + htab->glink->output_offset; + bfd_put_64 (htab->glink->owner, plt0, p); + p += 8; +- bfd_put_32 (htab->glink->owner, MFLR_R12, p); +- p += 4; +- bfd_put_32 (htab->glink->owner, BCL_20_31, p); +- p += 4; +- bfd_put_32 (htab->glink->owner, MFLR_R11, p); +- p += 4; +- bfd_put_32 (htab->glink->owner, LD_R2_0R11 | (-16 & 0xfffc), p); +- p += 4; +- bfd_put_32 (htab->glink->owner, MTLR_R12, p); +- p += 4; +- bfd_put_32 (htab->glink->owner, ADD_R11_R2_R11, p); +- p += 4; +- bfd_put_32 (htab->glink->owner, LD_R12_0R11, p); +- p += 4; +- bfd_put_32 (htab->glink->owner, LD_R2_0R11 | 8, p); +- p += 4; +- bfd_put_32 (htab->glink->owner, MTCTR_R12, p); +- p += 4; +- bfd_put_32 (htab->glink->owner, LD_R11_0R11 | 16, p); +- p += 4; ++ if (htab->opd_abi) ++ { ++ bfd_put_32 (htab->glink->owner, MFLR_R12, p); ++ p += 4; ++ bfd_put_32 (htab->glink->owner, BCL_20_31, p); ++ p += 4; ++ bfd_put_32 (htab->glink->owner, MFLR_R11, p); ++ p += 4; ++ bfd_put_32 (htab->glink->owner, LD_R2_0R11 | (-16 & 0xfffc), p); ++ p += 4; ++ bfd_put_32 (htab->glink->owner, MTLR_R12, p); ++ p += 4; ++ bfd_put_32 (htab->glink->owner, ADD_R11_R2_R11, p); ++ p += 4; ++ bfd_put_32 (htab->glink->owner, LD_R12_0R11, p); ++ p += 4; ++ bfd_put_32 (htab->glink->owner, LD_R2_0R11 | 8, p); ++ p += 4; ++ bfd_put_32 (htab->glink->owner, MTCTR_R12, p); ++ p += 4; ++ bfd_put_32 (htab->glink->owner, LD_R11_0R11 | 16, p); ++ p += 4; ++ } ++ else ++ { ++ bfd_put_32 (htab->glink->owner, MFLR_R0, p); ++ p += 4; ++ bfd_put_32 (htab->glink->owner, BCL_20_31, p); ++ p += 4; ++ bfd_put_32 (htab->glink->owner, MFLR_R11, p); ++ p += 4; ++ bfd_put_32 (htab->glink->owner, LD_R2_0R11 | (-16 & 0xfffc), p); ++ p += 4; ++ bfd_put_32 (htab->glink->owner, MTLR_R0, p); ++ p += 4; ++ bfd_put_32 (htab->glink->owner, SUB_R12_R12_R11, p); ++ p += 4; ++ bfd_put_32 (htab->glink->owner, ADD_R11_R2_R11, p); ++ p += 4; ++ bfd_put_32 (htab->glink->owner, ADDI_R0_R12 | (-48 & 0xffff), p); ++ p += 4; ++ bfd_put_32 (htab->glink->owner, LD_R12_0R11, p); ++ p += 4; ++ bfd_put_32 (htab->glink->owner, SRDI_R0_R0_2, p); ++ p += 4; ++ bfd_put_32 (htab->glink->owner, MTCTR_R12, p); ++ p += 4; ++ bfd_put_32 (htab->glink->owner, LD_R11_0R11 | 8, p); ++ p += 4; ++ } + bfd_put_32 (htab->glink->owner, BCTR, p); + p += 4; + while (p - htab->glink->contents < GLINK_CALL_STUB_SIZE) +@@ -12091,17 +12175,21 @@ ppc64_elf_build_stubs (bfd_boolean emit_ + indx = 0; + while (p < htab->glink->contents + htab->glink->size) + { +- if (indx < 0x8000) +- { +- bfd_put_32 (htab->glink->owner, LI_R0_0 | indx, p); +- p += 4; +- } +- else ++ if (htab->opd_abi) + { +- bfd_put_32 (htab->glink->owner, LIS_R0_0 | PPC_HI (indx), p); +- p += 4; +- bfd_put_32 (htab->glink->owner, ORI_R0_R0_0 | PPC_LO (indx), p); +- p += 4; ++ if (indx < 0x8000) ++ { ++ bfd_put_32 (htab->glink->owner, LI_R0_0 | indx, p); ++ p += 4; ++ } ++ else ++ { ++ bfd_put_32 (htab->glink->owner, LIS_R0_0 | PPC_HI (indx), p); ++ p += 4; ++ bfd_put_32 (htab->glink->owner, ORI_R0_R0_0 | PPC_LO (indx), ++ p); ++ p += 4; ++ } + } + bfd_put_32 (htab->glink->owner, + B_DOT | ((htab->glink->contents - p + 8) & 0x3fffffc), p); +@@ -14192,8 +14280,8 @@ ppc64_elf_finish_dynamic_symbol (bfd *ou + rela.r_info = ELF64_R_INFO (h->dynindx, R_PPC64_JMP_SLOT); + rela.r_addend = ent->addend; + loc = (htab->relplt->contents +- + ((ent->plt.offset - PLT_INITIAL_ENTRY_SIZE) +- / (PLT_ENTRY_SIZE / sizeof (Elf64_External_Rela)))); ++ + ((ent->plt.offset - PLT_INITIAL_ENTRY_SIZE (htab)) ++ / PLT_ENTRY_SIZE (htab) * sizeof (Elf64_External_Rela))); + } + bfd_elf64_swap_reloca_out (output_bfd, &rela, loc); + } +@@ -14288,7 +14376,7 @@ ppc64_elf_finish_dynamic_sections (bfd * + of glink rather than the first entry point, which is + what ld.so needs, and now have a bigger stub to + support automatic multiple TOCs. */ +- dyn.d_un.d_ptr += GLINK_CALL_STUB_SIZE - 32; ++ dyn.d_un.d_ptr += GLINK_CALL_STUB_SIZE - 8 * 4; + break; + + case DT_PPC64_OPD: +@@ -14361,7 +14449,7 @@ ppc64_elf_finish_dynamic_sections (bfd * + { + /* Set .plt entry size. */ + elf_section_data (htab->plt->output_section)->this_hdr.sh_entsize +- = PLT_ENTRY_SIZE; ++ = PLT_ENTRY_SIZE (htab); + } + + /* brlt is SEC_LINKER_CREATED, so we need to write out relocs for diff --git a/SOURCES/gdb-rhbz1125820-ppc64le-enablement-11of37.patch b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-11of37.patch new file mode 100644 index 0000000..b3bd952 --- /dev/null +++ b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-11of37.patch @@ -0,0 +1,173 @@ +commit a078d95abc554b6c2572fcab5550591639b1c871 +Author: Alan Modra +Date: Tue Oct 29 16:17:22 2013 +1030 + + Support ELFv2 stack frame. + + The toc pointer save slot changes on ELFv2 from 40(1) to 24(1). + + * elf64-ppc.c (STK_LR, STK_TOC, STK_LINKER): Define. + (savegpr0_tail, restgpr0_tail, savefpr0_tail, restfpr0_tail) + build_plt_stub, build_tls_get_addr_stub, ppc_build_one_stub, + ppc64_elf_relocate_section): Use new defines. + +Index: gdb-7.6.1/bfd/elf64-ppc.c +=================================================================== +--- gdb-7.6.1.orig/bfd/elf64-ppc.c ++++ gdb-7.6.1/bfd/elf64-ppc.c +@@ -130,6 +130,14 @@ static bfd_vma opd_entry_value + /* The initial size of the plt reserved for the dynamic linker. */ + #define PLT_INITIAL_ENTRY_SIZE(htab) (htab->opd_abi ? 24 : 16) + ++/* Offsets to some stack save slots. */ ++#define STK_LR 16 ++#define STK_TOC(htab) (htab->opd_abi ? 40 : 24) ++/* This one is dodgy. ABIv2 does not have a linker word, so use the ++ CR save slot. Used only by optimised __tls_get_addr call stub, ++ relying on __tls_get_addr_opt not saving CR.. */ ++#define STK_LINKER(htab) (htab->opd_abi ? 32 : 8) ++ + /* TOC base pointers offset from start of TOC. */ + #define TOC_BASE_OFF 0x8000 + +@@ -140,7 +148,7 @@ static bfd_vma opd_entry_value + /* .plt call stub instructions. The normal stub is like this, but + sometimes the .plt entry crosses a 64k boundary and we need to + insert an addi to adjust r11. */ +-#define STD_R2_40R1 0xf8410028 /* std %r2,40(%r1) */ ++#define STD_R2_0R1 0xf8410000 /* std %r2,0+40(%r1) */ + #define ADDIS_R11_R2 0x3d620000 /* addis %r11,%r2,xxx@ha */ + #define LD_R12_0R11 0xe98b0000 /* ld %r12,xxx+0@l(%r11) */ + #define MTCTR_R12 0x7d8903a6 /* mtctr %r12 */ +@@ -164,7 +172,7 @@ static bfd_vma opd_entry_value + #define LD_R11_0R2 0xe9620000 /* ld %r11,xxx+0(%r2) */ + #define LD_R2_0R2 0xe8420000 /* ld %r2,xxx+0(%r2) */ + +-#define LD_R2_40R1 0xe8410028 /* ld %r2,40(%r1) */ ++#define LD_R2_0R1 0xe8410000 /* ld %r2,0(%r1) */ + + /* glink call stub instructions. We enter with the index in R0. */ + #define GLINK_CALL_STUB_SIZE (16*4) +@@ -6326,7 +6334,7 @@ static bfd_byte * + savegpr0_tail (bfd *abfd, bfd_byte *p, int r) + { + p = savegpr0 (abfd, p, r); +- bfd_put_32 (abfd, STD_R0_0R1 + 16, p); ++ bfd_put_32 (abfd, STD_R0_0R1 + STK_LR, p); + p = p + 4; + bfd_put_32 (abfd, BLR, p); + return p + 4; +@@ -6342,7 +6350,7 @@ restgpr0 (bfd *abfd, bfd_byte *p, int r) + static bfd_byte * + restgpr0_tail (bfd *abfd, bfd_byte *p, int r) + { +- bfd_put_32 (abfd, LD_R0_0R1 + 16, p); ++ bfd_put_32 (abfd, LD_R0_0R1 + STK_LR, p); + p = p + 4; + p = restgpr0 (abfd, p, r); + bfd_put_32 (abfd, MTLR_R0, p); +@@ -6397,7 +6405,7 @@ static bfd_byte * + savefpr0_tail (bfd *abfd, bfd_byte *p, int r) + { + p = savefpr (abfd, p, r); +- bfd_put_32 (abfd, STD_R0_0R1 + 16, p); ++ bfd_put_32 (abfd, STD_R0_0R1 + STK_LR, p); + p = p + 4; + bfd_put_32 (abfd, BLR, p); + return p + 4; +@@ -6413,7 +6421,7 @@ restfpr (bfd *abfd, bfd_byte *p, int r) + static bfd_byte * + restfpr0_tail (bfd *abfd, bfd_byte *p, int r) + { +- bfd_put_32 (abfd, LD_R0_0R1 + 16, p); ++ bfd_put_32 (abfd, LD_R0_0R1 + STK_LR, p); + p = p + 4; + p = restfpr (abfd, p, r); + bfd_put_32 (abfd, MTLR_R0, p); +@@ -9873,7 +9881,7 @@ build_plt_stub (struct ppc_link_hash_tab + } + if (ALWAYS_EMIT_R2SAVE + || stub_entry->stub_type == ppc_stub_plt_call_r2save) +- bfd_put_32 (obfd, STD_R2_40R1, p), p += 4; ++ bfd_put_32 (obfd, STD_R2_0R1 + STK_TOC (htab), p), p += 4; + bfd_put_32 (obfd, ADDIS_R11_R2 | PPC_HA (offset), p), p += 4; + bfd_put_32 (obfd, LD_R12_0R11 | PPC_LO (offset), p), p += 4; + if (plt_load_toc +@@ -9927,7 +9935,7 @@ build_plt_stub (struct ppc_link_hash_tab + } + if (ALWAYS_EMIT_R2SAVE + || stub_entry->stub_type == ppc_stub_plt_call_r2save) +- bfd_put_32 (obfd, STD_R2_40R1, p), p += 4; ++ bfd_put_32 (obfd, STD_R2_0R1 + STK_TOC (htab), p), p += 4; + bfd_put_32 (obfd, LD_R12_0R2 | PPC_LO (offset), p), p += 4; + if (plt_load_toc + && PPC_HA (offset + 8 + 8 * plt_static_chain) != PPC_HA (offset)) +@@ -9968,11 +9976,9 @@ build_plt_stub (struct ppc_link_hash_tab + #define ADD_R3_R12_R13 0x7c6c6a14 + #define BEQLR 0x4d820020 + #define MR_R3_R0 0x7c030378 +-#define MFLR_R11 0x7d6802a6 + #define STD_R11_0R1 0xf9610000 + #define BCTRL 0x4e800421 + #define LD_R11_0R1 0xe9610000 +-#define LD_R2_0R1 0xe8410000 + #define MTLR_R11 0x7d6803a6 + + static inline bfd_byte * +@@ -9990,15 +9996,15 @@ build_tls_get_addr_stub (struct ppc_link + bfd_put_32 (obfd, BEQLR, p), p += 4; + bfd_put_32 (obfd, MR_R3_R0, p), p += 4; + bfd_put_32 (obfd, MFLR_R11, p), p += 4; +- bfd_put_32 (obfd, STD_R11_0R1 + 32, p), p += 4; ++ bfd_put_32 (obfd, STD_R11_0R1 + STK_LINKER (htab), p), p += 4; + + if (r != NULL) + r[0].r_offset += 9 * 4; + p = build_plt_stub (htab, stub_entry, p, offset, r); + bfd_put_32 (obfd, BCTRL, p - 4); + +- bfd_put_32 (obfd, LD_R11_0R1 + 32, p), p += 4; +- bfd_put_32 (obfd, LD_R2_0R1 + 40, p), p += 4; ++ bfd_put_32 (obfd, LD_R11_0R1 + STK_LINKER (htab), p), p += 4; ++ bfd_put_32 (obfd, LD_R2_0R1 + STK_TOC (htab), p), p += 4; + bfd_put_32 (obfd, MTLR_R11, p), p += 4; + bfd_put_32 (obfd, BLR, p), p += 4; + +@@ -10122,7 +10128,7 @@ ppc_build_one_stub (struct bfd_hash_entr + htab->stub_error = TRUE; + return FALSE; + } +- bfd_put_32 (htab->stub_bfd, STD_R2_40R1, loc); ++ bfd_put_32 (htab->stub_bfd, STD_R2_0R1 + STK_TOC (htab), loc); + loc += 4; + size = 12; + if (PPC_HA (r2off) != 0) +@@ -10318,7 +10324,7 @@ ppc_build_one_stub (struct bfd_hash_entr + return FALSE; + } + +- bfd_put_32 (htab->stub_bfd, STD_R2_40R1, loc); ++ bfd_put_32 (htab->stub_bfd, STD_R2_0R1 + STK_TOC (htab), loc); + loc += 4; + size = 20; + if (PPC_HA (off) != 0) +@@ -13113,7 +13119,8 @@ ppc64_elf_relocate_section (bfd *output_ + insn = bfd_get_32 (input_bfd, contents + rel->r_offset); + if (insn == NOP + || insn == CROR_151515 || insn == CROR_313131) +- bfd_put_32 (input_bfd, STD_R2_40R1, ++ bfd_put_32 (input_bfd, ++ STD_R2_0R1 + STK_TOC (htab), + contents + rel->r_offset); + } + break; +@@ -13172,7 +13179,8 @@ ppc64_elf_relocate_section (bfd *output_ + /* Special stub used, leave nop alone. */ + } + else +- bfd_put_32 (input_bfd, LD_R2_40R1, ++ bfd_put_32 (input_bfd, ++ LD_R2_0R1 + STK_TOC (htab), + contents + rel->r_offset + 4); + can_plt_call = TRUE; + } diff --git a/SOURCES/gdb-rhbz1125820-ppc64le-enablement-12of37.patch b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-12of37.patch new file mode 100644 index 0000000..2e6bad9 --- /dev/null +++ b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-12of37.patch @@ -0,0 +1,115 @@ +commit e8910a83af41c3dbfd00191b2720d4094f8d9532 +Author: Alan Modra +Date: Tue Oct 29 16:34:35 2013 +1030 + + Replace DT_PPC_TLSOPT with DT_PPC_OPT. + + This removes the DT_PPC_TLSOPT/DT_PPC64_TLSOPT dynamic tag and replaces + it with DT_PPC_OPT/DT_PPC64_OPT tag to provide the same functionality + and more. This isn't backwards compatible, but the TLSOPT tag hasn't + been used since the tls optimisation support was never submitted to + glibc. + + /include/elf/ + * ppc.h (DT_PPC_TLSOPT): Delete. + (DT_PPC_OPT, PPC_OPT_TLS): Define. + * ppc64.h (DT_PPC64_TLSOPT): Delete. + (DT_PPC64_OPT, PPC64_OPT_TLS, PPC64_OPT_MULTI_TOC): Define. + bfd/ + * elf32-ppc.c (ppc_elf_size_dynamic_sections): Use new DT_PPC_OPT + tag to specify tls optimisation. + * elf64-ppc.c (ppc64_elf_size_dynamic_sections): Likewise. + (ppc64_elf_finish_dynamic_sections): Specify whether multiple + toc pointers are used via DT_PPC64_OPT. + binutils/ + * readelf.c (get_ppc_dynamic_type): Replace PPC_TLSOPT with PPC_OPT. + (get_ppc64_dynamic_type): Replace PPC64_TLSOPT with PPC64_OPT. + +Index: gdb-7.6.1/bfd/elf32-ppc.c +=================================================================== +--- gdb-7.6.1.orig/bfd/elf32-ppc.c ++++ gdb-7.6.1/bfd/elf32-ppc.c +@@ -6443,7 +6443,7 @@ ppc_elf_size_dynamic_sections (bfd *outp + if (!htab->no_tls_get_addr_opt + && htab->tls_get_addr != NULL + && htab->tls_get_addr->plt.plist != NULL +- && !add_dynamic_entry (DT_PPC_TLSOPT, 0)) ++ && !add_dynamic_entry (DT_PPC_OPT, PPC_OPT_TLS)) + return FALSE; + } + +Index: gdb-7.6.1/bfd/elf64-ppc.c +=================================================================== +--- gdb-7.6.1.orig/bfd/elf64-ppc.c ++++ gdb-7.6.1/bfd/elf64-ppc.c +@@ -9580,6 +9580,8 @@ ppc64_elf_size_dynamic_sections (bfd *ou + + if (htab->elf.dynamic_sections_created) + { ++ bfd_boolean tls_opt; ++ + /* Add some entries to the .dynamic section. We fill in the + values later, in ppc64_elf_finish_dynamic_sections, but we + must add the entries now so that we get the correct size for +@@ -9611,11 +9613,14 @@ ppc64_elf_size_dynamic_sections (bfd *ou + return FALSE; + } + +- if (!htab->no_tls_get_addr_opt +- && htab->tls_get_addr_fd != NULL +- && htab->tls_get_addr_fd->elf.plt.plist != NULL +- && !add_dynamic_entry (DT_PPC64_TLSOPT, 0)) +- return FALSE; ++ tls_opt = (!htab->no_tls_get_addr_opt ++ && htab->tls_get_addr_fd != NULL ++ && htab->tls_get_addr_fd->elf.plt.plist != NULL); ++ if (tls_opt || !htab->opd_abi) ++ { ++ if (!add_dynamic_entry (DT_PPC64_OPT, tls_opt ? PPC64_OPT_TLS : 0)) ++ return FALSE; ++ } + + if (relocs) + { +@@ -14394,6 +14399,11 @@ ppc64_elf_finish_dynamic_sections (bfd * + dyn.d_un.d_ptr = s->vma; + break; + ++ case DT_PPC64_OPT: ++ if (htab->do_multi_toc && htab->multi_toc_needed) ++ dyn.d_un.d_val |= PPC64_OPT_MULTI_TOC; ++ break; ++ + case DT_PPC64_OPDSZ: + s = bfd_get_section_by_name (output_bfd, ".opd"); + if (s == NULL) +Index: gdb-7.6.1/include/elf/ppc.h +=================================================================== +--- gdb-7.6.1.orig/include/elf/ppc.h ++++ gdb-7.6.1/include/elf/ppc.h +@@ -176,7 +176,8 @@ END_RELOC_NUMBERS (R_PPC_max) + #define DT_PPC_GOT (DT_LOPROC) + + /* Specify that tls descriptors should be optimized. */ +-#define DT_PPC_TLSOPT (DT_LOPROC + 1) ++#define DT_PPC_OPT (DT_LOPROC + 1) ++#define PPC_OPT_TLS 1 + + /* Processor specific flags for the ELF header e_flags field. */ + +Index: gdb-7.6.1/include/elf/ppc64.h +=================================================================== +--- gdb-7.6.1.orig/include/elf/ppc64.h ++++ gdb-7.6.1/include/elf/ppc64.h +@@ -225,7 +225,9 @@ ppc64_encode_local_entry(unsigned int va + #define DT_PPC64_OPD (DT_LOPROC + 1) + #define DT_PPC64_OPDSZ (DT_LOPROC + 2) + +-/* Specify that tls descriptors should be optimized. */ +-#define DT_PPC64_TLSOPT (DT_LOPROC + 3) ++/* Specify whether various optimisations are possible. */ ++#define DT_PPC64_OPT (DT_LOPROC + 3) ++#define PPC64_OPT_TLS 1 ++#define PPC64_OPT_MULTI_TOC 2 + + #endif /* _ELF_PPC64_H */ diff --git a/SOURCES/gdb-rhbz1125820-ppc64le-enablement-13of37.patch b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-13of37.patch new file mode 100644 index 0000000..b69105d --- /dev/null +++ b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-13of37.patch @@ -0,0 +1,496 @@ +commit a345bc8d317a159e3e887632d80c5a8282d34f07 +Author: Alan Modra +Date: Fri Nov 1 19:24:20 2013 +1030 + + PowerPC64 ELFv2 symbols defined in plt + + In a non-pic executable, ELFv2 like other targets, needs to emit a plt + entry even for non-call references to functions defined in shared + libraries, and define the function on the plt code. + + * elf64-ppc.c (ppc64_elf_copy_indirect_symbol): Copy + pointer_equality_needed flag. + (ppc64_elf_check_relocs): For ELFv2 arrange to emit plt + entries for references to functions in shared libraries on + non-call relocs. + (readonly_dynrelocs): Split into function of the same name and.. + (maybe_set_textrel): ..this new function. Update call. + (ppc64_elf_adjust_dynamic_symbol): Don't emit dynrelocs for + ELFv2 in most cases if we have a plt entry. Use new + readonly_relocs. + (allocate_dynrelocs): For ELFv2, don't allocate dynreloc space + for ifunc in static executables. + (size_global_entry_stubs): New function. + (ppc64_elf_size_dynamic_sections): Call size_global_entry_stubs. + Save end of glink branch table. + (ppc64_elf_hash_symbol): New function. + (build_global_entry_stubs): New function. + (ppc64_elf_build_stubs): Call build_global_entry_stubs. Adjust + glink sizing. + (ppc64_elf_relocate_section): Tidy plt16/32/64 reloc code. + (ppc64_elf_finish_dynamic_symbol): For ELFv2, adjust symbols + defined on plt code. + +Index: gdb-7.6.1/bfd/elf64-ppc.c +=================================================================== +--- gdb-7.6.1.orig/bfd/elf64-ppc.c ++++ gdb-7.6.1/bfd/elf64-ppc.c +@@ -109,6 +109,7 @@ static bfd_vma opd_entry_value + #define elf_backend_maybe_function_sym ppc64_elf_maybe_function_sym + #define elf_backend_always_size_sections ppc64_elf_func_desc_adjust + #define elf_backend_size_dynamic_sections ppc64_elf_size_dynamic_sections ++#define elf_backend_hash_symbol ppc64_elf_hash_symbol + #define elf_backend_init_index_section _bfd_elf_init_2_index_sections + #define elf_backend_action_discarded ppc64_elf_action_discarded + #define elf_backend_relocate_section ppc64_elf_relocate_section +@@ -174,6 +175,9 @@ static bfd_vma opd_entry_value + + #define LD_R2_0R1 0xe8410000 /* ld %r2,0(%r1) */ + ++#define ADDIS_R12_R12 0x3d8c0000 /* addis %r12,%r12,xxx@ha */ ++#define LD_R12_0R12 0xe98c0000 /* ld %r12,xxx@l(%r12) */ ++ + /* glink call stub instructions. We enter with the index in R0. */ + #define GLINK_CALL_STUB_SIZE (16*4) + /* 0: */ +@@ -4502,6 +4506,7 @@ ppc64_elf_copy_indirect_symbol (struct b + edir->elf.ref_regular |= eind->elf.ref_regular; + edir->elf.ref_regular_nonweak |= eind->elf.ref_regular_nonweak; + edir->elf.needs_plt |= eind->elf.needs_plt; ++ edir->elf.pointer_equality_needed |= eind->elf.pointer_equality_needed; + + /* Copy over any dynamic relocs we may have on the indirect sym. */ + if (eind->dyn_relocs != NULL) +@@ -5219,6 +5224,14 @@ ppc64_elf_check_relocs (bfd *abfd, struc + if (!update_local_sym_info (abfd, symtab_hdr, r_symndx, + rel->r_addend, tls_type)) + return FALSE; ++ ++ /* We may also need a plt entry if the symbol turns out to be ++ an ifunc. */ ++ if (h != NULL && !info->shared && abiversion (abfd) == 2) ++ { ++ if (!update_plt_info (abfd, &h->plt.plist, rel->r_addend)) ++ return FALSE; ++ } + break; + + case R_PPC64_PLT16_HA: +@@ -5467,12 +5480,6 @@ ppc64_elf_check_relocs (bfd *abfd, struc + } + /* Fall through. */ + +- case R_PPC64_REL30: +- case R_PPC64_REL32: +- case R_PPC64_REL64: +- case R_PPC64_ADDR14: +- case R_PPC64_ADDR14_BRNTAKEN: +- case R_PPC64_ADDR14_BRTAKEN: + case R_PPC64_ADDR16: + case R_PPC64_ADDR16_DS: + case R_PPC64_ADDR16_HA: +@@ -5483,6 +5490,23 @@ ppc64_elf_check_relocs (bfd *abfd, struc + case R_PPC64_ADDR16_HIGHESTA: + case R_PPC64_ADDR16_LO: + case R_PPC64_ADDR16_LO_DS: ++ if (h != NULL && !info->shared && abiversion (abfd) == 2 ++ && rel->r_addend == 0) ++ { ++ /* We may need a .plt entry if this reloc refers to a ++ function in a shared lib. */ ++ if (!update_plt_info (abfd, &h->plt.plist, rel->r_addend)) ++ return FALSE; ++ h->pointer_equality_needed = 1; ++ } ++ /* Fall through. */ ++ ++ case R_PPC64_REL30: ++ case R_PPC64_REL32: ++ case R_PPC64_REL64: ++ case R_PPC64_ADDR14: ++ case R_PPC64_ADDR14_BRNTAKEN: ++ case R_PPC64_ADDR14_BRTAKEN: + case R_PPC64_ADDR24: + case R_PPC64_ADDR32: + case R_PPC64_UADDR16: +@@ -6667,6 +6691,25 @@ ppc64_elf_func_desc_adjust (bfd *obfd AT + return TRUE; + } + ++/* Return true if we have dynamic relocs that apply to read-only sections. */ ++ ++static bfd_boolean ++readonly_dynrelocs (struct elf_link_hash_entry *h) ++{ ++ struct ppc_link_hash_entry *eh; ++ struct elf_dyn_relocs *p; ++ ++ eh = (struct ppc_link_hash_entry *) h; ++ for (p = eh->dyn_relocs; p != NULL; p = p->next) ++ { ++ asection *s = p->sec->output_section; ++ ++ if (s != NULL && (s->flags & SEC_READONLY) != 0) ++ return TRUE; ++ } ++ return FALSE; ++} ++ + /* Adjust a symbol defined by a dynamic object and referenced by a + regular object. The current definition is in some section of the + dynamic object, but we're not including those sections. We have to +@@ -6704,6 +6747,26 @@ ppc64_elf_adjust_dynamic_symbol (struct + h->plt.plist = NULL; + h->needs_plt = 0; + } ++ else if (abiversion (info->output_bfd) == 2) ++ { ++ /* After adjust_dynamic_symbol, non_got_ref set in the ++ non-shared case means that we have allocated space in ++ .dynbss for the symbol and thus dyn_relocs for this ++ symbol should be discarded. ++ If we get here we know we are making a PLT entry for this ++ symbol, and in an executable we'd normally resolve ++ relocations against this symbol to the PLT entry. Allow ++ dynamic relocs if the reference is weak, and the dynamic ++ relocs will not cause text relocation. */ ++ if (!h->ref_regular_nonweak ++ && h->non_got_ref ++ && h->type != STT_GNU_IFUNC ++ && !readonly_dynrelocs (h)) ++ h->non_got_ref = 0; ++ ++ /* If making a plt entry, then we don't need copy relocs. */ ++ return TRUE; ++ } + } + else + h->plt.plist = NULL; +@@ -6738,26 +6801,12 @@ ppc64_elf_adjust_dynamic_symbol (struct + if (!h->def_dynamic || !h->ref_regular || h->def_regular) + return TRUE; + +- if (ELIMINATE_COPY_RELOCS) ++ /* If we didn't find any dynamic relocs in read-only sections, then ++ we'll be keeping the dynamic relocs and avoiding the copy reloc. */ ++ if (ELIMINATE_COPY_RELOCS && !readonly_dynrelocs (h)) + { +- struct ppc_link_hash_entry * eh; +- struct elf_dyn_relocs *p; +- +- eh = (struct ppc_link_hash_entry *) h; +- for (p = eh->dyn_relocs; p != NULL; p = p->next) +- { +- s = p->sec->output_section; +- if (s != NULL && (s->flags & SEC_READONLY) != 0) +- break; +- } +- +- /* If we didn't find any dynamic relocs in read-only sections, then +- we'll be keeping the dynamic relocs and avoiding the copy reloc. */ +- if (p == NULL) +- { +- h->non_got_ref = 0; +- return TRUE; +- } ++ h->non_got_ref = 0; ++ return TRUE; + } + + if (h->plt.plist != NULL) +@@ -9167,7 +9216,8 @@ allocate_dynrelocs (struct elf_link_hash + + if (eh->dyn_relocs == NULL + || (!htab->elf.dynamic_sections_created +- && h->type != STT_GNU_IFUNC)) ++ && (h->type != STT_GNU_IFUNC ++ || !htab->opd_abi))) + return TRUE; + + /* In the shared -Bsymbolic case, discard space allocated for +@@ -9263,28 +9313,59 @@ allocate_dynrelocs (struct elf_link_hash + return TRUE; + } + +-/* Find any dynamic relocs that apply to read-only sections. */ ++/* Called via elf_link_hash_traverse from ppc64_elf_size_dynamic_sections ++ to set up space for global entry stubs. These are put in glink, ++ after the branch table. */ + + static bfd_boolean +-readonly_dynrelocs (struct elf_link_hash_entry *h, void *inf) ++size_global_entry_stubs (struct elf_link_hash_entry *h, void *inf) + { +- struct ppc_link_hash_entry *eh; +- struct elf_dyn_relocs *p; ++ struct bfd_link_info *info; ++ struct ppc_link_hash_table *htab; ++ struct plt_entry *pent; ++ asection *s; + +- eh = (struct ppc_link_hash_entry *) h; +- for (p = eh->dyn_relocs; p != NULL; p = p->next) +- { +- asection *s = p->sec->output_section; ++ if (h->root.type == bfd_link_hash_indirect) ++ return TRUE; + +- if (s != NULL && (s->flags & SEC_READONLY) != 0) +- { +- struct bfd_link_info *info = inf; ++ if (!h->pointer_equality_needed) ++ return TRUE; + +- info->flags |= DF_TEXTREL; ++ if (h->def_regular) ++ return TRUE; + +- /* Not an error, just cut short the traversal. */ +- return FALSE; +- } ++ info = inf; ++ htab = ppc_hash_table (info); ++ if (htab == NULL) ++ return FALSE; ++ ++ s = htab->glink; ++ for (pent = h->plt.plist; pent != NULL; pent = pent->next) ++ if (pent->plt.offset != (bfd_vma) -1 ++ && pent->addend == 0) ++ { ++ s->size = (s->size + 15) & -16; ++ s->size += 16; ++ break; ++ } ++ return TRUE; ++} ++ ++/* Set DF_TEXTREL if we find any dynamic relocs that apply to ++ read-only sections. */ ++ ++static bfd_boolean ++maybe_set_textrel (struct elf_link_hash_entry *h, void *info) ++{ ++ if (h->root.type == bfd_link_hash_indirect) ++ return TRUE; ++ ++ if (readonly_dynrelocs (h)) ++ { ++ ((struct bfd_link_info *) info)->flags |= DF_TEXTREL; ++ ++ /* Not an error, just cut short the traversal. */ ++ return FALSE; + } + return TRUE; + } +@@ -9435,6 +9516,12 @@ ppc64_elf_size_dynamic_sections (bfd *ou + /* Allocate global sym .plt and .got entries, and space for global + sym dynamic relocs. */ + elf_link_hash_traverse (&htab->elf, allocate_dynrelocs, info); ++ /* Stash the end of glink branch table. */ ++ if (htab->glink != NULL) ++ htab->glink->rawsize = htab->glink->size; ++ ++ if (!htab->opd_abi && !info->shared) ++ elf_link_hash_traverse (&htab->elf, size_global_entry_stubs, info); + + first_tlsld = NULL; + for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) +@@ -9632,7 +9719,7 @@ ppc64_elf_size_dynamic_sections (bfd *ou + /* If any dynamic relocs apply to a read-only section, + then we need a DT_TEXTREL entry. */ + if ((info->flags & DF_TEXTREL) == 0) +- elf_link_hash_traverse (&htab->elf, readonly_dynrelocs, info); ++ elf_link_hash_traverse (&htab->elf, maybe_set_textrel, info); + + if ((info->flags & DF_TEXTREL) != 0) + { +@@ -9646,6 +9733,19 @@ ppc64_elf_size_dynamic_sections (bfd *ou + return TRUE; + } + ++/* Return TRUE if symbol should be hashed in the `.gnu.hash' section. */ ++ ++static bfd_boolean ++ppc64_elf_hash_symbol (struct elf_link_hash_entry *h) ++{ ++ if (h->plt.plist != NULL ++ && !h->def_regular ++ && !h->pointer_equality_needed) ++ return FALSE; ++ ++ return _bfd_elf_hash_symbol (h); ++} ++ + /* Determine the type of stub needed, if any, for a call. */ + + static inline enum ppc_stub_type +@@ -12049,6 +12149,79 @@ ppc64_elf_toc (bfd *obfd) + return TOCstart; + } + ++/* Called via elf_link_hash_traverse from ppc64_elf_build_stubs to ++ write out any global entry stubs. */ ++ ++static bfd_boolean ++build_global_entry_stubs (struct elf_link_hash_entry *h, void *inf) ++{ ++ struct bfd_link_info *info; ++ struct ppc_link_hash_table *htab; ++ struct plt_entry *pent; ++ asection *s; ++ ++ if (h->root.type == bfd_link_hash_indirect) ++ return TRUE; ++ ++ if (!h->pointer_equality_needed) ++ return TRUE; ++ ++ if (h->def_regular) ++ return TRUE; ++ ++ info = inf; ++ htab = ppc_hash_table (info); ++ if (htab == NULL) ++ return FALSE; ++ ++ s = htab->glink; ++ for (pent = h->plt.plist; pent != NULL; pent = pent->next) ++ if (pent->plt.offset != (bfd_vma) -1 ++ && pent->addend == 0) ++ { ++ bfd_byte *p; ++ asection *plt; ++ bfd_vma off; ++ ++ /* For ELFv2, if this symbol is not defined in a regular file ++ and we are not generating a shared library or pie, then we ++ need to define the symbol in the executable on a call stub. ++ This is to avoid text relocations. */ ++ h->root.u.def.section = s; ++ h->root.u.def.value = s->size; ++ s->size += 16; ++ p = s->contents + h->root.u.def.value; ++ plt = htab->plt; ++ if (!htab->elf.dynamic_sections_created ++ || h->dynindx == -1) ++ plt = htab->iplt; ++ off = pent->plt.offset + plt->output_offset + plt->output_section->vma; ++ off -= h->root.u.def.value + s->output_offset + s->output_section->vma; ++ ++ if (off + 0x80008000 > 0xffffffff || (off & 3) != 0) ++ { ++ info->callbacks->einfo ++ (_("%P: linkage table error against `%T'\n"), ++ h->root.root.string); ++ bfd_set_error (bfd_error_bad_value); ++ htab->stub_error = TRUE; ++ } ++ ++ if (PPC_HA (off) != 0) ++ { ++ bfd_put_32 (s->owner, ADDIS_R12_R12 | PPC_HA (off), p); ++ p += 4; ++ } ++ bfd_put_32 (s->owner, LD_R12_0R12 | PPC_LO (off), p); ++ p += 4; ++ bfd_put_32 (s->owner, MTCTR_R12, p); ++ p += 4; ++ bfd_put_32 (s->owner, BCTR, p); ++ break; ++ } ++ return TRUE; ++} ++ + /* Build all the stubs associated with the current output file. + The stubs are kept in a hash table attached to the main linker + hash table. This function is called via gldelf64ppc_finish. */ +@@ -12184,7 +12357,7 @@ ppc64_elf_build_stubs (bfd_boolean emit_ + + /* Build the .glink lazy link call stubs. */ + indx = 0; +- while (p < htab->glink->contents + htab->glink->size) ++ while (p < htab->glink->contents + htab->glink->rawsize) + { + if (htab->opd_abi) + { +@@ -12207,7 +12380,13 @@ ppc64_elf_build_stubs (bfd_boolean emit_ + indx++; + p += 4; + } +- htab->glink->rawsize = p - htab->glink->contents; ++ ++ /* Build .glink global entry stubs. */ ++ if (htab->glink->size > htab->glink->rawsize) ++ { ++ htab->glink->size = (htab->glink->rawsize + 15) & -16; ++ elf_link_hash_traverse (&htab->elf, build_global_entry_stubs, info); ++ } + } + + if (htab->brlt->size != 0) +@@ -12311,7 +12490,7 @@ ppc64_elf_build_stubs (bfd_boolean emit_ + bfd_put_32 (htab->elf.dynobj, val, p); + p += 4; + /* .glink size. */ +- bfd_put_32 (htab->elf.dynobj, htab->glink->rawsize - 8, p); ++ bfd_put_32 (htab->elf.dynobj, htab->glink->size - 8, p); + p += 4; + /* Augmentation. */ + p += 1; +@@ -12361,7 +12540,6 @@ ppc64_elf_build_stubs (bfd_boolean emit_ + } + + if (stub_sec != NULL +- || htab->glink->rawsize != htab->glink->size + || (htab->glink_eh_frame != NULL + && htab->glink_eh_frame->rawsize != htab->glink_eh_frame->size)) + { +@@ -13588,13 +13766,14 @@ ppc64_elf_relocate_section (bfd *output_ + { + struct plt_entry *ent; + for (ent = h->elf.plt.plist; ent != NULL; ent = ent->next) +- if (ent->addend == orig_rel.r_addend +- && ent->plt.offset != (bfd_vma) -1) ++ if (ent->plt.offset != (bfd_vma) -1 ++ && ent->addend == orig_rel.r_addend) + { + relocation = (htab->plt->output_section->vma + + htab->plt->output_offset + + ent->plt.offset); + unresolved_reloc = FALSE; ++ break; + } + } + break; +@@ -14297,6 +14476,30 @@ ppc64_elf_finish_dynamic_symbol (bfd *ou + / PLT_ENTRY_SIZE (htab) * sizeof (Elf64_External_Rela))); + } + bfd_elf64_swap_reloca_out (output_bfd, &rela, loc); ++ ++ if (!htab->opd_abi) ++ { ++ if (!h->def_regular) ++ { ++ /* Mark the symbol as undefined, rather than as ++ defined in glink. Leave the value if there were ++ any relocations where pointer equality matters ++ (this is a clue for the dynamic linker, to make ++ function pointer comparisons work between an ++ application and shared library), otherwise set it ++ to zero. */ ++ sym->st_shndx = SHN_UNDEF; ++ if (!h->pointer_equality_needed) ++ sym->st_value = 0; ++ else if (!h->ref_regular_nonweak) ++ { ++ /* This breaks function pointer comparisons, but ++ that is better than breaking tests for a NULL ++ function pointer. */ ++ sym->st_value = 0; ++ } ++ } ++ } + } + + if (h->needs_copy) diff --git a/SOURCES/gdb-rhbz1125820-ppc64le-enablement-14of37.patch b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-14of37.patch new file mode 100644 index 0000000..f69828b --- /dev/null +++ b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-14of37.patch @@ -0,0 +1,59 @@ +commit 52a82034ac9a288d2d8e60efa880623288b5d228 +Author: Alan Modra +Date: Fri Nov 1 19:25:56 2013 +1030 + + Edit ELFv2 global entry prologue to non-PIC + + Changing addis r2,r12,..; addi r2,r2,.. to lis r2,..; addi r2,r2.. + in non-PIC executables has the benefit of removing a dependency on r12. + + bfd/ + * elf64-ppc.c (ppc64_elf_relocate_section): Edit global entry + prologue to non-PIC in non-PIC executables. + ld/testsuite/ + * ld-powerpc/elfv2exe.d: Adjust for non-PIC global entry. + +Index: gdb-7.6.1/bfd/elf64-ppc.c +=================================================================== +--- gdb-7.6.1.orig/bfd/elf64-ppc.c ++++ gdb-7.6.1/bfd/elf64-ppc.c +@@ -13280,6 +13280,39 @@ ppc64_elf_relocate_section (bfd *output_ + rel->r_info = ELF64_R_INFO (r_symndx, r_type); + } + break; ++ ++ case R_PPC64_REL16_HA: ++ /* If we are generating a non-PIC executable, edit ++ . 0: addis 2,12,.TOC.-0b@ha ++ . addi 2,2,.TOC.-0b@l ++ used by ELFv2 global entry points to set up r2, to ++ . lis 2,.TOC.@ha ++ . addi 2,2,.TOC.@l ++ if .TOC. is in range. */ ++ if (!info->shared ++ && h != NULL && &h->elf == htab->elf.hgot ++ && rel + 1 < relend ++ && rel[1].r_info == ELF64_R_INFO (r_symndx, R_PPC64_REL16_LO) ++ && rel[1].r_offset == rel->r_offset + 4 ++ && rel[1].r_addend == rel->r_addend + 4 ++ && relocation + 0x80008000 <= 0xffffffff) ++ { ++ unsigned int insn1, insn2; ++ bfd_vma offset = rel->r_offset - d_offset; ++ insn1 = bfd_get_32 (output_bfd, contents + offset); ++ insn2 = bfd_get_32 (output_bfd, contents + offset + 4); ++ if ((insn1 & 0xffff0000) == 0x3c4c0000 /* addis 2,12 */ ++ && (insn2 & 0xffff0000) == 0x38420000 /* addi 2,2 */) ++ { ++ r_type = R_PPC64_ADDR16_HA; ++ rel->r_info = ELF64_R_INFO (r_symndx, r_type); ++ rel->r_addend -= d_offset; ++ rel[1].r_info = ELF64_R_INFO (r_symndx, R_PPC64_ADDR16_LO); ++ rel[1].r_addend -= d_offset + 4; ++ bfd_put_32 (output_bfd, 0x3c400000, contents + offset); ++ } ++ } ++ break; + } + + /* Handle other relocations that tweak non-addend part of insn. */ diff --git a/SOURCES/gdb-rhbz1125820-ppc64le-enablement-15of37.patch b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-15of37.patch new file mode 100644 index 0000000..08cdc92 --- /dev/null +++ b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-15of37.patch @@ -0,0 +1,93 @@ +commit afe397ea85a3d09d936c93328a1f6bf640577cf3 +Author: Alan Modra +Date: Wed Nov 6 10:20:52 2013 +1030 + + Correct elf64-ppc.c handling of protected symbols + + Some places in elf64-ppc.c carelessly used SYMBOL_CALLS_LOCAL when + the proper test is SYMBOL_REFERENCES_LOCAL for cases where we take the + address of a protected symbol. This works OK for function descriptors + but not for ELFv2. Setting symbols to their global entry stub a + little earlier is to ensure _bfd_elf_hash_symbol allows such symbols + in .gnu.hash. + + * elf64-ppc.c (ppc64_elf_edit_toc): Use SYMBOL_REFERENCES_LOCAL + here, not SYMBOL_CALLS_LOCAL. + (ppc64_elf_relocate_section): Likewise. + (size_global_entry_stubs): Set undefined symbols on their global + entry stubs here.. + (build_global_entry_stubs): ..rather than here. + (ppc64_elf_build_stubs): Don't reset glink->size before calling + build_global_entry_stubs. + +Index: gdb-7.6.1/bfd/elf64-ppc.c +=================================================================== +--- gdb-7.6.1.orig/bfd/elf64-ppc.c ++++ gdb-7.6.1/bfd/elf64-ppc.c +@@ -8496,7 +8496,7 @@ ppc64_elf_edit_toc (struct bfd_link_info + || discarded_section (sym_sec)) + continue; + +- if (!SYMBOL_CALLS_LOCAL (info, h)) ++ if (!SYMBOL_REFERENCES_LOCAL (info, h)) + continue; + + if (h != NULL) +@@ -9344,7 +9344,13 @@ size_global_entry_stubs (struct elf_link + if (pent->plt.offset != (bfd_vma) -1 + && pent->addend == 0) + { ++ /* For ELFv2, if this symbol is not defined in a regular file ++ and we are not generating a shared library or pie, then we ++ need to define the symbol in the executable on a call stub. ++ This is to avoid text relocations. */ + s->size = (s->size + 15) & -16; ++ h->root.u.def.section = s; ++ h->root.u.def.value = s->size; + s->size += 16; + break; + } +@@ -12183,13 +12189,6 @@ build_global_entry_stubs (struct elf_lin + asection *plt; + bfd_vma off; + +- /* For ELFv2, if this symbol is not defined in a regular file +- and we are not generating a shared library or pie, then we +- need to define the symbol in the executable on a call stub. +- This is to avoid text relocations. */ +- h->root.u.def.section = s; +- h->root.u.def.value = s->size; +- s->size += 16; + p = s->contents + h->root.u.def.value; + plt = htab->plt; + if (!htab->elf.dynamic_sections_created +@@ -12383,10 +12382,7 @@ ppc64_elf_build_stubs (bfd_boolean emit_ + + /* Build .glink global entry stubs. */ + if (htab->glink->size > htab->glink->rawsize) +- { +- htab->glink->size = (htab->glink->rawsize + 15) & -16; +- elf_link_hash_traverse (&htab->elf, build_global_entry_stubs, info); +- } ++ elf_link_hash_traverse (&htab->elf, build_global_entry_stubs, info); + } + + if (htab->brlt->size != 0) +@@ -13624,7 +13620,7 @@ ppc64_elf_relocate_section (bfd *output_ + if (!WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, + &h->elf) + || (info->shared +- && SYMBOL_CALLS_LOCAL (info, &h->elf))) ++ && SYMBOL_REFERENCES_LOCAL (info, &h->elf))) + /* This is actually a static link, or it is a + -Bsymbolic link and the symbol is defined + locally, or the symbol was forced to be local +@@ -14003,7 +13999,7 @@ ppc64_elf_relocate_section (bfd *output_ + + if (skip) + memset (&outrel, 0, sizeof outrel); +- else if (!SYMBOL_CALLS_LOCAL (info, &h->elf) ++ else if (!SYMBOL_REFERENCES_LOCAL (info, &h->elf) + && !is_opd + && r_type != R_PPC64_TOC) + { diff --git a/SOURCES/gdb-rhbz1125820-ppc64le-enablement-16of37.patch b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-16of37.patch new file mode 100644 index 0000000..231cfb6 --- /dev/null +++ b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-16of37.patch @@ -0,0 +1,22 @@ +commit 14b5f73fac0e34c2fca81aa0dfbc9c7eebc922f2 +Author: Alan Modra +Date: Mon Nov 11 13:46:26 2013 +1030 + + PowerPC64 ELFv2, allocate dynreloc space for ifunc + + * elf64-ppc.c (allocate_dynrelocs): Revert 2013-11-04 change. + +Index: gdb-7.6.1/bfd/elf64-ppc.c +=================================================================== +--- gdb-7.6.1.orig/bfd/elf64-ppc.c ++++ gdb-7.6.1/bfd/elf64-ppc.c +@@ -9216,8 +9216,7 @@ allocate_dynrelocs (struct elf_link_hash + + if (eh->dyn_relocs == NULL + || (!htab->elf.dynamic_sections_created +- && (h->type != STT_GNU_IFUNC +- || !htab->opd_abi))) ++ && h->type != STT_GNU_IFUNC)) + return TRUE; + + /* In the shared -Bsymbolic case, discard space allocated for diff --git a/SOURCES/gdb-rhbz1125820-ppc64le-enablement-17of37.patch b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-17of37.patch new file mode 100644 index 0000000..71e32df --- /dev/null +++ b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-17of37.patch @@ -0,0 +1,358 @@ +commit ef1bc9e72fd2f0310ac3113acc41e1c115e3ac79 +Author: Alan Modra +Date: Mon Nov 11 14:14:40 2013 +1030 + + PowerPC64 ELFv2 trampoline match + + ELFv2 needs different plt call stubs to ELFv1, register usage differs + too. When I added these to ld I changed register usage in the ELFv1 + stubs as well, simplifying the linker code and (perhaps) future + maintenance. All well and good, but this means gdb needs to cope with + more stub variants. This patch also handles skipping over addis/addi + setting up r2 in ELFv2 global entry code. We want breakpoints to be + set past this point to catch calls via the local entry point. + + * ppc64-tdep.c (ppc64_plt_entry_point): Renamed from.. + (ppc64_desc_entry_point): ..this. Update comments here and at + call points. + (ppc64_standard_linkage1, ppc64_standard_linkage2, + ppc64_standard_linkage3): Update comments. + (ppc64_standard_linkage4, ppc64_standard_linkage5, + (ppc64_standard_linkage6, ppc64_standard_linkage7): New insn + patterns. + (ppc64_standard_linkage4_target): New function. + (ppc64_skip_trampoline_code): Skip ELFv2 patterns too. + * rs6000-tdep.c (skip_prologue): Skip ELFv2 r2 setup. Correct + nop match. Fix comment wrap. + +Index: gdb-7.6.1/gdb/ppc64-tdep.c +=================================================================== +--- gdb-7.6.1.orig/gdb/ppc64-tdep.c ++++ gdb-7.6.1/gdb/ppc64-tdep.c +@@ -48,21 +48,21 @@ + | (((spr) & 0x3e0) << 6) \ + | (((xo) & 0x3ff) << 1)) + +-/* If DESC is the address of a 64-bit PowerPC FreeBSD function +- descriptor, return the descriptor's entry point. */ ++/* If PLT is the address of a 64-bit PowerPC PLT entry, ++ return the function's entry point. */ + + static CORE_ADDR +-ppc64_desc_entry_point (struct gdbarch *gdbarch, CORE_ADDR desc) ++ppc64_plt_entry_point (struct gdbarch *gdbarch, CORE_ADDR plt) + { + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); +- /* The first word of the descriptor is the entry point. */ +- return (CORE_ADDR) read_memory_unsigned_integer (desc, 8, byte_order); ++ /* The first word of the PLT entry is the function entry point. */ ++ return (CORE_ADDR) read_memory_unsigned_integer (plt, 8, byte_order); + } + + /* Patterns for the standard linkage functions. These are built by + build_plt_stub in bfd/elf64-ppc.c. */ + +-/* Old PLT call stub. */ ++/* Old ELFv1 PLT call stub. */ + + static struct ppc_insn_pattern ppc64_standard_linkage1[] = + { +@@ -96,7 +96,7 @@ static struct ppc_insn_pattern ppc64_sta + { 0, 0, 0 } + }; + +-/* Current PLT call stub to access PLT entries more than +/- 32k from r2. ++/* ELFv1 PLT call stub to access PLT entries more than +/- 32k from r2. + Also supports older stub with different placement of std 2,40(1), + a stub that omits the std 2,40(1), and both versions of power7 + thread safety read barriers. Note that there are actually two more +@@ -144,7 +144,7 @@ static struct ppc_insn_pattern ppc64_sta + { 0, 0, 0 } + }; + +-/* Current PLT call stub to access PLT entries within +/- 32k of r2. */ ++/* ELFv1 PLT call stub to access PLT entries within +/- 32k of r2. */ + + static struct ppc_insn_pattern ppc64_standard_linkage3[] = + { +@@ -181,6 +181,128 @@ static struct ppc_insn_pattern ppc64_sta + { 0, 0, 0 } + }; + ++/* ELFv1 PLT call stub to access PLT entries more than +/- 32k from r2. ++ A more modern variant of ppc64_standard_linkage2 differing in ++ register usage. */ ++ ++static struct ppc_insn_pattern ppc64_standard_linkage4[] = ++ { ++ /* std r2, 40(r1) */ ++ { -1, insn_ds (62, 2, 1, 40, 0), 1 }, ++ ++ /* addis r11, r2, */ ++ { insn_d (-1, -1, -1, 0), insn_d (15, 11, 2, 0), 0 }, ++ ++ /* ld r12, (r11) */ ++ { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 12, 11, 0, 0), 0 }, ++ ++ /* addi r11, r11, */ ++ { insn_d (-1, -1, -1, 0), insn_d (14, 11, 11, 0), 1 }, ++ ++ /* mtctr r12 */ ++ { insn_xfx (-1, -1, -1, -1), insn_xfx (31, 12, 9, 467), 0 }, ++ ++ /* xor r2, r12, r12 */ ++ { -1, 0x7d826278, 1 }, ++ ++ /* add r11, r11, r2 */ ++ { -1, 0x7d6b1214, 1 }, ++ ++ /* ld r2, (r11) */ ++ { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 2, 11, 0, 0), 0 }, ++ ++ /* ld r11, (r11) */ ++ { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 11, 0, 0), 1 }, ++ ++ /* bctr */ ++ { -1, 0x4e800420, 1 }, ++ ++ /* cmpldi r2, 0 */ ++ { -1, 0x28220000, 1 }, ++ ++ { 0, 0, 0 } ++ }; ++ ++/* ELFv1 PLT call stub to access PLT entries within +/- 32k of r2. ++ A more modern variant of ppc64_standard_linkage3 differing in ++ register usage. */ ++ ++static struct ppc_insn_pattern ppc64_standard_linkage5[] = ++ { ++ /* std r2, 40(r1) */ ++ { -1, insn_ds (62, 2, 1, 40, 0), 1 }, ++ ++ /* ld r12, (r2) */ ++ { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 12, 2, 0, 0), 0 }, ++ ++ /* addi r2, r2, */ ++ { insn_d (-1, -1, -1, 0), insn_d (14, 2, 2, 0), 1 }, ++ ++ /* mtctr r12 */ ++ { insn_xfx (-1, -1, -1, -1), insn_xfx (31, 12, 9, 467), 0 }, ++ ++ /* xor r11, r12, r12 */ ++ { -1, 0x7d8b6278, 1 }, ++ ++ /* add r2, r2, r11 */ ++ { -1, 0x7c425a14, 1 }, ++ ++ /* ld r11, (r2) */ ++ { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 2, 0, 0), 1 }, ++ ++ /* ld r2, (r2) */ ++ { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 2, 2, 0, 0), 0 }, ++ ++ /* bctr */ ++ { -1, 0x4e800420, 1 }, ++ ++ /* cmpldi r2, 0 */ ++ { -1, 0x28220000, 1 }, ++ ++ { 0, 0, 0 } ++ }; ++ ++/* ELFv2 PLT call stub to access PLT entries more than +/- 32k from r2. */ ++ ++static struct ppc_insn_pattern ppc64_standard_linkage6[] = ++ { ++ /* std r2, 24(r1) */ ++ { -1, insn_ds (62, 2, 1, 24, 0), 1 }, ++ ++ /* addis r11, r2, */ ++ { insn_d (-1, -1, -1, 0), insn_d (15, 11, 2, 0), 0 }, ++ ++ /* ld r12, (r11) */ ++ { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 12, 11, 0, 0), 0 }, ++ ++ /* mtctr r12 */ ++ { insn_xfx (-1, -1, -1, -1), insn_xfx (31, 12, 9, 467), 0 }, ++ ++ /* bctr */ ++ { -1, 0x4e800420, 0 }, ++ ++ { 0, 0, 0 } ++ }; ++ ++/* ELFv2 PLT call stub to access PLT entries within +/- 32k of r2. */ ++ ++static struct ppc_insn_pattern ppc64_standard_linkage7[] = ++ { ++ /* std r2, 24(r1) */ ++ { -1, insn_ds (62, 2, 1, 40, 0), 1 }, ++ ++ /* ld r12, (r2) */ ++ { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 12, 2, 0, 0), 0 }, ++ ++ /* mtctr r12 */ ++ { insn_xfx (-1, -1, -1, -1), insn_xfx (31, 12, 9, 467), 0 }, ++ ++ /* bctr */ ++ { -1, 0x4e800420, 0 }, ++ ++ { 0, 0, 0 } ++ }; ++ + /* When the dynamic linker is doing lazy symbol resolution, the first + call to a function in another object will go like this: + +@@ -243,16 +365,14 @@ ppc64_standard_linkage1_target (struct f + struct gdbarch *gdbarch = get_frame_arch (frame); + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + +- /* The address of the function descriptor this linkage function +- references. */ +- CORE_ADDR desc ++ /* The address of the PLT entry this linkage function references. */ ++ CORE_ADDR plt + = ((CORE_ADDR) get_frame_register_unsigned (frame, + tdep->ppc_gp0_regnum + 2) + + (ppc_insn_d_field (insn[0]) << 16) + + ppc_insn_ds_field (insn[2])); + +- /* The first word of the descriptor is the entry point. Return that. */ +- return ppc64_desc_entry_point (gdbarch, desc); ++ return ppc64_plt_entry_point (gdbarch, plt); + } + + static CORE_ADDR +@@ -262,16 +382,14 @@ ppc64_standard_linkage2_target (struct f + struct gdbarch *gdbarch = get_frame_arch (frame); + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + +- /* The address of the function descriptor this linkage function +- references. */ +- CORE_ADDR desc ++ /* The address of the PLT entry this linkage function references. */ ++ CORE_ADDR plt + = ((CORE_ADDR) get_frame_register_unsigned (frame, + tdep->ppc_gp0_regnum + 2) + + (ppc_insn_d_field (insn[1]) << 16) + + ppc_insn_ds_field (insn[3])); + +- /* The first word of the descriptor is the entry point. Return that. */ +- return ppc64_desc_entry_point (gdbarch, desc); ++ return ppc64_plt_entry_point (gdbarch, plt); + } + + static CORE_ADDR +@@ -281,15 +399,28 @@ ppc64_standard_linkage3_target (struct f + struct gdbarch *gdbarch = get_frame_arch (frame); + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + +- /* The address of the function descriptor this linkage function +- references. */ +- CORE_ADDR desc ++ /* The address of the PLT entry this linkage function references. */ ++ CORE_ADDR plt + = ((CORE_ADDR) get_frame_register_unsigned (frame, + tdep->ppc_gp0_regnum + 2) + + ppc_insn_ds_field (insn[1])); + +- /* The first word of the descriptor is the entry point. Return that. */ +- return ppc64_desc_entry_point (gdbarch, desc); ++ return ppc64_plt_entry_point (gdbarch, plt); ++} ++ ++static CORE_ADDR ++ppc64_standard_linkage4_target (struct frame_info *frame, ++ CORE_ADDR pc, unsigned int *insn) ++{ ++ struct gdbarch *gdbarch = get_frame_arch (frame); ++ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); ++ ++ CORE_ADDR plt ++ = ((CORE_ADDR) get_frame_register_unsigned (frame, tdep->ppc_gp0_regnum + 2) ++ + (ppc_insn_d_field (insn[1]) << 16) ++ + ppc_insn_ds_field (insn[2])); ++ ++ return ppc64_plt_entry_point (gdbarch, plt); + } + + +@@ -300,13 +431,27 @@ CORE_ADDR + ppc64_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc) + { + #define MAX(a,b) ((a) > (b) ? (a) : (b)) +- unsigned int insns[MAX (MAX (ARRAY_SIZE (ppc64_standard_linkage1), +- ARRAY_SIZE (ppc64_standard_linkage2)), +- ARRAY_SIZE (ppc64_standard_linkage3)) - 1]; ++ unsigned int insns[MAX (MAX (MAX (ARRAY_SIZE (ppc64_standard_linkage1), ++ ARRAY_SIZE (ppc64_standard_linkage2)), ++ MAX (ARRAY_SIZE (ppc64_standard_linkage3), ++ ARRAY_SIZE (ppc64_standard_linkage4))), ++ MAX (MAX (ARRAY_SIZE (ppc64_standard_linkage5), ++ ARRAY_SIZE (ppc64_standard_linkage6)), ++ ARRAY_SIZE (ppc64_standard_linkage7))) - 1]; + CORE_ADDR target; + +- if (ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage3, insns) +- && (insns[8] != 0 || insns[9] != 0)) ++ if (ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage7, insns)) ++ pc = ppc64_standard_linkage3_target (frame, pc, insns); ++ else if (ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage6, insns)) ++ pc = ppc64_standard_linkage4_target (frame, pc, insns); ++ else if (ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage5, insns) ++ && (insns[8] != 0 || insns[9] != 0)) ++ pc = ppc64_standard_linkage3_target (frame, pc, insns); ++ else if (ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage4, insns) ++ && (insns[9] != 0 || insns[10] != 0)) ++ pc = ppc64_standard_linkage4_target (frame, pc, insns); ++ else if (ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage3, insns) ++ && (insns[8] != 0 || insns[9] != 0)) + pc = ppc64_standard_linkage3_target (frame, pc, insns); + else if (ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage2, insns) + && (insns[10] != 0 || insns[11] != 0)) +Index: gdb-7.6.1/gdb/rs6000-tdep.c +=================================================================== +--- gdb-7.6.1.orig/gdb/rs6000-tdep.c ++++ gdb-7.6.1/gdb/rs6000-tdep.c +@@ -1667,7 +1667,19 @@ skip_prologue (struct gdbarch *gdbarch, + continue; + + } +- else if ((op & 0xffff0000) == 0x60000000) ++ else if ((op & 0xffff0000) == 0x3c4c0000 ++ || (op & 0xffff0000) == 0x3c400000 ++ || (op & 0xffff0000) == 0x38420000) ++ { ++ /* . 0: addis 2,12,.TOC.-0b@ha ++ . addi 2,2,.TOC.-0b@l ++ or ++ . lis 2,.TOC.@ha ++ . addi 2,2,.TOC.@l ++ used by ELFv2 global entry points to set up r2. */ ++ continue; ++ } ++ else if (op == 0x60000000) + { + /* nop */ + /* Allow nops in the prologue, but do not consider them to +@@ -1678,8 +1690,7 @@ skip_prologue (struct gdbarch *gdbarch, + + } + else if ((op & 0xffff0000) == 0x3c000000) +- { /* addis 0,0,NUM, used +- for >= 32k frames */ ++ { /* addis 0,0,NUM, used for >= 32k frames */ + fdata->offset = (op & 0x0000ffff) << 16; + fdata->frameless = 0; + r0_contains_arg = 0; +@@ -1687,8 +1698,7 @@ skip_prologue (struct gdbarch *gdbarch, + + } + else if ((op & 0xffff0000) == 0x60000000) +- { /* ori 0,0,NUM, 2nd ha +- lf of >= 32k frames */ ++ { /* ori 0,0,NUM, 2nd half of >= 32k frames */ + fdata->offset |= (op & 0x0000ffff); + fdata->frameless = 0; + r0_contains_arg = 0; diff --git a/SOURCES/gdb-rhbz1125820-ppc64le-enablement-18of37.patch b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-18of37.patch new file mode 100644 index 0000000..99f7a81 --- /dev/null +++ b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-18of37.patch @@ -0,0 +1,31 @@ +commit 2c3f079f58204594bc271b919a643e9f2813aa12 +Author: Alan Modra +Date: Tue Dec 3 15:01:20 2013 +1030 + + PowerPC64 linking of --just-symbols objects (klibc) + + With -mcmodel=medium we can't assume that a -R object doesn't use + toc-relative addressing if there's no toc. Lots of things are + accessed via r2, not just the toc/got section. Also, testing for + .opd is plain wrong for ELFv2. + + * elf64-ppc.c (ppc64_elf_link_just_syms): Remove .got check. + Handle ELFv2. + +Index: gdb-7.6.1/bfd/elf64-ppc.c +=================================================================== +--- gdb-7.6.1.orig/bfd/elf64-ppc.c ++++ gdb-7.6.1/bfd/elf64-ppc.c +@@ -4887,10 +4887,8 @@ ppc64_elf_link_just_syms (asection *sec, + && (sec->owner->flags & (EXEC_P | DYNAMIC)) != 0 + && is_ppc64_elf (sec->owner)) + { +- asection *got = bfd_get_section_by_name (sec->owner, ".got"); +- if (got != NULL +- && got->size >= elf_backend_got_header_size +- && bfd_get_section_by_name (sec->owner, ".opd") != NULL) ++ if (abiversion (sec->owner) >= 2 ++ || bfd_get_section_by_name (sec->owner, ".opd") != NULL) + sec->has_toc_reloc = 1; + } + _bfd_elf_link_just_syms (sec, info); diff --git a/SOURCES/gdb-rhbz1125820-ppc64le-enablement-19of37.patch b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-19of37.patch new file mode 100644 index 0000000..980ffb3 --- /dev/null +++ b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-19of37.patch @@ -0,0 +1,110 @@ +commit 00f412ee52ff042dd349118443ef289175669b7d +Author: Alan Modra +Date: Tue Dec 3 17:48:31 2013 +1030 + + More PowerPC64 ELFv2 --just-symbols fixes + + I don't know what I was thinking here to omit the save of r2. + Possibly I was looking at -msave-toc-indirect code at the time, where + r2 is saved in the function prologue. + + * elf64-ppc.c (ppc_build_one_stub ): + Don't omit saving of r2 for ELFv2. Don't addi 2,2,0. + (ppc_size_one_stub ): Adjust to suit. + +Index: gdb-7.6.1/bfd/elf64-ppc.c +=================================================================== +--- gdb-7.6.1.orig/bfd/elf64-ppc.c ++++ gdb-7.6.1/bfd/elf64-ppc.c +@@ -10392,8 +10392,7 @@ ppc_build_one_stub (struct bfd_hash_entr + r[0].r_offset = loc - stub_entry->stub_sec->contents; + if (bfd_big_endian (info->output_bfd)) + r[0].r_offset += 2; +- if (stub_entry->stub_type == ppc_stub_plt_branch_r2off +- && htab->opd_abi) ++ if (stub_entry->stub_type == ppc_stub_plt_branch_r2off) + r[0].r_offset += 4; + r[0].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS); + r[0].r_addend = dest; +@@ -10406,8 +10405,7 @@ ppc_build_one_stub (struct bfd_hash_entr + } + } + +- if (stub_entry->stub_type != ppc_stub_plt_branch_r2off +- || !htab->opd_abi) ++ if (stub_entry->stub_type != ppc_stub_plt_branch_r2off) + { + if (PPC_HA (off) != 0) + { +@@ -10426,7 +10424,7 @@ ppc_build_one_stub (struct bfd_hash_entr + { + bfd_vma r2off = get_r2off (info, stub_entry); + +- if (r2off == 0) ++ if (r2off == 0 && htab->opd_abi) + { + htab->stub_error = TRUE; + return FALSE; +@@ -10434,28 +10432,29 @@ ppc_build_one_stub (struct bfd_hash_entr + + bfd_put_32 (htab->stub_bfd, STD_R2_0R1 + STK_TOC (htab), loc); + loc += 4; +- size = 20; ++ size = 16; + if (PPC_HA (off) != 0) + { + size += 4; + bfd_put_32 (htab->stub_bfd, ADDIS_R11_R2 | PPC_HA (off), loc); + loc += 4; + bfd_put_32 (htab->stub_bfd, LD_R12_0R11 | PPC_LO (off), loc); +- loc += 4; + } + else +- { +- bfd_put_32 (htab->stub_bfd, LD_R12_0R2 | PPC_LO (off), loc); +- loc += 4; +- } ++ bfd_put_32 (htab->stub_bfd, LD_R12_0R2 | PPC_LO (off), loc); + + if (PPC_HA (r2off) != 0) + { + size += 4; ++ loc += 4; + bfd_put_32 (htab->stub_bfd, ADDIS_R2_R2 | PPC_HA (r2off), loc); ++ } ++ if (PPC_LO (r2off) != 0) ++ { ++ size += 4; + loc += 4; ++ bfd_put_32 (htab->stub_bfd, ADDI_R2_R2 | PPC_LO (r2off), loc); + } +- bfd_put_32 (htab->stub_bfd, ADDI_R2_R2 | PPC_LO (r2off), loc); + } + loc += 4; + bfd_put_32 (htab->stub_bfd, MTCTR_R12, loc); +@@ -10749,8 +10748,7 @@ ppc_size_one_stub (struct bfd_hash_entry + stub_entry->stub_sec->flags |= SEC_RELOC; + } + +- if (stub_entry->stub_type != ppc_stub_plt_branch_r2off +- || !htab->opd_abi) ++ if (stub_entry->stub_type != ppc_stub_plt_branch_r2off) + { + size = 12; + if (PPC_HA (off) != 0) +@@ -10758,12 +10756,14 @@ ppc_size_one_stub (struct bfd_hash_entry + } + else + { +- size = 20; ++ size = 16; + if (PPC_HA (off) != 0) + size += 4; + + if (PPC_HA (r2off) != 0) + size += 4; ++ if (PPC_LO (r2off) != 0) ++ size += 4; + } + } + else if (info->emitrelocations) diff --git a/SOURCES/gdb-rhbz1125820-ppc64le-enablement-20of37.patch b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-20of37.patch new file mode 100644 index 0000000..cdf10de --- /dev/null +++ b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-20of37.patch @@ -0,0 +1,33 @@ +commit 3ba720c788c2845c93a6dfe592f36163cbfa63fd +Author: Alan Modra +Date: Fri Jan 24 14:22:10 2014 +1030 + + Fixes powerpc64le ld segfaults when --emit-relocs is used. + + ELFv2 needs fewer relocs to annotate plt call stubs. I correctly + allocated a smaller buffer and wrote the proper relocs, but stupidly + bumped the reloc count as for ELFv1. + + * elf64-ppc.c (ppc_build_one_stub): Correct reloc count passed + to get_relocs for ELFv2. + +Index: gdb-7.6.1/bfd/elf64-ppc.c +=================================================================== +--- gdb-7.6.1.orig/bfd/elf64-ppc.c ++++ gdb-7.6.1/bfd/elf64-ppc.c +@@ -10546,10 +10546,11 @@ ppc_build_one_stub (struct bfd_hash_entr + if (info->emitrelocations) + { + r = get_relocs (stub_entry->stub_sec, +- (2 +- + (PPC_HA (off) != 0) +- + (htab->plt_static_chain +- && PPC_HA (off + 16) == PPC_HA (off)))); ++ ((PPC_HA (off) != 0) ++ + (htab->opd_abi ++ ? 2 + (htab->plt_static_chain ++ && PPC_HA (off + 16) == PPC_HA (off)) ++ : 1))); + if (r == NULL) + return FALSE; + r[0].r_offset = loc - stub_entry->stub_sec->contents; diff --git a/SOURCES/gdb-rhbz1125820-ppc64le-enablement-21of37.patch b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-21of37.patch new file mode 100644 index 0000000..5e91429 --- /dev/null +++ b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-21of37.patch @@ -0,0 +1,28 @@ +commit fa0079ea727e512d592fff1241a82a0a2f628903 +Author: Ulrich Weigand +Date: Tue Jan 28 17:49:13 2014 +0100 + + Fix typo in ppc64_standard_linkage7 + + The ppc64_standard_linkage7 pattern added by Alan's recent patch: + https://sourceware.org/ml/gdb-patches/2013-11/msg00274.html + contains a typo: the ELFv2 TOC slot offset is 24, not 40. + This was correct in the comment, but not the actual code. + + ChangeLog: + + * ppc64-tdep.c (ppc64_standard_linkage7): Fix typo. + +Index: gdb-7.6.1/gdb/ppc64-tdep.c +=================================================================== +--- gdb-7.6.1.orig/gdb/ppc64-tdep.c ++++ gdb-7.6.1/gdb/ppc64-tdep.c +@@ -289,7 +289,7 @@ static struct ppc_insn_pattern ppc64_sta + static struct ppc_insn_pattern ppc64_standard_linkage7[] = + { + /* std r2, 24(r1) */ +- { -1, insn_ds (62, 2, 1, 40, 0), 1 }, ++ { -1, insn_ds (62, 2, 1, 24, 0), 1 }, + + /* ld r12, (r2) */ + { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 12, 2, 0, 0), 0 }, diff --git a/SOURCES/gdb-rhbz1125820-ppc64le-enablement-22of37.patch b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-22of37.patch new file mode 100644 index 0000000..4afaaa6 --- /dev/null +++ b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-22of37.patch @@ -0,0 +1,45 @@ +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. + +Index: gdb-7.6.1/gdb/auxv.c +=================================================================== +--- gdb-7.6.1.orig/gdb/auxv.c ++++ gdb-7.6.1/gdb/auxv.c +@@ -441,6 +441,7 @@ fprint_target_auxv (struct ui_file *file + TAG (AT_IGNOREPPC, _("Entry should be ignored"), dec); + TAG (AT_BASE_PLATFORM, _("String identifying base platform"), str); + TAG (AT_RANDOM, _("Address of 16 random bytes"), hex); ++ TAG (AT_HWCAP2, _("Extension of AT_HWCAP"), hex); + TAG (AT_EXECFN, _("File name of executable"), str); + TAG (AT_SECURE, _("Boolean, was exec setuid-like?"), dec); + TAG (AT_SYSINFO, _("Special system info/entry points"), hex); +Index: gdb-7.6.1/include/elf/common.h +=================================================================== +--- gdb-7.6.1.orig/include/elf/common.h ++++ gdb-7.6.1/include/elf/common.h +@@ -954,6 +954,7 @@ + #define AT_BASE_PLATFORM 24 /* String identifying real platform, + may differ from AT_PLATFORM. */ + #define AT_RANDOM 25 /* Address of 16 random bytes. */ ++#define AT_HWCAP2 26 /* Extension of AT_HWCAP. */ + #define AT_EXECFN 31 /* Filename of executable. */ + /* Pointer to the global system page used for system calls and other + nice things. */ diff --git a/SOURCES/gdb-rhbz1125820-ppc64le-enablement-23of37.patch b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-23of37.patch new file mode 100644 index 0000000..244a79a --- /dev/null +++ b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-23of37.patch @@ -0,0 +1,1394 @@ +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. + +Index: gdb-7.6.1/gdb/ppc-sysv-tdep.c +=================================================================== +--- gdb-7.6.1.orig/gdb/ppc-sysv-tdep.c ++++ gdb-7.6.1/gdb/ppc-sysv-tdep.c +@@ -609,8 +609,7 @@ ppc_sysv_abi_push_dummy_call (struct gdb + 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, +@@ -1101,80 +1100,287 @@ convert_code_addr_to_desc_addr (CORE_ADD + 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. + +- 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. */ ++ If ALIGN is nonzero, it specifies the minimum alignment required ++ for the on-stack copy of the argument. */ + + static void +-ppc64_sysv_abi_push_float (struct gdbarch *gdbarch, struct regcache *regcache, +- struct gdbarch_tdep *tdep, struct type *type, +- const bfd_byte *val, int freg, int greg, +- CORE_ADDR gparam) ++ppc64_sysv_abi_push_val (struct gdbarch *gdbarch, ++ const bfd_byte *val, int len, int align, ++ struct ppc64_sysv_argpos *argpos) + { +- gdb_byte regval[MAX_REGISTER_SIZE]; +- const gdb_byte *p; ++ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); ++ int offset = 0; + +- if (TYPE_LENGTH (type) <= 8) ++ /* Enforce alignment of stack location, if requested. */ ++ if (align > tdep->wordsize) ++ { ++ 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) + { +- /* Version 1.7 of the 64-bit PowerPC ELF ABI says: ++ 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_integer (struct gdbarch *gdbarch, ULONGEST val, ++ struct ppc64_sysv_argpos *argpos) ++{ ++ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); ++ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); ++ gdb_byte buf[MAX_REGISTER_SIZE]; + +- "Single precision floating point values are mapped to +- the first word in a single doubleword." ++ if (argpos->regcache) ++ store_unsigned_integer (buf, tdep->wordsize, byte_order, val); ++ ppc64_sysv_abi_push_val (gdbarch, buf, tdep->wordsize, 0, argpos); ++} + +- And version 1.9 says: ++/* 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. */ + +- "Single precision floating point values are mapped to +- the second word in a single doubleword." ++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; + +- GDB then writes single precision floating point values +- at both words in a doubleword, to support both ABIs. */ +- if (TYPE_LENGTH (type) == 4) ++ if (TYPE_LENGTH (type) <= 8 ++ && TYPE_CODE (type) == TYPE_CODE_FLT) ++ { ++ /* Floats and doubles go in f1 .. f13. 32-bit floats are converted ++ to double first. */ ++ if (argpos->regcache && argpos->freg <= 13) + { +- memcpy (regval, val, 4); +- memcpy (regval + 4, val, 4); +- p = regval; ++ int regnum = tdep->ppc_fp0_regnum + argpos->freg; ++ struct type *regtype = register_type (gdbarch, regnum); ++ gdb_byte regval[MAX_REGISTER_SIZE]; ++ ++ convert_typed_floating (val, type, regval, regtype); ++ regcache_cooked_write (argpos->regcache, regnum, regval); + } +- else +- p = val; + +- /* Write value in the stack's parameter save area. */ +- write_memory (gparam, p, 8); ++ argpos->freg++; ++ } ++ else if (TYPE_LENGTH (type) <= 8 ++ && TYPE_CODE (type) == TYPE_CODE_DECFLOAT) ++ { ++ /* Floats and doubles go in f1 .. f13. 32-bit decimal floats are ++ placed in the least significant word. */ ++ if (argpos->regcache && argpos->freg <= 13) ++ { ++ int regnum = tdep->ppc_fp0_regnum + argpos->freg; ++ int offset = 8 - TYPE_LENGTH (type); + +- /* Floats and Doubles go in f1 .. f13. They also consume a left aligned +- GREG, and can end up in memory. */ +- if (freg <= 13) ++ regcache_cooked_write_part (argpos->regcache, regnum, ++ offset, TYPE_LENGTH (type), val); ++ } ++ ++ argpos->freg++; ++ } ++ else if (TYPE_LENGTH (type) == 16 ++ && TYPE_CODE (type) == TYPE_CODE_FLT ++ && (gdbarch_long_double_format (gdbarch) ++ == floatformats_ibm_long_double)) ++ { ++ /* IBM long double stored in two consecutive FPRs. */ ++ if (argpos->regcache && argpos->freg <= 13) + { +- struct type *regtype; ++ int regnum = tdep->ppc_fp0_regnum + argpos->freg; + +- regtype = register_type (gdbarch, tdep->ppc_fp0_regnum + freg); +- convert_typed_floating (val, type, regval, regtype); +- regcache_cooked_write (regcache, tdep->ppc_fp0_regnum + freg, regval); ++ regcache_cooked_write (argpos->regcache, regnum, val); ++ if (argpos->freg <= 12) ++ regcache_cooked_write (argpos->regcache, regnum + 1, val + 8); ++ } ++ ++ argpos->freg += 2; ++ } ++ else if (TYPE_LENGTH (type) == 16 ++ && TYPE_CODE (type) == TYPE_CODE_DECFLOAT) ++ { ++ /* 128-bit decimal floating-point values are stored in and even/odd ++ pair of FPRs, with the even FPR holding the most significant half. */ ++ argpos->freg += argpos->freg & 1; ++ ++ if (argpos->regcache && argpos->freg <= 12) ++ { ++ int regnum = tdep->ppc_fp0_regnum + argpos->freg; ++ ++ regcache_cooked_write (argpos->regcache, regnum, val); ++ regcache_cooked_write (argpos->regcache, regnum + 1, val + 8); ++ } ++ ++ argpos->freg += 2; ++ } ++} ++ ++/* VAL is a value of AltiVec vector type. Load it into a vector register ++ if required by the ABI, and update ARGPOS. */ ++ ++static void ++ppc64_sysv_abi_push_vreg (struct gdbarch *gdbarch, const bfd_byte *val, ++ struct ppc64_sysv_argpos *argpos) ++{ ++ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); ++ ++ if (argpos->regcache && argpos->vreg <= 13) ++ regcache_cooked_write (argpos->regcache, ++ tdep->ppc_vr0_regnum + argpos->vreg, val); ++ ++ argpos->vreg++; ++} ++ ++/* VAL is a value of TYPE. Load it into memory and/or registers ++ as required by the ABI, and update ARGPOS. */ ++ ++static void ++ppc64_sysv_abi_push_param (struct gdbarch *gdbarch, ++ struct type *type, const bfd_byte *val, ++ struct ppc64_sysv_argpos *argpos) ++{ ++ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); ++ ++ if (TYPE_CODE (type) == TYPE_CODE_FLT ++ || TYPE_CODE (type) == TYPE_CODE_DECFLOAT) ++ { ++ /* Floating-point scalars are passed in floating-point registers. */ ++ ppc64_sysv_abi_push_val (gdbarch, val, TYPE_LENGTH (type), 0, argpos); ++ ppc64_sysv_abi_push_freg (gdbarch, type, val, argpos); ++ } ++ else if (TYPE_CODE (type) == TYPE_CODE_ARRAY && TYPE_VECTOR (type) ++ && tdep->vector_abi == POWERPC_VEC_ALTIVEC ++ && TYPE_LENGTH (type) == 16) ++ { ++ /* AltiVec vectors are passed aligned, and in vector registers. */ ++ ppc64_sysv_abi_push_val (gdbarch, val, TYPE_LENGTH (type), 16, argpos); ++ ppc64_sysv_abi_push_vreg (gdbarch, val, argpos); ++ } ++ else if (TYPE_CODE (type) == TYPE_CODE_ARRAY && TYPE_VECTOR (type) ++ && TYPE_LENGTH (type) >= 16) ++ { ++ /* Non-Altivec vectors are passed by reference. */ ++ ++ /* Copy value onto the stack ... */ ++ CORE_ADDR addr = align_up (argpos->refparam, 16); ++ if (argpos->regcache) ++ write_memory (addr, val, TYPE_LENGTH (type)); ++ argpos->refparam = align_up (addr + TYPE_LENGTH (type), tdep->wordsize); ++ ++ /* ... and pass a pointer to the copy as parameter. */ ++ ppc64_sysv_abi_push_integer (gdbarch, addr, argpos); ++ } ++ else if ((TYPE_CODE (type) == TYPE_CODE_INT ++ || TYPE_CODE (type) == TYPE_CODE_ENUM ++ || TYPE_CODE (type) == TYPE_CODE_BOOL ++ || TYPE_CODE (type) == TYPE_CODE_CHAR ++ || TYPE_CODE (type) == TYPE_CODE_PTR ++ || TYPE_CODE (type) == TYPE_CODE_REF) ++ && TYPE_LENGTH (type) <= tdep->wordsize) ++ { ++ ULONGEST word = 0; ++ ++ if (argpos->regcache) ++ { ++ /* Sign extend the value, then store it unsigned. */ ++ word = unpack_long (type, val); ++ ++ /* Convert any function code addresses into descriptors. */ ++ if (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) +- regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + greg, regval); ++ ++ ppc64_sysv_abi_push_integer (gdbarch, word, argpos); + } + else + { +- /* IBM long double stored in two doublewords of the +- parameter save area and corresponding registers. */ +- if (!tdep->soft_float && freg <= 13) +- { +- regcache_cooked_write (regcache, tdep->ppc_fp0_regnum + freg, val); +- if (freg <= 12) +- regcache_cooked_write (regcache, tdep->ppc_fp0_regnum + freg + 1, +- val + 8); +- } +- if (greg <= 10) +- { +- regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + greg, val); +- if (greg <= 9) +- regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + greg + 1, +- val + 8); ++ ppc64_sysv_abi_push_val (gdbarch, val, TYPE_LENGTH (type), 0, argpos); ++ ++ /* The ABI (version 1.9) specifies that structs containing a ++ single floating-point value, at any level of nesting of ++ single-member structs, are passed in floating-point registers. */ ++ if (TYPE_CODE (type) == TYPE_CODE_STRUCT ++ && TYPE_NFIELDS (type) == 1) ++ { ++ while (TYPE_CODE (type) == TYPE_CODE_STRUCT ++ && TYPE_NFIELDS (type) == 1) ++ type = check_typedef (TYPE_FIELD_TYPE (type, 0)); ++ ++ if (TYPE_CODE (type) == TYPE_CODE_FLT) ++ ppc64_sysv_abi_push_freg (gdbarch, type, val, argpos); + } +- write_memory (gparam, val, TYPE_LENGTH (type)); + } + } + +@@ -1236,20 +1442,11 @@ ppc64_sysv_abi_push_dummy_call (struct g + 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) + { +@@ -1257,19 +1454,21 @@ ppc64_sysv_abi_push_dummy_call (struct g + 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 +@@ -1278,14 +1477,7 @@ ppc64_sysv_abi_push_dummy_call (struct g + 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++) + { +@@ -1293,432 +1485,54 @@ ppc64_sysv_abi_push_dummy_call (struct g + struct type *type = check_typedef (value_type (arg)); + const bfd_byte *val = value_contents (arg); + +- if (TYPE_CODE (type) == TYPE_CODE_FLT && TYPE_LENGTH (type) <= 8) +- { +- if (write_pass) +- ppc64_sysv_abi_push_float (gdbarch, regcache, tdep, type, +- val, freg, greg, gparam); +- +- freg++; +- greg++; +- /* Always consume parameter stack space. */ +- gparam = align_up (gparam + 8, tdep->wordsize); +- } +- else if (TYPE_CODE (type) == TYPE_CODE_FLT +- && TYPE_LENGTH (type) == 16 +- && (gdbarch_long_double_format (gdbarch) +- == floatformats_ibm_long_double)) +- { +- if (write_pass) +- ppc64_sysv_abi_push_float (gdbarch, regcache, tdep, type, +- val, freg, greg, gparam); +- freg += 2; +- greg += 2; +- gparam = align_up (gparam + TYPE_LENGTH (type), tdep->wordsize); +- } +- else if (TYPE_CODE (type) == TYPE_CODE_COMPLEX +- && (TYPE_LENGTH (type) == 8 || TYPE_LENGTH (type) == 16)) +- { +- int i; +- +- for (i = 0; i < 2; i++) +- { +- if (write_pass) +- { +- struct type *target_type; +- +- target_type = check_typedef (TYPE_TARGET_TYPE (type)); +- ppc64_sysv_abi_push_float (gdbarch, regcache, tdep, +- target_type, val + i * +- TYPE_LENGTH (target_type), +- freg, greg, gparam); +- } +- freg++; +- greg++; +- /* Always consume parameter stack space. */ +- gparam = align_up (gparam + 8, tdep->wordsize); +- } +- } +- else if (TYPE_CODE (type) == TYPE_CODE_COMPLEX +- && TYPE_LENGTH (type) == 32 +- && (gdbarch_long_double_format (gdbarch) +- == floatformats_ibm_long_double)) +- { +- int i; +- +- for (i = 0; i < 2; i++) +- { +- struct type *target_type; +- +- target_type = check_typedef (TYPE_TARGET_TYPE (type)); +- if (write_pass) +- ppc64_sysv_abi_push_float (gdbarch, regcache, tdep, +- target_type, val + i * +- TYPE_LENGTH (target_type), +- freg, greg, gparam); +- freg += 2; +- greg += 2; +- gparam = align_up (gparam + TYPE_LENGTH (target_type), +- tdep->wordsize); +- } +- } +- else if (TYPE_CODE (type) == TYPE_CODE_DECFLOAT +- && TYPE_LENGTH (type) <= 8) +- { +- /* 32-bit and 64-bit decimal floats go in f1 .. f13. They can +- end up in memory. */ +- if (write_pass) +- { +- gdb_byte regval[MAX_REGISTER_SIZE]; +- const gdb_byte *p; +- +- /* 32-bit decimal floats are right aligned in the +- doubleword. */ +- if (TYPE_LENGTH (type) == 4) +- { +- memcpy (regval + 4, val, 4); +- p = regval; +- } +- else +- p = val; +- +- /* Write value in the stack's parameter save area. */ +- write_memory (gparam, p, 8); +- +- if (freg <= 13) +- regcache_cooked_write (regcache, +- tdep->ppc_fp0_regnum + freg, p); +- } +- +- freg++; +- greg++; +- /* Always consume parameter stack space. */ +- gparam = align_up (gparam + 8, tdep->wordsize); +- } +- else if (TYPE_CODE (type) == TYPE_CODE_DECFLOAT && +- TYPE_LENGTH (type) == 16) ++ if (TYPE_CODE (type) == TYPE_CODE_COMPLEX) + { +- /* 128-bit decimal floats go in f2 .. f12, always in even/odd +- pairs. They can end up in memory, using two doublewords. */ +- if (write_pass) +- { +- if (freg <= 12) +- { +- /* Make sure freg is even. */ +- freg += freg & 1; +- regcache_cooked_write (regcache, +- tdep->ppc_fp0_regnum + freg, val); +- regcache_cooked_write (regcache, +- tdep->ppc_fp0_regnum + freg + 1, val + 8); +- } +- +- write_memory (gparam, val, TYPE_LENGTH (type)); +- } ++ /* Complex types are passed as if two independent scalars. */ ++ struct type *eltype = check_typedef (TYPE_TARGET_TYPE (type)); + +- freg += 2; +- greg += 2; +- gparam = align_up (gparam + TYPE_LENGTH (type), tdep->wordsize); ++ ppc64_sysv_abi_push_param (gdbarch, eltype, val, &argpos); ++ ppc64_sysv_abi_push_param (gdbarch, eltype, ++ val + TYPE_LENGTH (eltype), &argpos); + } +- else if (TYPE_LENGTH (type) < 16 +- && TYPE_CODE (type) == TYPE_CODE_ARRAY +- && TYPE_VECTOR (type) ++ else if (TYPE_CODE (type) == TYPE_CODE_ARRAY && TYPE_VECTOR (type) + && opencl_abi) + { + /* OpenCL vectors shorter than 16 bytes are passed as if +- a series of independent scalars. */ +- struct type *eltype = check_typedef (TYPE_TARGET_TYPE (type)); +- int i, nelt = TYPE_LENGTH (type) / TYPE_LENGTH (eltype); ++ a series of independent scalars; OpenCL vectors 16 bytes ++ or longer are passed as if a series of AltiVec vectors. */ ++ struct type *eltype; ++ int i, nelt; ++ ++ if (TYPE_LENGTH (type) < 16) ++ eltype = check_typedef (TYPE_TARGET_TYPE (type)); ++ else ++ eltype = register_type (gdbarch, tdep->ppc_vr0_regnum); + ++ nelt = TYPE_LENGTH (type) / TYPE_LENGTH (eltype); + for (i = 0; i < nelt; i++) + { + const gdb_byte *elval = val + i * TYPE_LENGTH (eltype); + +- if (TYPE_CODE (eltype) == TYPE_CODE_FLT) +- { +- if (write_pass) +- { +- gdb_byte regval[MAX_REGISTER_SIZE]; +- const gdb_byte *p; +- +- if (TYPE_LENGTH (eltype) == 4) +- { +- memcpy (regval, elval, 4); +- memcpy (regval + 4, elval, 4); +- p = regval; +- } +- else +- p = elval; +- +- write_memory (gparam, p, 8); +- +- if (freg <= 13) +- { +- int regnum = tdep->ppc_fp0_regnum + freg; +- struct type *regtype +- = register_type (gdbarch, regnum); +- +- convert_typed_floating (elval, eltype, +- regval, regtype); +- regcache_cooked_write (regcache, regnum, regval); +- } +- +- if (greg <= 10) +- regcache_cooked_write (regcache, +- tdep->ppc_gp0_regnum + greg, +- regval); +- } +- +- freg++; +- greg++; +- gparam = align_up (gparam + 8, tdep->wordsize); +- } +- else +- { +- if (write_pass) +- { +- ULONGEST word = unpack_long (eltype, elval); +- if (greg <= 10) +- regcache_cooked_write_unsigned +- (regcache, tdep->ppc_gp0_regnum + greg, word); +- +- write_memory_unsigned_integer +- (gparam, tdep->wordsize, byte_order, word); +- } +- +- greg++; +- gparam = align_up (gparam + TYPE_LENGTH (eltype), +- tdep->wordsize); +- } ++ ppc64_sysv_abi_push_param (gdbarch, eltype, elval, &argpos); + } + } +- 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); +- } +- greg++; +- gparam = align_up (gparam + TYPE_LENGTH (type), tdep->wordsize); +- } + else + { +- ssize_t byte; +- for (byte = 0; byte < TYPE_LENGTH (type); +- byte += tdep->wordsize) +- { +- if (write_pass && greg <= 10) +- { +- gdb_byte regval[MAX_REGISTER_SIZE]; +- ssize_t 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. */ +- ssize_t 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; + } + } + +@@ -1754,271 +1568,252 @@ ppc64_sysv_abi_push_dummy_call (struct g + 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. ++ This routine also handles components of aggregate return types; ++ INDEX describes which part of the aggregate is to be handled. + +- 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) ++ 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)); ++ /* 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; + +- /* Floats and doubles in F1. */ +- if (TYPE_CODE (valtype) == TYPE_CODE_FLT && TYPE_LENGTH (valtype) <= 8) ++ if (writebuf != NULL) ++ { ++ /* Be careful to sign extend the value. */ ++ regcache_cooked_write_unsigned (regcache, regnum, ++ unpack_long (valtype, writebuf)); ++ } ++ if (readbuf != NULL) ++ { ++ /* Extract the integer from GPR. Since this is truncating the ++ value, there isn't a sign extension problem. */ ++ ULONGEST regval; ++ ++ regcache_cooked_read_unsigned (regcache, regnum, ®val); ++ store_unsigned_integer (readbuf, TYPE_LENGTH (valtype), ++ gdbarch_byte_order (gdbarch), regval); ++ } ++ return 1; ++ } ++ ++ /* Floats and doubles go in f1 .. f13. 32-bit floats are converted ++ to double first. */ ++ if (TYPE_LENGTH (valtype) <= 8 ++ && TYPE_CODE (valtype) == TYPE_CODE_FLT) + { ++ int regnum = tdep->ppc_fp0_regnum + 1 + index; ++ struct type *regtype = register_type (gdbarch, regnum); + gdb_byte regval[MAX_REGISTER_SIZE]; +- 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); ++ regcache_cooked_write (regcache, regnum, regval); + } + if (readbuf != NULL) + { +- regcache_cooked_read (regcache, tdep->ppc_fp0_regnum + 1, regval); ++ regcache_cooked_read (regcache, regnum, regval); + convert_typed_floating (regval, regtype, readbuf, valtype); + } +- return RETURN_VALUE_REGISTER_CONVENTION; ++ return 1; + } +- if (TYPE_CODE (valtype) == TYPE_CODE_DECFLOAT) +- return get_decimal_float_return_value (gdbarch, valtype, regcache, readbuf, +- writebuf); +- /* Integers in r3. */ +- if ((TYPE_CODE (valtype) == TYPE_CODE_INT +- || TYPE_CODE (valtype) == TYPE_CODE_ENUM +- || TYPE_CODE (valtype) == TYPE_CODE_CHAR +- || TYPE_CODE (valtype) == TYPE_CODE_BOOL) +- && TYPE_LENGTH (valtype) <= 8) ++ ++ /* 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 (writebuf != NULL) ++ regcache_cooked_write_part (regcache, regnum, ++ offset, TYPE_LENGTH (valtype), writebuf); ++ if (readbuf != NULL) ++ regcache_cooked_read_part (regcache, regnum, ++ offset, TYPE_LENGTH (valtype), readbuf); ++ return 1; ++ } ++ ++ /* IBM long double stored in two consecutive FPRs. */ ++ if (TYPE_LENGTH (valtype) == 16 ++ && TYPE_CODE (valtype) == TYPE_CODE_FLT ++ && (gdbarch_long_double_format (gdbarch) ++ == floatformats_ibm_long_double)) ++ { ++ int regnum = tdep->ppc_fp0_regnum + 1 + 2 * index; ++ + if (writebuf != NULL) + { +- /* Be careful to sign extend the value. */ +- regcache_cooked_write_unsigned (regcache, tdep->ppc_gp0_regnum + 3, +- unpack_long (valtype, writebuf)); ++ regcache_cooked_write (regcache, regnum, writebuf); ++ regcache_cooked_write (regcache, regnum + 1, writebuf + 8); + } + if (readbuf != NULL) + { +- /* Extract the integer from r3. Since this is truncating the +- value, there isn't a sign extension problem. */ +- ULONGEST regval; +- regcache_cooked_read_unsigned (regcache, tdep->ppc_gp0_regnum + 3, +- ®val); +- store_unsigned_integer (readbuf, TYPE_LENGTH (valtype), byte_order, +- regval); ++ regcache_cooked_read (regcache, regnum, readbuf); ++ regcache_cooked_read (regcache, regnum + 1, readbuf + 8); + } +- 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) ++ ++ /* 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) + { +- /* All pointers live in r3. */ ++ int regnum = tdep->ppc_fp0_regnum + 2 + 2 * index; ++ + if (writebuf != NULL) +- regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + 3, writebuf); ++ { ++ regcache_cooked_write (regcache, regnum, writebuf); ++ regcache_cooked_write (regcache, regnum + 1, writebuf + 8); ++ } + if (readbuf != NULL) +- regcache_cooked_read (regcache, tdep->ppc_gp0_regnum + 3, readbuf); +- return RETURN_VALUE_REGISTER_CONVENTION; ++ { ++ regcache_cooked_read (regcache, regnum, readbuf); ++ regcache_cooked_read (regcache, regnum + 1, readbuf + 8); ++ } ++ 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) ++ ++ /* 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) + { +- struct type *eltype = check_typedef (TYPE_TARGET_TYPE (valtype)); +- int i, nelt = TYPE_LENGTH (valtype) / TYPE_LENGTH (eltype); ++ int regnum = tdep->ppc_vr0_regnum + 2 + index; + +- for (i = 0; i < nelt; i++) +- { +- int offset = i * TYPE_LENGTH (eltype); ++ if (writebuf != NULL) ++ regcache_cooked_write (regcache, regnum, writebuf); ++ if (readbuf != NULL) ++ regcache_cooked_read (regcache, regnum, readbuf); ++ return 1; ++ } + +- 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); ++ return 0; ++} + +- 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; ++/* The 64 bit ABI return value convention. + +- 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); +- } +- } +- } ++ 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). + +- return RETURN_VALUE_REGISTER_CONVENTION; +- } +- /* OpenCL vectors >= 16 bytes are returned in v2..v9. */ +- if (TYPE_CODE (valtype) == TYPE_CODE_ARRAY +- && TYPE_VECTOR (valtype) +- && TYPE_LENGTH (valtype) >= 16 +- && opencl_abi) ++ 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) + { +- int n_regs = TYPE_LENGTH (valtype) / 16; +- int i; ++ eltype = check_typedef (TYPE_TARGET_TYPE (valtype)); + +- for (i = 0; i < n_regs; i++) ++ for (i = 0; i < 2; i++) + { +- int offset = i * 16; +- int regnum = tdep->ppc_vr0_regnum + 2 + i; ++ ok = ppc64_sysv_abi_return_value_base (gdbarch, eltype, regcache, ++ readbuf, writebuf, i); ++ gdb_assert (ok); + +- if (writebuf != NULL) +- regcache_cooked_write (regcache, regnum, writebuf + offset); +- if (readbuf != NULL) +- regcache_cooked_read (regcache, regnum, readbuf + offset); ++ if (readbuf) ++ readbuf += TYPE_LENGTH (eltype); ++ if (writebuf) ++ writebuf += TYPE_LENGTH (eltype); + } +- + return RETURN_VALUE_REGISTER_CONVENTION; + } +- /* Array type has more than one use. */ +- if (TYPE_CODE (valtype) == TYPE_CODE_ARRAY) +- { +- /* Small character arrays are returned, right justified, in r3. */ +- if (TYPE_LENGTH (valtype) <= 8 +- && TYPE_CODE (TYPE_TARGET_TYPE (valtype)) == TYPE_CODE_INT +- && TYPE_LENGTH (TYPE_TARGET_TYPE (valtype)) == 1) +- { +- int offset = (register_size (gdbarch, tdep->ppc_gp0_regnum + 3) +- - TYPE_LENGTH (valtype)); +- if (writebuf != NULL) +- regcache_cooked_write_part (regcache, tdep->ppc_gp0_regnum + 3, +- offset, TYPE_LENGTH (valtype), writebuf); +- if (readbuf != NULL) +- regcache_cooked_read_part (regcache, tdep->ppc_gp0_regnum + 3, +- offset, TYPE_LENGTH (valtype), readbuf); +- return RETURN_VALUE_REGISTER_CONVENTION; +- } +- /* A VMX vector is returned in v2. */ +- if (TYPE_CODE (valtype) == TYPE_CODE_ARRAY +- && TYPE_VECTOR (valtype) +- && tdep->vector_abi == POWERPC_VEC_ALTIVEC) +- { +- if (readbuf) +- regcache_cooked_read (regcache, tdep->ppc_vr0_regnum + 2, readbuf); +- if (writebuf) +- regcache_cooked_write (regcache, tdep->ppc_vr0_regnum + 2, +- writebuf); +- return RETURN_VALUE_REGISTER_CONVENTION; +- } +- } +- /* Big floating point values get stored in adjacent floating +- point registers, starting with F1. */ +- if (TYPE_CODE (valtype) == TYPE_CODE_FLT +- && (TYPE_LENGTH (valtype) == 16 || TYPE_LENGTH (valtype) == 32)) ++ ++ /* OpenCL vectors shorter than 16 bytes are returned as if ++ a series of independent scalars; OpenCL vectors 16 bytes ++ or longer are returned as if a series of AltiVec vectors. */ ++ if (TYPE_CODE (valtype) == TYPE_CODE_ARRAY && TYPE_VECTOR (valtype) ++ && opencl_abi) + { +- if (writebuf || readbuf != NULL) ++ if (TYPE_LENGTH (valtype) < 16) ++ eltype = check_typedef (TYPE_TARGET_TYPE (valtype)); ++ else ++ eltype = register_type (gdbarch, tdep->ppc_vr0_regnum); ++ ++ nelt = TYPE_LENGTH (valtype) / TYPE_LENGTH (eltype); ++ for (i = 0; i < nelt; i++) + { +- 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)) ++ ++ /* 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 < 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); +- } +- } +- } ++ 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; + } +- /* Big complex values get stored in f1:f4. */ +- if (TYPE_CODE (valtype) == TYPE_CODE_COMPLEX && TYPE_LENGTH (valtype) == 32) ++ ++ /* 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) + { +- 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; ++ 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/SOURCES/gdb-rhbz1125820-ppc64le-enablement-24of37.patch b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-24of37.patch new file mode 100644 index 0000000..6f1c5b0 --- /dev/null +++ b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-24of37.patch @@ -0,0 +1,33 @@ +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. + +Index: gdb-7.6.1/gdb/ppc-sysv-tdep.c +=================================================================== +--- gdb-7.6.1.orig/gdb/ppc-sysv-tdep.c ++++ gdb-7.6.1/gdb/ppc-sysv-tdep.c +@@ -1149,7 +1149,8 @@ ppc64_sysv_abi_push_val (struct 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/SOURCES/gdb-rhbz1125820-ppc64le-enablement-25of37.patch b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-25of37.patch new file mode 100644 index 0000000..a928855 --- /dev/null +++ b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-25of37.patch @@ -0,0 +1,58 @@ +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. + +Index: gdb-7.6.1/gdb/testsuite/gdb.arch/altivec-regs.exp +=================================================================== +--- gdb-7.6.1.orig/gdb/testsuite/gdb.arch/altivec-regs.exp ++++ gdb-7.6.1/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" + 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/SOURCES/gdb-rhbz1125820-ppc64le-enablement-26of37.patch b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-26of37.patch new file mode 100644 index 0000000..fd0ae6a --- /dev/null +++ b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-26of37.patch @@ -0,0 +1,125 @@ +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. + +Index: gdb-7.6.1/gdb/rs6000-tdep.c +=================================================================== +--- gdb-7.6.1.orig/gdb/rs6000-tdep.c ++++ gdb-7.6.1/gdb/rs6000-tdep.c +@@ -2830,10 +2830,12 @@ efpr_pseudo_register_read (struct gdbarc + { + 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. */ +@@ -2843,10 +2845,12 @@ efpr_pseudo_register_write (struct gdbar + { + 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 +Index: gdb-7.6.1/gdb/testsuite/gdb.arch/vsx-regs.exp +=================================================================== +--- gdb-7.6.1.orig/gdb/testsuite/gdb.arch/vsx-regs.exp ++++ gdb-7.6.1/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_register2 "uint128 = 0xdeadbeefdeadbeefdeadbeefdeadbeef, v2_double = .0x1, 0x1., v4_float = .0x0, 0x0, 0x0, 0x0., v4_int32 = .0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef., v8_int16 = .0xdead, 0xbeef, 0xdead, 0xbeef, 0xdead, 0xbeef, 0xdead, 0xbeef., v16_int8 = .0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef.." + +-set vector_register1_vr ".uint128 = 0x3ff4cccccccccccc0000000100000001, v4_float = .0x1, 0xf99999a0, 0x0, 0x0., v4_int32 = .0x3ff4cccc, 0xcccccccc, 0x1, 0x1., v8_int16 = .0x3ff4, 0xcccc, 0xcccc, 0xcccc, 0x0, 0x1, 0x0, 0x1., v16_int8 = .0x3f, 0xf4, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1.." ++ set vector_register2_vr "uint128 = 0xdeadbeefdeadbeefdeadbeefdeadbeef, v4_float = .0x0, 0x0, 0x0, 0x0., v4_int32 = .0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef., v8_int16 = .0xdead, 0xbeef, 0xdead, 0xbeef, 0xdead, 0xbeef, 0xdead, 0xbeef., v16_int8 = .0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef.." + +-set vector_register2 "uint128 = 0xdeadbeefdeadbeefdeadbeefdeadbeef, v2_double = .0x1, 0x1., v4_float = .0x0, 0x0, 0x0, 0x0., v4_int32 = .0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef., v8_int16 = .0xdead, 0xbeef, 0xdead, 0xbeef, 0xdead, 0xbeef, 0xdead, 0xbeef., v16_int8 = .0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef.." ++ set vector_register3 ".uint128 = 0x00000001000000010000000100000001, v2_double = .0x0, 0x0., v4_float = .0x0, 0x0, 0x0, 0x0., v4_int32 = .0x1, 0x1, 0x1, 0x1., v8_int16 = .0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1., v16_int8 = .0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1.." + +-set vector_register2_vr "uint128 = 0xdeadbeefdeadbeefdeadbeefdeadbeef, v4_float = .0x0, 0x0, 0x0, 0x0., v4_int32 = .0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef., v8_int16 = .0xdead, 0xbeef, 0xdead, 0xbeef, 0xdead, 0xbeef, 0xdead, 0xbeef., v16_int8 = .0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef.." ++ set vector_register3_vr ".uint128 = 0x00000001000000010000000100000001, v4_float = .0x0, 0x0, 0x0, 0x0., v4_int32 = .0x1, 0x1, 0x1, 0x1., v8_int16 = .0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1., v16_int8 = .0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1.." ++} else { ++ set vector_register1 ".uint128 = 0x3ff4cccccccccccc0000000000000000, v2_double = .0x0, 0x1., v4_float = .0x0, 0x0, 0xf99999a0, 0x1., v4_int32 = .0x0, 0x0, 0xcccccccc, 0x3ff4cccc., v8_int16 = .0x0, 0x0, 0x0, 0x0, 0xcccc, 0xcccc, 0xcccc, 0x3ff4., v16_int8 = .0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xf4, 0x3f.." + +-set vector_register3 ".uint128 = 0x00000001000000010000000100000001, v2_double = .0x0, 0x0., v4_float = .0x0, 0x0, 0x0, 0x0., v4_int32 = .0x1, 0x1, 0x1, 0x1., v8_int16 = .0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1., v16_int8 = .0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1.." ++ set vector_register1_vr ".uint128 = 0x3ff4cccccccccccc0000000100000001, v4_float = .0x0, 0x0, 0xf99999a0, 0x1., v4_int32 = .0x1, 0x1, 0xcccccccc, 0x3ff4cccc., v8_int16 = .0x1, 0x0, 0x1, 0x0, 0xcccc, 0xcccc, 0xcccc, 0x3ff4., v16_int8 = .0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xf4, 0x3f.." + +-set vector_register3_vr ".uint128 = 0x00000001000000010000000100000001, v4_float = .0x0, 0x0, 0x0, 0x0., v4_int32 = .0x1, 0x1, 0x1, 0x1., v8_int16 = .0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1., v16_int8 = .0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1.." ++ set vector_register2 "uint128 = 0xdeadbeefdeadbeefdeadbeefdeadbeef, v2_double = .0x1, 0x1., v4_float = .0x0, 0x0, 0x0, 0x0., v4_int32 = .0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef., v8_int16 = .0xbeef, 0xdead, 0xbeef, 0xdead, 0xbeef, 0xdead, 0xbeef, 0xdead., v16_int8 = .0xef, 0xbe, 0xad, 0xde, 0xef, 0xbe, 0xad, 0xde, 0xef, 0xbe, 0xad, 0xde, 0xef, 0xbe, 0xad, 0xde.." ++ ++ set vector_register2_vr "uint128 = 0xdeadbeefdeadbeefdeadbeefdeadbeef, v4_float = .0x0, 0x0, 0x0, 0x0., v4_int32 = .0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef., v8_int16 = .0xbeef, 0xdead, 0xbeef, 0xdead, 0xbeef, 0xdead, 0xbeef, 0xdead., v16_int8 = .0xef, 0xbe, 0xad, 0xde, 0xef, 0xbe, 0xad, 0xde, 0xef, 0xbe, 0xad, 0xde, 0xef, 0xbe, 0xad, 0xde.." ++ ++ set vector_register3 ".uint128 = 0x00000001000000010000000100000001, v2_double = .0x0, 0x0., v4_float = .0x0, 0x0, 0x0, 0x0., v4_int32 = .0x1, 0x1, 0x1, 0x1., v8_int16 = .0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0., v16_int8 = .0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0.." ++ ++ set vector_register3_vr ".uint128 = 0x00000001000000010000000100000001, v4_float = .0x0, 0x0, 0x0, 0x0., v4_int32 = .0x1, 0x1, 0x1, 0x1., v8_int16 = .0x1, 0x0, 0x1, 0x0, 0x1, 0x0, 0x1, 0x0., v16_int8 = .0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0.." ++} + + set float_register ".raw 0xdeadbeefdeadbeef." + diff --git a/SOURCES/gdb-rhbz1125820-ppc64le-enablement-27of37.patch b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-27of37.patch new file mode 100644 index 0000000..8e2285d --- /dev/null +++ b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-27of37.patch @@ -0,0 +1,45 @@ +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. + +Index: gdb-7.6.1/gdb/ppc-sysv-tdep.c +=================================================================== +--- gdb-7.6.1.orig/gdb/ppc-sysv-tdep.c ++++ gdb-7.6.1/gdb/ppc-sysv-tdep.c +@@ -1231,7 +1231,10 @@ ppc64_sysv_abi_push_freg (struct 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); +@@ -1640,7 +1643,10 @@ ppc64_sysv_abi_return_value_base (struct + && 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/SOURCES/gdb-rhbz1125820-ppc64le-enablement-28of37.patch b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-28of37.patch new file mode 100644 index 0000000..0409f9b --- /dev/null +++ b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-28of37.patch @@ -0,0 +1,118 @@ +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*-*. + +Index: gdb-7.6.1/gdb/ppc-sysv-tdep.c +=================================================================== +--- gdb-7.6.1.orig/gdb/ppc-sysv-tdep.c ++++ gdb-7.6.1/gdb/ppc-sysv-tdep.c +@@ -1269,9 +1269,11 @@ ppc64_sysv_abi_push_freg (struct 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; +@@ -1684,16 +1686,18 @@ ppc64_sysv_abi_return_value_base (struct + && 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; + } +Index: gdb-7.6.1/gdb/rs6000-tdep.c +=================================================================== +--- gdb-7.6.1.orig/gdb/rs6000-tdep.c ++++ gdb-7.6.1/gdb/rs6000-tdep.c +@@ -2723,10 +2723,10 @@ dfp_pseudo_register_read (struct gdbarch + else + { + status = regcache_raw_read (regcache, tdep->ppc_fp0_regnum + +- 2 * reg_index + 1, buffer + 8); ++ 2 * reg_index + 1, buffer); + if (status == REG_VALID) + status = regcache_raw_read (regcache, tdep->ppc_fp0_regnum + +- 2 * reg_index, buffer); ++ 2 * reg_index, buffer + 8); + } + + return status; +@@ -2752,9 +2752,9 @@ dfp_pseudo_register_write (struct gdbarc + else + { + regcache_raw_write (regcache, tdep->ppc_fp0_regnum + +- 2 * reg_index + 1, buffer + 8); ++ 2 * reg_index + 1, buffer); + regcache_raw_write (regcache, tdep->ppc_fp0_regnum + +- 2 * reg_index, buffer); ++ 2 * reg_index, buffer + 8); + } + } + +Index: gdb-7.6.1/gdb/testsuite/gdb.arch/powerpc-d128-regs.exp +=================================================================== +--- gdb-7.6.1.orig/gdb/testsuite/gdb.arch/powerpc-d128-regs.exp ++++ gdb-7.6.1/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/SOURCES/gdb-rhbz1125820-ppc64le-enablement-29of37.patch b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-29of37.patch new file mode 100644 index 0000000..f73b094 --- /dev/null +++ b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-29of37.patch @@ -0,0 +1,143 @@ +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. + +Index: gdb-7.6.1/gdb/ppc-tdep.h +=================================================================== +--- gdb-7.6.1.orig/gdb/ppc-tdep.h ++++ gdb-7.6.1/gdb/ppc-tdep.h +@@ -182,6 +182,15 @@ extern void ppc_collect_vsxregset (const + + /* Private data that this module attaches to struct gdbarch. */ + ++/* ELF ABI version used by the inferior. */ ++enum powerpc_elf_abi ++{ ++ POWERPC_ELF_AUTO, ++ POWERPC_ELF_V1, ++ POWERPC_ELF_V2, ++ POWERPC_ELF_LAST ++}; ++ + /* Vector ABI used by the inferior. */ + enum powerpc_vector_abi + { +@@ -197,6 +206,8 @@ struct gdbarch_tdep + int wordsize; /* Size in bytes of fixed-point word. */ + int soft_float; /* Avoid FP registers for arguments? */ + ++ enum powerpc_elf_abi elf_abi; /* ELF ABI version. */ ++ + /* How to pass vector arguments. Never set to AUTO or LAST. */ + enum powerpc_vector_abi vector_abi; + +Index: gdb-7.6.1/gdb/rs6000-tdep.c +=================================================================== +--- gdb-7.6.1.orig/gdb/rs6000-tdep.c ++++ gdb-7.6.1/gdb/rs6000-tdep.c +@@ -48,6 +48,7 @@ + + #include "elf-bfd.h" + #include "elf/ppc.h" ++#include "elf/ppc64.h" + + #include "solib-svr4.h" + #include "ppc-tdep.h" +@@ -3605,6 +3606,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; +@@ -3911,6 +3913,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, +@@ -3947,6 +3964,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) +@@ -3989,6 +4021,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) +@@ -4011,6 +4045,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/SOURCES/gdb-rhbz1125820-ppc64le-enablement-30of37.patch b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-30of37.patch new file mode 100644 index 0000000..f1c30e6 --- /dev/null +++ b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-30of37.patch @@ -0,0 +1,118 @@ +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. + +Index: gdb-7.6.1/gdb/ppc-linux-tdep.c +=================================================================== +--- gdb-7.6.1.orig/gdb/ppc-linux-tdep.c ++++ gdb-7.6.1/gdb/ppc-linux-tdep.c +@@ -1331,13 +1331,16 @@ ppc_linux_init_abi (struct gdbarch_info + + if (tdep->wordsize == 8) + { +- /* Handle PPC GNU/Linux 64-bit function pointers (which are really +- function descriptors). */ +- set_gdbarch_convert_from_func_ptr_addr +- (gdbarch, ppc64_convert_from_func_ptr_addr); ++ if (tdep->elf_abi == POWERPC_ELF_V1) ++ { ++ /* Handle PPC GNU/Linux 64-bit function pointers (which are really ++ function descriptors). */ ++ set_gdbarch_convert_from_func_ptr_addr ++ (gdbarch, ppc64_convert_from_func_ptr_addr); + +- set_gdbarch_elf_make_msymbol_special (gdbarch, +- ppc64_elf_make_msymbol_special); ++ set_gdbarch_elf_make_msymbol_special ++ (gdbarch, ppc64_elf_make_msymbol_special); ++ } + + /* Shared library handling. */ + set_gdbarch_skip_trampoline_code (gdbarch, ppc64_skip_trampoline_code); +Index: gdb-7.6.1/gdb/ppc-sysv-tdep.c +=================================================================== +--- gdb-7.6.1.orig/gdb/ppc-sysv-tdep.c ++++ gdb-7.6.1/gdb/ppc-sysv-tdep.c +@@ -1351,8 +1351,9 @@ ppc64_sysv_abi_push_param (struct gdbarc + 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)); +@@ -1552,24 +1553,32 @@ ppc64_sysv_abi_push_dummy_call (struct g + breakpoint. */ + regcache_cooked_write_signed (regcache, tdep->ppc_lr_regnum, bp_addr); + +- /* Use the func_addr to find the descriptor, and use that to find +- the TOC. If we're calling via a function pointer, the pointer +- itself identifies the descriptor. */ +- { +- struct type *ftype = check_typedef (value_type (function)); +- CORE_ADDR desc_addr = value_as_address (function); +- +- if (TYPE_CODE (ftype) == TYPE_CODE_PTR +- || convert_code_addr_to_desc_addr (func_addr, &desc_addr)) +- { +- /* The TOC is the second double word in the descriptor. */ +- CORE_ADDR toc = +- read_memory_unsigned_integer (desc_addr + tdep->wordsize, +- tdep->wordsize, byte_order); +- regcache_cooked_write_unsigned (regcache, +- tdep->ppc_gp0_regnum + 2, toc); +- } +- } ++ /* In the ELFv1 ABI, use the func_addr to find the descriptor, and use ++ that to find the TOC. If we're calling via a function pointer, ++ the pointer itself identifies the descriptor. */ ++ if (tdep->elf_abi == POWERPC_ELF_V1) ++ { ++ struct type *ftype = check_typedef (value_type (function)); ++ CORE_ADDR desc_addr = value_as_address (function); ++ ++ if (TYPE_CODE (ftype) == TYPE_CODE_PTR ++ || convert_code_addr_to_desc_addr (func_addr, &desc_addr)) ++ { ++ /* The TOC is the second double word in the descriptor. */ ++ CORE_ADDR toc = ++ read_memory_unsigned_integer (desc_addr + tdep->wordsize, ++ tdep->wordsize, byte_order); ++ ++ regcache_cooked_write_unsigned (regcache, ++ tdep->ppc_gp0_regnum + 2, toc); ++ } ++ } ++ ++ /* In the ELFv2 ABI, we need to pass the target address in r12 since ++ we may be calling a global entry point. */ ++ if (tdep->elf_abi == POWERPC_ELF_V2) ++ regcache_cooked_write_unsigned (regcache, ++ tdep->ppc_gp0_regnum + 12, func_addr); + + return sp; + } diff --git a/SOURCES/gdb-rhbz1125820-ppc64le-enablement-31of37.patch b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-31of37.patch new file mode 100644 index 0000000..94894d3 --- /dev/null +++ b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-31of37.patch @@ -0,0 +1,37 @@ +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. + +Index: gdb-7.6.1/gdb/ppc-sysv-tdep.c +=================================================================== +--- gdb-7.6.1.orig/gdb/ppc-sysv-tdep.c ++++ gdb-7.6.1/gdb/ppc-sysv-tdep.c +@@ -1473,9 +1473,13 @@ ppc64_sysv_abi_push_dummy_call (struct g + 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/SOURCES/gdb-rhbz1125820-ppc64le-enablement-32of37.patch b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-32of37.patch new file mode 100644 index 0000000..61720fd --- /dev/null +++ b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-32of37.patch @@ -0,0 +1,295 @@ +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. + +Index: gdb-7.6.1/gdb/ppc-sysv-tdep.c +=================================================================== +--- gdb-7.6.1.orig/gdb/ppc-sysv-tdep.c ++++ gdb-7.6.1/gdb/ppc-sysv-tdep.c +@@ -1100,6 +1100,160 @@ convert_code_addr_to_desc_addr (CORE_ADD + return 1; + } + ++/* Walk down the type tree of TYPE counting consecutive base elements. ++ If *FIELD_TYPE is NULL, then set it to the first valid floating point ++ or vector type. If a non-floating point or vector type is found, or ++ if a floating point or vector type that doesn't match a non-NULL ++ *FIELD_TYPE is found, then return -1, otherwise return the count in the ++ sub-tree. */ ++ ++static LONGEST ++ppc64_aggregate_candidate (struct type *type, ++ struct type **field_type) ++{ ++ type = check_typedef (type); ++ ++ switch (TYPE_CODE (type)) ++ { ++ case TYPE_CODE_FLT: ++ case TYPE_CODE_DECFLOAT: ++ if (!*field_type) ++ *field_type = type; ++ if (TYPE_CODE (*field_type) == TYPE_CODE (type) ++ && TYPE_LENGTH (*field_type) == TYPE_LENGTH (type)) ++ return 1; ++ break; ++ ++ case TYPE_CODE_COMPLEX: ++ type = TYPE_TARGET_TYPE (type); ++ if (TYPE_CODE (type) == TYPE_CODE_FLT ++ || TYPE_CODE (type) == TYPE_CODE_DECFLOAT) ++ { ++ if (!*field_type) ++ *field_type = type; ++ if (TYPE_CODE (*field_type) == TYPE_CODE (type) ++ && TYPE_LENGTH (*field_type) == TYPE_LENGTH (type)) ++ return 2; ++ } ++ break; ++ ++ case TYPE_CODE_ARRAY: ++ if (TYPE_VECTOR (type)) ++ { ++ if (!*field_type) ++ *field_type = type; ++ if (TYPE_CODE (*field_type) == TYPE_CODE (type) ++ && TYPE_LENGTH (*field_type) == TYPE_LENGTH (type)) ++ return 1; ++ } ++ else ++ { ++ LONGEST count, low_bound, high_bound; ++ ++ count = ppc64_aggregate_candidate ++ (TYPE_TARGET_TYPE (type), field_type); ++ if (count == -1) ++ return -1; ++ ++ if (!get_array_bounds (type, &low_bound, &high_bound)) ++ return -1; ++ count *= high_bound - low_bound; ++ ++ /* There must be no padding. */ ++ if (count == 0) ++ return TYPE_LENGTH (type) == 0 ? 0 : -1; ++ else if (TYPE_LENGTH (type) != count * TYPE_LENGTH (*field_type)) ++ return -1; ++ ++ return count; ++ } ++ break; ++ ++ case TYPE_CODE_STRUCT: ++ case TYPE_CODE_UNION: ++ { ++ LONGEST count = 0; ++ int i; ++ ++ for (i = 0; i < TYPE_NFIELDS (type); i++) ++ { ++ LONGEST sub_count; ++ ++ if (field_is_static (&TYPE_FIELD (type, i))) ++ continue; ++ ++ sub_count = ppc64_aggregate_candidate ++ (TYPE_FIELD_TYPE (type, i), field_type); ++ if (sub_count == -1) ++ return -1; ++ ++ if (TYPE_CODE (type) == TYPE_CODE_STRUCT) ++ count += sub_count; ++ else ++ count = max (count, sub_count); ++ } ++ ++ /* There must be no padding. */ ++ if (count == 0) ++ return TYPE_LENGTH (type) == 0 ? 0 : -1; ++ else if (TYPE_LENGTH (type) != count * TYPE_LENGTH (*field_type)) ++ return -1; ++ ++ return count; ++ } ++ break; ++ ++ default: ++ break; ++ } ++ ++ return -1; ++} ++ ++/* If an argument of type TYPE is a homogeneous float or vector aggregate ++ that shall be passed in FP/vector registers according to the ELFv2 ABI, ++ return the homogeneous element type in *ELT_TYPE and the number of ++ elements in *N_ELTS, and return non-zero. Otherwise, return zero. */ ++ ++static int ++ppc64_elfv2_abi_homogeneous_aggregate (struct type *type, ++ struct type **elt_type, int *n_elts) ++{ ++ /* Complex types at the top level are treated separately. However, ++ complex types can be elements of homogeneous aggregates. */ ++ if (TYPE_CODE (type) == TYPE_CODE_STRUCT ++ || TYPE_CODE (type) == TYPE_CODE_UNION ++ || (TYPE_CODE (type) == TYPE_CODE_ARRAY && !TYPE_VECTOR (type))) ++ { ++ struct type *field_type = NULL; ++ LONGEST field_count = ppc64_aggregate_candidate (type, &field_type); ++ ++ if (field_count > 0) ++ { ++ int n_regs = ((TYPE_CODE (field_type) == TYPE_CODE_FLT ++ || TYPE_CODE (field_type) == TYPE_CODE_DECFLOAT)? ++ (TYPE_LENGTH (field_type) + 7) >> 3 : 1); ++ ++ /* The ELFv2 ABI allows homogeneous aggregates to occupy ++ up to 8 registers. */ ++ if (field_count * n_regs <= 8) ++ { ++ if (elt_type) ++ *elt_type = field_type; ++ if (n_elts) ++ *n_elts = (int) field_count; ++ /* 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 + { +@@ -1388,6 +1542,29 @@ ppc64_sysv_abi_push_param (struct gdbarc + 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); ++ } ++ } + } + } + +@@ -1833,6 +2010,72 @@ ppc64_sysv_abi_return_value (struct gdba + return RETURN_VALUE_REGISTER_CONVENTION; + } + ++ /* In the ELFv2 ABI, homogeneous floating-point or vector ++ aggregates are returned in registers. */ ++ if (tdep->elf_abi == POWERPC_ELF_V2 ++ && ppc64_elfv2_abi_homogeneous_aggregate (valtype, &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/SOURCES/gdb-rhbz1125820-ppc64le-enablement-33of37.patch b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-33of37.patch new file mode 100644 index 0000000..d97115c --- /dev/null +++ b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-33of37.patch @@ -0,0 +1,357 @@ +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. + +Index: gdb-7.6.1/gdb/gdbarch.c +=================================================================== +--- gdb-7.6.1.orig/gdb/gdbarch.c ++++ gdb-7.6.1/gdb/gdbarch.c +@@ -200,6 +200,7 @@ struct gdbarch + gdbarch_return_in_first_hidden_param_p_ftype *return_in_first_hidden_param_p; + gdbarch_skip_prologue_ftype *skip_prologue; + gdbarch_skip_main_prologue_ftype *skip_main_prologue; ++ gdbarch_skip_entrypoint_ftype *skip_entrypoint; + gdbarch_inner_than_ftype *inner_than; + gdbarch_breakpoint_from_pc_ftype *breakpoint_from_pc; + gdbarch_remote_breakpoint_from_pc_ftype *remote_breakpoint_from_pc; +@@ -371,6 +372,7 @@ struct gdbarch startup_gdbarch = + default_return_in_first_hidden_param_p, /* return_in_first_hidden_param_p */ + 0, /* skip_prologue */ + 0, /* skip_main_prologue */ ++ 0, /* skip_entrypoint */ + 0, /* inner_than */ + 0, /* breakpoint_from_pc */ + default_remote_breakpoint_from_pc, /* remote_breakpoint_from_pc */ +@@ -672,6 +674,7 @@ verify_gdbarch (struct gdbarch *gdbarch) + if (gdbarch->skip_prologue == 0) + fprintf_unfiltered (log, "\n\tskip_prologue"); + /* Skip verify of skip_main_prologue, has predicate. */ ++ /* Skip verify of skip_entrypoint, has predicate. */ + if (gdbarch->inner_than == 0) + fprintf_unfiltered (log, "\n\tinner_than"); + if (gdbarch->breakpoint_from_pc == 0) +@@ -1285,6 +1288,12 @@ gdbarch_dump (struct gdbarch *gdbarch, s + "gdbarch_dump: single_step_through_delay = <%s>\n", + host_address_to_string (gdbarch->single_step_through_delay)); + fprintf_unfiltered (file, ++ "gdbarch_dump: gdbarch_skip_entrypoint_p() = %d\n", ++ gdbarch_skip_entrypoint_p (gdbarch)); ++ fprintf_unfiltered (file, ++ "gdbarch_dump: skip_entrypoint = <%s>\n", ++ host_address_to_string (gdbarch->skip_entrypoint)); ++ fprintf_unfiltered (file, + "gdbarch_dump: gdbarch_skip_main_prologue_p() = %d\n", + gdbarch_skip_main_prologue_p (gdbarch)); + fprintf_unfiltered (file, +@@ -2635,6 +2644,30 @@ set_gdbarch_skip_main_prologue (struct g + } + + int ++gdbarch_skip_entrypoint_p (struct gdbarch *gdbarch) ++{ ++ gdb_assert (gdbarch != NULL); ++ return gdbarch->skip_entrypoint != NULL; ++} ++ ++CORE_ADDR ++gdbarch_skip_entrypoint (struct gdbarch *gdbarch, CORE_ADDR ip) ++{ ++ gdb_assert (gdbarch != NULL); ++ gdb_assert (gdbarch->skip_entrypoint != NULL); ++ if (gdbarch_debug >= 2) ++ fprintf_unfiltered (gdb_stdlog, "gdbarch_skip_entrypoint called\n"); ++ return gdbarch->skip_entrypoint (gdbarch, ip); ++} ++ ++void ++set_gdbarch_skip_entrypoint (struct gdbarch *gdbarch, ++ gdbarch_skip_entrypoint_ftype skip_entrypoint) ++{ ++ gdbarch->skip_entrypoint = skip_entrypoint; ++} ++ ++int + gdbarch_inner_than (struct gdbarch *gdbarch, CORE_ADDR lhs, CORE_ADDR rhs) + { + gdb_assert (gdbarch != NULL); +Index: gdb-7.6.1/gdb/gdbarch.h +=================================================================== +--- gdb-7.6.1.orig/gdb/gdbarch.h ++++ gdb-7.6.1/gdb/gdbarch.h +@@ -487,6 +487,24 @@ typedef CORE_ADDR (gdbarch_skip_main_pro + extern CORE_ADDR gdbarch_skip_main_prologue (struct gdbarch *gdbarch, CORE_ADDR ip); + extern void set_gdbarch_skip_main_prologue (struct gdbarch *gdbarch, gdbarch_skip_main_prologue_ftype *skip_main_prologue); + ++/* On some platforms, a single function may provide multiple entry points, ++ e.g. one that is used for function-pointer calls and a different one ++ that is used for direct function calls. ++ In order to ensure that breakpoints set on the function will trigger ++ no matter via which entry point the function is entered, a platform ++ may provide the skip_entrypoint callback. It is called with IP set ++ to the main entry point of a function (as determined by the symbol table), ++ and should return the address of the innermost entry point, where the ++ actual breakpoint needs to be set. Note that skip_entrypoint is used ++ by GDB common code even when debugging optimized code, where skip_prologue ++ is not used. */ ++ ++extern int gdbarch_skip_entrypoint_p (struct gdbarch *gdbarch); ++ ++typedef CORE_ADDR (gdbarch_skip_entrypoint_ftype) (struct gdbarch *gdbarch, CORE_ADDR ip); ++extern CORE_ADDR gdbarch_skip_entrypoint (struct gdbarch *gdbarch, CORE_ADDR ip); ++extern void set_gdbarch_skip_entrypoint (struct gdbarch *gdbarch, gdbarch_skip_entrypoint_ftype *skip_entrypoint); ++ + typedef int (gdbarch_inner_than_ftype) (CORE_ADDR lhs, CORE_ADDR rhs); + extern int gdbarch_inner_than (struct gdbarch *gdbarch, CORE_ADDR lhs, CORE_ADDR rhs); + extern void set_gdbarch_inner_than (struct gdbarch *gdbarch, gdbarch_inner_than_ftype *inner_than); +Index: gdb-7.6.1/gdb/gdbarch.sh +=================================================================== +--- gdb-7.6.1.orig/gdb/gdbarch.sh ++++ gdb-7.6.1/gdb/gdbarch.sh +@@ -527,6 +527,19 @@ m:int:return_in_first_hidden_param_p:str + + m:CORE_ADDR:skip_prologue:CORE_ADDR ip:ip:0:0 + M:CORE_ADDR:skip_main_prologue:CORE_ADDR ip:ip ++# On some platforms, a single function may provide multiple entry points, ++# e.g. one that is used for function-pointer calls and a different one ++# that is used for direct function calls. ++# In order to ensure that breakpoints set on the function will trigger ++# no matter via which entry point the function is entered, a platform ++# may provide the skip_entrypoint callback. It is called with IP set ++# to the main entry point of a function (as determined by the symbol table), ++# and should return the address of the innermost entry point, where the ++# actual breakpoint needs to be set. Note that skip_entrypoint is used ++# by GDB common code even when debugging optimized code, where skip_prologue ++# is not used. ++M:CORE_ADDR:skip_entrypoint:CORE_ADDR ip:ip ++ + f:int:inner_than:CORE_ADDR lhs, CORE_ADDR rhs:lhs, rhs:0:0 + m:const gdb_byte *:breakpoint_from_pc:CORE_ADDR *pcptr, int *lenptr:pcptr, lenptr::0: + # Return the adjusted address and kind to use for Z0/Z1 packets. +Index: gdb-7.6.1/gdb/infrun.c +=================================================================== +--- gdb-7.6.1.orig/gdb/infrun.c ++++ gdb-7.6.1/gdb/infrun.c +@@ -3162,6 +3162,10 @@ fill_in_stop_func (struct gdbarch *gdbar + ecs->stop_func_start + += gdbarch_deprecated_function_start_offset (gdbarch); + ++ if (gdbarch_skip_entrypoint_p (gdbarch)) ++ ecs->stop_func_start = gdbarch_skip_entrypoint (gdbarch, ++ ecs->stop_func_start); ++ + ecs->stop_func_filled_in = 1; + } + } +Index: gdb-7.6.1/gdb/ppc-linux-tdep.c +=================================================================== +--- gdb-7.6.1.orig/gdb/ppc-linux-tdep.c ++++ gdb-7.6.1/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" +@@ -875,6 +876,55 @@ ppc_linux_core_read_description (struct + } + } + ++ ++/* 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 minimal_symbol *fun; ++ int local_entry_offset = 0; ++ ++ fun = lookup_minimal_symbol_by_pc (pc); ++ if (fun == 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)) ++ local_entry_offset = 8; ++ ++ if (SYMBOL_VALUE_ADDRESS (fun) <= pc ++ && pc < SYMBOL_VALUE_ADDRESS (fun) + local_entry_offset) ++ return SYMBOL_VALUE_ADDRESS (fun) + local_entry_offset; ++ ++ return pc; ++} ++ + /* Implementation of `gdbarch_stap_is_single_operand', as defined in + gdbarch.h. */ + +@@ -1341,6 +1391,13 @@ ppc_linux_init_abi (struct gdbarch_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); +Index: gdb-7.6.1/gdb/symtab.c +=================================================================== +--- gdb-7.6.1.orig/gdb/symtab.c ++++ gdb-7.6.1/gdb/symtab.c +@@ -2872,6 +2872,8 @@ skip_prologue_sal (struct symtab_and_lin + + /* Skip "first line" of function (which is actually its prologue). */ + pc += gdbarch_deprecated_function_start_offset (gdbarch); ++ if (gdbarch_skip_entrypoint_p (gdbarch)) ++ pc = gdbarch_skip_entrypoint (gdbarch, pc); + if (skip) + pc = gdbarch_skip_prologue (gdbarch, pc); + +Index: gdb-7.6.1/gdb/testsuite/gdb.base/sigbpt.exp +=================================================================== +--- gdb-7.6.1.orig/gdb/testsuite/gdb.base/sigbpt.exp ++++ gdb-7.6.1/gdb/testsuite/gdb.base/sigbpt.exp +@@ -82,7 +82,7 @@ gdb_test "break keeper" + set bowler_addrs bowler + set segv_addr none + gdb_test {display/i $pc} +-gdb_test "advance *bowler" "bowler.*" "advance to the bowler" ++gdb_test "advance bowler" "bowler.*" "advance to the bowler" + set test "stepping to fault" + set signame "SIGSEGV" + gdb_test_multiple "stepi" "$test" { +Index: gdb-7.6.1/gdb/testsuite/gdb.base/step-bt.c +=================================================================== +--- gdb-7.6.1.orig/gdb/testsuite/gdb.base/step-bt.c ++++ gdb-7.6.1/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/SOURCES/gdb-rhbz1125820-ppc64le-enablement-34of37.patch b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-34of37.patch new file mode 100644 index 0000000..7515fcd --- /dev/null +++ b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-34of37.patch @@ -0,0 +1,83 @@ +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. + +Index: gdb-7.6.1/gdb/testsuite/gdb.asm/asm-source.exp +=================================================================== +--- gdb-7.6.1.orig/gdb/testsuite/gdb.asm/asm-source.exp ++++ gdb-7.6.1/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 +Index: gdb-7.6.1/gdb/testsuite/gdb.asm/powerpc64le.inc +=================================================================== +--- /dev/null ++++ gdb-7.6.1/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/SOURCES/gdb-rhbz1125820-ppc64le-enablement-35of37.patch b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-35of37.patch new file mode 100644 index 0000000..426ae97 --- /dev/null +++ b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-35of37.patch @@ -0,0 +1,134 @@ +commit 397998fc32a34d3c8993ef46da45c3957a4dd402 +Author: Alan Modra +Date: Tue Jun 3 10:55:29 2014 +0930 + + Support fusion for ELFv2 stubs + + Power8 fuses addis,addi and addis,ld sequences when the target of the + addis is the same as the addi/ld. Thus + addis r12,r2,xxx@ha + addi r12,r12,xxx@l / ld r12,xxx@l(r12) + is faster than + addis r11,r2,xxx@ha + addi r12,r11,xxx@l / ld r12,xxx@l(r11) + So use the form that allows fusion in plt call and branch stubs. + + bfd/ + * elf64-ppc.c (ADDIS_R12_R2): Define. + (build_plt_stub): Support fusion on ELFv2 stub. + (ppc_build_one_stub): Likewise for plt branch stubs. + gold/ + * powerpc.cc (addis_12_2): Define. + (Stub_table::do_write): Support fusion on ELFv2 stubs. + ld/testsuite/ + * ld-powerpc/elfv2exe.d: Update for changed plt call stubs. + gdb/ + * ppc64-tdep.c (ppc64_standard_linkage8): New. + (ppc64_skip_trampoline_code): Recognise ELFv2 stub supporting fusion. + +Index: gdb-7.6.1/bfd/elf64-ppc.c +=================================================================== +--- gdb-7.6.1.orig/bfd/elf64-ppc.c ++++ gdb-7.6.1/bfd/elf64-ppc.c +@@ -175,6 +175,7 @@ static bfd_vma opd_entry_value + + #define LD_R2_0R1 0xe8410000 /* ld %r2,0(%r1) */ + ++#define ADDIS_R12_R2 0x3d820000 /* addis %r12,%r2,xxx@ha */ + #define ADDIS_R12_R12 0x3d8c0000 /* addis %r12,%r12,xxx@ha */ + #define LD_R12_0R12 0xe98c0000 /* ld %r12,xxx@l(%r12) */ + +@@ -9990,8 +9991,16 @@ build_plt_stub (struct ppc_link_hash_tab + if (ALWAYS_EMIT_R2SAVE + || stub_entry->stub_type == ppc_stub_plt_call_r2save) + bfd_put_32 (obfd, STD_R2_0R1 + STK_TOC (htab), p), p += 4; +- bfd_put_32 (obfd, ADDIS_R11_R2 | PPC_HA (offset), p), p += 4; +- bfd_put_32 (obfd, LD_R12_0R11 | PPC_LO (offset), p), p += 4; ++ if (plt_load_toc) ++ { ++ bfd_put_32 (obfd, ADDIS_R11_R2 | PPC_HA (offset), p), p += 4; ++ bfd_put_32 (obfd, LD_R12_0R11 | PPC_LO (offset), p), p += 4; ++ } ++ else ++ { ++ bfd_put_32 (obfd, ADDIS_R12_R2 | PPC_HA (offset), p), p += 4; ++ bfd_put_32 (obfd, LD_R12_0R12 | PPC_LO (offset), p), p += 4; ++ } + if (plt_load_toc + && PPC_HA (offset + 8 + 8 * plt_static_chain) != PPC_HA (offset)) + { +@@ -10410,9 +10419,9 @@ ppc_build_one_stub (struct bfd_hash_entr + if (PPC_HA (off) != 0) + { + size = 16; +- bfd_put_32 (htab->stub_bfd, ADDIS_R11_R2 | PPC_HA (off), loc); ++ bfd_put_32 (htab->stub_bfd, ADDIS_R12_R2 | PPC_HA (off), loc); + loc += 4; +- bfd_put_32 (htab->stub_bfd, LD_R12_0R11 | PPC_LO (off), loc); ++ bfd_put_32 (htab->stub_bfd, LD_R12_0R12 | PPC_LO (off), loc); + } + else + { +@@ -10436,9 +10445,9 @@ ppc_build_one_stub (struct bfd_hash_entr + if (PPC_HA (off) != 0) + { + size += 4; +- bfd_put_32 (htab->stub_bfd, ADDIS_R11_R2 | PPC_HA (off), loc); ++ bfd_put_32 (htab->stub_bfd, ADDIS_R12_R2 | PPC_HA (off), loc); + loc += 4; +- bfd_put_32 (htab->stub_bfd, LD_R12_0R11 | PPC_LO (off), loc); ++ bfd_put_32 (htab->stub_bfd, LD_R12_0R12 | PPC_LO (off), loc); + } + else + bfd_put_32 (htab->stub_bfd, LD_R12_0R2 | PPC_LO (off), loc); +Index: gdb-7.6.1/gdb/ppc64-tdep.c +=================================================================== +--- gdb-7.6.1.orig/gdb/ppc64-tdep.c ++++ gdb-7.6.1/gdb/ppc64-tdep.c +@@ -303,6 +303,29 @@ static struct ppc_insn_pattern ppc64_sta + { 0, 0, 0 } + }; + ++/* ELFv2 PLT call stub to access PLT entries more than +/- 32k from r2, ++ supporting fusion. */ ++ ++static struct ppc_insn_pattern ppc64_standard_linkage8[] = ++ { ++ /* std r2, 24(r1) */ ++ { -1, insn_ds (62, 2, 1, 24, 0), 1 }, ++ ++ /* addis r12, r2, */ ++ { insn_d (-1, -1, -1, 0), insn_d (15, 12, 2, 0), 0 }, ++ ++ /* ld r12, (r12) */ ++ { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 12, 12, 0, 0), 0 }, ++ ++ /* mtctr r12 */ ++ { insn_xfx (-1, -1, -1, -1), insn_xfx (31, 12, 9, 467), 0 }, ++ ++ /* bctr */ ++ { -1, 0x4e800420, 0 }, ++ ++ { 0, 0, 0 } ++ }; ++ + /* When the dynamic linker is doing lazy symbol resolution, the first + call to a function in another object will go like this: + +@@ -437,10 +460,14 @@ ppc64_skip_trampoline_code (struct frame + ARRAY_SIZE (ppc64_standard_linkage4))), + MAX (MAX (ARRAY_SIZE (ppc64_standard_linkage5), + ARRAY_SIZE (ppc64_standard_linkage6)), +- ARRAY_SIZE (ppc64_standard_linkage7))) - 1]; ++ MAX (ARRAY_SIZE (ppc64_standard_linkage7), ++ ARRAY_SIZE (ppc64_standard_linkage8)))) ++ - 1]; + CORE_ADDR target; + +- if (ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage7, insns)) ++ if (ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage8, insns)) ++ pc = ppc64_standard_linkage4_target (frame, pc, insns); ++ else if (ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage7, insns)) + pc = ppc64_standard_linkage3_target (frame, pc, insns); + else if (ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage6, insns)) + pc = ppc64_standard_linkage4_target (frame, pc, insns); diff --git a/SOURCES/gdb-rhbz1125820-ppc64le-enablement-36of37.patch b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-36of37.patch new file mode 100644 index 0000000..b1fe2a0 --- /dev/null +++ b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-36of37.patch @@ -0,0 +1,86 @@ +https://sourceware.org/ml/gdb-patches/2014-09/msg00156.html +Message-Id: <1409947102-32166-1-git-send-email-emachado@linux.vnet.ibm.com> + +commit 2e4bb98a0e52acbb2da4ae441b89a568af26adf8 +Author: Edjunior Barbosa Machado +Date: Mon Sep 8 13:37:23 2014 -0300 + + Fix ppc_collect/supply_ptrace_register() routines + + This patch fixes the routines to collect and supply ptrace registers on ppc64le + gdbserver. Originally written for big endian arch, they were causing several + issues on little endian. With this fix, the number of unexpected failures in + the testsuite dropped from 263 to 72 on ppc64le. + + gdb/gdbserver/ChangeLog + + * linux-ppc-low.c (ppc_collect_ptrace_register): Adjust routine to take + endianness into account. + (ppc_supply_ptrace_register): Likewise. + +Index: gdb-7.6.1/gdb/gdbserver/linux-ppc-low.c +=================================================================== +--- gdb-7.6.1.orig/gdb/gdbserver/linux-ppc-low.c ++++ gdb-7.6.1/gdb/gdbserver/linux-ppc-low.c +@@ -170,25 +170,52 @@ ppc_cannot_fetch_register (int regno) + static void + ppc_collect_ptrace_register (struct regcache *regcache, int regno, char *buf) + { +- int size = register_size (regno); +- + memset (buf, 0, sizeof (long)); + +- if (size < sizeof (long)) +- collect_register (regcache, regno, buf + sizeof (long) - size); ++ if (__BYTE_ORDER == __LITTLE_ENDIAN) ++ { ++ /* Little-endian values always sit at the left end of the buffer. */ ++ collect_register (regcache, regno, buf); ++ } ++ else if (__BYTE_ORDER == __BIG_ENDIAN) ++ { ++ /* Big-endian values sit at the right end of the buffer. In case of ++ registers whose sizes are smaller than sizeof (long), we must use a ++ padding to access them correctly. */ ++ int size = register_size (regno); ++ ++ if (size < sizeof (long)) ++ collect_register (regcache, regno, buf + sizeof (long) - size); ++ else ++ collect_register (regcache, regno, buf); ++ } + else +- collect_register (regcache, regno, buf); ++ perror_with_name ("Unexpected byte order"); + } + + static void + ppc_supply_ptrace_register (struct regcache *regcache, + int regno, const char *buf) + { +- int size = register_size (regno); +- if (size < sizeof (long)) +- supply_register (regcache, regno, buf + sizeof (long) - size); ++ if (__BYTE_ORDER == __LITTLE_ENDIAN) ++ { ++ /* Little-endian values always sit at the left end of the buffer. */ ++ supply_register (regcache, regno, buf); ++ } ++ else if (__BYTE_ORDER == __BIG_ENDIAN) ++ { ++ /* Big-endian values sit at the right end of the buffer. In case of ++ registers whose sizes are smaller than sizeof (long), we must use a ++ padding to access them correctly. */ ++ int size = register_size (regno); ++ ++ if (size < sizeof (long)) ++ supply_register (regcache, regno, buf + sizeof (long) - size); ++ else ++ supply_register (regcache, regno, buf); ++ } + else +- supply_register (regcache, regno, buf); ++ perror_with_name ("Unexpected byte order"); + } + + diff --git a/SOURCES/gdb-rhbz1125820-ppc64le-enablement-37of37.patch b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-37of37.patch new file mode 100644 index 0000000..cda4549 --- /dev/null +++ b/SOURCES/gdb-rhbz1125820-ppc64le-enablement-37of37.patch @@ -0,0 +1,127 @@ + + Message-Id: <1410525085-29172-1-git-send-email-emachado@linux.vnet.ibm.com> + +commit 9d9bf2df89db515958b429a1aeb1db38884ba488 +Author: Edjunior Barbosa Machado +Date: Fri Sep 12 09:20:25 2014 -0300 + + PR tdep/17379: Fix internal-error when stack pointer is invalid. + + The problem is that rs6000_frame_cache attempts to read the stack backchain via + read_memory_unsigned_integer, which throws an exception if the stack pointer is + invalid. With this patch, it calls safe_read_memory_integer instead, which + doesn't throw an exception and allows for safe handling of that situation. + + gdb/ChangeLog + 2014-09-12 Edjunior Barbosa Machado + Ulrich Weigand  + + PR tdep/17379 + * rs6000-tdep.c (rs6000_frame_cache): Use safe_read_memory_integer + instead of read_memory_unsigned_integer. + + gdb/testcase/ChangeLog + 2014-09-12 Edjunior Barbosa Machado + + PR tdep/17379 + * gdb.arch/powerpc-stackless.S: New file. + * gdb.arch/powerpc-stackless.exp: New file. + +Index: gdb-7.6.1/gdb/rs6000-tdep.c +=================================================================== +--- gdb-7.6.1.orig/gdb/rs6000-tdep.c ++++ gdb-7.6.1/gdb/rs6000-tdep.c +@@ -3241,9 +3241,14 @@ rs6000_frame_cache (struct frame_info *t + } + + if (!fdata.frameless) +- /* Frameless really means stackless. */ +- cache->base +- = read_memory_unsigned_integer (cache->base, wordsize, byte_order); ++ { ++ /* Frameless really means stackless. */ ++ LONGEST backchain; ++ ++ if (safe_read_memory_integer (cache->base, wordsize, ++ byte_order, &backchain)) ++ cache->base = (CORE_ADDR) backchain; ++ } + + trad_frame_set_value (cache->saved_regs, + gdbarch_sp_regnum (gdbarch), cache->base); +Index: gdb-7.6.1/gdb/testsuite/gdb.arch/powerpc-stackless.S +=================================================================== +--- /dev/null ++++ gdb-7.6.1/gdb/testsuite/gdb.arch/powerpc-stackless.S +@@ -0,0 +1,24 @@ ++/* This testcase is part of GDB, the GNU debugger. ++ ++ Copyright 2014 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . */ ++ ++#include ++ ++FUNC_START(main) ++ li sp,0 ++ mtlr sp ++ blr ++FUNC_END(main) +Index: gdb-7.6.1/gdb/testsuite/gdb.arch/powerpc-stackless.exp +=================================================================== +--- /dev/null ++++ gdb-7.6.1/gdb/testsuite/gdb.arch/powerpc-stackless.exp +@@ -0,0 +1,42 @@ ++# Copyright 2014 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++# Testcase for PR tdep/17379. ++ ++if {![istarget "powerpc*-*-*"]} then { ++ verbose "Skipping powerpc-stackless.exp" ++ return ++} ++ ++standard_testfile .S ++ ++if { [prepare_for_testing $testfile.exp $testfile $srcfile] } { ++ untested powerpc-stackless.exp ++ return -1 ++} ++ ++# Run until SIGSEGV. ++gdb_run_cmd ++ ++set test "run until SIGSEGV" ++gdb_test_multiple "" $test { ++ -re "Program received signal SIGSEGV.*$gdb_prompt $" { ++ pass $test ++ } ++} ++ ++# Ensure that 'info registers' works properly and does not generate ++# an internal-error. ++gdb_test "info registers" "r0.*" "info registers" diff --git a/SOURCES/gdb-rhbz1163339-add-auto-load-scripts-directory.patch b/SOURCES/gdb-rhbz1163339-add-auto-load-scripts-directory.patch new file mode 100644 index 0000000..bcf8bcc --- /dev/null +++ b/SOURCES/gdb-rhbz1163339-add-auto-load-scripts-directory.patch @@ -0,0 +1,136 @@ +Date: Thu, 13 Nov 2014 16:26:37 +0100 +From: Jan Kratochvil +To: gdb-patches at sourceware dot org +Cc: Jakub Filak +Subject: [patch] Add add-auto-load-scripts-directory + +--jho1yZJdad60DJr+ +Content-Type: text/plain; charset=us-ascii +Content-Disposition: inline + +Hi, + +there is already "add-auto-load-safe-path" which works +like "set auto-load safe-path" but in append mode. + +There was missing an append equivalent for "set auto-load scripts-directory". + +ABRT has directory /var/cache/abrt-di/ as an alternative one +to /usr/lib/debug/ . Therefore ABRT needs to use -iex parameters to add this +/var/cache/abrt-di/ directory as a first-class debuginfo directory. +Using absolute "set auto-load scripts-directory" would hard-code the path +possibly overriding local system directory additions; besides it would not be +nice anyway. + +No regressions on {x86_64,x86_64-m32,i686}-fedora21-linux-gnu; although I have +seen some heavy regressions there today unrelated to this patch. + + +Thanks, +Jan + +--jho1yZJdad60DJr+ +Content-Type: text/plain; charset=us-ascii +Content-Disposition: inline; filename="addautoload.patch" + +gdb/ +2014-11-13 Jan Kratochvil + + Add add-auto-load-scripts-directory. + * NEWS (Changes since GDB 7.8): Add add-auto-load-scripts-directory. + * auto-load.c (add_auto_load_dir): New function. + (_initialize_auto_load): Install it. + +gdb/doc/ +2014-11-13 Jan Kratochvil + + Add add-auto-load-scripts-directory. + * gdb.texinfo (Auto-loading): Add add-auto-load-scripts-directory link. + (objfile-gdbdotext file): Add add-auto-load-scripts-directory. + +Index: gdb-7.6.1/gdb/NEWS +=================================================================== +--- gdb-7.6.1.orig/gdb/NEWS ++++ gdb-7.6.1/gdb/NEWS +@@ -1,6 +1,12 @@ + What has changed in GDB? + (Organized release by release) + ++* New commands: ++ ++add-auto-load-scripts-directory directory ++ Add entries to the list of directories from which to load auto-loaded ++ scripts. ++ + * Newly installed $prefix/bin/gcore acts as a shell interface for the + GDB command gcore. + +Index: gdb-7.6.1/gdb/auto-load.c +=================================================================== +--- gdb-7.6.1.orig/gdb/auto-load.c ++++ gdb-7.6.1/gdb/auto-load.c +@@ -298,6 +298,22 @@ Use 'set auto-load safe-path /' for disa + auto_load_safe_path_vec_update (); + } + ++/* "add-auto-load-scripts-directory" command for the auto_load_dir configuration ++ variable. */ ++ ++static void ++add_auto_load_dir (char *args, int from_tty) ++{ ++ char *s; ++ ++ if (args == NULL || *args == 0) ++ error (_("Directory argument required.")); ++ ++ s = xstrprintf ("%s%c%s", auto_load_dir, DIRNAME_SEPARATOR, args); ++ xfree (auto_load_dir); ++ auto_load_dir = s; ++} ++ + /* Implementation for filename_is_in_pattern overwriting the caller's FILENAME + and PATTERN. */ + +@@ -1295,6 +1311,15 @@ access the current full list setting."), + &cmdlist); + set_cmd_completer (cmd, filename_completer); + ++ cmd = add_cmd ("add-auto-load-scripts-directory", class_support, ++ add_auto_load_dir, ++ _("Add entries to the list of directories from which to load " ++ "auto-loaded scripts.\n\ ++See the commands 'set auto-load scripts-directory' and\n\ ++'show auto-load scripts-directory' to access the current full list setting."), ++ &cmdlist); ++ set_cmd_completer (cmd, filename_completer); ++ + add_setshow_boolean_cmd ("auto-load", class_maintenance, + &debug_auto_load, _("\ + Set auto-load verifications debugging."), _("\ +Index: gdb-7.6.1/gdb/doc/gdb.texinfo +=================================================================== +--- gdb-7.6.1.orig/gdb/doc/gdb.texinfo ++++ gdb-7.6.1/gdb/doc/gdb.texinfo +@@ -21929,6 +21929,8 @@ These are @value{GDBN} control commands + @tab Control for @value{GDBN} auto-loaded scripts location. + @item @xref{show auto-load scripts-directory}. + @tab Show @value{GDBN} auto-loaded scripts location. ++@item @xref{add-auto-load-scripts-directory}. ++@tab Add directory for auto-loaded scripts location list. + @item @xref{set auto-load local-gdbinit}. + @tab Control for init file in the current directory. + @item @xref{show auto-load local-gdbinit}. +@@ -27213,6 +27215,12 @@ to the @env{PATH} environment variable. + @kindex show auto-load scripts-directory + @item show auto-load scripts-directory + Show @value{GDBN} auto-loaded scripts location. ++ ++@anchor{add-auto-load-scripts-directory} ++@kindex add-auto-load-scripts-directory ++@item add-auto-load-scripts-directory @r{[}@var{directories}@r{]} ++Add an entry (or list of entries) to the list of auto-loaded scripts locations. ++Multiple entries may be delimited by the host platform path separator in use. + @end table + + @value{GDBN} does not track which files it has already auto-loaded this way. diff --git a/SOURCES/gdb-rhbz809179-global-variable-nested-dso.patch b/SOURCES/gdb-rhbz809179-global-variable-nested-dso.patch new file mode 100644 index 0000000..581f3d3 --- /dev/null +++ b/SOURCES/gdb-rhbz809179-global-variable-nested-dso.patch @@ -0,0 +1,225 @@ +This bug is already fixed in the RHEL-7.1 GDB version. However, it is +also important to add a testcase, so the following is a patch to add +this test. + +This is the original message submitted to gdb-patches: + + From: Sergio Durigan Junior + To: GDB Patches + Subject: [PATCH] Add test for global variable that is nested by another DSO + Date: Thu, 4 Sep 2014 17:32:53 -0400 + Message-Id: <1409866373-16413-1-git-send-email-sergiodj@redhat.com> + + This is just a testcase addition that I am proposing for upstream GDB. + We have this in our internal tree, and the related RH bug is: + + + + (You might not be able to see all the comments without privileges.) + + This bug is about a global variable that got incorrectly displayed by + GDB. This bug has already been fixed a long time ago by Joel's + commit: + + commit 19630284f570790ebf6d50bfb43caa1f125ee88a + Author: Joel Brobecker + Date: Tue Jun 5 13:50:50 2012 +0000 + + But I think a testcase for it wouldn't hurt. + + So, consider the following scenario: + + $ cat solib1.c + int test; + void c_main (void) + { + test = 42; + } + + $ cat solib2.c + int test; + void b_main (void) + { + test = 42; + } + + $ cat main.c + int main (int argc, char *argv[]) + { + c_main (); + b_main (); + return 0; + } + + $ gcc -g -fPIC -shared -o libSO1.so -c solib1.c + $ gcc -g -fPIC -shared -o libSO2.so -c solib2.c + $ gcc -g -o main -L$PWD -lSO1 -lSO2 main.c + $ LD_LIBRARY_PATH=. gdb -q -batch -ex 'b c_main' -ex r -ex n -ex 'p test' ./main + ... + $1 = 0 + + This happened with GDB before Joel's commit above. Now, things work + and GDB is able to correctly display the nested global variable: + + $ LD_LIBRARY_PATH=. gdb -q -batch -ex 'b c_main' -ex r -ex n -ex 'p test' ./main + ... + $1 = 42 + + The testcase attached tests this behavior. + + gdb/testsuite/ChangeLog: + 2014-09-04 Sergio Durigan Junior + + * gdb.base/global-var-nested-by-dso-solib1.c: New file. + * gdb.base/global-var-nested-by-dso-solib2.c: Likewise. + * gdb.base/global-var-nested-by-dso.c: Likewise. + * gdb.base/global-var-nested-by-dso.exp: Likewise. + + +Index: gdb-7.6.1/gdb/testsuite/gdb.base/global-var-nested-by-dso-solib1.c +=================================================================== +--- /dev/null ++++ gdb-7.6.1/gdb/testsuite/gdb.base/global-var-nested-by-dso-solib1.c +@@ -0,0 +1,24 @@ ++/* Copyright 2014 Free Software Foundation, Inc. ++ ++ This file is part of GDB. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . */ ++ ++int test; ++ ++void ++c_main (void) ++{ ++ test = 42; ++} +Index: gdb-7.6.1/gdb/testsuite/gdb.base/global-var-nested-by-dso-solib2.c +=================================================================== +--- /dev/null ++++ gdb-7.6.1/gdb/testsuite/gdb.base/global-var-nested-by-dso-solib2.c +@@ -0,0 +1,24 @@ ++/* Copyright 2014 Free Software Foundation, Inc. ++ ++ This file is part of GDB. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . */ ++ ++int test; ++ ++void ++b_main (void) ++{ ++ test = 42; ++} +Index: gdb-7.6.1/gdb/testsuite/gdb.base/global-var-nested-by-dso.c +=================================================================== +--- /dev/null ++++ gdb-7.6.1/gdb/testsuite/gdb.base/global-var-nested-by-dso.c +@@ -0,0 +1,24 @@ ++/* Copyright 2014 Free Software Foundation, Inc. ++ ++ This file is part of GDB. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . */ ++ ++int ++main (int argc, char *argv[]) ++{ ++ c_main (); ++ b_main (); ++ return 0; ++} +Index: gdb-7.6.1/gdb/testsuite/gdb.base/global-var-nested-by-dso.exp +=================================================================== +--- /dev/null ++++ gdb-7.6.1/gdb/testsuite/gdb.base/global-var-nested-by-dso.exp +@@ -0,0 +1,55 @@ ++# Copyright 2014 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++if { [skip_shlib_tests] } { ++ return 0 ++} ++ ++standard_testfile ++ ++set lib1name $testfile-solib1 ++set srcfile_lib1 $srcdir/$subdir/$lib1name.c ++set binfile_lib1 [standard_output_file $lib1name.so] ++ ++set lib2name $testfile-solib2 ++set srcfile_lib2 $srcdir/$subdir/$lib2name.c ++set binfile_lib2 [standard_output_file $lib2name.so] ++ ++if { [gdb_compile_shlib $srcfile_lib1 $binfile_lib1 \ ++ [list debug additional_flags=-fPIC]] != "" } { ++ untested "Could not compile $binfile_lib1." ++ return -1 ++} ++ ++if { [gdb_compile_shlib $srcfile_lib2 $binfile_lib2 \ ++ [list debug additional_flags=-fPIC]] != "" } { ++ untested "Could not compile $binfile_lib2." ++ return -1 ++} ++ ++if { [gdb_compile $srcdir/$subdir/$srcfile $binfile executable \ ++ [list debug shlib=$binfile_lib1 shlib=$binfile_lib2]] != "" } { ++ return -1 ++} ++ ++clean_restart $binfile ++ ++if { ![runto_main] } { ++ return -1 ++} ++ ++gdb_test "next" "$decimal.*b_main \\(\\);" ++gdb_test "next" "$decimal.*return 0;" ++gdb_test "print test" " = 42" diff --git a/SPECS/gdb.spec b/SPECS/gdb.spec index 7d9c2d8..c918ee4 100644 --- a/SPECS/gdb.spec +++ b/SPECS/gdb.spec @@ -37,7 +37,7 @@ Version: 7.6.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: 51%{?dist} +Release: 64%{?dist} License: GPLv3+ and GPLv3+ with exceptions and GPLv2+ and GPLv2+ with exceptions and GPL+ and LGPLv2+ and BSD and Public Domain Group: Development/Debuggers @@ -600,6 +600,72 @@ Patch850: gdb-gnat-dwarf-crash-1of3.patch Patch851: gdb-gnat-dwarf-crash-2of3.patch Patch852: gdb-gnat-dwarf-crash-3of3.patch +# Port GDB to PPC64LE (ELFv2) (RH BZ 1125820). +# Work mostly done by Ulrich Weigand and Alan Modra, from IBM. +Patch928: gdb-rhbz1125820-ppc64le-enablement-01of37.patch +Patch929: gdb-rhbz1125820-ppc64le-enablement-02of37.patch +Patch930: gdb-rhbz1125820-ppc64le-enablement-03of37.patch +Patch931: gdb-rhbz1125820-ppc64le-enablement-04of37.patch +Patch932: gdb-rhbz1125820-ppc64le-enablement-05of37.patch +Patch933: gdb-rhbz1125820-ppc64le-enablement-06of37.patch +Patch934: gdb-rhbz1125820-ppc64le-enablement-07of37.patch +Patch935: gdb-rhbz1125820-ppc64le-enablement-08of37.patch +Patch936: gdb-rhbz1125820-ppc64le-enablement-09of37.patch +Patch937: gdb-rhbz1125820-ppc64le-enablement-10of37.patch +Patch938: gdb-rhbz1125820-ppc64le-enablement-11of37.patch +Patch939: gdb-rhbz1125820-ppc64le-enablement-12of37.patch +Patch940: gdb-rhbz1125820-ppc64le-enablement-13of37.patch +Patch941: gdb-rhbz1125820-ppc64le-enablement-14of37.patch +Patch942: gdb-rhbz1125820-ppc64le-enablement-15of37.patch +Patch943: gdb-rhbz1125820-ppc64le-enablement-16of37.patch +Patch944: gdb-rhbz1125820-ppc64le-enablement-17of37.patch +Patch945: gdb-rhbz1125820-ppc64le-enablement-18of37.patch +Patch946: gdb-rhbz1125820-ppc64le-enablement-19of37.patch +Patch947: gdb-rhbz1125820-ppc64le-enablement-20of37.patch +Patch948: gdb-rhbz1125820-ppc64le-enablement-21of37.patch +Patch949: gdb-rhbz1125820-ppc64le-enablement-22of37.patch +Patch950: gdb-rhbz1125820-ppc64le-enablement-23of37.patch +Patch951: gdb-rhbz1125820-ppc64le-enablement-24of37.patch +Patch952: gdb-rhbz1125820-ppc64le-enablement-25of37.patch +Patch953: gdb-rhbz1125820-ppc64le-enablement-26of37.patch +Patch954: gdb-rhbz1125820-ppc64le-enablement-27of37.patch +Patch955: gdb-rhbz1125820-ppc64le-enablement-28of37.patch +Patch956: gdb-rhbz1125820-ppc64le-enablement-29of37.patch +Patch957: gdb-rhbz1125820-ppc64le-enablement-30of37.patch +Patch958: gdb-rhbz1125820-ppc64le-enablement-31of37.patch +Patch959: gdb-rhbz1125820-ppc64le-enablement-32of37.patch +Patch960: gdb-rhbz1125820-ppc64le-enablement-33of37.patch +Patch961: gdb-rhbz1125820-ppc64le-enablement-34of37.patch +Patch962: gdb-rhbz1125820-ppc64le-enablement-35of37.patch +Patch969: gdb-rhbz1125820-ppc64le-enablement-36of37.patch +Patch974: gdb-rhbz1125820-ppc64le-enablement-37of37.patch + +# Fix 'incomplete backtraces from core dumps from crash in signal +# handler' (RH BZ 1086894). +Patch963: gdb-rhbz1086894-incomplete-bt-coredump-signal-handler.patch + +# Fix 'gdb for aarch64 needs the ability to single step through atomic +# sequences' (RH BZ 1093259, Kyle McMartin). +Patch964: gdb-rhbz1093259-aarch64-single-step-atomic-seq.patch + +# Fix '[RHEL7] Can't access TLS variables in statically linked +# binaries' (RH BZ 1080657, Jan Kratochvil). +Patch965: gdb-rhbz1080657-tls-variable-static-linked-binary-1of3.patch +Patch966: gdb-rhbz1080657-tls-variable-static-linked-binary-2of3.patch +Patch967: gdb-rhbz1080657-tls-variable-static-linked-binary-3of3.patch + +# Include testcase for 'Global variable nested by another dso shows up +# incorrectly in gdb' (RH BZ 809179). The fix for this bug is already +# included in the RHEL-7.1 GDB. +Patch968: gdb-rhbz809179-global-variable-nested-dso.patch + +# Fix 'Slow gstack performance' (RH BZ 1103894, Jan Kratochvil). +Patch972: gdb-rhbz1103894-slow-gstack-performance.patch + +# Fix '[RFE] please add add-auto-load-scripts-directory command' (RH +# BZ 1163339, Jan Kratochvil). +Patch976: gdb-rhbz1163339-add-auto-load-scripts-directory.patch + %if 0%{!?rhel:1} || 0%{?rhel} > 6 # RL_STATE_FEDORA_GDB would not be found for: # Patch642: gdb-readline62-ask-more-rh.patch @@ -933,6 +999,51 @@ find -name "*.info*"|xargs rm -f %patch850 -p1 %patch851 -p1 %patch852 -p1 +%patch928 -p1 +%patch929 -p1 +%patch930 -p1 +%patch931 -p1 +%patch932 -p1 +%patch933 -p1 +%patch934 -p1 +%patch935 -p1 +%patch936 -p1 +%patch937 -p1 +%patch938 -p1 +%patch939 -p1 +%patch940 -p1 +%patch941 -p1 +%patch942 -p1 +%patch943 -p1 +%patch944 -p1 +%patch945 -p1 +%patch946 -p1 +%patch947 -p1 +%patch948 -p1 +%patch949 -p1 +%patch950 -p1 +%patch951 -p1 +%patch952 -p1 +%patch953 -p1 +%patch954 -p1 +%patch955 -p1 +%patch956 -p1 +%patch957 -p1 +%patch958 -p1 +%patch959 -p1 +%patch960 -p1 +%patch961 -p1 +%patch962 -p1 +%patch969 -p1 +%patch974 -p1 +%patch963 -p1 +%patch964 -p1 +%patch965 -p1 +%patch966 -p1 +%patch967 -p1 +%patch968 -p1 +%patch972 -p1 +%patch976 -p1 %patch836 -p1 %patch837 -p1 @@ -1018,7 +1129,7 @@ export LDFLAGS="%{?__global_ldflags}" --with-system-gdbinit=%{_sysconfdir}/gdbinit \ --with-gdb-datadir=%{_datadir}/gdb \ --enable-gdb-build-warnings=,-Wno-unused \ -%ifnarch %{ix86} alpha ia64 ppc s390 s390x x86_64 ppc64 sparc sparcv9 sparc64 +%ifnarch %{ix86} alpha ia64 ppc s390 s390x x86_64 ppc64 ppc64le sparc sparcv9 sparc64 --disable-werror \ %else --enable-werror \ @@ -1080,7 +1191,7 @@ $(: It breaks RHEL-5 by %{_target_platform} being noarch-redhat-linux-gnu ) \ %ifarch noarch $(:) %else - --enable-targets=s390-linux-gnu,powerpc-linux-gnu \ + --enable-targets=s390-linux-gnu,powerpc-linux-gnu,powerpcle-linux-gnu \ %{_target_platform} %endif %endif @@ -1462,6 +1573,59 @@ fi %endif # 0%{!?el5:1} || "%{_target_cpu}" == "noarch" %changelog +* Sat Nov 22 2014 Jan Kratochvil - 7.6.1-64.el7 +- Fix '[FJ7.0 Bug]: gdb: fail to refer to errno on a core dump file' + (RH BZ 1166549, Jan Kratochvil). + +* Fri Nov 14 2014 Sergio Durigan Junior - 7.6.1-63.el7 +- Fix '[RFE] please add add-auto-load-scripts-directory command' (RH + BZ 1163339, Jan Kratochvil). + +* Wed Oct 15 2014 Sergio Durigan Junior - 7.6.1-62.el7 +- Include patch to fix internal-error when stack pointer is invalid + (RH BZ 1125820, Edjunior Barbosa Machado). Rename PPC64LE patches + to reflect the addition of the patch. + +* Fri Oct 03 2014 Sergio Durigan Junior - 7.6.1-61.el7 +- Fix 'Slow gstack performance' (RH BZ 1103894, Jan Kratochvil). + +* Tue Sep 30 2014 Sergio Durigan Junior - 7.6.1-60.el7 +- Adjust gdb-add-index script to work with binaries in the CWD (RH BZ + 1104029). + +* Mon Sep 08 2014 Sergio Durigan Junior - 7.6.1-59.el7 +- Adjust previous patch to build on GDB 7.6.1, where we do not have + multi-arch + multi-target on GDBserver yet (RH BZ 1125820). + +* Mon Sep 08 2014 Sergio Durigan Junior - 7.6.1-58.el7 +- Include patch to fix ppc_collect/supply_ptrace_register GDBserver + functions, related to PPC64LE support (RH BZ 1125820, Edjunior + Barbosa Machado). Rename PPC64LE patches to reflect the addition of + the patch. + +* Fri Sep 05 2014 Sergio Durigan Junior - 7.6.1-57.el7 +- Include testcase for 'Global variable nested by another dso shows up + incorrectly in gdb' (RH BZ 809179). The fix for this bug is already + included in the RHEL-7.1 GDB. + +* Wed Aug 27 2014 Sergio Durigan Junior - 7.6.1-56.el7 +- Fix '[RHEL7] Can't access TLS variables in statically linked + binaries' (RH BZ 1080657, Jan Kratochvil). + +* Fri Aug 22 2014 Sergio Durigan Junior - 7.6.1-55.el7 +- Fix 'gdb for aarch64 needs the ability to single step through atomic + sequences' (RH BZ 1093259, Kyle McMartin). + +* Thu Aug 21 2014 Sergio Durigan Junior - 7.6.1-54.el7 +- Make sure the testcase from the last fix only runs on AArch64. + +* Thu Aug 21 2014 Sergio Durigan Junior - 7.6.1-53.el7 +- Fix 'incomplete backtraces from core dumps from crash in signal + handler' (RH BZ 1086894, Hui Zhu and Yao Qi). + +* Mon Aug 18 2014 Sergio Durigan Junior - 7.6.1-52.el7 +- Port PPC64LE to RHEL-7.1 GDB (RH BZ 1125820, Ulrich Weigand and Alan Modra) + * Mon Feb 24 2014 Jan Kratochvil - 7.6.1-51.el7 - Merge from Fedora 19.