Extracted components from OProfile 0.9.4 to be run on the phone.
diff --git a/config.h b/config.h
index c220da5..2b3b8a6 100644
--- a/config.h
+++ b/config.h
@@ -65,7 +65,7 @@
 #define OP_BINDIR "/usr/local/bin/"
 
 /* package data directory */
-#define OP_DATADIR "/usr/local/share/oprofile/"
+#define OP_DATADIR "/data/oprofile/"
 
 /* Name of package */
 #define PACKAGE "oprofile"
@@ -95,7 +95,7 @@
 /* #undef TRUE_FALSE_ALREADY_DEFINED */
 
 /* Version number of package */
-#define VERSION "0.9.1"
+#define VERSION "0.9.4"
 
 /* Define to 1 if the X Window System is missing or not being used. */
 /* #undef X_DISPLAY_MISSING */
diff --git a/daemon/Android.mk b/daemon/Android.mk
index ce7acae..abee74c 100644
--- a/daemon/Android.mk
+++ b/daemon/Android.mk
@@ -9,20 +9,22 @@
 	opd_kernel.c \
 	opd_mangling.c \
 	opd_perfmon.c \
+	opd_pipe.c \
 	opd_sfile.c \
+	opd_spu.c \
 	opd_stats.c \
 	opd_trans.c \
 	oprofiled.c
 
 LOCAL_STATIC_LIBRARIES := \
-	libpopt libutil libdb libabic libop
+	libpopt libutil libdb libabi libop
 
 LOCAL_C_INCLUDES := \
 	$(LOCAL_PATH)/.. \
 	$(LOCAL_PATH)/../libdb \
 	$(LOCAL_PATH)/../libutil \
 	$(LOCAL_PATH)/../libop \
-	$(LOCAL_PATH)/../libabic
+	$(LOCAL_PATH)/../libabi
 
 LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
 LOCAL_MODULE_TAGS := debug
diff --git a/daemon/init.c b/daemon/init.c
index 162861b..be0b9da 100644
--- a/daemon/init.c
+++ b/daemon/init.c
@@ -7,6 +7,10 @@
  *
  * @author John Levon
  * @author Philippe Elie
+ * @Modifications Daniel Hansel
+ * Modified by Aravind Menon for Xen
+ * These modifications are:
+ * Copyright (C) 2005 Hewlett-Packard Co.
  */
 
 #include "config.h"
@@ -14,6 +18,7 @@
 #include "oprofiled.h"
 #include "opd_stats.h"
 #include "opd_sfile.h"
+#include "opd_pipe.h"
 #include "opd_kernel.h"
 #include "opd_trans.h"
 #include "opd_anon.h"
@@ -30,17 +35,30 @@
 #include <fcntl.h>
 #include <stdio.h>
 #include <errno.h>
+#include <limits.h>
 #include <stdlib.h>
+#include <sys/time.h>
+#if ANDROID
+#include <sys/wait.h>
+#else
+#include <wait.h>
+#endif
+#include <string.h>
 
 size_t kernel_pointer_size;
 
 static fd_t devfd;
 static char * sbuf;
 static size_t s_buf_bytesize;
+extern char * session_dir;
+static char start_time_str[32];
+static int jit_conversion_running;
 
 static void opd_sighup(void);
 static void opd_alarm(void);
 static void opd_sigterm(void);
+static void opd_sigchild(void);
+static void opd_do_jitdumps(void);
 
 /**
  * opd_open_files - open necessary files
@@ -50,7 +68,7 @@
  */
 static void opd_open_files(void)
 {
-	devfd = op_open_device(OP_DRIVER_BASE"/buffer");
+	devfd = op_open_device("/dev/oprofile/buffer");
 	if (devfd == -1) {
 		if (errno == EINVAL)
 			fprintf(stderr, "Failed to open device. Possibly you have passed incorrect\n"
@@ -61,7 +79,7 @@
 	}
 
 	/* give output before re-opening stdout as the logfile */
-	printf("Using log file " OP_LOG_FILE "\n");
+	printf("Using log file %s\n", op_log_file);
 
 	/* set up logfile */
 	close(0);
@@ -73,6 +91,7 @@
 	}
 
 	opd_open_logfile();
+	opd_create_pipe();
 
 	printf("oprofiled started %s", op_get_time());
 	printf("kernel pointer size: %lu\n",
@@ -87,12 +106,12 @@
 	FILE * status_file;
 
 retry:
-	status_file = fopen(OP_DUMP_STATUS, "w");
+	status_file = fopen(op_dump_status, "w");
 
 	if (!status_file && errno == EMFILE) {
 		if (sfile_lru_clear()) {
 			printf("LRU cleared but file open fails for %s.\n",
-			       OP_DUMP_STATUS);
+			       op_dump_status);
 			abort();
 		}
 		goto retry;
@@ -130,6 +149,48 @@
 	complete_dump();
 }
  
+static void opd_do_jitdumps(void)
+{ 
+	pid_t childpid;
+	int arg_num;
+	unsigned long long end_time = 0ULL;
+	struct timeval tv;
+	char end_time_str[32];
+	char opjitconv_path[PATH_MAX + 1];
+	char * exec_args[6];
+
+	if (jit_conversion_running)
+		return;
+	jit_conversion_running = 1;
+
+	childpid = fork();
+	switch (childpid) {
+		case -1:
+			perror("Error forking JIT dump process!");
+			break;
+		case 0:
+			gettimeofday(&tv, NULL);
+			end_time = tv.tv_sec;
+			sprintf(end_time_str, "%llu", end_time);
+			sprintf(opjitconv_path, "%s/%s", OP_BINDIR, "opjitconv");
+			arg_num = 0;
+			exec_args[arg_num++] = opjitconv_path;
+			if (vmisc)
+				exec_args[arg_num++] = "-d";
+			exec_args[arg_num++] = session_dir;
+			exec_args[arg_num++] = start_time_str;
+			exec_args[arg_num++] = end_time_str;
+			exec_args[arg_num] = (char *) NULL;
+			execvp("opjitconv", exec_args);
+			fprintf(stderr, "Failed to exec %s: %s\n",
+			        exec_args[0], strerror(errno));
+			/* We don't want any cleanup in the child */
+			_exit(EXIT_FAILURE);
+		default:
+			break;
+	} 
+
+} 
 
 /**
  * opd_do_read - enter processing loop
@@ -141,6 +202,8 @@
  */
 static void opd_do_read(char * buf, size_t size)
 {
+	opd_open_pipe();
+
 	while (1) {
 		ssize_t count = -1;
 
@@ -164,6 +227,9 @@
 			if (signal_term)
 				opd_sigterm();
 
+			if (signal_child)
+				opd_sigchild();
+
 			if (signal_usr1) {
 				signal_usr1 = 0;
 				perfmon_start();
@@ -173,10 +239,17 @@
 				signal_usr2 = 0;
 				perfmon_stop();
 			}
+
+			if (is_jitconv_requested()) {
+				verbprintf(vmisc, "Start opjitconv was triggered\n");
+				opd_do_jitdumps();
+			}
 		}
 
 		opd_do_samples(buf, count);
 	}
+	
+	opd_close_pipe();
 }
 
 
@@ -204,27 +277,45 @@
 static void clean_exit(void)
 {
 	perfmon_exit();
-	unlink(OP_LOCK_FILE);
+	unlink(op_lock_file);
 }
 
 
 static void opd_sigterm(void)
 {
+	opd_do_jitdumps();
 	opd_print_stats();
 	printf("oprofiled stopped %s", op_get_time());
 	exit(EXIT_FAILURE);
 }
- 
 
+/* SIGCHLD received from JIT dump child process. */
+static void opd_sigchild(void)
+{
+	int child_status;
+	wait(&child_status);
+	jit_conversion_running = 0;
+	if (WIFEXITED(child_status) && (!WEXITSTATUS(child_status))) {
+		verbprintf(vmisc, "JIT dump processing complete.\n");
+	} else {
+		printf("JIT dump processing exited abnormally: %d\n",
+		       WEXITSTATUS(child_status));
+	}
+
+}
+ 
 static void opd_26_init(void)
 {
 	size_t i;
 	size_t opd_buf_size;
+	unsigned long long start_time = 0ULL;
+	struct timeval tv;
 
 	opd_create_vmlinux(vmlinux, kernel_range);
+	opd_create_xen(xenimage, xen_range);
 
-	opd_buf_size = opd_read_fs_int(OP_DRIVER_BASE"/", "buffer_size", 1);
-	kernel_pointer_size = opd_read_fs_int(OP_DRIVER_BASE"/", "pointer_size", 1);
+	opd_buf_size = opd_read_fs_int("/dev/oprofile/", "buffer_size", 1);
+	kernel_pointer_size = opd_read_fs_int("/dev/oprofile/", "pointer_size", 1);
 
 	s_buf_bytesize = opd_buf_size * kernel_pointer_size;
 
@@ -247,13 +338,19 @@
 		perror("oprofiled: couldn't set exit cleanup: ");
 		exit(EXIT_FAILURE);
 	}
+
+	/* trigger kernel module setup before returning control to opcontrol */
+	opd_open_files();
+	gettimeofday(&tv, NULL);
+	start_time = 0ULL;
+	start_time = tv.tv_sec;
+	sprintf(start_time_str, "%llu", start_time);
+		  
 }
 
 
 static void opd_26_start(void)
 {
-	opd_open_files();
-
 	/* simple sleep-then-process loop */
 	opd_do_read(sbuf, s_buf_bytesize);
 }
diff --git a/daemon/opd_anon.c b/daemon/opd_anon.c
index b5e42d8..9caea3d 100644
--- a/daemon/opd_anon.c
+++ b/daemon/opd_anon.c
@@ -14,6 +14,7 @@
  * @remark Read the file COPYING
  *
  * @author John Levon
+ * @Modifications Gisle Dankel
  */
 
 #include "opd_anon.h"
@@ -25,21 +26,24 @@
 #include <limits.h>
 #include <stdlib.h>
 #include <stdio.h>
+#include <string.h>
 
 #define HASH_SIZE 1024
 #define HASH_BITS (HASH_SIZE - 1)
 
-#define LRU_SIZE 1000
-#define LRU_AMOUNT (LRU_SIZE/5)
+/*
+ * Note that this value is tempered by the fact that when we miss in the
+ * anon cache, we'll tear down all the mappings for that tgid. Thus, LRU
+ * of a mapping can potentially clear out a much larger number of
+ * mappings.
+ */
+#define LRU_SIZE 8192
+#define LRU_AMOUNT (LRU_SIZE/8)
 
 static struct list_head hashes[HASH_SIZE];
 static struct list_head lru;
 static size_t nr_lru;
 
-/* never called in buffer-processing context, so we don't need
- * to update struct transient. Note the 'U' of LRU is based on
- * parsing time, not actual use.
- */
 static void do_lru(struct transient * trans)
 {
 	size_t nr_to_kill = LRU_AMOUNT;
@@ -53,6 +57,7 @@
 			clear_trans_current(trans);
 		if (trans->last_anon == entry)
 			clear_trans_last(trans);
+		sfile_clear_anon(entry);
 		list_del(&entry->list);
 		list_del(&entry->lru_list);
 		--nr_lru;
@@ -60,8 +65,6 @@
 		if (nr_to_kill-- == 0)
 			break;
 	}
-
-	sfile_clear_anon();
 }
 
 
@@ -87,6 +90,7 @@
 		if (entry->tgid == tgid && entry->app_cookie == app) {
 			if (trans->last_anon == entry)
 				clear_trans_last(trans);
+			sfile_clear_anon(entry);
 			list_del(&entry->list);
 			list_del(&entry->lru_list);
 			--nr_lru;
@@ -94,7 +98,6 @@
 		}
 	}
 
-	sfile_clear_anon();
 	if (vmisc) {
 		char const * name = verbose_cookie(app);
 		printf("Cleared anon maps for tgid %u (%s).\n", tgid, name);
@@ -103,7 +106,7 @@
 
 
 static void
-add_anon_mapping(struct transient * trans, vma_t start, vma_t end)
+add_anon_mapping(struct transient * trans, vma_t start, vma_t end, char * name)
 {
 	unsigned long hash = hash_anon(trans->tgid, trans->app_cookie);
 	struct anon_mapping * m = xmalloc(sizeof(struct anon_mapping));
@@ -111,6 +114,7 @@
 	m->app_cookie = trans->app_cookie;
 	m->start = start;
 	m->end = end;
+	strncpy(m->name, name, MAX_IMAGE_NAME_SIZE + 1);
 	list_add_tail(&m->list, &hashes[hash]);
 	list_add_tail(&m->lru_list, &lru);
 	if (++nr_lru == LRU_SIZE)
@@ -128,8 +132,7 @@
 {
 	FILE * fp = NULL;
 	char buf[PATH_MAX];
-	unsigned long start;
-	unsigned long end;
+	vma_t start, end;
 	int ret;
 
 	snprintf(buf, PATH_MAX, "/proc/%d/maps", trans->tgid);
@@ -138,16 +141,20 @@
 		return;
 
 	while (fgets(buf, PATH_MAX, fp) != NULL) {
-		char tmp[20];
-		/* Note that this actually includes all mappings,
-		 * since we want stuff like [heap]
+		char tmp[MAX_IMAGE_NAME_SIZE + 1];
+		char name[MAX_IMAGE_NAME_SIZE + 1];
+		/* Some anon maps have labels like
+		 * [heap], [stack], [vdso], [vsyscall] ...
+		 * Keep track of these labels. If a map has no name, call it "anon".
+		 * Ignore all mappings starting with "/" (file or shared memory object)
 		 */
-		ret = sscanf(buf, "%lx-%lx %19s %19s %19s %19s %19s",
-		             &start, &end, tmp, tmp, tmp, tmp, tmp);
-		if (ret < 6)
+		strcpy(name, "anon");
+		ret = sscanf(buf, "%llx-%llx %20s %20s %20s %20s %20s",
+		             &start, &end, tmp, tmp, tmp, tmp, name);
+		if (ret < 6 || name[0] == '/')
 			continue;
 
-		add_anon_mapping(trans, start, end);
+		add_anon_mapping(trans, start, end, name);
 	}
 
 	fclose(fp);
diff --git a/daemon/opd_anon.h b/daemon/opd_anon.h
index 63a7723..3f66b55 100644
--- a/daemon/opd_anon.h
+++ b/daemon/opd_anon.h
@@ -25,6 +25,9 @@
  */
 #define VMA_SHIFT 13 
 
+/* Maximum size of the image name considered */
+#define MAX_IMAGE_NAME_SIZE 20
+
 struct anon_mapping {
 	/** start of the mapping */
 	vma_t start;
@@ -38,6 +41,7 @@
 	struct list_head list;
 	/** lru list */
 	struct list_head lru_list;
+	char name[MAX_IMAGE_NAME_SIZE+1];
 };
 
 /**
diff --git a/daemon/opd_cookie.c b/daemon/opd_cookie.c
index 48e1e80..3578e48 100644
--- a/daemon/opd_cookie.c
+++ b/daemon/opd_cookie.c
@@ -60,12 +60,24 @@
 #endif /* __NR_lookup_dcookie */
 
 #if (defined(__powerpc__) && !defined(__powerpc64__)) || defined(__hppa__)\
-	|| (defined(__s390__) && !defined(__s390x__))
+	|| (defined(__s390__) && !defined(__s390x__)) \
+	|| (defined(__mips__) && (_MIPS_SIM == _MIPS_SIM_ABI32) \
+	    && defined(__MIPSEB__)) \
+        || (defined(__arm__) && defined(__ARM_EABI__) \
+            && defined(__ARMEB__))
 static inline int lookup_dcookie(cookie_t cookie, char * buf, size_t size)
 {
 	return syscall(__NR_lookup_dcookie, (unsigned long)(cookie >> 32),
 		       (unsigned long)(cookie & 0xffffffff), buf, size);
 }
+#elif (defined(__mips__) && (_MIPS_SIM == _MIPS_SIM_ABI32)) \
+	|| (defined(__arm__) && defined(__ARM_EABI__))
+static inline int lookup_dcookie(cookie_t cookie, char * buf, size_t size)
+{
+	return syscall(__NR_lookup_dcookie,
+		       (unsigned long)(cookie & 0xffffffff),
+		       (unsigned long)(cookie >> 32), buf, size);
+}
 #else
 static inline int lookup_dcookie(cookie_t cookie, char * buf, size_t size)
 {
diff --git a/daemon/opd_events.c b/daemon/opd_events.c
index f9346df..81a87d2 100644
--- a/daemon/opd_events.c
+++ b/daemon/opd_events.c
@@ -142,7 +142,8 @@
 
 void fill_header(struct opd_header * header, unsigned long counter,
                  vma_t anon_start, vma_t cg_to_anon_start,
-                 int is_kernel, int cg_to_is_kernel, time_t mtime)
+                 int is_kernel, int cg_to_is_kernel,
+                 int spu_samples, uint64_t embed_offset, time_t mtime)
 {
 	struct opd_event * event = find_counter_event(counter);
 
@@ -158,5 +159,7 @@
 	header->cpu_speed = cpu_speed;
 	header->mtime = mtime;
 	header->anon_start = anon_start;
+	header->spu_profile = spu_samples;
+	header->embedded_offset = embed_offset;
 	header->cg_to_anon_start = cg_to_anon_start;
 }
diff --git a/daemon/opd_events.h b/daemon/opd_events.h
index 5b86836..3bd0106 100644
--- a/daemon/opd_events.h
+++ b/daemon/opd_events.h
@@ -13,6 +13,7 @@
 
 #include "op_types.h"
 
+#include <stdint.h>
 #include <time.h>
 
 /** event description for setup (perfmon) and mangling */
@@ -40,6 +41,7 @@
 /** fill the sample file header with event info etc. */
 void fill_header(struct opd_header * header, unsigned long counter,
                  vma_t anon_start, vma_t anon_end,
-                 int is_kernel, int cg_to_is_kernel, time_t mtime);
+                 int is_kernel, int cg_to_is_kernel,
+                 int spu_samples, uint64_t embed_offset, time_t mtime);
 
 #endif /* OPD_EVENTS_H */
diff --git a/daemon/opd_interface.h b/daemon/opd_interface.h
index 8abb2c4..c876830 100644
--- a/daemon/opd_interface.h
+++ b/daemon/opd_interface.h
@@ -8,6 +8,9 @@
  *
  * @author John Levon
  * @author Philippe Elie
+ * Modified by Aravind Menon for Xen
+ * These modifications are:
+ * Copyright (C) 2005 Hewlett-Packard Co.
  */
 
 #ifndef OPD_INTERFACE_H
@@ -17,10 +20,26 @@
 #define CPU_SWITCH_CODE			2
 #define COOKIE_SWITCH_CODE		3
 #define KERNEL_ENTER_SWITCH_CODE	4
-#define KERNEL_EXIT_SWITCH_CODE		5
-#define MODULE_LOADED_CODE              6
+#define USER_ENTER_SWITCH_CODE		5
+#define MODULE_LOADED_CODE		6
 #define CTX_TGID_CODE			7
 #define TRACE_BEGIN_CODE		8
-#define LAST_CODE			9
+/* Code 9 used to be TRACE_END_CODE which is not used anymore  */
+/* Code 9 is now considered an unknown escape code             */
+#define XEN_ENTER_SWITCH_CODE		10
+/*
+ * Ugly work-around for the unfortunate collision between Xenoprof's
+ * DOMAIN_SWITCH_CODE (in use on x86) and Cell's SPU_PROFILING_CODE
+ * (in use with Power):
+ */
+#if defined(__powerpc__)
+#define SPU_PROFILING_CODE		11
+#define SPU_CTX_SWITCH_CODE		12
+#define DOMAIN_SWITCH_CODE		13
+#define LAST_CODE			14
+#else
+#define DOMAIN_SWITCH_CODE		11
+#define LAST_CODE			12
+#endif
  
 #endif /* OPD_INTERFACE_H */
diff --git a/daemon/opd_kernel.c b/daemon/opd_kernel.c
index d314bc9..5ebc210 100644
--- a/daemon/opd_kernel.c
+++ b/daemon/opd_kernel.c
@@ -7,6 +7,9 @@
  *
  * @author John Levon
  * @author Philippe Elie
+ * Modified by Aravind Menon for Xen
+ * These modifications are:
+ * Copyright (C) 2005 Hewlett-Packard Co.
  */
 
 #include "opd_kernel.h"
@@ -29,6 +32,8 @@
 
 static struct kernel_image vmlinux_image;
 
+static struct kernel_image xen_image;
+
 void opd_create_vmlinux(char const * name, char const * arg)
 {
 	/* vmlinux is *not* on the list of modules */
@@ -54,6 +59,31 @@
 	}
 }
 
+void opd_create_xen(char const * name, char const * arg)
+{
+	/* xen is *not* on the list of modules */
+	list_init(&xen_image.list);
+
+	/* for no xen */
+	if (no_xen) {
+		xen_image.name = "no-xen";
+		return;
+	}
+
+	xen_image.name = xstrdup(name);
+
+	sscanf(arg, "%llx,%llx", &xen_image.start, &xen_image.end);
+
+	verbprintf(vmisc, "xen_start = %llx, xen_end = %llx\n",
+	           xen_image.start, xen_image.end);
+
+	if (!xen_image.start && !xen_image.end) {
+		fprintf(stderr, "error: mis-parsed xen range: %llx-%llx\n",
+		        xen_image.start, xen_image.end);
+		exit(EXIT_FAILURE);
+	}
+}
+
 
 /**
  * Allocate and initialise a kernel image description
@@ -112,11 +142,11 @@
 	char * line;
 	struct kernel_image * image;
 	int module_size;
-	char ref_count[32];
+	char ref_count[32+1];
 	int ret;
 	char module_name[256+1];
-	char live_info[32];
-	char dependencies[4096];
+	char live_info[32+1];
+	char dependencies[4096+1];
 	unsigned long long start_address;
 
 	if (no_vmlinux)
@@ -145,7 +175,7 @@
 			continue;
 		}
 
-		ret = sscanf(line, "%256s %u %31s %4095s %31s %llx",
+		ret = sscanf(line, "%256s %u %32s %4096s %32s %llx",
 			     module_name, &module_size, ref_count,
 			     dependencies, live_info, &start_address);
 		if (ret != 6) {
@@ -192,5 +222,8 @@
 			return image;
 	}
 
+	if (xen_image.start <= trans->pc && xen_image.end > trans->pc)
+		return &xen_image;
+
 	return NULL;
 }
diff --git a/daemon/opd_kernel.h b/daemon/opd_kernel.h
index 7c035ee..cb71a30 100644
--- a/daemon/opd_kernel.h
+++ b/daemon/opd_kernel.h
@@ -7,6 +7,9 @@
  *
  * @author John Levon
  * @author Philippe Elie
+ * Modified by Aravind Menon for Xen
+ * These modifications are:
+ * Copyright (C) 2005 Hewlett-Packard Co.
  */
 
 #ifndef OPD_KERNEL_H
@@ -20,6 +23,8 @@
 /** create the kernel image */
 void opd_create_vmlinux(char const * name, char const * arg);
 
+void opd_create_xen(char const * name, char const * arg);
+
 /** opd_reread_module_info - parse /proc/modules for kernel modules */
 void opd_reread_module_info(void);
 
diff --git a/daemon/opd_mangling.c b/daemon/opd_mangling.c
index a22f98c..08a6079 100644
--- a/daemon/opd_mangling.c
+++ b/daemon/opd_mangling.c
@@ -57,8 +57,10 @@
 static char * mangle_anon(struct anon_mapping const * anon)
 {
 	char * name = xmalloc(PATH_MAX);
+
 	snprintf(name, 1024, "%u.0x%llx.0x%llx", (unsigned int)anon->tgid,
-	         anon->start, anon->end);
+	       anon->start, anon->end);
+
 	return name;
 }
 
