Shuffle breakpoint functions around
diff --git a/breakpoint.h b/breakpoint.h
index ce926d2..36f239f 100644
--- a/breakpoint.h
+++ b/breakpoint.h
@@ -71,6 +71,7 @@
struct breakpoint {
struct bp_callbacks *cbs;
struct library_symbol *libsym;
+ struct Process *proc;
void *addr;
unsigned char orig_value[BREAKPOINT_LENGTH];
int enabled;
@@ -97,9 +98,19 @@
/* XXX this is currently not called anywhere. */
void breakpoint_destroy(struct breakpoint *bp);
-/* This is actually three functions rolled in one:
+/* Call enable_breakpoint the first time it's called. Returns 0 on
+ * success and a negative value on failure. */
+int breakpoint_turn_on(struct breakpoint *bp);
+
+/* Call disable_breakpoint when turned off the same number of times
+ * that it was turned on. Returns 0 on success and a negative value
+ * on failure. */
+int breakpoint_turn_off(struct breakpoint *bp);
+
+/* This is actually several functions rolled in one:
+ * - malloc
* - breakpoint_init
- * - proc_breakpoint_insert
+ * - proc_add_breakpoint
* - breakpoint_enable
* XXX I think it should be broken up somehow. */
struct breakpoint *insert_breakpoint(struct Process *proc, void *addr,
@@ -108,9 +119,12 @@
/* Name of a symbol associated with BP. May be NULL. */
const char *breakpoint_name(const struct breakpoint *bp);
+/* A library that this breakpoint comes from. May be NULL. */
+struct library *breakpoint_library(const struct breakpoint *bp);
+
/* Again, this seems to be several interfaces rolled into one:
* - breakpoint_disable
- * - proc_breakpoint_remove
+ * - proc_remove_breakpoint
* - breakpoint_destroy
* XXX */
void delete_breakpoint(struct Process *proc, void *addr);
diff --git a/breakpoints.c b/breakpoints.c
index 0d2fa5f..bc3c7c1 100644
--- a/breakpoints.c
+++ b/breakpoints.c
@@ -68,11 +68,16 @@
}
#endif
+/* On second thought, I don't think we need PROC. All the translation
+ * (arch_translate_address in particular) should be doable using
+ * static lookups of various sections in the ELF file. We shouldn't
+ * need process for anything. */
int
breakpoint_init(struct breakpoint *bp, struct Process *proc,
target_address_t addr, struct library_symbol *libsym)
{
bp->cbs = NULL;
+ bp->proc = NULL;
bp->addr = addr;
memset(bp->orig_value, 0, sizeof(bp->orig_value));
bp->enabled = 0;
@@ -103,6 +108,32 @@
arch_breakpoint_destroy(bp);
}
+int
+breakpoint_turn_on(struct breakpoint *bp)
+{
+ /* Make sure it was inserted. XXX In a clean world, we would
+ * have breakpoint_site representing a place and breakpoint
+ * representing inserted breakpoint. */
+ assert(bp->proc != NULL);
+ bp->enabled++;
+ if (bp->enabled == 1) {
+ assert(bp->proc->pid != 0);
+ enable_breakpoint(bp->proc, bp);
+ }
+ return 0;
+}
+
+int
+breakpoint_turn_off(struct breakpoint *bp)
+{
+ assert(bp->proc != NULL);
+ bp->enabled--;
+ if (bp->enabled == 0)
+ disable_breakpoint(bp->proc, bp);
+ assert(bp->enabled >= 0);
+ return 0;
+}
+
struct breakpoint *
insert_breakpoint(struct Process *proc, void *addr,
struct library_symbol *libsym)
@@ -125,22 +156,31 @@
return NULL;
}
+ /* XXX what we need to do instead is have a list of
+ * breakpoints that are enabled at this address. The
+ * following works if every breakpoint is the same and there's
+ * no extra data, but that doesn't hold anymore. For now it
+ * will suffice, about the only realistic case where we need
+ * to have more than one breakpoint per address is return from
+ * a recursive library call. */
struct breakpoint *sbp = dict_find_entry(leader->breakpoints, addr);
if (sbp == NULL) {
sbp = malloc(sizeof(*sbp));
if (sbp == NULL
- || breakpoint_init(sbp, proc, addr, libsym) < 0
- || dict_enter(leader->breakpoints, addr, sbp) < 0) {
+ || breakpoint_init(sbp, proc, addr, libsym) < 0) {
+ free(sbp);
+ return NULL;
+ }
+ if (proc_add_breakpoint(proc, sbp) < 0) {
+ fail:
+ breakpoint_destroy(sbp);
free(sbp);
return NULL;
}
}
- sbp->enabled++;
- if (sbp->enabled == 1) {
- assert(proc->pid != 0);
- enable_breakpoint(proc, sbp);
- }
+ if (breakpoint_turn_on(sbp) < 0)
+ goto fail;
return sbp;
}
@@ -161,10 +201,11 @@
if (sbp == NULL)
return;
- sbp->enabled--;
- if (sbp->enabled == 0)
- disable_breakpoint(proc, sbp);
- assert(sbp->enabled >= 0);
+ if (breakpoint_turn_off(sbp) < 0) {
+ fprintf(stderr, "Couldn't turn off the breakpoint %s@%p\n",
+ breakpoint_name(sbp), sbp->addr);
+ return;
+ }
}
const char *
@@ -174,6 +215,13 @@
return bp->libsym != NULL ? bp->libsym->name : NULL;
}
+struct library *
+breakpoint_library(const struct breakpoint *bp)
+{
+ assert(bp != NULL);
+ return bp->libsym != NULL ? bp->libsym->lib : NULL;
+}
+
static void
enable_bp_cb(void *addr, void *sbp, void *proc)
{
@@ -238,16 +286,37 @@
dict_apply_to_all(proc->breakpoints, disable_bp_cb, proc);
}
+struct entry_breakpoint {
+ struct breakpoint super;
+ target_address_t dyn_addr;
+};
+
static void
-entry_callback_hit(struct breakpoint *bp, struct Process *proc)
+entry_callback_hit(struct breakpoint *a, struct Process *proc)
{
+ struct entry_breakpoint *bp = (void *)a;
fprintf(stderr, "entry_callback_hit\n");
if (proc == NULL || proc->leader == NULL)
return;
- delete_breakpoint(proc, bp->addr); // xxx
+ delete_breakpoint(proc, bp->super.addr); // xxx
//enable_all_breakpoints(proc);
- linkmap_init(proc);
+ linkmap_init(proc, bp->dyn_addr);
+}
+
+int
+entry_breakpoint_init(struct Process *proc,
+ struct entry_breakpoint *bp, target_address_t addr)
+{
+ int err;
+ if ((err = breakpoint_init(&bp->super, proc, addr, NULL)) < 0)
+ return err;
+
+ static struct bp_callbacks entry_callbacks = {
+ .on_hit = entry_callback_hit,
+ };
+ bp->super.cbs = &entry_callbacks;
+ return 0;
}
int
@@ -264,30 +333,43 @@
assert(proc->leader == proc);
if (options.libcalls && proc->filename) {
- struct library *lib = ltelf_read_main_binary(proc, proc->filename);
+ struct library *lib = ltelf_read_main_binary(proc,
+ proc->filename);
+ struct entry_breakpoint *entry_bp = NULL;
+ int bp_state = 0;
+ int result = -1;
switch (lib != NULL) {
fail:
proc_remove_library(proc, lib);
library_destroy(lib);
+ switch (bp_state) {
+ case 2:
+ proc_remove_breakpoint(proc, &entry_bp->super);
+ case 1:
+ breakpoint_destroy(&entry_bp->super);
+ }
+ free(entry_bp);
case 0:
- return -1;
+ return result;
}
+
proc_add_library(proc, lib);
fprintf(stderr, "note: symbols in %s were not filtered.\n",
lib->name);
- struct breakpoint *entry_bp
- = insert_breakpoint(proc, lib->entry, NULL);
- if (entry_bp == NULL) {
- error(0, errno, "couldn't insert entry breakpoint");
+ entry_bp = malloc(sizeof(*entry_bp));
+ if (entry_bp == NULL
+ || (result = entry_breakpoint_init(proc, entry_bp,
+ lib->entry)) < 0)
goto fail;
- }
- fprintf(stderr, "setting entry_callbacks by hand, fix it\n");
- static struct bp_callbacks entry_callbacks = {
- .on_hit = entry_callback_hit,
- };
- entry_bp->cbs = &entry_callbacks;
+ ++bp_state;
+ if ((result = proc_add_breakpoint(proc, &entry_bp->super)) < 0)
+ goto fail;
+
+ ++bp_state;
+ if ((result = breakpoint_turn_on(&entry_bp->super)) < 0)
+ goto fail;
}
proc->callstack_depth = 0;
diff --git a/common.h b/common.h
index 4990920..8e7fdf7 100644
--- a/common.h
+++ b/common.h
@@ -195,7 +195,7 @@
extern size_t umovebytes (Process *proc, void * addr, void * laddr, size_t count);
extern int ffcheck(void * maddr);
extern void * sym2addr(Process *, struct library_symbol *);
-extern int linkmap_init(struct Process *);
+extern int linkmap_init(struct Process *proc, void *dyn_addr);
extern void arch_check_dbg(Process *proc);
extern int task_kill (pid_t pid, int sig);
diff --git a/library.h b/library.h
index 13b82ea..dbccb08 100644
--- a/library.h
+++ b/library.h
@@ -92,11 +92,14 @@
target_address_t base;
/* Absolute address of the entry point. Useful for main
- * binary, though I the value might be useful for the dynamic
- * linker, too (in case we ever want to do early process
- * tracing). */
+ * binary, though I suppose the value might be useful for the
+ * dynamic linker, too (in case we ever want to do early
+ * process tracing). */
target_address_t entry;
+ /* Address of PT_DYNAMIC segment. */
+ target_address_t dyn_addr;
+
/* Symbols associated with the library. */
struct library_symbol *symbols;
const char *name;
diff --git a/ltrace-elf.c b/ltrace-elf.c
index a609307..b20ea7c 100644
--- a/ltrace-elf.c
+++ b/ltrace-elf.c
@@ -346,8 +346,6 @@
lte->dyn_addr = shdr.sh_addr;
fprintf(stderr, "dyn_addr = %#lx\n", lte->dyn_addr);
- extern void *dyn_addr;
- dyn_addr = (void *)lte->dyn_addr;
lte->dyn_sz = shdr.sh_size;
data = elf_getdata(scn, NULL);
@@ -491,6 +489,7 @@
library_init(lib, libname, 1);
lib->base = (target_address_t)lte.base_addr;
lib->entry = entry;
+ lib->dyn_addr = (target_address_t)lte.dyn_addr;
size_t i;
for (i = 0; i < lte.relplt_count; ++i) {
diff --git a/proc.c b/proc.c
index 2ef50d4..46d7b7c 100644
--- a/proc.c
+++ b/proc.c
@@ -546,3 +546,38 @@
return NULL;
}
+
+int
+proc_add_breakpoint(struct Process *proc, struct breakpoint *bp)
+{
+ struct Process *leader = proc->leader;
+
+ /* Only the group leader should be getting the breakpoints and
+ * thus have ->breakpoint initialized. */
+ assert(leader != NULL);
+ assert(leader->breakpoints != NULL);
+
+ /* Make sure it wasn't inserted yet. */
+ assert(bp->proc == NULL);
+
+ debug(DEBUG_FUNCTION, "proc_insert_breakpoint(pid=%d, %s@%p)",
+ proc->pid, breakpoint_name(bp), bp->addr);
+
+ assert(dict_find_entry(leader->breakpoints, bp->addr) == NULL);
+ if (dict_enter(leader->breakpoints, bp->addr, bp) < 0) {
+ error(0, errno, "couldn't enter breakpoint %s@%p to dictionary",
+ breakpoint_name(bp), bp->addr);
+ return -1;
+ }
+
+ bp->proc = proc;
+ return 0;
+}
+
+int
+proc_remove_breakpoint(struct Process *proc, struct breakpoint *bp)
+{
+ /* XXX We can't, really. We are missing dict_remove. */
+ assert(!"Not yet implemented!");
+ abort();
+}
diff --git a/proc.h b/proc.h
index 84241bf..90e37ff 100644
--- a/proc.h
+++ b/proc.h
@@ -31,6 +31,7 @@
#include "dict.h"
struct library;
+struct breakpoint;
/* XXX Move this somewhere where it makes sense. When the mess in
* common.h is disentangled, that would actually be a good place for
@@ -190,5 +191,10 @@
void *data),
void *data);
+/* Insert BP into PROC. */
+int proc_add_breakpoint(struct Process *proc, struct breakpoint *bp);
+
+/* Remove BP from PROC. */
+int proc_remove_breakpoint(struct Process *proc, struct breakpoint *bp);
#endif /* _PROC_H_ */
diff --git a/sysdeps/linux-gnu/ppc/plt.c b/sysdeps/linux-gnu/ppc/plt.c
index d346eb6..a54632d 100644
--- a/sysdeps/linux-gnu/ppc/plt.c
+++ b/sysdeps/linux-gnu/ppc/plt.c
@@ -598,7 +598,9 @@
}
}
-/* For some symbol types, we need to set up custom callbacks. */
+/* For some symbol types, we need to set up custom callbacks. XXX we
+ * don't need PROC here, we can store the data in BP if it is of
+ * interest to us. */
int
arch_breakpoint_init(struct Process *proc, struct breakpoint *bp)
{
diff --git a/sysdeps/linux-gnu/proc.c b/sysdeps/linux-gnu/proc.c
index 1e3c86d..b533689 100644
--- a/sysdeps/linux-gnu/proc.c
+++ b/sysdeps/linux-gnu/proc.c
@@ -393,11 +393,9 @@
return;
}
-void *dyn_addr;
int
-linkmap_init(struct Process *proc)
+linkmap_init(struct Process *proc, target_address_t dyn_addr)
{
- return 0;
void *dbg_addr = NULL;
struct r_debug *rdbg = NULL;
//struct cb_data data;