Petr Machata 51c97fb
diff --git a/ltrace-elf.c b/ltrace-elf.c
Petr Machata 51c97fb
index 92b642b..6f86d56 100644
Petr Machata 51c97fb
--- a/ltrace-elf.c
Petr Machata 51c97fb
+++ b/ltrace-elf.c
Petr Machata 51c97fb
@@ -531,6 +531,38 @@ elf_read_relocs(struct ltelf *lte, Elf_Scn *scn, GElf_Shdr *shdr,
Petr Machata 51c97fb
 	return 0;
Petr Machata 51c97fb
 }
Petr Machata 51c97fb
 
Petr Machata 51c97fb
+int
Petr Machata 51c97fb
+elf_load_dynamic_entry(struct ltelf *lte, int tag, GElf_Addr *valuep)
Petr Machata 51c97fb
+{
Petr Machata 51c97fb
+	Elf_Scn *scn;
Petr Machata 51c97fb
+	GElf_Shdr shdr;
Petr Machata 51c97fb
+	if (elf_get_section_type(lte, SHT_DYNAMIC, &scn, &shdr) < 0
Petr Machata 51c97fb
+	    || scn == NULL) {
Petr Machata 51c97fb
+	fail:
Petr Machata 51c97fb
+		fprintf(stderr, "Couldn't get SHT_DYNAMIC: %s\n",
Petr Machata 51c97fb
+			elf_errmsg(-1));
Petr Machata 51c97fb
+		return -1;
Petr Machata 51c97fb
+	}
Petr Machata 51c97fb
+
Petr Machata 51c97fb
+	Elf_Data *data = elf_loaddata(scn, &shdr);
Petr Machata 51c97fb
+	if (data == NULL)
Petr Machata 51c97fb
+		goto fail;
Petr Machata 51c97fb
+
Petr Machata 51c97fb
+	size_t j;
Petr Machata 51c97fb
+	for (j = 0; j < shdr.sh_size / shdr.sh_entsize; ++j) {
Petr Machata 51c97fb
+		GElf_Dyn dyn;
Petr Machata 51c97fb
+		if (gelf_getdyn(data, j, &dyn) == NULL)
Petr Machata 51c97fb
+			goto fail;
Petr Machata 51c97fb
+
Petr Machata 51c97fb
+		if(dyn.d_tag == tag) {
Petr Machata 51c97fb
+			*valuep = dyn.d_un.d_ptr;
Petr Machata 51c97fb
+			return 0;
Petr Machata 51c97fb
+		}
Petr Machata 51c97fb
+	}
Petr Machata 51c97fb
+
Petr Machata 51c97fb
+	return -1;
Petr Machata 51c97fb
+}
Petr Machata 51c97fb
+
Petr Machata 51c97fb
 static int
Petr Machata 51c97fb
 ltelf_read_elf(struct ltelf *lte, const char *filename)