@@ -78,6 +80,7 @@
 	} else if (sf->anon) {
 		values.flags |= MANGLE_ANON;
 		values.image_name = mangle_anon(sf->anon);
+		values.anon_name = sf->anon->name;
 	} else {
 		values.image_name = find_cookie(sf->cookie);
 	}
@@ -108,6 +111,7 @@
 		} else if (last->anon) {
 			values.flags |= MANGLE_CG_ANON;
 			values.cg_image_name = mangle_anon(last->anon);
+			values.anon_name = last->anon->name;
 		} else {
 			values.cg_image_name = find_cookie(last->cookie);
 		}
@@ -139,6 +143,7 @@
 {
 	char * mangled;
 	char const * binary;
+	int spu_profile = 0;
 	vma_t last_start = 0;
 	int err;
 
@@ -182,10 +187,14 @@
 	if (last && last->anon)
 		last_start = last->anon->start;
 
+	if (sf->embedded_offset != UNUSED_EMBEDDED_OFFSET)
+		spu_profile = 1;
+
 	fill_header(odb_get_data(file), counter,
 		    sf->anon ? sf->anon->start : 0, last_start,
 		    !!sf->kernel, last ? !!last->kernel : 0,
-	            binary ? op_get_mtime(binary) : 0);
+		    spu_profile, sf->embedded_offset,
+		    binary ? op_get_mtime(binary) : 0);
 
 out:
 	sfile_put(sf);
diff --git a/daemon/opd_perfmon.c b/daemon/opd_perfmon.c
index d95030d..a1b158a 100644
--- a/daemon/opd_perfmon.c
+++ b/daemon/opd_perfmon.c
@@ -380,6 +380,7 @@
 	close(child->up_pipe[1]);
 }
 
+static struct child* xen_ctx;
 
 void perfmon_init(void)
 {
@@ -389,6 +390,24 @@
 	if (cpu_type == CPU_TIMER_INT)
 		return;
 
+	if (!no_xen) {
+		xen_ctx = xmalloc(sizeof(struct child));
+		xen_ctx->pid = getpid();
+		xen_ctx->up_pipe[0] = -1;
+		xen_ctx->up_pipe[1] = -1;
+		xen_ctx->sigusr1 = 0;
+		xen_ctx->sigusr2 = 0;
+		xen_ctx->sigterm = 0;
+
+		create_context(xen_ctx);
+
+		write_pmu(xen_ctx);
+		
+		load_context(xen_ctx);
+		return;
+	}
+	
+
 	nr = sysconf(_SC_NPROCESSORS_ONLN);
 	if (nr == -1) {
 		fprintf(stderr, "Couldn't determine number of CPUs.\n");
@@ -431,6 +450,9 @@
 	if (cpu_type == CPU_TIMER_INT)
 		return;
 
+	if (!no_xen)
+		return;
+
 	for (i = 0; i < nr_cpus; ++i) {
 		kill(children[i].pid, SIGKILL);
 		waitpid(children[i].pid, NULL, 0);
@@ -445,6 +467,11 @@
 	if (cpu_type == CPU_TIMER_INT)
 		return;
 
+	if (!no_xen) {
+		perfmon_start_child(xen_ctx->ctx_fd);
+		return;
+	}
+
 	for (i = 0; i < nr_cpus; ++i)
 		kill(children[i].pid, SIGUSR1);
 }
@@ -457,6 +484,11 @@
 	if (cpu_type == CPU_TIMER_INT)
 		return;
 
+	if (!no_xen) {
+		perfmon_stop_child(xen_ctx->ctx_fd);
+		return;
+	}
+	
 	for (i = 0; i < nr_cpus; ++i)
 		kill(children[i].pid, SIGUSR2);
 }
diff --git a/daemon/opd_pipe.c b/daemon/opd_pipe.c
new file mode 100644
index 0000000..a5c334a
--- /dev/null
+++ b/daemon/opd_pipe.c
@@ -0,0 +1,96 @@
+/**
+ * @file daemon/opd_pipe.c
+ * Functions handling the $SESSIONDIR/opd_pipe FIFO special file.
+ * NOTE: This code is dealing with potentially insecure input.
+ *
+ * @remark Copyright 2008 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author Daniel Hansel
+ */
+
+#include "opd_pipe.h"
+#include "opd_printf.h"
+#include "op_config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+static int fifo;
+
+void opd_create_pipe(void)
+{
+	mode_t orig_umask = umask(0111);
+	if (mkfifo(op_pipe_file, 0666) == -1) {
+		if (errno != EEXIST) {
+			perror("oprofiled: couldn't create pipe: ");
+			exit(EXIT_FAILURE);
+		}
+	}
+	umask(orig_umask);
+}
+
+
+void opd_open_pipe(void)
+{
+	fifo = open(op_pipe_file, O_RDONLY | O_NONBLOCK);
+	if (fifo == -1) {
+		perror("oprofiled: couldn't open pipe: ");
+		exit(EXIT_FAILURE);
+	}
+}
+
+
+void opd_close_pipe(void)
+{
+	close(fifo);
+}
+
+
+int is_jitconv_requested(void)
+{
+	/* number of dropped (unknown) requests */
+	static long nr_drops = 0;
+	/* modulus to output only a few warnings to avoid flooding oprofiled.log */
+	static int mod_cnt_drops = 1;
+	FILE * fd;
+	char line[256];
+	int i, ret = 0;
+
+	/* get a file descriptor to the pipe */
+	fd = fdopen(fifo, "r");
+
+	if (fd == NULL) {
+		perror("oprofiled: couldn't create file descriptor: ");
+		exit(EXIT_FAILURE);
+	}
+
+	/* read up to 99 lines to check for 'do_jitconv' */
+	for (i = 0; i < 99; i++) {
+		/* just break if no new line is found */
+		if (fgets(line, 256, fd) == NULL)
+			break;
+		line[strlen(line) - 1] = '\0';
+
+		if (strstr(line, "do_jitconv") != NULL) {
+			ret = 1;
+		} else {
+			nr_drops++;
+
+			if (nr_drops % mod_cnt_drops == 0) {
+				printf(
+				       "Warning: invalid pipe request received (dropped request(s): %ld)\n",
+				       nr_drops);
+				/* increase modulus to avoid flooding log file */
+				mod_cnt_drops *= 5;
+			}
+		}
+	}
+
+	return ret;
+}
diff --git a/daemon/opd_pipe.h b/daemon/opd_pipe.h
new file mode 100644
index 0000000..7f96b07
--- /dev/null
+++ b/daemon/opd_pipe.h
@@ -0,0 +1,45 @@
+/**
+ * @file daemon/opd_pipe.h
+ * Functions handling the $SESSIONDIR/opd_pipe FIFO special file.
+ * NOTE: This code is dealing with potencially insecure input.
+ *
+ * @remark Copyright 2008 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author Daniel Hansel
+ */
+
+#ifndef OPD_PIPE_H_
+#define OPD_PIPE_H_
+ 
+/**
+ * opd_create_pipe - creates the oprofiled fifo file
+ *
+ * Creates the Oprofile daemon fifo pipe to enable communication between
+ * the daemon and the 'opcontrol --dump' command. Failure to create the pipe
+ * is a fatal error.
+ */
+void opd_create_pipe(void);
+
+/**
+ * opd_open_pipe - opens the oprofiled fifo file
+ */
+void opd_open_pipe(void);
+
+/**
+ * opd_close_pipe - closes the oprofiled fifo file
+ *
+ * Closes the Oprofile daemon fifo pipe.
+ */
+void opd_close_pipe(void);
+
+/**
+ * is_jitconv_requested - check for request to jit conversion
+ *
+ * Checks the Oprofile daemon fifo pipe for do_jitconv request.
+ * If jit conversion is requested ('do_jitconv' is sent) the check returns 1.
+ * Otherwise it returns 0.
+ */
+int is_jitconv_requested(void);
+
+#endif /*OPD_PIPE_H_*/
diff --git a/daemon/opd_sfile.c b/daemon/opd_sfile.c
index 58fdccd..03ebf55 100644
--- a/daemon/opd_sfile.c
+++ b/daemon/opd_sfile.c
@@ -199,6 +199,14 @@
 
 	sf->ignored = is_sf_ignored(sf);
 
+	sf->embedded_offset = trans->embedded_offset;
+
+	/* If embedded_offset is a valid value, it means we're
+	 * processing a Cell BE SPU profile; in which case, we
+	 * want sf->app_cookie to hold trans->app_cookie.
+	 */
+	if (trans->embedded_offset != UNUSED_EMBEDDED_OFFSET)
+		sf->app_cookie = trans->app_cookie;
 	return sf;
 }
 
@@ -399,7 +407,7 @@
 	key = to & (0xffffffff);
 	key |= ((uint64_t)from) << 32;
 
-	err = odb_insert(file, key, 1);
+	err = odb_update_node(file, key);
 	if (err) {
 		fprintf(stderr, "%s: %s\n", __FUNCTION__, strerror(err));
 		abort();
@@ -438,7 +446,7 @@
 		return;
 	}
 
-	err = odb_insert(file, (uint64_t)pc, 1);
+	err = odb_update_node(file, (uint64_t)pc);
 	if (err) {
 		fprintf(stderr, "%s: %s\n", __FUNCTION__, strerror(err));
 		abort();
@@ -446,7 +454,7 @@
 }
 
 
-static int close_sfile(struct sfile * sf)
+static int close_sfile(struct sfile * sf, void * data __attribute__((unused)))
 {
 	size_t i;
 
@@ -460,13 +468,13 @@
 
 static void kill_sfile(struct sfile * sf)
 {
-	close_sfile(sf);
+	close_sfile(sf, NULL);
 	list_del(&sf->hash);
 	list_del(&sf->lru);
 }
 
 
-static int sync_sfile(struct sfile * sf)
+static int sync_sfile(struct sfile * sf, void * data __attribute__((unused)))
 {
 	size_t i;
 
@@ -477,22 +485,25 @@
 }
 
 
-static int is_sfile_kernel(struct sfile * sf)
+static int is_sfile_kernel(struct sfile * sf, void * data __attribute__((unused)))
 {
 	return !!sf->kernel;
 }
 
 
-static int is_sfile_anon(struct sfile * sf)
+static int is_sfile_anon(struct sfile * sf, void * data)
 {
-	return !!sf->anon;
+	return sf->anon == data;
 }
 
 
-static void for_one_sfile(struct sfile * sf, int (*func)(struct sfile *))
+typedef int (*sfile_func)(struct sfile *, void *);
+
+static void
+for_one_sfile(struct sfile * sf, sfile_func func, void * data)
 {
 	size_t i;
-	int free_sf = func(sf);
+	int free_sf = func(sf, data);
 
 	for (i = 0; i < CG_HASH_SIZE; ++i) {
 		struct list_head * pos;
@@ -500,7 +511,7 @@
 		list_for_each_safe(pos, pos2, &sf->cg_hash[i]) {
 			struct cg_entry * cg =
 				list_entry(pos, struct cg_entry, hash);
-			if (free_sf || func(&cg->to)) {
+			if (free_sf || func(&cg->to, data)) {
 				kill_sfile(&cg->to);
 				list_del(&cg->hash);
 				free(cg);
@@ -515,39 +526,39 @@
 }
 
 
-static void for_each_sfile(int (*func)(struct sfile *))
+static void for_each_sfile(sfile_func func, void * data)
 {
 	struct list_head * pos;
 	struct list_head * pos2;
 
 	list_for_each_safe(pos, pos2, &lru_list) {
 		struct sfile * sf = list_entry(pos, struct sfile, lru);
-		for_one_sfile(sf, func);
+		for_one_sfile(sf, func, data);
 	}
 }
 
 
 void sfile_clear_kernel(void)
 {
-	for_each_sfile(is_sfile_kernel);
+	for_each_sfile(is_sfile_kernel, NULL);
 }
 
 
-void sfile_clear_anon(void)
+void sfile_clear_anon(struct anon_mapping * anon)
 {
-	for_each_sfile(is_sfile_anon);
+	for_each_sfile(is_sfile_anon, anon);
 }
 
 
 void sfile_sync_files(void)
 {
-	for_each_sfile(sync_sfile);
+	for_each_sfile(sync_sfile, NULL);
 }
 
 
 void sfile_close_files(void)
 {
-	for_each_sfile(close_sfile);
+	for_each_sfile(close_sfile, NULL);
 }
 
 
@@ -578,7 +589,7 @@
 		if (!--amount)
 			break;
 		sf = list_entry(pos, struct sfile, lru);
-		for_one_sfile(sf, (int (*)(struct sfile *))always_true);
+		for_one_sfile(sf, (sfile_func)always_true, NULL);
 	}
 
 	return 0;
diff --git a/daemon/opd_sfile.h b/daemon/opd_sfile.h
index 56ed25b..86d5025 100644
--- a/daemon/opd_sfile.h
+++ b/daemon/opd_sfile.h
@@ -25,6 +25,7 @@
 struct transient;
 
 #define CG_HASH_SIZE 16
+#define UNUSED_EMBEDDED_OFFSET ~0LLU
 
 /**
  * Each set of sample files (where a set is over the physical counter
@@ -50,6 +51,8 @@
 	struct kernel_image * kernel;
 	/** anonymous mapping */
 	struct anon_mapping * anon;
+	/** embedded offset for Cell BE SPU */
+	uint64_t embedded_offset;
 
 	/** hash table link */
 	struct list_head hash;
@@ -74,8 +77,10 @@
 /** clear any sfiles that are for the kernel */
 void sfile_clear_kernel(void);
 
-/** clear any sfiles that are for anon mappings */
-void sfile_clear_anon(void);
+struct anon_mapping;
+
+/** clear any sfiles for the given anon mapping */
+void sfile_clear_anon(struct anon_mapping *);
 
 /** sync sample files */
 void sfile_sync_files(void);
diff --git a/daemon/opd_spu.c b/daemon/opd_spu.c
new file mode 100644
index 0000000..62a2c2b
--- /dev/null
+++ b/daemon/opd_spu.c
@@ -0,0 +1,176 @@
+/**
+ * @file daemon/opd_spu.c
+ * Processing the sample buffer for Cell BE SPU profile
+ *
+ * @remark Copyright 2007 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author Maynard Johnson
+ * (C) Copyright IBM Corporation 2007
+ */
+
+#include "opd_interface.h"
+#include "opd_printf.h"
+#include "opd_sfile.h"
+#include "opd_stats.h"
+#include "opd_trans.h"
+#include "op_libiberty.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+
+struct spu_context_info {
+	pid_t tid;
+	pid_t tgid;
+	cookie_t app_cookie;
+	uint64_t embedded_offset;
+	cookie_t spu_cookie;
+};
+
+static struct spu_context_info * spu_context_cache;
+
+/* Forward declaration */
+static void process_spu_samples(struct transient * trans);
+
+void (*special_processor)(struct transient *);
+
+/*
+ * This function is called when the first value found in the
+ * buffer (after the beginning ESCAPE_CODE) is SPU_PROFILING_CODE.
+ * Once we get here, the rest of the processing of the buffer is
+ * Cell-SPU-specific, so we do not need to return until the
+ * trans.buffer is empty.
+ */
+void code_spu_profiling(struct transient * trans)
+{
+	/* Next value in buffer is the number of SPUs. */
+	unsigned long long num_spus = pop_buffer_value(trans);
+	/* Free the cache from previous run */
+	free(spu_context_cache);
+	spu_context_cache = xmalloc(sizeof(struct spu_context_info) * num_spus);
+	special_processor = process_spu_samples;
+	process_spu_samples(trans);
+}
+
+void code_spu_ctx_switch(struct transient * trans)
+{
+	clear_trans_current(trans);
+
+	if (!enough_remaining(trans, 6)) {
+		trans->remaining = 0;
+		return;
+	}
+
+	/* First value in the buffer for an SPU context switch is
+	 * the SPU number.  For SPU profiling, 'cpu' = 'spu'.
+	 */
+	trans->cpu = pop_buffer_value(trans);
+	trans->tid = pop_buffer_value(trans);
+	trans->tgid = pop_buffer_value(trans);
+	trans->app_cookie = pop_buffer_value(trans);
+
+	if (vmisc) {
+		char const * app = find_cookie(trans->app_cookie);
+		printf("SPU_CTX_SWITCH to tid %lu, tgid %lu, cookie %llx(%s)\n",
+		       (unsigned long)trans->tid, (unsigned long)trans->tgid,
+		       trans->app_cookie, app ? app : "none");
+	}
+
+	/* The trans->cookie will point to the binary file where the SPU ELF
+	 * can be found.  If the SPU ELF is embedded, it may be embedded in
+	 * either the executable application binary or a shared lib.  If shared
+	 * library, then trans->cookie will differ from the previously obtained
+	 * trans->app_cookie.  For the non-embedded case, trans->cookie always
+	 * points to a separate binary file.
+	 */
+	trans->cookie = pop_buffer_value(trans);
+	trans->embedded_offset = pop_buffer_value(trans);
+}
+
+
+static void cache_spu_context_info(struct transient * trans)
+{
+	int i = trans->cpu;
+	spu_context_cache[i].tid = trans->tid;
+	spu_context_cache[i].tgid = trans->tgid;
+	spu_context_cache[i].app_cookie = trans->app_cookie;
+	spu_context_cache[i].embedded_offset = trans->embedded_offset;
+	spu_context_cache[i].spu_cookie = trans->cookie;
+}
+
+static void update_trans_for_spu(struct transient * trans)
+{
+	int i = trans->cpu;
+	trans->tid = spu_context_cache[i].tid;
+	trans->tgid = spu_context_cache[i].tgid;
+	trans->app_cookie = spu_context_cache[i].app_cookie;
+	trans->embedded_offset = spu_context_cache[i].embedded_offset;
+	trans->cookie = spu_context_cache[i].spu_cookie;
+}
+#define SPU_NUM_MASK 0xFFFFFFFF00000000ULL
+#define SPU_CYCLES_COUNTER 0
+
+static void opd_put_spu_sample
+(struct transient * trans, unsigned long long pc)
+{
+	unsigned long spu_number = (pc & SPU_NUM_MASK) >> 32;
+	if (trans->cpu != spu_number) {
+		trans->cpu = spu_number;
+	        clear_trans_current(trans);
+		update_trans_for_spu(trans);
+	}
+	/* get the current sfile if needed */
+	if (!trans->current)
+		trans->current = sfile_find(trans);
+
+	if (trans->tracing != TRACING_ON)
+		trans->event = SPU_CYCLES_COUNTER;
+
+	trans->pc = (pc & ~SPU_NUM_MASK);
+	/* log the sample or arc */
+	sfile_log_sample(trans);
+
+	/* switch to trace mode */
+	if (trans->tracing == TRACING_START)
+		trans->tracing = TRACING_ON;
+
+	update_trans_last(trans);
+}
+
+/*
+ * This function processes SPU context switches and
+ * SPU program counter samples.  After processing a
+ * context switch (via handlers[code)), we cache the
+ * SPU context information that has been temporarily
+ * stored in trans.
+ */
+static void process_spu_samples(struct transient * trans)
+{
+	unsigned long long code;
+	trans->in_kernel = 0;
+	while (trans->remaining) {
+		code = pop_buffer_value(trans);
+
+		if (!is_escape_code(code)) {
+			opd_put_spu_sample(trans, code);
+			continue;
+		}
+
+		if (!trans->remaining) {
+			verbprintf(vmisc, "Dangling ESCAPE_CODE.\n");
+			opd_stats[OPD_DANGLING_CODE]++;
+			break;
+		}
+
+		/* started with ESCAPE_CODE, next is type */
+		code = pop_buffer_value(trans);
+
+		if (code >= LAST_CODE) {
+			fprintf(stderr, "Unknown code %llu\n", code);
+			abort();
+		}
+
+		handlers[code](trans);
+		cache_spu_context_info(trans);
+	}
+}
diff --git a/daemon/opd_stats.c b/daemon/opd_stats.c
index 1a7f0f7..ddb1940 100644
--- a/daemon/opd_stats.c
+++ b/daemon/opd_stats.c
@@ -9,12 +9,10 @@
  * @author Philippe Elie
  */
 
-#include "config.h"
 #include "opd_stats.h"
 #include "oprofiled.h"
 
 #include "op_get_time.h"
-#include "op_config.h"
 
 #include <dirent.h>
 #include <stdlib.h>
@@ -53,22 +51,22 @@
 	printf("Nr. samples lost due to no permanent mapping: %lu\n",
 		opd_stats[OPD_LOST_NO_MAPPING]);
 	print_if("Nr. event lost due to buffer overflow: %u\n",
-	       OP_DRIVER_BASE"/stats", "event_lost_overflow", 1);
+	       "/dev/oprofile/stats", "event_lost_overflow", 1);
 	print_if("Nr. samples lost due to no mapping: %u\n",
-	       OP_DRIVER_BASE"/stats", "sample_lost_no_mapping", 1);
+	       "/dev/oprofile/stats", "sample_lost_no_mapping", 1);
 	print_if("Nr. backtraces skipped due to no file mapping: %u\n",
-	       OP_DRIVER_BASE"/stats", "bt_lost_no_mapping", 0);
+	       "/dev/oprofile/stats", "bt_lost_no_mapping", 0);
 	print_if("Nr. samples lost due to no mm: %u\n",
-	       OP_DRIVER_BASE"/stats", "sample_lost_no_mm", 1);
+	       "/dev/oprofile/stats", "sample_lost_no_mm", 1);
 
