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