Petr Machata 51c97fb
 {
Petr Machata 51c97fb
diff --git a/ltrace-elf.h b/ltrace-elf.h
Petr Machata 51c97fb
index ea14512..db4ffe9 100644
Petr Machata 51c97fb
--- a/ltrace-elf.h
Petr Machata 51c97fb
+++ b/ltrace-elf.h
Petr Machata 51c97fb
@@ -139,6 +139,10 @@ struct elf_each_symbol_t {
Petr Machata 51c97fb
 int elf_read_relocs(struct ltelf *lte, Elf_Scn *scn, GElf_Shdr *shdr,
Petr Machata 51c97fb
 		    struct vect *rela_vec);
Petr Machata 51c97fb
 
Petr Machata 51c97fb
+/* Read a given DT_ TAG from LTE.  Value is returned in *VALUEP.
Petr Machata 51c97fb
+ * Returns 0 on success or a negative value on failure.  */
Petr Machata 51c97fb
+int elf_load_dynamic_entry(struct ltelf *lte, int tag, GElf_Addr *valuep);
Petr Machata 51c97fb
+
Petr Machata 51c97fb
 /* Read, respectively, 1, 2, 4, or 8 bytes from Elf data at given
Petr Machata 51c97fb
  * OFFSET, and store it in *RETP.  Returns 0 on success or a negative
Petr Machata 51c97fb
  * value if there's not enough data.  */
Petr Machata 51c97fb
diff --git a/sysdeps/linux-gnu/arm/arch.h b/sysdeps/linux-gnu/arm/arch.h
Petr Machata 51c97fb
index 58a7fdf..6d0d902 100644
Petr Machata 51c97fb
--- a/sysdeps/linux-gnu/arm/arch.h
Petr Machata 51c97fb
+++ b/sysdeps/linux-gnu/arm/arch.h
Petr Machata 51c97fb
@@ -22,6 +22,8 @@
Petr Machata 51c97fb
 #ifndef LTRACE_ARM_ARCH_H
Petr Machata 51c97fb
 #define LTRACE_ARM_ARCH_H
Petr Machata 51c97fb
 
Petr Machata 51c97fb
+#include <libelf.h>
Petr Machata 51c97fb
+
Petr Machata 51c97fb
 #define ARCH_HAVE_ENABLE_BREAKPOINT 1
Petr Machata 51c97fb
 #define ARCH_HAVE_DISABLE_BREAKPOINT 1
Petr Machata 51c97fb
 
Petr Machata 51c97fb
@@ -47,7 +49,7 @@ struct arch_breakpoint_data {
Petr Machata 51c97fb
 
Petr Machata 51c97fb
 #define ARCH_HAVE_LTELF_DATA
Petr Machata 51c97fb
 struct arch_ltelf_data {
Petr Machata 51c97fb
-	/* We have this only for the hooks.  */
Petr Machata 51c97fb
+	Elf_Data *jmprel_data;
Petr Machata 51c97fb
 };
Petr Machata 51c97fb
 
Petr Machata 51c97fb
 #define ARCH_HAVE_LIBRARY_DATA
Petr Machata 51c97fb
diff --git a/sysdeps/linux-gnu/arm/fetch.c b/sysdeps/linux-gnu/arm/fetch.c
Petr Machata 51c97fb
index 5081d78..b500448 100644
Petr Machata 51c97fb
--- a/sysdeps/linux-gnu/arm/fetch.c
Petr Machata 51c97fb
+++ b/sysdeps/linux-gnu/arm/fetch.c
Petr Machata 51c97fb
@@ -32,200 +32,12 @@
Petr Machata 51c97fb
 #include "backend.h"
Petr Machata 51c97fb
 #include "fetch.h"
Petr Machata 51c97fb
 #include "library.h"
Petr Machata 51c97fb
-#include "ltrace-elf.h"
Petr Machata 51c97fb
 #include "proc.h"
Petr Machata 51c97fb
 #include "ptrace.h"
Petr Machata 51c97fb
 #include "regs.h"
Petr Machata 51c97fb
 #include "type.h"
Petr Machata 51c97fb
 #include "value.h"
Petr Machata 51c97fb
 
Petr Machata 51c97fb
-static int
Petr Machata 51c97fb
-get_hardfp(uint64_t abi_vfp_args)
Petr Machata 51c97fb
-{
Petr Machata 51c97fb
-	if (abi_vfp_args == 2)
Petr Machata 51c97fb
-		fprintf(stderr,
Petr Machata 51c97fb
-			"Tag_ABI_VFP_args value 2 (tool chain-specific "
Petr Machata 51c97fb
-			"conventions) not supported.\n");
Petr Machata 51c97fb
-	return abi_vfp_args == 1;
Petr Machata 51c97fb
-}
Petr Machata 51c97fb
-
Petr Machata 51c97fb
-int
Petr Machata 51c97fb
-arch_elf_init(struct ltelf *lte, struct library *lib)
Petr Machata 51c97fb
-{
Petr Machata 51c97fb
-	/* Nothing in this section is strictly critical.  It's not
Petr Machata 51c97fb
-	 * that much of a deal if we fail to guess right whether the
Petr Machata 51c97fb
-	 * ABI is softfp or hardfp.  */
Petr Machata 51c97fb
-	unsigned hardfp = 0;
Petr Machata 51c97fb
-
Petr Machata 51c97fb
-	Elf_Scn *scn;
Petr Machata 51c97fb
-	Elf_Data *data;
Petr Machata 51c97fb
-	GElf_Shdr shdr;
Petr Machata 51c97fb
-	if (elf_get_section_type(lte, SHT_ARM_ATTRIBUTES, &scn, &shdr) < 0
Petr Machata 51c97fb
-	    || (scn != NULL && (data = elf_loaddata(scn, &shdr)) == NULL)) {
Petr Machata 51c97fb
-		fprintf(stderr,
Petr Machata 51c97fb
-			"Error when obtaining ARM attribute section: %s\n",
Petr Machata 51c97fb
-			elf_errmsg(-1));
Petr Machata 51c97fb
-		goto done;
Petr Machata 51c97fb
-
Petr Machata 51c97fb
-	} else if (scn != NULL && data != NULL) {
Petr Machata 51c97fb
-		GElf_Xword offset = 0;
Petr Machata 51c97fb
-		uint8_t version;
Petr Machata 51c97fb
-		if (elf_read_next_u8(data, &offset, &version) < 0) {
Petr Machata 51c97fb
-			goto done;
Petr Machata 51c97fb
-		} else if (version != 'A') {
Petr Machata 51c97fb
-			fprintf(stderr, "Unsupported ARM attribute section "
Petr Machata 51c97fb
-				"version %d ('%c').\n", version, version);
Petr Machata 51c97fb
-			goto done;
Petr Machata 51c97fb
-		}
Petr Machata 51c97fb
-
Petr Machata 51c97fb
-		do {
Petr Machata 51c97fb
-			const char signature[] = "aeabi";
Petr Machata 51c97fb
-			/* N.B. LEN is including the length field
Petr Machata 51c97fb
-			 * itself.  */
Petr Machata 51c97fb
-			uint32_t sec_len;
Petr Machata 51c97fb
-			if (elf_read_u32(data, offset, &sec_len) < 0
Petr Machata 51c97fb
-			    || !elf_can_read_next(data, offset, sec_len)) {
Petr Machata 51c97fb
-				goto done;
Petr Machata 51c97fb
-			}
Petr Machata 51c97fb
-			const GElf_Xword next_offset = offset + sec_len;
Petr Machata 51c97fb
-			offset += 4;
Petr Machata 51c97fb
-
Petr Machata 51c97fb
-			if (sec_len < 4 + sizeof signature
Petr Machata 51c97fb
-			    || strcmp(signature, data->d_buf + offset) != 0)
Petr Machata 51c97fb
-				goto skip;
Petr Machata 51c97fb
-			offset += sizeof signature;
Petr Machata 51c97fb
-
Petr Machata 51c97fb
-			const GElf_Xword offset0 = offset;
Petr Machata 51c97fb
-			uint64_t tag;
Petr Machata 51c97fb
-			uint32_t sub_len;
Petr Machata 51c97fb
-			if (elf_read_next_uleb128(data, &offset, &tag) < 0
Petr Machata 51c97fb
-			    || elf_read_next_u32(data, &offset, &sub_len) < 0
Petr Machata 51c97fb
-			    || !elf_can_read_next(data, offset0, sub_len))
Petr Machata 51c97fb
-				goto done;
Petr Machata 51c97fb
-
Petr Machata 51c97fb
-			if (tag != 1)
Petr Machata 51c97fb
-				/* IHI0045D_ABI_addenda: "section and
Petr Machata 51c97fb
-				 * symbol attributes are deprecated
Petr Machata 51c97fb
-				 * [...] consumers are permitted to
Petr Machata 51c97fb
-				 * ignore them."  */
Petr Machata 51c97fb
-				goto skip;
Petr Machata 51c97fb
-
Petr Machata 51c97fb
-			while (offset < offset0 + sub_len) {
Petr Machata 51c97fb
-				if (elf_read_next_uleb128(data,
Petr Machata 51c97fb
-							  &offset, &tag) < 0)
Petr Machata 51c97fb
-					goto done;
Petr Machata 51c97fb
-
Petr Machata 51c97fb
-				switch (tag) {
Petr Machata 51c97fb
-					uint64_t v;
Petr Machata 51c97fb
-				case 6: /* Tag_CPU_arch */
Petr Machata 51c97fb
-				case 7: /* Tag_CPU_arch_profile */
Petr Machata 51c97fb
-				case 8: /* Tag_ARM_ISA_use */
Petr Machata 51c97fb
-				case 9: /* Tag_THUMB_ISA_use */
Petr Machata 51c97fb
-				case 10: /* Tag_FP_arch */
Petr Machata 51c97fb
-				case 11: /* Tag_WMMX_arch */
Petr Machata 51c97fb
-				case 12: /* Tag_Advanced_SIMD_arch */
Petr Machata 51c97fb
-				case 13: /* Tag_PCS_config */
Petr Machata 51c97fb
-				case 14: /* Tag_ABI_PCS_R9_use */
Petr Machata 51c97fb
-				case 15: /* Tag_ABI_PCS_RW_data */
Petr Machata 51c97fb
-				case 16: /* Tag_ABI_PCS_RO_data */
Petr Machata 51c97fb
-				case 17: /* Tag_ABI_PCS_GOT_use */
Petr Machata 51c97fb
-				case 18: /* Tag_ABI_PCS_wchar_t */
Petr Machata 51c97fb
-				case 19: /* Tag_ABI_FP_rounding */
Petr Machata 51c97fb
-				case 20: /* Tag_ABI_FP_denormal */
Petr Machata 51c97fb
-				case 21: /* Tag_ABI_FP_exceptions */
Petr Machata 51c97fb
-				case 22: /* Tag_ABI_FP_user_exceptions */
Petr Machata 51c97fb
-				case 23: /* Tag_ABI_FP_number_model */
Petr Machata 51c97fb
-				case 24: /* Tag_ABI_align_needed */
Petr Machata 51c97fb
-				case 25: /* Tag_ABI_align_preserved */
Petr Machata 51c97fb
-				case 26: /* Tag_ABI_enum_size */
Petr Machata 51c97fb
-				case 27: /* Tag_ABI_HardFP_use */
Petr Machata 51c97fb
-				case 28: /* Tag_ABI_VFP_args */
Petr Machata 51c97fb
-				case 29: /* Tag_ABI_WMMX_args */
Petr Machata 51c97fb
-				case 30: /* Tag_ABI_optimization_goals */
Petr Machata 51c97fb
-				case 31: /* Tag_ABI_FP_optimization_goals */
Petr Machata 51c97fb
-				case 32: /* Tag_compatibility */
Petr Machata 51c97fb
-				case 34: /* Tag_CPU_unaligned_access */
Petr Machata 51c97fb
-				case 36: /* Tag_FP_HP_extension */
Petr Machata 51c97fb
-				case 38: /* Tag_ABI_FP_16bit_format */
Petr Machata 51c97fb
-				case 42: /* Tag_MPextension_use */
Petr Machata 51c97fb
-				case 70: /* Tag_MPextension_use as well */
Petr Machata 51c97fb
-				case 44: /* Tag_DIV_use */
Petr Machata 51c97fb
-				case 64: /* Tag_nodefaults */
Petr Machata 51c97fb
-				case 66: /* Tag_T2EE_use */
Petr Machata 51c97fb
-				case 68: /* Tag_Virtualization_use */
Petr Machata 51c97fb
-				uleb128:
Petr Machata 51c97fb
-					if (elf_read_next_uleb128
Petr Machata 51c97fb
-						(data, &offset, &v) < 0)
Petr Machata 51c97fb
-						goto done;
Petr Machata 51c97fb
-					if (tag == 28)
Petr Machata 51c97fb
-						hardfp = get_hardfp(v);
Petr Machata 51c97fb
-					if (tag != 32)
Petr Machata 51c97fb
-						continue;
Petr Machata 51c97fb
-
Petr Machata 51c97fb
-					/* Tag 32 has two arguments,
Petr Machata 51c97fb
-					 * fall through.  */
Petr Machata 51c97fb
-
Petr Machata 51c97fb
-				case 4:	/* Tag_CPU_raw_name */
Petr Machata 51c97fb
-				case 5:	/* Tag_CPU_name */
Petr Machata 51c97fb
-				case 65: /* Tag_also_compatible_with */
Petr Machata 51c97fb
-				case 67: /* Tag_conformance */
Petr Machata 51c97fb
-				ntbs:
Petr Machata 51c97fb
-					offset += strlen(data->d_buf
Petr Machata 51c97fb
-							 + offset) + 1;
Petr Machata 51c97fb
-					continue;
Petr Machata 51c97fb
-				}
Petr Machata 51c97fb
-
Petr Machata 51c97fb
-				/* Handle unknown tags in a generic
Petr Machata 51c97fb
-				 * manner, if possible.  */
Petr Machata 51c97fb
-				if (tag <= 32) {
Petr Machata 51c97fb
-					fprintf(stderr,
Petr Machata 51c97fb
-						"Unknown tag %lld "
Petr Machata 51c97fb
-						"at offset %#llx "
Petr Machata 51c97fb
-						"of ARM attribute section.",
Petr Machata 51c97fb
-						tag, offset);
Petr Machata 51c97fb
-					goto skip;
Petr Machata 51c97fb
-				} else if (tag % 2 == 0) {
Petr Machata 51c97fb
-					goto uleb128;
Petr Machata 51c97fb
-				} else {
Petr Machata 51c97fb
-					goto ntbs;
Petr Machata 51c97fb
-				}
Petr Machata 51c97fb
-			}
Petr Machata 51c97fb
-
Petr Machata 51c97fb
-		skip:
Petr Machata 51c97fb
-			offset = next_offset;
Petr Machata 51c97fb
-
Petr Machata 51c97fb
-		} while (elf_can_read_next(data, offset, 1));
Petr Machata 51c97fb
-
Petr Machata 51c97fb
-	}
Petr Machata 51c97fb
-
Petr Machata 51c97fb
-done:
Petr Machata 51c97fb
-	lib->arch.hardfp = hardfp;
Petr Machata 51c97fb
-	return 0;
Petr Machata 51c97fb
-}
Petr Machata 51c97fb
-
Petr Machata 51c97fb
-void
Petr Machata 51c97fb
-arch_elf_destroy(struct ltelf *lte)
Petr Machata 51c97fb
-{
Petr Machata 51c97fb
-}
Petr Machata 51c97fb
-
Petr Machata 51c97fb
-int
Petr Machata 51c97fb
-arch_library_init(struct library *lib)
Petr Machata 51c97fb
-{
Petr Machata 51c97fb
-	return 0;
Petr Machata 51c97fb
-}
Petr Machata 51c97fb
-
Petr Machata 51c97fb
-void
Petr Machata 51c97fb
-arch_library_destroy(struct library *lib)
Petr Machata 51c97fb
-{
Petr Machata 51c97fb
-}
Petr Machata 51c97fb
-
Petr Machata 51c97fb
-int
Petr Machata 51c97fb
-arch_library_clone(struct library *retp, struct library *lib)
Petr Machata 51c97fb
-{
Petr Machata 51c97fb
-	retp->arch = lib->arch;
Petr Machata 51c97fb
-	return 0;
Petr Machata 51c97fb
-}
Petr Machata 51c97fb
-
Petr Machata 51c97fb
 enum {
Petr Machata 51c97fb
 	/* How many (double) VFP registers the AAPCS uses for
Petr Machata 51c97fb
 	 * parameter passing.  */
Petr Machata 51c97fb
diff --git a/sysdeps/linux-gnu/arm/plt.c b/sysdeps/linux-gnu/arm/plt.c
Petr Machata 51c97fb
index d1bf7ca..9e9e37f 100644
Petr Machata 51c97fb
--- a/sysdeps/linux-gnu/arm/plt.c
Petr Machata 51c97fb
+++ b/sysdeps/linux-gnu/arm/plt.c
Petr Machata 51c97fb
@@ -1,5 +1,6 @@
Petr Machata 51c97fb
 /*
Petr Machata 51c97fb
  * This file is part of ltrace.
Petr Machata 51c97fb
+ * Copyright (C) 2013 Petr Machata, Red Hat Inc.
Petr Machata 51c97fb
  * Copyright (C) 2010 Zach Welch, CodeSourcery
Petr Machata 51c97fb
  * Copyright (C) 2004,2008,2009 Juan Cespedes
Petr Machata 51c97fb
  *
Petr Machata 51c97fb
@@ -20,20 +21,205 @@
Petr Machata 51c97fb
  */
Petr Machata 51c97fb
 
Petr Machata 51c97fb
 #include <gelf.h>
Petr Machata 51c97fb
+#include <stdio.h>
Petr Machata 51c97fb
+#include <string.h>
Petr Machata 51c97fb
 
Petr Machata 51c97fb
 #include "proc.h"
Petr Machata 51c97fb
 #include "library.h"
Petr Machata 51c97fb
 #include "ltrace-elf.h"
Petr Machata 51c97fb
 
Petr Machata 51c97fb
 static int
Petr Machata 51c97fb
+get_hardfp(uint64_t abi_vfp_args)
Petr Machata 51c97fb
+{
Petr Machata 51c97fb
+	if (abi_vfp_args == 2)
Petr Machata 51c97fb
+		fprintf(stderr,
Petr Machata 51c97fb
+			"Tag_ABI_VFP_args value 2 (tool chain-specific "
Petr Machata 51c97fb
+			"conventions) not supported.\n");
Petr Machata 51c97fb
+	return abi_vfp_args == 1;
Petr Machata 51c97fb
+}
Petr Machata 51c97fb
+
Petr Machata 51c97fb
+int
Petr Machata 51c97fb
+arch_elf_init(struct ltelf *lte, struct library *lib)
Petr Machata 51c97fb
+{
Petr Machata 51c97fb
+	GElf_Addr jmprel_addr;
Petr Machata 51c97fb
+	Elf_Scn *jmprel_sec;
Petr Machata 51c97fb
+	GElf_Shdr jmprel_shdr;
Petr Machata 51c97fb
+	if (elf_load_dynamic_entry(lte, DT_JMPREL, &jmprel_addr) < 0
Petr Machata 51c97fb
+	    || elf_get_section_covering(lte, jmprel_addr,
Petr Machata 51c97fb
+					&jmprel_sec, &jmprel_shdr) < 0
Petr Machata 51c97fb
+	    || jmprel_sec == NULL)
Petr Machata 51c97fb
+		return -1;
Petr Machata 51c97fb
+
Petr Machata 51c97fb
+	lte->arch.jmprel_data = elf_loaddata(jmprel_sec, &jmprel_shdr);
Petr Machata 51c97fb
+	if (lte->arch.jmprel_data == NULL)
Petr Machata 51c97fb
+		return -1;
Petr Machata 51c97fb
+
Petr Machata 51c97fb
+	/* Nothing in this section is strictly critical.  It's not
Petr Machata 51c97fb
+	 * that much of a deal if we fail to guess right whether the
Petr Machata 51c97fb
+	 * ABI is softfp or hardfp.  */
Petr Machata 51c97fb
+	unsigned hardfp = 0;
Petr Machata 51c97fb
+
Petr Machata 51c97fb
+	Elf_Scn *scn;
Petr Machata 51c97fb
+	Elf_Data *data;
Petr Machata 51c97fb
+	GElf_Shdr shdr;
Petr Machata 51c97fb
+	if (elf_get_section_type(lte, SHT_ARM_ATTRIBUTES, &scn, &shdr) < 0
Petr Machata 51c97fb
+	    || (scn != NULL && (data = elf_loaddata(scn, &shdr)) == NULL)) {
Petr Machata 51c97fb
+		fprintf(stderr,
Petr Machata 51c97fb
+			"Error when obtaining ARM attribute section: %s\n",
Petr Machata 51c97fb
+			elf_errmsg(-1));
Petr Machata 51c97fb
+		goto done;
Petr Machata 51c97fb
+
Petr Machata 51c97fb
+	} else if (scn != NULL && data != NULL) {
Petr Machata 51c97fb
+		GElf_Xword offset = 0;
Petr Machata 51c97fb
+		uint8_t version;
Petr Machata 51c97fb
+		if (elf_read_next_u8(data, &offset, &version) < 0) {
Petr Machata 51c97fb
+			goto done;
Petr Machata 51c97fb
+		} else if (version != 'A') {
Petr Machata 51c97fb
+			fprintf(stderr, "Unsupported ARM attribute section "
Petr Machata 51c97fb
+				"version %d ('%c').\n", version, version);
Petr Machata 51c97fb
+			goto done;
Petr Machata 51c97fb
+		}
Petr Machata 51c97fb
+
Petr Machata 51c97fb
+		do {
Petr Machata 51c97fb
+			const char signature[] = "aeabi";
Petr Machata 51c97fb
+			/* N.B. LEN is including the length field
Petr Machata 51c97fb
+			 * itself.  */
Petr Machata 51c97fb
+			uint32_t sec_len;
Petr Machata 51c97fb
+			if (elf_read_u32(data, offset, &sec_len) < 0
Petr Machata 51c97fb
+			    || !elf_can_read_next(data, offset, sec_len)) {
Petr Machata 51c97fb
+				goto done;
Petr Machata 51c97fb
+			}
Petr Machata 51c97fb
+			const GElf_Xword next_offset = offset + sec_len;
Petr Machata 51c97fb
+			offset += 4;
Petr Machata 51c97fb
+
Petr Machata 51c97fb
+			if (sec_len < 4 + sizeof signature
Petr Machata 51c97fb
+			    || strcmp(signature, data->d_buf + offset) != 0)
Petr Machata 51c97fb
+				goto skip;
Petr Machata 51c97fb
+			offset += sizeof signature;
Petr Machata 51c97fb
+
Petr Machata 51c97fb
+			const GElf_Xword offset0 = offset;
Petr Machata 51c97fb
+			uint64_t tag;
Petr Machata 51c97fb
+			uint32_t sub_len;
Petr Machata 51c97fb
+			if (elf_read_next_uleb128(data, &offset, &tag) < 0
Petr Machata 51c97fb
+			    || elf_read_next_u32(data, &offset, &sub_len) < 0
Petr Machata 51c97fb
+			    || !elf_can_read_next(data, offset0, sub_len))
Petr Machata 51c97fb
+				goto done;
Petr Machata 51c97fb
+
Petr Machata 51c97fb
+			if (tag != 1)
Petr Machata 51c97fb
+				/* IHI0045D_ABI_addenda: "section and
Petr Machata 51c97fb
+				 * symbol attributes are deprecated
Petr Machata 51c97fb
+				 * [...] consumers are permitted to
Petr Machata 51c97fb
+				 * ignore them."  */
Petr Machata 51c97fb
+				goto skip;
Petr Machata 51c97fb
+
Petr Machata 51c97fb
+			while (offset < offset0 + sub_len) {
Petr Machata 51c97fb
+				if (elf_read_next_uleb128(data,
Petr Machata 51c97fb
+							  &offset, &tag) < 0)
Petr Machata 51c97fb
+					goto done;
Petr Machata 51c97fb
+
Petr Machata 51c97fb
+				switch (tag) {
Petr Machata 51c97fb
+					uint64_t v;
Petr Machata 51c97fb
+				case 6: /* Tag_CPU_arch */
Petr Machata 51c97fb
+				case 7: /* Tag_CPU_arch_profile */
Petr Machata 51c97fb
+				case 8: /* Tag_ARM_ISA_use */
Petr Machata 51c97fb
+				case 9: /* Tag_THUMB_ISA_use */
Petr Machata 51c97fb
+				case 10: /* Tag_FP_arch */
Petr Machata 51c97fb
+				case 11: /* Tag_WMMX_arch */
Petr Machata 51c97fb
+				case 12: /* Tag_Advanced_SIMD_arch */
Petr Machata 51c97fb
+				case 13: /* Tag_PCS_config */
Petr Machata 51c97fb
+				case 14: /* Tag_ABI_PCS_R9_use */
Petr Machata 51c97fb
+				case 15: /* Tag_ABI_PCS_RW_data */
Petr Machata 51c97fb
+				case 16: /* Tag_ABI_PCS_RO_data */
Petr Machata 51c97fb
+				case 17: /* Tag_ABI_PCS_GOT_use */
Petr Machata 51c97fb
+				case 18: /* Tag_ABI_PCS_wchar_t */
Petr Machata 51c97fb
+				case 19: /* Tag_ABI_FP_rounding */
Petr Machata 51c97fb
+				case 20: /* Tag_ABI_FP_denormal */
Petr Machata 51c97fb
+				case 21: /* Tag_ABI_FP_exceptions */
Petr Machata 51c97fb
+				case 22: /* Tag_ABI_FP_user_exceptions */
Petr Machata 51c97fb
+				case 23: /* Tag_ABI_FP_number_model */
Petr Machata 51c97fb
+				case 24: /* Tag_ABI_align_needed */
Petr Machata 51c97fb
+				case 25: /* Tag_ABI_align_preserved */
Petr Machata 51c97fb
+				case 26: /* Tag_ABI_enum_size */
Petr Machata 51c97fb
+				case 27: /* Tag_ABI_HardFP_use */
Petr Machata 51c97fb
+				case 28: /* Tag_ABI_VFP_args */
Petr Machata 51c97fb
+				case 29: /* Tag_ABI_WMMX_args */
Petr Machata 51c97fb
+				case 30: /* Tag_ABI_optimization_goals */
Petr Machata 51c97fb
+				case 31: /* Tag_ABI_FP_optimization_goals */
Petr Machata 51c97fb
+				case 32: /* Tag_compatibility */
Petr Machata 51c97fb
+				case 34: /* Tag_CPU_unaligned_access */
Petr Machata 51c97fb
+				case 36: /* Tag_FP_HP_extension */
Petr Machata 51c97fb
+				case 38: /* Tag_ABI_FP_16bit_format */
Petr Machata 51c97fb
+				case 42: /* Tag_MPextension_use */
Petr Machata 51c97fb
+				case 70: /* Tag_MPextension_use as well */
Petr Machata 51c97fb
+				case 44: /* Tag_DIV_use */
Petr Machata 51c97fb
+				case 64: /* Tag_nodefaults */
Petr Machata 51c97fb
+				case 66: /* Tag_T2EE_use */
Petr Machata 51c97fb
+				case 68: /* Tag_Virtualization_use */
Petr Machata 51c97fb
+				uleb128:
Petr Machata 51c97fb
+					if (elf_read_next_uleb128
Petr Machata 51c97fb
+						(data, &offset, &v) < 0)
Petr Machata 51c97fb
+						goto done;
Petr Machata 51c97fb
+					if (tag == 28)
Petr Machata 51c97fb
+						hardfp = get_hardfp(v);
Petr Machata 51c97fb
+					if (tag != 32)
Petr Machata 51c97fb
+						continue;
Petr Machata 51c97fb
+
Petr Machata 51c97fb
+					/* Tag 32 has two arguments,
Petr Machata 51c97fb
+					 * fall through.  */
Petr Machata 51c97fb
+
Petr Machata 51c97fb
+				case 4:	/* Tag_CPU_raw_name */
Petr Machata 51c97fb
+				case 5:	/* Tag_CPU_name */
Petr Machata 51c97fb
+				case 65: /* Tag_also_compatible_with */
Petr Machata 51c97fb
+				case 67: /* Tag_conformance */
Petr Machata 51c97fb
+				ntbs:
Petr Machata 51c97fb
+					offset += strlen(data->d_buf
Petr Machata 51c97fb
+							 + offset) + 1;
Petr Machata 51c97fb
+					continue;
Petr Machata 51c97fb
+				}
Petr Machata 51c97fb
+
Petr Machata 51c97fb
+				/* Handle unknown tags in a generic
Petr Machata 51c97fb
+				 * manner, if possible.  */
Petr Machata 51c97fb
+				if (tag <= 32) {
Petr Machata 51c97fb
+					fprintf(stderr,
Petr Machata 51c97fb
+						"Unknown tag %lld "
Petr Machata 51c97fb
+						"at offset %#llx "
Petr Machata 51c97fb
+						"of ARM attribute section.",
Petr Machata 51c97fb
+						tag, offset);
Petr Machata 51c97fb
+					goto skip;
Petr Machata 51c97fb
+				} else if (tag % 2 == 0) {
Petr Machata 51c97fb
+					goto uleb128;
Petr Machata 51c97fb
+				} else {
Petr Machata 51c97fb
+					goto ntbs;
Petr Machata 51c97fb
+				}
Petr Machata 51c97fb
+			}
Petr Machata 51c97fb
+
Petr Machata 51c97fb
+		skip:
Petr Machata 51c97fb
+			offset = next_offset;
Petr Machata 51c97fb
+
Petr Machata 51c97fb
+		} while (elf_can_read_next(data, offset, 1));
Petr Machata 51c97fb
+
Petr Machata 51c97fb
+	}
Petr Machata 51c97fb
+
Petr Machata 51c97fb
+done:
Petr Machata 51c97fb
+	lib->arch.hardfp = hardfp;
Petr Machata 51c97fb
+	return 0;
Petr Machata 51c97fb
+}
Petr Machata 51c97fb
+
Petr Machata 51c97fb
+void
Petr Machata 51c97fb
+arch_elf_destroy(struct ltelf *lte)
Petr Machata 51c97fb
+{
Petr Machata 51c97fb
+}
Petr Machata 51c97fb
+
Petr Machata 51c97fb
+static int
Petr Machata 51c97fb
 arch_plt_entry_has_stub(struct ltelf *lte, size_t off) {
Petr Machata 51c97fb
-	uint16_t op = *(uint16_t *)((char *)lte->relplt->d_buf + off);
Petr Machata 51c97fb
+	char *buf = (char *) lte->arch.jmprel_data->d_buf;
Petr Machata 51c97fb
+	uint16_t op = *(uint16_t *) (buf + off);
Petr Machata 51c97fb
 	return op == 0x4778;
Petr Machata 51c97fb
 }
Petr Machata 51c97fb
 
Petr Machata 51c97fb
 GElf_Addr
Petr Machata 51c97fb
 arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela * rela) {
Petr Machata 51c97fb
-	size_t start = lte->relplt->d_size + 12;
Petr Machata 51c97fb
+	size_t start = lte->arch.jmprel_data->d_size + 12;
Petr Machata 51c97fb
 	size_t off = start + 20, i;
Petr Machata 51c97fb
 	for (i = 0; i < ndx; i++)
Petr Machata 51c97fb
 		off += arch_plt_entry_has_stub(lte, off) ? 16 : 12;
Petr Machata 51c97fb
@@ -47,3 +233,21 @@ sym2addr(struct process *proc, struct library_symbol *sym)
Petr Machata 51c97fb
 {
Petr Machata 51c97fb
 	return sym->enter_addr;
Petr Machata 51c97fb
 }
Petr Machata 51c97fb
+
Petr Machata 51c97fb
+int
Petr Machata 51c97fb
+arch_library_init(struct library *lib)
Petr Machata 51c97fb
+{
Petr Machata 51c97fb
+	return 0;
Petr Machata 51c97fb
+}
Petr Machata 51c97fb
+
Petr Machata 51c97fb
+void
Petr Machata 51c97fb
+arch_library_destroy(struct library *lib)
Petr Machata 51c97fb
+{
Petr Machata 51c97fb
+}
Petr Machata 51c97fb
+
Petr Machata 51c97fb
+int
Petr Machata 51c97fb
+arch_library_clone(struct library *retp, struct library *lib)
Petr Machata 51c97fb
+{
Petr Machata 51c97fb
+	retp->arch = lib->arch;
Petr Machata 51c97fb
+	return 0;
Petr Machata 51c97fb
+}
Petr Machata 51c97fb
diff --git a/sysdeps/linux-gnu/ppc/plt.c b/sysdeps/linux-gnu/ppc/plt.c
Petr Machata 51c97fb
index 5e3ffe1..3ec1397 100644
Petr Machata 51c97fb
--- a/sysdeps/linux-gnu/ppc/plt.c
Petr Machata 51c97fb
+++ b/sysdeps/linux-gnu/ppc/plt.c
Petr Machata 51c97fb
@@ -402,38 +402,6 @@ get_glink_vma(struct ltelf *lte, GElf_Addr ppcgot, Elf_Data *plt_data)
Petr Machata 51c97fb
 }
Petr Machata 51c97fb
 
Petr Machata 51c97fb
 static int
Petr Machata 51c97fb
-load_dynamic_entry(struct ltelf *lte, int tag, GElf_Addr *valuep)
Petr Machata 51c97fb
-{
Petr Machata 51c97fb
-	Elf_Scn *scn;
Petr Machata 51c97fb
-	GElf_Shdr shdr;
Petr Machata 51c97fb
-	if (elf_get_section_type(lte, SHT_DYNAMIC, &scn, &shdr) < 0
Petr Machata 51c97fb
-	    || scn == NULL) {
Petr Machata 51c97fb
-	fail:
Petr Machata 51c97fb
-		fprintf(stderr, "Couldn't get SHT_DYNAMIC: %s\n",
Petr Machata 51c97fb
-			elf_errmsg(-1));
Petr Machata 51c97fb
-		return -1;
Petr Machata 51c97fb
-	}
Petr Machata 51c97fb
-
Petr Machata 51c97fb
-	Elf_Data *data = elf_loaddata(scn, &shdr);
Petr Machata 51c97fb
-	if (data == NULL)
Petr Machata 51c97fb
-		goto fail;
Petr Machata 51c97fb
-
Petr Machata 51c97fb
-	size_t j;
Petr Machata 51c97fb
-	for (j = 0; j < shdr.sh_size / shdr.sh_entsize; ++j) {
Petr Machata 51c97fb
-		GElf_Dyn dyn;
Petr Machata 51c97fb
-		if (gelf_getdyn(data, j, &dyn) == NULL)
Petr Machata 51c97fb
-			goto fail;
Petr Machata 51c97fb
-
Petr Machata 51c97fb
-		if(dyn.d_tag == tag) {
Petr Machata 51c97fb
-			*valuep = dyn.d_un.d_ptr;
Petr Machata 51c97fb
-			return 0;
Petr Machata 51c97fb
-		}
Petr Machata 51c97fb
-	}
Petr Machata 51c97fb
-
Petr Machata 51c97fb
-	return -1;
Petr Machata 51c97fb
-}
Petr Machata 51c97fb
-
Petr Machata 51c97fb
-static int
Petr Machata 51c97fb
 nonzero_data(Elf_Data *data)
Petr Machata 51c97fb
 {
Petr Machata 51c97fb
 	/* We are not supposed to get here if there's no PLT.  */
Petr Machata 51c97fb
@@ -488,8 +456,8 @@ arch_elf_init(struct ltelf *lte, struct library *lib)
Petr Machata 51c97fb
 	Elf_Scn *rela_sec;
Petr Machata 51c97fb
 	GElf_Shdr rela_shdr;
Petr Machata 51c97fb
 	if ((lte->ehdr.e_machine == EM_PPC64 || lte->arch.secure_plt)
Petr Machata 51c97fb
-	    && load_dynamic_entry(lte, DT_RELA, &rela) == 0
Petr Machata 51c97fb
-	    && load_dynamic_entry(lte, DT_RELASZ, &relasz) == 0
Petr Machata 51c97fb
+	    && elf_load_dynamic_entry(lte, DT_RELA, &rela) == 0
Petr Machata 51c97fb
+	    && elf_load_dynamic_entry(lte, DT_RELASZ, &relasz) == 0
Petr Machata 51c97fb
 	    && elf_get_section_covering(lte, rela, &rela_sec, &rela_shdr) == 0
Petr Machata 51c97fb
 	    && rela_sec != NULL) {
Petr Machata 51c97fb
 
Petr Machata 51c97fb
@@ -509,7 +477,7 @@ arch_elf_init(struct ltelf *lte, struct library *lib)
Petr Machata 51c97fb
 
Petr Machata 51c97fb
 	if (lte->ehdr.e_machine == EM_PPC && lte->arch.secure_plt) {
Petr Machata 51c97fb
 		GElf_Addr ppcgot;
Petr Machata 51c97fb
-		if (load_dynamic_entry(lte, DT_PPC_GOT, &ppcgot) < 0) {
Petr Machata 51c97fb
+		if (elf_load_dynamic_entry(lte, DT_PPC_GOT, &ppcgot) < 0) {
Petr Machata 51c97fb
 			fprintf(stderr, "couldn't find DT_PPC_GOT\n");
Petr Machata 51c97fb
 			return -1;
Petr Machata 51c97fb
 		}
Petr Machata 51c97fb
@@ -522,7 +490,8 @@ arch_elf_init(struct ltelf *lte, struct library *lib)
Petr Machata 51c97fb
 
Petr Machata 51c97fb
 	} else if (lte->ehdr.e_machine == EM_PPC64) {
Petr Machata 51c97fb
 		GElf_Addr glink_vma;
Petr Machata 51c97fb
-		if (load_dynamic_entry(lte, DT_PPC64_GLINK, &glink_vma) < 0) {
Petr Machata 51c97fb
+		if (elf_load_dynamic_entry(lte, DT_PPC64_GLINK,
Petr Machata 51c97fb
+					   &glink_vma) < 0) {
Petr Machata 51c97fb
 			fprintf(stderr, "couldn't find DT_PPC64_GLINK\n");
Petr Machata 51c97fb
 			return -1;
Petr Machata 51c97fb
 		}
Petr Machata 51c97fb
@@ -532,8 +501,8 @@ arch_elf_init(struct ltelf *lte, struct library *lib)
Petr Machata 51c97fb
 
Petr Machata 51c97fb
 	} else {
Petr Machata 51c97fb
 		/* By exhaustion--PPC32 BSS.  */
Petr Machata 51c97fb
-		if (load_dynamic_entry(lte, DT_PLTGOT,
Petr Machata 51c97fb
-				       &lib->arch.pltgot_addr) < 0) {
Petr Machata 51c97fb
+		if (elf_load_dynamic_entry(lte, DT_PLTGOT,
Petr Machata 51c97fb
+					   &lib->arch.pltgot_addr) < 0) {
Petr Machata 51c97fb
 			fprintf(stderr, "couldn't find DT_PLTGOT\n");
Petr Machata 51c97fb
 			return -1;
Petr Machata 51c97fb
 		}