auto import from //depot/cupcake/@135843
diff --git a/libdb/db_debug.c b/libdb/db_debug.c
new file mode 100644
index 0000000..0575570
--- /dev/null
+++ b/libdb/db_debug.c
@@ -0,0 +1,132 @@
+/**
+ * @file db_debug.c
+ * Debug routines for libdb
+ *
+ * @remark Copyright 2002 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author Philippe Elie
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "odb.h"
+
+static int check_circular_list(odb_data_t const * data)
+{
+	odb_node_nr_t pos;
+	int do_abort = 0;
+	unsigned char * bitmap = malloc(data->descr->current_size);
+	memset(bitmap, '\0', data->descr->current_size);
+
+	for (pos = 0 ; pos < data->descr->size * BUCKET_FACTOR ; ++pos) {
+
+		odb_index_t index = data->hash_base[pos];
+		if (index && !do_abort) {
+			while (index) {
+				if (bitmap[index])
+					do_abort = 1;
+
+				bitmap[index] = 1;
+				index = data->node_base[index].next;
+			}
+		}
+
+		if (do_abort) {
+			printf("circular list detected size: %d\n",
+			       data->descr->current_size);
+
+			memset(bitmap, '\0', data->descr->current_size);
+
+			index = data->hash_base[pos];
+			while (index) {
+				printf("%d ", index);
+				if (bitmap[index])
+					exit(1);
+
+				bitmap[index] = 1;
+				index = data->node_base[index].next;
+			}
+		}
+
+		/* purely an optimization: intead of memset the map reset only
+		 * the needed part: not my use to optimize test but here the
+		 * test was so slow it was useless */
+		index = data->hash_base[pos];
+		while (index) {
+			bitmap[index] = 1;
+			index = data->node_base[index].next;
+		}
+	}
+
+	free(bitmap);
+
+	return do_abort;
+}
+
+static int check_redundant_key(odb_data_t const * data, odb_key_t max)
+{
+	odb_node_nr_t pos;
+
+	unsigned char * bitmap = malloc(max + 1);
+	memset(bitmap, '\0', max + 1);
+
+	for (pos = 1 ; pos < data->descr->current_size ; ++pos) {
+		if (bitmap[data->node_base[pos].key]) {
+			printf("redundant key found %lld\n",
+			       (unsigned long long)data->node_base[pos].key);
+			return 1;
+		}
+		bitmap[data->node_base[pos].key] = 1;
+	}
+	free(bitmap);
+
+	return 0;
+}
+
+int odb_check_hash(odb_t const * odb)
+{
+	odb_node_nr_t pos;
+	odb_node_nr_t nr_node = 0;
+	odb_node_nr_t nr_node_out_of_bound = 0;
+	int ret = 0;
+	odb_key_t max = 0;
+	odb_data_t * data = odb->data;
+
+	for (pos = 0 ; pos < data->descr->size * BUCKET_FACTOR ; ++pos) {
+		odb_index_t index = data->hash_base[pos];
+		while (index) {
+			if (index >= data->descr->current_size) {
+				nr_node_out_of_bound++;
+				break;
+			}
+			++nr_node;
+
+			if (data->node_base[index].key > max)
+				max = data->node_base[index].key;
+
+			index = data->node_base[index].next;
+		}
+	}
+
+	if (nr_node != data->descr->current_size - 1) {
+		printf("hash table walk found %d node expect %d node\n",
+		       nr_node, data->descr->current_size - 1);
+		ret = 1;
+	}
+
+	if (nr_node_out_of_bound) {
+		printf("out of bound node index: %d\n", nr_node_out_of_bound);
+		ret = 1;
+	}
+
+	if (ret == 0)
+		ret = check_circular_list(data);
+
+	if (ret == 0)
+		ret = check_redundant_key(data, max);
+
+	return ret;
+}