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;
+ }
}
}