Index: HelenOS.config
===================================================================
--- HelenOS.config	(revision ae75e2e3eeabda7f649cf80e1f0e25cbb7a7386e)
+++ HelenOS.config	(revision e095644fa3dee2172f750ac4b6c58a572cec9c46)
@@ -486,2 +486,5 @@
 % Mount /data on startup
 ! [CONFIG_START_BD=y] CONFIG_MOUNT_DATA (n/y)
+
+% Verbose task dumps
+! CONFIG_VERBOSE_DUMPS (n/y)
Index: boot/Makefile.common
===================================================================
--- boot/Makefile.common	(revision ae75e2e3eeabda7f649cf80e1f0e25cbb7a7386e)
+++ boot/Makefile.common	(revision e095644fa3dee2172f750ac4b6c58a572cec9c46)
@@ -56,5 +56,6 @@
 	$(USPACEDIR)/srv/fs/devfs/devfs \
 	$(USPACEDIR)/srv/fs/tmpfs/tmpfs \
-	$(USPACEDIR)/srv/fs/fat/fat
+	$(USPACEDIR)/srv/fs/fat/fat \
+	$(USPACEDIR)/srv/taskmon/taskmon
 
 RD_APPS = \
@@ -65,4 +66,5 @@
 	$(USPACEDIR)/app/mkfat/mkfat \
 	$(USPACEDIR)/app/redir/redir \
+	$(USPACEDIR)/app/taskdump/taskdump \
 	$(USPACEDIR)/app/tester/tester \
 	$(USPACEDIR)/app/tetris/tetris \
Index: kernel/generic/include/interrupt.h
===================================================================
--- kernel/generic/include/interrupt.h	(revision ae75e2e3eeabda7f649cf80e1f0e25cbb7a7386e)
+++ kernel/generic/include/interrupt.h	(revision e095644fa3dee2172f750ac4b6c58a572cec9c46)
@@ -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 ae75e2e3eeabda7f649cf80e1f0e25cbb7a7386e)
+++ kernel/generic/include/ipc/event_types.h	(revision e095644fa3dee2172f750ac4b6c58a572cec9c46)
@@ -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/mm/as.h
===================================================================
--- kernel/generic/include/mm/as.h	(revision ae75e2e3eeabda7f649cf80e1f0e25cbb7a7386e)
+++ kernel/generic/include/mm/as.h	(revision e095644fa3dee2172f750ac4b6c58a572cec9c46)
@@ -36,4 +36,10 @@
 #define KERN_AS_H_
 
+#ifdef KERNEL
+#include <arch/types.h>
+#else
+#include <sys/types.h>
+#endif
+
 /** Address space area flags. */
 #define AS_AREA_READ		1
@@ -41,4 +47,16 @@
 #define AS_AREA_EXEC		4
 #define AS_AREA_CACHEABLE	8
+
+/** Address space area info exported to userspace. */
+typedef struct {
+	/** Starting address */
+	uintptr_t start_addr;
+
+	/** Area size */
+	size_t size;
+
+	/** Area flags */
+	int flags;
+} as_area_info_t;
 
 #ifdef KERNEL
@@ -268,4 +286,5 @@
 
 /* Introspection functions. */
+extern void as_get_area_info(as_t *as, as_area_info_t **obuf, size_t *osize);
 extern void as_print(as_t *as);
 
Index: kernel/generic/include/udebug/udebug.h
===================================================================
--- kernel/generic/include/udebug/udebug.h	(revision ae75e2e3eeabda7f649cf80e1f0e25cbb7a7386e)
+++ kernel/generic/include/udebug/udebug.h	(revision e095644fa3dee2172f750ac4b6c58a572cec9c46)
@@ -96,4 +96,18 @@
  */
 UDEBUG_M_THREAD_READ,
