Support latent and delayed symbols
Neither latent, nor delayed symbols are given a breakpoint. The difference
is in who's responsible for the state. Latent symbols are (will be) used
by ltrace core. Delayed symbols are used by backends. Only when both of
these flags are cleared is a breakpoint enabled for the symbol.
diff --git a/ChangeLog b/ChangeLog
index 79837ae..198ef4d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2012-09-27 Petr Machata <pmachata@redhat.com>
+
+ * library.h (struct library_symbol.latent): New field.
+ (struct library_symbol.delayed): Likewise.
+ * library.c (private_library_symbol_init): Take arguments to
+ initialize the two.
+ (library_symbol_init, library_symbol_clone): Update callers.
+
2012-09-26 Petr Machata <pmachata@redhat.com>
* ltrace-elf.h (default_elf_add_plt_entry): Drop.
diff --git a/library.c b/library.c
index cbd4a35..c2ba169 100644
--- a/library.c
+++ b/library.c
@@ -113,13 +113,16 @@
private_library_symbol_init(struct library_symbol *libsym,
arch_addr_t addr,
const char *name, int own_name,
- enum toplt type_of_plt)
+ enum toplt type_of_plt,
+ int latent, int delayed)
{
libsym->next = NULL;
libsym->lib = NULL;
libsym->plt_type = type_of_plt;
libsym->name = name;
libsym->own_name = own_name;
+ libsym->latent = latent;
+ libsym->delayed = delayed;
libsym->enter_addr = (void *)(uintptr_t)addr;
}
@@ -134,7 +137,8 @@
arch_addr_t addr, const char *name, int own_name,
enum toplt type_of_plt)
{
- private_library_symbol_init(libsym, addr, name, own_name, type_of_plt);
+ private_library_symbol_init(libsym, addr, name, own_name,
+ type_of_plt, 0, 0);
/* If arch init fails, we've already set libsym->name and
* own_name. But we return failure, and the client code isn't
@@ -159,7 +163,8 @@
return -1;
private_library_symbol_init(retp, libsym->enter_addr,
- name, libsym->own_name, libsym->plt_type);
+ name, libsym->own_name, libsym->plt_type,
+ libsym->latent, libsym->delayed);
if (arch_library_symbol_clone(retp, libsym) < 0) {
private_library_symbol_destroy(retp);
diff --git a/library.h b/library.h
index d764da9..21dc96a 100644
--- a/library.h
+++ b/library.h
@@ -45,7 +45,21 @@
const char *name;
arch_addr_t enter_addr;
enum toplt plt_type;
- char own_name;
+ int own_name : 1;
+
+ /* This is relevant for PLT symbols. Latent PLT symbols are
+ * those that don't match any of the -e rules, but that might
+ * potentially become active if a library implementing them
+ * appears that matches a -l rule. Ltrace core is responsible
+ * for clearing latent flag. */
+ int latent : 1;
+
+ /* Delayed symbols are those for which a breakpoint shouldn't
+ * be enabled yet. They are similar to latent symbols, but
+ * backend is responsible for clearing the delayed flag. See
+ * proc_activate_delayed_symbol. */
+ int delayed : 1;
+
struct arch_library_symbol_data arch;
};
@@ -112,7 +126,8 @@
/* Address of PT_DYNAMIC segment. */
arch_addr_t dyn_addr;
- /* Symbols associated with the library. */
+ /* Symbols associated with the library. This includes a
+ * symbols that don't have a breakpoint attached (yet). */
struct library_symbol *symbols;
const char *soname;
diff --git a/proc.c b/proc.c
index 99bf31b..eb3e552 100644
--- a/proc.c
+++ b/proc.c
@@ -629,11 +629,10 @@
proc->event_handler = NULL;
}
-static enum callback_status
-breakpoint_for_symbol(struct library_symbol *libsym, void *data)
+static int
+breakpoint_for_symbol(struct library_symbol *libsym, struct Process *proc)
{
arch_addr_t bp_addr;
- struct Process *proc = data;
assert(proc->leader == proc);
bp_addr = sym2addr(proc, libsym);
@@ -644,11 +643,16 @@
*
* Allow the backend to add these into the process representation
* but don't put breakpoints at this point. Let the backend fix that
- * up later. */
+ * up later.
+ *
+ * XXX This should be changed to delayed symbols. */
if (bp_addr == 0 && libsym->plt_type == LS_TOPLT_GOTONLY) {
/* Don't add breakpoints yet. */
return CBS_CONT;
}
+ /* Don't enable latent or delayed symbols. */
+ if (libsym->latent || libsym->delayed)
+ return 0;
/* If there is an artificial breakpoint on the same address,
* its libsym will be NULL, and we can smuggle our libsym
@@ -667,7 +671,7 @@
if (bp != NULL) {
assert(bp->libsym == NULL);
bp->libsym = libsym;
- return CBS_CONT;
+ return 0;
}
bp = malloc(sizeof(*bp));
@@ -675,7 +679,7 @@
|| breakpoint_init(bp, proc, bp_addr, libsym) < 0) {
fail:
free(bp);
- return CBS_FAIL;
+ return -1;
}
if (proc_add_breakpoint(proc, bp) < 0) {
breakpoint_destroy(bp);
@@ -688,7 +692,31 @@
goto fail;
}
- return CBS_CONT;
+ return 0;
+}
+
+static enum callback_status
+cb_breakpoint_for_symbol(struct library_symbol *libsym, void *data)
+{
+ return breakpoint_for_symbol(libsym, data) < 0 ? CBS_FAIL : CBS_CONT;
+}
+
+static int
+proc_activate_latent_symbol(struct Process *proc,
+ struct library_symbol *libsym)
+{
+ assert(libsym->latent);
+ libsym->latent = 0;
+ return breakpoint_for_symbol(libsym, proc);
+}
+
+int
+proc_activate_delayed_symbol(struct Process *proc,
+ struct library_symbol *libsym)
+{
+ assert(libsym->delayed);
+ libsym->delayed = 0;
+ return breakpoint_for_symbol(libsym, proc);
}
void
@@ -700,10 +728,12 @@
debug(DEBUG_PROCESS, "added library %s@%p (%s) to %d",
lib->soname, lib->base, lib->pathname, proc->pid);
+ /* Insert breakpoints for all active (non-latent) symbols. */
struct library_symbol *libsym = NULL;
- while ((libsym = library_each_symbol(lib, libsym, breakpoint_for_symbol,
+ while ((libsym = library_each_symbol(lib, libsym,
+ cb_breakpoint_for_symbol,
proc)) != NULL)
- fprintf(stderr, "couldn't insert breakpoint for %s to %d: %s",
+ fprintf(stderr, "Couldn't insert breakpoint for %s to %d: %s.",
libsym->name, proc->pid, strerror(errno));
}
diff --git a/proc.h b/proc.h
index b61e420..9864e1b 100644
--- a/proc.h
+++ b/proc.h
@@ -206,6 +206,14 @@
* was found and unlinked, otherwise returns a negative value. */
int proc_remove_library(struct Process *proc, struct library *lib);
+/* Clear a delayed flag. If a symbol is neither latent, nor delayed,
+ * a breakpoint is inserted for it. Returns 0 if the activation was
+ * successful or a negative value if it failed. Note that if a symbol
+ * is both latent and delayed, this will not enable the corresponding
+ * breakpoint. */
+int proc_activate_delayed_symbol(struct Process *proc,
+ struct library_symbol *libsym);
+
/* Iterate through the libraries of PROC. See callback.h for notes on
* iteration interfaces. */
struct library *proc_each_library(struct Process *proc, struct library *start,