File ltrace-ppc64le_git13.patch of Package ltrace

--- sysdeps/linux-gnu/ppc/plt.c.ori
+++ sysdeps/linux-gnu/ppc/plt.c
@@ -120,6 +120,10 @@
  * catch the point where the slot is resolved, would hit the return
  * breakpoint and that's not currently handled well.
  *
+ * On PPC32 with secure PLT, IFUNC symbols in main binary actually
+ * don't refer to the resolver itself.  Instead they refer to a PLT
+ * slot.
+ *
  * XXX TODO If we have hardware watch point, we might put a read watch
  * on .plt slot, and discover the offenders this way.  I don't know
  * the details, but I assume at most a handful (like, one or two, if
@@ -471,6 +475,36 @@ arch_elf_init(struct ltelf *lte, struct library *lib)
 		 * value to something conspicuous.  */
 		lib->arch.bss_plt_prelinked = -1;
 
+	/* On PPC64 and PPC32 secure, IRELATIVE relocations actually
+	 * relocate .iplt section, and as such are stored in .rela.dyn
+	 * (where all non-PLT relocations are stored) instead of
+	 * .rela.plt.  Add these to lte->plt_relocs.  */
+	extern int read_relplt(struct ltelf *lte, Elf_Scn *scn, GElf_Shdr *shdr,
+			       struct vect *ret);
+
+	GElf_Addr rela, relasz;
+	Elf_Scn *rela_sec;
+	GElf_Shdr rela_shdr;
+	if ((lte->ehdr.e_machine == EM_PPC64 || lte->arch.secure_plt)
+	    && load_dynamic_entry(lte, DT_RELA, &rela) == 0
+	    && load_dynamic_entry(lte, DT_RELASZ, &relasz) == 0
+	    && elf_get_section_covering(lte, rela, &rela_sec, &rela_shdr) == 0
+	    && rela_sec != NULL) {
+
+		struct vect v;
+		VECT_INIT(&v, GElf_Rela);
+		int ret = read_relplt(lte, rela_sec, &rela_shdr, &v);
+		if (ret >= 0
+		    && VECT_EACH(&v, GElf_Rela, NULL,
+				 reloc_copy_if_irelative, lte) != NULL)
+			ret = -1;
+
+		VECT_DESTROY(&v, GElf_Rela, NULL, NULL);
+
+		if (ret < 0)
+			return ret;
+	}
+
 	if (lte->ehdr.e_machine == EM_PPC && lte->arch.secure_plt) {
 		GElf_Addr ppcgot;
 		if (load_dynamic_entry(lte, DT_PPC_GOT, &ppcgot) < 0) {
@@ -581,35 +613,6 @@ arch_elf_init(struct ltelf *lte, struct library *lib)
 		}
 	}
 
-	/* On PPC64, IRELATIVE relocations actually relocate .iplt
-	 * section, and as such are stored in .rela.dyn (where all
-	 * non-PLT relocations are stored) instead of .rela.plt.  Add
-	 * these to lte->plt_relocs.  */
-	extern int read_relplt(struct ltelf *lte, Elf_Scn *scn, GElf_Shdr *shdr,
-			       struct vect *ret);
-
-	GElf_Addr rela, relasz;
-	Elf_Scn *rela_sec;
-	GElf_Shdr rela_shdr;
-	if (lte->ehdr.e_machine == EM_PPC64
-	    && load_dynamic_entry(lte, DT_RELA, &rela) == 0
-	    && load_dynamic_entry(lte, DT_RELASZ, &relasz) == 0
-	    && elf_get_section_covering(lte, rela, &rela_sec, &rela_shdr) == 0
-	    && rela_sec != NULL) {
-
-		struct vect v;
-		VECT_INIT(&v, GElf_Rela);
-		int ret = read_relplt(lte, rela_sec, &rela_shdr, &v);
-		if (ret >= 0
-		    && VECT_EACH(&v, GElf_Rela, NULL,
-				 reloc_copy_if_irelative, lte) != NULL)
-			ret = -1;
-
-		VECT_DESTROY(&v, GElf_Rela, NULL, NULL);
-
-		if (ret < 0)
-			return ret;
-	}
 	return 0;
 }
 
