Index: kernel/generic/include/interrupt.h
===================================================================
--- kernel/generic/include/interrupt.h	(revision 8f80c776122ce206c51851f4cac39bcd4a236d9a)
+++ kernel/generic/include/interrupt.h	(revision 8eec3c82a9d04f56cd45c25f1e2466f94a863763)
@@ -46,4 +46,14 @@
 typedef void (* iroutine)(int, istate_t *);
 
+typedef struct {
+	const char *name;
+	iroutine f;
+	uint64_t cycles;
+	uint64_t count;
+} exc_table_t;
+
+IRQ_SPINLOCK_EXTERN(exctbl_lock);
+extern exc_table_t exc_table[];
+
 extern void fault_if_from_uspace(istate_t *, const char *, ...);
 extern iroutine exc_register(int, const char *, iroutine);
Index: kernel/generic/include/sysinfo/abi.h
===================================================================
--- kernel/generic/include/sysinfo/abi.h	(revision 8f80c776122ce206c51851f4cac39bcd4a236d9a)
+++ kernel/generic/include/sysinfo/abi.h	(revision 8eec3c82a9d04f56cd45c25f1e2466f94a863763)
@@ -40,6 +40,7 @@
 #define LOAD_STEPS  3
 
-/** Maximum task name size */
+/** Maximum name sizes */
 #define TASK_NAME_BUFLEN  20
+#define EXC_NAME_BUFLEN   20
 
 /** Thread states */
@@ -123,4 +124,14 @@
 } stats_thread_t;
 
+/** Statistics about a single exception
+ *
+ */
+typedef struct {
+	unsigned int id;             /**< Exception ID */
+	char desc[EXC_NAME_BUFLEN];  /**< Description */
+	uint64_t cycles;             /**< Number of CPU cycles in the handler */
+	uint64_t count;              /**< Number of handled exceptions */
+} stats_exc_t;
+
 /** Load fixed-point value */
 typedef uint32_t load_t;
Index: kernel/generic/src/interrupt/interrupt.c
===================================================================
--- kernel/generic/src/interrupt/interrupt.c	(revision 8f80c776122ce206c51851f4cac39bcd4a236d9a)
+++ kernel/generic/src/interrupt/interrupt.c	(revision 8eec3c82a9d04f56cd45c25f1e2466f94a863763)
@@ -53,11 +53,9 @@
 #include <symtab.h>
 #include <proc/thread.h>
-
-static struct {
-	const char *name;
-	iroutine f;
-} exc_table[IVT_ITEMS];
-
-SPINLOCK_INITIALIZE(exctbl_lock);
+#include <arch/cycle.h>
+#include <str.h>
+
+exc_table_t exc_table[IVT_ITEMS];
+IRQ_SPINLOCK_INITIALIZE(exctbl_lock);
 
 /** Register exception handler
@@ -72,11 +70,13 @@
 	ASSERT(n < IVT_ITEMS);
 	
-	spinlock_lock(&exctbl_lock);
+	irq_spinlock_lock(&exctbl_lock, true);
 	
 	iroutine old = exc_table[n].f;
 	exc_table[n].f = handler;
 	exc_table[n].name = name;
-	
-	spinlock_unlock(&exctbl_lock);
+	exc_table[n].cycles = 0;
+	exc_table[n].count = 0;
+	
+	irq_spinlock_unlock(&exctbl_lock, true);
 	
 	return old;
@@ -92,9 +92,11 @@
 {
 	ASSERT(n < IVT_ITEMS);
+	
+	uint64_t begin_cycle = get_cycle();
 	
 	/* Account user cycles */
 	if (THREAD) {
 		irq_spinlock_lock(&THREAD->lock, false);
-		thread_update_accounting(true);
+		THREAD->ucycles += begin_cycle - THREAD->last_cycle;
 		irq_spinlock_unlock(&THREAD->lock, false);
 	}
@@ -116,7 +118,13 @@
 		thread_exit();
 	
+	/* Account exception handling */
+	uint64_t end_cycle = get_cycle();
+	exc_table[n].cycles += end_cycle - begin_cycle;
+	exc_table[n].count++;
+	
+	/* Do not charge THREAD for exception cycles */
 	if (THREAD) {
 		irq_spinlock_lock(&THREAD->lock, false);
-		thread_update_accounting(false);
+		THREAD->last_cycle = end_cycle;
 		irq_spinlock_unlock(&THREAD->lock, false);
 	}
