Index: uspace/app/trace/Makefile
===================================================================
--- uspace/app/trace/Makefile	(revision 9a1b20c34d5404b8272209d06c0239aa1a2384da)
+++ uspace/app/trace/Makefile	(revision 9a1b20c34d5404b8272209d06c0239aa1a2384da)
@@ -0,0 +1,78 @@
+#
+# 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.
+#
+
+## Setup toolchain
+#
+
+LIBC_PREFIX = ../../lib/libc
+SOFTINT_PREFIX = ../../lib/softint
+include $(LIBC_PREFIX)/Makefile.toolchain
+
+CFLAGS += -I../../srv/kbd/include
+
+LIBS = $(LIBC_PREFIX)/libc.a
+
+## Sources
+#
+
+OUTPUT = trace
+SOURCES = trace.c \
+	syscalls.c \
+	ipcp.c \
+	ipc_desc.c \
+	proto.c \
+	errors.c
+
+OBJECTS := $(addsuffix .o,$(basename $(SOURCES)))
+
+.PHONY: all clean depend disasm
+
+all: $(OUTPUT) disasm
+
+-include Makefile.depend
+
+clean:
+	-rm -f $(OUTPUT) $(OBJECTS) $(OUTPUT).map $(OUTPUT).disasm Makefile.depend
+
+depend:
+	$(CC) $(DEFS) $(CFLAGS) -M $(SOURCES) > Makefile.depend
+
+$(OUTPUT): $(OBJECTS) $(LIBS)
+	$(LD) -T $(LIBC_PREFIX)/arch/$(ARCH)/_link.ld $(OBJECTS) $(LIBS) $(LFLAGS) -o $@ -Map $(OUTPUT).map
+
+disasm:
+	$(OBJDUMP) -d $(OUTPUT) >$(OUTPUT).disasm
+
+%.o: %.S
+	$(CC) $(DEFS) $(AFLAGS) $(CFLAGS) -D__ASM__ -c $< -o $@
+
+%.o: %.s
+	$(AS) $(AFLAGS) $< -o $@
+
+%.o: %.c
+	$(CC) $(DEFS) $(CFLAGS) -c $< -o $@
Index: uspace/app/trace/errors.c
===================================================================
--- uspace/app/trace/errors.c	(revision 9a1b20c34d5404b8272209d06c0239aa1a2384da)
+++ uspace/app/trace/errors.c	(revision 9a1b20c34d5404b8272209d06c0239aa1a2384da)
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2008 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 trace
+ * @{
+ */
+/** @file
+ */
+
+#include <errno.h>
+#include "errors.h"
+
+const err_desc_t err_desc[] = {
+	[-EOK]		= { "EOK",		"No error" },
+	[-ENOENT]	= { "ENOENT",		"No such entry" },
+	[-ENOMEM]	= { "ENOMEM",		"Not enough memory" },
+	[-ELIMIT]	= { "ELIMIT",		"Limit exceeded" },
+	[-EREFUSED]	= { "EREFUSED",		"Connection refused" },
+
+	[-EFORWARD]	= { "EFORWARD",		"Forward error" },
+	[-EPERM]	= { "EPERM",		"Permission denied" },
+	[-EHANGUP]	= { "EHANGUP",		"Answerbox closed connection" },
+	[-EEXISTS]	= { "EEXISTS",		"Entry already exists" },
+	[-EBADMEM]	= { "EBADMEM",		"Bad memory pointer" },
+
+	[-ENOTSUP]	= { "ENOTSUP",		"Not supported" },
+	[-EADDRNOTAVAIL] = { "EADDRNOTAVAIL", 	"Address not available." },
+	[-ETIMEOUT]	= { "ETIMEOUT",		"Timeout expired" },
+	[-EINVAL]	= { "EINVAL",		"Invalid value" },
+	[-EBUSY]	= { "EBUSY",		"Resource is busy" },
+
+	[-EOVERFLOW]	= { "EOVERFLOW",	"The result does not fit its size." }
+};
+
+/** @}
+ */
Index: uspace/app/trace/errors.h
===================================================================
--- uspace/app/trace/errors.h	(revision 9a1b20c34d5404b8272209d06c0239aa1a2384da)
+++ uspace/app/trace/errors.h	(revision 9a1b20c34d5404b8272209d06c0239aa1a2384da)
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2008 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 trace
+ * @{
+ */
+/** @file
+ */
+
+#ifndef ERRORS_H_
+#define ERRORS_H_
+
+typedef struct {
+	char *name;	/**< Error value name (Exx) */
+	char *desc;	/**< Error description */
+} err_desc_t;
+
+extern const err_desc_t err_desc[];
+
+#endif
+
+/** @}
+ */
Index: uspace/app/trace/ipc_desc.c
===================================================================
--- uspace/app/trace/ipc_desc.c	(revision 9a1b20c34d5404b8272209d06c0239aa1a2384da)
+++ uspace/app/trace/ipc_desc.c	(revision 9a1b20c34d5404b8272209d06c0239aa1a2384da)
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2008 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 trace
+ * @{
+ */
+/** @file
+ */
+
+#include <stdlib.h>
+#include <ipc/ipc.h>
+#include "ipc_desc.h"
+
+ipc_m_desc_t ipc_methods[] = {
+	/* System methods */
+	{ IPC_M_CONNECT_TO_ME,	"CONNECT_TO_ME" },
+	{ IPC_M_CONNECT_ME_TO,	"CONNECT_ME_TO" },
+	{ IPC_M_PHONE_HUNGUP,	"PHONE_HUNGUP" },
+	{ IPC_M_SHARE_OUT,	"SHARE_OUT" },
+	{ IPC_M_SHARE_IN,	"SHARE_IN" },
+	{ IPC_M_DATA_WRITE,	"DATA_WRITE" },
+	{ IPC_M_DATA_READ,	"DATA_READ" },
+	{ IPC_M_DEBUG_ALL,	"DEBUG_ALL" },
+
+	/* Well-known methods */
+	{ IPC_M_PING,		"PING" },
+
+	/* Terminating entry */
+	{ 0, NULL }
+};
+
+/** @}
+ */
Index: uspace/app/trace/ipc_desc.h
===================================================================
--- uspace/app/trace/ipc_desc.h	(revision 9a1b20c34d5404b8272209d06c0239aa1a2384da)
+++ uspace/app/trace/ipc_desc.h	(revision 9a1b20c34d5404b8272209d06c0239aa1a2384da)
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2008 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 trace
+ * @{
+ */
+/** @file
+ */
+
+#ifndef IPC_DESC_H_
+#define IPC_DESC_H_
+
+typedef struct {
+	int number;
+	char *name;
+} ipc_m_desc_t;
+
+extern ipc_m_desc_t ipc_methods[];
+
+#endif
+
+/** @}
+ */
Index: uspace/app/trace/ipcp.c
===================================================================
--- uspace/app/trace/ipcp.c	(revision 9a1b20c34d5404b8272209d06c0239aa1a2384da)
+++ uspace/app/trace/ipcp.c	(revision 9a1b20c34d5404b8272209d06c0239aa1a2384da)
@@ -0,0 +1,268 @@
+/*
+ * Copyright (c) 2008 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 trace
+ * @{
+ */
+/** @file
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <libadt/hash_table.h>
+
+#include "ipc_desc.h"
+#include "proto.h"
+#include "ipcp.h"
+
+#define IPCP_CALLID_SYNC 0
+
+typedef struct {
+	int phone_hash;
+	ipc_call_t question;
+
+	int call_hash;
+
+	link_t link;
+} pending_call_t;
+
+typedef struct {
+	int server;
+	proto_t *proto;
+} connection_t;
+
+#define MAX_PHONE 64
+connection_t connections[MAX_PHONE];
+int have_conn[MAX_PHONE];
+
+#define PCALL_TABLE_CHAINS 32
+hash_table_t pending_calls;
+
+static hash_index_t pending_call_hash(unsigned long key[]);
+static int pending_call_compare(unsigned long key[], hash_count_t keys,
+    link_t *item);
+static void pending_call_remove_callback(link_t *item);
+
+hash_table_operations_t pending_call_ops = {
+	.hash = pending_call_hash,
+	.compare = pending_call_compare,
+	.remove_callback = pending_call_remove_callback
+};
+
+
+static hash_index_t pending_call_hash(unsigned long key[])
+{
+//	printf("pending_call_hash\n");
+	return key[0] % PCALL_TABLE_CHAINS;
+}
+
+static int pending_call_compare(unsigned long key[], hash_count_t keys,
+    link_t *item)
+{
+	pending_call_t *hs;
+
+//	printf("pending_call_compare\n");
+	hs = hash_table_get_instance(item, pending_call_t, link);
+
+	return key[0] == hs->call_hash;
+}
+
+static void pending_call_remove_callback(link_t *item)
+{
+//	printf("pending_call_remove_callback\n");
+}
+
+
+void ipcp_connection_set(int phone, int server, proto_t *proto)
+{
+	if (phone <0 || phone >= MAX_PHONE) return;
+	connections[phone].server = server;
+	connections[phone].proto = proto;
+	have_conn[phone] = 1;
+}
+
+void ipcp_connection_clear(int phone)
+{
+	have_conn[phone] = 0;
+	connections[phone].server = 0;
+	connections[phone].proto = NULL;
+}
+
+static void ipc_m_print(proto_t *proto, ipcarg_t method)
+{
+	ipc_m_desc_t *desc;
+	oper_t *oper;
+
+	/* FIXME: too slow */
+	desc = ipc_methods;
+	while (desc->number != 0) {
+		if (desc->number == method) {
+			printf("%s (%d)", desc->name, method);
+			return;
+		}
+
+		++desc;
+	}
+
+	if (proto != NULL) {
+		oper = proto_get_oper(proto, method);
+		if (oper != NULL) {
+			printf("%s (%d)", oper->name, method);
+			return;
+		}
+	}
+
+	printf("%d", method);
+}
+
+void ipcp_init(void)
+{
+	hash_table_create(&pending_calls, PCALL_TABLE_CHAINS, 1, &pending_call_ops);
+}
+
+void ipcp_cleanup(void)
+{
+	hash_table_destroy(&pending_calls);
+}
+
+void ipcp_call_out(int phone, ipc_call_t *call, ipc_callid_t hash)
+{
+	pending_call_t *pcall;
+	proto_t *proto;
+	unsigned long key[1];
+
+	if (have_conn[phone]) proto = connections[phone].proto;
+	else proto = NULL;
+
+//	printf("ipcp_call_out()\n");
+	printf("call id: 0x%x, phone: %d, proto: %s, method: ", hash, phone,
+		(proto ? proto->name : "n/a"));
+	ipc_m_print(proto, IPC_GET_METHOD(*call));
+	printf(" args: (%u, %u, %u, %u, %u)\n",
+	    IPC_GET_ARG1(*call),
+	    IPC_GET_ARG2(*call),
+	    IPC_GET_ARG3(*call),
+	    IPC_GET_ARG4(*call),
+	    IPC_GET_ARG5(*call)
+	);
+
+	/* Store call in hash table for response matching */
+
+	pcall = malloc(sizeof(pending_call_t));
+	pcall->phone_hash = phone;
+	pcall->question = *call;
+	pcall->call_hash = hash;
+
+	key[0] = hash;
+
+	hash_table_insert(&pending_calls, key, &pcall->link);
+}
+
+static void parse_answer(pending_call_t *pcall, ipc_call_t *answer)
+{
+	int phone;
+	ipcarg_t method;
+	ipcarg_t service;
+	int retval;
+	static proto_t proto_unknown = { .name = "unknown" };
+	proto_t *proto;
+	int cphone;
+
+//	printf("parse_answer\n");
+
+	phone = pcall->phone_hash;
+	method = IPC_GET_METHOD(pcall->question);
+	retval = IPC_GET_RETVAL(*answer);
+	printf("phone=%d, method=%d, retval=%d\n",
+		phone, method, retval);
+
+	if (phone == 0 && method == IPC_M_CONNECT_ME_TO && retval == 0) {
+		/* Connected to a service (through NS) */
+		service = IPC_GET_ARG1(pcall->question);
+		proto = proto_get_by_srv(service);
+		if (proto == NULL) proto = &proto_unknown;
+
+		cphone = IPC_GET_ARG5(*answer);
+		printf("registering connection (phone %d, protocol: %s)\n", cphone,
+			proto->name);
+		ipcp_connection_set(cphone, 0, proto);
+	}
+}
+
+void ipcp_call_in(ipc_call_t *call, ipc_callid_t hash)
+{
+	link_t *item;
+	pending_call_t *pcall;
+	unsigned long key[1];
+
+//	printf("ipcp_call_in()\n");
+/*	printf("phone: %d, method: ", call->in_phone_hash);
+	ipc_m_print(IPC_GET_METHOD(*call));
+	printf(" args: (%u, %u, %u, %u, %u)\n",
+	    IPC_GET_ARG1(*call),
+	    IPC_GET_ARG2(*call),
+	    IPC_GET_ARG3(*call),
+	    IPC_GET_ARG4(*call),
+	    IPC_GET_ARG5(*call)
+	);*/
+
+	if ((hash & IPC_CALLID_ANSWERED) == 0 && hash != IPCP_CALLID_SYNC) {
+		/* Not a response */
+		printf("Not a response (hash %d)\n", hash);
+		return;
+	}
+
+	hash = hash & ~IPC_CALLID_ANSWERED;
+	key[0] = hash;
+
+	item = hash_table_find(&pending_calls, key);
+	if (item == NULL) return; // No matching question found
+	
+	pcall = hash_table_get_instance(item, pending_call_t, link);
+
+	printf("response matched to question\n");
+	hash_table_remove(&pending_calls, key, 1);
+
+	parse_answer(pcall, call);
+	free(pcall);
+}
+
+void ipcp_call_sync(int phone, ipc_call_t *call, ipc_call_t *answer)
+{
+	ipcp_call_out(phone, call, IPCP_CALLID_SYNC);
+	ipcp_call_in(answer, IPCP_CALLID_SYNC);
+}
+
+void ipcp_hangup(int phone, int rc)
+{
+	printf("hangup phone %d -> %d\n", phone, rc);
+	ipcp_connection_clear(phone);
+}
+
+/** @}
+ */
Index: uspace/app/trace/ipcp.h
===================================================================
--- uspace/app/trace/ipcp.h	(revision 9a1b20c34d5404b8272209d06c0239aa1a2384da)
+++ uspace/app/trace/ipcp.h	(revision 9a1b20c34d5404b8272209d06c0239aa1a2384da)
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2008 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 trace
+ * @{
+ */
+/** @file
+ */
+
+#ifndef IPCP_H_
+#define IPCP_H_
+
+#include <ipc/ipc.h>
+#include "proto.h"
+
+void ipcp_init(void);
+void ipcp_cleanup(void);
+
+void ipcp_call_out(int phone, ipc_call_t *call, ipc_callid_t hash);
+void ipcp_call_sync(int phone, ipc_call_t *call, ipc_call_t *answer);
+void ipcp_call_in(ipc_call_t *call, ipc_callid_t hash);
+void ipcp_hangup(int phone, int rc);
+
+void ipcp_connection_set(int phone, int server, proto_t *proto);
+void ipcp_connection_clear(int phone);
+
+#endif
+
+/** @}
+ */
Index: uspace/app/trace/proto.c
===================================================================
--- uspace/app/trace/proto.c	(revision 9a1b20c34d5404b8272209d06c0239aa1a2384da)
+++ uspace/app/trace/proto.c	(revision 9a1b20c34d5404b8272209d06c0239aa1a2384da)
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2008 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 trace
+ * @{
+ */
+/** @file
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ipc/ipc.h>
+#include <libadt/hash_table.h>
+
+#include "proto.h"
+
+#define SRV_PROTO_TABLE_CHAINS 32
+#define METHOD_OPER_TABLE_CHAINS 32
+
+hash_table_t srv_proto;
+
+typedef struct {
+	int srv;
+	proto_t *proto;
+	link_t link;
+} srv_proto_t;
+
+typedef struct {
+	ipcarg_t method;
+	oper_t *oper;
+	link_t link;
+} method_oper_t;
+
+static hash_index_t srv_proto_hash(unsigned long key[]);
+static int srv_proto_compare(unsigned long key[], hash_count_t keys,
+    link_t *item);
+static void srv_proto_remove_callback(link_t *item);
+
+hash_table_operations_t srv_proto_ops = {
+	.hash = srv_proto_hash,
+	.compare = srv_proto_compare,
+	.remove_callback = srv_proto_remove_callback
+};
+
+static hash_index_t method_oper_hash(unsigned long key[]);
+static int method_oper_compare(unsigned long key[], hash_count_t keys,
+    link_t *item);
+static void method_oper_remove_callback(link_t *item);
+
+hash_table_operations_t method_oper_ops = {
+	.hash = method_oper_hash,
+	.compare = method_oper_compare,
+	.remove_callback = method_oper_remove_callback
+};
+
+static hash_index_t srv_proto_hash(unsigned long key[])
+{
+	return key[0] % SRV_PROTO_TABLE_CHAINS;
+}
+
+static int srv_proto_compare(unsigned long key[], hash_count_t keys,
+    link_t *item)
+{
+	srv_proto_t *sp;
+
+	sp = hash_table_get_instance(item, srv_proto_t, link);
+
+	return key[0] == sp->srv;
+}
+
+static void srv_proto_remove_callback(link_t *item)
+{
+}
+
+static hash_index_t method_oper_hash(unsigned long key[])
+{
+	return key[0] % METHOD_OPER_TABLE_CHAINS;
+}
+
+static int method_oper_compare(unsigned long key[], hash_count_t keys,
+    link_t *item)
+{
+	method_oper_t *mo;
+
+	mo = hash_table_get_instance(item, method_oper_t, link);
+
+	return key[0] == mo->method;
+}
+
+static void method_oper_remove_callback(link_t *item)
+{
+}
+
+
+void proto_init(void)
+{
+	hash_table_create(&srv_proto, SRV_PROTO_TABLE_CHAINS, 1,
+	    &srv_proto_ops);
+}
+
+void proto_cleanup(void)
+{
+	hash_table_destroy(&srv_proto);
+}
+
+void proto_register(int srv, proto_t *proto)
+{
+	srv_proto_t *sp;
+	unsigned long key;
+
+	sp = malloc(sizeof(srv_proto_t));
+	sp->srv = srv;
+	sp->proto = proto;
+	key = srv;
+
+	hash_table_insert(&srv_proto, &key, &sp->link);
+}
+
+proto_t *proto_get_by_srv(int srv)
+{
+	unsigned long key;
+	link_t *item;
+	srv_proto_t *sp;
+
+	key = srv;
+	item = hash_table_find(&srv_proto, &key);
+	if (item == NULL) return NULL;
+
+	sp = hash_table_get_instance(item, srv_proto_t, link);
+	return sp->proto;
+}
+
+static void proto_struct_init(proto_t *proto, char *name)
+{
+	proto->name = name;
+	hash_table_create(&proto->method_oper, SRV_PROTO_TABLE_CHAINS, 1,
+	    &method_oper_ops);
+}
+
+proto_t *proto_new(char *name)
+{
+	proto_t *p;
+
+	p = malloc(sizeof(proto_t));
+	proto_struct_init(p, name);
+
+	return p;
+}
+
+void proto_add_oper(proto_t *proto, int method, oper_t *oper)
+{
+	method_oper_t *mo;
+	unsigned long key;
+
+	mo = malloc(sizeof(method_oper_t));
+	mo->method = method;
+	mo->oper = oper;
+	key = method;
+
+	hash_table_insert(&proto->method_oper, &key, &mo->link);	
+}
+
+oper_t *proto_get_oper(proto_t *proto, int method)
+{
+	unsigned long key;
+	link_t *item;
+	method_oper_t *mo;
+
+	key = method;
+	item = hash_table_find(&proto->method_oper, &key);
+	if (item == NULL) return NULL;
+
+	mo = hash_table_get_instance(item, method_oper_t, link);
+	return mo->oper;
+}
+
+static void oper_struct_init(oper_t *oper, char *name)
+{
+	oper->name = name;
+}
+
+oper_t *oper_new(char *name)
+{
+	oper_t *o;
+
+	o = malloc(sizeof(oper_t));
+	oper_struct_init(o, name);
+
+	return o;
+}
+
+/** @}
+ */
Index: uspace/app/trace/proto.h
===================================================================
--- uspace/app/trace/proto.h	(revision 9a1b20c34d5404b8272209d06c0239aa1a2384da)
+++ uspace/app/trace/proto.h	(revision 9a1b20c34d5404b8272209d06c0239aa1a2384da)
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2008 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 trace
+ * @{
+ */
+/** @file
+ */
+
+#ifndef PROTO_H_
+#define PROTO_H_
+
+#include <libadt/hash_table.h>
+
+typedef struct {
+	char *name;
+} oper_t;
+
+typedef struct {
+	/** Protocol name */
+	char *name;
+
+	/** Maps method number to operation */
+	hash_table_t method_oper;
+} proto_t;
+
+/* Maps service number to protocol */
+extern hash_table_t srv_proto;
+
+void proto_init(void);
+void proto_cleanup(void);
+
+void proto_register(int srv, proto_t *proto);
+proto_t *proto_get_by_srv(int srv);
+proto_t *proto_new(char *name);
+void proto_add_oper(proto_t *proto, int method, oper_t *oper);
+oper_t *proto_get_oper(proto_t *proto, int method);
+
+oper_t *oper_new(char *name);
+
+
+#endif
+
+/** @}
+ */
Index: uspace/app/trace/syscalls.c
===================================================================
--- uspace/app/trace/syscalls.c	(revision 9a1b20c34d5404b8272209d06c0239aa1a2384da)
+++ uspace/app/trace/syscalls.c	(revision 9a1b20c34d5404b8272209d06c0239aa1a2384da)
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2008 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 trace
+ * @{
+ */
+/** @file
+ */
+
+#include <kernel/syscall/syscall.h>
+#include "syscalls.h"
+
+const sc_desc_t syscall_desc[] = {
+    [SYS_KLOG] ={ "klog",				3,	RV_INT_ERRNO },
+    [SYS_TLS_SET] = { "tls_set",			1,	RV_ERRNO },
+    [SYS_THREAD_CREATE] = { "thread_create",		3,	RV_ERRNO },
+    [SYS_THREAD_EXIT] = { "thread_exit",		1,	RV_ERRNO },
+    [SYS_THREAD_GET_ID] = { "thread_get_id",		1,	RV_ERRNO },
+
+    [SYS_TASK_GET_ID] = { "task_get_id",		1,	RV_ERRNO },
+    [SYS_FUTEX_SLEEP] = { "futex_sleep_timeout",	3,	RV_ERRNO },
+    [SYS_FUTEX_WAKEUP] = { "futex_wakeup",		1,	RV_ERRNO },
+
+    [SYS_AS_AREA_CREATE] = { "as_area_create",		3,	RV_ERRNO },
+    [SYS_AS_AREA_RESIZE] = { "as_area_resize",		3,	RV_ERRNO },
+    [SYS_AS_AREA_DESTROY] = { "as_area_destroy",	1,	RV_ERRNO },
+
+    [SYS_IPC_CALL_SYNC_FAST] = { "ipc_call_sync_fast",	6,	RV_ERRNO },
+    [SYS_IPC_CALL_SYNC_SLOW] = { "ipc_call_sync_slow",	3,	RV_ERRNO },
+    [SYS_IPC_CALL_ASYNC_FAST] = { "ipc_call_async_fast", 6,	RV_HASH },
+    [SYS_IPC_CALL_ASYNC_SLOW] = { "ipc_call_async_slow", 2,	RV_HASH },
+
+    [SYS_IPC_ANSWER_FAST] = { "ipc_answer_fast",	6,	RV_ERRNO },
+    [SYS_IPC_ANSWER_SLOW] = { "ipc_answer_slow",	2,	RV_ERRNO },
+    [SYS_IPC_FORWARD_FAST] = { "ipc_forward_fast",	6,	RV_ERRNO },
+    [SYS_IPC_WAIT] = { "ipc_wait_for_call",		3,	RV_HASH },
+    [SYS_IPC_HANGUP] = { "ipc_hangup",			1,	RV_ERRNO },
+    [SYS_IPC_REGISTER_IRQ] = { "ipc_register_irq",	4,	RV_ERRNO },
+    [SYS_IPC_UNREGISTER_IRQ] = { "ipc_unregister_irq",	2,	RV_ERRNO },
+
+    [SYS_CAP_GRANT] = { "cap_grant",			2,	RV_ERRNO },
+    [SYS_CAP_REVOKE] = { "cap_revoke",			2,	RV_ERRNO },
+    [SYS_PHYSMEM_MAP] = { "physmem_map",		4,	RV_ERRNO },
+    [SYS_IOSPACE_ENABLE] = { "iospace_enable",		1,	RV_ERRNO },
+    [SYS_PREEMPT_CONTROL] = { "preempt_control",	1,	RV_ERRNO },
+
+    [SYS_SYSINFO_VALID] = { "sysinfo_valid",		2,	RV_HASH },
+    [SYS_SYSINFO_VALUE] = { "sysinfo_value",		2,	RV_HASH },
+    [SYS_DEBUG_ENABLE_CONSOLE] = { "debug_enable_console", 0,	RV_ERRNO },
+    [SYS_IPC_CONNECT_KBOX] = { "ipc_connect_kbox",	1,	RV_ERRNO }
+};
+
+/** @}
+ */
Index: uspace/app/trace/syscalls.h
===================================================================
--- uspace/app/trace/syscalls.h	(revision 9a1b20c34d5404b8272209d06c0239aa1a2384da)
+++ uspace/app/trace/syscalls.h	(revision 9a1b20c34d5404b8272209d06c0239aa1a2384da)
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2008 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 trace
+ * @{
+ */
+/** @file
+ */
+
+#ifndef SYSCALLS_H_
+#define SYSCALLS_H_
+
+typedef enum {
+	RV_INTEGER,
+	RV_HASH,
+	RV_ERRNO,
+	RV_INT_ERRNO
+} rv_type_t;
+
+typedef struct {
+	char *name;
+	int n_args;
+	rv_type_t rv_type;
+} sc_desc_t;
+
+extern const sc_desc_t syscall_desc[];
+
+#endif
+
+/** @}
+ */
Index: uspace/app/trace/trace.c
===================================================================
--- uspace/app/trace/trace.c	(revision 9a1b20c34d5404b8272209d06c0239aa1a2384da)
+++ uspace/app/trace/trace.c	(revision 9a1b20c34d5404b8272209d06c0239aa1a2384da)
@@ -0,0 +1,542 @@
+/*
+ * Copyright (c) 2008 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 trace
+ * @{
+ */
+/** @file
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syscall.h>
+#include <ipc/ipc.h>
+#include <fibril.h>
+#include <errno.h>
+#include <udebug.h>
+#include <async.h>
+
+// Temporary: service and method names
+#include "proto.h"
+#include <ipc/services.h>
+#include "../../srv/vfs/vfs.h"
+#include "../../srv/console/console.h"
+
+#include "syscalls.h"
+#include "ipcp.h"
+#include "errors.h"
+
+#define THBUF_SIZE 64
+unsigned thread_hash_buf[THBUF_SIZE];
+unsigned n_threads;
+
+int next_thread_id;
+
+int phoneid;
+int abort_trace;
+
+unsigned thash;
+volatile int paused;
+
+void thread_trace_start(unsigned thread_hash);
+
+static proto_t *proto_console;
+
+static int task_connect(task_id_t task_id)
+{
+	int rc;
+
+	printf("ipc_connect_task(%lld)... ", task_id);
+	rc = ipc_connect_kbox(task_id);
+	printf("-> %d\n", rc);
+	phoneid = rc;
+	if (rc < 0) return rc;
+
+	printf("udebug_begin()... ");
+	rc = udebug_begin(phoneid);
+	printf("-> %d\n", rc);
+	if (rc < 0) return rc;
+
+	printf("udebug_set_evmask(0x%x)... ", UDEBUG_EM_ALL);
+	rc = udebug_set_evmask(phoneid, UDEBUG_EM_ALL);
+	printf("-> %d\n", rc);
+	if (rc < 0) return rc;
+
+	return 0;
+}
+
+static int get_thread_list(void)
+{
+	int rc;
+	size_t tb_copied;
+	size_t tb_needed;
+	int i;
+
+	printf("send IPC_M_DEBUG_THREAD_READ message\n");
+	rc = udebug_thread_read(phoneid, thread_hash_buf,
+		THBUF_SIZE*sizeof(unsigned), &tb_copied, &tb_needed);
+	printf("-> %d\n", rc);
+	if (rc < 0) return rc;
+
+	n_threads = tb_copied / sizeof(unsigned);
+
+	printf("thread IDs:");
+	for (i=0; i<n_threads; i++) {
+		printf(" %u", thread_hash_buf[i]);
+	}
+	printf("\ntotal of %u threads\n", tb_needed/sizeof(unsigned));
+
+	return 0;
+}
+
+static void print_sc_retval(int retval, rv_type_t rv_type)
+{
+	printf (" -> ");
+	if (rv_type == RV_INTEGER) {
+		printf("%d", retval);
+	} else if (rv_type == RV_HASH) {
+		printf("0x%08x", retval);
+	} else if (rv_type == RV_ERRNO) {
+		if (retval >= -15 && retval <= 0) {
+			printf("%d %s (%s)", retval,
+			    err_desc[retval].name,
+			    err_desc[retval].desc);
+		} else {
+			printf("%d", retval);
+		}
+	} else if (rv_type == RV_INT_ERRNO) {
+		if (retval >= -15 && retval < 0) {
+			printf("%d %s (%s)", retval,
+			    err_desc[retval].name,
+			    err_desc[retval].desc);
+		} else {
+			printf("%d", retval);
+		}
+	}
+	putchar('\n');
+}
+
+static void print_sc_args(unsigned *sc_args, int n)
+{
+	int i;
+
+	putchar('(');
+	if (n > 0) printf("%d", sc_args[0]);
+	for (i=1; i<n; i++) {
+		printf(", %d", sc_args[i]);
+	}
+	putchar(')');
+}
+
+static void sc_ipc_call_async_fast(unsigned *sc_args, int sc_rc)
+{
+	ipc_call_t call;
+	int phoneid;
+	
+	if (sc_rc == IPC_CALLRET_FATAL || sc_rc == IPC_CALLRET_TEMPORARY)
+		return;
+
+	phoneid = sc_args[0];
+
+	IPC_SET_METHOD(call, sc_args[1]);
+	IPC_SET_ARG1(call, sc_args[2]);
+	IPC_SET_ARG2(call, sc_args[3]);
+	IPC_SET_ARG3(call, sc_args[4]);
+	IPC_SET_ARG4(call, sc_args[5]);
+	IPC_SET_ARG5(call, 0);
+
+	ipcp_call_out(phoneid, &call, sc_rc);
+}
+
+static void sc_ipc_call_async_slow(unsigned *sc_args, int sc_rc)
+{
+	ipc_call_t call;
+	int rc;
+
+	if (sc_rc == IPC_CALLRET_FATAL || sc_rc == IPC_CALLRET_TEMPORARY)
+		return;
+
+	memset(&call, 0, sizeof(call));
+	rc = udebug_mem_read(phoneid, &call.args, sc_args[1], sizeof(call.args));
+
+	if (rc >= 0) {
+		ipcp_call_out(sc_args[0], &call, sc_rc);
+	}
+}
+
+static void sc_ipc_call_sync_fast(unsigned *sc_args)
+{
+	ipc_call_t question, reply;
+	int rc;
+	int phoneidx;
+
+//	printf("sc_ipc_call_sync_fast()\n");
+	phoneidx = sc_args[0];
+
+	IPC_SET_METHOD(question, sc_args[1]);
+	IPC_SET_ARG1(question, sc_args[2]);
+	IPC_SET_ARG2(question, sc_args[3]);
+	IPC_SET_ARG3(question, sc_args[4]);
+	IPC_SET_ARG4(question, 0);
+	IPC_SET_ARG5(question, 0);
+
+//	printf("memset\n");
+	memset(&reply, 0, sizeof(reply));
+//	printf("udebug_mem_read(phone=%d, buffer_ptr=%u, src_addr=%d, n=%d\n",
+//		phoneid, &reply.args, sc_args[5], sizeof(reply.args));
+	rc = udebug_mem_read(phoneid, &reply.args, sc_args[5], sizeof(reply.args));
+//	printf("dmr->%d\n", rc);
+	if (rc < 0) return;
+
+//	printf("call ipc_call_sync\n");
+	ipcp_call_sync(phoneidx, &question, &reply);
+}
+
+static void sc_ipc_call_sync_slow(unsigned *sc_args)
+{
+	ipc_call_t question, reply;
+	int rc;
+
+	memset(&question, 0, sizeof(question));
+	rc = udebug_mem_read(phoneid, &question.args, sc_args[1], sizeof(question.args));
+	printf("dmr->%d\n", rc);
+	if (rc < 0) return;
+
+	memset(&reply, 0, sizeof(reply));
+	rc = udebug_mem_read(phoneid, &reply.args, sc_args[2], sizeof(reply.args));
+	printf("dmr->%d\n", rc);
+	if (rc < 0) return;
+
+	ipcp_call_sync(sc_args[0], &question, &reply);
+}
+
+static void sc_ipc_wait(unsigned *sc_args, int sc_rc)
+{
+	ipc_call_t call;
+	int rc;
+
+	if (sc_rc == 0) return;
+
+	memset(&call, 0, sizeof(call));
+	rc = udebug_mem_read(phoneid, &call, sc_args[0], sizeof(call));
+//	printf("udebug_mem_read(phone %d, dest %d, app-mem src %d, size %d -> %d\n",
+//		phoneid, (int)&call, sc_args[0], sizeof(call), rc);
+
+	if (rc >= 0) {
+		ipcp_call_in(&call, sc_rc);
+	}
+}
+
+static void event_syscall_b(unsigned thread_id, unsigned thread_hash,  unsigned sc_id, int sc_rc)
+{
+	unsigned sc_args[6];
+	int rc;
+
+	/* Read syscall arguments */
+	rc = udebug_args_read(phoneid, thread_hash, sc_args);
+
+	async_serialize_start();
+
+//	printf("[%d] ", thread_id);
+
+	if (rc < 0) {
+		printf("error\n");
+		async_serialize_end();
+		return;
+	}
+
+	/* Print syscall name, id and arguments */
+	printf("%s", syscall_desc[sc_id].name);
+	print_sc_args(sc_args, syscall_desc[sc_id].n_args);
+
+	async_serialize_end();
+}
+
+static void event_syscall_e(unsigned thread_id, unsigned thread_hash,  unsigned sc_id, int sc_rc)
+{
+	unsigned sc_args[6];
+	int rv_type;
+	int rc;
+
+	/* Read syscall arguments */
+	rc = udebug_args_read(phoneid, thread_hash, sc_args);
+
+	async_serialize_start();
+
+//	printf("[%d] ", thread_id);
+
+	if (rc < 0) {
+		printf("error\n");
+		async_serialize_end();
+		return;
+	}
+
+	rv_type = syscall_desc[sc_id].rv_type;
+	print_sc_retval(sc_rc, rv_type);
+
+	switch (sc_id) {
+	case SYS_IPC_CALL_ASYNC_FAST:
+		sc_ipc_call_async_fast(sc_args, sc_rc);
+		break;
+	case SYS_IPC_CALL_ASYNC_SLOW:
+		sc_ipc_call_async_slow(sc_args, sc_rc);
+		break;
+	case SYS_IPC_CALL_SYNC_FAST:
+		sc_ipc_call_sync_fast(sc_args);
+		break;
+	case SYS_IPC_CALL_SYNC_SLOW:
+		sc_ipc_call_sync_slow(sc_args);
+		break;
+	case SYS_IPC_WAIT:
+		sc_ipc_wait(sc_args, sc_rc);
+		break;
+	default:
+		break;
+	}
+
+	async_serialize_end();
+}
+
+static void event_thread_b(unsigned hash)
+{
+	async_serialize_start();
+	printf("new thread, hash 0x%x\n", hash);
+	async_serialize_end();
+
+	thread_trace_start(hash);
+}
+
+static int trace_loop(void *thread_hash_arg)
+{
+	int rc;
+	unsigned ev_type;
+	unsigned thread_hash;
+	unsigned thread_id;
+	unsigned val0, val1;
+
+	thread_hash = (unsigned)thread_hash_arg;
+	thread_id = next_thread_id++;
+
+	printf("trace_loop(%d)\n", thread_id);	
+
+	while (!abort_trace) {
+
+		/* Run thread until an event occurs */
+		rc = udebug_go(phoneid, thread_hash,
+		    &ev_type, &val0, &val1);
+
+//		printf("rc = %d, ev_type=%d\n", rc, ev_type);
+		if (ev_type == UDEBUG_EVENT_FINISHED) {
+			printf("thread %u debugging finished\n", thread_id);
+			break;
+		}
+
+		if (rc >= 0) {
+			switch (ev_type) {
+			case UDEBUG_EVENT_SYSCALL_B:
+				event_syscall_b(thread_id, thread_hash, val0, (int)val1);
+				break;
+			case UDEBUG_EVENT_SYSCALL_E:
+				event_syscall_e(thread_id, thread_hash, val0, (int)val1);
+				break;
+			case UDEBUG_EVENT_STOP:
+				printf("stop event\n");
+				printf("waiting for resume\n");
+				while (paused) {
+					usleep(1000000);
+					fibril_yield();
+					printf(".");
+				}
+				printf("resumed\n");
+				break;
+			case UDEBUG_EVENT_THREAD_B:
+				event_thread_b(val0);
+				break;
+			case UDEBUG_EVENT_THREAD_E:
+				printf("thread 0x%x exited\n", val0);
+				abort_trace = 1;
+				break;
+			default:
+				printf("unknown event type %d\n", ev_type);
+				break;
+			}
+		}
+
+	}
+
+	printf("trace_loop(%d) exiting\n", thread_id);
+	return 0;
+}
+
+void thread_trace_start(unsigned thread_hash)
+{
+	fid_t fid;
+
+	thash = thread_hash;
+
+	fid = fibril_create(trace_loop, (void *)thread_hash);
+	if (fid == 0) {
+		printf("Warning: Failed creating fibril\n");
+	}
+	fibril_add_ready(fid);
+}
+
+static void trace_active_task(task_id_t task_id)
+{
+	int i;
+	int rc;
+	int c;
+
+	printf("Syscall Tracer\n");
+
+	rc = task_connect(task_id);
+	if (rc < 0) {
+		printf("Failed to connect to task %lld\n", task_id);
+		return;
+	}
+
+	printf("Connected to task %lld\n", task_id);
+
+	ipcp_init();
+	ipcp_connection_set(1, 0, proto_console);
+
+	rc = get_thread_list();
+	if (rc < 0) {
+		printf("Failed to get thread list (error %d)\n", rc);
+		return;
+	}
+
+	abort_trace = 0;
+
+	for (i = 0; i < n_threads; i++) {
+		thread_trace_start(thread_hash_buf[i]);
+	}
+
+	while(1) {
+		c = getchar();
+		if (c == 'q') break;
+		if (c == 'p') {
+			paused = 1;
+			rc = udebug_stop(phoneid, thash);
+			printf("stop -> %d\n", rc);
+		}
+		if (c == 'r') {
+			paused = 0;
+		}
+	}
+
+	printf("terminate debugging session...\n");
+	abort_trace = 1;
+	udebug_end(phoneid);
+	ipc_hangup(phoneid);
+
+	ipcp_cleanup();
+
+	printf("done\n");
+	return;
+}
+
+static void main_init(void)
+{
+	proto_t *p;
+	oper_t *o;
+
+	next_thread_id = 1;
+	paused = 0;
+
+	proto_init();
+
+	p = proto_new("vfs");
+	o = oper_new("read");
+	proto_add_oper(p, VFS_READ, o);
+	o = oper_new("write");
+	proto_add_oper(p, VFS_WRITE, o);
+	o = oper_new("truncate");
+	proto_add_oper(p, VFS_TRUNCATE, o);
+	o = oper_new("mount");
+	proto_add_oper(p, VFS_MOUNT, o);
+	o = oper_new("unmount");
+	proto_add_oper(p, VFS_UNMOUNT, o);
+
+	proto_register(SERVICE_VFS, p);
+
+	p = proto_new("console");
+	o = oper_new("getchar");
+	proto_add_oper(p, CONSOLE_GETCHAR, o);
+	o = oper_new("putchar");
+	proto_add_oper(p, CONSOLE_PUTCHAR, o);
+	o = oper_new("clear");
+	proto_add_oper(p, CONSOLE_CLEAR, o);
+	o = oper_new("goto");
+	proto_add_oper(p, CONSOLE_GOTO, o);
+	o = oper_new("getsize");
+	proto_add_oper(p, CONSOLE_GETSIZE, o);
+	o = oper_new("flush");
+	proto_add_oper(p, CONSOLE_FLUSH, o);
+	o = oper_new("set_style");
+	proto_add_oper(p, CONSOLE_SET_STYLE, o);
+	o = oper_new("cursor_visibility");
+	proto_add_oper(p, CONSOLE_CURSOR_VISIBILITY, o);
+	o = oper_new("flush");
+	proto_add_oper(p, CONSOLE_FLUSH, o);
+
+	proto_console = p;
+	proto_register(SERVICE_CONSOLE, p);
+}
+
+static void print_syntax()
+{
+	printf("syntax: trace <task_id>\n");
+}
+
+int main(int argc, char *argv[])
+{
+	task_id_t task_id;
+	char *err_p;
+
+	if (argc != 2) {
+		printf("Mising argument\n");
+		print_syntax();
+		return 1;
+	}
+
+	task_id = strtol(argv[1], &err_p, 10);
+
+	if (*err_p) {
+		printf("Task ID syntax error\n");
+		print_syntax();
+		return 1;
+	}
+
+	main_init();
+	trace_active_task(task_id);
+}
+
+/** @}
+ */
