File ltrace-ppc64le_git8.patch of Package ltrace

--- backend.h.ori
+++ backend.h
@@ -310,6 +310,23 @@ enum plt_status arch_elf_add_plt_entry(struct Process *proc, struct ltelf *lte,
 				       const char *name, GElf_Rela *rela,
 				       size_t i, struct library_symbol **ret);
 
+/* The following callback has to be implemented in backend if arch.h
+ * defines OS_HAVE_ADD_FUNC_ENTRY.
+ *
+ * This is called for every symbol in ltrace is about to add to the
+ * library constructed for LTE in process PROC.
+ *
+ * If this function returns plt_default, then if there is a
+ * pre-existing symbol, its name may be updated if the newly-found
+ * name is shorter.  Otherwise a new symbol is created.
+ *
+ * If plt_ok or plt_default are returned, the chain of symbols passed
+ * back in RET is added to library under construction.  */
+enum plt_status os_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);
+
 /* This callback needs to be implemented if arch.h defines
  * ARCH_HAVE_DYNLINK_DONE.  It is called after the dynamic linker is
  * done with the process startup.  */
--- ltrace-elf.c.ori
+++ ltrace-elf.c
@@ -109,6 +109,22 @@ arch_elf_add_plt_entry(struct Process *proc, struct ltelf *lte,
 }
 #endif
 
+#ifndef OS_HAVE_ADD_FUNC_ENTRY
+enum plt_status
+os_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 (GELF_ST_TYPE(sym->st_info) != STT_FUNC) {
+		*ret = NULL;
+		return plt_ok;
+	} else {
+		return plt_default;
+	}
+}
+#endif
+
 Elf_Data *
 elf_loaddata(Elf_Scn *scn, GElf_Shdr *shdr)
 {
@@ -617,6 +633,17 @@ filter_symbol_chain(struct filter *filter,
 	}
 }
 