@@ -185,39 +193,52 @@
 	unsigned int i;
 	
-	spinlock_lock(&exctbl_lock);
+	irq_spinlock_lock(&exctbl_lock, true);
 	
 #ifdef __32_BITS__
-	printf("Exc Description          Handler    Symbol\n");
-	printf("--- -------------------- ---------- --------\n");
+	printf("Exc Description          Count      Cycles     Handler    Symbol\n");
+	printf("--- -------------------- ---------- ---------- ---------- --------\n");
 #endif
 	
 #ifdef __64_BITS__
-	printf("Exc Description          Handler            Symbol\n");
-	printf("--- -------------------- ------------------ --------\n");
+	printf("Exc Description          Count      Cycles     Handler            Symbol\n");
+	printf("--- -------------------- ---------- ---------- ------------------ --------\n");
 #endif
 	
 	for (i = 0; i < IVT_ITEMS; i++) {
-		const char *symbol = symtab_fmt_name_lookup((unative_t) exc_table[i].f);
+		uint64_t count;
+		char count_suffix;
+		
+		order_suffix(exc_table[i].count, &count, &count_suffix);
+		
+		uint64_t cycles;
+		char cycles_suffix;
+		
+		order_suffix(exc_table[i].cycles, &cycles, &cycles_suffix);
+		
+		const char *symbol =
+		    symtab_fmt_name_lookup((unative_t) exc_table[i].f);
 		
 #ifdef __32_BITS__
-		printf("%-3u %-20s %10p %s\n", i + IVT_FIRST, exc_table[i].name,
-			exc_table[i].f, symbol);
+		printf("%-3u %-20s %9" PRIu64 "%c %9" PRIu64 "%c %10p %s\n",
+		    i + IVT_FIRST, exc_table[i].name, count, count_suffix,
+		    cycles, cycles_suffix, exc_table[i].f, symbol);
 #endif
 		
 #ifdef __64_BITS__
-		printf("%-3u %-20s %18p %s\n", i + IVT_FIRST, exc_table[i].name,
-			exc_table[i].f, symbol);
+		printf("%-3u %-20s %9" PRIu64 "%c %9" PRIu64 "%c %18p %s\n",
+		    i + IVT_FIRST, exc_table[i].name, count, count_suffix,
+		    cycles, cycles_suffix, exc_table[i].f, symbol);
 #endif
 		
 		if (((i + 1) % 20) == 0) {
 			printf(" -- Press any key to continue -- ");
-			spinlock_unlock(&exctbl_lock);
+			irq_spinlock_unlock(&exctbl_lock, true);
 			indev_pop_character(stdin);
-			spinlock_lock(&exctbl_lock);
+			irq_spinlock_lock(&exctbl_lock, true);
 			printf("\n");
 		}
 	}
 	
-	spinlock_unlock(&exctbl_lock);
+	irq_spinlock_unlock(&exctbl_lock, true);
 #endif
 	
Index: kernel/generic/src/sysinfo/stats.c
===================================================================
--- kernel/generic/src/sysinfo/stats.c	(revision 8f80c776122ce206c51851f4cac39bcd4a236d9a)
+++ kernel/generic/src/sysinfo/stats.c	(revision 8eec3c82a9d04f56cd45c25f1e2466f94a863763)
@@ -44,4 +44,5 @@
 #include <proc/task.h>
 #include <proc/thread.h>
+#include <interrupt.h>
 #include <str.h>
 #include <errno.h>
@@ -535,4 +536,115 @@
 }
 
