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/BUGS b/BUGS
index 2f3576e..c3be4a1 100644
--- a/BUGS
+++ b/BUGS
@@ -2,4 +2,4 @@
 * Manual page is not accurate (config files...)
 * elf.c only supports elf32 binaries
 * netscape sometimes dies with SIGSEGV (is this still true?)
-* It only works on Linux/i386, Linux/m68k, and Linux/arm
+* It lacks support for several Linux archs, and many operating systems
diff --git a/Makefile.in b/Makefile.in
index 37f4873..2ca7e1f 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -21,7 +21,8 @@
 
 OBJ	=	ltrace.o options.o elf.o output.o read_config_file.o	\
 		execute_program.o wait_for_something.o process_event.o	\
-		display_args.o breakpoints.o proc.o demangle.o
+		display_args.o breakpoints.o proc.o demangle.o dict.o \
+		debug.o
 
 all:		ltrace
 
diff --git a/README b/README
index 65cb433..992d9fe 100644
--- a/README
+++ b/README
@@ -2,7 +2,7 @@
 
                        A Dynamic Library Tracer
 
-         Copyright 1997-2002 Juan Cespedes <cespedes@debian.org>
+         Copyright 1997-2003 Juan Cespedes <cespedes@debian.org>
 
 
 Contents
@@ -67,7 +67,7 @@
 
 6. License
 ----------
-    Copyright (C) 1997-2002 Juan Cespedes <cespedes@debian.org>
+    Copyright (C) 1997-2003 Juan Cespedes <cespedes@debian.org>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
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;
 }
diff --git a/config.h.in b/config.h.in
index 17769ca..1a271ed 100644
--- a/config.h.in
+++ b/config.h.in
@@ -24,8 +24,5 @@
 /* Define if you have the <getopt.h> header file.  */
 #undef HAVE_GETOPT_H
 
-/* Define if you have the dl library (-ldl).  */
-#undef HAVE_LIBDL
-
 /* Define if you have the iberty library (-liberty).  */
 #undef HAVE_LIBIBERTY
diff --git a/configure b/configure
index 9950894..0cce6dc 100755
--- a/configure
+++ b/configure
@@ -859,63 +859,16 @@
 test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
 
 
