This is the mail archive of the gdb-cvs@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[binutils-gdb] Pass HWCAP to ifunc resolver


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=e1b2624a08fae1f669d879946d5041945b4dc248

commit e1b2624a08fae1f669d879946d5041945b4dc248
Author: Andreas Arnez <arnez@linux.vnet.ibm.com>
Date:   Fri Sep 9 19:59:53 2016 +0200

    Pass HWCAP to ifunc resolver
    
    On various GNU Elf architectures, including AArch64, ARM, s390/s390x,
    ppc32/64, and sparc32/64, the dynamic loader passes HWCAP as a parameter
    to each ifunc resolver.  Currently there is an open glibc Bugzilla that
    requests this to be generalized to all architectures:
    
      https://sourceware.org/bugzilla/show_bug.cgi?id=19766
    
    And various ifunc resolvers already rely on receiving HWCAP.  Currently
    GDB always calls an ifunc resolver without any arguments; thus the
    resolver may receive garbage, and based on that, the resolver may decide
    to return a function that is not suited for the given platform.
    
    This patch always passes HWCAP to ifunc resolvers, even on systems where
    the dynamic loader currently behaves otherwise.  The rationale is
    that (1) the dynamic loader may get adjusted on those systems as well in
    the future; (2) passing an unused argument should not cause a problem
    with existing resolvers; and (3) the logic is much simpler without such
    a distinction.
    
    gdb/ChangeLog:
    
    	* elfread.c (auxv.h): New include.
    	(elf_gnu_ifunc_resolve_addr): Pass HWCAP to ifunc resolver.
    
    gdb/testsuite/ChangeLog:
    
    	* gdb.base/gnu-ifunc-lib.c (resolver_hwcap): New external
    	variable declaration.
    	(gnu_ifunc): Add parameter hwcap.  Store it in resolver_hwcap.
    	* gdb.base/gnu-ifunc.c (resolver_hwcap): New global variable.
    	* gdb.base/gnu-ifunc.exp: Add test to verify that the resolver
    	received HWCAP as its argument.