-	if (!(dir = opendir(OP_DRIVER_BASE"/stats/")))
+	if (!(dir = opendir("/dev/oprofile/stats/")))
 		goto out;
 	while ((dirent = readdir(dir))) {
 		int cpu_nr;
 		char path[256];
 		if (sscanf(dirent->d_name, "cpu%d", &cpu_nr) != 1)
 			continue;
-		snprintf(path, 256, OP_DRIVER_BASE"/stats/%s", dirent->d_name);
+		snprintf(path, 256, "/dev/oprofile/stats/%s", dirent->d_name);
 
 		print_if("Nr. samples lost cpu buffer overflow: %u\n",
 		     path, "sample_lost_overflow", 1);
@@ -78,6 +76,8 @@
 		     path, "sample_received", 1);
 		print_if("Nr. backtrace aborted: %u\n", 
 		     path, "backtrace_aborted", 0);
+		print_if("Nr. samples lost invalid pc: %u\n", 
+		     path, "sample_invalid_eip", 0);
 	}
 	closedir(dir);
 out:
diff --git a/daemon/opd_trans.c b/daemon/opd_trans.c
index eb22e5f..871e6e6 100644
--- a/daemon/opd_trans.c
+++ b/daemon/opd_trans.c
@@ -7,6 +7,13 @@
  *
  * @author John Levon
  * @author Philippe Elie
+ * Modified by Aravind Menon for Xen
+ * These modifications are:
+ * Copyright (C) 2005 Hewlett-Packard Co.
+ *
+ * Modified by Maynard Johnson <maynardj@us.ibm.com>
+ * These modifications are:
+ * (C) Copyright IBM Corporation 2007
  */
 
 #include "opd_trans.h"
@@ -41,21 +48,7 @@
 }
 
 
-void update_trans_last(struct transient * trans)
-{
-	trans->last = trans->current;
-	trans->last_anon = trans->anon;
-	trans->last_pc = trans->pc;
-}
-
-
-static inline int is_escape_code(uint64_t code)
-{
-	return kernel_pointer_size == 4 ? code == ~0LU : code == ~0LLU;
-}
-
-
-static uint64_t pop_buffer_value(struct transient * trans)
+uint64_t pop_buffer_value(struct transient * trans)
 {
 	uint64_t val;
 
@@ -78,7 +71,7 @@
 }
 
 
-static int enough_remaining(struct transient * trans, size_t size)
+int enough_remaining(struct transient * trans, size_t size)
 {
 	if (trans->remaining >= size)
 		return 1;
@@ -219,9 +212,9 @@
 }
 
 
-static void code_kernel_exit(struct transient * trans)
+static void code_user_enter(struct transient * trans)
 {
-	verbprintf(vmisc, "KERNEL_EXIT_SWITCH to user-space\n");
+	verbprintf(vmisc, "USER_ENTER_SWITCH to user-space\n");
 	trans->in_kernel = 0;
 	clear_trans_current(trans);
 	clear_trans_last(trans);
@@ -248,22 +241,44 @@
 	trans->tracing = TRACING_START;
 }
 
+static void code_xen_enter(struct transient * trans)
+{
+	verbprintf(vmisc, "XEN_ENTER_SWITCH to xen\n");
+	trans->in_kernel = 1;
+	trans->current = NULL;
+	/* subtlety: we must keep trans->cookie cached, even though it's 
+	 * meaningless for Xen - we won't necessarily get a cookie switch 
+	 * on Xen exit. See comments in opd_sfile.c. It seems that we can 
+	 * get away with in_kernel = 1 as long as we supply the correct 
+	 * Xen image, and its address range in startup find_kernel_image 
+	 * is modified to look in the Xen image also
+	 */
+}
 
-typedef void (*handler_t)(struct transient *);
+extern void code_spu_profiling(struct transient * trans);
+extern void code_spu_ctx_switch(struct transient * trans);
 
