Index: kernel/generic/include/interrupt.h
===================================================================
--- kernel/generic/include/interrupt.h	(revision 336db2955b9fd1ee85c8818b9408bc4e9dad9fc2)
+++ kernel/generic/include/interrupt.h	(revision fea0ce628d7b303f0184370fc5e54b52cc69e1ef)
@@ -46,17 +46,5 @@
 typedef void (* iroutine)(int n, istate_t *istate);
 
-#define fault_if_from_uspace(istate, fmt, ...) \
-{ \
-	if (istate_from_uspace(istate)) { \
-		task_t *task = TASK; \
-		printf("Task %s (%" PRIu64 ") killed due to an exception at " \
-		    "program counter %p.\n", task->name, task->taskid, istate_get_pc(istate)); \
-		stack_trace_istate(istate); \
-		printf("Kill message: " fmt "\n", ##__VA_ARGS__); \
-		task_kill(task->taskid); \
-		thread_exit(); \
-	} \
-}
-
+extern void fault_if_from_uspace(istate_t *istate, char *fmt, ...);
 extern iroutine exc_register(int n, const char *name, iroutine f);
 extern void exc_dispatch(int n, istate_t *t);
Index: kernel/generic/include/ipc/event_types.h
===================================================================
--- kernel/generic/include/ipc/event_types.h	(revision 336db2955b9fd1ee85c8818b9408bc4e9dad9fc2)
+++ kernel/generic/include/ipc/event_types.h	(revision fea0ce628d7b303f0184370fc5e54b52cc69e1ef)
@@ -37,6 +37,10 @@
 
 typedef enum event_type {
+	/** New data available in kernel log */
 	EVENT_KLOG = 0,
+	/** Returning from kernel console to userspace */
 	EVENT_KCONSOLE,
+	/** A thread has faulted and will be terminated */
+	EVENT_FAULT,
 	EVENT_END
 } event_type_t;
Index: kernel/generic/include/udebug/udebug.h
===================================================================
--- kernel/generic/include/udebug/udebug.h	(revision 336db2955b9fd1ee85c8818b9408bc4e9dad9fc2)
+++ kernel/generic/include/udebug/udebug.h	(revision fea0ce628d7b303f0184370fc5e54b52cc69e1ef)
@@ -153,4 +153,5 @@
 
 #include <synch/mutex.h>
+#include <synch/condvar.h>
 #include <arch/interrupt.h>
 #include <atomic.h>
@@ -195,4 +196,5 @@
 	bool stoppable;		/**< thread is stoppable */
 	bool active;		/**< thread is in a debugging session */
+	condvar_t active_cv;
 } udebug_thread_t;
 
Index: kernel/generic/src/interrupt/interrupt.c
===================================================================
--- kernel/generic/src/interrupt/interrupt.c	(revision 336db2955b9fd1ee85c8818b9408bc4e9dad9fc2)
+++ kernel/generic/src/interrupt/interrupt.c	(revision fea0ce628d7b303f0184370fc5e54b52cc69e1ef)
@@ -44,4 +44,8 @@
 #include <console/console.h>
 #include <console/cmd.h>
+#include <ipc/event.h>
+#include <synch/mutex.h>
+#include <time/delay.h>
+#include <macros.h>
 #include <panic.h>
 #include <print.h>
@@ -107,4 +111,51 @@
 	fault_if_from_uspace(istate, "Unhandled exception %d.", n);
 	panic("Unhandled exception %d.", n);
+}
+
+/** Terminate thread and task if exception came from userspace. */
+void fault_if_from_uspace(istate_t *istate, char *fmt, ...)
+{
+	task_t *task = TASK;
+	va_list args;
+
+	if (!istate_from_uspace(istate))
+		return;
+
+	printf("Task %s (%" PRIu64 ") killed due to an exception at "
+	    "program counter %p.\n", task->name, task->taskid,
+	    istate_get_pc(istate));
+
+	stack_trace_istate(istate);
+
+	printf("Kill message: ");
+	va_start(args, fmt);
+	vprintf(fmt, args);
+	va_end(args);
+	printf("\n");
+
+	if (event_is_subscribed(EVENT_FAULT)) {
+		event_notify_3(EVENT_FAULT, LOWER32(TASK->taskid),
+		    UPPER32(TASK->taskid), (unative_t) THREAD);
+	}
+
+#ifdef CONFIG_UDEBUG
+	/* Wait until a debugger attends to us. */
+	mutex_lock(&THREAD->udebug.lock);
+	while (!THREAD->udebug.active)
+		condvar_wait(&THREAD->udebug.active_cv, &THREAD->udebug.lock);
+	mutex_unlock(&THREAD->udebug.lock);
+
+	udebug_stoppable_begin();
+	udebug_stoppable_end();
+
+	/* Make sure the debugging session is over before proceeding. */
+	mutex_lock(&THREAD->udebug.lock);
+	while (THREAD->udebug.active)
+		condvar_wait(&THREAD->udebug.active_cv, &THREAD->udebug.lock);
+	mutex_unlock(&THREAD->udebug.lock);
+#endif
+
+	task_kill(task->taskid);
+	thread_exit();
 }
 
Index: kernel/generic/src/udebug/udebug.c
===================================================================
--- kernel/generic/src/udebug/udebug.c	(revision 336db2955b9fd1ee85c8818b9408bc4e9dad9fc2)
+++ kernel/generic/src/udebug/udebug.c	(revision fea0ce628d7b303f0184370fc5e54b52cc69e1ef)
@@ -69,4 +69,5 @@
 	mutex_initialize(&ut->lock, MUTEX_PASSIVE);
 	waitq_initialize(&ut->go_wq);
+	condvar_initialize(&ut->active_cv);
 
 	ut->go_call = NULL;
@@ -446,6 +447,9 @@
 				waitq_wakeup(&t->udebug.go_wq, WAKEUP_FIRST);
 			}
+			mutex_unlock(&t->udebug.lock);
+			condvar_broadcast(&t->udebug.active_cv);
+		} else {
+			mutex_unlock(&t->udebug.lock);
 		}
-		mutex_unlock(&t->udebug.lock);
 	}
 
Index: kernel/generic/src/udebug/udebug_ops.c
===================================================================
--- kernel/generic/src/udebug/udebug_ops.c	(revision 336db2955b9fd1ee85c8818b9408bc4e9dad9fc2)
+++ kernel/generic/src/udebug/udebug_ops.c	(revision fea0ce628d7b303f0184370fc5e54b52cc69e1ef)
@@ -209,7 +209,11 @@
 
 		mutex_lock(&t->udebug.lock);
-		if ((t->flags & THREAD_FLAG_USPACE) != 0)
+		if ((t->flags & THREAD_FLAG_USPACE) != 0) {
 			t->udebug.active = true;
-		mutex_unlock(&t->udebug.lock);
+			mutex_unlock(&t->udebug.lock);
+			condvar_broadcast(&t->udebug.active_cv);
+		} else {
+			mutex_unlock(&t->udebug.lock);
+		}
 	}
 
