File ltrace-ppc64le_git15.patch of Package ltrace
--- sysdeps/linux-gnu/ppc/arch.h.ori
+++ sysdeps/linux-gnu/ppc/arch.h
@@ -39,6 +39,7 @@
#define ARCH_HAVE_ATOMIC_SINGLESTEP
#define ARCH_HAVE_ADD_PLT_ENTRY
+#define ARCH_HAVE_ADD_FUNC_ENTRY
#define ARCH_HAVE_TRANSLATE_ADDRESS
#define ARCH_HAVE_DYNLINK_DONE
#define ARCH_HAVE_FETCH_ARG
--- sysdeps/linux-gnu/ppc/plt.c.ori
+++ sysdeps/linux-gnu/ppc/plt.c
@@ -120,9 +120,12 @@
* 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.
+ * On PPC32 with secure PLT, the address of IFUNC symbols in main
+ * binary actually isn't of the resolver, but of a PLT slot. We
+ * therefore have to locate the corresponding PLT relocation (which is
+ * of type R_PPC_IRELATIVE) and request that it be traced. The addend
+ * of that relocation is an address of resolver, and we request
+ * tracing of the xyz.IFUNC symbol there.
*
* 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
@@ -653,6 +656,59 @@ unresolve_plt_slot(struct Process *proc, GElf_Addr addr, GElf_Addr value)
}
enum plt_status
+arch_elf_add_func_entry(struct Process *proc, struct ltelf *lte,
+ const GElf_Sym *sym,
+ arch_addr_t addr, const char *name,
+ struct library_symbol **ret)
+{
+ if (lte->ehdr.e_machine != EM_PPC || lte->ehdr.e_type == ET_DYN)
+ return plt_default;
+
+ bool ifunc = false;
+#ifdef STT_GNU_IFUNC
+ ifunc = GELF_ST_TYPE(sym->st_info) == STT_GNU_IFUNC;
+#endif
+ if (! ifunc)
+ return plt_default;
+
+ size_t len = vect_size(<e->plt_relocs);
+ size_t i;
+ for (i = 0; i < len; ++i) {
+ GElf_Rela *rela = VECT_ELEMENT(<e->plt_relocs, GElf_Rela, i);
+ if (sym->st_value == arch_plt_sym_val(lte, i, rela)) {
+
+ struct library_symbol *libsym = malloc(sizeof *libsym);
+
+ /* XXX double cast. */
+ arch_addr_t resolver_addr
+ = (arch_addr_t) (uintptr_t) rela->r_addend;
+
+ if (name == NULL || libsym == NULL
+ || library_symbol_init(libsym, resolver_addr,
+ name, 1,
+ LS_TOPLT_EXEC) < 0) {
+ fail:
+ free(libsym);
+ return plt_fail;
+ }
+
+ if (elf_add_plt_entry(proc, lte, name, rela,
+ i, ret) < 0) {
+ library_symbol_destroy(libsym);
+ goto fail;
+ }
+
+ libsym->next = *ret;
+ *ret = libsym;
+ return plt_ok;
+ }
+ }
+
+ *ret = NULL;
+ return plt_ok;
+}
+
+enum plt_status
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)