Version 0.3.27

* Removed dependency on libdl (it is no longer needed)
* Wrote generic dictionary, used in demangle.c and breakpoints.c
* Added debug.c for better debugging output
diff --git a/breakpoints.c b/breakpoints.c
index 9b113a7..73dd638 100644
--- a/breakpoints.c
+++ b/breakpoints.c
@@ -2,10 +2,6 @@
 #include "config.h"
 #endif
 
-#include "ltrace.h"
-#include "options.h"
-#include "output.h"
-
 #include <stdlib.h>
 #include <assert.h>
 
@@ -13,134 +9,43 @@
 #include <sys/ptrace.h>
 #endif
 
-/*****************************************************************************/
-
-/*
-  Dictionary code done by Morten Eriksen <mortene@sim.no>.
-
-  FIXME: should we merge with dictionary code in demangle.c? 19990704 mortene.
-*/
-
-struct dict_entry {
-	struct process * proc;
-	struct breakpoint brk; /* addr field of struct is the hash key. */
-	struct dict_entry * next;
-};
-
-#define DICTTABLESIZE 997 /* Semi-randomly selected prime number. */
-static struct dict_entry * dict_buckets[DICTTABLESIZE];
-static int dict_initialized = 0;
-
-static void dict_init(void);
-static void dict_clear(void);
-static struct breakpoint * dict_enter(struct process * proc, void * brkaddr);
-struct breakpoint * dict_find_entry(struct process * proc, void * brkaddr);
-static void dict_apply_to_all(void (* func)(struct process *, struct breakpoint *, void * data), void * data);
-
-
-static void
-dict_init(void) {
-	int i;
-	/* FIXME: is this necessary? Check with ANSI C spec. 19990702 mortene. */
-	for (i = 0; i < DICTTABLESIZE; i++) dict_buckets[i] = NULL;
-	dict_initialized = 1;
-}
-
-static void
-dict_clear(void) {
-	int i;
-	struct dict_entry * entry, * nextentry;
-
-	for (i = 0; i < DICTTABLESIZE; i++) {
-		for (entry = dict_buckets[i]; entry != NULL; entry = nextentry) {
-			nextentry = entry->next;
-			free(entry);
-		}
-		dict_buckets[i] = NULL;
-	}
-}
-
-static struct breakpoint *
-dict_enter(struct process * proc, void * brkaddr) {
-	struct dict_entry * entry, * newentry;
-	unsigned int bucketpos = ((unsigned long int)brkaddr) % DICTTABLESIZE;
-
-	newentry = malloc(sizeof(struct dict_entry));
-	if (!newentry) {
-		perror("malloc");
-		return NULL;
-	}
-
-	newentry->proc = proc;
-	newentry->brk.addr = brkaddr;
-	newentry->brk.enabled = 0;
-	newentry->next = NULL;
-
-	entry = dict_buckets[bucketpos];
-	while (entry && entry->next) entry = entry->next;
-
-	if (entry) entry->next = newentry;
-	else dict_buckets[bucketpos] = newentry;
-
-	if (opt_d > 2)
-		output_line(0, "new brk dict entry at %p\n", brkaddr);
-
-	return &(newentry->brk);
-}
-
-struct breakpoint *
-dict_find_entry(struct process * proc, void * brkaddr) {
-	unsigned int bucketpos = ((unsigned long int)brkaddr) % DICTTABLESIZE;
-	struct dict_entry * entry = dict_buckets[bucketpos];
-	while (entry) {
-		if ((entry->brk.addr == brkaddr) && (entry->proc == proc)) break;
-		entry = entry->next;
-	}
-	return entry ? &(entry->brk) : NULL;
-}
-
-static void
-dict_apply_to_all(void (* func)(struct process *, struct breakpoint *, void * data), void * data) {
-	int i;
-
-	for (i = 0; i < DICTTABLESIZE; i++) {
-		struct dict_entry * entry = dict_buckets[i];
-		while (entry) {
-			func(entry->proc, &(entry->brk), data);
-			entry = entry->next;
-		}
-	}
-}
-
-#undef DICTTABLESIZE
+#include "ltrace.h"
+#include "options.h"
+#include "debug.h"
+#include "dict.h"
 
 /*****************************************************************************/
 
 struct breakpoint *
 address2bpstruct(struct process * proc, void * addr) {
-	return dict_find_entry(proc, addr);
+	return dict_find_entry(proc->breakpoints, addr);
 }
 
 void
 insert_breakpoint(struct process * proc, void * addr) {
 	struct breakpoint * sbp;
 
-	if (!dict_initialized) {
-		dict_init();
-		atexit(dict_clear);
+	if (!proc->breakpoints) {
+		proc->breakpoints = dict_init(dict_key2hash_int, dict_key_cmp_int);
+		/* atexit(brk_dict_clear); */ /* why bother to do this on exit? */
 	}
-
-	sbp = dict_find_entry(proc, addr);
-	if (!sbp) sbp = dict_enter(proc, addr);
-	if (!sbp) return;
-
+	sbp = dict_find_entry(proc->breakpoints, addr);
+	if (!sbp) {
+		sbp = malloc(sizeof(struct breakpoint));
+		if (!sbp) {
+			return; /* TODO FIXME XXX: error_mem */
+		}
+		dict_enter(proc->breakpoints, addr, sbp);
+		sbp->addr = addr;
+		sbp->enabled = 0;
+	}
 	sbp->enabled++;
 	if (sbp->enabled==1 && proc->pid) enable_breakpoint(proc->pid, sbp);
 }
 
 void
 delete_breakpoint(struct process * proc, void * addr) {
-	struct breakpoint * sbp = dict_find_entry(proc, addr);
+	struct breakpoint * sbp = dict_find_entry(proc->breakpoints, addr);
 	assert(sbp); /* FIXME: remove after debugging has been done. */
 	/* This should only happen on out-of-memory conditions. */
 	if (sbp == NULL) return;
@@ -151,9 +56,10 @@
 }
 
 static void
-enable_bp_cb(struct process * proc, struct breakpoint * sbp, void * data) {
-	struct process * myproc = (struct process *)data;
-	if (myproc == proc && sbp->enabled) enable_breakpoint(proc->pid, sbp);
+enable_bp_cb(void * addr, void * sbp, void * proc) {
+	if (((struct breakpoint *)sbp)->enabled) {
+		enable_breakpoint(((struct process *)proc)->pid, sbp);
+	}
 }
 
 void
@@ -174,27 +80,24 @@
 		}
 #endif
 
-		if (opt_d>0) {
-			output_line(0, "Enabling breakpoints for pid %u...", proc->pid);
-		}
-		dict_apply_to_all(enable_bp_cb, proc);
+		debug(1, "Enabling breakpoints for pid %u...", proc->pid);
+		dict_apply_to_all(proc->breakpoints, enable_bp_cb, proc);
 	}
 	proc->breakpoints_enabled = 1;
 }
 
 static void
-disable_bp_cb(struct process * proc, struct breakpoint * sbp, void * data) {
-	struct process * myproc = (struct process *)data;
-	if (myproc == proc && sbp->enabled) disable_breakpoint(proc->pid, sbp);
+disable_bp_cb(void * addr, void * sbp, void * proc) {
+	if (((struct breakpoint *)sbp)->enabled) {
+		disable_breakpoint(((struct process *)proc)->pid, sbp);
+	}
 }
 
 void
 disable_all_breakpoints(struct process * proc) {
 	if (proc->breakpoints_enabled) {
-		if (opt_d>0) {
-			output_line(0, "Disabling breakpoints for pid %u...", proc->pid);
-		}
-		dict_apply_to_all(disable_bp_cb, proc);
+		debug(1, "Disabling breakpoints for pid %u...", proc->pid);
+		dict_apply_to_all(proc->breakpoints, disable_bp_cb, proc);
 	}
 	proc->breakpoints_enabled = 0;
 }