-echo $ac_n "checking for dlopen in -ldl""... $ac_c" 1>&6
-echo "configure:864: checking for dlopen in -ldl" >&5
-ac_lib_var=`echo dl'_'dlopen | sed 'y%./+-%__p_%'`
-if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
-  echo $ac_n "(cached) $ac_c" 1>&6
-else
-  ac_save_LIBS="$LIBS"
-LIBS="-ldl  $LIBS"
-cat > conftest.$ac_ext <<EOF
-#line 872 "configure"
-#include "confdefs.h"
-/* Override any gcc2 internal prototype to avoid an error.  */
-/* We use char because int might match the return type of a gcc2
-    builtin and then its argument prototype would still apply.  */
-char dlopen();
-
-int main() {
-dlopen()
-; return 0; }
-EOF
-if { (eval echo configure:883: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
-  rm -rf conftest*
-  eval "ac_cv_lib_$ac_lib_var=yes"
-else
-  echo "configure: failed program was:" >&5
-  cat conftest.$ac_ext >&5
-  rm -rf conftest*
-  eval "ac_cv_lib_$ac_lib_var=no"
-fi
-rm -f conftest*
-LIBS="$ac_save_LIBS"
-
-fi
-if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
-  echo "$ac_t""yes" 1>&6
-    ac_tr_lib=HAVE_LIB`echo dl | sed -e 's/[^a-zA-Z0-9_]/_/g' \
-    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
-  cat >> confdefs.h <<EOF
-#define $ac_tr_lib 1
-EOF
-
-  LIBS="-ldl $LIBS"
-
-else
-  echo "$ac_t""no" 1>&6
-fi
-
 echo $ac_n "checking for cplus_demangle in -liberty""... $ac_c" 1>&6
-echo "configure:911: checking for cplus_demangle in -liberty" >&5
+echo "configure:864: checking for cplus_demangle in -liberty" >&5
 ac_lib_var=`echo iberty'_'cplus_demangle | sed 'y%./+-%__p_%'`
 if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   ac_save_LIBS="$LIBS"
-LIBS="-liberty -ldl $LIBS"
+LIBS="-liberty  $LIBS"
 cat > conftest.$ac_ext <<EOF
-#line 919 "configure"
+#line 872 "configure"
 #include "confdefs.h"
 /* Override any gcc2 internal prototype to avoid an error.  */
 /* We use char because int might match the return type of a gcc2
@@ -926,7 +879,7 @@
 cplus_demangle()
 ; return 0; }
 EOF
-if { (eval echo configure:930: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:883: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   eval "ac_cv_lib_$ac_lib_var=yes"
 else
@@ -955,7 +908,7 @@
 
 
 echo $ac_n "checking ltrace version""... $ac_c" 1>&6
-echo "configure:959: checking ltrace version" >&5
+echo "configure:912: checking ltrace version" >&5
 
 ltrace_version=`sed -n '1s/ltrace (\([0-9.]\+\)).*/\1/p' ${srcdir}/debian/changelog`
 sed -e "s/@VERSION@/${ltrace_version}/g" \
@@ -965,7 +918,7 @@
 
 
 echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
-echo "configure:969: checking how to run the C preprocessor" >&5
+echo "configure:922: checking how to run the C preprocessor" >&5
 # On Suns, sometimes $CPP names a directory.
 if test -n "$CPP" && test -d "$CPP"; then
   CPP=
@@ -980,13 +933,13 @@
   # On the NeXT, cc -E runs the code through the compiler's parser,
   # not just through cpp.
   cat > conftest.$ac_ext <<EOF
-#line 984 "configure"
+#line 937 "configure"
 #include "confdefs.h"
 #include <assert.h>
 Syntax Error
 EOF
 ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:990: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:943: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
 ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
 if test -z "$ac_err"; then
   :
@@ -997,13 +950,13 @@
   rm -rf conftest*
   CPP="${CC-cc} -E -traditional-cpp"
   cat > conftest.$ac_ext <<EOF
-#line 1001 "configure"
+#line 954 "configure"
 #include "confdefs.h"
 #include <assert.h>
 Syntax Error
 EOF
 ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1007: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:960: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
 ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
 if test -z "$ac_err"; then
   :
@@ -1014,13 +967,13 @@
   rm -rf conftest*
   CPP="${CC-cc} -nologo -E"
   cat > conftest.$ac_ext <<EOF
-#line 1018 "configure"
+#line 971 "configure"
 #include "confdefs.h"
 #include <assert.h>
 Syntax Error
 EOF
 ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1024: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:977: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
 ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
 if test -z "$ac_err"; then
   :
@@ -1045,12 +998,12 @@
 echo "$ac_t""$CPP" 1>&6
 
 echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
-echo "configure:1049: checking for ANSI C header files" >&5
+echo "configure:1002: checking for ANSI C header files" >&5
 if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1054 "configure"
+#line 1007 "configure"
 #include "confdefs.h"
 #include <stdlib.h>
 #include <stdarg.h>
@@ -1058,7 +1011,7 @@
 #include <float.h>
 EOF
 ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1062: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:1015: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
 ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
 if test -z "$ac_err"; then
   rm -rf conftest*
@@ -1075,7 +1028,7 @@
 if test $ac_cv_header_stdc = yes; then
   # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
 cat > conftest.$ac_ext <<EOF
-#line 1079 "configure"
+#line 1032 "configure"
 #include "confdefs.h"
 #include <string.h>
 EOF
@@ -1093,7 +1046,7 @@
 if test $ac_cv_header_stdc = yes; then
   # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
 cat > conftest.$ac_ext <<EOF
-#line 1097 "configure"
+#line 1050 "configure"
 #include "confdefs.h"
 #include <stdlib.h>
 EOF
@@ -1114,7 +1067,7 @@
   :
 else
   cat > conftest.$ac_ext <<EOF
-#line 1118 "configure"
+#line 1071 "configure"
 #include "confdefs.h"
 #include <ctype.h>
 #define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
@@ -1125,7 +1078,7 @@
 exit (0); }
 
 EOF
-if { (eval echo configure:1129: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:1082: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
 then
   :
 else
@@ -1152,17 +1105,17 @@
 do
 ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
 echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
-echo "configure:1156: checking for $ac_hdr" >&5
+echo "configure:1109: checking for $ac_hdr" >&5
 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1161 "configure"
+#line 1114 "configure"
 #include "confdefs.h"
 #include <$ac_hdr>
 EOF
 ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1166: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:1119: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
 ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
 if test -z "$ac_err"; then
   rm -rf conftest*
@@ -1189,12 +1142,12 @@
 done
 
 echo $ac_n "checking for working const""... $ac_c" 1>&6
-echo "configure:1193: checking for working const" >&5
+echo "configure:1146: checking for working const" >&5
 if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1198 "configure"
+#line 1151 "configure"
 #include "confdefs.h"
 
 int main() {
@@ -1243,7 +1196,7 @@
 
 ; return 0; }
 EOF
-if { (eval echo configure:1247: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:1200: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
   rm -rf conftest*
   ac_cv_c_const=yes
 else
@@ -1264,12 +1217,12 @@
 fi
 
 echo $ac_n "checking for uid_t in sys/types.h""... $ac_c" 1>&6
-echo "configure:1268: checking for uid_t in sys/types.h" >&5
+echo "configure:1221: checking for uid_t in sys/types.h" >&5
 if eval "test \"`echo '$''{'ac_cv_type_uid_t'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1273 "configure"
+#line 1226 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 EOF
@@ -1298,12 +1251,12 @@
 fi
 
 echo $ac_n "checking for pid_t""... $ac_c" 1>&6
-echo "configure:1302: checking for pid_t" >&5
+echo "configure:1255: checking for pid_t" >&5
 if eval "test \"`echo '$''{'ac_cv_type_pid_t'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1307 "configure"
+#line 1260 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #if STDC_HEADERS
@@ -1333,12 +1286,12 @@
 for ac_func in getopt getopt_long
 do
 echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
-echo "configure:1337: checking for $ac_func" >&5
+echo "configure:1290: checking for $ac_func" >&5
 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1342 "configure"
+#line 1295 "configure"
 #include "confdefs.h"
 /* System header to define __stub macros and hopefully few prototypes,
     which can conflict with char $ac_func(); below.  */
@@ -1361,7 +1314,7 @@
 
 ; return 0; }
 EOF
-if { (eval echo configure:1365: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1318: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   eval "ac_cv_func_$ac_func=yes"
 else
diff --git a/configure.in b/configure.in
index 35acb4a..98dd645 100644
--- a/configure.in
+++ b/configure.in
@@ -12,8 +12,7 @@
 AC_PROG_INSTALL
 
 dnl Checks for libraries.
-AC_CHECK_LIB(dl, dlopen)
-AC_CHECK_LIB(iberty, cplus_demangle,,,-ldl)
+AC_CHECK_LIB(iberty, cplus_demangle,,,)
 
 AC_MSG_CHECKING(ltrace version)
 changequote(<<, >>)
diff --git a/debian/changelog b/debian/changelog
index 00f14b9..89b41ad 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,11 @@
+ltrace (0.3.27) unstable; urgency=low
+
+  * 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
+
+ -- Juan Cespedes <cespedes@debian.org>  Fri, 31 Jan 2003 18:58:55 +0100
+
 ltrace (0.3.26) unstable; urgency=low
 
   * Fixed `ltrace -L' in powerpc
diff --git a/debian/control b/debian/control
index 1de2c81..3e546bb 100644
--- a/debian/control
+++ b/debian/control
@@ -2,7 +2,7 @@
 Section: utils
 Priority: optional
 Maintainer: Juan Cespedes <cespedes@debian.org>
-Standards-Version: 3.5.5
+Standards-Version: 3.5.6
 Build-Depends: binutils-dev
 
 Package: ltrace
diff --git a/debian/copyright b/debian/copyright
index 1893192..31535aa 100644
--- a/debian/copyright
+++ b/debian/copyright
@@ -4,7 +4,7 @@
 
 Copyrights
 ----------
-Copyright (C) 1997-2002 Juan Cespedes <cespedes@debian.org>
+Copyright (C) 1997-2003 Juan Cespedes <cespedes@debian.org>
 
 ARMLinux port: Copyright (C) 1998 Pat Beirne <pbeirne@home.com>
 m68k port: Copyright (C) 1998 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
diff --git a/debian/rules b/debian/rules
index 6cd930a..5f7eb45 100755
--- a/debian/rules
+++ b/debian/rules
@@ -1,6 +1,6 @@
 #! /usr/bin/make -f 
 #
-# Copyright (C) 1997-2002 Juan Cespedes <cespedes@debian.org>
+# Copyright (C) 1997-2003 Juan Cespedes <cespedes@debian.org>
 
 .PHONY:		binary binary-indep binary-arch clean
 
diff --git a/debug.c b/debug.c
new file mode 100644
index 0000000..125974a
--- /dev/null
+++ b/debug.c
@@ -0,0 +1,21 @@
+#include <stdio.h>
+#include <stdarg.h>
+
+#include "debug.h"
+#include "options.h"
+#include "output.h"
+
+void
+debug_(int level, char *file, int line, char *func, char *fmt, ...) {
+	char buf[1024];
+	va_list args;
+
+	if (opt_d < level) {
+		return;
+	}
+	va_start(args, fmt);
+	vsnprintf(buf, 1024, fmt, args);
+	va_end(args);
+
+	output_line(NULL, "DEBUG: %s:%d: %s(): %s", file, line, func, buf);
+}
diff --git a/debug.h b/debug.h
new file mode 100644
index 0000000..90a10e5
--- /dev/null
+++ b/debug.h
@@ -0,0 +1,20 @@
+#include <features.h>
+
+void debug_(int level, char *file, int line, char *func, char *fmt, ...);
+
+# define debug(level, expr...) debug_(level, __FILE__, __LINE__, DEBUG_FUNCTION, expr)
+
+/* Version 2.4 and later of GCC define a magical variable `__PRETTY_FUNCTION__'
+   which contains the name of the function currently being defined.
+   This is broken in G++ before version 2.6.
+   C9x has a similar variable called __func__, but prefer the GCC one since
+   it demangles C++ function names.  */
+# if __GNUC_PREREQ (2, 4)
+#   define DEBUG_FUNCTION	__PRETTY_FUNCTION__
+# else
+#  if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L
+#   define DEBUG_FUNCTION	__func__
+#  else
+#   define DEBUG_FUNCTION	((__const char *) 0)
+#  endif
+# endif
diff --git a/demangle.c b/demangle.c
index 8f0d24e..73fbf06 100644
--- a/demangle.c
+++ b/demangle.c
@@ -12,128 +12,33 @@
 #include "output.h"
 #include "demangle.h"
 
-/*****************************************************************************/
-
-/*
-  The string dictionary code done by Morten Eriksen <mortene@sim.no>.
-
-  FIXME: since this is a generic string dictionary, it should perhaps
-  be cleaned up a bit, "object-ified" and placed in its own .c + .h
-  pair of files? 19990702 mortene.
-*/
-
-struct dict_entry
-{
-	unsigned int key;
-	const char * mangled, * demangled;
-	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 void dict_enter(const char * mangled, const char * demangled);
-static const char * dict_find_entry(const char * mangled);
-static unsigned int dict_hash_string(const char * s);
-
-
-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((void *)(entry->mangled));
-			if (entry->mangled != entry->demangled)
-				free((void *)(entry->demangled));
-			free(entry);
-		}
-		dict_buckets[i] = NULL;
-	}
-}
-
-static void
-dict_enter(const char * mangled, const char * demangled) {
-	struct dict_entry * entry, * newentry;
-	unsigned int key = dict_hash_string(mangled);
-
-	newentry = malloc(sizeof(struct dict_entry));
-	if (!newentry) {
-		perror("malloc");
-		return;
-	}
-
-	newentry->key = key;
-	newentry->mangled = mangled;
-	newentry->demangled = demangled;
-	newentry->next = NULL;
-
-	entry = dict_buckets[key % DICTTABLESIZE];
-	while (entry && entry->next) entry = entry->next;
-
-	if (entry) entry->next = newentry;
-	else dict_buckets[key % DICTTABLESIZE] = newentry;
-
-	if (opt_d > 2)
-		output_line(0, "new dict entry: '%s' -> '%s'\n", mangled, demangled);
-}
-
-static const char *
-dict_find_entry(const char * mangled) {
-	unsigned int key = dict_hash_string(mangled);
-	struct dict_entry * entry = dict_buckets[key % DICTTABLESIZE];
-	while (entry) {
-		if ((entry->key == key) && (strcmp(entry->mangled, mangled) == 0)) break;
-		entry = entry->next;
-	}
-	return entry ? entry->demangled : NULL;
-}
-
-static unsigned int
-dict_hash_string(const char * s) {
-	unsigned int total = 0, shift = 0;
-
-	while (*s) {
-		total = total ^ ((*s) << shift);
-		shift += 5;
-		if (shift > 24) shift -= 24;
-		s++;
-	}
-	return total;
-}
-
-#undef DICTTABLESIZE
+#include "dict.h"
 
 /*****************************************************************************/
 
+static struct dict * d = NULL;
+
+static void
+my_demangle_dict_clear(void) {
+	/* FIXME TODO XXX: I should also free all (key,value) pairs */
+	dict_clear(d);
+}
+
 const char *
 my_demangle(const char * function_name) {
 	const char * tmp, * fn_copy;
 
-	if (!dict_initialized) {
-		dict_init();
-		atexit(dict_clear);
+	if (!d) {
+		d = dict_init(dict_key2hash_string, dict_key_cmp_string);
+		atexit(my_demangle_dict_clear);
 	}
  
-	tmp = dict_find_entry(function_name);
+	tmp = dict_find_entry(d, (void *)function_name);
 	if (!tmp) {
 		fn_copy = strdup(function_name);
 		tmp = cplus_demangle(function_name+strspn(function_name, "_"), DMGL_ANSI | DMGL_PARAMS);
 		if (!tmp) tmp = fn_copy;
-		if (tmp) dict_enter(fn_copy, tmp);
+		if (tmp) dict_enter(d, (void *)fn_copy, (void *)tmp);
 	}
 	return tmp;
 }
diff --git a/dict.c b/dict.c
new file mode 100644
index 0000000..f428820
--- /dev/null
+++ b/dict.c
@@ -0,0 +1,151 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "debug.h"
+
+/*
+  Dictionary based on code by Morten Eriksen <mortene@sim.no>.
+*/
+
+#include "dict.h"
+
+struct dict_entry {
+	unsigned int hash;
+	void * key;
+	void * value;
+	struct dict_entry * next;
+};
+
+/* #define DICTTABLESIZE 97 */
+#define DICTTABLESIZE 997 /* Semi-randomly selected prime number. */
+/* #define DICTTABLESIZE 9973 */
+/* #define DICTTABLESIZE 99991 */
+/* #define DICTTABLESIZE 999983 */
+
+struct dict {
+	struct dict_entry * buckets[DICTTABLESIZE];
+	unsigned int (*key2hash)(void *);
+	int (*key_cmp)(void *, void *);
+};
+
+struct dict *
+dict_init(unsigned int (*key2hash)(void *), int (*key_cmp)(void *, void *)) {
+	struct dict * d;
+	int i;
+
+	d = malloc(sizeof(struct dict));
+	if (!d) {
+		perror("malloc()");
+		exit(1);
+	}
+	for (i = 0; i < DICTTABLESIZE; i++) { /* better use memset()? */
+		d->buckets[i] = NULL;
+	}
+	d->key2hash = key2hash;
+	d->key_cmp = key_cmp;
+	return d;
+}
+
+void
+dict_clear(struct dict * d) {
+	int i;
+	struct dict_entry * entry, * nextentry;
+
+	for (i = 0; i < DICTTABLESIZE; i++) {
+		for (entry = d->buckets[i]; entry != NULL; entry = nextentry) {
+			nextentry = entry->next;
+			free(entry);
+		}
+		d->buckets[i] = NULL;
+	}
+	free(d);
+}
+
+int
+dict_enter(struct dict * d, void * key, void * value) {
+	struct dict_entry * entry, * newentry;
+	unsigned int hash = d->key2hash(key);
+	unsigned int bucketpos = hash % DICTTABLESIZE;
+
+	newentry = malloc(sizeof(struct dict_entry));
+	if (!newentry) {
+		perror("malloc");
+		exit(1);
+	}
+
+	newentry->hash  = hash;
+	newentry->key   = key;
+	newentry->value = value;
+	newentry->next  = NULL;
+
+	entry = d->buckets[bucketpos];
+	while (entry && entry->next) entry = entry->next;
+
+	if (entry) entry->next = newentry;
+	else d->buckets[bucketpos] = newentry;
+
+	debug(3, "new dict entry at %p[%d]: (%p,%p)\n", d, bucketpos, key, value);
+	return 0;
+}
+
+void *
+dict_find_entry(struct dict * d, void * key) {
+	unsigned int hash = d->key2hash(key);
+	unsigned int bucketpos = hash % DICTTABLESIZE;
+	struct dict_entry * entry;
+
+	for (entry = d->buckets[bucketpos]; entry; entry = entry->next) {
+		if (hash != entry->hash) {
+			continue;
+		}
+		if (!d->key_cmp(key, entry->key)) {
+			break;
+		}
+	}
+	return entry ? entry->value : NULL;
+}
+
+void
+dict_apply_to_all(struct dict * d, void (*func)(void *key, void *value, void *data), void *data) {
+	int i;
+
+	for (i = 0; i < DICTTABLESIZE; i++) {
+		struct dict_entry * entry = d->buckets[i];
+		while (entry) {
+			func(entry->key, entry->value, data);
+			entry = entry->next;
+		}
+	}
+}
+
+/*****************************************************************************/
+
+unsigned int
+dict_key2hash_string(void * key) {
+	const char * s = (const char *)key;
+	unsigned int total = 0, shift = 0;
+
+	while (*s) {
+		total = total ^ ((*s) << shift);
+		shift += 5;
+		if (shift > 24) shift -= 24;
+		s++;
+	}
+	return total;
+}
+
+int
+dict_key_cmp_string(void * key1, void * key2) {
+	return strcmp((const char *)key1, (const char *)key2);
+}
+
+unsigned int
+dict_key2hash_int(void * key) {
+	return (unsigned int)key;
+}
+
+int
+dict_key_cmp_int(void * key1, void * key2) {
+	return key1 - key2;
+}
+
diff --git a/dict.h b/dict.h
new file mode 100644
index 0000000..6be0995
--- /dev/null
+++ b/dict.h
@@ -0,0 +1,18 @@
+/*
+  Dictionary based on code by Morten Eriksen <mortene@sim.no>.
+*/
+
+struct dict;
+
+extern struct dict * dict_init(unsigned int (*key2hash)(void *),
+		int (*key_cmp)(void *, void *));
+extern void dict_clear(struct dict * d);
+extern int dict_enter(struct dict * d, void * key, void * value);
+extern void * dict_find_entry(struct dict * d, void * key);
+extern void dict_apply_to_all(struct dict * d,
+		void (*func)(void *key, void *value, void *data), void *data);
+
+extern unsigned int dict_key2hash_string(void * key);
+extern int dict_key_cmp_string(void * key1, void * key2);
+extern unsigned int dict_key2hash_int(void * key);
+extern int dict_key_cmp_int(void * key1, void * key2);
diff --git a/elf.c b/elf.c
index b3f7a12..d1fb6ca 100644
--- a/elf.c
+++ b/elf.c
@@ -21,8 +21,7 @@
 
 #include "ltrace.h"
 #include "elf.h"
-#include "options.h"
-#include "output.h"
+#include "debug.h"
 
 static void do_init_elf(struct ltelf *lte, const char *filename);
 static void do_close_elf(struct ltelf *lte);
@@ -42,9 +41,7 @@
 do_init_elf(struct ltelf *lte, const char *filename) {
 	struct stat sbuf;
 
-	if (opt_d > 0) {
-		output_line(0, "Reading ELF from %s...", filename);
-	}
+	debug(1, "Reading ELF from %s...", filename);
 
 	lte->fd = open(filename, O_RDONLY);
 	if (lte->fd == -1) {
@@ -137,11 +134,9 @@
 		}
 	}
 
-	if (opt_d > 1) {
-		output_line(0, "symtab: 0x%08x", (unsigned)lte->symtab);
-		output_line(0, "symtab_len: %lu", lte->symtab_len);
-		output_line(0, "strtab: 0x%08x", (unsigned)lte->strtab);
-	}
+	debug(2, "symtab: 0x%08x", (unsigned)lte->symtab);
+	debug(2, "symtab_len: %lu", lte->symtab_len);
+	debug(2, "strtab: 0x%08x", (unsigned)lte->strtab);
 }
 
 static void
@@ -165,14 +160,9 @@
 	library_symbols->name = &lte->strtab[lte->symtab[i].st_name];
 	library_symbols->next = tmp;
 
-	if (opt_d > 1) {
-		output_line(
-			0,
-			"addr: 0x%08x, symbol: \"%s\"",
+	debug(2, "addr: 0x%08x, symbol: \"%s\"",
 			(unsigned)lte->symtab[i].st_value,
-			&lte->strtab[lte->symtab[i].st_name]
-		);
-	}
+			&lte->strtab[lte->symtab[i].st_name]);
 }
 
 /*
diff --git a/execute_program.c b/execute_program.c
index 0306678..6efc03c 100644
--- a/execute_program.c
+++ b/execute_program.c
@@ -13,40 +13,9 @@
 
 #include "ltrace.h"
 #include "options.h"
-#include "output.h"
+#include "debug.h"
 #include "sysdep.h"
 
-static void change_uid(struct process * proc);
-
-void
-execute_program(struct process * sp, char **argv) {
-	pid_t pid;
-
-	if (opt_d) {
-		output_line(0, "Executing `%s'...", sp->filename);
-	}
-
-	pid = fork();
-	if (pid<0) {
-		perror("ltrace: fork");
-		exit(1);
-	} else if (!pid) {	/* child */
-		change_uid(sp);
-		trace_me();
-		execvp(sp->filename, argv);
-		fprintf(stderr, "Can't execute `%s': %s\n", sp->filename, strerror(errno));
-		exit(1);
-	}
-
-	if (opt_d) {
-		output_line(0, "PID=%d", pid);
-	}
-
-	sp->pid = pid;
-
-	return;
-}
-
 static void
 change_uid(struct process * proc) {
 	uid_t run_uid, run_euid;
@@ -97,3 +66,28 @@
 		}
 	}
 }