-static handler_t handlers[LAST_CODE + 1] = {
+handler_t handlers[LAST_CODE + 1] = {
 	&code_unknown,
 	&code_ctx_switch,
 	&code_cpu_switch,
 	&code_cookie_switch,
 	&code_kernel_enter,
-	&code_kernel_exit,
+ 	&code_user_enter,
 	&code_module_loaded,
 	/* tgid handled differently */
 	&code_unknown,
 	&code_trace_begin,
+	&code_unknown,
+ 	&code_xen_enter,
+#if defined(__powerpc__)
+	&code_spu_profiling,
+	&code_spu_ctx_switch,
+#endif
+	&code_unknown,
 };
 
+extern void (*special_processor)(struct transient *);
 
 void opd_process_samples(char const * buffer, size_t count)
 {
@@ -283,6 +298,7 @@
 		.in_kernel = -1,
 		.cpu = -1,
 		.tid = -1,
+		.embedded_offset = UNUSED_EMBEDDED_OFFSET,
 		.tgid = -1
 	};
 
@@ -292,9 +308,22 @@
 	 */
 	unsigned long long code;
 
+	if (special_processor) {
+		special_processor(&trans);
+		return;
+	}
+
+    int i;
+
+    for (i = 0; i < count && i < 200; i++) {
+        verbprintf(vmisc, "buffer[%d] is %x\n", i, buffer[i]);
+    }
+
 	while (trans.remaining) {
 		code = pop_buffer_value(&trans);
 
+        verbprintf(vmisc, "In opd_process_samples (code is %lld)\n", code);
+
 		if (!is_escape_code(code)) {
 			opd_put_sample(&trans, code);
 			continue;
@@ -309,6 +338,7 @@
 		// started with ESCAPE_CODE, next is type
 		code = pop_buffer_value(&trans);
 	
+        verbprintf(vmisc, "next code is %lld\n", code);
 		if (code >= LAST_CODE) {
 			fprintf(stderr, "Unknown code %llu\n", code);
 			abort();
diff --git a/daemon/opd_trans.h b/daemon/opd_trans.h
index d5d601b..ab4e816 100644
--- a/daemon/opd_trans.h
+++ b/daemon/opd_trans.h
@@ -7,6 +7,10 @@
  *
  * @author John Levon
  * @author Philippe Elie
+ *
+ * Modified by Maynard Johnson <maynardj@us.ibm.com>
+ * These modifications are:
+ * (C) Copyright IBM Corporation 2007
  */
 
 #ifndef OPD_TRANS_H
@@ -15,6 +19,8 @@
 #include "opd_cookie.h"
 #include "op_types.h"
 
+#include <stdint.h>
+
 struct sfile;
 struct anon_mapping;
 
@@ -47,8 +53,27 @@
 	unsigned long cpu;
 	pid_t tid;
 	pid_t tgid;
+	uint64_t embedded_offset;
 };
 
+typedef void (*handler_t)(struct transient *);
+extern handler_t handlers[];
+
+uint64_t pop_buffer_value(struct transient * trans);
+int enough_remaining(struct transient * trans, size_t size);
+static inline void update_trans_last(struct transient * trans)
+{
+	trans->last = trans->current;
+	trans->last_anon = trans->anon;
+	trans->last_pc = trans->pc;
+}
+
+extern size_t kernel_pointer_size;
+static inline int is_escape_code(uint64_t code)
+{
+	return kernel_pointer_size == 4 ? code == ~0LU : code == ~0LLU;
+}
+
 void opd_process_samples(char const * buffer, size_t count);
 
 /** used when we need to clear data that's been freed */
diff --git a/daemon/oprofiled.c b/daemon/oprofiled.c
index 281f10f..ec2ea1b 100644
--- a/daemon/oprofiled.c
+++ b/daemon/oprofiled.c
@@ -7,6 +7,9 @@
  *
  * @author John Levon
  * @author Philippe Elie
+ * Modified by Aravind Menon for Xen
+ * These modifications are:
+ * Copyright (C) 2005 Hewlett-Packard Co.
  */
 
 #include "config.h"
@@ -43,6 +46,7 @@
 sig_atomic_t signal_alarm;
 sig_atomic_t signal_hup;
 sig_atomic_t signal_term;
+sig_atomic_t signal_child;
 sig_atomic_t signal_usr1;
 sig_atomic_t signal_usr2;
 
@@ -60,6 +64,10 @@
 int no_vmlinux;
 char * vmlinux;
 char * kernel_range;
+char * session_dir;
+int no_xen;
+char * xenimage;
+char * xen_range;
 static char * verbose;
 static char * binary_name_filter;
 static char * events;
@@ -72,9 +80,12 @@
 static struct list_head images_filter[OPD_IMAGE_FILTER_HASH_SIZE];
 
 static struct poptOption options[] = {
+	{ "session-dir", 0, POPT_ARG_STRING, &session_dir, 0, "place sample database in dir instead of default location", "/var/lib/oprofile", },
 	{ "kernel-range", 'r', POPT_ARG_STRING, &kernel_range, 0, "Kernel VMA range", "start-end", },
 	{ "vmlinux", 'k', POPT_ARG_STRING, &vmlinux, 0, "vmlinux kernel image", "file", },
 	{ "no-vmlinux", 0, POPT_ARG_NONE, &no_vmlinux, 0, "vmlinux kernel image file not available", NULL, },
+	{ "xen-range", 0, POPT_ARG_STRING, &xen_range, 0, "Xen VMA range", "start-end", },
+	{ "xen-image", 0, POPT_ARG_STRING, &xenimage, 0, "Xen image", "file", },
 	{ "image", 0, POPT_ARG_STRING, &binary_name_filter, 0, "image name filter", "profile these comma separated image" },
 	{ "separate-lib", 0, POPT_ARG_INT, &separate_lib, 0, "separate library samples for each distinct application", "[0|1]", },
 	{ "separate-kernel", 0, POPT_ARG_INT, &separate_kernel, 0, "separate kernel samples for each distinct application", "[0|1]", },
@@ -90,7 +101,7 @@
 
 void opd_open_logfile(void)
 {
-	if (open(OP_LOG_FILE, O_WRONLY|O_CREAT|O_NOCTTY|O_APPEND, 0755) == -1) {
+	if (open(op_log_file, O_WRONLY|O_CREAT|O_NOCTTY|O_APPEND, 0644) == -1) {
 		perror("oprofiled: couldn't re-open stdout: ");
 		exit(EXIT_FAILURE);
 	}
@@ -129,9 +140,9 @@
 {
 	opd_fork();
 
-	if (chdir(OP_BASE_DIR)) {
-		fprintf(stderr, "oprofiled: opd_go_daemon: couldn't chdir to "
-			OP_BASE_DIR ": %s", strerror(errno));
+	if (chdir(op_session_dir)) {
+		fprintf(stderr, "oprofiled: opd_go_daemon: couldn't chdir to %s: %s",
+			op_session_dir, strerror(errno));
 		exit(EXIT_FAILURE);
 	}
 
@@ -146,15 +157,13 @@
 
 static void opd_write_abi(void)
 {
-#ifdef OPROF_ABI
 	char * cbuf;
  
-	cbuf = xmalloc(strlen(OP_BASE_DIR) + 5);
-	strcpy(cbuf, OP_BASE_DIR);
+	cbuf = xmalloc(strlen(op_session_dir) + 5);
+	strcpy(cbuf, op_session_dir);
 	strcat(cbuf, "/abi");
 	op_write_abi_to_file(cbuf);
 	free(cbuf);
-#endif
 }
 
 
@@ -178,6 +187,11 @@
 {
 	signal_term = 1;
 }
+
+static void opd_sigchild(int val __attribute__((unused)))
+{
+	signal_child = 1;
+}
  
 
 static void opd_sigusr1(int val __attribute__((unused)))
@@ -225,6 +239,16 @@
 		exit(EXIT_FAILURE);
 	}
 
+	act.sa_handler = opd_sigchild;
+	act.sa_flags = 0;
+	sigemptyset(&act.sa_mask);
+	sigaddset(&act.sa_mask, SIGCHLD);
+
+	if (sigaction(SIGCHLD, &act, NULL)) {
+		perror("oprofiled: install of SIGCHLD handler failed: ");
+		exit(EXIT_FAILURE);
+	}
+
 	act.sa_handler = opd_sigusr1;
 	act.sa_flags = 0;
 	sigemptyset(&act.sa_mask);
@@ -241,7 +265,7 @@
 	sigaddset(&act.sa_mask, SIGTERM);
 
 	if (sigaction(SIGUSR2, &act, NULL)) {
-		perror("oprofiled: install of SIGUSR1 handler failed: ");
+		perror("oprofiled: install of SIGUSR2 handler failed: ");
 		exit(EXIT_FAILURE);
 	}
 }
@@ -407,7 +431,26 @@
 		poptPrintHelp(optcon, stderr, 0);
 		exit(EXIT_FAILURE);
 	}
-	
+
+	if (!xenimage || !strcmp("", xenimage)) {
+		no_xen = 1;
+	} else {
+		no_xen = 0;
+
+		/* canonicalise xen image filename. */
+		tmp = xmalloc(PATH_MAX);
+		if (realpath(xenimage, tmp))
+			xenimage = tmp;
+		else
+			free(tmp);
+
+		if (!xen_range || !strcmp("", xen_range)) {
+			fprintf(stderr, "oprofiled: no Xen VMA range specified.\n");
+			poptPrintHelp(optcon, stderr, 0);
+			exit(EXIT_FAILURE);
+		}
+	}
+
 	opd_parse_events(events);
 
 	opd_parse_image_filter();
@@ -422,10 +465,11 @@
 static struct oprofiled_ops * get_ops(void)
 {
 	switch (op_get_interface()) {
+#ifndef ANDROID
 		case OP_INTERFACE_24:
 			printf("Using 2.4 OProfile kernel interface.\n");
-			//return &opd_24_ops;
-            return 0; // android. we should never need that.
+			return &opd_24_ops;
+#endif
 		case OP_INTERFACE_26:
 			printf("Using 2.6+ OProfile kernel interface.\n");
 			return &opd_26_ops;
@@ -445,13 +489,13 @@
 	struct rlimit rlim = { 2048, 2048 };
 
 	opd_options(argc, argv);
+	init_op_config_dirs(session_dir);
 
 	opd_setup_signals();
 
 	err = setrlimit(RLIMIT_NOFILE, &rlim);
-	if (err) {
+	if (err)
 		perror("warning: could not set RLIMIT_NOFILE to 2048: ");
-	}
 
 	opd_write_abi();
 
@@ -464,9 +508,9 @@
 	/* clean up every 10 minutes */
 	alarm(60 * 10);
 
-	if (op_write_lock_file(OP_LOCK_FILE)) {
-		fprintf(stderr, "oprofiled: could not create lock file "
-			OP_LOCK_FILE "\n");
+	if (op_write_lock_file(op_lock_file)) {
+		fprintf(stderr, "oprofiled: could not create lock file %s\n",
+			op_lock_file);
 		exit(EXIT_FAILURE);
 	}
 
diff --git a/daemon/oprofiled.h b/daemon/oprofiled.h
index 23f40d2..b319df1 100644
--- a/daemon/oprofiled.h
+++ b/daemon/oprofiled.h
@@ -7,6 +7,9 @@
  *
  * @author John Levon
  * @author Philippe Elie
+ * Modified by Aravind Menon for Xen
+ * These modifications are:
+ * Copyright (C) 2005 Hewlett-Packard Co.
  */
 
 #ifndef OPROFILED_H
@@ -47,6 +50,7 @@
 extern sig_atomic_t signal_alarm;
 extern sig_atomic_t signal_hup;
 extern sig_atomic_t signal_term;
+extern sig_atomic_t signal_child;
 extern sig_atomic_t signal_usr1;
 extern sig_atomic_t signal_usr2;
 
@@ -58,5 +62,8 @@
 extern int no_vmlinux;
 extern char * vmlinux;
 extern char * kernel_range;
+extern int no_xen;
+extern char * xenimage;
+extern char * xen_range;
 
 #endif /* OPROFILED_H */
diff --git a/libabi/Android.mk b/libabi/Android.mk
new file mode 100644
index 0000000..3213c1e
--- /dev/null
+++ b/libabi/Android.mk
@@ -0,0 +1,14 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= op_abi.c
+
+LOCAL_MODULE := libabi
+
+LOCAL_C_INCLUDES := \
+	$(LOCAL_PATH)/.. \
+	$(LOCAL_PATH)/../libdb \
+	$(LOCAL_PATH)/../libutil \
+	$(LOCAL_PATH)/../libop
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/libabi/abi.cpp b/libabi/abi.cpp
new file mode 100644
index 0000000..04a6b2d
--- /dev/null
+++ b/libabi/abi.cpp
@@ -0,0 +1,75 @@
+/**
+ * @file abi.cpp
+ *
+ * @remark Copyright 2002 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author Graydon Hoare
+ * @author John Levon
+ * @author Philippe Elie
+ */
+
+#include "abi.h"
+#include "op_abi.h"
+#include "odb.h"
+#include "op_sample_file.h"
+
+#include <iostream>
+#include <cassert>
+
+using namespace std;
+
+typedef map<string, int> abi_map;
+typedef abi_map::const_iterator abi_iter;
+
+abi_exception::abi_exception(string const d) : desc(d) {}
+
+
+abi::abi()
+{
+	op_abi_entry const * entry = get_abi();
+	for ( ; entry->name != 0; ++entry)
+		slots[entry->name] = entry->offset;
+
+	slots["little_endian"] = op_little_endian();
+}
+
+
+int abi::need(string const key) const throw (abi_exception)
+{
+	if (slots.find(key) != slots.end())
+		return slots.find(key)->second;
+	else
+		throw abi_exception(string("missing ABI key: ") + key);
+}
+
+
+bool abi::operator==(abi const & other) const
+{
+	return slots == other.slots;
+}
+
+
+ostream & operator<<(ostream & o, abi const & abi)
+{
+	abi_iter i = abi.slots.begin();
+	abi_iter e = abi.slots.end();
+
+	for (; i != e; ++i)
+		o << i->first << " " << i->second << endl;
+
+	return o;
+}
+
+
+istream & operator>>(istream & i, abi & abi)
+{
+	string key;
+	int val;
+	abi.slots.clear();
+
+	while(i >> key >> val)
+		abi.slots[key] = val;
+
+	return i;
+}
diff --git a/libabi/abi.h b/libabi/abi.h
new file mode 100644
index 0000000..8b63e7f
--- /dev/null
+++ b/libabi/abi.h
@@ -0,0 +1,42 @@
+/**
+ * @file abi.h
+ *
+ * Contains internal ABI management class
+ *
+ * @remark Copyright 2002 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author Graydon Hoare
+ */
+
+#ifndef OPROF_ABI_H
+#define OPROF_ABI_H
+ 
+#include <string>
+#include <map>
+#include <iosfwd>
+
+struct abi_exception : std::exception {
+	std::string const desc;
+ 
+	explicit abi_exception(std::string const d);
+ 
+	~abi_exception() throw() {}
+};
+
+
+class abi {
+public:
+	abi();
+
+	int need(std::string const key) const throw (abi_exception);
+
+	bool operator==(abi const & other) const;
+	friend std::ostream & operator<<(std::ostream & o, abi const & abi);
+	friend std::istream & operator>>(std::istream & i, abi & abi);
+
+private:
+	std::map<std::string, int> slots;
+};
+
+#endif // OPROF_ABI_H
diff --git a/libabi/op_abi.c b/libabi/op_abi.c
new file mode 100644
index 0000000..283e3ff
--- /dev/null
+++ b/libabi/op_abi.c
@@ -0,0 +1,94 @@
+/**
+ * @file op_abi.c
+ * This file contains a simple C interface to the ABI-describing functionality,
+ * the majority of which is implemented in C++. This is the file which is 
+ * intended for use in files outside the /libabi directory.
+ *
+ * @remark Copyright 2002, 2005 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author Graydon Hoare
+ * @author Philippe Elie
+ */
+
+#include "op_abi.h"
+#include "odb.h"
+#include "op_sample_file.h"
+
+#include <stdio.h>
+#include <stddef.h>
+#include <assert.h>
+
+static struct op_abi_entry const abi_entries[] = {
+	{ "sizeof_double", sizeof(double) },
+	{ "sizeof_time_t", sizeof(time_t) },
+	{ "sizeof_u8", sizeof(u8) },
+	{ "sizeof_u32", sizeof(u32) },
+	{ "sizeof_int", sizeof(int) },
+	{ "sizeof_unsigned_int", sizeof(unsigned int) },
+	{ "sizeof_odb_key_t", sizeof(odb_key_t) },
+	{ "sizeof_odb_index_t", sizeof(odb_index_t) },
+	{ "sizeof_odb_value_t", sizeof(odb_value_t) },
+	{ "sizeof_odb_node_nr_t", sizeof(odb_node_nr_t) },
+	{ "sizeof_odb_descr_t", sizeof(odb_descr_t) },
+	{ "sizeof_odb_node_t", sizeof(odb_node_t) },
+	{ "sizeof_struct_opd_header", sizeof(struct opd_header) },
+	
+	{ "offsetof_node_key", offsetof(odb_node_t, key) },
+	{ "offsetof_node_value", offsetof(odb_node_t, value) },
+	{ "offsetof_node_next", offsetof(odb_node_t, next) },
+	
+	{ "offsetof_descr_size", offsetof(odb_descr_t, size) },
+	{ "offsetof_descr_current_size", offsetof(odb_descr_t, current_size) },
+	
+	{ "offsetof_header_magic", offsetof(struct opd_header, magic) },
+	{ "offsetof_header_version", offsetof(struct opd_header, version) },
+	{ "offsetof_header_cpu_type", offsetof(struct opd_header, cpu_type) },
+	{ "offsetof_header_ctr_event", offsetof(struct opd_header, ctr_event) },
+	{ "offsetof_header_ctr_um", offsetof(struct opd_header, ctr_um) },
+	{ "offsetof_header_ctr_count", offsetof(struct opd_header, ctr_count) },
+	{ "offsetof_header_is_kernel", offsetof(struct opd_header, is_kernel) },
+	{ "offsetof_header_cpu_speed", offsetof(struct opd_header, cpu_speed) },
+	{ "offsetof_header_mtime", offsetof(struct opd_header, mtime) },
+	{ "offsetof_header_cg_to_is_kernel", offsetof(struct opd_header, cg_to_is_kernel), },
+	{ "offsetof_header_anon_start", offsetof(struct opd_header, anon_start) },
+	{ "offsetof_header_cg_to_anon_start", offsetof(struct opd_header, cg_to_anon_start) },
+	
+	{ NULL, 0 },
+};
+
+
+struct op_abi_entry const * get_abi(void)
+{
+	return abi_entries;
+}
+
+
+int op_little_endian(void)
+{
+	unsigned int probe = 0xff;
+	size_t sz = sizeof(unsigned int);
+	unsigned char * probe_byte = (unsigned char *)&probe;
+
+	assert(probe_byte[0] == 0xff || probe_byte[sz - 1] == 0xff);
+
+	return probe_byte[0] == 0xff;
+}
+
+
+int op_write_abi_to_file(char const * abi_file)
+{
+	FILE * fp;
+	struct op_abi_entry const * abi_entry;
+
+	if ((fp = fopen(abi_file, "w")) == NULL)
+		return 0;
+
+	for (abi_entry = get_abi() ; abi_entry->name != NULL; ++abi_entry)
+		fprintf(fp, "%s %u\n", abi_entry->name, abi_entry->offset);
+	fprintf(fp, "little_endian %d\n", op_little_endian());
+
+	fclose(fp);
+
+	return 1;
+}
diff --git a/libabi/op_abi.h b/libabi/op_abi.h
new file mode 100644
index 0000000..fbd337b
--- /dev/null
+++ b/libabi/op_abi.h
@@ -0,0 +1,43 @@
+/**
+ * @file op_abi.h
+ * This file contains a simple C interface to the ABI-describing functionality,
+ * the majority of which is implemented in C++. this is the file which is 
+ * intended for use in files outside the /libabi directory.
+ *
+ * @remark Copyright 2002 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author Graydon Hoare
+ * @author Philippe Elie
+ */
+
+#ifndef OP_ABI_H
+#define OP_ABI_H
+
+struct op_abi_entry {
+	char const * name;
+	/// offset or size of the named entry
+	int offset;
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/// return array is terminated by a NULL entry in name field
+struct op_abi_entry const * get_abi(void);
+
+/// return non zero if the abi is little endian
+int op_little_endian(void);
+
+/**
+ * Write current abi to file.
+ * return 1 on success, 0 on failure
+ */
+int op_write_abi_to_file(char const * abi_file);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // OP_ABI_H
diff --git a/libabi/opimport.cpp b/libabi/opimport.cpp
new file mode 100644
index 0000000..57f74a7
--- /dev/null
+++ b/libabi/opimport.cpp
@@ -0,0 +1,225 @@
+/**
+ * @file opimport.cpp
+ * Import sample files from other ABI
+ *
+ * @remark Copyright 2002 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author Graydon Hoare
+ */
+
+#include "abi.h"
+#include "odb.h"
+#include "popt_options.h"
+#include "op_sample_file.h"
+
+#include <fstream>
+#include <iostream>
+#include <vector>
+#include <cassert>
+#include <cstring>
+#include <cstdlib>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <cstdlib>
+#include <cstring>
+
+using namespace std;
+
+namespace {
+	string output_filename;
+	string abi_filename;
+	bool verbose;
+	bool force;
+};
+
+
+popt::option options_array[] = {
+	popt::option(verbose, "verbose", 'V', "verbose output"),
+	popt::option(output_filename, "output", 'o', "output to file", "filename"),
+	popt::option(abi_filename, "abi", 'a', "abi description", "filename"),
+	popt::option(force, "force", 'f', "force conversion, even if identical")
+};
+
+
+struct extractor {
+
+	abi const & theabi;
+
+	unsigned char const * begin;
+	unsigned char const * end;
+	bool little_endian;
+
+	explicit
+	extractor(abi const & a, unsigned char const * src, size_t len)
+		: theabi(a), begin(src), end(src + len) {
+		little_endian = theabi.need(string("little_endian")) == 1;
+		if (verbose) {
+			cerr << "source byte order is: "
+			     << string(little_endian ? "little" : "big")
+			     << " endian" << endl;
+		}
+	}
+
+	template <typename T>
+	void extract(T & targ, void const * src_,
+	             char const * sz, char const * off);
+};
+
+
+template <typename T>
+void extractor::extract(T & targ, void const * src_,
+                        char const * sz, char const * off)
+{
+	unsigned char const * src = static_cast<unsigned char const *>(src_)
+		+ theabi.need(off);
+	size_t nbytes = theabi.need(sz);
+	
+	if (nbytes == 0)
+		return;
+	
+	assert(nbytes <= sizeof(T));
+	assert(src >= begin);
+	assert(src + nbytes <= end);
+	
+	if (verbose)
+		cerr << hex << "get " << sz << " = " << nbytes
+		     << " bytes @ " << off << " = " << (src - begin)
+		     << " : ";
+
+	targ = 0;
+	if (little_endian)
+		while(nbytes--)
+			targ = (targ << 8) | src[nbytes];
+	else
+		for(size_t i = 0; i < nbytes; ++i)
+			targ = (targ << 8) | src[i];
+	
+	if (verbose)
+		cerr << " = " << targ << endl;
+}
+
+
+void import_from_abi(abi const & abi, void const * srcv,
+                     size_t len, odb_t * dest) throw (abi_exception)
+{
+	struct opd_header * head =
+		static_cast<opd_header *>(odb_get_data(dest));
+	unsigned char const * src = static_cast<unsigned char const *>(srcv);
+	unsigned char const * const begin = src;
+	extractor ext(abi, src, len);	
+
+	memcpy(head->magic, src + abi.need("offsetof_header_magic"), 4);
+
+	// begin extracting opd header
+	ext.extract(head->version, src, "sizeof_u32", "offsetof_header_version");
+	ext.extract(head->cpu_type, src, "sizeof_u32", "offsetof_header_cpu_type");
+	ext.extract(head->ctr_event, src, "sizeof_u32", "offsetof_header_ctr_event");
+	ext.extract(head->ctr_um, src, "sizeof_u32", "offsetof_header_ctr_um");
+	ext.extract(head->ctr_count, src, "sizeof_u32", "offsetof_header_ctr_count");
+	ext.extract(head->is_kernel, src, "sizeof_u32", "offsetof_header_is_kernel");
+	// "double" extraction is unlikely to work
+	head->cpu_speed = 0.0;
+	ext.extract(head->mtime, src, "sizeof_time_t", "offsetof_header_mtime");
+	ext.extract(head->cg_to_is_kernel, src, "sizeof_u32",
+		"offsetof_header_cg_to_is_kernel");
+	ext.extract(head->anon_start, src, "sizeof_u32",
+		"offsetof_header_anon_start");
+	ext.extract(head->cg_to_anon_start, src, "sizeof_u32",
+		"offsetof_header_cg_to_anon_start");
+	src += abi.need("sizeof_struct_opd_header");
+	// done extracting opd header
+
+	// begin extracting necessary parts of descr
+	odb_node_nr_t node_nr;
+	ext.extract(node_nr, src, "sizeof_odb_node_nr_t", "offsetof_descr_current_size");
+	src += abi.need("sizeof_odb_descr_t");
+	// done extracting descr
+
+	// skip node zero, it is reserved and contains nothing usefull
+	src += abi.need("sizeof_odb_node_t");
+
+	// begin extracting nodes
+	unsigned int step = abi.need("sizeof_odb_node_t");
+	if (verbose)
+		cerr << "extracting " << node_nr << " nodes of " << step << " bytes each " << endl;
+
+	assert(src + (node_nr * step) <= begin + len);
+
+	for (odb_node_nr_t i = 1 ; i < node_nr ; ++i, src += step) {
+		odb_key_t key;
+		odb_value_t val;
+		ext.extract(key, src, "sizeof_odb_key_t", "offsetof_node_key");
+		ext.extract(val, src, "sizeof_odb_value_t", "offsetof_node_value");
+		int rc = odb_add_node(dest, key, val);
+		if (rc != EXIT_SUCCESS) {
+			cerr << strerror(rc) << endl;
+			exit(EXIT_FAILURE);
+		}
+	}
+	// done extracting nodes
+}
+
+
+int main(int argc, char const ** argv)
+{
+
+	vector<string> inputs;
+	popt::parse_options(argc, argv, inputs);
+
+	if (inputs.size() != 1) {
+		cerr << "error: must specify exactly 1 input file" << endl;
+		exit(1);
+	}
+
+	abi current_abi, input_abi;
+
+	{
+		ifstream abi_file(abi_filename.c_str());
+		if (!abi_file) {
+			cerr << "error: cannot open abi file "
+			     << abi_filename << endl;
+			exit(1);
+		}
+		abi_file >> input_abi;
+	}
+
+	if (!force && current_abi == input_abi) {
+		cerr << "input abi is identical to native. "
+		     << "no conversion necessary." << endl;
+		exit(1);
+	}
+
+	int in_fd;
+	struct stat statb;
+	void * in;
+	odb_t dest;
+	int rc;
+
+	assert((in_fd = open(inputs[0].c_str(), O_RDONLY)) > 0);		
+	assert(fstat(in_fd, &statb) == 0);
+	assert((in = mmap(0, statb.st_size, PROT_READ,
+			  MAP_PRIVATE, in_fd, 0)) != (void *)-1);
+
+	rc = odb_open(&dest, output_filename.c_str(), ODB_RDWR,
+		      sizeof(struct opd_header));
+	if (rc) {
+		cerr << "odb_open() fail:\n"
+		     << strerror(rc) << endl;
+		exit(EXIT_FAILURE);
+	}
+
+	try {
+		import_from_abi(input_abi, in, statb.st_size, &dest);
+	} catch (abi_exception & e) {
+		cerr << "caught abi exception: " << e.desc << endl;
+	}
+
+	odb_close(&dest);
+
+	assert(munmap(in, statb.st_size) == 0);
+}
diff --git a/libdb/db_debug.c b/libdb/db_debug.c
index 8e88dcc..0575570 100644
--- a/libdb/db_debug.c
+++ b/libdb/db_debug.c
@@ -26,9 +26,9 @@
 		odb_index_t index = data->hash_base[pos];
 		if (index && !do_abort) {
 			while (index) {
-				if (bitmap[index]) {
+				if (bitmap[index])
 					do_abort = 1;
-				}
+
 				bitmap[index] = 1;
 				index = data->node_base[index].next;
 			}
@@ -43,9 +43,9 @@
 			index = data->hash_base[pos];
 			while (index) {
 				printf("%d ", index);
-				if (bitmap[index]) {
+				if (bitmap[index])
 					exit(1);
-				}
+
 				bitmap[index] = 1;
 				index = data->node_base[index].next;
 			}
@@ -122,13 +122,11 @@
 		ret = 1;
 	}
 
-	if (ret == 0) {
+	if (ret == 0)
 		ret = check_circular_list(data);
-	}
 
-	if (ret == 0) {
+	if (ret == 0)
 		ret = check_redundant_key(data, max);
-	}
 
 	return ret;
 }
diff --git a/libdb/db_insert.c b/libdb/db_insert.c
index 2c99640..018c294 100644
--- a/libdb/db_insert.c
+++ b/libdb/db_insert.c
@@ -17,26 +17,74 @@
 
 #include "odb.h"
 
-int odb_insert(odb_t * odb, odb_key_t key, odb_value_t value)
+
+static inline int add_node(odb_data_t * data, odb_key_t key, odb_value_t value)
+{
+	odb_index_t new_node;
+	odb_node_t * node;
+	odb_index_t index;
+
+	/* no locking is necessary: iteration interface retrieve data through
+	 * the node_base array, we doesn't increase current_size now but it's
+	 * done by odb_commit_reservation() so the new slot is visible only
+	 * after the increment
+	 */
+	if (data->descr->current_size >= data->descr->size) {
+		if (odb_grow_hashtable(data))
+			return EINVAL;
+	}
+	new_node = data->descr->current_size;
+
+	node = &data->node_base[new_node];
+	node->value = value;
+	node->key = key;
+
+	index = odb_do_hash(data, key);
+	node->next = data->hash_base[index];
+	data->hash_base[index] = new_node;
+
+	/* FIXME: we need wrmb() here */
+	odb_commit_reservation(data);
+
+	return 0;
+}
+
+int odb_update_node(odb_t * odb, odb_key_t key)
 {
 	odb_index_t index;
-	odb_index_t new_node;
 	odb_node_t * node;
 	odb_data_t * data;
 
 	data = odb->data;
 	index = data->hash_base[odb_do_hash(data, key)];
 	while (index) {
-		if (index <= 0 || index >= data->descr->current_size) {
-			return EINVAL;
-		}
 		node = &data->node_base[index];
 		if (node->key == key) {
-			if (node->value + value >= node->value) {
-				node->value += value;
+			if (node->value + 1 != 0) {
+				node->value += 1;
 			} else {
 				/* post profile tools must handle overflow */
-				node->value = ~(odb_value_t)0;
+				/* FIXME: the tricky way will be just to add
+				 * a goto to jump right before the return
+				 * add_node(), in this way we no longer can
+				 * overflow. It'll work because new node are
+				 * linked at the start of the node list for
+				 * this bucket so this loop will see first a
+				 * non overflowed node if one exist. When we
+				 * grow the hashtable the most recently
+				 * allocated node for this key will be setup
+				 * last, so again it'll be linked at start of
+				 * the list. pp tools looke like ok with this
+				 * change.
+				 *
+				 * This change doesn't involve any file format
+				 * change but perhaps it's a bit hacky to do
+				 * this w/o bumping the sample file format
+				 * version. The drawback of this is the added
+				 * node are additive not multiplicative.
+				 * (multiplicative as if we add more bits to
+				 * store a value)
+				 */
 			}
 			return 0;
 		}
@@ -44,23 +92,11 @@
 		index = node->next;
 	}
 
-	/* no locking is necessary: iteration interface retrieve data through
-	 * the node_base array, odb_hash_add_node() increase current_size but
-	 * odb_travel just ignore node with a zero key so on setting the key
-	 * atomically update the node */
-	new_node = odb_hash_add_node(odb);
-	if (new_node == ODB_NODE_NR_INVALID) {
-		return EINVAL;
-	}
+	return add_node(data, key, 1);
+}
 
-	node = &data->node_base[new_node];
-	node->value = value;
-	node->key = key;
 
-	/* we need to recalculate hash code, hash table has perhaps grown */
-	index = odb_do_hash(data, key);
-	node->next = data->hash_base[index];
-	data->hash_base[index] = new_node;
-	
-	return 0;
+int odb_add_node(odb_t * odb, odb_key_t key, odb_value_t value)
+{
+	return add_node(odb->data, key, value);
 }
diff --git a/libdb/db_manage.c b/libdb/db_manage.c
index d9cc1ce..d8a6fcb 100644
--- a/libdb/db_manage.c
+++ b/libdb/db_manage.c
@@ -11,11 +11,14 @@
 #define _GNU_SOURCE
 
 #include <stdlib.h>
+#ifndef ANDROID
+#include <sys/fcntl.h>
+#else
 #include <fcntl.h>
+#endif
 #include <sys/mman.h>
 #include <sys/types.h>
 #include <sys/stat.h>
-#include <fcntl.h>
 #include <unistd.h>
 #include <errno.h>
 #include <string.h>
@@ -61,65 +64,60 @@
 }
 
 
-odb_index_t odb_hash_add_node(odb_t * odb)
+int odb_grow_hashtable(odb_data_t * data)
 {
-	odb_data_t * data = odb->data;
+	unsigned int old_file_size;
+	unsigned int new_file_size;
+	unsigned int pos;
+	void * new_map;
 
-	if (data->descr->current_size >= data->descr->size) {
-		unsigned int old_file_size;
-		unsigned int new_file_size;
-		unsigned int pos;
-		void * new_map;
+	old_file_size = tables_size(data, data->descr->size);
+	new_file_size = tables_size(data, data->descr->size * 2);
 
-		old_file_size = tables_size(data, data->descr->size);
-		new_file_size = tables_size(data, data->descr->size * 2);
+	if (ftruncate(data->fd, new_file_size))
+		return 1;
 
-		if (ftruncate(data->fd, new_file_size))
-			return ODB_NODE_NR_INVALID;
+	new_map = mremap(data->base_memory,
+			 old_file_size, new_file_size, MREMAP_MAYMOVE);
 
-		new_map = mremap(data->base_memory,
-				old_file_size, new_file_size, MREMAP_MAYMOVE);
+	if (new_map == MAP_FAILED)
+		return 1;
 
-		if (new_map == MAP_FAILED)
-			return ODB_NODE_NR_INVALID;
+	data->base_memory = new_map;
+	data->descr = odb_to_descr(data);
+	data->descr->size *= 2;
+	data->node_base = odb_to_node_base(data);
+	data->hash_base = odb_to_hash_base(data);
+	data->hash_mask = (data->descr->size * BUCKET_FACTOR) - 1;
 
-		data->base_memory = new_map;
-		data->descr = odb_to_descr(data);
-		data->descr->size *= 2;
-		data->node_base = odb_to_node_base(data);
-		data->hash_base = odb_to_hash_base(data);
-		data->hash_mask = (data->descr->size * BUCKET_FACTOR) - 1;
-
-		/* rebuild the hash table, node zero is never used. This works
-		 * because layout of file is node table then hash table,
-		 * sizeof(node) > sizeof(bucket) and when we grow table we
-		 * double size ==> old hash table and new hash table can't
-		 * overlap so on the new hash table is entirely in the new
-		 * memory area (the grown part) and we know the new hash
-		 * hash table is zeroed. That's why we don't need to zero init
-		 * the new table */
-		/* OK: the above is not exact
-		 * if BUCKET_FACTOR < sizeof(bd_node_t) / sizeof(bd_node_nr_t)
-		 * all things are fine and we don't need to init the hash
-		 * table because in this case the new hash table is completely
-		 * inside the new growed part. Avoiding to touch this memory is
-		 * useful.
-		 */
+	/* rebuild the hash table, node zero is never used. This works
+	 * because layout of file is node table then hash table,
+	 * sizeof(node) > sizeof(bucket) and when we grow table we
+	 * double size ==> old hash table and new hash table can't
+	 * overlap so on the new hash table is entirely in the new
+	 * memory area (the grown part) and we know the new hash
+	 * hash table is zeroed. That's why we don't need to zero init
+	 * the new table */
+	/* OK: the above is not exact
+	 * if BUCKET_FACTOR < sizeof(bd_node_t) / sizeof(bd_node_nr_t)
+	 * all things are fine and we don't need to init the hash
+	 * table because in this case the new hash table is completely
+	 * inside the new growed part. Avoiding to touch this memory is
+	 * useful.
+	 */
 #if 0
-		for (pos = 0 ; pos < data->descr->size*BUCKET_FACTOR ; ++pos) {
-			data->hash_base[pos] = 0;
-		}
+	for (pos = 0 ; pos < data->descr->size*BUCKET_FACTOR ; ++pos)
+		data->hash_base[pos] = 0;
 #endif
 
-		for (pos = 1; pos < data->descr->current_size; ++pos) {
-			odb_node_t * node = &data->node_base[pos];
-			size_t index = odb_do_hash(data, node->key);
-			node->next = data->hash_base[index];
-			data->hash_base[index] = pos;
-		}
+	for (pos = 1; pos < data->descr->current_size; ++pos) {
+		odb_node_t * node = &data->node_base[pos];
+		size_t index = odb_do_hash(data, node->key);
+		node->next = data->hash_base[index];
+		data->hash_base[index] = pos;
 	}
 
-	return (odb_index_t)data->descr->current_size++;
+	return 0;
 }
 
 
diff --git a/libdb/db_stat.c b/libdb/db_stat.c
index ab3ed18..6d29e9a 100644
--- a/libdb/db_stat.c
+++ b/libdb/db_stat.c
@@ -12,12 +12,13 @@
 #include <stdio.h>
 
 #include "odb.h"
+#include "op_types.h"
 
 /// hold various statistics data for a db file
 struct odb_hash_stat_t {
 	odb_node_nr_t node_nr;			/**< allocated node number */
 	odb_node_nr_t used_node_nr;		/**< in use node number */
-	odb_value_t   total_count;		/**< cumulated samples count */
+	count_type    total_count;		/**< cumulated samples count */
 	odb_index_t   hash_table_size;		/**< hash table entry number */
 	odb_node_nr_t max_list_length;		/**< worst case   */
 	double       average_list_length;	/**< average case */
@@ -74,7 +75,7 @@
 {
 	printf("total node number:   %d\n", stat->node_nr);
 	printf("total used node:     %d\n", stat->used_node_nr);
-	printf("total count:         %d\n", stat->total_count);
+	printf("total count:         %llu\n", stat->total_count);
 	printf("hash table size:     %d\n", stat->hash_table_size);
 	printf("greater list length: %d\n", stat->max_list_length);
 	printf("average non empty list length: %2.4f\n", stat->average_list_length);
diff --git a/libdb/odb.h b/libdb/odb.h
index c88baea..c190b57 100644
--- a/libdb/odb.h
+++ b/libdb/odb.h
@@ -135,14 +135,28 @@
 /** issue a msync on the used size of the mmaped file */
 void odb_sync(odb_t const * odb);
 
-/** add a page returning its index. Take care all page pointer can be
- * invalidated by this call !
- * returns the index of the created node on success or
- * ODB_NODE_NR_INVALID on failure, in this case this function do nothing
- * and errno is set by the first libc call failure allowing to retry after
- * cleanup some program resource.
+/**
+ * grow the hashtable in such way current_size is the index of the first free
+ * node. Take care all node pointer can be invalidated by this call.
+ *
+ * Node allocation is done in a two step way 1st) ensure a free node exist
+ * eventually, caller can setup it, 2nd) commit the node allocation with
+ * odb_commit_reservation().
+ * This is done in this way to ensure node setup is visible from another
+ * process like pp tools in an atomic way.
+ *
+ * returns 0 on success, non zero on failure in this case this function do
+ * nothing and errno is set by the first libc call failure allowing to retry
+ * after cleanup some program resource.
  */
-odb_node_nr_t odb_hash_add_node(odb_t * odb);
+int odb_grow_hashtable(odb_data_t * data);
+/**
+ * commit a previously successfull node reservation. This can't fail.
+ */
+static __inline void odb_commit_reservation(odb_data_t * data)
+{
+	++data->descr->current_size;
+}
 
 /** "immpossible" node number to indicate an error from odb_hash_add_node() */
 #define ODB_NODE_NR_INVALID ((odb_node_nr_t)-1)
@@ -158,11 +172,19 @@
 void odb_hash_free_stat(odb_hash_stat_t * stats);
 
 /* db_insert.c */
-/** insert info at key, if key already exist the info is added to the
- * existing samples
+/** update info at key by incrementing its associated value by one, 
+ * if the key does not exist a new node is created and the value associated
+ * is set to one.
+ *
  * returns EXIT_SUCCESS on success, EXIT_FAILURE on failure
  */
-int odb_insert(odb_t * odb, odb_key_t key, odb_value_t value);
+int odb_update_node(odb_t * odb, odb_key_t key);
+
+/** Add a new node w/o regarding if a node with the same key already exists
+ *
+ * returns EXIT_SUCCESS on success, EXIT_FAILURE on failure
+ */
+int odb_add_node(odb_t * odb, odb_key_t key, odb_value_t value);
 
 /* db_travel.c */
 /**
@@ -171,13 +193,11 @@
  *
  * odb_node_nr_t node_nr, pos;
  * odb_node_t * node = odb_get_iterator(odb, &node_nr);
- *	for ( pos = 0 ; pos < node_nr ; ++pos) {
- *		if (node[pos].key) {
- *			// do something
- *		}
- *	}
+ *	for ( pos = 0 ; pos < node_nr ; ++pos)
+ *		// do something
  *
- *  note than caller *must* filter nil key.
+ *  note than caller does not need to filter nil key as it's a valid key,
+ * The returned range is all valid (i.e. should never contain zero value).
  */
 odb_node_t * odb_get_iterator(odb_t const * odb, odb_node_nr_t * nr);
 
diff --git a/libop/Android.mk b/libop/Android.mk
index 99fd081..8fbd1e6 100644
--- a/libop/Android.mk
+++ b/libop/Android.mk
@@ -3,6 +3,7 @@
 
 LOCAL_SRC_FILES:= \
 	op_alloc_counter.c \
+	op_config.c \
 	op_cpu_type.c \
 	op_events.c \
 	op_get_interface.c \
diff --git a/libop/op_alloc_counter.c b/libop/op_alloc_counter.c
index 8d20134..353100a 100644
--- a/libop/op_alloc_counter.c
+++ b/libop/op_alloc_counter.c
@@ -12,6 +12,8 @@
  */
 
 #include <stdlib.h>
+#include <ctype.h>
+#include <dirent.h>
 
 #include "op_events.h"
 #include "op_libiberty.h"
@@ -130,7 +132,7 @@
 		counter_arc const * arc = list_entry(pos, counter_arc, next);
 
 		if (allocated_mask & (1 << arc->counter))
-			return 0;
+			continue;
 
 		counter_map[depth] = arc->counter;
 
@@ -143,6 +145,41 @@
 	return 0;
 }
 
+/* determine which directories are counter directories
+ */
+static int perfcounterdir(const struct dirent * entry)
+{
+	return (isdigit(entry->d_name[0]));
+}
+
+
+/**
+ * @param mask pointer where to place bit mask of unavailable counters
+ *
+ * return >= 0 number of counters that are available
+ *        < 0  could not determine number of counters
+ *
+ */
+static int op_get_counter_mask(u32 * mask)
+{
+	struct dirent **counterlist;
+	int count, i;
+	/* assume nothing is available */
+	u32 available=0;
+
+	count = scandir("/dev/oprofile", &counterlist, perfcounterdir, alphasort);
+	if (count < 0)
+		/* unable to determine bit mask */
+		return -1;
+	/* convert to bit map (0 where counter exists) */
+	for (i=0; i<count; ++i) {
+		available |= 1 << atoi(counterlist[i]->d_name);
+		free(counterlist[i]);
+	}
+	*mask=~available;
+	free(counterlist);
+	return count;
+}
 
 size_t * map_event_to_counter(struct op_event const * pev[], int nr_events,
                               op_cpu cpu_type)
@@ -150,8 +187,14 @@
 	counter_arc_head * ctr_arc;
 	size_t * counter_map;
 	int nr_counters;
+	u32 unavailable_counters = 0;
 
-	nr_counters = op_get_nr_counters(cpu_type);
+	nr_counters = op_get_counter_mask(&unavailable_counters);
+	/* no counters then probably perfmon managing perfmon hw */
+	if (nr_counters <= 0) {
+		nr_counters = op_get_nr_counters(cpu_type);
+		unavailable_counters = (~0) << nr_counters;
+	}
 	if (nr_counters < nr_events)
 		return 0;
 
@@ -159,7 +202,8 @@
 
 	counter_map = xmalloc(nr_counters * sizeof(size_t));
 
-	if (!allocate_counter(ctr_arc, nr_events, 0, 0, counter_map)) {
+	if (!allocate_counter(ctr_arc, nr_events, 0, unavailable_counters,
+			      counter_map)) {
 		free(counter_map);
 		counter_map = 0;
 	}
diff --git a/libop/op_config.c b/libop/op_config.c
new file mode 100644
index 0000000..837242b
--- /dev/null
+++ b/libop/op_config.c
@@ -0,0 +1,77 @@
+/**
+ * @file op_config.c
+ * Oprofile configuration parameters.
+ *
+ * @remark Copyright 2002 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author Nathan Tallent
+ * @Modifications Daniel Hansel
+ */
+
+#include "op_config.h"
+#include "op_config_24.h"
+
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+/* paths in op_config.h */
+char op_session_dir[PATH_MAX];
+char op_samples_dir[PATH_MAX];
+char op_samples_current_dir[PATH_MAX];
+char op_lock_file[PATH_MAX];
+char op_log_file[PATH_MAX];
+char op_pipe_file[PATH_MAX];
+char op_dump_status[PATH_MAX];
+
+/* paths in op_config_24.h */
+char op_device[PATH_MAX];
+char op_note_device[PATH_MAX];
+char op_hash_device[PATH_MAX];
+
+void
+init_op_config_dirs(char const * session_dir)
+{
+	int session_dir_len;
+
+	assert(session_dir);	
+	session_dir_len = strlen(session_dir);
+
+	if (session_dir_len + strlen("/samples/oprofiled.log") > PATH_MAX) {
+		fprintf(stderr, "Session_dir string \"%s\" is too large.\n", 
+			session_dir);
+		exit(EXIT_FAILURE);
+	}
+	
+	strcpy(op_session_dir, session_dir);
+	
+	strcpy(op_samples_dir, op_session_dir);
+	strcat(op_samples_dir, "/samples/");
+	
+	strcpy(op_samples_current_dir, op_samples_dir);
+	strcat(op_samples_current_dir, "/current/");
+
+	strcpy(op_lock_file, op_session_dir);
+	strcat(op_lock_file, "/lock");
+
+	strcpy(op_pipe_file, op_session_dir);
+	strcat(op_pipe_file, "/opd_pipe");
+
+	strcpy(op_log_file, op_samples_dir);
+	strcat(op_log_file, "oprofiled.log");
+
+	strcpy(op_dump_status, op_session_dir);
+	strcat(op_dump_status, "/complete_dump");
+
+	strcpy(op_device, op_session_dir);
+	strcat(op_device, "/opdev");
+
+	strcpy(op_note_device, op_session_dir);
+	strcat(op_note_device, "/opnotedev");
+
+	strcpy(op_hash_device, op_session_dir);
+	strcat(op_hash_device, "/ophashmapdev");
+}
diff --git a/libop/op_config.h b/libop/op_config.h
index 5e16ede..b384497 100644
--- a/libop/op_config.h
+++ b/libop/op_config.h
@@ -9,30 +9,50 @@
  *
  * @author John Levon
  * @author Philippe Elie
+ * @Modifications Daniel Hansel
  */
 
 #ifndef OP_CONFIG_H
 #define OP_CONFIG_H
 
-/* various paths, duplicated in opcontrol */
+#if defined(__cplusplus)
+extern "C" {
+#endif
+  
+/** 
+ * must be called to initialize the paths below.
+ * @param session_dir  the non-NULL value of the base session directory
+ */
+void init_op_config_dirs(char const * session_dir);
 
-#define OP_DRIVER_BASE "/dev.oprofile"
-#define OP_BASE_DIR "/tmp/oprofile/"
-//#define OP_BASE_DIR "/var/lib/oprofile/"
+/* 
+ * various paths, corresponding to opcontrol, that should be
+ * initialized by init_op_config_dirs() above. 
+ */
+extern char op_session_dir[];
+extern char op_samples_dir[];
+extern char op_samples_current_dir[];
+extern char op_lock_file[];
+extern char op_log_file[];
+extern char op_pipe_file[];
+extern char op_dump_status[];
 
-#define OP_SAMPLES_DIR OP_BASE_DIR "samples/"
-#define OP_SAMPLES_CURRENT_DIR OP_SAMPLES_DIR "current/"
-#define OP_LOCK_FILE OP_BASE_DIR "lock"
-#define OP_LOG_FILE OP_BASE_DIR "oprofiled.log"
-#define OP_DUMP_STATUS OP_BASE_DIR "complete_dump"
+#define OP_DRIVER_BASE  "/dev/oprofile"
+#define OP_DATA_DIR     "/data/oprofile"
 
 /* Global directory that stores debug files */
 #ifndef DEBUGDIR
-//#define DEBUGDIR "/usr/lib/debug"
-#define DEBUGDIR "/tmp/debug"
+#define DEBUGDIR "/usr/lib/debug"
 #endif
 
 #define OPD_MAGIC "DAE\n"
-#define OPD_VERSION 0x10
+#define OPD_VERSION 0x11
+
+#define OP_MIN_CPU_BUF_SIZE 2048
+#define OP_MAX_CPU_BUF_SIZE 131072
+
+#if defined(__cplusplus)
+}
+#endif
 
 #endif /* OP_CONFIG_H */
diff --git a/libop/op_config_24.h b/libop/op_config_24.h
index 8767244..1786fae 100644
--- a/libop/op_config_24.h
+++ b/libop/op_config_24.h
@@ -14,22 +14,24 @@
 #define OP_CONFIG_24_H
 
 #define OP_MOUNT "/proc/sys/dev/oprofile/"
- 
-#define OP_DEVICE OP_BASE_DIR "opdev"
-#define OP_NOTE_DEVICE OP_BASE_DIR "opnotedev"
-#define OP_HASH_DEVICE OP_BASE_DIR "ophashmapdev"
+
+extern char op_device[];
+extern char op_note_device[];
+extern char op_hash_device[];
 
 /*@{\name module default/min/max settings */
 
 /** 65536 * sizeof(op_sample) */
 #define OP_DEFAULT_BUF_SIZE 65536
-/** we don't try to wake-up daemon until it remains more than this free entry
- * in eviction buffer */
+/** 
+ * we don't try to wake-up daemon until it remains more than this free entry
+ * in eviction buffer 
+ */
 #define OP_PRE_WATERMARK(buffer_size)			\
 	(((buffer_size) / 8) < OP_MIN_PRE_WATERMARK	\
 		? OP_MIN_PRE_WATERMARK			\
 		: (buffer_size) / 8)
-/* minimal buffer water mark before we try to wakeup daemon */
+/** minimal buffer water mark before we try to wakeup daemon */
 #define OP_MIN_PRE_WATERMARK 8192
 /** maximum number of entry in samples eviction buffer */
 #define OP_MAX_BUF_SIZE	1048576
@@ -38,13 +40,15 @@
 
 /** 16384 * sizeof(op_note) = 273680 bytes default */
 #define OP_DEFAULT_NOTE_SIZE 16384
-/** we don't try to wake-up daemon until it remains more than this free entry
- * in note buffer */
+/** 
+ * we don't try to wake-up daemon until it remains more than this free entry
+ * in note buffer 
+ */
 #define OP_PRE_NOTE_WATERMARK(note_size)		\
 	(((note_size) / 32) < OP_MIN_NOTE_PRE_WATERMARK	\
 		? OP_MIN_NOTE_PRE_WATERMARK		\
 		: (note_size) / 32)
-/* minimal note buffer water mark before we try to wakeup daemon */
+/** minimal note buffer water mark before we try to wakeup daemon */
 #define OP_MIN_NOTE_PRE_WATERMARK 512
 /** maximum number of entry in note buffer */
 #define OP_MAX_NOTE_TABLE_SIZE	1048576
@@ -58,8 +62,10 @@
 
 /*@}*/
 
-/** nr entries in hash map. This is the maximum number of name components
- * allowed. Must be a prime number */
+/** 
+ * nr entries in hash map. This is the maximum number of name components
+ * allowed. Must be a prime number 
+ */
 #define OP_HASH_MAP_NR 4093
 
 /** size of string pool in bytes */
diff --git a/libop/op_cpu_type.c b/libop/op_cpu_type.c
index d7ff4a7..b9d13de 100644
--- a/libop/op_cpu_type.c
+++ b/libop/op_cpu_type.c
@@ -9,14 +9,11 @@
  * @author Philippe Elie
  */
 
-#include "config.h"
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
 #include "op_cpu_type.h"
-#include "op_config.h"
 
 struct cpu_descr {
 	char const * pretty;
@@ -48,8 +45,13 @@
 	{ "ARM/XScale PMU2", "arm/xscale2", CPU_ARM_XSCALE2, 5 },
 	{ "ppc64 POWER4", "ppc64/power4", CPU_PPC64_POWER4, 8 },
 	{ "ppc64 POWER5", "ppc64/power5", CPU_PPC64_POWER5, 6 },
+	{ "ppc64 POWER5+", "ppc64/power5+", CPU_PPC64_POWER5p, 6 },
 	{ "ppc64 970", "ppc64/970", CPU_PPC64_970, 8 },
+	{ "MIPS 20K", "mips/20K", CPU_MIPS_20K, 1},
 	{ "MIPS 24K", "mips/24K", CPU_MIPS_24K, 2},
+	{ "MIPS 25K", "mips/25K", CPU_MIPS_25K, 2},
+	{ "MIPS 34K", "mips/34K", CPU_MIPS_34K, 4},
+	{ "MIPS 5K", "mips/5K", CPU_MIPS_5K, 2},
 	{ "MIPS R10000", "mips/r10000", CPU_MIPS_R10000, 2 },
 	{ "MIPS R12000", "mips/r12000", CPU_MIPS_R12000, 4 },
 	{ "QED RM7000", "mips/rm7000", CPU_MIPS_RM7000, 1 },
@@ -58,6 +60,20 @@
 	{ "NEC VR5432", "mips/vr5432", CPU_MIPS_VR5432, 2 },
 	{ "NEC VR5500", "mips/vr5500", CPU_MIPS_VR5500, 2 },
 	{ "e500", "ppc/e500", CPU_PPC_E500, 4 },
+	{ "e500v2", "ppc/e500v2", CPU_PPC_E500_2, 4 },
+	{ "Core Solo / Duo", "i386/core", CPU_CORE, 2 },
+	{ "PowerPC G4", "ppc/7450",  CPU_PPC_7450, 6 },
+	{ "Core 2", "i386/core_2", CPU_CORE_2, 2 },
+	{ "ppc64 POWER6", "ppc64/power6", CPU_PPC64_POWER6, 4 },
+	{ "ppc64 970MP", "ppc64/970MP", CPU_PPC64_970MP, 8 },
+	{ "ppc64 Cell Broadband Engine", "ppc64/cell-be", CPU_PPC64_CELL, 8 },
+	{ "AMD64 family10", "x86-64/family10", CPU_FAMILY10, 4 },
+	{ "ppc64 PA6T", "ppc64/pa6t", CPU_PPC64_PA6T, 6 },
+	{ "ARM MPCore", "arm/mpcore", CPU_ARM_MPCORE, 2 },
+	{ "ARM V6 PMU", "arm/armv6", CPU_ARM_V6, 3 },
+	{ "ppc64 POWER5++", "ppc64/power5++", CPU_PPC64_POWER5pp, 6 },
+	{ "e300", "ppc/e300", CPU_PPC_E300, 4 },
+	{ "AVR32", "avr32", CPU_AVR32, 3 },
 };
  
 static size_t const nr_cpu_descrs = sizeof(cpu_descrs) / sizeof(struct cpu_descr);
@@ -71,7 +87,7 @@
 	fp = fopen("/proc/sys/dev/oprofile/cpu_type", "r");
 	if (!fp) {
 		/* Try 2.6's oprofilefs one instead. */
-		fp = fopen(OP_DRIVER_BASE"/cpu_type", "r");
+		fp = fopen("/dev/oprofile/cpu_type", "r");
 		if (!fp) {
 			fprintf(stderr, "Unable to open cpu_type file for reading\n");
 			fprintf(stderr, "Make sure you have done opcontrol --init\n");
diff --git a/libop/op_cpu_type.h b/libop/op_cpu_type.h
index 9def1d7..be95ae2 100644
--- a/libop/op_cpu_type.h
+++ b/libop/op_cpu_type.h
@@ -16,7 +16,9 @@
 extern "C" {
 #endif
 
-/** supported cpu type */
+/**
+ * Supported cpu type.  Always add new CPU types at the very end.
+ */
 typedef enum {
 	CPU_NO_GOOD = -1, /**< unsupported CPU type */
 	CPU_PPRO, /**< Pentium Pro */
@@ -41,8 +43,13 @@
 	CPU_ARM_XSCALE2, /**< ARM XScale 2 */
 	CPU_PPC64_POWER4, /**< ppc64 POWER4 family */
 	CPU_PPC64_POWER5, /**< ppc64 POWER5 family */
+	CPU_PPC64_POWER5p, /**< ppc64 Power5+ family */
 	CPU_PPC64_970, /**< ppc64 970 family */
+	CPU_MIPS_20K, /**< MIPS 20K */
 	CPU_MIPS_24K, /**< MIPS 24K */
+	CPU_MIPS_25K, /**< MIPS 25K */
+	CPU_MIPS_34K, /**< MIPS 34K */
+	CPU_MIPS_5K, /**< MIPS 5K */
 	CPU_MIPS_R10000, /**< MIPS R10000 */
 	CPU_MIPS_R12000, /**< MIPS R12000 */
 	CPU_MIPS_RM7000, /**< QED  RM7000 */
@@ -51,6 +58,20 @@
 	CPU_MIPS_VR5432, /**< NEC VR5432 */
 	CPU_MIPS_VR5500, /**< MIPS VR5500, VR5532 and VR7701 */
 	CPU_PPC_E500,	/**< e500 */
+	CPU_PPC_E500_2,	/**< e500v2 */
+	CPU_CORE, /**< Core Solo / Duo series */
+	CPU_PPC_7450, /**< PowerPC G4 */
+	CPU_CORE_2, /**< Intel Core 2 */
+	CPU_PPC64_POWER6, /**< ppc64 POWER6 family */
+	CPU_PPC64_970MP, /**< ppc64 970MP */
+	CPU_PPC64_CELL, /**< ppc64 Cell Broadband Engine*/
+	CPU_FAMILY10, /**< AMD family 10 */
+ 	CPU_PPC64_PA6T, /**< ppc64 PA6T */
+	CPU_ARM_MPCORE, /**< ARM MPCore */
+	CPU_ARM_V6, /**< ARM V6 */
+	CPU_PPC64_POWER5pp,  /**< ppc64 Power5++ family */
+	CPU_PPC_E300, /**< e300 */
+	CPU_AVR32, /**< AVR32 */
 	MAX_CPU_TYPE
 } op_cpu;
 
diff --git a/libop/op_events.c b/libop/op_events.c
index 47bae76..b4a10e7 100644
--- a/libop/op_events.c
+++ b/libop/op_events.c
@@ -39,9 +39,8 @@
 static int parse_int(char const * str)
 {
 	int value;
-	if (sscanf(str, "%d", &value) != 1) {
+	if (sscanf(str, "%d", &value) != 1)
 		parse_error("expected decimal value");
-	}
 
 	return value;
 }
@@ -50,9 +49,11 @@
 static int parse_hex(char const * str)
 {
 	int value;
-	if (sscanf(str, "%x", &value) != 1) {
+	/* 0x/0X to force the use of hexa notation for field intended to
+	   be in hexadecimal */
+	if (sscanf(str, "0x%x", &value) != 1 &&
+	    sscanf(str, "0X%x", &value) != 1)
 		parse_error("expected hexadecimal value");
-	}
 
 	return value;
 }
@@ -61,9 +62,9 @@
 static u64 parse_long_hex(char const * str)
 {
 	u64 value;
-	if (sscanf(str, "%Lx", &value) != 1) {
+	if (sscanf(str, "%Lx", &value) != 1)
 		parse_error("expected long hexadecimal value");
-	}
+
 	fflush(stderr);
 	return value;
 }
@@ -187,12 +188,11 @@
 			um = new_unit_mask();
 			parse_um(um, line);
 		} else {
-			if (!um) {
+			if (!um)
 				parse_error("no unit mask name line");
-			}
-			if (um->num >= MAX_UNIT_MASK) {
+			if (um->num >= MAX_UNIT_MASK)
 				parse_error("oprofile: maximum unit mask entries exceeded");
-			}
+
 			parse_um_entry(&um->um[um->num], line);
 			++(um->num);
 		}
@@ -259,9 +259,8 @@
 	colon = strchr(colon, ':');
 
 	if (!colon) {
-		if (*c) {
+		if (*c)
 			parse_error("next_token(): garbage at end of line");
-		}
 		return 0;
 	}
 
@@ -337,6 +336,10 @@
 				if (seen_name)
 					parse_error("duplicate name: tag");
 				seen_name = 1;
+				if (strchr(value, '/') != NULL)
+					parse_error("invalid event name");
+				if (strchr(value, '.') != NULL)
+					parse_error("invalid event name");
 				event->name = value;
 			} else if (strcmp(name, "event") == 0) {
 				if (seen_event)
@@ -385,7 +388,7 @@
 static void check_unit_mask(struct op_unit_mask const * um,
 	char const * cpu_name)
 {
-	u16 i;
+	u32 i;
 
 	if (!um->used) {
 		fprintf(stderr, "um %s is not used\n", um->name);
@@ -397,10 +400,10 @@
 			"entry (%s)\n", um->name, cpu_name);
 		exit(EXIT_FAILURE);
 	} else if (um->unit_type_mask == utm_bitmask) {
-		u16 default_mask = um->default_mask;
-		for (i = 0; i < um->num; ++i) {
+		u32 default_mask = um->default_mask;
+		for (i = 0; i < um->num; ++i)
 			default_mask &= ~um->um[i].value;
-		}
+
 		if (default_mask) {
 			fprintf(stderr, "um %s default mask is not valid "
 				"(%s)\n", um->name, cpu_name);
@@ -519,7 +522,7 @@
 }
 
 
-static struct op_event * find_event(u8 nr)
+static struct op_event * find_event(u32 nr)
 {
 	struct list_head * pos;
 
@@ -557,7 +560,7 @@
 /**
  *  This function is PPC64-specific.
  */
-static char const * get_mapping(u8 nr, FILE * fp) 
+static char const * get_mapping(u32 nr, FILE * fp) 
 {
 	char * line;
 	char * name;
@@ -587,14 +590,13 @@
 		c = line;
 		while (next_token(&c, &name, &value)) {
 			if (strcmp(name, "event") == 0) {
-				u8 evt;
+				u32 evt;
 				if (seen_event)
 					parse_error("duplicate event tag");
 				seen_event = 1;
 				evt = parse_hex(value);
-				if (evt == nr) {
+				if (evt == nr)
 					event_found = 1;
-				}
 				free(value);
 			} else if (strcmp(name, "mmcr0") == 0) {
 				if (seen_mmcr0)
@@ -639,15 +641,20 @@
 }
 
 
-char const * find_mapping_for_event(u8 nr, op_cpu cpu_type)
+char const * find_mapping_for_event(u32 nr, op_cpu cpu_type)
 {
 	char const * cpu_name = op_get_cpu_name(cpu_type);
 	FILE * fp = open_event_mapping_file(cpu_name);
 	char const * map = NULL;
 	switch (cpu_type) {
+		case CPU_PPC64_PA6T:
 		case CPU_PPC64_970:
+		case CPU_PPC64_970MP:
 		case CPU_PPC64_POWER4:
 		case CPU_PPC64_POWER5:
+		case CPU_PPC64_POWER5p:
+		case CPU_PPC64_POWER5pp:
+		case CPU_PPC64_POWER6:
 			if (!fp) {
 				fprintf(stderr, "oprofile: could not open event mapping file %s\n", filename);
 				exit(EXIT_FAILURE);
@@ -680,7 +687,7 @@
 }
 
 
-struct op_event * op_find_event(op_cpu cpu_type, u8 nr)
+struct op_event * op_find_event(op_cpu cpu_type, u32 nr)
 {
 	struct op_event * event;
 
@@ -692,7 +699,7 @@
 }
 
 
-int op_check_events(int ctr, u8 nr, u16 um, op_cpu cpu_type)
+int op_check_events(int ctr, u32 nr, u32 um, op_cpu cpu_type)
 {
 	int ret = OP_OK_EVENT;
 	struct op_event * event;
@@ -747,8 +754,11 @@
 		case CPU_PII:
 		case CPU_PIII:
 		case CPU_P6_MOBILE:
+		case CPU_CORE:
+		case CPU_CORE_2:
 		case CPU_ATHLON:
 		case CPU_HAMMER:
+		case CPU_FAMILY10:
 			descr->name = "CPU_CLK_UNHALTED";
 			break;
 
@@ -781,12 +791,26 @@
 		// we could possibly use the CCNT
 		case CPU_ARM_XSCALE1:
 		case CPU_ARM_XSCALE2:
+		case CPU_ARM_MPCORE:
+		case CPU_ARM_V6:
+		case CPU_AVR32:
 			descr->name = "CPU_CYCLES";
 			break;
 
+		case CPU_PPC64_PA6T:
 		case CPU_PPC64_970:
+		case CPU_PPC64_970MP:
+		case CPU_PPC_7450:
 		case CPU_PPC64_POWER4:
 		case CPU_PPC64_POWER5:
+		case CPU_PPC64_POWER6:
+		case CPU_PPC64_POWER5p:
+		case CPU_PPC64_POWER5pp:
+		case CPU_PPC64_CELL:
+			descr->name = "CYCLES";
+			break;
+
+		case CPU_MIPS_20K:
 			descr->name = "CYCLES";
 			break;
 
@@ -794,6 +818,15 @@
 			descr->name = "INSTRUCTIONS";
 			break;
 
+		case CPU_MIPS_34K:
+			descr->name = "INSTRUCTIONS";
+			break;
+
+		case CPU_MIPS_5K:
+		case CPU_MIPS_25K:
+			descr->name = "CYCLES";
+			break;
+
 		case CPU_MIPS_R10000:
 		case CPU_MIPS_R12000:
 			descr->name = "INSTRUCTIONS_GRADUATED";
@@ -814,9 +847,11 @@
 			break;
 
 		case CPU_PPC_E500:
+		case CPU_PPC_E500_2:
+		case CPU_PPC_E300:
 			descr->name = "CPU_CLK";
 			break;
-             
+
 		// don't use default, if someone add a cpu he wants a compiler
 		// warning if he forgets to handle it here.
 		case CPU_TIMER_INT:
diff --git a/libop/op_events.h b/libop/op_events.h
index 1796fb9..f6462fc 100644
--- a/libop/op_events.h
+++ b/libop/op_events.h
@@ -28,8 +28,8 @@
 	utm_bitmask		/**< bitmask */
 };
 
-/** up to sixteen allowed unit masks */
-#define MAX_UNIT_MASK 16
+/** up to thirty two allowed unit masks */
+#define MAX_UNIT_MASK 32
 
 
 /** Describe an unit mask. */
@@ -37,9 +37,9 @@
 	char * name;		/**< name of unit mask type */
 	u32 num;		/**< number of possible unit masks */
 	enum unit_mask_type unit_type_mask;
-	u16 default_mask;	/**< only the gui use it */
+	u32 default_mask;	/**< only the gui use it */
 	struct op_described_um {
-		u16 value;
+		u32 value;
 		char * desc;
 	} um[MAX_UNIT_MASK];
 	struct list_head um_next; /**< next um in list */
@@ -50,7 +50,7 @@
 /** Describe an event. */
 struct op_event {
 	u32 counter_mask;	/**< bitmask of allowed counter  */
-	u8 val;			/**< event number */
+	u32 val;		/**< event number */
 	/** which unit mask if any allowed */
 	struct op_unit_mask * unit;			
 	char * name;		/**< the event name */
@@ -63,7 +63,7 @@
 struct list_head * op_events(op_cpu cpu_type);
 
 /** Find a given event, returns NULL on error */
-struct op_event * op_find_event(op_cpu cpu_type, u8 nr);
+struct op_event * op_find_event(op_cpu cpu_type, u32 nr);
 
 /** Find a given event by name */
 struct op_event * find_event_by_name(char const * name);
@@ -72,7 +72,7 @@
  * Find a mapping for a given event ID for architectures requiring additional information
  * from what is held in the events file. 
  */
-char const * find_mapping_for_event(u8 val, op_cpu cpu_type);
+char const * find_mapping_for_event(u32 val, op_cpu cpu_type);
 
 
 /** op_check_events() return code */
@@ -96,7 +96,7 @@
  *
  * \sa op_cpu, OP_EVENTS_OK
  */
-int op_check_events(int ctr, u8 event, u16 um, op_cpu cpu_type);
+int op_check_events(int ctr, u32 event, u32 um, op_cpu cpu_type);
 
 /**
  * free memory used by any call to above function. Need to be called only once
diff --git a/libop/op_get_interface.c b/libop/op_get_interface.c
index b57a79f..bdf72a5 100644
--- a/libop/op_get_interface.c
+++ b/libop/op_get_interface.c
@@ -8,15 +8,12 @@
  * @author Will Cohen
  */
 
-#include "config.h"
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
 #include "op_cpu_type.h"
 #include "op_file.h"
-#include "op_config.h"
 
 op_interface op_get_interface(void)
 {
@@ -27,7 +24,7 @@
 
 	if (op_file_readable("/proc/sys/dev/oprofile/cpu_type")) {
 		current_interface = OP_INTERFACE_24;
-	} else if (op_file_readable(OP_DRIVER_BASE"/cpu_type")) {
+	} else if (op_file_readable("/dev/oprofile/cpu_type")) {
 		current_interface = OP_INTERFACE_26;
 	}
 
diff --git a/libop/op_mangle.c b/libop/op_mangle.c
index a78d87f..1efe5b1 100644
--- a/libop/op_mangle.c
+++ b/libop/op_mangle.c
@@ -19,12 +19,14 @@
 #include "op_sample_file.h"
 #include "op_config.h"
 
-static void append_image(char * dest, int flags, int anon, char const * name)
+static void append_image(char * dest, int flags, int anon, char const * name, char const * anon_name)
 {
 	if ((flags & MANGLE_KERNEL) && !strchr(name, '/')) {
 		strcat(dest, "{kern}/");
 	} else if (anon) {
-		strcat(dest, "{anon}/");
+		strcat(dest, "{anon:");
+		strcat(dest, anon_name);
+		strcat(dest,"}/");
 	} else {
 		strcat(dest, "{root}/");
 	}
@@ -44,15 +46,19 @@
 	 * them), see P:3, FIXME: this is a bit weirds, we prolly need to
 	 * reword pp_interface */
 	char const * image_name = values->dep_name;
+	char const * anon_name = values->anon_name;
 	char const * dep_name = values->image_name;
 	char const * cg_image_name = values->cg_image_name;
 
-	len = strlen(OP_SAMPLES_CURRENT_DIR) + strlen(dep_name) + 1
-	             + strlen(values->event_name) + 1 + strlen(image_name) + 1;
+	len = strlen(op_samples_current_dir) + strlen(dep_name) + 1
+		+ strlen(values->event_name) + 1 + strlen(image_name) + 1;
 
 	if (values->flags & MANGLE_CALLGRAPH)
 		len += strlen(cg_image_name) + 1;
 
+	if (anon || cg_anon)
+		len += strlen(anon_name);
+
 	/* provision for tgid, tid, unit_mask, cpu and some {root}, {dep},
 	 * {kern}, {anon} and {cg} marker */
 	/* FIXME: too ugly */
@@ -60,15 +66,16 @@
 
 	mangled = xmalloc(len);
 
-	strcpy(mangled, OP_SAMPLES_CURRENT_DIR);
-	append_image(mangled, values->flags, 0, image_name);
+	strcpy(mangled, op_samples_current_dir);
+	append_image(mangled, values->flags, 0, image_name, anon_name);
 
 	strcat(mangled, "{dep}" "/");
-	append_image(mangled, values->flags, anon, dep_name);
+	append_image(mangled, values->flags, anon, dep_name, anon_name);
 
 	if (values->flags & MANGLE_CALLGRAPH) {
 		strcat(mangled, "{cg}" "/");
-		append_image(mangled, values->flags, cg_anon, cg_image_name);
+		append_image(mangled, values->flags, cg_anon,
+		             cg_image_name, anon_name);
 	}
 
 	strcat(mangled, values->event_name);
diff --git a/libop/op_mangle.h b/libop/op_mangle.h
index 5d02d94..9b600dc 100644
--- a/libop/op_mangle.h
+++ b/libop/op_mangle.h
@@ -37,6 +37,7 @@
 	int flags;
 
 	char const * image_name;
+	char const * anon_name;
 	char const * dep_name;
 	char const * cg_image_name;
 	char const * event_name;
diff --git a/libop/op_sample_file.h b/libop/op_sample_file.h
index c3121c8..4f9f1d0 100644
--- a/libop/op_sample_file.h
+++ b/libop/op_sample_file.h
@@ -14,6 +14,7 @@
 
 #include "op_types.h"
 
+#include <stdint.h>
 #include <time.h>
 
 /* header of the sample files */
@@ -29,6 +30,9 @@
 	double cpu_speed;
 	time_t mtime;
 	u32 cg_to_is_kernel;
+	/* spu_profile=1 says sample file contains Cell BE SPU profile data */
+	u32 spu_profile;
+	uint64_t embedded_offset;
 	u64 anon_start;
 	u64 cg_to_anon_start;
 	/* binary compatibility reserve */
diff --git a/libutil/Android.mk b/libutil/Android.mk
index 29f3bfb..6a7cf5d 100644
--- a/libutil/Android.mk
+++ b/libutil/Android.mk
@@ -7,6 +7,7 @@
 	op_file.c \
 	op_fileio.c \
 	op_get_time.c \
+	op_growable_buffer.c \
 	op_libiberty.c \
 	op_lockfile.c \
 	op_popt.c \
diff --git a/libutil/op_file.c b/libutil/op_file.c
index f2658b4..e3e6cb6 100644
--- a/libutil/op_file.c
+++ b/libutil/op_file.c
@@ -11,7 +11,9 @@
 
 #include <sys/stat.h>
 #include <unistd.h>
-
+#include <fcntl.h>
+#include <dirent.h>
+#include <fnmatch.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <errno.h>
@@ -71,3 +73,113 @@
 	free(str);
 	return ret;
 }
+
+
+inline static int is_dot_or_dotdot(char const * name)
+{
+	return name[0] == '.' &&
+		(name[1] == '\0' ||
+		 (name[1] == '.' && name[2] == '\0'));
+}
+
+
+/* If non-null is returned, the caller is responsible for freeing
+ * the memory allocated for the return value. */
+static char * make_pathname_from_dirent(char const * basedir,
+				      struct dirent * ent,
+				      struct stat * st_buf)
+{
+	int name_len;
+	char * name;
+	name_len = strlen(basedir) + strlen("/") + strlen(ent->d_name) + 1;
+	name = xmalloc(name_len);
+	sprintf(name, "%s/%s", basedir,	ent->d_name);
+	if (stat(name, st_buf) != 0) {
+		free(name);
+		name = NULL;
+	}
+	return name;
+}
+
+
+int get_matching_pathnames(void * name_list, get_pathname_callback getpathname,
+			   char const * base_dir, char const * filter,
+			   enum recursion_type recursion)
+{
+/* The algorithm below depends on recursion type (of which there are 3)
+ * and whether the current dirent matches the filter.  There are 6 possible
+ * different behaviors, which is why we define 6 case below in the switch
+ * statement of the algorithm.  Actually, when the recursion type is
+ * MATCH_DIR_ONLY_RECURSION, the behavior is the same, whether or not the dir
+ * entry matches the filter.  However, the behavior of the recursion types
+ * NO_RECURSION and MATCH_ANY_ENTRY_RECURSION do depend on the dir entry
+ * filter match, so for simplicity, we perform this match for all recursion
+ * types and logically OR the match result with the  value of the passed
+ * recursion_type.
+ */
+#define NO_MATCH 0
+#define MATCH 1
+
+	DIR * dir;
+	struct dirent * ent;
+	struct stat stat_buffer;
+	int match;
+	char * name = NULL;
+
+	if (!(dir = opendir(base_dir)))
+		return -1;
+	while ((ent = readdir(dir)) != 0) {
+		if (is_dot_or_dotdot(ent->d_name))
+			continue;
+		if (fnmatch(filter, ent->d_name, 0) == 0)
+			match = 1;
+		else
+			match = 0;
+
+		switch (recursion | match) {
+		case NO_RECURSION + NO_MATCH:
+		case MATCH_ANY_ENTRY_RECURSION + NO_MATCH:
+			// nothing to do but continue the loop
+			break;
+		case NO_RECURSION + MATCH:
+			getpathname(ent->d_name, name_list);
+			break;
+		case MATCH_ANY_ENTRY_RECURSION + MATCH:
+			name = make_pathname_from_dirent(base_dir, ent,
+						       &stat_buffer);
+			if (name && S_ISDIR(stat_buffer.st_mode) &&
+			    !S_ISLNK(stat_buffer.st_mode)) {
+				get_matching_pathnames(
+					name_list, getpathname,
+					name, filter, recursion);
+			} else {
+				getpathname(name, name_list);
+			}
+			free(name);
+			break;
+		case MATCH_DIR_ONLY_RECURSION + NO_MATCH:
+		case MATCH_DIR_ONLY_RECURSION + MATCH:
+			name = make_pathname_from_dirent(base_dir, ent,
+						       &stat_buffer);
+			if (name && S_ISDIR(stat_buffer.st_mode) &&
+			    !S_ISLNK(stat_buffer.st_mode)) {
+				/* Check if full directory name contains
+				 * match to the filter; if so, add it to
+				 * name_list and quit; else, recurse.
+				 */
+				if (!fnmatch(filter, name, 0)) {
+					getpathname(name, name_list);
+				} else {
+					get_matching_pathnames(
+						name_list, getpathname,
+						name, filter, recursion);
+				}
+			}
+			free(name);
+			break;
+		}
+	}
+	closedir(dir);
+
+	return 0;
+}
diff --git a/libutil/op_file.h b/libutil/op_file.h
index 2774ffe..d22862c 100644
--- a/libutil/op_file.h
+++ b/libutil/op_file.h
@@ -57,6 +57,51 @@
  */
 int create_path(char const * path);
 
+/**
+ * Clients of get_matching_pathnames must provide their own implementation
+ * of get_pathname_callback.
+ */
+typedef void (*get_pathname_callback)(char const * pathname, void * name_list);
+
+/* This enum is intended solely for the use of get_matching_pathnames(),
+ * bit 0 is reserved for internal use..*/
+enum recursion_type {
+	NO_RECURSION = 2,
+	MATCH_ANY_ENTRY_RECURSION = 4,
+	MATCH_DIR_ONLY_RECURSION = 8,
+};
+/**
+ * @param name_list where to store result
+ * @param get_pathname_callback client-provided callback function
+ * @param base_dir directory from where lookup starts
+ * @param filter a pathname filter
+ * @param recursion recursion_type -- see above enum and following description:
+ *	NO_RECURSION:  Find matching files from passed base_dir and call
+ *          get_pathname_callback to add entry to name_list to be returned.
+ *	MATCH_ANY_ENTRY_RECURSION: Starting at base_dir, for each entry in the
+ *	   dir that matches the filter: if entry is of type 'dir', recurse;
+ *         else call get_pathname_callback to add entry to name_list to be
+ *         returned.
+ *	MATCH_DIR_ONLY_RECURSION: Starting at base_dir, if an entry in the
+ *         dir is of type 'dir' and its complete pathname contains a match to
+ *         the filter, call get_pathname_callback to add entry to name_list to
+ *         be returned; else recurse.
+ *
+ * Returns 0 on success.
+ *
+ * Return a list of pathnames under base_dir, filtered by filter and optionally
+ * looking in sub-directory. See description above of the recursion_type 
+ * parameter for more details.
+ *    NOTE: For C clients: Your implementation of the get_pathname_callback
+ *          function will probably dynamically allocate storage for elements
+ *          added to name_list.  If so, remember to free that memory when it's
+ *          no longer needed.
+ */
+int get_matching_pathnames(void * name_list, get_pathname_callback,
+			   char const * base_dir, char const * filter,
+			   enum recursion_type recursion);
+
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/libutil/op_growable_buffer.c b/libutil/op_growable_buffer.c
new file mode 100644
index 0000000..d138f36
--- /dev/null
+++ b/libutil/op_growable_buffer.c
@@ -0,0 +1,46 @@
+/**
+ * @file op_growable_buffer.c
+ * a growable buffer implementation
+ *
+ * @remark Copyright 2007 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author Philippe Elie
+ */
+
+#include "op_growable_buffer.h"
+#include "op_libiberty.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+void init_buffer(struct growable_buffer * b)
+{
+	b->max_size = 0;
+	b->size = 0;
+	b->p = NULL;
+}
+
+
+void free_buffer(struct growable_buffer * b)
+{
+	free(b->p);
+}
+
+
+static void grow_buffer(struct growable_buffer * b)
+{
+	size_t new_size = (b->max_size + b->size) * 2;
+	b->p = xrealloc(b->p, new_size);
+	b->max_size = new_size;
+}
+
+
+void add_data(struct growable_buffer * b, void const * data, size_t len)
+{
+	size_t old_size = b->size;
+	b->size += len;
+	if (b->size > b->max_size)
+		grow_buffer(b);
+	memcpy(b->p + old_size, data, len);
+}
diff --git a/libutil/op_growable_buffer.h b/libutil/op_growable_buffer.h
new file mode 100644
index 0000000..491969a
--- /dev/null
+++ b/libutil/op_growable_buffer.h
@@ -0,0 +1,45 @@
+/**
+ * @file op_growable_buffer.h
+ * a growable buffer interface
+ *
+ * @remark Copyright 2007 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author Philippe Elie
+ */
+
+#ifndef OP_GROWABLE_BUFFER_H
+#define OP_GROWABLE_BUFFER_H
+
+#include <stddef.h>
+
+struct growable_buffer {
+	void * p;
+	size_t size;
+	size_t max_size;
+};
+
+/**
+ * init_buffer - initialize an empty buffer
+ * @param buffer the buffer to initialize
+ *
+ * init_buffer do not do any allocation, the first allocation will occur
+ * when add_data() with a non zero len param will be called.
+ */
+void init_buffer(struct growable_buffer * buffer);
+
+/**
+ * free_buffer - free the memory allocated for this buffer
+ * @param buffer the buffer to free
+ */
+void free_buffer(struct growable_buffer * buffer);
+
+/**
+ * add_data - add data to this buffer
+ * @param b the buffer where to add data
+ * @param data a pointer to the data to add
+ * @param len number of byte to add to the buffer
+ */
+void add_data(struct growable_buffer * b, void const * data, size_t len);
+
+#endif /* !OP_GROWABLE_BUFFER_H */
diff --git a/libutil/op_libiberty.c b/libutil/op_libiberty.c
index 3f2725a..0cf45d3 100644
--- a/libutil/op_libiberty.c
+++ b/libutil/op_libiberty.c
@@ -11,7 +11,6 @@
  */
 
 #include <string.h>
-#include <stdlib.h>
 
 #include "op_libiberty.h"
 
@@ -37,27 +36,3 @@
 	return output;
 }
 #endif
-
-#ifndef HAVE_LIBIBERTY_H
-
-void xmalloc_set_program_name(char const * a)
-{
-}
-
-void * xmalloc(size_t s)
-{
-    return malloc(s);
-}
-
-void * xrealloc(void *p, size_t s)
-{
-    return realloc(p, s);
-}
-
-/* Copy a string into a memory buffer without fail.  */
-char * xstrdup(char const * str)
-{
-    return strdup(str);
-}
-
-#endif
diff --git a/libutil/op_libiberty.h b/libutil/op_libiberty.h
index 5372a10..ea02a50 100644
--- a/libutil/op_libiberty.h
+++ b/libutil/op_libiberty.h
@@ -34,6 +34,7 @@
 /* some system have a libiberty.a but no libiberty.h so we must provide
  * ourself the missing proto */
 #ifndef HAVE_LIBIBERTY_H
+
 /* Set the program name used by xmalloc.  */
 void xmalloc_set_program_name(char const *);
 
@@ -63,6 +64,14 @@
 
 #endif	/* !HAVE_LIBIBERTY_H */
 
+#ifdef ANDROID
+#define xmalloc(s)      malloc(s)
+#define xrealloc(p,s)   realloc(p,s)
+#define xstrdup(str)    strdup(str)
+#define xmalloc_set_program_name(n)
+#endif
+
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/libutil/op_list.h b/libutil/op_list.h
index 2e93dda..ed0cd8a 100644
--- a/libutil/op_list.h
+++ b/libutil/op_list.h
@@ -117,7 +117,7 @@
  * list_empty - tests whether a list is empty
  * @param head  the list to test.
  */
-static __inline__ int list_empty(struct list_head * head)
+static __inline__ int list_empty(struct list_head const * head)
 {
 	return head->next == head;
 }
diff --git a/libutil/op_types.h b/libutil/op_types.h
index 612af20..c025b23 100644
--- a/libutil/op_types.h
+++ b/libutil/op_types.h
@@ -27,6 +27,9 @@
 /** generic type for holding addresses */
 typedef unsigned long long vma_t;
 
+/** generic type to hold a sample count in pp tools */
+typedef u64 count_type;
+
 #else
 #include <linux/types.h>
 #endif
diff --git a/opcontrol/Android.mk b/opcontrol/Android.mk
index d238e9e..56211ad 100644
--- a/opcontrol/Android.mk
+++ b/opcontrol/Android.mk
@@ -5,7 +5,7 @@
 	opcontrol.cpp
 
 LOCAL_STATIC_LIBRARIES := \
-	libpopt libutil libdb libabic libop
+	libpopt libutil libdb libabi libop
 
 LOCAL_C_INCLUDES := \
 	$(LOCAL_PATH)/.. \
diff --git a/opcontrol/opcontrol.cpp b/opcontrol/opcontrol.cpp
index c0b29c7..50067cc 100644
--- a/opcontrol/opcontrol.cpp
+++ b/opcontrol/opcontrol.cpp
@@ -1,172 +1,275 @@
 /*
- * opcontrol/opcontrol.cpp
+ * Copyright 2008, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
  */
 
+/*
+ * Binary implementation of the original opcontrol script due to missing tools
+ * like awk, test, etc.
+ */
+
+#include <unistd.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+
 #include "op_config.h"
 
-#include <stdlib.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <errno.h>
-#include <assert.h>
-#include <dirent.h>
-#include <sys/stat.h>
+#if 0
+#define verbose(fmt...) printf(fmt)
+#else
+#define verbose(fmt...)
+#endif
 
-static int usage(const char* name);
-static int echo(const char* str, const char* file);
-static int read_num(const char* file);
+/* Experiments found that using a small interval may hang the device, and the
+ * more events tracked simultaneously, the longer the interval has to be.
+ */
+int min_count[3] = {150000, 200000, 250000};
+int list_events; 
+int show_usage;
+int setup;
+int quick;
+int num_events;
+int start;
+int stop;
+int reset;
 
-static int start_profiler(int argc, char const * argv[]);
-static int stop_profiler();
-static int reset_profiler();
-static int status_profiler();
+int selected_events[3];
+int selected_counts[3];
 
-int main(int argc, char const * argv[])
-{
-    if (argc < 2)
-        return usage(argv[0]);
+char kernel_range[512];
+char vmlinux[512];
 
-    const char* tool = argv[1];
+struct option long_options[] = {
+    {"help", 0, &show_usage, 1},
+    {"list-events", 0, &list_events, 1},
+    {"reset", 0, &reset, 1},
+    {"setup", 0, &setup, 1},
+    {"quick", 0, &quick, 1},
+    {"event", 1, 0, 'e'},
+    {"vmlinux", 1, 0, 'v'},
+    {"kernel-range", 1, 0, 'r'},
+    {"start", 0, &start, 1},
+    {"stop", 0, &stop, 1},
+    {"shutdown", 0, 0, 'h'},
+    {"status", 0, 0, 't'},
+    {0, 0, 0, 0},
+};
 
-    int ret = 0;
-    if (!strcmp("start", tool))        ret = start_profiler(argc-2, argv+2);
-    else if (!strcmp("stop", tool))    ret = stop_profiler();
-    else if (!strcmp("reset", tool))   ret = reset_profiler();
-    else if (!strcmp("status", tool))  ret = status_profiler();
+struct event_info {
+    int id;
+    const char *name;
+    const char *explanation;
+} event_info[] = {
+    {0x00, "IFU_IFETCH_MISS", 
+     "number of instruction fetch misses"},
+    {0x01, "CYCLES_IFU_MEM_STALL", 
+     "cycles instruction fetch pipe is stalled"},
+    {0x02, "CYCLES_DATA_STALL", 
+     "cycles stall occurs for due to data dependency"},
+    {0x03, "ITLB_MISS", 
+     "number of Instruction MicroTLB misses"},
+    {0x04, "DTLB_MISS", 
+     "number of Data MicroTLB misses"},
+    {0x05, "BR_INST_EXECUTED", 
+     "branch instruction executed w/ or w/o program flow change"},
+    {0x06, "BR_INST_MISS_PRED", 
+     "branch mispredicted"},
+    {0x07, "INSN_EXECUTED", 
+     "instructions executed"},
+    {0x09, "DCACHE_ACCESS", 
+     "data cache access, cacheable locations"},
+    {0x0a, "DCACHE_ACCESS_ALL", 
+     "data cache access, all locations"},
+    {0x0b, "DCACHE_MISS", 
+     "data cache miss"},
+    {0x0c, "DCACHE_WB", 
+     "data cache writeback, 1 event for every half cacheline"},
+    {0x0d, "PC_CHANGE", 
+     "number of times the program counter was changed without a mode switch"},
+    {0x0f, "TLB_MISS", 
+     "Main TLB miss"},
+    {0x10, "EXP_EXTERNAL", 
+     "Explicit external data access"},
+    {0x11, "LSU_STALL", 
+     "cycles stalled because Load Store request queue is full"},
+    {0x12, "WRITE_DRAIN", 
+     "Times write buffer was drained"},
+    {0xff, "CPU_CYCLES", 
+     "clock cycles counter"}, 
+};
 
-    return ret ? usage(argv[0]) : 0;
+void usage() {
+    printf("\nopcontrol: usage:\n"
+           "   --list-events    list event types\n"
+           "   --help           this message\n"
+           "   --setup          setup directories\n"
+           "   --quick          setup and select CPU_CYCLES:150000\n"
+           "   --status         show configuration\n"
+           "   --start          start data collection\n"
+           "   --stop           stop data collection\n"
+           "   --reset          clears out data from current session\n"
+           "   --shutdown       kill the oprofile daeman\n"
+           "   --event=eventspec\n"
+           "      Choose an event. May be specified multiple times.\n"
+           "      eventspec is in the form of name[:count], where :\n"
+           "        name:  event name, see \"opcontrol --list-events\"\n"
+           "        count: reset counter value\n" 
+           "   --vmlinux=file   vmlinux kernel image\n"
+           "   --kernel-range=start,end\n"
+           "                    kernel range vma address in hexadecimal\n"
+          );
 }
 
-int usage(const char* name)
-{
-    printf("usage: %s [start [-e event][-p type][-c depth][-i names]"
-            " | stop | reset | status]\n", name);
-    return 0;
+void setup_session_dir() {
+    int fd;
+
+    fd = open(OP_DATA_DIR, O_RDONLY);
+    if (fd != -1) {
+        system("rm -r "OP_DATA_DIR);
+        close(fd);
+    }
+
+    if (mkdir(OP_DATA_DIR, 755)) {
+        fprintf(stderr, "Cannot create directory \"%s\": %s\n",
+                OP_DATA_DIR, strerror(errno));
+    }
+    if (mkdir(OP_DATA_DIR"/samples", 644)) {
+        fprintf(stderr, "Cannot create directory \"%s\": %s\n",
+                OP_DATA_DIR"/samples", strerror(errno));
+    }
 }
 
+int do_setup() {
+    char dir[1024];
 
-int start_profiler(int argc, char const * argv[])
-{
-    char const* backtrace_depth = "0";
-    if (argc&1)
-        return -1; 
+    setup_session_dir();
 
-    while (argc>0) {
-        if (!strcmp("-c", argv[0]))
-            backtrace_depth = argv[1];
-        else if (!strcmp("-p", argv[0]))
-            ; // type
-        else if (!strcmp("-e", argv[0]))
-            ; // event
-        else if (!strcmp("-i", argv[0]))
-            ; // images
-        argc-=2;
-        argv+=2;        
-    }
-
-    int err;
-
-    err = echo(backtrace_depth, OP_DRIVER_BASE"/backtrace_depth");
-    if (err) {
-        printf("couldn't set backtrace depth. backtraces disabled.\n");
-    }
-
-    err = echo("1", OP_DRIVER_BASE"/enable");
-    if (err) {
-        printf("couldn't start profiling, is the oprofile driver installed?\n");
+    if (mkdir(OP_DRIVER_BASE, 644)) {
+        fprintf(stderr, "Cannot create directory "OP_DRIVER_BASE": %s\n",
+                strerror(errno));
         return -1;
     }
-
-    // XXX: start daemon with all good options ...
-
-    mkdir(OP_BASE_DIR, 644);
-    return 0;
-}
-
-int stop_profiler()
-{
-    int dump, stop;
-    dump = echo("1", OP_DRIVER_BASE"/dump");
-        // XXX: should wait for complete_dump
-    usleep(250000);
-    stop = echo("0", OP_DRIVER_BASE"/enable");
-    if (dump || stop) {
-        printf("couldn't stop profiling, is the oprofile driver installed?\n");
+    if (system("mount -t oprofilefs nodev "OP_DRIVER_BASE)) {
         return -1;
     }
-    int num = read_num(OP_DRIVER_BASE"/stats/cpu0/sample_received");
-    printf("profiler stopped with %u samples received\n", num);
     return 0;
 }
 
-int rm_dir_content(const char* path)
+void do_list_events()
 {
-    DIR* d = opendir(path);
-    if (d) {
-        struct dirent* de;
-        while ((de = readdir(d))) {
-            if(de->d_name[0] == '.') continue;
-            struct stat s;
-            char* tmp = (char*)malloc(strlen(path)+strlen(de->d_name)+2);
-            if (tmp) {
-                sprintf(tmp, "%s/%s", path, de->d_name);
-                if (lstat(tmp, &s) == 0) {
-                    int mode = s.st_mode & S_IFMT;
-                    if (mode == S_IFDIR) {
-                        rm_dir_content(tmp);
-                        rmdir(tmp);
-                    } else if (mode == S_IFLNK) {
-                    } else if (mode == S_IFSOCK) {
-                    } else if (mode == S_IFREG) {
-                        unlink(tmp);
-                    }
-                }
-                free(tmp);
-            }
+    unsigned int i;
+
+    printf("%-20s: %s\n", "name", "meaning");
+    printf("----------------------------------------"
+           "--------------------------------------\n");
+    for (i = 0; i < sizeof(event_info)/sizeof(struct event_info); i++) {
+        printf("%-20s: %s\n", event_info[i].name, event_info[i].explanation);
+    }
+}
+
+int find_event_id_from_name(const char *name) {
+    unsigned int i;
+
+    for (i = 0; i < sizeof(event_info)/sizeof(struct event_info); i++) {
+        if (!strcmp(name, event_info[i].name)) {
+            return i;
         }
-        closedir(d);
     }
-    return 0;
-}
-
-int reset_profiler()
-{
-    echo("1", OP_DRIVER_BASE"/dump");
-    usleep(250000);
-    // should erase all samples
-    rm_dir_content(OP_BASE_DIR);
-    return 0;
-}
-
-
-int status_profiler()
-{
-    int num = read_num(OP_DRIVER_BASE"/enable");
-    if (num >= 0) {
-        printf("profiler %s\n", num ? "started" : "not started");
-        num = read_num(OP_DRIVER_BASE"/stats/cpu0/sample_received");
-        printf("  %9u samples received\n", num);
-        num = read_num(OP_DRIVER_BASE"/stats/cpu0/backtrace_aborted");
-        printf("  %9u backtrace aborted\n", num);
-        num = read_num(OP_DRIVER_BASE"/stats/cpu0/sample_lost_overflow");
-        printf("  %9u samples lost overflow\n", num);
-        num = read_num(OP_DRIVER_BASE"/backtrace_depth");
-        printf("  %9u backtrace_depth\n", num);
-        return 0;
-    }
-    printf("couldn't get profiling status, is the oprofile driver installed?\n");
     return -1;
-
 }
 
-int echo(const char* str, const char* file)
+const char * find_event_name_from_id(int id) {
+    unsigned int i;
+
+    for (i = 0; i < sizeof(event_info)/sizeof(struct event_info); i++) {
+        if (event_info[i].id == id) {
+            return event_info[i].name;
+        }
+    }
+    return NULL;
+}
+
+int process_event(const char *event_spec) {
+    char event_name[512];
+    char count_name[512];
+    unsigned int i;
+    int event_id;
+    int count_val;
+
+    strncpy(event_name, event_spec, 512);
+    count_name[0] = 0;
+
+    /* First, check if the name is followed by ":" */
+    for (i = 0; i < strlen(event_name); i++) {
+        if (event_name[i] == 0) {
+            break;
+        }
+        if (event_name[i] == ':') {
+            strncpy(count_name, event_name+i+1, 512);
+            event_name[i] = 0;
+            break;
+        }
+    }
+    event_id = find_event_id_from_name(event_name);
+    if (event_id == -1) {
+        fprintf(stderr, "Unknown event name: %s\n", event_name);
+        return -1;
+    }
+
+    /* Use defualt count */
+    if (count_name[0] == 0) {
+        count_val = min_count[0];
+    } else {
+        count_val = atoi(count_name);
+    }
+
+    selected_events[num_events] = event_id;
+    selected_counts[num_events++] = count_val;
+    verbose("event_id is %d\n", event_id);
+    verbose("count_val is %d\n", count_val);
+    return 0;
+}
+
+int echo_dev(const char* str, int val, const char* file, int counter)
 {
-    int fd = open(file, O_WRONLY);
-    if (fd<0)
+    char fullname[512];
+    char content[128];
+    int fd;
+    
+    if (counter >= 0) {
+        snprintf(fullname, 512, OP_DRIVER_BASE"/%d/%s", counter, file);
+    }
+    else {
+        snprintf(fullname, 512, OP_DRIVER_BASE"/%s", file);
+    }
+    fd = open(fullname, O_WRONLY);
+    if (fd<0) {
+        fprintf(stderr, "Cannot open %s: %s\n", fullname, strerror(errno));
         return fd;
-    write(fd, str, strlen(str));
+    }
+    if (str == 0) {
+        sprintf(content, "%d", val);
+    }
+    else {
+        strncpy(content, str, 128);
+    }
+    verbose("Configure %s (%s)\n", fullname, content);
+    write(fd, content, strlen(content));
     close(fd);
     return 0;
 }
@@ -181,3 +284,258 @@
     return atoi(buffer);
 }
 
+void do_status()
+{
+    int num;
+    char fullname[512];
+    int i;
+
+    printf("Driver directory: %s\n", OP_DRIVER_BASE);
+    printf("Session directory: %s\n", OP_DATA_DIR);
+    for (i = 0; i < 3; i++) {
+        sprintf(fullname, OP_DRIVER_BASE"/%d/enabled", i);
+        num = read_num(fullname);
+        if (num > 0) {
+            printf("Counter %d:\n", i);
+
+            /* event name */
+            sprintf(fullname, OP_DRIVER_BASE"/%d/event", i);
+            num = read_num(fullname);
+            printf("    name: %s\n", find_event_name_from_id(num));
+
+            /* profile interval */
+            sprintf(fullname, OP_DRIVER_BASE"/%d/count", i);
+            num = read_num(fullname);
+            printf("    count: %d\n", num);
+        }
+        else {
+            printf("Counter %d disabled\n", i);
+        }
+    }
+
+    num = read_num(OP_DATA_DIR"/lock");
+    if (num >= 0) {
+        int fd;
+        /* Still needs to check if this lock is left-over */
+        sprintf(fullname, "/proc/%d", num);
+        fd = open(fullname, O_RDONLY);
+        if (fd == -1) {
+            printf("Session directory is not clean - do \"opcontrol --setup\""
+                   " before you continue\n");
+            return;
+        }
+        else {
+            close(fd);
+            printf("oprofiled pid: %d\n", num);
+            num = read_num(OP_DRIVER_BASE"/enable");
+            printf("profiler is%s running\n", num == 0 ? " not" : "");
+            num = read_num(OP_DRIVER_BASE"/stats/cpu0/sample_received");
+            printf("  %9u samples received\n", num);
+            num = read_num(OP_DRIVER_BASE"/stats/cpu0/sample_lost_overflow");
+            printf("  %9u samples lost overflow\n", num);
+#if 0
+            /* FIXME - backtrace seems broken */
+            num = read_num(OP_DRIVER_BASE"/stats/cpu0/backtrace_aborted");
+            printf("  %9u backtrace aborted\n", num);
+            num = read_num(OP_DRIVER_BASE"/backtrace_depth");
+            printf("  %9u backtrace_depth\n", num);
+#endif
+        }
+    }
+    else {
+        printf("oprofiled is not running\n");
+    }
+}
+
+void do_reset() 
+{
+    int fd;
+
+    fd = open(OP_DATA_DIR"/samples/current", O_RDONLY);
+    if (fd == -1) {
+        return;
+    }
+    close(fd);
+    system("rm -r "OP_DATA_DIR"/samples/current");
+}
+
+int main(int argc, char * const argv[])
+{
+    int option_index;
+    char command[1024];
+
+    /* Initialize default strings */
+    strcpy(vmlinux, "--no-vmlinux");
+    strcpy(kernel_range, "");
+
+    while (1) {
+        int c = getopt_long(argc, argv, "", long_options, &option_index);
+        if (c == -1) {
+            break;
+        }
+        switch (c) {
+            case 0:
+                break;
+            /* --event */
+            case 'e':   
+                if (num_events == 3) {
+                    fprintf(stderr, "More than 3 events specified\n");
+                    exit(1);
+                }
+                if (process_event(optarg)) {
+                    exit(1);
+                }
+                break;
+            /* --vmlinux */
+            case 'v':
+                sprintf(vmlinux, "-k %s", optarg);
+                break;
+            /* --kernel-range */
+            case 'r':
+                sprintf(kernel_range, "-r %s", optarg);
+                break;
+            /* --shutdown */
+            case 'h': {
+                int pid = read_num(OP_DATA_DIR"/lock");
+                if (pid >= 0) {
+                    kill(pid, SIGKILL);
+                }   
+                setup_session_dir();
+                break;
+            }
+            /* --status */
+            case 't':
+                do_status();
+                break;
+            default:
+                usage();
+                exit(1);
+        }
+    }
+    verbose("list_events = %d\n", list_events);
+    verbose("setup = %d\n", setup);
+
+    if (list_events) {
+        do_list_events();
+    }
+
+    if (quick) {
+        process_event("CPU_CYCLES");
+        setup = 1;
+    }
+
+    if (reset) {
+        do_reset();
+    }
+
+    if (show_usage) {
+        usage();
+    }
+
+    if (setup) {
+        if (do_setup()) {
+            fprintf(stderr, "do_setup failed");
+            exit(1);
+        }
+    }
+
+    if (num_events != 0) {
+        int i;
+
+        strcpy(command, "oprofiled --session-dir="OP_DATA_DIR);
+
+        /* Since counter #3 can only handle CPU_CYCLES, check and shuffle the 
+         * order a bit so that the maximal number of events can be profiled
+         * simultaneously
+         */
+        if (num_events == 3) {
+            for (i = 0; i < num_events; i++) {
+                int event_idx = selected_events[i];
+
+                if (event_info[event_idx].id == 0xff) {
+                    break;
+                }
+            }
+
+            /* No CPU_CYCLES is found */
+            if (i == 3) {
+                fprintf(stderr, "You can only specify three events if one of "
+                                "them is CPU_CYCLES\n");
+                exit(1);
+            }
+            /* Swap CPU_CYCLES to counter #2 (starting from #0)*/
+            else if (i != 2) {
+                int temp;
+
+                temp = selected_events[2];
+                selected_events[2] = selected_events[i];
+                selected_events[i] = temp;
+
+                temp = selected_counts[2];
+                selected_counts[2] = selected_counts[i];
+                selected_counts[i] = temp;
+            }
+        }
+
+
+        /* Configure the counters and enable them */
+        for (i = 0; i < num_events; i++) {
+            int event_idx = selected_events[i];
+            int setup_result = 0;
+
+            if (i == 0) {
+                snprintf(command+strlen(command), 1024 - strlen(command), 
+                         " --events=");
+            }
+            else {
+                snprintf(command+strlen(command), 1024 - strlen(command), 
+                         ",");
+            }
+            /* Compose name:id:count:unit_mask:kernel:user, something like
+             * --events=CYCLES_DATA_STALL:2:0:200000:0:1:1,....
+             */
+            snprintf(command+strlen(command), 1024 - strlen(command), 
+                     "%s:%d:%d:%d:0:1:1",
+                     event_info[event_idx].name,
+                     event_info[event_idx].id,
+                     i,
+                     selected_counts[i]);
+
+            setup_result |= echo_dev("1", 0, "user", i);
+            setup_result |= echo_dev("1", 0, "kernel", i);
+            setup_result |= echo_dev("0", 0, "unit_mask", i);
+            setup_result |= echo_dev("1", 0, "enabled", i);
+            setup_result |= echo_dev(NULL, selected_counts[i], "count", i);
+            setup_result |= echo_dev(NULL, event_info[event_idx].id, 
+                                     "event", i);
+            if (setup_result) {
+                fprintf(stderr, "Counter configuration failed for %s\n",
+                        event_info[event_idx].name);
+                fprintf(stderr, "Did you do \"opcontrol --setup\" first?\n");
+                exit(1);
+            }
+        }
+
+        /* Disable the unused counters */
+        for (i = num_events; i < 3; i++) {
+            echo_dev("0", 0, "enabled", i);
+        }
+
+        snprintf(command+strlen(command), 1024 - strlen(command), " %s",
+                 vmlinux);
+        if (kernel_range[0]) {
+            snprintf(command+strlen(command), 1024 - strlen(command), " %s",
+                     kernel_range);
+        }
+        verbose("command: %s\n", command);
+        system(command);
+    }
+
+    if (start) {
+        echo_dev("1", 0, "enable", -1);
+    }
+
+    if (stop) {
+        echo_dev("0", 0, "enable", -1);
+    }
+}