@@ -652,39 +655,45 @@ arch_elf_add_plt_entry(struct Process *proc, struct ltelf *lte,
 		       const char *a_name, GElf_Rela *rela, size_t ndx,
 		       struct library_symbol **ret)
 {
-	if (lte->ehdr.e_machine == EM_PPC) {
-		if (lte->arch.secure_plt)
-			return plt_default;
-
-		struct library_symbol *libsym = NULL;
-		if (default_elf_add_plt_entry(proc, lte, a_name, rela, ndx,
-					      &libsym) < 0)
-			return plt_fail;
-
-		/* On PPC32 with BSS PLT, delay the symbol until
-		 * dynamic linker is done.  */
-		assert(!libsym->delayed);
-		libsym->delayed = 1;
-
-		*ret = libsym;
-		return plt_ok;
-
-	}
-
 	bool is_irelative = reloc_is_irelative(lte->ehdr.e_machine, rela);
 	char *name;
-	if (is_irelative)
-		name = linux_elf_find_irelative_name(lte, rela);
-	else
+	if (! is_irelative) {
 		name = strdup(a_name);
+	} else {
+		GElf_Addr addr = lte->ehdr.e_machine == EM_PPC64
+			? (GElf_Addr) rela->r_addend
+			: arch_plt_sym_val(lte, ndx, rela);
+		name = linux_elf_find_irelative_name(lte, addr);
+	}
 
-	if (name == NULL)
+	if (name == NULL) {
+	fail:
+		free(name);
 		return plt_fail;
+	}
+
+	struct library_symbol *chain = NULL;
+	if (lte->ehdr.e_machine == EM_PPC) {
+		if (default_elf_add_plt_entry(proc, lte, name, rela, ndx,
+					      &chain) < 0)
+			goto fail;
+
+		if (! lte->arch.secure_plt) {
+			/* On PPC32 with BSS PLT, delay the symbol
+			 * until dynamic linker is done.  */
+			assert(!chain->delayed);
+			chain->delayed = 1;
+		}
+
+	ok:
+		*ret = chain;
+		free(name);
+		return plt_ok;
+	}
 
 	/* PPC64.  If we have stubs, we return a chain of breakpoint
 	 * sites, one for each stub that corresponds to this PLT
 	 * entry.  */
-	struct library_symbol *chain = NULL;
 	struct library_symbol **symp;
 	for (symp = &lte->arch.stubs; *symp != NULL; ) {
 		struct library_symbol *sym = *symp;
@@ -699,11 +708,8 @@ arch_elf_add_plt_entry(struct Process *proc, struct ltelf *lte,
 		chain = sym;
 	}
 
-	if (chain != NULL) {
-		*ret = chain;
-		free(name);
-		return plt_ok;
-	}
+	if (chain != NULL)
+		goto ok;
 
 	/* We don't have stub symbols.  Find corresponding .plt slot,
 	 * and check whether it contains the corresponding PLT address
@@ -719,19 +725,16 @@ arch_elf_add_plt_entry(struct Process *proc, struct ltelf *lte,
 	       || plt_slot_addr < lte->plt_addr + lte->plt_size);
 
 	GElf_Addr plt_slot_value;
-	if (read_plt_slot_value(proc, plt_slot_addr, &plt_slot_value) < 0) {
-		free(name);
-		return plt_fail;
-	}
+	if (read_plt_slot_value(proc, plt_slot_addr, &plt_slot_value) < 0)
+		goto fail;
 
 	struct library_symbol *libsym = malloc(sizeof(*libsym));
 	if (libsym == NULL) {
 		fprintf(stderr, "allocation for .plt slot: %s\n",
 			strerror(errno));
-	fail:
-		free(name);
+	fail2:
 		free(libsym);
-		return plt_fail;
+		goto fail;
 	}
 
 	/* XXX The double cast should be removed when
@@ -739,7 +742,7 @@ arch_elf_add_plt_entry(struct Process *proc, struct ltelf *lte,
 	if (library_symbol_init(libsym,
 				(arch_addr_t) (uintptr_t) plt_entry_addr,
 				name, 1, LS_TOPLT_EXEC) < 0)
-		goto fail;
+		goto fail2;
 	libsym->arch.plt_slot_addr = plt_slot_addr;
 
 	if (! is_irelative
@@ -759,7 +762,7 @@ arch_elf_add_plt_entry(struct Process *proc, struct ltelf *lte,
 
 		if (unresolve_plt_slot(proc, plt_slot_addr, plt_entry_addr) < 0) {
 			library_symbol_destroy(libsym);
-			goto fail;
+			goto fail2;
 		}
 
 		if (! is_irelative) {
--- sysdeps/linux-gnu/trace.c.ori
+++ sysdeps/linux-gnu/trace.c
@@ -1241,10 +1241,10 @@ irelative_name_cb(GElf_Sym *symbol, const char *name, void *d)
 }
 
 char *
-linux_elf_find_irelative_name(struct ltelf *lte, GElf_Rela *rela)
+linux_elf_find_irelative_name(struct ltelf *lte, GElf_Addr addr)
 {
-	struct irelative_name_data_t data = { rela->r_addend, NULL };
-	if (rela->r_addend != 0
+	struct irelative_name_data_t data = { addr, NULL };
+	if (addr != 0
 	    && elf_each_symbol(lte, 0,
 			       irelative_name_cb, &data).status < 0)
 		return NULL;
@@ -1256,8 +1256,7 @@ linux_elf_find_irelative_name(struct ltelf *lte, GElf_Rela *rela)
 #define NAME "IREL."
 		/* NAME\0 + 0x + digits.  */
 		char *tmp_name = alloca(sizeof NAME + 2 + 16);
-		sprintf(tmp_name, NAME "%#" PRIx64,
-			(uint64_t)rela->r_addend);
+		sprintf(tmp_name, NAME "%#" PRIx64, (uint64_t) addr);
 		name = tmp_name;
 #undef NAME
 	}
@@ -1271,7 +1270,7 @@ linux_elf_add_plt_entry_irelative(struct Process *proc, struct ltelf *lte,
 				  struct library_symbol **ret)
 
 {
-	char *name = linux_elf_find_irelative_name(lte, rela);
+	char *name = linux_elf_find_irelative_name(lte, rela->r_addend);
 	int i = default_elf_add_plt_entry(proc, lte, name, rela, ndx, ret);
 	free(name);
 	return i < 0 ? plt_fail : plt_ok;
--- sysdeps/linux-gnu/trace.h.ori
+++ sysdeps/linux-gnu/trace.h
@@ -137,9 +137,9 @@ enum plt_status linux_elf_add_plt_entry_irelative(struct Process *proc,
 						  struct library_symbol **ret);
 
 /* Service routine of the above.  Determines a name corresponding to
- * RELA, or invents a new one.  Returns NULL on failures, otherwise it
+ * ADDR, or invents a new one.  Returns NULL on failures, otherwise it
  * returns a malloc'd pointer that the caller is responsible for
  * freeing.  */
-char *linux_elf_find_irelative_name(struct ltelf *lte, GElf_Rela *rela);
+char *linux_elf_find_irelative_name(struct ltelf *lte, GElf_Addr addr);
 
 #endif /* _LTRACE_LINUX_TRACE_H_ */