Don't create PLT symbols that don't match filtering criteria
- instead of creating them, keeping them around, and then just not enabling
breakpoints for them
diff --git a/filter.c b/filter.c
index 7f6921d..7a7bbe3 100644
--- a/filter.c
+++ b/filter.c
@@ -131,7 +131,7 @@
return re_match_or_error(&matcher->libname_re, lib->pathname,
"library pathname");
case FLM_MAIN:
- return lib->next == NULL;
+ return lib->type == LT_LIBTYPE_MAIN;
}
assert(matcher->type != matcher->type);
abort();
@@ -156,7 +156,8 @@
}
int
-filter_matches_symbol(struct filter *filt, struct library_symbol *sym)
+filter_matches_symbol(struct filter *filt,
+ const char *sym_name, struct library *lib)
{
if (filt == NULL)
return 0;
@@ -174,8 +175,8 @@
continue;
}
- if (matcher_matches_library(it->lib_matcher, sym->lib)
- && re_match_or_error(&it->symbol_re, sym->name,
+ if (matcher_matches_library(it->lib_matcher, lib)
+ && re_match_or_error(&it->symbol_re, sym_name,
"symbol name"))
matches = !matches;
}
diff --git a/filter.h b/filter.h
index 0320036..65c575a 100644
--- a/filter.h
+++ b/filter.h
@@ -93,6 +93,7 @@
/* Ask whether FILTER matches this symbol. Returns 0 if it doesn't,
* or non-0 value if it does. */
-int filter_matches_symbol(struct filter *filt, struct library_symbol *sym);
+int filter_matches_symbol(struct filter *filt, const char *sym_name,
+ struct library *lib);
#endif /* FILTER_H */
diff --git a/handle_event.c b/handle_event.c
index 28992d4..c96b9e6 100644
--- a/handle_event.c
+++ b/handle_event.c
@@ -426,7 +426,7 @@
free(syscall);
return NULL;
}
- library_init(syscalls);
+ library_init(syscalls, (enum library_type)-1);
library_set_soname(syscalls, "SYS", 0);
library_symbol_init(syscall, 0, name, 0, LS_TOPLT_NONE);
library_add_symbol(syscalls, syscall);
diff --git a/library.c b/library.c
index 4b7b002..5c80529 100644
--- a/library.c
+++ b/library.c
@@ -100,7 +100,7 @@
}
void
-library_init(struct library *lib)
+library_init(struct library *lib, enum library_type type)
{
lib->next = NULL;
lib->soname = NULL;
@@ -108,6 +108,7 @@
lib->pathname = NULL;
lib->own_pathname = 0;
lib->symbols = NULL;
+ lib->type = type;
}
int
@@ -123,9 +124,9 @@
return -1;
}
- library_init(retp);
- library_set_soname(lib, soname, lib->own_soname);
- library_set_soname(lib, pathname, lib->own_pathname);
+ library_init(retp, lib->type);
+ library_set_soname(retp, soname, lib->own_soname);
+ library_set_soname(retp, pathname, lib->own_pathname);
struct library_symbol *it;
struct library_symbol **nsymp = &retp->symbols;
diff --git a/library.h b/library.h
index befd344..60a4818 100644
--- a/library.h
+++ b/library.h
@@ -80,6 +80,12 @@
enum callback_status library_symbol_equal_cb(struct library_symbol *libsym,
void *standard);
+enum library_type {
+ LT_LIBTYPE_MAIN,
+ LT_LIBTYPE_DSO,
+ LT_LIBTYPE_DLOPEN,
+};
+
/* XXX we might consider sharing libraries across processes. Things
* like libc will be opened by every single process, no point cloning
* these everywhere. But for now, keep the ownership structure
@@ -110,12 +116,14 @@
const char *soname;
const char *pathname;
+ enum library_type type;
+
char own_soname : 1;
char own_pathname : 1;
};
/* Init LIB. */
-void library_init(struct library *lib);
+void library_init(struct library *lib, enum library_type type);
/* Initialize RETP to a library identical to LIB. Symbols are not
* shared, but copied over. Returns 0 on success and a negative value
diff --git a/ltrace-elf.c b/ltrace-elf.c
index bec85a0..5d01581 100644
--- a/ltrace-elf.c
+++ b/ltrace-elf.c
@@ -15,6 +15,7 @@
#include "common.h"
#include "proc.h"
#include "library.h"
+#include "filter.h"
#ifdef PLT_REINITALISATION_BP
extern char *PLTs_initialized_by_here;
@@ -455,30 +456,77 @@
close(lte->fd);
}
-struct library *
-ltelf_read_library(struct Process *proc, const char *filename, GElf_Addr bias)
+static int
+populate_plt(struct Process *proc, const char *filename,
+ struct ltelf *lte, struct library *lib)
+{
+ size_t i;
+ for (i = 0; i < lte->relplt_count; ++i) {
+ GElf_Rel rel;
+ GElf_Rela rela;
+ GElf_Sym sym;
+ void *ret;
+
+ if (lte->relplt->d_type == ELF_T_REL) {
+ ret = gelf_getrel(lte->relplt, i, &rel);
+ rela.r_offset = rel.r_offset;
+ rela.r_info = rel.r_info;
+ rela.r_addend = 0;
+ } else {
+ ret = gelf_getrela(lte->relplt, i, &rela);
+ }
+
+ if (ret == NULL
+ || ELF64_R_SYM(rela.r_info) >= lte->dynsym_count
+ || gelf_getsym(lte->dynsym, ELF64_R_SYM(rela.r_info),
+ &sym) == NULL)
+ error(EXIT_FAILURE, 0,
+ "Couldn't get relocation from \"%s\"",
+ filename);
+
+ char const *name = lte->dynstr + sym.st_name;
+
+ if (!filter_matches_symbol(options.plt_filter, name, lib))
+ continue;
+
+ fprintf(stderr, "%s@%s matches\n", name, lib->soname);
+
+ struct library_symbol *libsym;
+ switch (arch_elf_add_plt_entry(proc, lte, name,
+ &rela, i, &libsym)) {
+ case plt_default:
+ if (default_elf_add_plt_entry(proc, lte, name,
+ &rela, i, &libsym) < 0)
+ case plt_fail:
+ return -1;
+ case plt_ok:
+ if (libsym != NULL)
+ library_add_symbol(lib, libsym);
+ }
+ }
+ return 0;
+}
+
+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 NULL;
+ return -1;
proc->e_machine = lte.ehdr.e_machine;
- struct library *lib = malloc(sizeof(*lib));
- if (lib != NULL)
- library_init(lib);
filename = strdup(filename);
char *soname = NULL;
int own_soname = 0;
+ int status = 0;
if (lib == NULL || filename == NULL) {
fail:
if (own_soname)
free(soname);
- if (lib != NULL)
- library_destroy(lib);
free((char *)filename);
- free(lib);
- lib = NULL;
+ status = -1;
goto done;
}
@@ -501,59 +549,33 @@
lib->entry = entry;
lib->dyn_addr = (target_address_t)lte.dyn_addr;
- size_t i;
- for (i = 0; i < lte.relplt_count; ++i) {
- GElf_Rel rel;
- GElf_Rela rela;
- GElf_Sym sym;
- void *ret;
-
- if (lte.relplt->d_type == ELF_T_REL) {
- ret = gelf_getrel(lte.relplt, i, &rel);
- rela.r_offset = rel.r_offset;
- rela.r_info = rel.r_info;
- rela.r_addend = 0;
- } else {
- ret = gelf_getrela(lte.relplt, i, &rela);
- }
-
- if (ret == NULL
- || ELF64_R_SYM(rela.r_info) >= lte.dynsym_count
- || gelf_getsym(lte.dynsym, ELF64_R_SYM(rela.r_info),
- &sym) == NULL)
- error(EXIT_FAILURE, 0,
- "Couldn't get relocation from \"%s\"",
- filename);
-
- char const *name = lte.dynstr + sym.st_name;
- struct library_symbol *libsym;
- switch (arch_elf_add_plt_entry(proc, <e, name,
- &rela, i, &libsym)) {
- case plt_default:
- if (default_elf_add_plt_entry(proc, <e, name,
- &rela, i, &libsym) < 0)
- case plt_fail:
- goto fail;
- case plt_ok:
- if (libsym != NULL)
- library_add_symbol(lib, libsym);
- }
- }
+ if (filter_matches_library(options.plt_filter, lib)
+ && populate_plt(proc, filename, <e, lib) < 0)
+ goto fail;
done:
do_close_elf(<e);
- return lib;
+ return status;
}
struct library *
ltelf_read_main_binary(struct Process *proc, const char *path)
{
+ struct library *lib = malloc(sizeof(*lib));
+ if (lib == NULL)
+ return NULL;
+ library_init(lib, LT_LIBTYPE_MAIN);
+
fprintf(stderr, "ltelf_read_main_binary %d %s\n", proc->pid, path);
char *fname = pid2name(proc->pid);
- struct library *lib = ltelf_read_library(proc, fname, 0);
- if (lib != NULL) {
- library_set_pathname(lib, path, 0);
- library_set_soname(lib, rindex(path, '/') + 1, 0);
+ if (ltelf_read_library(lib, proc, fname, 0) < 0) {
+ library_destroy(lib);
+ free(lib);
+ return NULL;
}
+
+ library_set_pathname(lib, path, 0);
+ library_set_soname(lib, rindex(path, '/') + 1, 0);
+
return lib;
}
diff --git a/ltrace-elf.h b/ltrace-elf.h
index de5538a..4a27598 100644
--- a/ltrace-elf.h
+++ b/ltrace-elf.h
@@ -52,8 +52,8 @@
/* XXX is it possible to put breakpoints in VDSO and VSYSCALL
* pseudo-libraries? For now we assume that all libraries can be
* opened via a filesystem. BASE is ignored for ET_EXEC files. */
-struct library *ltelf_read_library(struct Process *proc,
- const char *filename, GElf_Addr bias);
+int ltelf_read_library(struct library *lib, struct Process *proc,
+ const char *filename, GElf_Addr bias);
/* Create a library object representing the main binary. The entry
* point address is stored to *ENTRYP. */
diff --git a/options.c b/options.c
index 5651048..d4e16a8 100644
--- a/options.c
+++ b/options.c
@@ -392,14 +392,14 @@
}
static void
-parse_filter_chain(struct options_t *options, const char *expr)
+parse_filter_chain(const char *expr, struct filter **retp)
{
char *str = strdup(expr);
if (str == NULL) {
error(0, errno, "filter '%s' will be ignored", expr);
return;
}
- options->filter = recursive_parse_chain(str);
+ *retp = recursive_parse_chain(str);
}
char **
@@ -481,7 +481,7 @@
break;
case 'e':
- parse_filter_chain(&options, optarg);
+ parse_filter_chain(optarg, &options.plt_filter);
break;
case 'f':
@@ -640,8 +640,8 @@
/* Set default filter. Use @MAIN for now, as that's what
* ltrace used to have in the past. XXX Maybe we should make
* this "*" instead. */
- if (options.filter == NULL) {
- parse_filter_chain(&options, "@MAIN");
+ if (options.plt_filter == NULL) {
+ parse_filter_chain("@MAIN", &options.plt_filter);
options.hide_caller = 1;
}
diff --git a/options.h b/options.h
index 9cd0bfc..82b13c8 100644
--- a/options.h
+++ b/options.h
@@ -21,7 +21,7 @@
#if defined(HAVE_LIBUNWIND)
int bt_depth; /* how may levels of stack frames to show */
#endif /* defined(HAVE_LIBUNWIND) */
- struct filter *filter;
+ struct filter *plt_filter;
int hide_caller; /* Whether caller library should be hidden. */
};
extern struct options_t options;
diff --git a/proc.c b/proc.c
index eb97f05..01689bb 100644
--- a/proc.c
+++ b/proc.c
@@ -16,7 +16,6 @@
#include "common.h"
#include "breakpoint.h"
#include "proc.h"
-#include "filter.h"
static int
process_bare_init(struct Process *proc, const char *filename, pid_t pid)
@@ -487,9 +486,6 @@
{
struct Process *proc = data;
- if (!filter_matches_symbol(options.filter, libsym))
- return CBS_CONT;
-
struct breakpoint *bp = malloc(sizeof(*bp));
if (bp == NULL
|| breakpoint_init(bp, proc, libsym->enter_addr, libsym) < 0) {
@@ -523,9 +519,6 @@
fprintf(stderr, "=== Added library %s@%p (%s) to %d:\n",
lib->soname, lib->base, lib->pathname, proc->pid);
- if (!filter_matches_library(options.filter, lib))
- return;
-
struct library_symbol *libsym = NULL;
while ((libsym = library_each_symbol(lib, libsym, breakpoint_for_symbol,
proc)) != NULL)
diff --git a/sysdeps/linux-gnu/proc.c b/sysdeps/linux-gnu/proc.c
index 95a67e7..6002a1c 100644
--- a/sysdeps/linux-gnu/proc.c
+++ b/sysdeps/linux-gnu/proc.c
@@ -459,13 +459,21 @@
fprintf(stderr, "DSO addr=%#lx, name='%s'\n",
rlm.l_addr, lib_name);
- struct library *lib
- = ltelf_read_library(proc, lib_name, rlm.l_addr);
+
+ struct library *lib = malloc(sizeof(*lib));
if (lib == NULL) {
+ fail:
+ if (lib != NULL)
+ library_destroy(lib);
error(0, errno, "Couldn't load ELF object %s\n",
lib_name);
continue;
}
+ library_init(lib, LT_LIBTYPE_DSO);
+
+ if (ltelf_read_library(lib, proc, lib_name, rlm.l_addr) < 0)
+ goto fail;
+
lib->key = key;
proc_add_library(proc, lib);
}