aboutsummaryrefslogtreecommitdiff
path: root/gdb/elfread.c
diff options
context:
space:
mode:
authorAndreas Arnez <arnez@linux.vnet.ibm.com>2016-09-09 19:59:53 +0200
committerAndreas Arnez <arnez@linux.vnet.ibm.com>2016-09-09 19:59:53 +0200
commite1b2624a08fae1f669d879946d5041945b4dc248 (patch)
tree2b3634606789cdb6b21fd1a0fe5e0e6b666f9a82 /gdb/elfread.c
parent3569342c148dd1cb4b2e1bdafe64a9e3a3701813 (diff)
downloadgdb-e1b2624a08fae1f669d879946d5041945b4dc248.zip
gdb-e1b2624a08fae1f669d879946d5041945b4dc248.tar.gz
gdb-e1b2624a08fae1f669d879946d5041945b4dc248.tar.bz2
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.
Diffstat (limited to 'gdb/elfread.c')
-rw-r--r--gdb/elfread.c13
1 files changed, 10 insertions, 3 deletions
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);