better debugging support (-d option)
diff --git a/breakpoints.c b/breakpoints.c
index 968d1f1..7112d49 100644
--- a/breakpoints.c
+++ b/breakpoints.c
@@ -20,6 +20,7 @@
 
 Breakpoint *
 address2bpstruct(Process *proc, void *addr) {
+	debug(DEBUG_FUNCTION, "address2bpstruct(pid=%d, addr=%p)", proc->pid, addr);
 	return dict_find_entry(proc->breakpoints, addr);
 }
 
@@ -27,6 +28,8 @@
 insert_breakpoint(Process *proc, void *addr,
 		  struct library_symbol *libsym) {
 	Breakpoint *sbp;
+
+	debug(DEBUG_FUNCTION, "insert_breakpoint(pid=%d, addr=%p, symbol=%s)", proc->pid, addr, libsym ? libsym->name : "NULL");
 	debug(1, "symbol=%s, addr=%p", libsym?libsym->name:"(nil)", addr);
 
 	if (!addr)
@@ -56,7 +59,11 @@
 
 void
 delete_breakpoint(Process *proc, void *addr) {
-	Breakpoint *sbp = dict_find_entry(proc->breakpoints, addr);
+	Breakpoint *sbp;
+
+	debug(DEBUG_FUNCTION, "delete_breakpoint(pid=%d, addr=%p)", proc->pid, addr);
+
+	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)
@@ -70,6 +77,7 @@
 
 static void
 enable_bp_cb(void *addr, void *sbp, void *proc) {
+	debug(DEBUG_FUNCTION, "enable_bp_cb(pid=%d)", ((Process *)proc)->pid);
 	if (((Breakpoint *)sbp)->enabled) {
 		enable_breakpoint(((Process *)proc)->pid, sbp);
 	}
@@ -77,6 +85,7 @@
 
 void
 enable_all_breakpoints(Process *proc) {
+	debug(DEBUG_FUNCTION, "enable_all_breakpoints(pid=%d)", proc->pid);
 	if (proc->breakpoints_enabled <= 0) {
 #ifdef __powerpc__
 		unsigned long a;
@@ -133,6 +142,7 @@
 
 static void
 disable_bp_cb(void *addr, void *sbp, void *proc) {
+	debug(DEBUG_FUNCTION, "disable_bp_cb(pid=%d)", ((Process *)proc)->pid);
 	if (((Breakpoint *)sbp)->enabled) {
 		disable_breakpoint(((Process *)proc)->pid, sbp);
 	}
@@ -140,6 +150,7 @@
 
 void
 disable_all_breakpoints(Process *proc) {
+	debug(DEBUG_FUNCTION, "disable_all_breakpoints(pid=%d)", proc->pid);
 	if (proc->breakpoints_enabled) {
 		debug(1, "Disabling breakpoints for pid %u...", proc->pid);
 		dict_apply_to_all(proc->breakpoints, disable_bp_cb, proc);
@@ -149,6 +160,7 @@
 
 static void
 free_bp_cb(void *addr, void *sbp, void *data) {
+	debug(DEBUG_FUNCTION, "free_bp_cb(sbp=%p)", sbp);
 	assert(sbp);
 	free(sbp);
 }
@@ -157,6 +169,7 @@
 breakpoints_init(Process *proc) {
 	struct library_symbol *sym;
 
+	debug(DEBUG_FUNCTION, "breakpoints_init(pid=%d)", proc->pid);
 	if (proc->breakpoints) {	/* let's remove that struct */
 		dict_apply_to_all(proc->breakpoints, free_bp_cb, NULL);
 		dict_clear(proc->breakpoints);
@@ -198,7 +211,11 @@
 
 void
 reinitialize_breakpoints(Process *proc) {
-	struct library_symbol *sym = proc->list_of_symbols;
+	struct library_symbol *sym;
+
+	debug(DEBUG_FUNCTION, "reinitialize_breakpoints(pid=%d)", proc->pid);
+
+	sym = proc->list_of_symbols;
 
 	while (sym) {
 		if (sym->needs_init) {
diff --git a/debug.c b/debug.c
index c31a9a9..e6b9748 100644
--- a/debug.c
+++ b/debug.c
@@ -6,19 +6,18 @@
 #include "output.h"
 
 void
-debug_(int level, const char *file, int line, const char *func,
-		const char *fmt, ...) {
+debug_(int level, const char *file, int line, const char *fmt, ...) {
 	char buf[1024];
 	va_list args;
 
-	if (options.debug < level) {
+	if (!(options.debug & 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);
+	output_line(NULL, "DEBUG: %s:%d: %s", file, line, buf);
 }
 
 // The following section provides a way to print things, like hex dumps,
diff --git a/debug.h b/debug.h
index 7a9761b..6b30e6a 100644
--- a/debug.h
+++ b/debug.h
@@ -1,23 +1,17 @@
 #include <features.h>
 
-void debug_(int level, const char *file, int line, const char *func,
-		const char *fmt, ...) __attribute__((format(printf,5,6)));
+/* debug levels:
+ */
+enum {
+	DEBUG_EVENT    = 0x10,
+	DEBUG_PROCESS  = 0x20,
+	DEBUG_FUNCTION = 0x40
+};
+
+void debug_(int level, const char *file, int line,
+		const char *fmt, ...) __attribute__((format(printf,4,5)));
 
 int xinfdump(long, void *, int);
 
-# define debug(level, expr...) debug_(level, __FILE__, __LINE__, DEBUG_FUNCTION, expr)
+# define debug(level, expr...) debug_(level, __FILE__, __LINE__, 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	"???"
-#  endif
-# endif
diff --git a/demangle.c b/demangle.c
index 8626fe3..35fd63b 100644
--- a/demangle.c
+++ b/demangle.c
@@ -9,6 +9,7 @@
 #include "options.h"
 #include "output.h"
 #include "demangle.h"
+#include "debug.h"
 
 #include "dict.h"
 
@@ -26,6 +27,8 @@
 	int status = 0;
 #endif
 
+	debug(DEBUG_FUNCTION, "my_demangle(name=%s)", function_name);
+
 	if (!d)
 		d = dict_init(dict_key2hash_string, dict_key_cmp_string);
 
diff --git a/dict.c b/dict.c
index 0f44f5d..e55d367 100644
--- a/dict.c
+++ b/dict.c
@@ -36,6 +36,8 @@
 	struct dict *d;
 	int i;
 
+	debug(DEBUG_FUNCTION, "dict_init()");
+
 	d = malloc(sizeof(struct dict));
 	if (!d) {
 		perror("malloc()");
@@ -54,6 +56,7 @@
 	int i;
 	struct dict_entry *entry, *nextentry;
 
+	debug(DEBUG_FUNCTION, "dict_clear()");
 	assert(d);
 	for (i = 0; i < DICTTABLESIZE; i++) {
 		for (entry = d->buckets[i]; entry != NULL; entry = nextentry) {
@@ -68,8 +71,13 @@
 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;
+	unsigned int hash;
+	unsigned int bucketpos;
+
+	debug(DEBUG_FUNCTION, "dict_enter()");
+
+	hash = d->key2hash(key);
+	bucketpos = hash % DICTTABLESIZE;
 
 	assert(d);
 	newentry = malloc(sizeof(struct dict_entry));
@@ -98,10 +106,15 @@
 
 void *
 dict_find_entry(struct dict *d, void *key) {
-	unsigned int hash = d->key2hash(key);
-	unsigned int bucketpos = hash % DICTTABLESIZE;
+	unsigned int hash;
+	unsigned int bucketpos;
 	struct dict_entry *entry;
 
+	debug(DEBUG_FUNCTION, "dict_find_entry()");
+
+	hash = d->key2hash(key);
+	bucketpos = hash % DICTTABLESIZE;
+
 	assert(d);
 	for (entry = d->buckets[bucketpos]; entry; entry = entry->next) {
 		if (hash != entry->hash) {
@@ -119,6 +132,8 @@
 		  void (*func) (void *key, void *value, void *data), void *data) {
 	int i;
 
+	debug(DEBUG_FUNCTION, "dict_apply_to_all()");
+
 	if (!d) {
 		return;
 	}
@@ -171,6 +186,8 @@
 	struct dict *d;
 	int i;
 
+	debug(DEBUG_FUNCTION, "dict_clone()");
+
 	d = malloc(sizeof(struct dict));
 	if (!d) {
 		perror("malloc()");
diff --git a/elf.c b/elf.c
index 27ce1b0..ff9e26f 100644
--- a/elf.c
+++ b/elf.c
@@ -35,6 +35,7 @@
 	GElf_Addr relplt_addr = 0;
 	size_t relplt_size = 0;
 
+	debug(DEBUG_FUNCTION, "do_init_elf(filename=%s)", filename);
 	debug(1, "Reading ELF from %s...", filename);
 
 	memset(lte, 0, sizeof(*lte));
@@ -320,6 +321,7 @@
 
 static void
 do_close_elf(struct ltelf *lte) {
+	debug(DEBUG_FUNCTION, "do_close_elf()");
 	if (lte->lte_flags & LTE_HASH_MALLOCED)
 		free((char *)lte->hash);
 	elf_end(lte->elf);
@@ -331,6 +333,9 @@
 		   struct library_symbol **library_symbolspp,
 		   enum toplt type_of_plt, int is_weak) {
 	struct library_symbol *s;
+
+	debug(DEBUG_FUNCTION, "add_library_symbol()");
+
 	s = malloc(sizeof(struct library_symbol) + strlen(name) + 1);
 	if (s == NULL)
 		error(EXIT_FAILURE, errno, "add_library_symbol failed");
@@ -460,6 +465,8 @@
 	struct library_symbol **lib_tail = NULL;
 	int exit_out = 0;
 
+	debug(DEBUG_FUNCTION, "read_elf(file=%s)", proc->filename);
+
 	elf_version(EV_CURRENT);
 
 	do_init_elf(lte, proc->filename);
diff --git a/ltrace.1 b/ltrace.1
index 04a1503..e24b16c 100644
--- a/ltrace.1
+++ b/ltrace.1
@@ -6,7 +6,7 @@
 
 .SH SYNOPSIS
 .B ltrace
-.I "[-CdfhiLrStttV] [-a column] [-A maxelts] [-e expr] [-l filename] [-n nr] [-o filename] [-p pid] ... [-s strsize] [-u username] [-X extern] [-x extern] ... [--align=column] [--debug] [--demangle] [--help] [--indent=nr] [--library=filename] [--output=filename] [--version] [command [arg ...]]"
+.I "[-CfhiLrStttV] [-a column] [-A maxelts] [-d level] [-e expr] [-l filename] [-n nr] [-o filename] [-p pid] ... [-s strsize] [-u username] [-X extern] [-x extern] ... [--align=column] [--debug=level] [--demangle] [--help] [--indent=nr] [--library=filename] [--output=filename] [--version] [command [arg ...]]"
 
 .SH DESCRIPTION
 .B ltrace
@@ -36,11 +36,20 @@
 Besides removing any initial underscore prefix used by the system,
 this makes C++ function names readable.
 .TP
-.I \-d, \-\-debug
-Increase the debugging level.
-Use more (ie.
-.I \-dd
-) for greater debugging information.
+.I \-d, \-\-debug level
+Show debugging output of
+.B ltrace
+itself.
+.I level
+must be a sum of some of the following numbers:
+.RS
+.TP
+.B 0x10
+DEBUG_EVENT.  Shows every event received by a traced program
+.TP
+.B 0x20
+DEBUG_PROCESS.  Shows every action carried out in a traced program
+.RE
 .TP
 .I \-e expr
 A qualifying expression which modifies which events to trace.
diff --git a/options.c b/options.c
index e954eeb..042eb7a 100644
--- a/options.c
+++ b/options.c
@@ -93,9 +93,9 @@
 #  endif
 # endif
 # if HAVE_GETOPT_LONG
-		"  -d, --debug         print debugging info.\n"
+		"  -d, --debug=LEVEL   print debugging info.\n"
 # else
-		"  -d                  print debugging info.\n"
+		"  -d LEVEL            print debugging info.\n"
 # endif
 		"  -e expr             modify which events to trace.\n"
 		"  -f                  trace children (fork() and clone()).\n"
@@ -226,18 +226,18 @@
 			{"version", 0, 0, 'V'},
 			{0, 0, 0, 0}
 		};
-		c = getopt_long(argc, argv, "+cdfhiLrStTV"
+		c = getopt_long(argc, argv, "+cfhiLrStTV"
 # ifdef USE_DEMANGLE
 				"C"
 # endif
-				"a:A:e:F:l:n:o:p:s:u:x:X:", long_options,
+				"a:A:d:e:F:l:n:o:p:s:u:x:X:", long_options,
 				&option_index);
 #else
-		c = getopt(argc, argv, "+cdfhiLrStTV"
+		c = getopt(argc, argv, "+cfhiLrStTV"
 # ifdef USE_DEMANGLE
 				"C"
 # endif
-				"a:A:e:F:l:n:o:p:s:u:x:X:");
+				"a:A:d:e:F:l:n:o:p:s:u:x:X:");
 #endif
 		if (c == -1) {
 			break;
@@ -258,7 +258,7 @@
 			break;
 #endif
 		case 'd':
-			options.debug++;
+			options.debug = strtoul(optarg,NULL,0);
 			break;
 		case 'e':
 			{
diff --git a/process_event.c b/process_event.c
index d15d8f7..94ecaac 100644
--- a/process_event.c
+++ b/process_event.c
@@ -40,11 +40,13 @@
 
 /* TODO */
 void * address_clone(void * addr) {
+	debug(DEBUG_FUNCTION, "address_clone(%p)", addr);
 	return addr;
 }
 
 void * breakpoint_clone(void * bp) {
 	Breakpoint * b;
+	debug(DEBUG_FUNCTION, "breakpoint_clone(%p)", bp);
 	b = malloc(sizeof(Breakpoint));
 	if (!b) {
 		perror("malloc()");
@@ -63,7 +65,11 @@
 
 static int
 pending_new(pid_t pid) {
-	Pending_New * p = pending_news;
+	Pending_New * p;
+
+	debug(DEBUG_FUNCTION, "pending_new(%d)", pid);
+
+	p = pending_news;
 	while (p) {
 		if (p->pid == pid) {
 			return 1;
@@ -75,7 +81,11 @@
 
 static void
 pending_new_insert(pid_t pid) {
-	Pending_New * p = malloc(sizeof(Pending_New));
+	Pending_New * p;
+
+	debug(DEBUG_FUNCTION, "pending_new_insert(%d)", pid);
+
+	p = malloc(sizeof(Pending_New));
 	if (!p) {
 		perror("malloc()");
 		exit(1);
@@ -89,6 +99,8 @@
 pending_new_remove(pid_t pid) {
 	Pending_New *p, *pred;
 
+	debug(DEBUG_FUNCTION, "pending_new_remove(%d)", pid);
+
 	p = pending_news;
 	if (p->pid == pid) {
 		pending_news = p->next;
@@ -109,6 +121,8 @@
 process_clone(Event * event) {
 	Process *p;
 
+	debug(DEBUG_FUNCTION, "process_clone(pid=%d)", event->proc->pid);
+
 	p = malloc(sizeof(Process));
 	if (!p) {
 		perror("malloc()");
@@ -136,7 +150,11 @@
 
 static void
 process_new(Event * event) {
-	Process * proc = pid2proc(event->e_un.newpid);
+	Process * proc;
+
+	debug(DEBUG_FUNCTION, "process_new(pid=%d)", event->e_un.newpid);
+
+	proc = pid2proc(event->e_un.newpid);
 	if (!proc) {
 		pending_new_insert(event->e_un.newpid);
 	} else {
@@ -163,6 +181,8 @@
 		sizeof signalent1 / sizeof signalent1[0]
 	};
 
+	debug(DEBUG_FUNCTION, "shortsignal(pid=%d, signum=%d)", proc->pid, signum);
+
 	if (proc->personality > sizeof signalents / sizeof signalents[0])
 		abort();
 	if (signum < 0 || signum >= nsignals[proc->personality]) {
@@ -186,6 +206,8 @@
 		sizeof syscalent1 / sizeof syscalent1[0]
 	};
 
+	debug(DEBUG_FUNCTION, "sysname(pid=%d, sysnum=%d)", proc->pid, sysnum);
+
 	if (proc->personality > sizeof syscalents / sizeof syscalents[0])
 		abort();
 	if (sysnum < 0 || sysnum >= nsyscals[proc->personality]) {
@@ -206,6 +228,8 @@
 	};
 	int nsyscals = sizeof arch_syscalent / sizeof arch_syscalent[0];
 
+	debug(DEBUG_FUNCTION, "arch_sysname(pid=%d, sysnum=%d)", proc->pid, sysnum);
+
 	if (sysnum < 0 || sysnum >= nsyscals) {
 		sprintf(result, "ARCH_%d", sysnum);
 		return result;
@@ -218,6 +242,7 @@
 
 void
 process_event(Event *event) {
+	debug(DEBUG_FUNCTION, "process_event(pid=%d, type=%d)", event->proc ? event->proc->pid : -1, event->type);
 	switch (event->type) {
 	case EVENT_NONE:
 		debug(1, "event: none");
@@ -286,6 +311,7 @@
 
 static void
 process_signal(Event *event) {
+	debug(DEBUG_FUNCTION, "process_signal(pid=%d, signum=%d)", event->proc->pid, event->e_un.signum);
 	if (exiting && event->e_un.signum == SIGSTOP) {
 		pid_t pid = event->proc->pid;
 		disable_all_breakpoints(event->proc);
@@ -301,6 +327,7 @@
 
 static void
 process_exit(Event *event) {
+	debug(DEBUG_FUNCTION, "process_exit(pid=%d, status=%d)", event->proc->pid, event->e_un.ret_val);
 	output_line(event->proc, "+++ exited (status %d) +++",
 		    event->e_un.ret_val);
 	remove_proc(event->proc);
@@ -308,6 +335,7 @@
 
 static void
 process_exit_signal(Event *event) {
+	debug(DEBUG_FUNCTION, "process_exit_signal(pid=%d, signum=%d)", event->proc->pid, event->e_un.signum);
 	output_line(event->proc, "+++ killed by %s +++",
 		    shortsignal(event->proc, event->e_un.signum));
 	remove_proc(event->proc);
@@ -317,7 +345,7 @@
 remove_proc(Process *proc) {
 	Process *tmp, *tmp2;
 
-	debug(1, "Removing pid %u\n", proc->pid);
+	debug(DEBUG_FUNCTION, "remove_proc(pid=%d)", proc->pid);
 
 	if (list_of_processes == proc) {
 		tmp = list_of_processes;
@@ -339,6 +367,7 @@
 
 static void
 process_syscall(Event *event) {
+	debug(DEBUG_FUNCTION, "process_syscall(pid=%d, sysnum=%d)", event->proc->pid, event->e_un.sysnum);
 	if (options.syscalls) {
 		output_left(LT_TOF_SYSCALL, event->proc,
 			    sysname(event->proc, event->e_un.sysnum));
@@ -352,12 +381,14 @@
 
 static void
 process_exec(Event * event) {
+	debug(DEBUG_FUNCTION, "process_exec(pid=%d)", event->proc->pid);
 	output_line(event->proc, "--- exec() ---");
 	abort();
 }
 
 static void
 process_arch_syscall(Event *event) {
+	debug(DEBUG_FUNCTION, "process_arch_syscall(pid=%d, sysnum=%d)", event->proc->pid, event->e_un.sysnum);
 	if (options.syscalls) {
 		output_left(LT_TOF_SYSCALL, event->proc,
 				arch_sysname(event->proc, event->e_un.sysnum));
@@ -378,6 +409,7 @@
 	struct timeval diff;
 	struct callstack_element *elem;
 
+	debug(DEBUG_FUNCTION, "calc_time_spent(pid=%d)", proc->pid);
 	elem = &proc->callstack[proc->callstack_depth - 1];
 
 	gettimeofday(&tv, &tz);
@@ -394,6 +426,7 @@
 
 static void
 process_sysret(Event *event) {
+	debug(DEBUG_FUNCTION, "process_sysret(pid=%d, sysnum=%d)", event->proc->pid, event->e_un.sysnum);
 	if (opt_T || options.summary) {
 		calc_time_spent(event->proc);
 	}
@@ -407,6 +440,7 @@
 
 static void
 process_arch_sysret(Event *event) {
+	debug(DEBUG_FUNCTION, "process_arch_sysret(pid=%d, sysnum=%d)", event->proc->pid, event->e_un.sysnum);
 	if (opt_T || options.summary) {
 		calc_time_spent(event->proc);
 	}
@@ -423,6 +457,7 @@
 	int i, j;
 	Breakpoint *sbp;
 
+	debug(DEBUG_FUNCTION, "process_breakpoint(pid=%d, addr=%p)", event->proc->pid, event->e_un.brk_addr);
 	debug(2, "event: breakpoint (%p)", event->e_un.brk_addr);
 
 #ifdef __powerpc__
@@ -552,6 +587,7 @@
 callstack_push_syscall(Process *proc, int sysnum) {
 	struct callstack_element *elem;
 
+	debug(DEBUG_FUNCTION, "callstack_push_syscall(pid=%d, sysnum=%d)", proc->pid, sysnum);
 	/* FIXME: not good -- should use dynamic allocation. 19990703 mortene. */
 	if (proc->callstack_depth == MAX_CALLDEPTH - 1) {
 		fprintf(stderr, "Error: call nesting too deep!\n");
@@ -574,6 +610,7 @@
 callstack_push_symfunc(Process *proc, struct library_symbol *sym) {
 	struct callstack_element *elem;
 
+	debug(DEBUG_FUNCTION, "callstack_push_symfunc(pid=%d, symbol=%s)", proc->pid, sym->name);
 	/* FIXME: not good -- should use dynamic allocation. 19990703 mortene. */
 	if (proc->callstack_depth == MAX_CALLDEPTH - 1) {
 		fprintf(stderr, "Error: call nesting too deep!\n");
@@ -601,6 +638,7 @@
 	struct callstack_element *elem;
 	assert(proc->callstack_depth > 0);
 
+	debug(DEBUG_FUNCTION, "callstack_pop(pid=%d)", proc->pid);
 	elem = &proc->callstack[proc->callstack_depth - 1];
 	if (!elem->is_syscall && elem->return_addr) {
 		delete_breakpoint(proc, elem->return_addr);
diff --git a/sysdeps/linux-gnu/breakpoint.c b/sysdeps/linux-gnu/breakpoint.c
index 5a56bd3..64b70e4 100644
--- a/sysdeps/linux-gnu/breakpoint.c
+++ b/sysdeps/linux-gnu/breakpoint.c
@@ -15,6 +15,11 @@
 extern void arch_enable_breakpoint(pid_t, Breakpoint *);
 void
 enable_breakpoint(pid_t pid, Breakpoint *sbp) {
+	if (sbp->libsym) {
+		debug(DEBUG_PROCESS, "enable_breakpoint: pid=%d, addr=%p, symbol=%s", pid, sbp->addr, sbp->libsym->name);
+	} else {
+		debug(DEBUG_PROCESS, "enable_breakpoint: pid=%d, addr=%p", pid, sbp->addr);
+	}
 	arch_enable_breakpoint(pid, sbp);
 }
 #else
@@ -22,7 +27,11 @@
 enable_breakpoint(pid_t pid, Breakpoint *sbp) {
 	unsigned int i, j;
 
-	debug(1, "enable_breakpoint(%d,%p)", pid, sbp->addr);
+	if (sbp->libsym) {
+		debug(DEBUG_PROCESS, "enable_breakpoint: pid=%d, addr=%p, symbol=%s", pid, sbp->addr, sbp->libsym->name);
+	} else {
+		debug(DEBUG_PROCESS, "enable_breakpoint: pid=%d, addr=%p", pid, sbp->addr);
+	}
 
 	for (i = 0; i < 1 + ((BREAKPOINT_LENGTH - 1) / sizeof(long)); i++) {
 		long a =
@@ -45,6 +54,11 @@
 extern void arch_disable_breakpoint(pid_t, const Breakpoint *sbp);
 void
 disable_breakpoint(pid_t pid, const Breakpoint *sbp) {
+	if (sbp->libsym) {
+		debug(DEBUG_PROCESS, "disable_breakpoint: pid=%d, addr=%p, symbol=%s", pid, sbp->addr, sbp->libsym->name);
+	} else {
+		debug(DEBUG_PROCESS, "disable_breakpoint: pid=%d, addr=%p", pid, sbp->addr);
+	}
 	arch_disable_breakpoint(pid, sbp);
 }
 #else
@@ -52,7 +66,11 @@
 disable_breakpoint(pid_t pid, const Breakpoint *sbp) {
 	unsigned int i, j;
 
-	debug(2, "disable_breakpoint(%d,%p)", pid, sbp->addr);
+	if (sbp->libsym) {
+		debug(DEBUG_PROCESS, "disable_breakpoint: pid=%d, addr=%p, symbol=%s", pid, sbp->addr, sbp->libsym->name);
+	} else {
+		debug(DEBUG_PROCESS, "disable_breakpoint: pid=%d, addr=%p", pid, sbp->addr);
+	}
 
 	for (i = 0; i < 1 + ((BREAKPOINT_LENGTH - 1) / sizeof(long)); i++) {
 		long a =
diff --git a/sysdeps/linux-gnu/events.c b/sysdeps/linux-gnu/events.c
index dfb8284..6dedcc9 100644
--- a/sysdeps/linux-gnu/events.c
+++ b/sysdeps/linux-gnu/events.c
@@ -25,17 +25,18 @@
 	int tmp;
 	int stop_signal;
 
+	debug(DEBUG_FUNCTION, "next_event()");
 	if (!list_of_processes) {
-		debug(1, "No more children");
+		debug(DEBUG_EVENT, "event: No more traced programs: exiting");
 		exit(0);
 	}
 	pid = wait(&status);
 	if (pid == -1) {
 		if (errno == ECHILD) {
-			debug(1, "No more children");
+			debug(DEBUG_EVENT, "event: No more traced programs: exiting");
 			exit(0);
 		} else if (errno == EINTR) {
-			debug(1, "wait received EINTR ?");
+			debug(DEBUG_EVENT, "event: none (wait received EINTR?)");
 			event.type = EVENT_NONE;
 			return &event;
 		}
@@ -45,6 +46,7 @@
 	event.proc = pid2proc(pid);
 	if (!event.proc) {
 		event.type = EVENT_NEW;
+		debug(DEBUG_EVENT, "event: NEW: pid=%d", pid);
 		return &event;
 	}
 	get_arch_dep(event.proc);
@@ -55,6 +57,7 @@
 		event.type = EVENT_NONE;
 		trace_set_options(event.proc, event.proc->pid);
 		continue_process(event.proc->pid);
+		debug(DEBUG_EVENT, "event: NONE: pid=%d (enabling breakpoints)", pid);
 		return &event;
 	}
 	if (opt_i) {
@@ -65,22 +68,27 @@
 		case 1:
 			event.type = EVENT_SYSCALL;
 			event.e_un.sysnum = tmp;
+			debug(DEBUG_EVENT, "event: SYSCALL: pid=%d, sysnum=%d", pid, tmp);
 			return &event;
 		case 2:
 			event.type = EVENT_SYSRET;
 			event.e_un.sysnum = tmp;
+			debug(DEBUG_EVENT, "event: SYSRET: pid=%d, sysnum=%d", pid, tmp);
 			return &event;
 		case 3:
 			event.type = EVENT_ARCH_SYSCALL;
 			event.e_un.sysnum = tmp;
+			debug(DEBUG_EVENT, "event: ARCH_SYSCALL: pid=%d, sysnum=%d", pid, tmp);
 			return &event;
 		case 4:
 			event.type = EVENT_ARCH_SYSRET;
 			event.e_un.sysnum = tmp;
+			debug(DEBUG_EVENT, "event: ARCH_SYSRET: pid=%d, sysnum=%d", pid, tmp);
 			return &event;
 		case -1:
 			event.type = EVENT_NONE;
 			continue_process(event.proc->pid);
+			debug(DEBUG_EVENT, "event: NONE: pid=%d (syscall_p returned -1)", pid);
 			return &event;
 	}
 	if (WIFSTOPPED(status) && ((status>>16 == PTRACE_EVENT_FORK) || (status>>16 == PTRACE_EVENT_VFORK) || (status>>16 == PTRACE_EVENT_CLONE))) {
@@ -88,24 +96,29 @@
 		ptrace(PTRACE_GETEVENTMSG, pid, NULL, &data);
 		event.type = EVENT_CLONE;
 		event.e_un.newpid = data;
+		debug(DEBUG_EVENT, "event: CLONE: pid=%d, newpid=%d", pid, (int)data);
 		return &event;
 	}
 	if (WIFSTOPPED(status) && (status>>16 == PTRACE_EVENT_EXEC)) {
 		event.type = EVENT_EXEC;
+		debug(DEBUG_EVENT, "event: EXEC: pid=%d", pid);
 		return &event;
 	}
 	if (WIFEXITED(status)) {
 		event.type = EVENT_EXIT;
 		event.e_un.ret_val = WEXITSTATUS(status);
+		debug(DEBUG_EVENT, "event: EXIT: pid=%d, status=%d", pid, event.e_un.ret_val);
 		return &event;
 	}
 	if (WIFSIGNALED(status)) {
 		event.type = EVENT_EXIT_SIGNAL;
 		event.e_un.signum = WTERMSIG(status);
+		debug(DEBUG_EVENT, "event: EXIT_SIGNAL: pid=%d, signum=%d", pid, event.e_un.signum);
 		return &event;
 	}
 	if (!WIFSTOPPED(status)) {
 		event.type = EVENT_NONE;
+		debug(DEBUG_EVENT, "event: NONE: pid=%d (wait error?)", pid);
 		return &event;
 	}
 
@@ -133,6 +146,7 @@
 	    && stop_signal != SIGTRAP) {
 		event.type = EVENT_SIGNAL;
 		event.e_un.signum = stop_signal;
+		debug(DEBUG_EVENT, "event: SIGNAL: pid=%d, signum=%d", pid, stop_signal);
 		return &event;
 	}
 
@@ -151,6 +165,7 @@
 		breakpoints_init(event.proc);
 		event.proc->pid = saved_pid;
 		continue_process(event.proc->pid);
+		debug(DEBUG_EVENT, "event: NONE: pid=%d (was_exec; placed breakpoints)", pid);
 		return &event;
 	}
 
@@ -161,5 +176,6 @@
 	}
 	event.e_un.brk_addr =
 	    event.proc->instruction_pointer - DECR_PC_AFTER_BREAK;
+	debug(DEBUG_EVENT, "event: BREAKPOINT: pid=%d, addr=%p", pid, event.e_un.brk_addr);
 	return &event;
 }
diff --git a/sysdeps/linux-gnu/trace.c b/sysdeps/linux-gnu/trace.c
index cbda70b..65d561f 100644
--- a/sysdeps/linux-gnu/trace.c
+++ b/sysdeps/linux-gnu/trace.c
@@ -161,6 +161,7 @@
 
 void
 trace_me(void) {
+	debug(DEBUG_PROCESS, "trace_me: pid=%d\n", getpid());
 	if (ptrace(PTRACE_TRACEME, 0, 1, 0) < 0) {
 		perror("PTRACE_TRACEME");
 		exit(1);
@@ -169,6 +170,7 @@
 
 int
 trace_pid(pid_t pid) {
+	debug(DEBUG_PROCESS, "trace_pid: pid=%d\n", pid);
 	if (ptrace(PTRACE_ATTACH, pid, 1, 0) < 0) {
 		return -1;
 	}
@@ -190,6 +192,8 @@
 	if (proc->tracesysgood & 0x80)
 		return;
 
+	debug(DEBUG_PROCESS, "trace_set_options: pid=%d\n", pid);
+
 	long options = PTRACE_O_TRACESYSGOOD | PTRACE_O_TRACEFORK |
 		PTRACE_O_TRACEVFORK | PTRACE_O_TRACECLONE |
 		PTRACE_O_TRACEEXEC;
@@ -203,6 +207,7 @@
 
 void
 untrace_pid(pid_t pid) {
+	debug(DEBUG_PROCESS, "untrace_pid: pid=%d\n", pid);
 	ptrace(PTRACE_DETACH, pid, 1, 0);
 }
 
@@ -210,6 +215,8 @@
 continue_after_signal(pid_t pid, int signum) {
 	Process *proc;
 
+	debug(DEBUG_PROCESS, "continue_after_signal: pid=%d, signum=%d", pid, signum);
+
 	proc = pid2proc(pid);
 	if (proc && proc->breakpoint_being_enabled) {
 #if defined __sparc__  || defined __ia64___
@@ -226,6 +233,8 @@
 continue_process(pid_t pid) {
 	/* We always trace syscalls to control fork(), clone(), execve()... */
 
+	debug(DEBUG_PROCESS, "continue_process: pid=%d", pid);
+
 	ptrace(PTRACE_SYSCALL, pid, 0, 0);
 }
 
@@ -237,6 +246,7 @@
 
 void
 continue_after_breakpoint(Process *proc, Breakpoint *sbp) {
+	debug(DEBUG_PROCESS, "continue_after_breakpoint: pid=%d, addr=%p", proc->pid, sbp->addr);
 	if (sbp->enabled)
 		disable_breakpoint(proc->pid, sbp);
 	set_instruction_pointer(proc, sbp->addr);