Diff:
---
 gdb/ChangeLog                          |  5 +++++
 gdb/elfread.c                          | 13 ++++++++++---
 gdb/testsuite/ChangeLog                |  9 +++++++++
 gdb/testsuite/gdb.base/gnu-ifunc-lib.c |  4 +++-
 gdb/testsuite/gdb.base/gnu-ifunc.c     |  4 ++++
 gdb/testsuite/gdb.base/gnu-ifunc.exp   | 15 +++++++++++++++
 6 files changed, 46 insertions(+), 4 deletions(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index e7cc712..b585914 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,8 @@
+2016-09-09  Andreas Arnez  <arnez@linux.vnet.ibm.com>
+
+	* elfread.c (auxv.h): New include.
+	(elf_gnu_ifunc_resolve_addr): Pass HWCAP to ifunc resolver.
+
 2016-09-08  Tom Tromey  <tom@tromey.com>
 
 	* remote.c (remote_notif_stop_ack, remote_wait_as)
diff --git a/gdb/elfread.c b/gdb/elfread.c
index e90466b..84355cf 100644
--- a/gdb/elfread.c
+++ b/gdb/elfread.c
@@ -46,6 +46,7 @@
 #include "gdb_bfd.h"
 #include "build-id.h"
 #include "location.h"
+#include "auxv.h"
 
 extern void _initialize_elfread (void);
 
@@ -860,6 +861,8 @@ elf_gnu_ifunc_resolve_addr (struct gdbarch *gdbarch, CORE_ADDR pc)
   CORE_ADDR start_at_pc, address;
   struct type *func_func_type = builtin_type (gdbarch)->builtin_func_func;
   struct value *function, *address_val;
+  CORE_ADDR hwcap = 0;
+  struct value *hwcap_val;
 
   /* Try first any non-intrusive methods without an inferior call.  */
 
@@ -875,10 +878,14 @@ elf_gnu_ifunc_resolve_addr (struct gdbarch *gdbarch, CORE_ADDR pc)
   function = allocate_value (func_func_type);
   set_value_address (function, pc);
 
-  /* STT_GNU_IFUNC resolver functions have no parameters.  FUNCTION is the
-     function entry address.  ADDRESS may be a function descriptor.  */
+  /* STT_GNU_IFUNC resolver functions usually receive the HWCAP vector as
+     parameter.  FUNCTION is the function entry address.  ADDRESS may be a
+     function descriptor.  */
 
-  address_val = call_function_by_hand (function, 0, NULL);
+  target_auxv_search (&current_target, AT_HWCAP, &hwcap);
+  hwcap_val = value_from_longest (builtin_type (gdbarch)
+				  ->builtin_unsigned_long, hwcap);
+  address_val = call_function_by_hand (function, 1, &hwcap_val);
   address = value_as_address (address_val);
   address = gdbarch_convert_from_func_ptr_addr (gdbarch, address,
 						&current_target);
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 958ec27..783e30f 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,12 @@
+2016-09-09  Andreas Arnez  <arnez@linux.vnet.ibm.com>
+
+	* gdb.base/gnu-ifunc-lib.c (resolver_hwcap): New external
+	variable declaration.
+	(gnu_ifunc): Add parameter hwcap.  Store it in resolver_hwcap.
+	* gdb.base/gnu-ifunc.c (resolver_hwcap): New global variable.
+	* gdb.base/gnu-ifunc.exp: Add test to verify that the resolver
+	received HWCAP as its argument.
+
 2016-09-06  Pedro Alves  <palves@redhat.com>
 
 	* gdb.base/new-ui-pending-input.c: New file.
diff --git a/gdb/testsuite/gdb.base/gnu-ifunc-lib.c b/gdb/testsuite/gdb.base/gnu-ifunc-lib.c
index 8a55f60..0c0aeef 100644
--- a/gdb/testsuite/gdb.base/gnu-ifunc-lib.c
+++ b/gdb/testsuite/gdb.base/gnu-ifunc-lib.c
@@ -16,6 +16,7 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 extern volatile int gnu_ifunc_initialized;
+extern volatile unsigned long resolver_hwcap;
 extern int init_stub (int arg);
 extern int final (int arg);
 
@@ -24,8 +25,9 @@ typedef int (*final_t) (int arg);
 asm (".type gnu_ifunc, %gnu_indirect_function");
 
 final_t
-gnu_ifunc (void)
+gnu_ifunc (unsigned long hwcap)
 {
+  resolver_hwcap = hwcap;
   if (! gnu_ifunc_initialized)
     return init_stub;
   else
diff --git a/gdb/testsuite/gdb.base/gnu-ifunc.c b/gdb/testsuite/gdb.base/gnu-ifunc.c
index c68866e..77dea30 100644
--- a/gdb/testsuite/gdb.base/gnu-ifunc.c
+++ b/gdb/testsuite/gdb.base/gnu-ifunc.c
@@ -35,6 +35,10 @@ final (int arg)
 
 volatile int gnu_ifunc_initialized;
 
+/* This stores the argument received by the ifunc resolver.  */
+
+volatile unsigned long resolver_hwcap = -1;
+
 static void
 gnu_ifunc_pre (void)
 {
diff --git a/gdb/testsuite/gdb.base/gnu-ifunc.exp b/gdb/testsuite/gdb.base/gnu-ifunc.exp
index 097e48a9..3b2775b 100644
--- a/gdb/testsuite/gdb.base/gnu-ifunc.exp
+++ b/gdb/testsuite/gdb.base/gnu-ifunc.exp
@@ -76,6 +76,21 @@ gdb_continue_to_breakpoint "break-at-call" ".*break-at-call.*"
 
 gdb_test "p gnu_ifunc (3)" " = 4"
 
+# Test that the resolver received its argument.
+
+set actual_hwcap "0x0"
+set test "info auxv"
+gdb_test_multiple $test $test {
+    -re "\r\n\\d+\\s+AT_HWCAP\[^\r\n\]+($hex)\r\n.*$gdb_prompt $" {
+	set actual_hwcap $expect_out(1,string)
+    }
+    -re ".*$gdb_prompt $" {
+	pass "$test (no HWCAP)"
+    }
+}
+
+gdb_test "p/x resolver_hwcap" "= $actual_hwcap" "resolver received HWCAP"
+
 # Test GDB will skip the gnu_ifunc resolver on first call.
 
 gdb_test "step" "\r\nfinal .*"


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]