+
+/** Read the list of the debugged task's address space areas.
+ *
+ * - ARG2 - destination address in the caller's address space
+ * - ARG3 - size of receiving buffer in bytes
+ *
+ * The kernel fills the buffer with a series of as_area_info_t structures.
+ * Upon answer, the kernel will set:
+ *
+ * - ARG2 - number of bytes that were actually copied
+ * - ARG3 - number of bytes of the complete data
+ *
+ */
+UDEBUG_M_AREAS_READ,
 
 /** Read the debugged tasks's memory.
@@ -139,4 +153,5 @@
 
 #include <synch/mutex.h>
+#include <synch/condvar.h>
 #include <arch/interrupt.h>
 #include <atomic.h>
@@ -181,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/include/udebug/udebug_ops.h
===================================================================
--- kernel/generic/include/udebug/udebug_ops.h	(revision ae75e2e3eeabda7f649cf80e1f0e25cbb7a7386e)
+++ kernel/generic/include/udebug/udebug_ops.h	(revision e095644fa3dee2172f750ac4b6c58a572cec9c46)
@@ -45,5 +45,6 @@
 int udebug_stop(thread_t *t, call_t *call);
 
-int udebug_thread_read(void **buffer, size_t buf_size, size_t *n);
+int udebug_thread_read(void **buffer, size_t buf_size, size_t *stored,
+    size_t *needed);
 int udebug_args_read(thread_t *t, void **buffer);
 
Index: kernel/generic/src/interrupt/interrupt.c
===================================================================
--- kernel/generic/src/interrupt/interrupt.c	(revision ae75e2e3eeabda7f649cf80e1f0e25cbb7a7386e)
+++ kernel/generic/src/interrupt/interrupt.c	(revision e095644fa3dee2172f750ac4b6c58a572cec9c46)
@@ -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/mm/as.c
===================================================================
--- kernel/generic/src/mm/as.c	(revision ae75e2e3eeabda7f649cf80e1f0e25cbb7a7386e)
+++ kernel/generic/src/mm/as.c	(revision e095644fa3dee2172f750ac4b6c58a572cec9c46)
@@ -1920,4 +1920,70 @@
 }
 
+/** Get list of adress space areas.
+ *
+ * @param as		Address space.
+ * @param obuf		Place to save pointer to returned buffer.
+ * @param osize		Place to save size of returned buffer.
+ */
+void as_get_area_info(as_t *as, as_area_info_t **obuf, size_t *osize)
+{
+	ipl_t ipl;
+	size_t area_cnt, area_idx, i;
+	link_t *cur;
+
+	as_area_info_t *info;
+	size_t isize;
+
+	ipl = interrupts_disable();
+	mutex_lock(&as->lock);
+
+	/* First pass, count number of areas. */
+
+	area_cnt = 0;
+
+	for (cur = as->as_area_btree.leaf_head.next;
+	    cur != &as->as_area_btree.leaf_head; cur = cur->next) {
+		btree_node_t *node;
+
+		node = list_get_instance(cur, btree_node_t, leaf_link);
+		area_cnt += node->keys;
+	}
+
+        isize = area_cnt * sizeof(as_area_info_t);
+	info = malloc(isize, 0);
+
+	/* Second pass, record data. */
+
+	area_idx = 0;
+
+	for (cur = as->as_area_btree.leaf_head.next;
+	    cur != &as->as_area_btree.leaf_head; cur = cur->next) {
+		btree_node_t *node;
+
+		node = list_get_instance(cur, btree_node_t, leaf_link);
+
+		for (i = 0; i < node->keys; i++) {
+			as_area_t *area = node->value[i];
+
+			ASSERT(area_idx < area_cnt);
+			mutex_lock(&area->lock);
+
+			info[area_idx].start_addr = area->base;
+			info[area_idx].size = FRAMES2SIZE(area->pages);
+			info[area_idx].flags = area->flags;
+			++area_idx;
+
+			mutex_unlock(&area->lock);
+		}
+	}
+
+	mutex_unlock(&as->lock);
+	interrupts_restore(ipl);
+
+	*obuf = info;
+	*osize = isize;
+}
+
+
 /** Print out information about address space.
  *
Index: kernel/generic/src/udebug/udebug.c
===================================================================
--- kernel/generic/src/udebug/udebug.c	(revision ae75e2e3eeabda7f649cf80e1f0e25cbb7a7386e)
+++ kernel/generic/src/udebug/udebug.c	(revision e095644fa3dee2172f750ac4b6c58a572cec9c46)
@@ -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_ipc.c
===================================================================
--- kernel/generic/src/udebug/udebug_ipc.c	(revision ae75e2e3eeabda7f649cf80e1f0e25cbb7a7386e)
+++ kernel/generic/src/udebug/udebug_ipc.c	(revision e095644fa3dee2172f750ac4b6c58a572cec9c46)
@@ -41,4 +41,5 @@
 #include <proc/task.h>
 #include <proc/thread.h>
+#include <mm/as.h>
 #include <arch.h>
 #include <errno.h>
@@ -165,11 +166,54 @@
 static void udebug_receive_thread_read(call_t *call)
 {
+	uintptr_t uspace_addr;
+	size_t buf_size;
+	void *buffer;
+	size_t copied, needed;
+	int rc;
+
+	uspace_addr = IPC_GET_ARG2(call->data);	/* Destination address */
+	buf_size = IPC_GET_ARG3(call->data);	/* Dest. buffer size */
+
+	/*
+	 * Read thread list. Variable n will be filled with actual number
+	 * of threads times thread-id size.
+	 */
+	rc = udebug_thread_read(&buffer, buf_size, &copied, &needed);
+	if (rc < 0) {
+		IPC_SET_RETVAL(call->data, rc);
+		ipc_answer(&TASK->kb.box, call);
+		return;
+	}
+
+	/*
+	 * Make use of call->buffer to transfer data to caller's userspace
+	 */
+
+	IPC_SET_RETVAL(call->data, 0);
+	/* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
+	   same code in process_answer() can be used 
+	   (no way to distinguish method in answer) */
+	IPC_SET_ARG1(call->data, uspace_addr);
+	IPC_SET_ARG2(call->data, copied);
+	IPC_SET_ARG3(call->data, needed);
+	call->buffer = buffer;
+
+	ipc_answer(&TASK->kb.box, call);
+}
+
+/** Process an AREAS_READ call.
+ *
+ * Returns a list of address space areas in the current task, as an array
+ * of as_area_info_t structures.
+ *
+ * @param call	The call structure.
+ */
+static void udebug_receive_areas_read(call_t *call)
+{
 	unative_t uspace_addr;
 	unative_t to_copy;
-	unsigned total_bytes;
-	unsigned buf_size;
-	void *buffer;
-	size_t n;
-	int rc;
+	size_t data_size;
+	size_t buf_size;
+	void *data;
 
 	uspace_addr = IPC_GET_ARG2(call->data);	/* Destination address */
@@ -177,20 +221,12 @@
 
 	/*
-	 * Read thread list. Variable n will be filled with actual number
-	 * of threads times thread-id size.
-	 */
-	rc = udebug_thread_read(&buffer, buf_size, &n);
-	if (rc < 0) {
-		IPC_SET_RETVAL(call->data, rc);
-		ipc_answer(&TASK->kb.box, call);
-		return;
-	}
-
-	total_bytes = n;
-
-	/* Copy MAX(buf_size, total_bytes) bytes */
-
-	if (buf_size > total_bytes)
-		to_copy = total_bytes;
+	 * Read area list.
+	 */
+	as_get_area_info(AS, (as_area_info_t **) &data, &data_size);
+
+	/* Copy MAX(buf_size, data_size) bytes */
+
+	if (buf_size > data_size)
+		to_copy = data_size;
 	else
 		to_copy = buf_size;
@@ -207,9 +243,10 @@
 	IPC_SET_ARG2(call->data, to_copy);
 
-	IPC_SET_ARG3(call->data, total_bytes);
-	call->buffer = buffer;
-
-	ipc_answer(&TASK->kb.box, call);
-}
+	IPC_SET_ARG3(call->data, data_size);
+	call->buffer = data;
+
+	ipc_answer(&TASK->kb.box, call);
+}
+
 
 /** Process an ARGS_READ call.
@@ -331,4 +368,7 @@
 		udebug_receive_thread_read(call);
 		break;
+	case UDEBUG_M_AREAS_READ:
+		udebug_receive_areas_read(call);
+		break;
 	case UDEBUG_M_ARGS_READ:
 		udebug_receive_args_read(call);
Index: kernel/generic/src/udebug/udebug_ops.c
===================================================================
--- kernel/generic/src/udebug/udebug_ops.c	(revision ae75e2e3eeabda7f649cf80e1f0e25cbb7a7386e)
+++ kernel/generic/src/udebug/udebug_ops.c	(revision e095644fa3dee2172f750ac4b6c58a572cec9c46)
@@ -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);
+		}
 	}
 
@@ -355,6 +359,7 @@
  *
  * If the sequence is longer than @a buf_size bytes, only as much hashes
- * as can fit are copied. The number of thread hashes copied is stored
- * in @a n.
+ * as can fit are copied. The number of bytes copied is stored in @a stored.
+ * The total number of thread bytes that could have been saved had there been
+ * enough space is stored in @a needed.
  *
  * The rationale for having @a buf_size is that this function is only
@@ -364,12 +369,15 @@
  * @param buffer	The buffer for storing thread hashes.
  * @param buf_size	Buffer size in bytes.
- * @param n		The actual number of hashes copied will be stored here.
- */
-int udebug_thread_read(void **buffer, size_t buf_size, size_t *n)
+ * @param stored	The actual number of bytes copied will be stored here.
+ * @param needed	Total number of hashes that could have been saved.
+ */
+int udebug_thread_read(void **buffer, size_t buf_size, size_t *stored,
+    size_t *needed)
 {
 	thread_t *t;
 	link_t *cur;
 	unative_t tid;
-	unsigned copied_ids;
+	size_t copied_ids;
+	size_t extra_ids;
 	ipl_t ipl;
 	unative_t *id_buffer;
@@ -380,5 +388,5 @@
 
 	/* Allocate a buffer to hold thread IDs */
-	id_buffer = malloc(buf_size, 0);
+	id_buffer = malloc(buf_size + 1, 0);
 
 	mutex_lock(&TASK->udebug.lock);
@@ -396,10 +404,8 @@
 	max_ids = buf_size / sizeof(unative_t);
 	copied_ids = 0;
+	extra_ids = 0;
 
 	/* FIXME: make sure the thread isn't past debug shutdown... */
 	for (cur = TASK->th_head.next; cur != &TASK->th_head; cur = cur->next) {
-		/* Do not write past end of buffer */
-		if (copied_ids >= max_ids) break;
-
 		t = list_get_instance(cur, thread_t, th_link);
 
@@ -409,8 +415,13 @@
 
 		/* Not interested in kernel threads. */
-		if ((flags & THREAD_FLAG_USPACE) != 0) {
+		if ((flags & THREAD_FLAG_USPACE) == 0)
+			continue;
+
+		if (copied_ids < max_ids) {
 			/* Using thread struct pointer as identification hash */
 			tid = (unative_t) t;
 			id_buffer[copied_ids++] = tid;
+		} else {
+			extra_ids++;
 		}
 	}
@@ -422,5 +433,6 @@
 
 	*buffer = id_buffer;
-	*n = copied_ids * sizeof(unative_t);
+	*stored = copied_ids * sizeof(unative_t);
+	*needed = (copied_ids + extra_ids) * sizeof(unative_t);
 
 	return 0;
Index: uspace/Makefile
===================================================================
--- uspace/Makefile	(revision ae75e2e3eeabda7f649cf80e1f0e25cbb7a7386e)
+++ uspace/Makefile	(revision e095644fa3dee2172f750ac4b6c58a572cec9c46)
@@ -40,4 +40,5 @@
 	app/mkfat \
 	app/redir \
+	app/taskdump \
 	app/tester \
 	app/tetris \
@@ -47,4 +48,5 @@
 	srv/loader \
 	srv/ns \
+	srv/taskmon \
 	srv/vfs \
 	srv/bd/ata_bd \
Index: uspace/app/init/init.c
===================================================================
--- uspace/app/init/init.c	(revision ae75e2e3eeabda7f649cf80e1f0e25cbb7a7386e)
+++ uspace/app/init/init.c	(revision e095644fa3dee2172f750ac4b6c58a572cec9c46)
@@ -233,4 +233,18 @@
 }
 
+static void mount_scratch(void)
+{
+	int rc;
+
+	printf("Trying to mount null/0 on /scratch... ");
+	fflush(stdout);
+
+	rc = mount("tmpfs", "/scratch", "null/0", "", 0);
+	if (rc == EOK)
+		printf("OK\n");
+	else
+		printf("Failed\n");
+}
+
 static void mount_data(void)
 {
@@ -255,6 +269,12 @@
 		return -1;
 	}
+
+	/* Make sure tmpfs is running. */
+	if (str_cmp(STRING(RDFMT), "tmpfs") != 0) {
+		spawn("/srv/tmpfs");
+	}
 	
 	spawn("/srv/devfs");
+	spawn("/srv/taskmon");
 	
 	if (!mount_devfs()) {
@@ -262,4 +282,6 @@
 		return -2;
 	}
+
+	mount_scratch();
 	
 	spawn("/srv/fhc");
Index: uspace/app/taskdump/Makefile
===================================================================
--- uspace/app/taskdump/Makefile	(revision e095644fa3dee2172f750ac4b6c58a572cec9c46)
+++ uspace/app/taskdump/Makefile	(revision e095644fa3dee2172f750ac4b6c58a572cec9c46)
@@ -0,0 +1,37 @@
+#
+# Copyright (c) 2010 Jiri Svoboda
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - The name of the author may not be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+USPACE_PREFIX = ../..
+LIBS = $(LIBC_PREFIX)/libc.a
+
+OUTPUT = taskdump
+
+SOURCES = \
+	taskdump.c
+
+include ../Makefile.common
Index: uspace/app/taskdump/taskdump.c
===================================================================
--- uspace/app/taskdump/taskdump.c	(revision e095644fa3dee2172f750ac4b6c58a572cec9c46)
+++ uspace/app/taskdump/taskdump.c	(revision e095644fa3dee2172f750ac4b6c58a572cec9c46)
@@ -0,0 +1,353 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup taskdump
+ * @{
+ */
+/** @file
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <ipc/ipc.h>
+#include <errno.h>
+#include <udebug.h>
+#include <task.h>
+#include <kernel/mm/as.h>
+#include <macros.h>
+#include <assert.h>
+#include <bool.h>
+
+#define LINE_BYTES 16
+
+#define DBUF_SIZE 4096
+static uint8_t data_buf[DBUF_SIZE];
+
+static int phoneid;
+static task_id_t task_id;
+static bool dump_memory;
+
+static int connect_task(task_id_t task_id);
+static int parse_args(int argc, char *argv[]);
+static void print_syntax();
+static int threads_dump(void);
+static int areas_dump(void);
+static int area_dump(as_area_info_t *area);
+static void hex_dump(uintptr_t addr, void *buffer, size_t size);
+
+int main(int argc, char *argv[])
+{
+	int rc;
+
+	/*
+	 * FIXME: The stdio module cannot currently detect whether we are
+	 * writing to a console or file. This workaround make file output
+	 * faster.
+	 */
+	setvbuf(stdout, NULL, _IOFBF, 32768);
+
+	printf("Task Dump Utility\n");
+	dump_memory = false;
+
+	if (parse_args(argc, argv) < 0)
+		return 1;
+
+	rc = connect_task(task_id);
+	if (rc < 0) {
+		printf("Failed connecting to task %lld.\n", task_id);
+		return 1;
+	}
+
+	printf("Dumping task %lld.\n\n", task_id);
+
+	rc = threads_dump();
+	if (rc < 0)
+		printf("Failed dumping threads.\n");
+
+	rc = areas_dump();
+	if (rc < 0)
+		printf("Failed dumping address space areas.\n");
+
+	udebug_end(phoneid);
+	ipc_hangup(phoneid);
+
+	return 0;
+}
+
+static int connect_task(task_id_t task_id)
+{
+	int rc;
+
+	rc = ipc_connect_kbox(task_id);
+
+	if (rc == ENOTSUP) {
+		printf("You do not have userspace debugging support "
+		    "compiled in the kernel.\n");
+		printf("Compile kernel with 'Support for userspace debuggers' "
+		    "(CONFIG_UDEBUG) enabled.\n");
+		return rc;
+	}
+
+	if (rc < 0) {
+		printf("Error connecting\n");
+		printf("ipc_connect_task(%lld) -> %d ", task_id, rc);
+		return rc;
+	}
+
+	phoneid = rc;
+
+	rc = udebug_begin(phoneid);
+	if (rc < 0) {
+		printf("udebug_begin() -> %d\n", rc);
+		return rc;
+	}
+
+	return 0;
+}
+
+static int parse_args(int argc, char *argv[])
+{
+	char *arg;
+	char *err_p;
+
+	task_id = 0;
+
+	--argc; ++argv;
+
+	while (argc > 0) {
+		arg = *argv;
+		if (arg[0] == '-') {
+			if (arg[1] == 't' && arg[2] == '\0') {
+				/* Task ID */
+				--argc; ++argv;
+				task_id = strtol(*argv, &err_p, 10);
+				if (*err_p) {
+					printf("Task ID syntax error\n");
+					print_syntax();
+					return -1;
+				}
+			} else if (arg[1] == 'm' && arg[2] == '\0') {
+				dump_memory = true;
+			} else {
+				printf("Uknown option '%s'\n", arg[0]);
+				print_syntax();
+				return -1;
+			}
+		} else {
+			break;
+		}
+
+		--argc; ++argv;
+	}
+
+	if (task_id == 0) {
+		printf("Missing task ID argument\n");
+		print_syntax();
+		return -1;
+	}
+
+	if (argc != 0) {
+		printf("Extra arguments\n");
+		print_syntax();
+		return -1;
+	}
+
+	return 0;
+}
+
+static void print_syntax()
+{
+	printf("Syntax: taskdump [-m] -t <task_id>\n");
+	printf("\t-m\tDump memory area contents.\n");
+	printf("\t-t <task_id>\tWhich task to dump.\n");
+}
+
+static int threads_dump(void)
+{
+	uintptr_t *thash_buf;
+	uintptr_t dummy_buf;
+	size_t buf_size, n_threads;
+
+	size_t copied;
+	size_t needed;
+	size_t i;
+	int rc;
+
+	/* TODO: See why NULL does not work. */
+	rc = udebug_thread_read(phoneid, &dummy_buf, 0, &copied, &needed);
+	if (rc < 0) {
+		printf("udebug_thread_read() -> %d\n", rc);
+		return rc;
+	}
+
+	if (needed == 0) {
+		printf("No threads.\n\n");
+		return 0;
+	}
+
+	buf_size = needed;
+	thash_buf = malloc(buf_size);
+
+	rc = udebug_thread_read(phoneid, thash_buf, buf_size, &copied, &needed);
+	if (rc < 0) {
+		printf("udebug_thread_read() -> %d\n", rc);
+		return rc;
+	}
+
+	assert(copied == buf_size);
+	assert(needed == buf_size);
+
+	n_threads = copied / sizeof(uintptr_t);
+
+	printf("Threads:\n");
+	for (i = 0; i < n_threads; i++) {
+		printf(" [%d] hash: 0x%lx\n", 1+i, thash_buf[i]);
+	}
+	putchar('\n');
+
+	free(thash_buf);
+
+	return 0;
+}
+
+static int areas_dump(void)
+{
+	as_area_info_t *ainfo_buf;
+	as_area_info_t dummy_buf;
+	size_t buf_size, n_areas;
+
+	size_t copied;
+	size_t needed;
+	size_t i;
+	int rc;
+
+	rc = udebug_areas_read(phoneid, &dummy_buf, 0, &copied, &needed);
+	if (rc < 0) {
+		printf("udebug_areas_read() -> %d\n", rc);
+		return rc;
+	}
+
+	buf_size = needed;
+	ainfo_buf = malloc(buf_size);
+
+	rc = udebug_areas_read(phoneid, ainfo_buf, buf_size, &copied, &needed);
+	if (rc < 0) {
+		printf("udebug_areas_read() -> %d\n", rc);
+		return rc;
+	}
+
+	assert(copied == buf_size);
+	assert(needed == buf_size);
+
+	n_areas = copied / sizeof(as_area_info_t);
+
+	printf("Address space areas:\n");
+	for (i = 0; i < n_areas; i++) {
+		printf(" [%d] flags: %c%c%c%c base: 0x%lx size: 0x%lx\n", 1+i,
+		    (ainfo_buf[i].flags & AS_AREA_READ) ? 'R' : '-',
+		    (ainfo_buf[i].flags & AS_AREA_WRITE) ? 'W' : '-',
+		    (ainfo_buf[i].flags & AS_AREA_EXEC) ? 'X' : '-',
+		    (ainfo_buf[i].flags & AS_AREA_CACHEABLE) ? 'C' : '-',
+		    ainfo_buf[i].start_addr, ainfo_buf[i].size);
+
+		if (dump_memory) {
+			putchar('\n');
+			area_dump(&ainfo_buf[i]);
+			putchar('\n');
+		}
+	}
+
+	putchar('\n');
+
+	free(ainfo_buf);
+
+	return 0;
+}
+
+static int area_dump(as_area_info_t *area)
+{
+	size_t to_copy;
+	size_t total;
+	uintptr_t addr;
+	int rc;
+
+	addr = area->start_addr;
+	total = 0;
+
+	while (total < area->size) {
+		to_copy = min(area->size - total, DBUF_SIZE);
+		rc = udebug_mem_read(phoneid, data_buf, addr, to_copy);
+		if (rc < 0) {
+			printf("udebug_mem_read() failed.\n");
+			return rc;
+		}
+
+		hex_dump(addr, data_buf, to_copy);
+
+		addr += to_copy;
+		total += to_copy;
+	}
+
+	return EOK;
+}
+
+static void hex_dump(uintptr_t addr, void *buffer, size_t size)
+{
+	uint8_t *data = (uint8_t *) buffer;
+	uint8_t b;
+	size_t pos, i;
+
+	assert(addr % LINE_BYTES == 0);
+	assert(size % LINE_BYTES == 0);
+
+	pos = 0;
+
+	while (pos < size) {
+		printf("%08x:", addr + pos);
+		for (i = 0; i < LINE_BYTES; ++i) {
+			if (i % 4 == 0) putchar(' ');
+			printf(" %02x", data[pos + i]);
+		}
+		putchar('\t');
+
+		for (i = 0; i < LINE_BYTES; ++i) {
+			b = data[pos + i];
+			if (b >= 32 && b < 127) {
+				putchar(b);
+			} else {
+				putchar(' ');
+			}
+		}
+		putchar('\n');
+		pos += LINE_BYTES;
+	}
+}
+
+/** @}
+ */
Index: uspace/lib/libc/generic/udebug.c
===================================================================
--- uspace/lib/libc/generic/udebug.c	(revision ae75e2e3eeabda7f649cf80e1f0e25cbb7a7386e)
+++ uspace/lib/libc/generic/udebug.c	(revision e095644fa3dee2172f750ac4b6c58a572cec9c46)
@@ -69,4 +69,20 @@
 }
 