+
+void
+execute_program(struct process * sp, char **argv) {
+	pid_t pid;
+
+	debug(1, "Executing `%s'...", sp->filename);
+
+	pid = fork();
+	if (pid<0) {
+		perror("ltrace: fork");
+		exit(1);
+	} else if (!pid) {	/* child */
+		change_uid(sp);
+		trace_me();
+		execvp(sp->filename, argv);
+		fprintf(stderr, "Can't execute `%s': %s\n", sp->filename, strerror(errno));
+		exit(1);
+	}
+
+	debug(1, "PID=%d", pid);
+
+	sp->pid = pid;
+
+	return;
+}
diff --git a/ltrace.c b/ltrace.c
index 78f74da..fbd6ca4 100644
--- a/ltrace.c
+++ b/ltrace.c
@@ -15,6 +15,7 @@
 #include "output.h"
 #include "read_config_file.h"
 #include "options.h"
+#include "debug.h"
 
 #ifndef SYSCONFDIR
 #define SYSCONFDIR "/etc"
@@ -42,9 +43,7 @@
 			}
 			tmp2 = tmp2->next;
 		}
-		if (opt_d>1) {
-			output_line(0,"Sending SIGSTOP to process %u\n",tmp->pid);
-		}
+		debug(2,"Sending SIGSTOP to process %u\n",tmp->pid);
 		kill(tmp->pid, SIGSTOP);
 		tmp = tmp->next;
 	}