+/** Get exceptions statistics
+ *
+ * @param item    Sysinfo item (unused).
+ * @param size    Size of the returned data.
+ * @param dry_run Do not get the data, just calculate the size.
+ *
+ * @return Data containing several stats_exc_t structures.
+ *         If the return value is not NULL, it should be freed
+ *         in the context of the sysinfo request.
+ */
+static void *get_stats_exceptions(struct sysinfo_item *item, size_t *size,
+    bool dry_run)
+{
+	*size = sizeof(stats_exc_t) * IVT_ITEMS;
+	
+	if ((dry_run) || (IVT_ITEMS == 0))
+		return NULL;
+	
+	stats_exc_t *stats_exceptions =
+	    (stats_exc_t *) malloc(*size, FRAME_ATOMIC);
+	if (stats_exceptions == NULL) {
+		/* No free space for allocation */
+		*size = 0;
+		return NULL;
+	}
+	
+	/* Messing with exception table, avoid deadlock */
+	irq_spinlock_lock(&exctbl_lock, true);
+	
+	unsigned int i;
+	for (i = 0; i < IVT_ITEMS; i++) {
+		stats_exceptions[i].id = i + IVT_FIRST;
+		str_cpy(stats_exceptions[i].desc, EXC_NAME_BUFLEN, exc_table[i].name);
+		stats_exceptions[i].cycles = exc_table[i].cycles;
+		stats_exceptions[i].count = exc_table[i].count;
+	}
+	
+	irq_spinlock_unlock(&exctbl_lock, true);
+	
+	return ((void *) stats_exceptions);
+}
+
+/** Get exception statistics
+ *
+ * Get statistics of a given exception. The exception number
+ * is passed as a string (current limitation of the sysinfo
+ * interface, but it is still reasonable for the given purpose).
+ *
+ * @param name    Exception number (string-encoded number).
+ * @param dry_run Do not get the data, just calculate the size.
+ *
+ * @return Sysinfo return holder. The type of the returned
+ *         data is either SYSINFO_VAL_UNDEFINED (unknown
+ *         exception number or memory allocation error) or
+ *         SYSINFO_VAL_FUNCTION_DATA (in that case the
+ *         generated data should be freed within the
+ *         sysinfo request context).
+ *
+ */
+static sysinfo_return_t get_stats_exception(const char *name, bool dry_run)
+{
+	/* Initially no return value */
+	sysinfo_return_t ret;
+	ret.tag = SYSINFO_VAL_UNDEFINED;
+	
+	/* Parse the exception number */
+	uint64_t excn;
+	if (str_uint64(name, NULL, 0, true, &excn) != EOK)
+		return ret;
+	
+#if IVT_FIRST > 0
+	if (excn < IVT_FIRST)
+		return ret;
+#endif
+	
+	if (excn >= IVT_ITEMS + IVT_FIRST)
+		return ret;
+	
+	if (dry_run) {
+		ret.tag = SYSINFO_VAL_FUNCTION_DATA;
+		ret.data.data = NULL;
+		ret.data.size = sizeof(stats_thread_t);
+	} else {
+		/* Update excn index for accessing exc_table */
+		excn -= IVT_FIRST;
+		
+		/* Allocate stats_exc_t structure */
+		stats_exc_t *stats_exception =
+		    (stats_exc_t *) malloc(sizeof(stats_exc_t), FRAME_ATOMIC);
+		if (stats_exception == NULL)
+			return ret;
+		
+		/* Messing with exception table, avoid deadlock */
+		irq_spinlock_lock(&exctbl_lock, true);
+		
+		/* Correct return value */
+		ret.tag = SYSINFO_VAL_FUNCTION_DATA;
+		ret.data.data = (void *) stats_exception;
+		ret.data.size = sizeof(stats_exc_t);
+		
+		stats_exception->id = excn;
+		str_cpy(stats_exception->desc, EXC_NAME_BUFLEN, exc_table[excn].name);
+		stats_exception->cycles = exc_table[excn].cycles;
+		stats_exception->count = exc_table[excn].count;
+		
+		irq_spinlock_unlock(&exctbl_lock, true);
+	}
+	
+	return ret;
+}
+
 /** Get physical memory statistics
  *
@@ -651,6 +763,8 @@
 	sysinfo_set_item_fn_data("system.tasks", NULL, get_stats_tasks);
 	sysinfo_set_item_fn_data("system.threads", NULL, get_stats_threads);
+	sysinfo_set_item_fn_data("system.exceptions", NULL, get_stats_exceptions);
 	sysinfo_set_subtree_fn("system.tasks", NULL, get_stats_task);
 	sysinfo_set_subtree_fn("system.threads", NULL, get_stats_thread);
+	sysinfo_set_subtree_fn("system.exceptions", NULL, get_stats_exception);
 }
 