+int udebug_areas_read(int phoneid, void *buffer, size_t n,
+	size_t *copied, size_t *needed)
+{
+	ipcarg_t a_copied, a_needed;
+	int rc;
+
+	rc = async_req_3_3(phoneid, IPC_M_DEBUG_ALL, UDEBUG_M_AREAS_READ,
+		(sysarg_t)buffer, n, NULL, &a_copied, &a_needed);
+
+	*copied = (size_t)a_copied;
+	*needed = (size_t)a_needed;
+
+	return rc;
+}
+
+
 int udebug_mem_read(int phoneid, void *buffer, uintptr_t addr, size_t n)
 {
Index: uspace/lib/libc/include/udebug.h
===================================================================
--- uspace/lib/libc/include/udebug.h	(revision ae75e2e3eeabda7f649cf80e1f0e25cbb7a7386e)
+++ uspace/lib/libc/include/udebug.h	(revision e095644fa3dee2172f750ac4b6c58a572cec9c46)
@@ -47,4 +47,6 @@
 int udebug_thread_read(int phoneid, void *buffer, size_t n,
 	size_t *copied, size_t *needed);
+int udebug_areas_read(int phoneid, void *buffer, size_t n,
+	size_t *copied, size_t *needed);
 int udebug_mem_read(int phoneid, void *buffer, uintptr_t addr, size_t n);
 int udebug_args_read(int phoneid, thash_t tid, sysarg_t *buffer);
Index: pace/lib/libpci/Makefile.build
===================================================================
--- uspace/lib/libpci/Makefile.build	(revision ae75e2e3eeabda7f649cf80e1f0e25cbb7a7386e)
+++ 	(revision )
@@ -1,64 +1,0 @@
-#
-# Copyright (c) 2005 Martin Decky
-# Copyright (c) 2007 Jakub Jermar
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-#
-# - Redistributions of source code must retain the above copyright
-#   notice, this list of conditions and the following disclaimer.
-# - Redistributions in binary form must reproduce the above copyright
-#   notice, this list of conditions and the following disclaimer in the
-#   documentation and/or other materials provided with the distribution.
-# - The name of the author may not be used to endorse or promote products
-#   derived from this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
-# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
-# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#
-
-## Setup toolchain
-#
-
-include Makefile.common
-include $(LIBC_PREFIX)/Makefile.toolchain
-
-## Sources
-#
-
-SOURCES = \
-	access.c \
-	generic.c \
-	names.c \
-	i386-ports.c
-
-OBJECTS := $(addsuffix .o,$(basename $(SOURCES)))
-
-.PHONY: all
-
-all: $(LIBPCI)
-
--include $(DEPEND)
-
-$(LIBPCI): $(OBJECTS)
-	$(AR) rc $@ $(OBJECTS)
-
-%.o: %.c $(DEPEND)
-	$(CC) $(DEFS) $(CFLAGS) -c $< -o $@
-ifeq ($(PRECHECK),y)
-	$(JOBFILE) $(JOB) $< $@ cc core $(DEFS) $(CFLAGS)
-endif
-
-$(DEPEND):
-	makedepend -f - -- $(DEPEND_DEFS) $(CFLAGS) -- $(SOURCES) > $@ 2> /dev/null
-	-[ -f $(DEPEND_PREV) ] && diff -q $(DEPEND_PREV) $@ && mv -f $(DEPEND_PREV) $@
Index: pace/lib/libpci/Makefile.common
===================================================================
--- uspace/lib/libpci/Makefile.common	(revision ae75e2e3eeabda7f649cf80e1f0e25cbb7a7386e)
+++ 	(revision )
@@ -1,37 +1,0 @@
-#
-# Copyright (c) 2005 Martin Decky
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-#
-# - Redistributions of source code must retain the above copyright
-#   notice, this list of conditions and the following disclaimer.
-# - Redistributions in binary form must reproduce the above copyright
-#   notice, this list of conditions and the following disclaimer in the
-#   documentation and/or other materials provided with the distribution.
-# - The name of the author may not be used to endorse or promote products
-#   derived from this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
-# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
-# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#
-
-
-## Common names
-#
-
-LIBC_PREFIX = ../../../../../lib/libc
-DEPEND = Makefile.depend
-DEPEND_PREV = $(DEPEND).prev
-JOB = libpci.job
-LIBPCI = libpci.a
Index: pace/srv/hid/kbd/port/i8042.h
===================================================================
--- uspace/srv/hid/kbd/port/i8042.h	(revision ae75e2e3eeabda7f649cf80e1f0e25cbb7a7386e)
+++ 	(revision )
@@ -1,55 +1,0 @@
-/*
- * Copyright (c) 2006 Josef Cejka
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup kbd_port
- * @ingroup  kbd
- * @{
- */
-
-/** @file
- * @brief i8042 port driver.
- */
-
-#ifndef KBD_PORT_i8042_H_
-#define KBD_PORT_i8042_H_
-
-#include <libarch/ddi.h>
-#include <libarch/types.h>
-
-struct i8042 {
-	ioport8_t data;
-	uint8_t pad[3];
-	ioport8_t status;
-} __attribute__ ((packed));
-typedef struct i8042 i8042_t;
-
-#endif
-
-/**
- * @}
- */ 
Index: uspace/srv/taskmon/Makefile
===================================================================
--- uspace/srv/taskmon/Makefile	(revision e095644fa3dee2172f750ac4b6c58a572cec9c46)
+++ uspace/srv/taskmon/Makefile	(revision e095644fa3dee2172f750ac4b6c58a572cec9c46)
@@ -0,0 +1,37 @@
+#
+# Copyright (c) 2010 Jiri Svoboda
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - The name of the author may not be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+USPACE_PREFIX = ../..
+LIBS = $(LIBC_PREFIX)/libc.a
+
+OUTPUT = taskmon
+
+SOURCES = \
+	taskmon.c
+
+include ../Makefile.common
Index: uspace/srv/taskmon/taskmon.c
===================================================================
--- uspace/srv/taskmon/taskmon.c	(revision e095644fa3dee2172f750ac4b6c58a572cec9c46)
+++ uspace/srv/taskmon/taskmon.c	(revision e095644fa3dee2172f750ac4b6c58a572cec9c46)
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup taskmon
+ * @brief
+ * @{
+ */
+/**
+ * @file
+ */
+
+#include <stdio.h>
+#include <ipc/ipc.h>
+#include <async.h>
+#include <ipc/services.h>
+#include <task.h>
+#include <event.h>
+#include <macros.h>
+#include <errno.h>
+
+#define NAME  "taskmon"
+
+static void fault_event(ipc_callid_t callid, ipc_call_t *call)
+{
+	char *argv[11];
+	char *fname;
+	char *dump_fname;
+	char *s_taskid;
+	char **s;
+
+	task_id_t taskid;
+	uintptr_t thread;
+
+	taskid = MERGE_LOUP32(IPC_GET_ARG1(*call), IPC_GET_ARG2(*call));
+	thread = IPC_GET_ARG3(*call);
+
+	if (asprintf(&s_taskid, "%lld", taskid) < 0) {
+		printf("Memory allocation failed.\n");
+		return;
+	}
+
+	if (asprintf(&dump_fname, "/scratch/d%lld.txt", taskid) < 0) {
+		printf("Memory allocation failed.\n");
+		return;
+	}
+
+	printf(NAME ": Task %lld fault in thread 0x%lx.\n", taskid, thread);
+
+	argv[0] = fname = "/app/redir";
+	argv[1] = "-i";
+	argv[2] = "/readme";
+	argv[3] = "-o";
+	argv[4] = dump_fname;
+	argv[5] = "--";
+
+#ifdef CONFIG_VERBOSE_DUMPS
+	argv[6] = "/app/taskdump";
+	argv[7] = "-m";
+	argv[8] = "-t";
+	argv[9] = s_taskid;
+	argv[10] = NULL;
+#else
+	argv[6] = "/app/taskdump";
+	argv[7] = "-t";
+	argv[8] = s_taskid;
+	argv[9] = NULL;
+#endif
+	printf(NAME ": Executing");
+        s = argv;
+	while (*s != NULL) {
+		printf(" %s", *s);
+		++s;
+	}
+	putchar('\n');
+
+	if (!task_spawn(fname, argv))
+		printf(NAME ": Error spawning taskdump.\n", fname);
+}
+
+int main(int argc, char *argv[])
+{
+	printf(NAME ": Task Monitoring Service\n");
+
+	if (event_subscribe(EVENT_FAULT, 0) != EOK) {
+		printf(NAME ": Error registering fault notifications.\n");
+		return -1;
+	}
+
+	async_set_interrupt_received(fault_event);
+	async_manager();
+
+	return 0;
+}
+
+/** @}
+ */
