Elementary support for -x
- this is applied across libraries. Syntax for the -x option is the same
as for -e
- this fails on symbol aliases. E.g. there are several symbols named like
strlen in libc: strlen, __GI_strlen, and perhaps others. This needs to
be taken into account, and symbol aliases shouldn't be enabled if
they were added under a different name already
diff --git a/ltrace-elf.c b/ltrace-elf.c
index 5d01581..69f3075 100644
--- a/ltrace-elf.c
+++ b/ltrace-elf.c
@@ -297,7 +297,7 @@
lte->symtab_count = shdr.sh_size / shdr.sh_entsize;
if ((lte->symtab == NULL
|| elf_getdata(scn, lte->symtab) != NULL)
- && opt_x != NULL)
+ && options.static_filter != NULL)
error(EXIT_FAILURE, 0,
"Couldn't get .symtab data from \"%s\"",
filename);
@@ -507,11 +507,74 @@
return 0;
}
+static int
+populate_this_symtab(struct Process *proc, const char *filename,
+ struct ltelf *lte, struct library *lib,
+ Elf_Data *symtab, const char *strtab, size_t size)
+{
+ size_t lib_len = strlen(lib->soname);
+ size_t i;
+ for (i = 0; i < size; ++i) {
+ GElf_Sym sym;
+ if (gelf_getsym(lte->symtab, i, &sym) == NULL) {
+ fail:
+ error(0, errno, "couldn't get symbol #%zd from %s: %s",
+ i, filename, elf_errmsg(-1));
+ continue;
+ }
+
+ if (sym.st_value == 0)
+ continue;
+
+ const char *name = strtab + sym.st_name;
+ if (!filter_matches_symbol(options.static_filter, name, lib))
+ continue;
+ fprintf(stderr, "%s@%s matches\n", name, lib->soname);
+
+ char *full_name = malloc(strlen(name) + 1 + lib_len + 1);
+ if (full_name == NULL)
+ goto fail;
+ sprintf(full_name, "%s@%s", name, lib->soname);
+
+ target_address_t addr
+ = (target_address_t)(sym.st_value + lte->bias);
+ target_address_t naddr;
+ if (arch_translate_address(proc, addr, &naddr) < 0) {
+ error(0, errno, "couldn't translate address of %s@%s",
+ name, lib->soname);
+ continue;
+ }
+ if (addr != naddr)
+ naddr += lte->bias;
+
+ struct library_symbol *libsym = malloc(sizeof(*libsym));
+ if (libsym == NULL)
+ goto fail;
+
+ library_symbol_init(libsym, naddr, full_name, 1, LS_TOPLT_NONE);
+ library_add_symbol(lib, libsym);
+ }
+ return 0;
+}
+
+static int
+populate_symtab(struct Process *proc, const char *filename,
+ struct ltelf *lte, struct library *lib)
+{
+ if (lte->symtab != NULL && lte->strtab != NULL)
+ return populate_this_symtab(proc, filename, lte, lib,
+ lte->symtab, lte->strtab,
+ lte->symtab_count);
+ else
+ return populate_this_symtab(proc, filename, lte, lib,
+ lte->dynsym, lte->dynstr,
+ lte->dynsym_count);
+}
+
int
ltelf_read_library(struct library *lib, struct Process *proc,
const char *filename, GElf_Addr bias)
{
- // XXX we leak LTE contents
struct ltelf lte = {};
if (do_init_elf(<e, filename, bias) < 0)
return -1;
@@ -553,6 +616,10 @@
&& populate_plt(proc, filename, <e, lib) < 0)
goto fail;
+ if (filter_matches_library(options.static_filter, lib)
+ && populate_symtab(proc, filename, <e, lib) < 0)
+ goto fail;
+
done:
do_close_elf(<e);
return status;
diff --git a/options.c b/options.c
index d4e16a8..0e8d106 100644
--- a/options.c
+++ b/options.c
@@ -48,10 +48,6 @@
/* List of pids given to option -p: */
struct opt_p_t *opt_p = NULL; /* attach to process with a given pid */
-/* List of global function names given to -x: */
-struct opt_x_t *opt_x = NULL;
-unsigned int opt_x_cnt = 0;
-
/* List of filenames give to option -F: */
struct opt_F_t *opt_F = NULL; /* alternate configuration file(s) */
@@ -581,31 +577,8 @@
/* Fall Thru */
case 'x':
- {
- struct opt_x_t *p = opt_x;
-
- /* First, check for duplicate. */
- while (p && strcmp(p->name, optarg)) {
- p = p->next;
- }
- if (p) {
- break;
- }
-
- /* If not duplicate, add to list. */
- p = malloc(sizeof(struct opt_x_t));
- if (!p) {
- perror("ltrace: malloc");
- exit(1);
- }
- opt_x_cnt++;
- p->name = optarg;
- p->found = 0;
- p->next = opt_x;
- p->hash = ~(0UL);
- opt_x = p;
- break;
- }
+ parse_filter_chain(optarg, &options.static_filter);
+ break;
default:
err_usage();
diff --git a/options.h b/options.h
index 82b13c8..651d424 100644
--- a/options.h
+++ b/options.h
@@ -22,6 +22,7 @@
int bt_depth; /* how may levels of stack frames to show */
#endif /* defined(HAVE_LIBUNWIND) */
struct filter *plt_filter;
+ struct filter *static_filter;
int hide_caller; /* Whether caller library should be hidden. */
};
extern struct options_t options;
@@ -41,18 +42,8 @@
struct opt_F_t *next;
};
-struct opt_x_t {
- char *name;
- int found;
- unsigned long hash;
- struct opt_x_t *next;
-};
-
extern struct opt_p_t *opt_p; /* attach to process with a given pid */
extern struct opt_F_t *opt_F; /* alternate configuration file(s) */
-extern struct opt_x_t *opt_x; /* list of functions to break at */
-extern unsigned int opt_x_cnt;
-
extern char **process_options(int argc, char **argv);