@@ -53,18 +52,14 @@
 static void
 signal_exit(int sig) {
 	exiting=1;
-	if (opt_d) {
-		output_line(0,"Received interrupt signal; exiting...");
-	}
+	debug(1,"Received interrupt signal; exiting...");
 	signal(SIGINT,SIG_IGN);
 	signal(SIGTERM,SIG_IGN);
 	signal(SIGALRM,signal_alarm);
 	if (opt_p) {
 		struct opt_p_t * tmp = opt_p;
 		while(tmp) {
-			if (opt_d>1) {
-				output_line(0,"Sending SIGSTOP to process %u\n",tmp->pid);
-			}
+			debug(2,"Sending SIGSTOP to process %u\n",tmp->pid);
 			kill(tmp->pid, SIGSTOP);
 			tmp = tmp->next;
 		}
@@ -99,10 +94,10 @@
 		strcat(path, "/.ltrace.conf");
 		read_config_file(path);
 	}
-	if (opt_d && opt_e) {
+	if (opt_e) {
 		struct opt_e_t * tmp = opt_e;
 		while(tmp) {
-			printf("Option -e: %s\n", tmp->name);
+			debug(1,"Option -e: %s\n", tmp->name);
 			tmp = tmp->next;
 		}
 	}
diff --git a/ltrace.h b/ltrace.h
index 4a9a783..a0af48f 100644
--- a/ltrace.h
+++ b/ltrace.h
@@ -5,6 +5,7 @@
 #include <stdio.h>
 
 #include "defs.h"
+#include "dict.h"
 
 /* BREAKPOINT_LENGTH is defined in "sysdep.h" */
 #include "sysdep.h"
@@ -76,6 +77,7 @@
 struct process {
 	char * filename;
 	pid_t pid;
+	struct dict * breakpoints;
 	int breakpoints_enabled;	/* -1:not enabled yet, 0:disabled, 1:enabled */
 
 	int callstack_depth;
diff --git a/options.c b/options.c
index e261ab4..fa2c555 100644
--- a/options.c
+++ b/options.c
@@ -3,7 +3,7 @@
 #endif
 
 #ifndef VERSION
-# define VERSION "0.3.26"
+# define VERSION "0.3.27"
 #endif
 
 #include <string.h>
diff --git a/proc.c b/proc.c
index 3c0a936..294340d 100644
--- a/proc.c
+++ b/proc.c
@@ -23,6 +23,7 @@
 	}
 	proc->filename = filename;
 	proc->pid = 0;
+	proc->breakpoints = NULL;
 	proc->breakpoints_enabled = -1;
 	proc->callstack_depth = 0;
 	proc->breakpoint_being_enabled = NULL;
diff --git a/process_event.c b/process_event.c
index 53012f4..e314c25 100644
--- a/process_event.c
+++ b/process_event.c
@@ -13,6 +13,7 @@
 #include "output.h"
 #include "options.h"
 #include "elf.h"
+#include "debug.h"
 
 #ifdef __powerpc__
 #include <sys/ptrace.h>
@@ -34,44 +35,30 @@
 process_event(struct event * event) {
 	switch (event->thing) {
 		case LT_EV_NONE:
-			if (opt_d>0) {
-				output_line(0, "event: none");
-			}
+			debug(1, "event: none");
 			return;
 		case LT_EV_SIGNAL:
-			if (opt_d>0) {
-				output_line(0, "event: signal (%d)", event->e_un.signum);
-			}
+			debug(1, "event: signal (%d)", event->e_un.signum);
 			process_signal(event);
 			return;
 		case LT_EV_EXIT:
-			if (opt_d>0) {
-				output_line(0, "event: exit (%d)", event->e_un.ret_val);
-			}
+			debug(1, "event: exit (%d)", event->e_un.ret_val);
 			process_exit(event);
 			return;
 		case LT_EV_EXIT_SIGNAL:
-			if (opt_d>0) {
-				output_line(0, "event: exit signal (%d)", event->e_un.signum);
-			}
+			debug(1, "event: exit signal (%d)", event->e_un.signum);
 			process_exit_signal(event);
 			return;
 		case LT_EV_SYSCALL:
-			if (opt_d>0) {
-				output_line(0, "event: syscall (%d)", event->e_un.sysnum);
-			}
+			debug(1, "event: syscall (%d)", event->e_un.sysnum);
 			process_syscall(event);
 			return;
 		case LT_EV_SYSRET:
-			if (opt_d>0) {
-				output_line(0, "event: sysret (%d)", event->e_un.sysnum);
-			}
+			debug(1, "event: sysret (%d)", event->e_un.sysnum);
 			process_sysret(event);
 			return;
 		case LT_EV_BREAKPOINT:
-			if (opt_d>0) {
-				output_line(0, "event: breakpoint");
-			}
+			debug(1, "event: breakpoint");
 			process_breakpoint(event);
 			return;
 		default:
@@ -144,9 +131,7 @@
 remove_proc(struct process * proc) {
 	struct process *tmp, *tmp2;
 
-	if (opt_d) {
-		output_line(0,"Removing pid %u\n", proc->pid);
-	}
+	debug(1, "Removing pid %u\n", proc->pid);
 
 	if (list_of_processes == proc) {
 		tmp = list_of_processes;
@@ -215,9 +200,7 @@
 	struct library_symbol * tmp;
 	int i,j;
 
-	if (opt_d>1) {
-		output_line(0,"event: breakpoint (0x%08x)", event->e_un.brk_addr);
-	}
+	debug(2, "event: breakpoint (0x%08x)", event->e_un.brk_addr);
 	if (event->proc->breakpoint_being_enabled) {
 		/* Reinsert breakpoint */
 		continue_enabling_breakpoint(event->proc->pid, event->proc->breakpoint_being_enabled);
@@ -230,7 +213,7 @@
 #ifdef __powerpc__
                        unsigned long a;
                        unsigned long addr = event->proc->callstack[i].c_un.libfunc->enter_addr;
-                       struct breakpoint *sbp = dict_find_entry(event->proc, addr);
+                       struct breakpoint *sbp = address2bpstruct(event->proc, addr);
                        unsigned char break_insn[] = BREAKPOINT_VALUE;
 
                        /*
diff --git a/read_config_file.c b/read_config_file.c
index 931d9cf..2ba9099 100644
--- a/read_config_file.c
+++ b/read_config_file.c
@@ -8,8 +8,8 @@
 
 #include "ltrace.h"
 #include "read_config_file.h"
-#include "options.h"
 #include "output.h"
+#include "debug.h"
 
 /*
  *	"void"		ARGTYPE_VOID
@@ -104,20 +104,14 @@
 	int i;
 
 	line_no++;
-	if (opt_d>2) {
-		output_line(0, "Reading line %d of `%s'", line_no, filename);
-	}
+	debug(3, "Reading line %d of `%s'", line_no, filename);
 	eat_spaces(&str);
 	fun.return_type = str2type(&str);
 	if (fun.return_type==ARGTYPE_UNKNOWN) {
-		if (opt_d>2) {
-			output_line(0, " Skipping line %d", line_no);
-		}
+		debug(3, " Skipping line %d", line_no);
 		return NULL;
 	}
-	if (opt_d>3) {
-		output_line(0, " return_type = %d", fun.return_type);
-	}
+	debug(4, " return_type = %d", fun.return_type);
 	eat_spaces(&str);
 	tmp = start_of_arg_sig(str);
 	if (!tmp) {
@@ -127,9 +121,7 @@
 	*tmp = '\0';
 	fun.name = strdup(str);
 	str = tmp+1;
-	if (opt_d>2) {
-		output_line(0, " name = %s", fun.name);
-	}
+	debug(3, " name = %s", fun.name);
 	fun.params_right = 0;
 	for(i=0; i<MAX_ARGS; i++) {
 		eat_spaces(&str);
@@ -171,9 +163,7 @@
 
 	filename = file;
 
-	if (opt_d) {
-		output_line(0, "Reading config file `%s'...", filename);
-	}
+	debug(1, "Reading config file `%s'...", filename);
 
 	stream = fopen(filename, "r");
 	if (!stream) {
@@ -184,9 +174,7 @@
 		struct function * tmp = process_line(buf);
 
 		if (tmp) {
-			if (opt_d > 1) {
-				output_line(0, "New function: `%s'", tmp->name);
-			}
+			debug(2, "New function: `%s'", tmp->name);
 			tmp->next = list_of_functions;
 			list_of_functions = tmp;
 		}
diff --git a/wait_for_something.c b/wait_for_something.c
index 8a471b2..aa1372f 100644
--- a/wait_for_something.c
+++ b/wait_for_something.c
@@ -12,7 +12,7 @@
 
 #include "ltrace.h"
 #include "options.h"
-#include "output.h"
+#include "debug.h"
 
 static struct event event;
 
@@ -27,22 +27,16 @@
 	int tmp;
 
 	if (!list_of_processes) {
-		if (opt_d) {
-			output_line(0, "No more children");
-		}
+		debug(1, "No more children");
 		exit(0);
 	}
 	pid = wait(&status);
 	if (pid==-1) {
 		if (errno==ECHILD) {
-			if (opt_d) {
-				output_line(0, "No more children");
-			}
+			debug(1, "No more children");
 			exit(0);
 		} else if (errno==EINTR) {
-			if (opt_d) {
-				output_line(0, "wait received EINTR ?");
-			}
+			debug(1, "wait received EINTR ?");
 			event.thing = LT_EV_NONE;
 			return &event;
 		}
@@ -55,9 +49,7 @@
 		exit(1);
 	}
 	event.proc->instruction_pointer = NULL;
-	if (opt_d>2) {
-		output_line(0,"signal from pid %u", pid);
-	}
+	debug(3, "signal from pid %u", pid);
 	if (event.proc->breakpoints_enabled == -1) {
 		enable_all_breakpoints(event.proc);
 		event.thing = LT_EV_NONE;