+static void
+delete_symbol_chain(struct library_symbol *libsym)
+{
+	while (libsym != NULL) {
+		struct library_symbol *tmp = libsym->next;
+		library_symbol_destroy(libsym);
+		free(libsym);
+		libsym = tmp;
+	}
+}
+
 static int
 populate_plt(struct Process *proc, const char *filename,
 	     struct ltelf *lte, struct library *lib,
@@ -639,7 +666,7 @@ populate_plt(struct Process *proc, const char *filename,
 		switch (arch_elf_add_plt_entry(proc, lte, name,
 					       &rela, i, &libsym)) {
 		case plt_fail:
-				return -1;
+			return -1;
 
 		case plt_default:
 			/* Add default entry to the beginning of LIBSYM.  */
@@ -734,16 +751,16 @@ populate_this_symtab(struct Process *proc, const char *filename,
 	for (i = 0; i < size; ++i) {
 		GElf_Sym sym;
 		if (gelf_getsym(symtab, i, &sym) == NULL) {
-		fail:
 			fprintf(stderr,
 				"couldn't get symbol #%zd from %s: %s\n",
 				i, filename, elf_errmsg(-1));
 			continue;
 		}
 
-		if (GELF_ST_TYPE(sym.st_info) != STT_FUNC
-		    || sym.st_value == 0
-		    || sym.st_shndx == STN_UNDEF)
+		if (sym.st_value == 0 || sym.st_shndx == STN_UNDEF
+		    /* Also ignore any special values besides direct
+		     * section references.  */
+		    || sym.st_shndx >= lte->ehdr.e_shnum)
 			continue;
 
 		/* Find symbol name and snip version.  */
@@ -757,14 +784,14 @@ populate_this_symtab(struct Process *proc, const char *filename,
 		name[len] = 0;
 
 		/* If we are interested in exports, store this name.  */
-		char *name_copy = NULL;
 		if (names != NULL) {
-			struct library_exported_name *export = NULL;
-			name_copy = strdup(name);
+			struct library_exported_name *export
+				= malloc(sizeof *export);
+			char *name_copy = strdup(name);
 
-			if (name_copy == NULL
-			    || (export = malloc(sizeof(*export))) == NULL) {
+			if (name_copy == NULL || export == NULL) {
 				free(name_copy);
+				free(export);
 				fprintf(stderr, "Couldn't store symbol %s.  "
 					"Tracing may be incomplete.\n", name);
 			} else {
@@ -797,42 +824,78 @@ populate_this_symtab(struct Process *proc, const char *filename,
 			continue;
 		}
 
-		char *full_name;
-		int own_full_name = 1;
-		if (name_copy == NULL) {
-			full_name = strdup(name);
-			if (full_name == NULL)
-				goto fail;
-		} else {
-			full_name = name_copy;
-			own_full_name = 0;
+		char *full_name = strdup(name);
+		if (full_name == NULL) {
+			fprintf(stderr, "couldn't copy name of %s@%s: %s\n",
+				name, lib->soname, strerror(errno));
+			continue;
 		}
 
-		/* Look whether we already have a symbol for this
-		 * address.  If not, add this one.  */
-		struct unique_symbol key = { naddr, NULL };
-		struct unique_symbol *unique
-			= lsearch(&key, symbols, &num_symbols,
-				  sizeof(*symbols), &unique_symbol_cmp);
-
-		if (unique->libsym == NULL) {
-			struct library_symbol *libsym = malloc(sizeof(*libsym));
-			if (libsym == NULL
-			    || library_symbol_init(libsym, naddr,
-						   full_name, own_full_name,
+		struct library_symbol *libsym = NULL;
+		switch (os_elf_add_func_entry(proc, lte, &sym,
+					      naddr, full_name, &libsym)) {
+		case plt_default:;
+			/* Put the default symbol to the chain.  */
+			struct library_symbol *tmp = malloc(sizeof *tmp);
+			if (tmp == NULL
+			    || library_symbol_init(tmp, naddr, full_name, 1,
 						   LS_TOPLT_NONE) < 0) {
-				--num_symbols;
-				goto fail;
+				free(tmp);
+
+				/* Either add the whole bunch, or none
+				 * of it.  Note that for plt_fail we
+				 * don't do this--it's the callee's
+				 * job to clean up after itself before
+				 * it bails out.  */
+				delete_symbol_chain(libsym);
+				libsym = NULL;
+
+		case plt_fail:
+				fprintf(stderr, "Couldn't add symbol %s@%s "
+					"for tracing.\n", name, lib->soname);
+
+				break;
 			}
-			unique->libsym = libsym;
-			unique->addr = naddr;
 
-		} else if (strlen(full_name) < strlen(unique->libsym->name)) {
-			library_symbol_set_name(unique->libsym,
-						full_name, own_full_name);
+			full_name = NULL;
+			tmp->next = libsym;
+			libsym = tmp;
+			break;
 
-		} else if (own_full_name) {
-			free(full_name);
+		case plt_ok:
+			break;
+		}
+
+		free(full_name);
+
+		struct library_symbol *tmp;
+		for (tmp = libsym; tmp != NULL; ) {
+			/* Look whether we already have a symbol for
+			 * this address.  If not, add this one.  If
+			 * yes, look if we should pick the new symbol
+			 * name.  */
+
+			struct unique_symbol key = { tmp->enter_addr, NULL };
+			struct unique_symbol *unique
+				= lsearch(&key, symbols, &num_symbols,
+					  sizeof *symbols, &unique_symbol_cmp);
+
+			if (unique->libsym == NULL) {
+				unique->libsym = tmp;
+				unique->addr = tmp->enter_addr;
+				tmp = tmp->next;
+			} else {
+				if (strlen(tmp->name)
+				    < strlen(unique->libsym->name)) {
+					library_symbol_set_name
+						(unique->libsym, tmp->name, 1);
+					tmp->name = NULL;
+				}
+				struct library_symbol *next = tmp->next;
+				library_symbol_destroy(tmp);
+				free(tmp);
+				tmp = next;
+			}
 		}
 	}