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;