All of lore.kernel.org
 help / color / mirror / Atom feed
From: Frederic Weisbecker <fweisbec@gmail.com>
To: LKML <linux-kernel@vger.kernel.org>
Cc: Steven Rostedt <srostedt@redhat.com>,
	Steven Rostedt <rostedt@goodmis.org>,
	Ingo Molnar <mingo@kernel.org>,
	Thomas Gleixner <tglx@linutronix.de>,
	Peter Zijlstra <peterz@infradead.org>,
	Arnaldo Carvalho de Melo <acme@infradead.org>,
	Borislav Petkov <bp@alien8.de>, Jiri Olsa <jolsa@redhat.com>,
	Arun Sharma <asharma@fb.com>, Namhyung Kim <namhyung.kim@lge.com>,
	Frederic Weisbecker <fweisbec@gmail.com>
Subject: [PATCH 01/15] perf: Separate out trace-cmd parse-events from perf files
Date: Fri,  6 Apr 2012 00:47:52 +0200	[thread overview]
Message-ID: <1333666086-6517-2-git-send-email-fweisbec@gmail.com> (raw)
In-Reply-To: <1333666086-6517-1-git-send-email-fweisbec@gmail.com>

From: Steven Rostedt <srostedt@redhat.com>

Move the trace-event-parse.c code that originally came from trace-cmd into
their own files. The new file will be called trace-parse-events.c, as
the name of trace-cmd's file was parse-events.c too, but it conflicted
with the parse-events.c file in perf that parses the command line.

This tries to update the code with mimimal changes.

Perf specific code stays in the trace-event-parse.[ch] files and
the common parsing code is now in trace-parse-events.c and
trace-parse-events.h.

Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Arnaldo Carvalho de Melo <acme@infradead.org>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Arun Sharma <asharma@fb.com>
Cc: Namhyung Kim <namhyung.kim@lge.com>
Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
---
 tools/perf/Makefile                  |    2 +
 tools/perf/util/trace-event-parse.c  | 3135 ----------------------------------
 tools/perf/util/trace-event.h        |  275 +---
 tools/perf/util/trace-parse-events.c | 3125 +++++++++++++++++++++++++++++++++
 tools/perf/util/trace-parse-events.h |  273 +++
 5 files changed, 3405 insertions(+), 3405 deletions(-)
 create mode 100644 tools/perf/util/trace-parse-events.c
 create mode 100644 tools/perf/util/trace-parse-events.h

diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 820371f..6f93a99 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -326,6 +326,7 @@ LIB_H += util/hist.h
 LIB_H += util/thread.h
 LIB_H += util/thread_map.h
 LIB_H += util/trace-event.h
+LIB_H += util/trace-parse-events.h
 LIB_H += util/probe-finder.h
 LIB_H += util/dwarf-aux.h
 LIB_H += util/probe-event.h
@@ -387,6 +388,7 @@ LIB_OBJS += $(OUTPUT)util/pmu-bison.o
 LIB_OBJS += $(OUTPUT)util/trace-event-read.o
 LIB_OBJS += $(OUTPUT)util/trace-event-info.o
 LIB_OBJS += $(OUTPUT)util/trace-event-scripting.o
+LIB_OBJS += $(OUTPUT)util/trace-parse-events.o
 LIB_OBJS += $(OUTPUT)util/svghelper.o
 LIB_OBJS += $(OUTPUT)util/sort.o
 LIB_OBJS += $(OUTPUT)util/hist.o
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c
index dfd1bd8..9477519 100644
--- a/tools/perf/util/trace-event-parse.c
+++ b/tools/perf/util/trace-event-parse.c
@@ -1,3142 +1,7 @@
-/*
- * Copyright (C) 2009, Steven Rostedt <srostedt@redhat.com>
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License (not later!)
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- *  The parts for function graph printing was taken and modified from the
- *  Linux Kernel that were written by Frederic Weisbecker.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-
 #include "../perf.h"
 #include "util.h"
 #include "trace-event.h"
 
-int header_page_ts_offset;
-int header_page_ts_size;
-int header_page_size_offset;
-int header_page_size_size;
-int header_page_overwrite_offset;
-int header_page_overwrite_size;
-int header_page_data_offset;
-int header_page_data_size;
-
-bool latency_format;
-
-static char *input_buf;
-static unsigned long long input_buf_ptr;
-static unsigned long long input_buf_siz;
-
-static int cpus;
-static int long_size;
-static int is_flag_field;
-static int is_symbolic_field;
-
-static struct format_field *
-find_any_field(struct event *event, const char *name);
-
-static void init_input_buf(char *buf, unsigned long long size)
-{
-	input_buf = buf;
-	input_buf_siz = size;
-	input_buf_ptr = 0;
-}
-
-struct cmdline {
-	char *comm;
-	int pid;
-};
-
-static struct cmdline *cmdlines;
-static int cmdline_count;
-
-static int cmdline_cmp(const void *a, const void *b)
-{
-	const struct cmdline *ca = a;
-	const struct cmdline *cb = b;
-
-	if (ca->pid < cb->pid)
-		return -1;
-	if (ca->pid > cb->pid)
-		return 1;
-
-	return 0;
-}
-
-void parse_cmdlines(char *file, int size __unused)
-{
-	struct cmdline_list {
-		struct cmdline_list	*next;
-		char			*comm;
-		int			pid;
-	} *list = NULL, *item;
-	char *line;
-	char *next = NULL;
-	int i;
-
-	line = strtok_r(file, "\n", &next);
-	while (line) {
-		item = malloc_or_die(sizeof(*item));
-		sscanf(line, "%d %as", &item->pid,
-		       (float *)(void *)&item->comm); /* workaround gcc warning */
-		item->next = list;
-		list = item;
-		line = strtok_r(NULL, "\n", &next);
-		cmdline_count++;
-	}
-
-	cmdlines = malloc_or_die(sizeof(*cmdlines) * cmdline_count);
-
-	i = 0;
-	while (list) {
-		cmdlines[i].pid = list->pid;
-		cmdlines[i].comm = list->comm;
-		i++;
-		item = list;
-		list = list->next;
-		free(item);
-	}
-
-	qsort(cmdlines, cmdline_count, sizeof(*cmdlines), cmdline_cmp);
-}
-
-static struct func_map {
-	unsigned long long		addr;
-	char				*func;
-	char				*mod;
-} *func_list;
-static unsigned int func_count;
-
-static int func_cmp(const void *a, const void *b)
-{
-	const struct func_map *fa = a;
-	const struct func_map *fb = b;
-
-	if (fa->addr < fb->addr)
-		return -1;
-	if (fa->addr > fb->addr)
-		return 1;
-
-	return 0;
-}
-
-void parse_proc_kallsyms(char *file, unsigned int size __unused)
-{
-	struct func_list {
-		struct func_list	*next;
-		unsigned long long	addr;
-		char			*func;
-		char			*mod;
-	} *list = NULL, *item;
-	char *line;
-	char *next = NULL;
-	char *addr_str;
-	char ch;
-	int ret __used;
-	int i;
-
-	line = strtok_r(file, "\n", &next);
-	while (line) {
-		item = malloc_or_die(sizeof(*item));
-		item->mod = NULL;
-		ret = sscanf(line, "%as %c %as\t[%as",
-			     (float *)(void *)&addr_str, /* workaround gcc warning */
-			     &ch,
-			     (float *)(void *)&item->func,
-			     (float *)(void *)&item->mod);
-		item->addr = strtoull(addr_str, NULL, 16);
-		free(addr_str);
-
-		/* truncate the extra ']' */
-		if (item->mod)
-			item->mod[strlen(item->mod) - 1] = 0;
-
-
-		item->next = list;
-		list = item;
-		line = strtok_r(NULL, "\n", &next);
-		func_count++;
-	}
-
-	func_list = malloc_or_die(sizeof(*func_list) * (func_count + 1));
-
-	i = 0;
-	while (list) {
-		func_list[i].func = list->func;
-		func_list[i].addr = list->addr;
-		func_list[i].mod = list->mod;
-		i++;
-		item = list;
-		list = list->next;
-		free(item);
-	}
-
-	qsort(func_list, func_count, sizeof(*func_list), func_cmp);
-
-	/*
-	 * Add a special record at the end.
-	 */
-	func_list[func_count].func = NULL;
-	func_list[func_count].addr = 0;
-	func_list[func_count].mod = NULL;
-}
-
-/*
- * We are searching for a record in between, not an exact
- * match.
- */
-static int func_bcmp(const void *a, const void *b)
-{
-	const struct func_map *fa = a;
-	const struct func_map *fb = b;
-
-	if ((fa->addr == fb->addr) ||
-
-	    (fa->addr > fb->addr &&
-	     fa->addr < (fb+1)->addr))
-		return 0;
-
-	if (fa->addr < fb->addr)
-		return -1;
-
-	return 1;
-}
-
-static struct func_map *find_func(unsigned long long addr)
-{
-	struct func_map *func;
-	struct func_map key;
-
-	key.addr = addr;
-
-	func = bsearch(&key, func_list, func_count, sizeof(*func_list),
-		       func_bcmp);
-
-	return func;
-}
-
-void print_funcs(void)
-{
-	int i;
-
-	for (i = 0; i < (int)func_count; i++) {
-		printf("%016llx %s",
-		       func_list[i].addr,
-		       func_list[i].func);
-		if (func_list[i].mod)
-			printf(" [%s]\n", func_list[i].mod);
-		else
-			printf("\n");
-	}
-}
-
-static struct printk_map {
-	unsigned long long		addr;
-	char				*printk;
-} *printk_list;
-static unsigned int printk_count;
-
-static int printk_cmp(const void *a, const void *b)
-{
-	const struct func_map *fa = a;
-	const struct func_map *fb = b;
-
-	if (fa->addr < fb->addr)
-		return -1;
-	if (fa->addr > fb->addr)
-		return 1;
-
-	return 0;
-}
-
-static struct printk_map *find_printk(unsigned long long addr)
-{
-	struct printk_map *printk;
-	struct printk_map key;
-
-	key.addr = addr;
-
-	printk = bsearch(&key, printk_list, printk_count, sizeof(*printk_list),
-			 printk_cmp);
-
-	return printk;
-}
-
-void parse_ftrace_printk(char *file, unsigned int size __unused)
-{
-	struct printk_list {
-		struct printk_list	*next;
-		unsigned long long	addr;
-		char			*printk;
-	} *list = NULL, *item;
-	char *line;
-	char *next = NULL;
-	char *addr_str;
-	int i;
-
-	line = strtok_r(file, "\n", &next);
-	while (line) {
-		addr_str = strsep(&line, ":");
-		if (!line) {
-			warning("error parsing print strings");
-			break;
-		}
-		item = malloc_or_die(sizeof(*item));
-		item->addr = strtoull(addr_str, NULL, 16);
-		/* fmt still has a space, skip it */
-		item->printk = strdup(line+1);
-		item->next = list;
-		list = item;
-		line = strtok_r(NULL, "\n", &next);
-		printk_count++;
-	}
-
-	printk_list = malloc_or_die(sizeof(*printk_list) * printk_count + 1);
-
-	i = 0;
-	while (list) {
-		printk_list[i].printk = list->printk;
-		printk_list[i].addr = list->addr;
-		i++;
-		item = list;
-		list = list->next;
-		free(item);
-	}
-
-	qsort(printk_list, printk_count, sizeof(*printk_list), printk_cmp);
-}
-
-void print_printk(void)
-{
-	int i;
-
-	for (i = 0; i < (int)printk_count; i++) {
-		printf("%016llx %s\n",
-		       printk_list[i].addr,
-		       printk_list[i].printk);
-	}
-}
-
-static struct event *alloc_event(void)
-{
-	struct event *event;
-
-	event = malloc_or_die(sizeof(*event));
-	memset(event, 0, sizeof(*event));
-
-	return event;
-}
-
-enum event_type {
-	EVENT_ERROR,
-	EVENT_NONE,
-	EVENT_SPACE,
-	EVENT_NEWLINE,
-	EVENT_OP,
-	EVENT_DELIM,
-	EVENT_ITEM,
-	EVENT_DQUOTE,
-	EVENT_SQUOTE,
-};
-
-static struct event *event_list;
-
-static void add_event(struct event *event)
-{
-	event->next = event_list;
-	event_list = event;
-}
-
-static int event_item_type(enum event_type type)
-{
-	switch (type) {
-	case EVENT_ITEM ... EVENT_SQUOTE:
-		return 1;
-	case EVENT_ERROR ... EVENT_DELIM:
-	default:
-		return 0;
-	}
-}
-
-static void free_arg(struct print_arg *arg)
-{
-	if (!arg)
-		return;
-
-	switch (arg->type) {
-	case PRINT_ATOM:
-		if (arg->atom.atom)
-			free(arg->atom.atom);
-		break;
-	case PRINT_NULL:
-	case PRINT_FIELD ... PRINT_OP:
-	default:
-		/* todo */
-		break;
-	}
-
-	free(arg);
-}
-
-static enum event_type get_type(int ch)
-{
-	if (ch == '\n')
-		return EVENT_NEWLINE;
-	if (isspace(ch))
-		return EVENT_SPACE;
-	if (isalnum(ch) || ch == '_')
-		return EVENT_ITEM;
-	if (ch == '\'')
-		return EVENT_SQUOTE;
-	if (ch == '"')
-		return EVENT_DQUOTE;
-	if (!isprint(ch))
-		return EVENT_NONE;
-	if (ch == '(' || ch == ')' || ch == ',')
-		return EVENT_DELIM;
-
-	return EVENT_OP;
-}
-
-static int __read_char(void)
-{
-	if (input_buf_ptr >= input_buf_siz)
-		return -1;
-
-	return input_buf[input_buf_ptr++];
-}
-
-static int __peek_char(void)
-{
-	if (input_buf_ptr >= input_buf_siz)
-		return -1;
-
-	return input_buf[input_buf_ptr];
-}
-
-static enum event_type __read_token(char **tok)
-{
-	char buf[BUFSIZ];
-	int ch, last_ch, quote_ch, next_ch;
-	int i = 0;
-	int tok_size = 0;
-	enum event_type type;
-
-	*tok = NULL;
-
-
-	ch = __read_char();
-	if (ch < 0)
-		return EVENT_NONE;
-
-	type = get_type(ch);
-	if (type == EVENT_NONE)
-		return type;
-
-	buf[i++] = ch;
-
-	switch (type) {
-	case EVENT_NEWLINE:
-	case EVENT_DELIM:
-		*tok = malloc_or_die(2);
-		(*tok)[0] = ch;
-		(*tok)[1] = 0;
-		return type;
-
-	case EVENT_OP:
-		switch (ch) {
-		case '-':
-			next_ch = __peek_char();
-			if (next_ch == '>') {
-				buf[i++] = __read_char();
-				break;
-			}
-			/* fall through */
-		case '+':
-		case '|':
-		case '&':
-		case '>':
-		case '<':
-			last_ch = ch;
-			ch = __peek_char();
-			if (ch != last_ch)
-				goto test_equal;
-			buf[i++] = __read_char();
-			switch (last_ch) {
-			case '>':
-			case '<':
-				goto test_equal;
-			default:
-				break;
-			}
-			break;
-		case '!':
-		case '=':
-			goto test_equal;
-		default: /* what should we do instead? */
-			break;
-		}
-		buf[i] = 0;
-		*tok = strdup(buf);
-		return type;
-
- test_equal:
-		ch = __peek_char();
-		if (ch == '=')
-			buf[i++] = __read_char();
-		break;
-
-	case EVENT_DQUOTE:
-	case EVENT_SQUOTE:
-		/* don't keep quotes */
-		i--;
-		quote_ch = ch;
-		last_ch = 0;
-		do {
-			if (i == (BUFSIZ - 1)) {
-				buf[i] = 0;
-				if (*tok) {
-					*tok = realloc(*tok, tok_size + BUFSIZ);
-					if (!*tok)
-						return EVENT_NONE;
-					strcat(*tok, buf);
-				} else
-					*tok = strdup(buf);
-
-				if (!*tok)
-					return EVENT_NONE;
-				tok_size += BUFSIZ;
-				i = 0;
-			}
-			last_ch = ch;
-			ch = __read_char();
-			buf[i++] = ch;
-			/* the '\' '\' will cancel itself */
-			if (ch == '\\' && last_ch == '\\')
-				last_ch = 0;
-		} while (ch != quote_ch || last_ch == '\\');
-		/* remove the last quote */
-		i--;
-		goto out;
-
-	case EVENT_ERROR ... EVENT_SPACE:
-	case EVENT_ITEM:
-	default:
-		break;
-	}
-
-	while (get_type(__peek_char()) == type) {
-		if (i == (BUFSIZ - 1)) {
-			buf[i] = 0;
-			if (*tok) {
-				*tok = realloc(*tok, tok_size + BUFSIZ);
-				if (!*tok)
-					return EVENT_NONE;
-				strcat(*tok, buf);
-			} else
-				*tok = strdup(buf);
-
-			if (!*tok)
-				return EVENT_NONE;
-			tok_size += BUFSIZ;
-			i = 0;
-		}
-		ch = __read_char();
-		buf[i++] = ch;
-	}
-
- out:
-	buf[i] = 0;
-	if (*tok) {
-		*tok = realloc(*tok, tok_size + i);
-		if (!*tok)
-			return EVENT_NONE;
-		strcat(*tok, buf);
-	} else
-		*tok = strdup(buf);
-	if (!*tok)
-		return EVENT_NONE;
-
-	return type;
-}
-
-static void free_token(char *tok)
-{
-	if (tok)
-		free(tok);
-}
-
-static enum event_type read_token(char **tok)
-{
-	enum event_type type;
-
-	for (;;) {
-		type = __read_token(tok);
-		if (type != EVENT_SPACE)
-			return type;
-
-		free_token(*tok);
-	}
-
-	/* not reached */
-	return EVENT_NONE;
-}
-
-/* no newline */
-static enum event_type read_token_item(char **tok)
-{
-	enum event_type type;
-
-	for (;;) {
-		type = __read_token(tok);
-		if (type != EVENT_SPACE && type != EVENT_NEWLINE)
-			return type;
-
-		free_token(*tok);
-	}
-
-	/* not reached */
-	return EVENT_NONE;
-}
-
-static int test_type(enum event_type type, enum event_type expect)
-{
-	if (type != expect) {
-		warning("Error: expected type %d but read %d",
-		    expect, type);
-		return -1;
-	}
-	return 0;
-}
-
-static int __test_type_token(enum event_type type, char *token,
-			     enum event_type expect, const char *expect_tok,
-			     bool warn)
-{
-	if (type != expect) {
-		if (warn)
-			warning("Error: expected type %d but read %d",
-				expect, type);
-		return -1;
-	}
-
-	if (strcmp(token, expect_tok) != 0) {
-		if (warn)
-			warning("Error: expected '%s' but read '%s'",
-				expect_tok, token);
-		return -1;
-	}
-	return 0;
-}
-
-static int test_type_token(enum event_type type, char *token,
-			   enum event_type expect, const char *expect_tok)
-{
-	return __test_type_token(type, token, expect, expect_tok, true);
-}
-
-static int __read_expect_type(enum event_type expect, char **tok, int newline_ok)
-{
-	enum event_type type;
-
-	if (newline_ok)
-		type = read_token(tok);
-	else
-		type = read_token_item(tok);
-	return test_type(type, expect);
-}
-
-static int read_expect_type(enum event_type expect, char **tok)
-{
-	return __read_expect_type(expect, tok, 1);
-}
-
-static int __read_expected(enum event_type expect, const char *str,
-			   int newline_ok, bool warn)
-{
-	enum event_type type;
-	char *token;
-	int ret;
-
-	if (newline_ok)
-		type = read_token(&token);
-	else
-		type = read_token_item(&token);
-
-	ret = __test_type_token(type, token, expect, str, warn);
-
-	free_token(token);
-
-	return ret;
-}
-
-static int read_expected(enum event_type expect, const char *str)
-{
-	return __read_expected(expect, str, 1, true);
-}
-
-static int read_expected_item(enum event_type expect, const char *str)
-{
-	return __read_expected(expect, str, 0, true);
-}
-
-static char *event_read_name(void)
-{
-	char *token;
-
-	if (read_expected(EVENT_ITEM, "name") < 0)
-		return NULL;
-
-	if (read_expected(EVENT_OP, ":") < 0)
-		return NULL;
-
-	if (read_expect_type(EVENT_ITEM, &token) < 0)
-		goto fail;
-
-	return token;
-
- fail:
-	free_token(token);
-	return NULL;
-}
-
-static int event_read_id(void)
-{
-	char *token;
-	int id = -1;
-
-	if (read_expected_item(EVENT_ITEM, "ID") < 0)
-		return -1;
-
-	if (read_expected(EVENT_OP, ":") < 0)
-		return -1;
-
-	if (read_expect_type(EVENT_ITEM, &token) < 0)
-		goto free;
-
-	id = strtoul(token, NULL, 0);
-
- free:
-	free_token(token);
-	return id;
-}
-
-static int field_is_string(struct format_field *field)
-{
-	if ((field->flags & FIELD_IS_ARRAY) &&
-	    (!strstr(field->type, "char") || !strstr(field->type, "u8") ||
-	     !strstr(field->type, "s8")))
-		return 1;
-
-	return 0;
-}
-
-static int field_is_dynamic(struct format_field *field)
-{
-	if (!strncmp(field->type, "__data_loc", 10))
-		return 1;
-
-	return 0;
-}
-
-static int event_read_fields(struct event *event, struct format_field **fields)
-{
-	struct format_field *field = NULL;
-	enum event_type type;
-	char *token;
-	char *last_token;
-	int count = 0;
-
-	do {
-		type = read_token(&token);
-		if (type == EVENT_NEWLINE) {
-			free_token(token);
-			return count;
-		}
-
-		count++;
-
-		if (test_type_token(type, token, EVENT_ITEM, "field"))
-			goto fail;
-		free_token(token);
-
-		type = read_token(&token);
-		/*
-		 * The ftrace fields may still use the "special" name.
-		 * Just ignore it.
-		 */
-		if (event->flags & EVENT_FL_ISFTRACE &&
-		    type == EVENT_ITEM && strcmp(token, "special") == 0) {
-			free_token(token);
-			type = read_token(&token);
-		}
-
-		if (test_type_token(type, token, EVENT_OP, ":") < 0)
-			return -1;
-
-		if (read_expect_type(EVENT_ITEM, &token) < 0)
-			goto fail;
-
-		last_token = token;
-
-		field = malloc_or_die(sizeof(*field));
-		memset(field, 0, sizeof(*field));
-
-		/* read the rest of the type */
-		for (;;) {
-			type = read_token(&token);
-			if (type == EVENT_ITEM ||
-			    (type == EVENT_OP && strcmp(token, "*") == 0) ||
-			    /*
-			     * Some of the ftrace fields are broken and have
-			     * an illegal "." in them.
-			     */
-			    (event->flags & EVENT_FL_ISFTRACE &&
-			     type == EVENT_OP && strcmp(token, ".") == 0)) {
-
-				if (strcmp(token, "*") == 0)
-					field->flags |= FIELD_IS_POINTER;
-
-				if (field->type) {
-					field->type = realloc(field->type,
-							      strlen(field->type) +
-							      strlen(last_token) + 2);
-					strcat(field->type, " ");
-					strcat(field->type, last_token);
-				} else
-					field->type = last_token;
-				last_token = token;
-				continue;
-			}
-
-			break;
-		}
-
-		if (!field->type) {
-			die("no type found");
-			goto fail;
-		}
-		field->name = last_token;
-
-		if (test_type(type, EVENT_OP))
-			goto fail;
-
-		if (strcmp(token, "[") == 0) {
-			enum event_type last_type = type;
-			char *brackets = token;
-			int len;
-
-			field->flags |= FIELD_IS_ARRAY;
-
-			type = read_token(&token);
-		        while (strcmp(token, "]") != 0) {
-				if (last_type == EVENT_ITEM &&
-				    type == EVENT_ITEM)
-					len = 2;
-				else
-					len = 1;
-				last_type = type;
-
-				brackets = realloc(brackets,
-						   strlen(brackets) +
-						   strlen(token) + len);
-				if (len == 2)
-					strcat(brackets, " ");
-				strcat(brackets, token);
-				free_token(token);
-				type = read_token(&token);
-				if (type == EVENT_NONE) {
-					die("failed to find token");
-					goto fail;
-				}
-			}
-
-			free_token(token);
-
-			brackets = realloc(brackets, strlen(brackets) + 2);
-			strcat(brackets, "]");
-
-			/* add brackets to type */
-
-			type = read_token(&token);
-			/*
-			 * If the next token is not an OP, then it is of
-			 * the format: type [] item;
-			 */
-			if (type == EVENT_ITEM) {
-				field->type = realloc(field->type,
-						      strlen(field->type) +
-						      strlen(field->name) +
-						      strlen(brackets) + 2);
-				strcat(field->type, " ");
-				strcat(field->type, field->name);
-				free_token(field->name);
-				strcat(field->type, brackets);
-				field->name = token;
-				type = read_token(&token);
-			} else {
-				field->type = realloc(field->type,
-						      strlen(field->type) +
-						      strlen(brackets) + 1);
-				strcat(field->type, brackets);
-			}
-			free(brackets);
-		}
-
-		if (field_is_string(field)) {
-			field->flags |= FIELD_IS_STRING;
-			if (field_is_dynamic(field))
-				field->flags |= FIELD_IS_DYNAMIC;
-		}
-
-		if (test_type_token(type, token,  EVENT_OP, ";"))
-			goto fail;
-		free_token(token);
-
-		if (read_expected(EVENT_ITEM, "offset") < 0)
-			goto fail_expect;
-
-		if (read_expected(EVENT_OP, ":") < 0)
-			goto fail_expect;
-
-		if (read_expect_type(EVENT_ITEM, &token))
-			goto fail;
-		field->offset = strtoul(token, NULL, 0);
-		free_token(token);
-
-		if (read_expected(EVENT_OP, ";") < 0)
-			goto fail_expect;
-
-		if (read_expected(EVENT_ITEM, "size") < 0)
-			goto fail_expect;
-
-		if (read_expected(EVENT_OP, ":") < 0)
-			goto fail_expect;
-
-		if (read_expect_type(EVENT_ITEM, &token))
-			goto fail;
-		field->size = strtoul(token, NULL, 0);
-		free_token(token);
-
-		if (read_expected(EVENT_OP, ";") < 0)
-			goto fail_expect;
-
-		type = read_token(&token);
-		if (type != EVENT_NEWLINE) {
-			/* newer versions of the kernel have a "signed" type */
-			if (test_type_token(type, token, EVENT_ITEM, "signed"))
-				goto fail;
-
-			free_token(token);
-
-			if (read_expected(EVENT_OP, ":") < 0)
-				goto fail_expect;
-
-			if (read_expect_type(EVENT_ITEM, &token))
-				goto fail;
-
-			if (strtoul(token, NULL, 0))
-				field->flags |= FIELD_IS_SIGNED;
-
-			free_token(token);
-			if (read_expected(EVENT_OP, ";") < 0)
-				goto fail_expect;
-
-			if (read_expect_type(EVENT_NEWLINE, &token))
-				goto fail;
-		}
-
-		free_token(token);
-
-		*fields = field;
-		fields = &field->next;
-
-	} while (1);
-
-	return 0;
-
-fail:
-	free_token(token);
-fail_expect:
-	if (field)
-		free(field);
-	return -1;
-}
-
-static int event_read_format(struct event *event)
-{
-	char *token;
-	int ret;
-
-	if (read_expected_item(EVENT_ITEM, "format") < 0)
-		return -1;
-
-	if (read_expected(EVENT_OP, ":") < 0)
-		return -1;
-
-	if (read_expect_type(EVENT_NEWLINE, &token))
-		goto fail;
-	free_token(token);
-
-	ret = event_read_fields(event, &event->format.common_fields);
-	if (ret < 0)
-		return ret;
-	event->format.nr_common = ret;
-
-	ret = event_read_fields(event, &event->format.fields);
-	if (ret < 0)
-		return ret;
-	event->format.nr_fields = ret;
-
-	return 0;
-
- fail:
-	free_token(token);
-	return -1;
-}
-
-enum event_type
-process_arg_token(struct event *event, struct print_arg *arg,
-		  char **tok, enum event_type type);
-
-static enum event_type
-process_arg(struct event *event, struct print_arg *arg, char **tok)
-{
-	enum event_type type;
-	char *token;
-
-	type = read_token(&token);
-	*tok = token;
-
-	return process_arg_token(event, arg, tok, type);
-}
-
-static enum event_type
-process_cond(struct event *event, struct print_arg *top, char **tok)
-{
-	struct print_arg *arg, *left, *right;
-	enum event_type type;
-	char *token = NULL;
-
-	arg = malloc_or_die(sizeof(*arg));
-	memset(arg, 0, sizeof(*arg));
-
-	left = malloc_or_die(sizeof(*left));
-
-	right = malloc_or_die(sizeof(*right));
-
-	arg->type = PRINT_OP;
-	arg->op.left = left;
-	arg->op.right = right;
-
-	*tok = NULL;
-	type = process_arg(event, left, &token);
-	if (test_type_token(type, token, EVENT_OP, ":"))
-		goto out_free;
-
-	arg->op.op = token;
-
-	type = process_arg(event, right, &token);
-
-	top->op.right = arg;
-
-	*tok = token;
-	return type;
-
-out_free:
-	free_token(*tok);
-	free(right);
-	free(left);
-	free_arg(arg);
-	return EVENT_ERROR;
-}
-
-static enum event_type
-process_array(struct event *event, struct print_arg *top, char **tok)
-{
-	struct print_arg *arg;
-	enum event_type type;
-	char *token = NULL;
-
-	arg = malloc_or_die(sizeof(*arg));
-	memset(arg, 0, sizeof(*arg));
-
-	*tok = NULL;
-	type = process_arg(event, arg, &token);
-	if (test_type_token(type, token, EVENT_OP, "]"))
-		goto out_free;
-
-	top->op.right = arg;
-
-	free_token(token);
-	type = read_token_item(&token);
-	*tok = token;
-
-	return type;
-
-out_free:
-	free_token(*tok);
-	free_arg(arg);
-	return EVENT_ERROR;
-}
-
-static int get_op_prio(char *op)
-{
-	if (!op[1]) {
-		switch (op[0]) {
-		case '*':
-		case '/':
-		case '%':
-			return 6;
-		case '+':
-		case '-':
-			return 7;
-			/* '>>' and '<<' are 8 */
-		case '<':
-		case '>':
-			return 9;
-			/* '==' and '!=' are 10 */
-		case '&':
-			return 11;
-		case '^':
-			return 12;
-		case '|':
-			return 13;
-		case '?':
-			return 16;
-		default:
-			die("unknown op '%c'", op[0]);
-			return -1;
-		}
-	} else {
-		if (strcmp(op, "++") == 0 ||
-		    strcmp(op, "--") == 0) {
-			return 3;
-		} else if (strcmp(op, ">>") == 0 ||
-			   strcmp(op, "<<") == 0) {
-			return 8;
-		} else if (strcmp(op, ">=") == 0 ||
-			   strcmp(op, "<=") == 0) {
-			return 9;
-		} else if (strcmp(op, "==") == 0 ||
-			   strcmp(op, "!=") == 0) {
-			return 10;
-		} else if (strcmp(op, "&&") == 0) {
-			return 14;
-		} else if (strcmp(op, "||") == 0) {
-			return 15;
-		} else {
-			die("unknown op '%s'", op);
-			return -1;
-		}
-	}
-}
-
-static void set_op_prio(struct print_arg *arg)
-{
-
-	/* single ops are the greatest */
-	if (!arg->op.left || arg->op.left->type == PRINT_NULL) {
-		arg->op.prio = 0;
-		return;
-	}
-
-	arg->op.prio = get_op_prio(arg->op.op);
-}
-
-static enum event_type
-process_op(struct event *event, struct print_arg *arg, char **tok)
-{
-	struct print_arg *left, *right = NULL;
-	enum event_type type;
-	char *token;
-
-	/* the op is passed in via tok */
-	token = *tok;
-
-	if (arg->type == PRINT_OP && !arg->op.left) {
-		/* handle single op */
-		if (token[1]) {
-			die("bad op token %s", token);
-			return EVENT_ERROR;
-		}
-		switch (token[0]) {
-		case '!':
-		case '+':
-		case '-':
-			break;
-		default:
-			die("bad op token %s", token);
-			return EVENT_ERROR;
-		}
-
-		/* make an empty left */
-		left = malloc_or_die(sizeof(*left));
-		left->type = PRINT_NULL;
-		arg->op.left = left;
-
-		right = malloc_or_die(sizeof(*right));
-		arg->op.right = right;
-
-		type = process_arg(event, right, tok);
-
-	} else if (strcmp(token, "?") == 0) {
-
-		left = malloc_or_die(sizeof(*left));
-		/* copy the top arg to the left */
-		*left = *arg;
-
-		arg->type = PRINT_OP;
-		arg->op.op = token;
-		arg->op.left = left;
-		arg->op.prio = 0;
-
-		type = process_cond(event, arg, tok);
-
-	} else if (strcmp(token, ">>") == 0 ||
-		   strcmp(token, "<<") == 0 ||
-		   strcmp(token, "&") == 0 ||
-		   strcmp(token, "|") == 0 ||
-		   strcmp(token, "&&") == 0 ||
-		   strcmp(token, "||") == 0 ||
-		   strcmp(token, "-") == 0 ||
-		   strcmp(token, "+") == 0 ||
-		   strcmp(token, "*") == 0 ||
-		   strcmp(token, "^") == 0 ||
-		   strcmp(token, "/") == 0 ||
-		   strcmp(token, "<") == 0 ||
-		   strcmp(token, ">") == 0 ||
-		   strcmp(token, "==") == 0 ||
-		   strcmp(token, "!=") == 0) {
-
-		left = malloc_or_die(sizeof(*left));
-
-		/* copy the top arg to the left */
-		*left = *arg;
-
-		arg->type = PRINT_OP;
-		arg->op.op = token;
-		arg->op.left = left;
-
-		set_op_prio(arg);
-
-		right = malloc_or_die(sizeof(*right));
-
-		type = read_token_item(&token);
-		*tok = token;
-
-		/* could just be a type pointer */
-		if ((strcmp(arg->op.op, "*") == 0) &&
-		    type == EVENT_DELIM && (strcmp(token, ")") == 0)) {
-			if (left->type != PRINT_ATOM)
-				die("bad pointer type");
-			left->atom.atom = realloc(left->atom.atom,
-					    sizeof(left->atom.atom) + 3);
-			strcat(left->atom.atom, " *");
-			*arg = *left;
-			free(arg);
-
-			return type;
-		}
-
-		type = process_arg_token(event, right, tok, type);
-
-		arg->op.right = right;
-
-	} else if (strcmp(token, "[") == 0) {
-
-		left = malloc_or_die(sizeof(*left));
-		*left = *arg;
-
-		arg->type = PRINT_OP;
-		arg->op.op = token;
-		arg->op.left = left;
-
-		arg->op.prio = 0;
-		type = process_array(event, arg, tok);
-
-	} else {
-		warning("unknown op '%s'", token);
-		event->flags |= EVENT_FL_FAILED;
-		/* the arg is now the left side */
-		return EVENT_NONE;
-	}
-
-	if (type == EVENT_OP) {
-		int prio;
-
-		/* higher prios need to be closer to the root */
-		prio = get_op_prio(*tok);
-
-		if (prio > arg->op.prio)
-			return process_op(event, arg, tok);
-
-		return process_op(event, right, tok);
-	}
-
-	return type;
-}
-
-static enum event_type
-process_entry(struct event *event __unused, struct print_arg *arg,
-	      char **tok)
-{
-	enum event_type type;
-	char *field;
-	char *token;
-
-	if (read_expected(EVENT_OP, "->") < 0)
-		return EVENT_ERROR;
-
-	if (read_expect_type(EVENT_ITEM, &token) < 0)
-		goto fail;
-	field = token;
-
-	arg->type = PRINT_FIELD;
-	arg->field.name = field;
-
-	if (is_flag_field) {
-		arg->field.field = find_any_field(event, arg->field.name);
-		arg->field.field->flags |= FIELD_IS_FLAG;
-		is_flag_field = 0;
-	} else if (is_symbolic_field) {
-		arg->field.field = find_any_field(event, arg->field.name);
-		arg->field.field->flags |= FIELD_IS_SYMBOLIC;
-		is_symbolic_field = 0;
-	}
-
-	type = read_token(&token);
-	*tok = token;
-
-	return type;
-
-fail:
-	free_token(token);
-	return EVENT_ERROR;
-}
-
-static char *arg_eval (struct print_arg *arg);
-
-static long long arg_num_eval(struct print_arg *arg)
-{
-	long long left, right;
-	long long val = 0;
-
-	switch (arg->type) {
-	case PRINT_ATOM:
-		val = strtoll(arg->atom.atom, NULL, 0);
-		break;
-	case PRINT_TYPE:
-		val = arg_num_eval(arg->typecast.item);
-		break;
-	case PRINT_OP:
-		switch (arg->op.op[0]) {
-		case '|':
-			left = arg_num_eval(arg->op.left);
-			right = arg_num_eval(arg->op.right);
-			if (arg->op.op[1])
-				val = left || right;
-			else
-				val = left | right;
-			break;
-		case '&':
-			left = arg_num_eval(arg->op.left);
-			right = arg_num_eval(arg->op.right);
-			if (arg->op.op[1])
-				val = left && right;
-			else
-				val = left & right;
-			break;
-		case '<':
-			left = arg_num_eval(arg->op.left);
-			right = arg_num_eval(arg->op.right);
-			switch (arg->op.op[1]) {
-			case 0:
-				val = left < right;
-				break;
-			case '<':
-				val = left << right;
-				break;
-			case '=':
-				val = left <= right;
-				break;
-			default:
-				die("unknown op '%s'", arg->op.op);
-			}
-			break;
-		case '>':
-			left = arg_num_eval(arg->op.left);
-			right = arg_num_eval(arg->op.right);
-			switch (arg->op.op[1]) {
-			case 0:
-				val = left > right;
-				break;
-			case '>':
-				val = left >> right;
-				break;
-			case '=':
-				val = left >= right;
-				break;
-			default:
-				die("unknown op '%s'", arg->op.op);
-			}
-			break;
-		case '=':
-			left = arg_num_eval(arg->op.left);
-			right = arg_num_eval(arg->op.right);
-
-			if (arg->op.op[1] != '=')
-				die("unknown op '%s'", arg->op.op);
-
-			val = left == right;
-			break;
-		case '!':
-			left = arg_num_eval(arg->op.left);
-			right = arg_num_eval(arg->op.right);
-
-			switch (arg->op.op[1]) {
-			case '=':
-				val = left != right;
-				break;
-			default:
-				die("unknown op '%s'", arg->op.op);
-			}
-			break;
-		case '+':
-			left = arg_num_eval(arg->op.left);
-			right = arg_num_eval(arg->op.right);
-			val = left + right;
-			break;
-		default:
-			die("unknown op '%s'", arg->op.op);
-		}
-		break;
-
-	case PRINT_NULL:
-	case PRINT_FIELD ... PRINT_SYMBOL:
-	case PRINT_STRING:
-	default:
-		die("invalid eval type %d", arg->type);
-
-	}
-	return val;
-}
-
-static char *arg_eval (struct print_arg *arg)
-{
-	long long val;
-	static char buf[20];
-
-	switch (arg->type) {
-	case PRINT_ATOM:
-		return arg->atom.atom;
-	case PRINT_TYPE:
-		return arg_eval(arg->typecast.item);
-	case PRINT_OP:
-		val = arg_num_eval(arg);
-		sprintf(buf, "%lld", val);
-		return buf;
-
-	case PRINT_NULL:
-	case PRINT_FIELD ... PRINT_SYMBOL:
-	case PRINT_STRING:
-	default:
-		die("invalid eval type %d", arg->type);
-		break;
-	}
-
-	return NULL;
-}
-
-static enum event_type
-process_fields(struct event *event, struct print_flag_sym **list, char **tok)
-{
-	enum event_type type;
-	struct print_arg *arg = NULL;
-	struct print_flag_sym *field;
-	char *token = NULL;
-	char *value;
-
-	do {
-		free_token(token);
-		type = read_token_item(&token);
-		if (test_type_token(type, token, EVENT_OP, "{"))
-			break;
-
-		arg = malloc_or_die(sizeof(*arg));
-
-		free_token(token);
-		type = process_arg(event, arg, &token);
-
-		if (type == EVENT_OP)
-			type = process_op(event, arg, &token);
-
-		if (type == EVENT_ERROR)
-			goto out_free;
-
-		if (test_type_token(type, token, EVENT_DELIM, ","))
-			goto out_free;
-
-		field = malloc_or_die(sizeof(*field));
-		memset(field, 0, sizeof(*field));
-
-		value = arg_eval(arg);
-		field->value = strdup(value);
-
-		free_token(token);
-		type = process_arg(event, arg, &token);
-		if (test_type_token(type, token, EVENT_OP, "}"))
-			goto out_free;
-
-		value = arg_eval(arg);
-		field->str = strdup(value);
-		free_arg(arg);
-		arg = NULL;
-
-		*list = field;
-		list = &field->next;
-
-		free_token(token);
-		type = read_token_item(&token);
-	} while (type == EVENT_DELIM && strcmp(token, ",") == 0);
-
-	*tok = token;
-	return type;
-
-out_free:
-	free_arg(arg);
-	free_token(token);
-
-	return EVENT_ERROR;
-}
-
-static enum event_type
-process_flags(struct event *event, struct print_arg *arg, char **tok)
-{
-	struct print_arg *field;
-	enum event_type type;
-	char *token;
-
-	memset(arg, 0, sizeof(*arg));
-	arg->type = PRINT_FLAGS;
-
-	if (read_expected_item(EVENT_DELIM, "(") < 0)
-		return EVENT_ERROR;
-
-	field = malloc_or_die(sizeof(*field));
-
-	type = process_arg(event, field, &token);
-	while (type == EVENT_OP)
-		type = process_op(event, field, &token);
-	if (test_type_token(type, token, EVENT_DELIM, ","))
-		goto out_free;
-
-	arg->flags.field = field;
-
-	type = read_token_item(&token);
-	if (event_item_type(type)) {
-		arg->flags.delim = token;
-		type = read_token_item(&token);
-	}
-
-	if (test_type_token(type, token, EVENT_DELIM, ","))
-		goto out_free;
-
-	type = process_fields(event, &arg->flags.flags, &token);
-	if (test_type_token(type, token, EVENT_DELIM, ")"))
-		goto out_free;
-
-	free_token(token);
-	type = read_token_item(tok);
-	return type;
-
-out_free:
-	free_token(token);
-	return EVENT_ERROR;
-}
-
-static enum event_type
-process_symbols(struct event *event, struct print_arg *arg, char **tok)
-{
-	struct print_arg *field;
-	enum event_type type;
-	char *token;
-
-	memset(arg, 0, sizeof(*arg));
-	arg->type = PRINT_SYMBOL;
-
-	if (read_expected_item(EVENT_DELIM, "(") < 0)
-		return EVENT_ERROR;
-
-	field = malloc_or_die(sizeof(*field));
-
-	type = process_arg(event, field, &token);
-	if (test_type_token(type, token, EVENT_DELIM, ","))
-		goto out_free;
-
-	arg->symbol.field = field;
-
-	type = process_fields(event, &arg->symbol.symbols, &token);
-	if (test_type_token(type, token, EVENT_DELIM, ")"))
-		goto out_free;
-
-	free_token(token);
-	type = read_token_item(tok);
-	return type;
-
-out_free:
-	free_token(token);
-	return EVENT_ERROR;
-}
-
-static enum event_type
-process_paren(struct event *event, struct print_arg *arg, char **tok)
-{
-	struct print_arg *item_arg;
-	enum event_type type;
-	char *token;
-
-	type = process_arg(event, arg, &token);
-
-	if (type == EVENT_ERROR)
-		return EVENT_ERROR;
-
-	if (type == EVENT_OP)
-		type = process_op(event, arg, &token);
-
-	if (type == EVENT_ERROR)
-		return EVENT_ERROR;
-
-	if (test_type_token(type, token, EVENT_DELIM, ")")) {
-		free_token(token);
-		return EVENT_ERROR;
-	}
-
-	free_token(token);
-	type = read_token_item(&token);
-
-	/*
-	 * If the next token is an item or another open paren, then
-	 * this was a typecast.
-	 */
-	if (event_item_type(type) ||
-	    (type == EVENT_DELIM && strcmp(token, "(") == 0)) {
-
-		/* make this a typecast and contine */
-
-		/* prevous must be an atom */
-		if (arg->type != PRINT_ATOM)
-			die("previous needed to be PRINT_ATOM");
-
-		item_arg = malloc_or_die(sizeof(*item_arg));
-
-		arg->type = PRINT_TYPE;
-		arg->typecast.type = arg->atom.atom;
-		arg->typecast.item = item_arg;
-		type = process_arg_token(event, item_arg, &token, type);
-
-	}
-
-	*tok = token;
-	return type;
-}
-
-
-static enum event_type
-process_str(struct event *event __unused, struct print_arg *arg, char **tok)
-{
-	enum event_type type;
-	char *token;
-
-	if (read_expected(EVENT_DELIM, "(") < 0)
-		return EVENT_ERROR;
-
-	if (read_expect_type(EVENT_ITEM, &token) < 0)
-		goto fail;
-
-	arg->type = PRINT_STRING;
-	arg->string.string = token;
-	arg->string.offset = -1;
-
-	if (read_expected(EVENT_DELIM, ")") < 0)
-		return EVENT_ERROR;
-
-	type = read_token(&token);
-	*tok = token;
-
-	return type;
-fail:
-	free_token(token);
-	return EVENT_ERROR;
-}
-
-enum event_type
-process_arg_token(struct event *event, struct print_arg *arg,
-		  char **tok, enum event_type type)
-{
-	char *token;
-	char *atom;
-
-	token = *tok;
-
-	switch (type) {
-	case EVENT_ITEM:
-		if (strcmp(token, "REC") == 0) {
-			free_token(token);
-			type = process_entry(event, arg, &token);
-		} else if (strcmp(token, "__print_flags") == 0) {
-			free_token(token);
-			is_flag_field = 1;
-			type = process_flags(event, arg, &token);
-		} else if (strcmp(token, "__print_symbolic") == 0) {
-			free_token(token);
-			is_symbolic_field = 1;
-			type = process_symbols(event, arg, &token);
-		} else if (strcmp(token, "__get_str") == 0) {
-			free_token(token);
-			type = process_str(event, arg, &token);
-		} else {
-			atom = token;
-			/* test the next token */
-			type = read_token_item(&token);
-
-			/* atoms can be more than one token long */
-			while (type == EVENT_ITEM) {
-				atom = realloc(atom, strlen(atom) + strlen(token) + 2);
-				strcat(atom, " ");
-				strcat(atom, token);
-				free_token(token);
-				type = read_token_item(&token);
-			}
-
-			/* todo, test for function */
-
-			arg->type = PRINT_ATOM;
-			arg->atom.atom = atom;
-		}
-		break;
-	case EVENT_DQUOTE:
-	case EVENT_SQUOTE:
-		arg->type = PRINT_ATOM;
-		arg->atom.atom = token;
-		type = read_token_item(&token);
-		break;
-	case EVENT_DELIM:
-		if (strcmp(token, "(") == 0) {
-			free_token(token);
-			type = process_paren(event, arg, &token);
-			break;
-		}
-	case EVENT_OP:
-		/* handle single ops */
-		arg->type = PRINT_OP;
-		arg->op.op = token;
-		arg->op.left = NULL;
-		type = process_op(event, arg, &token);
-
-		break;
-
-	case EVENT_ERROR ... EVENT_NEWLINE:
-	default:
-		die("unexpected type %d", type);
-	}
-	*tok = token;
-
-	return type;
-}
-
-static int event_read_print_args(struct event *event, struct print_arg **list)
-{
-	enum event_type type = EVENT_ERROR;
-	struct print_arg *arg;
-	char *token;
-	int args = 0;
-
-	do {
-		if (type == EVENT_NEWLINE) {
-			free_token(token);
-			type = read_token_item(&token);
-			continue;
-		}
-
-		arg = malloc_or_die(sizeof(*arg));
-		memset(arg, 0, sizeof(*arg));
-
-		type = process_arg(event, arg, &token);
-
-		if (type == EVENT_ERROR) {
-			free_arg(arg);
-			return -1;
-		}
-
-		*list = arg;
-		args++;
-
-		if (type == EVENT_OP) {
-			type = process_op(event, arg, &token);
-			list = &arg->next;
-			continue;
-		}
-
-		if (type == EVENT_DELIM && strcmp(token, ",") == 0) {
-			free_token(token);
-			*list = arg;
-			list = &arg->next;
-			continue;
-		}
-		break;
-	} while (type != EVENT_NONE);
-
-	if (type != EVENT_NONE)
-		free_token(token);
-
-	return args;
-}
-
-static int event_read_print(struct event *event)
-{
-	enum event_type type;
-	char *token;
-	int ret;
-
-	if (read_expected_item(EVENT_ITEM, "print") < 0)
-		return -1;
-
-	if (read_expected(EVENT_ITEM, "fmt") < 0)
-		return -1;
-
-	if (read_expected(EVENT_OP, ":") < 0)
-		return -1;
-
-	if (read_expect_type(EVENT_DQUOTE, &token) < 0)
-		goto fail;
-
- concat:
-	event->print_fmt.format = token;
-	event->print_fmt.args = NULL;
-
-	/* ok to have no arg */
-	type = read_token_item(&token);
-
-	if (type == EVENT_NONE)
-		return 0;
-
-	/* Handle concatination of print lines */
-	if (type == EVENT_DQUOTE) {
-		char *cat;
-
-		cat = malloc_or_die(strlen(event->print_fmt.format) +
-				    strlen(token) + 1);
-		strcpy(cat, event->print_fmt.format);
-		strcat(cat, token);
-		free_token(token);
-		free_token(event->print_fmt.format);
-		event->print_fmt.format = NULL;
-		token = cat;
-		goto concat;
-	}
-
-	if (test_type_token(type, token, EVENT_DELIM, ","))
-		goto fail;
-
-	free_token(token);
-
-	ret = event_read_print_args(event, &event->print_fmt.args);
-	if (ret < 0)
-		return -1;
-
-	return ret;
-
- fail:
-	free_token(token);
-	return -1;
-}
-
-static struct format_field *
-find_common_field(struct event *event, const char *name)
-{
-	struct format_field *format;
-
-	for (format = event->format.common_fields;
-	     format; format = format->next) {
-		if (strcmp(format->name, name) == 0)
-			break;
-	}
-
-	return format;
-}
-
-static struct format_field *
-find_field(struct event *event, const char *name)
-{
-	struct format_field *format;
-
-	for (format = event->format.fields;
-	     format; format = format->next) {
-		if (strcmp(format->name, name) == 0)
-			break;
-	}
-
-	return format;
-}
-
-static struct format_field *
-find_any_field(struct event *event, const char *name)
-{
-	struct format_field *format;
-
-	format = find_common_field(event, name);
-	if (format)
-		return format;
-	return find_field(event, name);
-}
-
-unsigned long long read_size(void *ptr, int size)
-{
-	switch (size) {
-	case 1:
-		return *(unsigned char *)ptr;
-	case 2:
-		return data2host2(ptr);
-	case 4:
-		return data2host4(ptr);
-	case 8:
-		return data2host8(ptr);
-	default:
-		/* BUG! */
-		return 0;
-	}
-}
-
-unsigned long long
-raw_field_value(struct event *event, const char *name, void *data)
-{
-	struct format_field *field;
-
-	field = find_any_field(event, name);
-	if (!field)
-		return 0ULL;
-
-	return read_size(data + field->offset, field->size);
-}
-
-void *raw_field_ptr(struct event *event, const char *name, void *data)
-{
-	struct format_field *field;
-
-	field = find_any_field(event, name);
-	if (!field)
-		return NULL;
-
-	if (field->flags & FIELD_IS_DYNAMIC) {
-		int offset;
-
-		offset = *(int *)(data + field->offset);
-		offset &= 0xffff;
-
-		return data + offset;
-	}
-
-	return data + field->offset;
-}
-
-static int get_common_info(const char *type, int *offset, int *size)
-{
-	struct event *event;
-	struct format_field *field;
-
-	/*
-	 * All events should have the same common elements.
-	 * Pick any event to find where the type is;
-	 */
-	if (!event_list)
-		die("no event_list!");
-
-	event = event_list;
-	field = find_common_field(event, type);
-	if (!field)
-		die("field '%s' not found", type);
-
-	*offset = field->offset;
-	*size = field->size;
-
-	return 0;
-}
-
-static int __parse_common(void *data, int *size, int *offset,
-			  const char *name)
-{
-	int ret;
-
-	if (!*size) {
-		ret = get_common_info(name, offset, size);
-		if (ret < 0)
-			return ret;
-	}
-	return read_size(data + *offset, *size);
-}
-
-int trace_parse_common_type(void *data)
-{
-	static int type_offset;
-	static int type_size;
-
-	return __parse_common(data, &type_size, &type_offset,
-			      "common_type");
-}
-
-int trace_parse_common_pid(void *data)
-{
-	static int pid_offset;
-	static int pid_size;
-
-	return __parse_common(data, &pid_size, &pid_offset,
-			      "common_pid");
-}
-
-int parse_common_pc(void *data)
-{
-	static int pc_offset;
-	static int pc_size;
-
-	return __parse_common(data, &pc_size, &pc_offset,
-			      "common_preempt_count");
-}
-
-int parse_common_flags(void *data)
-{
-	static int flags_offset;
-	static int flags_size;
-
-	return __parse_common(data, &flags_size, &flags_offset,
-			      "common_flags");
-}
-
-int parse_common_lock_depth(void *data)
-{
-	static int ld_offset;
-	static int ld_size;
-	int ret;
-
-	ret = __parse_common(data, &ld_size, &ld_offset,
-			     "common_lock_depth");
-	if (ret < 0)
-		return -1;
-
-	return ret;
-}
-
-struct event *trace_find_event(int id)
-{
-	struct event *event;
-
-	for (event = event_list; event; event = event->next) {
-		if (event->id == id)
-			break;
-	}
-	return event;
-}
-
-struct event *trace_find_next_event(struct event *event)
-{
-	if (!event)
-		return event_list;
-
-	return event->next;
-}
-
-static unsigned long long eval_num_arg(void *data, int size,
-				   struct event *event, struct print_arg *arg)
-{
-	unsigned long long val = 0;
-	unsigned long long left, right;
-	struct print_arg *larg;
-
-	switch (arg->type) {
-	case PRINT_NULL:
-		/* ?? */
-		return 0;
-	case PRINT_ATOM:
-		return strtoull(arg->atom.atom, NULL, 0);
-	case PRINT_FIELD:
-		if (!arg->field.field) {
-			arg->field.field = find_any_field(event, arg->field.name);
-			if (!arg->field.field)
-				die("field %s not found", arg->field.name);
-		}
-		/* must be a number */
-		val = read_size(data + arg->field.field->offset,
-				arg->field.field->size);
-		break;
-	case PRINT_FLAGS:
-	case PRINT_SYMBOL:
-		break;
-	case PRINT_TYPE:
-		return eval_num_arg(data, size, event, arg->typecast.item);
-	case PRINT_STRING:
-		return 0;
-		break;
-	case PRINT_OP:
-		if (strcmp(arg->op.op, "[") == 0) {
-			/*
-			 * Arrays are special, since we don't want
-			 * to read the arg as is.
-			 */
-			if (arg->op.left->type != PRINT_FIELD)
-				goto default_op; /* oops, all bets off */
-			larg = arg->op.left;
-			if (!larg->field.field) {
-				larg->field.field =
-					find_any_field(event, larg->field.name);
-				if (!larg->field.field)
-					die("field %s not found", larg->field.name);
-			}
-			right = eval_num_arg(data, size, event, arg->op.right);
-			val = read_size(data + larg->field.field->offset +
-					right * long_size, long_size);
-			break;
-		}
- default_op:
-		left = eval_num_arg(data, size, event, arg->op.left);
-		right = eval_num_arg(data, size, event, arg->op.right);
-		switch (arg->op.op[0]) {
-		case '|':
-			if (arg->op.op[1])
-				val = left || right;
-			else
-				val = left | right;
-			break;
-		case '&':
-			if (arg->op.op[1])
-				val = left && right;
-			else
-				val = left & right;
-			break;
-		case '<':
-			switch (arg->op.op[1]) {
-			case 0:
-				val = left < right;
-				break;
-			case '<':
-				val = left << right;
-				break;
-			case '=':
-				val = left <= right;
-				break;
-			default:
-				die("unknown op '%s'", arg->op.op);
-			}
-			break;
-		case '>':
-			switch (arg->op.op[1]) {
-			case 0:
-				val = left > right;
-				break;
-			case '>':
-				val = left >> right;
-				break;
-			case '=':
-				val = left >= right;
-				break;
-			default:
-				die("unknown op '%s'", arg->op.op);
-			}
-			break;
-		case '=':
-			if (arg->op.op[1] != '=')
-				die("unknown op '%s'", arg->op.op);
-			val = left == right;
-			break;
-		case '-':
-			val = left - right;
-			break;
-		case '+':
-			val = left + right;
-			break;
-		default:
-			die("unknown op '%s'", arg->op.op);
-		}
-		break;
-	default: /* not sure what to do there */
-		return 0;
-	}
-	return val;
-}
-
-struct flag {
-	const char *name;
-	unsigned long long value;
-};
-
-static const struct flag flags[] = {
-	{ "HI_SOFTIRQ", 0 },
-	{ "TIMER_SOFTIRQ", 1 },
-	{ "NET_TX_SOFTIRQ", 2 },
-	{ "NET_RX_SOFTIRQ", 3 },
-	{ "BLOCK_SOFTIRQ", 4 },
-	{ "BLOCK_IOPOLL_SOFTIRQ", 5 },
-	{ "TASKLET_SOFTIRQ", 6 },
-	{ "SCHED_SOFTIRQ", 7 },
-	{ "HRTIMER_SOFTIRQ", 8 },
-	{ "RCU_SOFTIRQ", 9 },
-
-	{ "HRTIMER_NORESTART", 0 },
-	{ "HRTIMER_RESTART", 1 },
-};
-
-unsigned long long eval_flag(const char *flag)
-{
-	int i;
-
-	/*
-	 * Some flags in the format files do not get converted.
-	 * If the flag is not numeric, see if it is something that
-	 * we already know about.
-	 */
-	if (isdigit(flag[0]))
-		return strtoull(flag, NULL, 0);
-
-	for (i = 0; i < (int)(sizeof(flags)/sizeof(flags[0])); i++)
-		if (strcmp(flags[i].name, flag) == 0)
-			return flags[i].value;
-
-	return 0;
-}
-
-static void print_str_arg(void *data, int size,
-			  struct event *event, struct print_arg *arg)
-{
-	struct print_flag_sym *flag;
-	unsigned long long val, fval;
-	char *str;
-	int print;
-
-	switch (arg->type) {
-	case PRINT_NULL:
-		/* ?? */
-		return;
-	case PRINT_ATOM:
-		printf("%s", arg->atom.atom);
-		return;
-	case PRINT_FIELD:
-		if (!arg->field.field) {
-			arg->field.field = find_any_field(event, arg->field.name);
-			if (!arg->field.field)
-				die("field %s not found", arg->field.name);
-		}
-		str = malloc_or_die(arg->field.field->size + 1);
-		memcpy(str, data + arg->field.field->offset,
-		       arg->field.field->size);
-		str[arg->field.field->size] = 0;
-		printf("%s", str);
-		free(str);
-		break;
-	case PRINT_FLAGS:
-		val = eval_num_arg(data, size, event, arg->flags.field);
-		print = 0;
-		for (flag = arg->flags.flags; flag; flag = flag->next) {
-			fval = eval_flag(flag->value);
-			if (!val && !fval) {
-				printf("%s", flag->str);
-				break;
-			}
-			if (fval && (val & fval) == fval) {
-				if (print && arg->flags.delim)
-					printf("%s", arg->flags.delim);
-				printf("%s", flag->str);
-				print = 1;
-				val &= ~fval;
-			}
-		}
-		break;
-	case PRINT_SYMBOL:
-		val = eval_num_arg(data, size, event, arg->symbol.field);
-		for (flag = arg->symbol.symbols; flag; flag = flag->next) {
-			fval = eval_flag(flag->value);
-			if (val == fval) {
-				printf("%s", flag->str);
-				break;
-			}
-		}
-		break;
-
-	case PRINT_TYPE:
-		break;
-	case PRINT_STRING: {
-		int str_offset;
-
-		if (arg->string.offset == -1) {
-			struct format_field *f;
-
-			f = find_any_field(event, arg->string.string);
-			arg->string.offset = f->offset;
-		}
-		str_offset = *(int *)(data + arg->string.offset);
-		str_offset &= 0xffff;
-		printf("%s", ((char *)data) + str_offset);
-		break;
-	}
-	case PRINT_OP:
-		/*
-		 * The only op for string should be ? :
-		 */
-		if (arg->op.op[0] != '?')
-			return;
-		val = eval_num_arg(data, size, event, arg->op.left);
-		if (val)
-			print_str_arg(data, size, event, arg->op.right->op.left);
-		else
-			print_str_arg(data, size, event, arg->op.right->op.right);
-		break;
-	default:
-		/* well... */
-		break;
-	}
-}
-
-static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struct event *event)
-{
-	static struct format_field *field, *ip_field;
-	struct print_arg *args, *arg, **next;
-	unsigned long long ip, val;
-	char *ptr;
-	void *bptr;
-
-	if (!field) {
-		field = find_field(event, "buf");
-		if (!field)
-			die("can't find buffer field for binary printk");
-		ip_field = find_field(event, "ip");
-		if (!ip_field)
-			die("can't find ip field for binary printk");
-	}
-
-	ip = read_size(data + ip_field->offset, ip_field->size);
-
-	/*
-	 * The first arg is the IP pointer.
-	 */
-	args = malloc_or_die(sizeof(*args));
-	arg = args;
-	arg->next = NULL;
-	next = &arg->next;
-
-	arg->type = PRINT_ATOM;
-	arg->atom.atom = malloc_or_die(32);
-	sprintf(arg->atom.atom, "%lld", ip);
-
-	/* skip the first "%pf : " */
-	for (ptr = fmt + 6, bptr = data + field->offset;
-	     bptr < data + size && *ptr; ptr++) {
-		int ls = 0;
-
-		if (*ptr == '%') {
- process_again:
-			ptr++;
-			switch (*ptr) {
-			case '%':
-				break;
-			case 'l':
-				ls++;
-				goto process_again;
-			case 'L':
-				ls = 2;
-				goto process_again;
-			case '0' ... '9':
-				goto process_again;
-			case 'p':
-				ls = 1;
-				/* fall through */
-			case 'd':
-			case 'u':
-			case 'x':
-			case 'i':
-				/* the pointers are always 4 bytes aligned */
-				bptr = (void *)(((unsigned long)bptr + 3) &
-						~3);
-				switch (ls) {
-				case 0:
-				case 1:
-					ls = long_size;
-					break;
-				case 2:
-					ls = 8;
-				default:
-					break;
-				}
-				val = read_size(bptr, ls);
-				bptr += ls;
-				arg = malloc_or_die(sizeof(*arg));
-				arg->next = NULL;
-				arg->type = PRINT_ATOM;
-				arg->atom.atom = malloc_or_die(32);
-				sprintf(arg->atom.atom, "%lld", val);
-				*next = arg;
-				next = &arg->next;
-				break;
-			case 's':
-				arg = malloc_or_die(sizeof(*arg));
-				arg->next = NULL;
-				arg->type = PRINT_STRING;
-				arg->string.string = strdup(bptr);
-				bptr += strlen(bptr) + 1;
-				*next = arg;
-				next = &arg->next;
-			default:
-				break;
-			}
-		}
-	}
-
-	return args;
-}
-
-static void free_args(struct print_arg *args)
-{
-	struct print_arg *next;
-
-	while (args) {
-		next = args->next;
-
-		if (args->type == PRINT_ATOM)
-			free(args->atom.atom);
-		else
-			free(args->string.string);
-		free(args);
-		args = next;
-	}
-}
-
-static char *get_bprint_format(void *data, int size __unused, struct event *event)
-{
-	unsigned long long addr;
-	static struct format_field *field;
-	struct printk_map *printk;
-	char *format;
-	char *p;
-
-	if (!field) {
-		field = find_field(event, "fmt");
-		if (!field)
-			die("can't find format field for binary printk");
-		printf("field->offset = %d size=%d\n", field->offset, field->size);
-	}
-
-	addr = read_size(data + field->offset, field->size);
-
-	printk = find_printk(addr);
-	if (!printk) {
-		format = malloc_or_die(45);
-		sprintf(format, "%%pf : (NO FORMAT FOUND at %llx)\n",
-			addr);
-		return format;
-	}
-
-	p = printk->printk;
-	/* Remove any quotes. */
-	if (*p == '"')
-		p++;
-	format = malloc_or_die(strlen(p) + 10);
-	sprintf(format, "%s : %s", "%pf", p);
-	/* remove ending quotes and new line since we will add one too */
-	p = format + strlen(format) - 1;
-	if (*p == '"')
-		*p = 0;
-
-	p -= 2;
-	if (strcmp(p, "\\n") == 0)
-		*p = 0;
-
-	return format;
-}
-
-static void pretty_print(void *data, int size, struct event *event)
-{
-	struct print_fmt *print_fmt = &event->print_fmt;
-	struct print_arg *arg = print_fmt->args;
-	struct print_arg *args = NULL;
-	const char *ptr = print_fmt->format;
-	unsigned long long val;
-	struct func_map *func;
-	const char *saveptr;
-	char *bprint_fmt = NULL;
-	char format[32];
-	int show_func;
-	int len;
-	int ls;
-
-	if (event->flags & EVENT_FL_ISFUNC)
-		ptr = " %pF <-- %pF";
-
-	if (event->flags & EVENT_FL_ISBPRINT) {
-		bprint_fmt = get_bprint_format(data, size, event);
-		args = make_bprint_args(bprint_fmt, data, size, event);
-		arg = args;
-		ptr = bprint_fmt;
-	}
-
-	for (; *ptr; ptr++) {
-		ls = 0;
-		if (*ptr == '\\') {
-			ptr++;
-			switch (*ptr) {
-			case 'n':
-				printf("\n");
-				break;
-			case 't':
-				printf("\t");
-				break;
-			case 'r':
-				printf("\r");
-				break;
-			case '\\':
-				printf("\\");
-				break;
-			default:
-				printf("%c", *ptr);
-				break;
-			}
-
-		} else if (*ptr == '%') {
-			saveptr = ptr;
-			show_func = 0;
- cont_process:
-			ptr++;
-			switch (*ptr) {
-			case '%':
-				printf("%%");
-				break;
-			case 'l':
-				ls++;
-				goto cont_process;
-			case 'L':
-				ls = 2;
-				goto cont_process;
-			case 'z':
-			case 'Z':
-			case '0' ... '9':
-				goto cont_process;
-			case 'p':
-				if (long_size == 4)
-					ls = 1;
-				else
-					ls = 2;
-
-				if (*(ptr+1) == 'F' ||
-				    *(ptr+1) == 'f') {
-					ptr++;
-					show_func = *ptr;
-				}
-
-				/* fall through */
-			case 'd':
-			case 'i':
-			case 'x':
-			case 'X':
-			case 'u':
-				if (!arg)
-					die("no argument match");
-
-				len = ((unsigned long)ptr + 1) -
-					(unsigned long)saveptr;
-
-				/* should never happen */
-				if (len > 32)
-					die("bad format!");
-
-				memcpy(format, saveptr, len);
-				format[len] = 0;
-
-				val = eval_num_arg(data, size, event, arg);
-				arg = arg->next;
-
-				if (show_func) {
-					func = find_func(val);
-					if (func) {
-						printf("%s", func->func);
-						if (show_func == 'F')
-							printf("+0x%llx",
-							       val - func->addr);
-						break;
-					}
-				}
-				switch (ls) {
-				case 0:
-					printf(format, (int)val);
-					break;
-				case 1:
-					printf(format, (long)val);
-					break;
-				case 2:
-					printf(format, (long long)val);
-					break;
-				default:
-					die("bad count (%d)", ls);
-				}
-				break;
-			case 's':
-				if (!arg)
-					die("no matching argument");
-
-				print_str_arg(data, size, event, arg);
-				arg = arg->next;
-				break;
-			default:
-				printf(">%c<", *ptr);
-
-			}
-		} else
-			printf("%c", *ptr);
-	}
-
-	if (args) {
-		free_args(args);
-		free(bprint_fmt);
-	}
-}
-
-static inline int log10_cpu(int nb)
-{
-	if (nb / 100)
-		return 3;
-	if (nb / 10)
-		return 2;
-	return 1;
-}
-
-static void print_lat_fmt(void *data, int size __unused)
-{
-	unsigned int lat_flags;
-	unsigned int pc;
-	int lock_depth;
-	int hardirq;
-	int softirq;
-
-	lat_flags = parse_common_flags(data);
-	pc = parse_common_pc(data);
-	lock_depth = parse_common_lock_depth(data);
-
-	hardirq = lat_flags & TRACE_FLAG_HARDIRQ;
-	softirq = lat_flags & TRACE_FLAG_SOFTIRQ;
-
-	printf("%c%c%c",
-	       (lat_flags & TRACE_FLAG_IRQS_OFF) ? 'd' :
-	       (lat_flags & TRACE_FLAG_IRQS_NOSUPPORT) ?
-	       'X' : '.',
-	       (lat_flags & TRACE_FLAG_NEED_RESCHED) ?
-	       'N' : '.',
-	       (hardirq && softirq) ? 'H' :
-	       hardirq ? 'h' : softirq ? 's' : '.');
-
-	if (pc)
-		printf("%x", pc);
-	else
-		printf(".");
-
-	if (lock_depth < 0)
-		printf(". ");
-	else
-		printf("%d ", lock_depth);
-}
-
-#define TRACE_GRAPH_INDENT	2
-
-static struct record *
-get_return_for_leaf(int cpu, int cur_pid, unsigned long long cur_func,
-		    struct record *next)
-{
-	struct format_field *field;
-	struct event *event;
-	unsigned long val;
-	int type;
-	int pid;
-
-	type = trace_parse_common_type(next->data);
-	event = trace_find_event(type);
-	if (!event)
-		return NULL;
-
-	if (!(event->flags & EVENT_FL_ISFUNCRET))
-		return NULL;
-
-	pid = trace_parse_common_pid(next->data);
-	field = find_field(event, "func");
-	if (!field)
-		die("function return does not have field func");
-
-	val = read_size(next->data + field->offset, field->size);
-
-	if (cur_pid != pid || cur_func != val)
-		return NULL;
-
-	/* this is a leaf, now advance the iterator */
-	return trace_read_data(cpu);
-}
-
-/* Signal a overhead of time execution to the output */
-static void print_graph_overhead(unsigned long long duration)
-{
-	/* Non nested entry or return */
-	if (duration == ~0ULL)
-		return (void)printf("  ");
-
-	/* Duration exceeded 100 msecs */
-	if (duration > 100000ULL)
-		return (void)printf("! ");
-
-	/* Duration exceeded 10 msecs */
-	if (duration > 10000ULL)
-		return (void)printf("+ ");
-
-	printf("  ");
-}
-
-static void print_graph_duration(unsigned long long duration)
-{
-	unsigned long usecs = duration / 1000;
-	unsigned long nsecs_rem = duration % 1000;
-	/* log10(ULONG_MAX) + '\0' */
-	char msecs_str[21];
-	char nsecs_str[5];
-	int len;
-	int i;
-
-	sprintf(msecs_str, "%lu", usecs);
-
-	/* Print msecs */
-	len = printf("%lu", usecs);
-
-	/* Print nsecs (we don't want to exceed 7 numbers) */
-	if (len < 7) {
-		snprintf(nsecs_str, 8 - len, "%03lu", nsecs_rem);
-		len += printf(".%s", nsecs_str);
-	}
-
-	printf(" us ");
-
-	/* Print remaining spaces to fit the row's width */
-	for (i = len; i < 7; i++)
-		printf(" ");
-
-	printf("|  ");
-}
-
-static void
-print_graph_entry_leaf(struct event *event, void *data, struct record *ret_rec)
-{
-	unsigned long long rettime, calltime;
-	unsigned long long duration, depth;
-	unsigned long long val;
-	struct format_field *field;
-	struct func_map *func;
-	struct event *ret_event;
-	int type;
-	int i;
-
-	type = trace_parse_common_type(ret_rec->data);
-	ret_event = trace_find_event(type);
-
-	field = find_field(ret_event, "rettime");
-	if (!field)
-		die("can't find rettime in return graph");
-	rettime = read_size(ret_rec->data + field->offset, field->size);
-
-	field = find_field(ret_event, "calltime");
-	if (!field)
-		die("can't find rettime in return graph");
-	calltime = read_size(ret_rec->data + field->offset, field->size);
-
-	duration = rettime - calltime;
-
-	/* Overhead */
-	print_graph_overhead(duration);
-
-	/* Duration */
-	print_graph_duration(duration);
-
-	field = find_field(event, "depth");
-	if (!field)
-		die("can't find depth in entry graph");
-	depth = read_size(data + field->offset, field->size);
-
-	/* Function */
-	for (i = 0; i < (int)(depth * TRACE_GRAPH_INDENT); i++)
-		printf(" ");
-
-	field = find_field(event, "func");
-	if (!field)
-		die("can't find func in entry graph");
-	val = read_size(data + field->offset, field->size);
-	func = find_func(val);
-
-	if (func)
-		printf("%s();", func->func);
-	else
-		printf("%llx();", val);
-}
-
-static void print_graph_nested(struct event *event, void *data)
-{
-	struct format_field *field;
-	unsigned long long depth;
-	unsigned long long val;
-	struct func_map *func;
-	int i;
-
-	/* No overhead */
-	print_graph_overhead(-1);
-
-	/* No time */
-	printf("           |  ");
-
-	field = find_field(event, "depth");
-	if (!field)
-		die("can't find depth in entry graph");
-	depth = read_size(data + field->offset, field->size);
-
-	/* Function */
-	for (i = 0; i < (int)(depth * TRACE_GRAPH_INDENT); i++)
-		printf(" ");
-
-	field = find_field(event, "func");
-	if (!field)
-		die("can't find func in entry graph");
-	val = read_size(data + field->offset, field->size);
-	func = find_func(val);
-
-	if (func)
-		printf("%s() {", func->func);
-	else
-		printf("%llx() {", val);
-}
-
-static void
-pretty_print_func_ent(void *data, int size, struct event *event,
-		      int cpu, int pid)
-{
-	struct format_field *field;
-	struct record *rec;
-	void *copy_data;
-	unsigned long val;
-
-	if (latency_format) {
-		print_lat_fmt(data, size);
-		printf(" | ");
-	}
-
-	field = find_field(event, "func");
-	if (!field)
-		die("function entry does not have func field");
-
-	val = read_size(data + field->offset, field->size);
-
-	/*
-	 * peek_data may unmap the data pointer. Copy it first.
-	 */
-	copy_data = malloc_or_die(size);
-	memcpy(copy_data, data, size);
-	data = copy_data;
-
-	rec = trace_peek_data(cpu);
-	if (rec) {
-		rec = get_return_for_leaf(cpu, pid, val, rec);
-		if (rec) {
-			print_graph_entry_leaf(event, data, rec);
-			goto out_free;
-		}
-	}
-	print_graph_nested(event, data);
-out_free:
-	free(data);
-}
-
-static void
-pretty_print_func_ret(void *data, int size __unused, struct event *event)
-{
-	unsigned long long rettime, calltime;
-	unsigned long long duration, depth;
-	struct format_field *field;
-	int i;
-
-	if (latency_format) {
-		print_lat_fmt(data, size);
-		printf(" | ");
-	}
-
-	field = find_field(event, "rettime");
-	if (!field)
-		die("can't find rettime in return graph");
-	rettime = read_size(data + field->offset, field->size);
-
-	field = find_field(event, "calltime");
-	if (!field)
-		die("can't find calltime in return graph");
-	calltime = read_size(data + field->offset, field->size);
-
-	duration = rettime - calltime;
-
-	/* Overhead */
-	print_graph_overhead(duration);
-
-	/* Duration */
-	print_graph_duration(duration);
-
-	field = find_field(event, "depth");
-	if (!field)
-		die("can't find depth in entry graph");
-	depth = read_size(data + field->offset, field->size);
-
-	/* Function */
-	for (i = 0; i < (int)(depth * TRACE_GRAPH_INDENT); i++)
-		printf(" ");
-
-	printf("}");
-}
-
-static void
-pretty_print_func_graph(void *data, int size, struct event *event,
-			int cpu, int pid)
-{
-	if (event->flags & EVENT_FL_ISFUNCENT)
-		pretty_print_func_ent(data, size, event, cpu, pid);
-	else if (event->flags & EVENT_FL_ISFUNCRET)
-		pretty_print_func_ret(data, size, event);
-	printf("\n");
-}
-
-void print_trace_event(int cpu, void *data, int size)
-{
-	struct event *event;
-	int type;
-	int pid;
-
-	type = trace_parse_common_type(data);
-
-	event = trace_find_event(type);
-	if (!event) {
-		warning("ug! no event found for type %d", type);
-		return;
-	}
-
-	pid = trace_parse_common_pid(data);
-
-	if (event->flags & (EVENT_FL_ISFUNCENT | EVENT_FL_ISFUNCRET))
-		return pretty_print_func_graph(data, size, event, cpu, pid);
-
-	if (latency_format)
-		print_lat_fmt(data, size);
-
-	if (event->flags & EVENT_FL_FAILED) {
-		printf("EVENT '%s' FAILED TO PARSE\n",
-		       event->name);
-		return;
-	}
-
-	pretty_print(data, size, event);
-}
-
-static void print_fields(struct print_flag_sym *field)
-{
-	printf("{ %s, %s }", field->value, field->str);
-	if (field->next) {
-		printf(", ");
-		print_fields(field->next);
-	}
-}
-
-static void print_args(struct print_arg *args)
-{
-	int print_paren = 1;
-
-	switch (args->type) {
-	case PRINT_NULL:
-		printf("null");
-		break;
-	case PRINT_ATOM:
-		printf("%s", args->atom.atom);
-		break;
-	case PRINT_FIELD:
-		printf("REC->%s", args->field.name);
-		break;
-	case PRINT_FLAGS:
-		printf("__print_flags(");
-		print_args(args->flags.field);
-		printf(", %s, ", args->flags.delim);
-		print_fields(args->flags.flags);
-		printf(")");
-		break;
-	case PRINT_SYMBOL:
-		printf("__print_symbolic(");
-		print_args(args->symbol.field);
-		printf(", ");
-		print_fields(args->symbol.symbols);
-		printf(")");
-		break;
-	case PRINT_STRING:
-		printf("__get_str(%s)", args->string.string);
-		break;
-	case PRINT_TYPE:
-		printf("(%s)", args->typecast.type);
-		print_args(args->typecast.item);
-		break;
-	case PRINT_OP:
-		if (strcmp(args->op.op, ":") == 0)
-			print_paren = 0;
-		if (print_paren)
-			printf("(");
-		print_args(args->op.left);
-		printf(" %s ", args->op.op);
-		print_args(args->op.right);
-		if (print_paren)
-			printf(")");
-		break;
-	default:
-		/* we should warn... */
-		return;
-	}
-	if (args->next) {
-		printf("\n");
-		print_args(args->next);
-	}
-}
-
-int parse_ftrace_file(char *buf, unsigned long size)
-{
-	struct format_field *field;
-	struct print_arg *arg, **list;
-	struct event *event;
-	int ret;
-
-	init_input_buf(buf, size);
-
-	event = alloc_event();
-	if (!event)
-		return -ENOMEM;
-
-	event->flags |= EVENT_FL_ISFTRACE;
-
-	event->name = event_read_name();
-	if (!event->name)
-		die("failed to read ftrace event name");
-
-	if (strcmp(event->name, "function") == 0)
-		event->flags |= EVENT_FL_ISFUNC;
-
-	else if (strcmp(event->name, "funcgraph_entry") == 0)
-		event->flags |= EVENT_FL_ISFUNCENT;
-
-	else if (strcmp(event->name, "funcgraph_exit") == 0)
-		event->flags |= EVENT_FL_ISFUNCRET;
-
-	else if (strcmp(event->name, "bprint") == 0)
-		event->flags |= EVENT_FL_ISBPRINT;
-
-	event->id = event_read_id();
-	if (event->id < 0)
-		die("failed to read ftrace event id");
-
-	add_event(event);
-
-	ret = event_read_format(event);
-	if (ret < 0)
-		die("failed to read ftrace event format");
-
-	ret = event_read_print(event);
-	if (ret < 0)
-		die("failed to read ftrace event print fmt");
-
-	/* New ftrace handles args */
-	if (ret > 0)
-		return 0;
-	/*
-	 * The arguments for ftrace files are parsed by the fields.
-	 * Set up the fields as their arguments.
-	 */
-	list = &event->print_fmt.args;
-	for (field = event->format.fields; field; field = field->next) {
-		arg = malloc_or_die(sizeof(*arg));
-		memset(arg, 0, sizeof(*arg));
-		*list = arg;
-		list = &arg->next;
-		arg->type = PRINT_FIELD;
-		arg->field.name = field->name;
-		arg->field.field = field;
-	}
-	return 0;
-}
-
-int parse_event_file(char *buf, unsigned long size, char *sys)
-{
-	struct event *event;
-	int ret;
-
-	init_input_buf(buf, size);
-
-	event = alloc_event();
-	if (!event)
-		return -ENOMEM;
-
-	event->name = event_read_name();
-	if (!event->name)
-		die("failed to read event name");
-
-	event->id = event_read_id();
-	if (event->id < 0)
-		die("failed to read event id");
-
-	ret = event_read_format(event);
-	if (ret < 0) {
-		warning("failed to read event format for %s", event->name);
-		goto event_failed;
-	}
-
-	ret = event_read_print(event);
-	if (ret < 0) {
-		warning("failed to read event print fmt for %s", event->name);
-		goto event_failed;
-	}
-
-	event->system = strdup(sys);
-
-#define PRINT_ARGS 0
-	if (PRINT_ARGS && event->print_fmt.args)
-		print_args(event->print_fmt.args);
-
-	add_event(event);
-	return 0;
-
- event_failed:
-	event->flags |= EVENT_FL_FAILED;
-	/* still add it even if it failed */
-	add_event(event);
-	return -1;
-}
-
-void parse_set_info(int nr_cpus, int long_sz)
-{
-	cpus = nr_cpus;
-	long_size = long_sz;
-}
-
 int common_pc(struct scripting_context *context)
 {
 	return parse_common_pc(context->event_data);
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
index 58ae14c..e78ef1e 100644
--- a/tools/perf/util/trace-event.h
+++ b/tools/perf/util/trace-event.h
@@ -1,271 +1,15 @@
-#ifndef __PERF_TRACE_EVENTS_H
-#define __PERF_TRACE_EVENTS_H
+#ifndef _PERF_UTIL_TRACE_EVENT_H
+#define _PERF_UTIL_TRACE_EVENT_H
 
-#include <stdbool.h>
 #include "parse-events.h"
+#include "trace-parse-events.h"
+#include "session.h"
 
 struct machine;
 struct perf_sample;
 union perf_event;
 struct thread;
 
-#define __unused __attribute__((unused))
-
-
-#ifndef PAGE_MASK
-#define PAGE_MASK (page_size - 1)
-#endif
-
-enum {
-	RINGBUF_TYPE_PADDING		= 29,
-	RINGBUF_TYPE_TIME_EXTEND	= 30,
-	RINGBUF_TYPE_TIME_STAMP		= 31,
-};
-
-#ifndef TS_SHIFT
-#define TS_SHIFT		27
-#endif
-
-#define NSECS_PER_SEC		1000000000ULL
-#define NSECS_PER_USEC		1000ULL
-
-enum format_flags {
-	FIELD_IS_ARRAY		= 1,
-	FIELD_IS_POINTER	= 2,
-	FIELD_IS_SIGNED		= 4,
-	FIELD_IS_STRING		= 8,
-	FIELD_IS_DYNAMIC	= 16,
-	FIELD_IS_FLAG		= 32,
-	FIELD_IS_SYMBOLIC	= 64,
-};
-
-struct format_field {
-	struct format_field	*next;
-	char			*type;
-	char			*name;
-	int			offset;
-	int			size;
-	unsigned long		flags;
-};
-
-struct format {
-	int			nr_common;
-	int			nr_fields;
-	struct format_field	*common_fields;
-	struct format_field	*fields;
-};
-
-struct print_arg_atom {
-	char			*atom;
-};
-
-struct print_arg_string {
-	char			*string;
-	int			offset;
-};
-
-struct print_arg_field {
-	char			*name;
-	struct format_field	*field;
-};
-
-struct print_flag_sym {
-	struct print_flag_sym	*next;
-	char			*value;
-	char			*str;
-};
-
-struct print_arg_typecast {
-	char 			*type;
-	struct print_arg	*item;
-};
-
-struct print_arg_flags {
-	struct print_arg	*field;
-	char			*delim;
-	struct print_flag_sym	*flags;
-};
-
-struct print_arg_symbol {
-	struct print_arg	*field;
-	struct print_flag_sym	*symbols;
-};
-
-struct print_arg;
-
-struct print_arg_op {
-	char			*op;
-	int			prio;
-	struct print_arg	*left;
-	struct print_arg	*right;
-};
-
-struct print_arg_func {
-	char			*name;
-	struct print_arg	*args;
-};
-
-enum print_arg_type {
-	PRINT_NULL,
-	PRINT_ATOM,
-	PRINT_FIELD,
-	PRINT_FLAGS,
-	PRINT_SYMBOL,
-	PRINT_TYPE,
-	PRINT_STRING,
-	PRINT_OP,
-};
-
-struct print_arg {
-	struct print_arg		*next;
-	enum print_arg_type		type;
-	union {
-		struct print_arg_atom		atom;
-		struct print_arg_field		field;
-		struct print_arg_typecast	typecast;
-		struct print_arg_flags		flags;
-		struct print_arg_symbol		symbol;
-		struct print_arg_func		func;
-		struct print_arg_string		string;
-		struct print_arg_op		op;
-	};
-};
-
-struct print_fmt {
-	char			*format;
-	struct print_arg	*args;
-};
-
-struct event {
-	struct event		*next;
-	char			*name;
-	int			id;
-	int			flags;
-	struct format		format;
-	struct print_fmt	print_fmt;
-	char			*system;
-};
-
-enum {
-	EVENT_FL_ISFTRACE	= 0x01,
-	EVENT_FL_ISPRINT	= 0x02,
-	EVENT_FL_ISBPRINT	= 0x04,
-	EVENT_FL_ISFUNC		= 0x08,
-	EVENT_FL_ISFUNCENT	= 0x10,
-	EVENT_FL_ISFUNCRET	= 0x20,
-
-	EVENT_FL_FAILED		= 0x80000000
-};
-
-struct record {
-	unsigned long long ts;
-	int size;
-	void *data;
-};
-
-struct record *trace_peek_data(int cpu);
-struct record *trace_read_data(int cpu);
-
-void parse_set_info(int nr_cpus, int long_sz);
-
-ssize_t trace_report(int fd, bool repipe);
-
-void *malloc_or_die(unsigned int size);
-
-void parse_cmdlines(char *file, int size);
-void parse_proc_kallsyms(char *file, unsigned int size);
-void parse_ftrace_printk(char *file, unsigned int size);
-
-void print_funcs(void);
-void print_printk(void);
-
-int parse_ftrace_file(char *buf, unsigned long size);
-int parse_event_file(char *buf, unsigned long size, char *sys);
-void print_trace_event(int cpu, void *data, int size);
-
-extern int file_bigendian;
-extern int host_bigendian;
-
-int bigendian(void);
-
-static inline unsigned short __data2host2(unsigned short data)
-{
-	unsigned short swap;
-
-	if (host_bigendian == file_bigendian)
-		return data;
-
-	swap = ((data & 0xffULL) << 8) |
-		((data & (0xffULL << 8)) >> 8);
-
-	return swap;
-}
-
-static inline unsigned int __data2host4(unsigned int data)
-{
-	unsigned int swap;
-
-	if (host_bigendian == file_bigendian)
-		return data;
-
-	swap = ((data & 0xffULL) << 24) |
-		((data & (0xffULL << 8)) << 8) |
-		((data & (0xffULL << 16)) >> 8) |
-		((data & (0xffULL << 24)) >> 24);
-
-	return swap;
-}
-
-static inline unsigned long long __data2host8(unsigned long long data)
-{
-	unsigned long long swap;
-
-	if (host_bigendian == file_bigendian)
-		return data;
-
-	swap = ((data & 0xffULL) << 56) |
-		((data & (0xffULL << 8)) << 40) |
-		((data & (0xffULL << 16)) << 24) |
-		((data & (0xffULL << 24)) << 8) |
-		((data & (0xffULL << 32)) >> 8) |
-		((data & (0xffULL << 40)) >> 24) |
-		((data & (0xffULL << 48)) >> 40) |
-		((data & (0xffULL << 56)) >> 56);
-
-	return swap;
-}
-
-#define data2host2(ptr)		__data2host2(*(unsigned short *)ptr)
-#define data2host4(ptr)		__data2host4(*(unsigned int *)ptr)
-#define data2host8(ptr)		({				\
-	unsigned long long __val;				\
-								\
-	memcpy(&__val, (ptr), sizeof(unsigned long long));	\
-	__data2host8(__val);					\
-})
-
-extern int header_page_ts_offset;
-extern int header_page_ts_size;
-extern int header_page_size_offset;
-extern int header_page_size_size;
-extern int header_page_data_offset;
-extern int header_page_data_size;
-
-extern bool latency_format;
-
-int trace_parse_common_type(void *data);
-int trace_parse_common_pid(void *data);
-int parse_common_pc(void *data);
-int parse_common_flags(void *data);
-int parse_common_lock_depth(void *data);
-struct event *trace_find_event(int id);
-struct event *trace_find_next_event(struct event *event);
-unsigned long long read_size(void *ptr, int size);
-unsigned long long
-raw_field_value(struct event *event, const char *name, void *data);
-void *raw_field_ptr(struct event *event, const char *name, void *data);
-unsigned long long eval_flag(const char *flag);
-
 int read_tracing_data(int fd, struct list_head *pattrs);
 
 struct tracing_data {
@@ -280,15 +24,6 @@ struct tracing_data *tracing_data_get(struct list_head *pattrs,
 void tracing_data_put(struct tracing_data *tdata);
 
 
-/* taken from kernel/trace/trace.h */
-enum trace_flag_type {
-	TRACE_FLAG_IRQS_OFF		= 0x01,
-	TRACE_FLAG_IRQS_NOSUPPORT	= 0x02,
-	TRACE_FLAG_NEED_RESCHED		= 0x04,
-	TRACE_FLAG_HARDIRQ		= 0x08,
-	TRACE_FLAG_SOFTIRQ		= 0x10,
-};
-
 struct scripting_ops {
 	const char *name;
 	int (*start_script) (const char *script, int argc, const char **argv);
@@ -314,4 +49,4 @@ int common_pc(struct scripting_context *context);
 int common_flags(struct scripting_context *context);
 int common_lock_depth(struct scripting_context *context);
 
-#endif /* __PERF_TRACE_EVENTS_H */
+#endif /* _PERF_UTIL_TRACE_EVENT_H */
diff --git a/tools/perf/util/trace-parse-events.c b/tools/perf/util/trace-parse-events.c
new file mode 100644
index 0000000..8a3fbe6
--- /dev/null
+++ b/tools/perf/util/trace-parse-events.c
@@ -0,0 +1,3125 @@
+/*
+ * Copyright (C) 2009, Steven Rostedt <srostedt@redhat.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License (not later!)
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  The parts for function graph printing was taken and modified from the
+ *  Linux Kernel that were written by Frederic Weisbecker.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include "../perf.h"
+#include "util.h"
+#include "trace-parse-events.h"
+
+int header_page_ts_offset;
+int header_page_ts_size;
+int header_page_size_offset;
+int header_page_size_size;
+int header_page_overwrite_offset;
+int header_page_overwrite_size;
+int header_page_data_offset;
+int header_page_data_size;
+
+bool latency_format;
+
+static char *input_buf;
+static unsigned long long input_buf_ptr;
+static unsigned long long input_buf_siz;
+
+static int cpus;
+static int long_size;
+static int is_flag_field;
+static int is_symbolic_field;
+
+static struct format_field *
+find_any_field(struct event *event, const char *name);
+
+static void init_input_buf(char *buf, unsigned long long size)
+{
+	input_buf = buf;
+	input_buf_siz = size;
+	input_buf_ptr = 0;
+}
+
+struct cmdline {
+	char *comm;
+	int pid;
+};
+
+static struct cmdline *cmdlines;
+static int cmdline_count;
+
+static int cmdline_cmp(const void *a, const void *b)
+{
+	const struct cmdline *ca = a;
+	const struct cmdline *cb = b;
+
+	if (ca->pid < cb->pid)
+		return -1;
+	if (ca->pid > cb->pid)
+		return 1;
+
+	return 0;
+}
+
+void parse_cmdlines(char *file, int size __unused)
+{
+	struct cmdline_list {
+		struct cmdline_list	*next;
+		char			*comm;
+		int			pid;
+	} *list = NULL, *item;
+	char *line;
+	char *next = NULL;
+	int i;
+
+	line = strtok_r(file, "\n", &next);
+	while (line) {
+		item = malloc_or_die(sizeof(*item));
+		sscanf(line, "%d %as", &item->pid,
+		       (float *)(void *)&item->comm); /* workaround gcc warning */
+		item->next = list;
+		list = item;
+		line = strtok_r(NULL, "\n", &next);
+		cmdline_count++;
+	}
+
+	cmdlines = malloc_or_die(sizeof(*cmdlines) * cmdline_count);
+
+	i = 0;
+	while (list) {
+		cmdlines[i].pid = list->pid;
+		cmdlines[i].comm = list->comm;
+		i++;
+		item = list;
+		list = list->next;
+		free(item);
+	}
+
+	qsort(cmdlines, cmdline_count, sizeof(*cmdlines), cmdline_cmp);
+}
+
+static struct func_map {
+	unsigned long long		addr;
+	char				*func;
+	char				*mod;
+} *func_list;
+static unsigned int func_count;
+
+static int func_cmp(const void *a, const void *b)
+{
+	const struct func_map *fa = a;
+	const struct func_map *fb = b;
+
+	if (fa->addr < fb->addr)
+		return -1;
+	if (fa->addr > fb->addr)
+		return 1;
+
+	return 0;
+}
+
+void parse_proc_kallsyms(char *file, unsigned int size __unused)
+{
+	struct func_list {
+		struct func_list	*next;
+		unsigned long long	addr;
+		char			*func;
+		char			*mod;
+	} *list = NULL, *item;
+	char *line;
+	char *next = NULL;
+	char *addr_str;
+	char ch;
+	int i;
+
+	line = strtok_r(file, "\n", &next);
+	while (line) {
+		item = malloc_or_die(sizeof(*item));
+		item->mod = NULL;
+		sscanf(line, "%as %c %as\t[%as",
+		       (float *)(void *)&addr_str, /* workaround gcc warning */
+		       &ch,
+		       (float *)(void *)&item->func,
+		       (float *)(void *)&item->mod);
+		item->addr = strtoull(addr_str, NULL, 16);
+		free(addr_str);
+
+		/* truncate the extra ']' */
+		if (item->mod)
+			item->mod[strlen(item->mod) - 1] = 0;
+
+
+		item->next = list;
+		list = item;
+		line = strtok_r(NULL, "\n", &next);
+		func_count++;
+	}
+
+	func_list = malloc_or_die(sizeof(*func_list) * (func_count + 1));
+
+	i = 0;
+	while (list) {
+		func_list[i].func = list->func;
+		func_list[i].addr = list->addr;
+		func_list[i].mod = list->mod;
+		i++;
+		item = list;
+		list = list->next;
+		free(item);
+	}
+
+	qsort(func_list, func_count, sizeof(*func_list), func_cmp);
+
+	/*
+	 * Add a special record at the end.
+	 */
+	func_list[func_count].func = NULL;
+	func_list[func_count].addr = 0;
+	func_list[func_count].mod = NULL;
+}
+
+/*
+ * We are searching for a record in between, not an exact
+ * match.
+ */
+static int func_bcmp(const void *a, const void *b)
+{
+	const struct func_map *fa = a;
+	const struct func_map *fb = b;
+
+	if ((fa->addr == fb->addr) ||
+
+	    (fa->addr > fb->addr &&
+	     fa->addr < (fb+1)->addr))
+		return 0;
+
+	if (fa->addr < fb->addr)
+		return -1;
+
+	return 1;
+}
+
+static struct func_map *find_func(unsigned long long addr)
+{
+	struct func_map *func;
+	struct func_map key;
+
+	key.addr = addr;
+
+	func = bsearch(&key, func_list, func_count, sizeof(*func_list),
+		       func_bcmp);
+
+	return func;
+}
+
+void print_funcs(void)
+{
+	int i;
+
+	for (i = 0; i < (int)func_count; i++) {
+		printf("%016llx %s",
+		       func_list[i].addr,
+		       func_list[i].func);
+		if (func_list[i].mod)
+			printf(" [%s]\n", func_list[i].mod);
+		else
+			printf("\n");
+	}
+}
+
+static struct printk_map {
+	unsigned long long		addr;
+	char				*printk;
+} *printk_list;
+static unsigned int printk_count;
+
+static int printk_cmp(const void *a, const void *b)
+{
+	const struct func_map *fa = a;
+	const struct func_map *fb = b;
+
+	if (fa->addr < fb->addr)
+		return -1;
+	if (fa->addr > fb->addr)
+		return 1;
+
+	return 0;
+}
+
+static struct printk_map *find_printk(unsigned long long addr)
+{
+	struct printk_map *printk;
+	struct printk_map key;
+
+	key.addr = addr;
+
+	printk = bsearch(&key, printk_list, printk_count, sizeof(*printk_list),
+			 printk_cmp);
+
+	return printk;
+}
+
+void parse_ftrace_printk(char *file, unsigned int size __unused)
+{
+	struct printk_list {
+		struct printk_list	*next;
+		unsigned long long	addr;
+		char			*printk;
+	} *list = NULL, *item;
+	char *line;
+	char *next = NULL;
+	char *addr_str;
+	int i;
+
+	line = strtok_r(file, "\n", &next);
+	while (line) {
+		addr_str = strsep(&line, ":");
+		if (!line) {
+			warning("error parsing print strings");
+			break;
+		}
+		item = malloc_or_die(sizeof(*item));
+		item->addr = strtoull(addr_str, NULL, 16);
+		/* fmt still has a space, skip it */
+		item->printk = strdup(line+1);
+		item->next = list;
+		list = item;
+		line = strtok_r(NULL, "\n", &next);
+		printk_count++;
+	}
+
+	printk_list = malloc_or_die(sizeof(*printk_list) * printk_count + 1);
+
+	i = 0;
+	while (list) {
+		printk_list[i].printk = list->printk;
+		printk_list[i].addr = list->addr;
+		i++;
+		item = list;
+		list = list->next;
+		free(item);
+	}
+
+	qsort(printk_list, printk_count, sizeof(*printk_list), printk_cmp);
+}
+
+void print_printk(void)
+{
+	int i;
+
+	for (i = 0; i < (int)printk_count; i++) {
+		printf("%016llx %s\n",
+		       printk_list[i].addr,
+		       printk_list[i].printk);
+	}
+}
+
+static struct event *alloc_event(void)
+{
+	struct event *event;
+
+	event = malloc_or_die(sizeof(*event));
+	memset(event, 0, sizeof(*event));
+
+	return event;
+}
+
+enum event_type {
+	EVENT_ERROR,
+	EVENT_NONE,
+	EVENT_SPACE,
+	EVENT_NEWLINE,
+	EVENT_OP,
+	EVENT_DELIM,
+	EVENT_ITEM,
+	EVENT_DQUOTE,
+	EVENT_SQUOTE,
+};
+
+static struct event *event_list;
+
+static void add_event(struct event *event)
+{
+	event->next = event_list;
+	event_list = event;
+}
+
+static int event_item_type(enum event_type type)
+{
+	switch (type) {
+	case EVENT_ITEM ... EVENT_SQUOTE:
+		return 1;
+	case EVENT_ERROR ... EVENT_DELIM:
+	default:
+		return 0;
+	}
+}
+
+static void free_arg(struct print_arg *arg)
+{
+	if (!arg)
+		return;
+
+	switch (arg->type) {
+	case PRINT_ATOM:
+		if (arg->atom.atom)
+			free(arg->atom.atom);
+		break;
+	case PRINT_NULL:
+	case PRINT_FIELD ... PRINT_OP:
+	default:
+		/* todo */
+		break;
+	}
+
+	free(arg);
+}
+
+static enum event_type get_type(int ch)
+{
+	if (ch == '\n')
+		return EVENT_NEWLINE;
+	if (isspace(ch))
+		return EVENT_SPACE;
+	if (isalnum(ch) || ch == '_')
+		return EVENT_ITEM;
+	if (ch == '\'')
+		return EVENT_SQUOTE;
+	if (ch == '"')
+		return EVENT_DQUOTE;
+	if (!isprint(ch))
+		return EVENT_NONE;
+	if (ch == '(' || ch == ')' || ch == ',')
+		return EVENT_DELIM;
+
+	return EVENT_OP;
+}
+
+static int __read_char(void)
+{
+	if (input_buf_ptr >= input_buf_siz)
+		return -1;
+
+	return input_buf[input_buf_ptr++];
+}
+
+static int __peek_char(void)
+{
+	if (input_buf_ptr >= input_buf_siz)
+		return -1;
+
+	return input_buf[input_buf_ptr];
+}
+
+static enum event_type __read_token(char **tok)
+{
+	char buf[BUFSIZ];
+	int ch, last_ch, quote_ch, next_ch;
+	int i = 0;
+	int tok_size = 0;
+	enum event_type type;
+
+	*tok = NULL;
+
+
+	ch = __read_char();
+	if (ch < 0)
+		return EVENT_NONE;
+
+	type = get_type(ch);
+	if (type == EVENT_NONE)
+		return type;
+
+	buf[i++] = ch;
+
+	switch (type) {
+	case EVENT_NEWLINE:
+	case EVENT_DELIM:
+		*tok = malloc_or_die(2);
+		(*tok)[0] = ch;
+		(*tok)[1] = 0;
+		return type;
+
+	case EVENT_OP:
+		switch (ch) {
+		case '-':
+			next_ch = __peek_char();
+			if (next_ch == '>') {
+				buf[i++] = __read_char();
+				break;
+			}
+			/* fall through */
+		case '+':
+		case '|':
+		case '&':
+		case '>':
+		case '<':
+			last_ch = ch;
+			ch = __peek_char();
+			if (ch != last_ch)
+				goto test_equal;
+			buf[i++] = __read_char();
+			switch (last_ch) {
+			case '>':
+			case '<':
+				goto test_equal;
+			default:
+				break;
+			}
+			break;
+		case '!':
+		case '=':
+			goto test_equal;
+		default: /* what should we do instead? */
+			break;
+		}
+		buf[i] = 0;
+		*tok = strdup(buf);
+		return type;
+
+ test_equal:
+		ch = __peek_char();
+		if (ch == '=')
+			buf[i++] = __read_char();
+		break;
+
+	case EVENT_DQUOTE:
+	case EVENT_SQUOTE:
+		/* don't keep quotes */
+		i--;
+		quote_ch = ch;
+		last_ch = 0;
+		do {
+			if (i == (BUFSIZ - 1)) {
+				buf[i] = 0;
+				if (*tok) {
+					*tok = realloc(*tok, tok_size + BUFSIZ);
+					if (!*tok)
+						return EVENT_NONE;
+					strcat(*tok, buf);
+				} else
+					*tok = strdup(buf);
+
+				if (!*tok)
+					return EVENT_NONE;
+				tok_size += BUFSIZ;
+				i = 0;
+			}
+			last_ch = ch;
+			ch = __read_char();
+			buf[i++] = ch;
+			/* the '\' '\' will cancel itself */
+			if (ch == '\\' && last_ch == '\\')
+				last_ch = 0;
+		} while (ch != quote_ch || last_ch == '\\');
+		/* remove the last quote */
+		i--;
+		goto out;
+
+	case EVENT_ERROR ... EVENT_SPACE:
+	case EVENT_ITEM:
+	default:
+		break;
+	}
+
+	while (get_type(__peek_char()) == type) {
+		if (i == (BUFSIZ - 1)) {
+			buf[i] = 0;
+			if (*tok) {
+				*tok = realloc(*tok, tok_size + BUFSIZ);
+				if (!*tok)
+					return EVENT_NONE;
+				strcat(*tok, buf);
+			} else
+				*tok = strdup(buf);
+
+			if (!*tok)
+				return EVENT_NONE;
+			tok_size += BUFSIZ;
+			i = 0;
+		}
+		ch = __read_char();
+		buf[i++] = ch;
+	}
+
+ out:
+	buf[i] = 0;
+	if (*tok) {
+		*tok = realloc(*tok, tok_size + i);
+		if (!*tok)
+			return EVENT_NONE;
+		strcat(*tok, buf);
+	} else
+		*tok = strdup(buf);
+	if (!*tok)
+		return EVENT_NONE;
+
+	return type;
+}
+
+static void free_token(char *tok)
+{
+	if (tok)
+		free(tok);
+}
+
+static enum event_type read_token(char **tok)
+{
+	enum event_type type;
+
+	for (;;) {
+		type = __read_token(tok);
+		if (type != EVENT_SPACE)
+			return type;
+
+		free_token(*tok);
+	}
+
+	/* not reached */
+	return EVENT_NONE;
+}
+
+/* no newline */
+static enum event_type read_token_item(char **tok)
+{
+	enum event_type type;
+
+	for (;;) {
+		type = __read_token(tok);
+		if (type != EVENT_SPACE && type != EVENT_NEWLINE)
+			return type;
+
+		free_token(*tok);
+	}
+
+	/* not reached */
+	return EVENT_NONE;
+}
+
+static int test_type(enum event_type type, enum event_type expect)
+{
+	if (type != expect) {
+		warning("Error: expected type %d but read %d",
+		    expect, type);
+		return -1;
+	}
+	return 0;
+}
+
+static int __test_type_token(enum event_type type, char *token,
+			     enum event_type expect, const char *expect_tok,
+			     bool warn)
+{
+	if (type != expect) {
+		if (warn)
+			warning("Error: expected type %d but read %d",
+				expect, type);
+		return -1;
+	}
+
+	if (strcmp(token, expect_tok) != 0) {
+		if (warn)
+			warning("Error: expected '%s' but read '%s'",
+				expect_tok, token);
+		return -1;
+	}
+	return 0;
+}
+
+static int test_type_token(enum event_type type, char *token,
+			   enum event_type expect, const char *expect_tok)
+{
+	return __test_type_token(type, token, expect, expect_tok, true);
+}
+
+static int __read_expect_type(enum event_type expect, char **tok, int newline_ok)
+{
+	enum event_type type;
+
+	if (newline_ok)
+		type = read_token(tok);
+	else
+		type = read_token_item(tok);
+	return test_type(type, expect);
+}
+
+static int read_expect_type(enum event_type expect, char **tok)
+{
+	return __read_expect_type(expect, tok, 1);
+}
+
+static int __read_expected(enum event_type expect, const char *str,
+			   int newline_ok, bool warn)
+{
+	enum event_type type;
+	char *token;
+	int ret;
+
+	if (newline_ok)
+		type = read_token(&token);
+	else
+		type = read_token_item(&token);
+
+	ret = __test_type_token(type, token, expect, str, warn);
+
+	free_token(token);
+
+	return ret;
+}
+
+static int read_expected(enum event_type expect, const char *str)
+{
+	return __read_expected(expect, str, 1, true);
+}
+
+static int read_expected_item(enum event_type expect, const char *str)
+{
+	return __read_expected(expect, str, 0, true);
+}
+
+static char *event_read_name(void)
+{
+	char *token;
+
+	if (read_expected(EVENT_ITEM, "name") < 0)
+		return NULL;
+
+	if (read_expected(EVENT_OP, ":") < 0)
+		return NULL;
+
+	if (read_expect_type(EVENT_ITEM, &token) < 0)
+		goto fail;
+
+	return token;
+
+ fail:
+	free_token(token);
+	return NULL;
+}
+
+static int event_read_id(void)
+{
+	char *token;
+	int id;
+
+	if (read_expected_item(EVENT_ITEM, "ID") < 0)
+		return -1;
+
+	if (read_expected(EVENT_OP, ":") < 0)
+		return -1;
+
+	if (read_expect_type(EVENT_ITEM, &token) < 0)
+		goto fail;
+
+	id = strtoul(token, NULL, 0);
+	free_token(token);
+	return id;
+
+ fail:
+	free_token(token);
+	return -1;
+}
+
+static int field_is_string(struct format_field *field)
+{
+	if ((field->flags & FIELD_IS_ARRAY) &&
+	    (!strstr(field->type, "char") || !strstr(field->type, "u8") ||
+	     !strstr(field->type, "s8")))
+		return 1;
+
+	return 0;
+}
+
+static int field_is_dynamic(struct format_field *field)
+{
+	if (!strncmp(field->type, "__data_loc", 10))
+		return 1;
+
+	return 0;
+}
+
+static int event_read_fields(struct event *event, struct format_field **fields)
+{
+	struct format_field *field = NULL;
+	enum event_type type;
+	char *token;
+	char *last_token;
+	int count = 0;
+
+	do {
+		type = read_token(&token);
+		if (type == EVENT_NEWLINE) {
+			free_token(token);
+			return count;
+		}
+
+		count++;
+
+		if (test_type_token(type, token, EVENT_ITEM, "field"))
+			goto fail;
+		free_token(token);
+
+		type = read_token(&token);
+		/*
+		 * The ftrace fields may still use the "special" name.
+		 * Just ignore it.
+		 */
+		if (event->flags & EVENT_FL_ISFTRACE &&
+		    type == EVENT_ITEM && strcmp(token, "special") == 0) {
+			free_token(token);
+			type = read_token(&token);
+		}
+
+		if (test_type_token(type, token, EVENT_OP, ":") < 0)
+			return -1;
+
+		if (read_expect_type(EVENT_ITEM, &token) < 0)
+			goto fail;
+
+		last_token = token;
+
+		field = malloc_or_die(sizeof(*field));
+		memset(field, 0, sizeof(*field));
+
+		/* read the rest of the type */
+		for (;;) {
+			type = read_token(&token);
+			if (type == EVENT_ITEM ||
+			    (type == EVENT_OP && strcmp(token, "*") == 0) ||
+			    /*
+			     * Some of the ftrace fields are broken and have
+			     * an illegal "." in them.
+			     */
+			    (event->flags & EVENT_FL_ISFTRACE &&
+			     type == EVENT_OP && strcmp(token, ".") == 0)) {
+
+				if (strcmp(token, "*") == 0)
+					field->flags |= FIELD_IS_POINTER;
+
+				if (field->type) {
+					field->type = realloc(field->type,
+							      strlen(field->type) +
+							      strlen(last_token) + 2);
+					strcat(field->type, " ");
+					strcat(field->type, last_token);
+				} else
+					field->type = last_token;
+				last_token = token;
+				continue;
+			}
+
+			break;
+		}
+
+		if (!field->type) {
+			die("no type found");
+			goto fail;
+		}
+		field->name = last_token;
+
+		if (test_type(type, EVENT_OP))
+			goto fail;
+
+		if (strcmp(token, "[") == 0) {
+			enum event_type last_type = type;
+			char *brackets = token;
+			int len;
+
+			field->flags |= FIELD_IS_ARRAY;
+
+			type = read_token(&token);
+			while (strcmp(token, "]") != 0) {
+				if (last_type == EVENT_ITEM &&
+				    type == EVENT_ITEM)
+					len = 2;
+				else
+					len = 1;
+				last_type = type;
+
+				brackets = realloc(brackets,
+						   strlen(brackets) +
+						   strlen(token) + len);
+				if (len == 2)
+					strcat(brackets, " ");
+				strcat(brackets, token);
+				free_token(token);
+				type = read_token(&token);
+				if (type == EVENT_NONE) {
+					die("failed to find token");
+					goto fail;
+				}
+			}
+
+			free_token(token);
+
+			brackets = realloc(brackets, strlen(brackets) + 2);
+			strcat(brackets, "]");
+
+			/* add brackets to type */
+
+			type = read_token(&token);
+			/*
+			 * If the next token is not an OP, then it is of
+			 * the format: type [] item;
+			 */
+			if (type == EVENT_ITEM) {
+				field->type = realloc(field->type,
+						      strlen(field->type) +
+						      strlen(field->name) +
+						      strlen(brackets) + 2);
+				strcat(field->type, " ");
+				strcat(field->type, field->name);
+				free_token(field->name);
+				strcat(field->type, brackets);
+				field->name = token;
+				type = read_token(&token);
+			} else {
+				field->type = realloc(field->type,
+						      strlen(field->type) +
+						      strlen(brackets) + 1);
+				strcat(field->type, brackets);
+			}
+			free(brackets);
+		}
+
+		if (field_is_string(field)) {
+			field->flags |= FIELD_IS_STRING;
+			if (field_is_dynamic(field))
+				field->flags |= FIELD_IS_DYNAMIC;
+		}
+
+		if (test_type_token(type, token,  EVENT_OP, ";"))
+			goto fail;
+		free_token(token);
+
+		if (read_expected(EVENT_ITEM, "offset") < 0)
+			goto fail_expect;
+
+		if (read_expected(EVENT_OP, ":") < 0)
+			goto fail_expect;
+
+		if (read_expect_type(EVENT_ITEM, &token))
+			goto fail;
+		field->offset = strtoul(token, NULL, 0);
+		free_token(token);
+
+		if (read_expected(EVENT_OP, ";") < 0)
+			goto fail_expect;
+
+		if (read_expected(EVENT_ITEM, "size") < 0)
+			goto fail_expect;
+
+		if (read_expected(EVENT_OP, ":") < 0)
+			goto fail_expect;
+
+		if (read_expect_type(EVENT_ITEM, &token))
+			goto fail;
+		field->size = strtoul(token, NULL, 0);
+		free_token(token);
+
+		if (read_expected(EVENT_OP, ";") < 0)
+			goto fail_expect;
+
+		type = read_token(&token);
+		if (type != EVENT_NEWLINE) {
+			/* newer versions of the kernel have a "signed" type */
+			if (test_type_token(type, token, EVENT_ITEM, "signed"))
+				goto fail;
+
+			free_token(token);
+
+			if (read_expected(EVENT_OP, ":") < 0)
+				goto fail_expect;
+
+			if (read_expect_type(EVENT_ITEM, &token))
+				goto fail;
+
+			if (strtoul(token, NULL, 0))
+				field->flags |= FIELD_IS_SIGNED;
+
+			free_token(token);
+			if (read_expected(EVENT_OP, ";") < 0)
+				goto fail_expect;
+
+			if (read_expect_type(EVENT_NEWLINE, &token))
+				goto fail;
+		}
+
+		free_token(token);
+
+		*fields = field;
+		fields = &field->next;
+
+	} while (1);
+
+	return 0;
+
+fail:
+	free_token(token);
+fail_expect:
+	if (field)
+		free(field);
+	return -1;
+}
+
+static int event_read_format(struct event *event)
+{
+	char *token;
+	int ret;
+
+	if (read_expected_item(EVENT_ITEM, "format") < 0)
+		return -1;
+
+	if (read_expected(EVENT_OP, ":") < 0)
+		return -1;
+
+	if (read_expect_type(EVENT_NEWLINE, &token))
+		goto fail;
+	free_token(token);
+
+	ret = event_read_fields(event, &event->format.common_fields);
+	if (ret < 0)
+		return ret;
+	event->format.nr_common = ret;
+
+	ret = event_read_fields(event, &event->format.fields);
+	if (ret < 0)
+		return ret;
+	event->format.nr_fields = ret;
+
+	return 0;
+
+ fail:
+	free_token(token);
+	return -1;
+}
+
+enum event_type
+process_arg_token(struct event *event, struct print_arg *arg,
+		  char **tok, enum event_type type);
+
+static enum event_type
+process_arg(struct event *event, struct print_arg *arg, char **tok)
+{
+	enum event_type type;
+	char *token;
+
+	type = read_token(&token);
+	*tok = token;
+
+	return process_arg_token(event, arg, tok, type);
+}
+
+static enum event_type
+process_cond(struct event *event, struct print_arg *top, char **tok)
+{
+	struct print_arg *arg, *left, *right;
+	enum event_type type;
+	char *token = NULL;
+
+	arg = malloc_or_die(sizeof(*arg));
+	memset(arg, 0, sizeof(*arg));
+
+	left = malloc_or_die(sizeof(*left));
+
+	right = malloc_or_die(sizeof(*right));
+
+	arg->type = PRINT_OP;
+	arg->op.left = left;
+	arg->op.right = right;
+
+	*tok = NULL;
+	type = process_arg(event, left, &token);
+	if (test_type_token(type, token, EVENT_OP, ":"))
+		goto out_free;
+
+	arg->op.op = token;
+
+	type = process_arg(event, right, &token);
+
+	top->op.right = arg;
+
+	*tok = token;
+	return type;
+
+out_free:
+	free_token(*tok);
+	free(right);
+	free(left);
+	free_arg(arg);
+	return EVENT_ERROR;
+}
+
+static enum event_type
+process_array(struct event *event, struct print_arg *top, char **tok)
+{
+	struct print_arg *arg;
+	enum event_type type;
+	char *token = NULL;
+
+	arg = malloc_or_die(sizeof(*arg));
+	memset(arg, 0, sizeof(*arg));
+
+	*tok = NULL;
+	type = process_arg(event, arg, &token);
+	if (test_type_token(type, token, EVENT_OP, "]"))
+		goto out_free;
+
+	top->op.right = arg;
+
+	free_token(token);
+	type = read_token_item(&token);
+	*tok = token;
+
+	return type;
+
+out_free:
+	free_token(*tok);
+	free_arg(arg);
+	return EVENT_ERROR;
+}
+
+static int get_op_prio(char *op)
+{
+	if (!op[1]) {
+		switch (op[0]) {
+		case '*':
+		case '/':
+		case '%':
+			return 6;
+		case '+':
+		case '-':
+			return 7;
+			/* '>>' and '<<' are 8 */
+		case '<':
+		case '>':
+			return 9;
+			/* '==' and '!=' are 10 */
+		case '&':
+			return 11;
+		case '^':
+			return 12;
+		case '|':
+			return 13;
+		case '?':
+			return 16;
+		default:
+			die("unknown op '%c'", op[0]);
+			return -1;
+		}
+	} else {
+		if (strcmp(op, "++") == 0 ||
+		    strcmp(op, "--") == 0) {
+			return 3;
+		} else if (strcmp(op, ">>") == 0 ||
+			   strcmp(op, "<<") == 0) {
+			return 8;
+		} else if (strcmp(op, ">=") == 0 ||
+			   strcmp(op, "<=") == 0) {
+			return 9;
+		} else if (strcmp(op, "==") == 0 ||
+			   strcmp(op, "!=") == 0) {
+			return 10;
+		} else if (strcmp(op, "&&") == 0) {
+			return 14;
+		} else if (strcmp(op, "||") == 0) {
+			return 15;
+		} else {
+			die("unknown op '%s'", op);
+			return -1;
+		}
+	}
+}
+
+static void set_op_prio(struct print_arg *arg)
+{
+
+	/* single ops are the greatest */
+	if (!arg->op.left || arg->op.left->type == PRINT_NULL) {
+		arg->op.prio = 0;
+		return;
+	}
+
+	arg->op.prio = get_op_prio(arg->op.op);
+}
+
+static enum event_type
+process_op(struct event *event, struct print_arg *arg, char **tok)
+{
+	struct print_arg *left, *right = NULL;
+	enum event_type type;
+	char *token;
+
+	/* the op is passed in via tok */
+	token = *tok;
+
+	if (arg->type == PRINT_OP && !arg->op.left) {
+		/* handle single op */
+		if (token[1]) {
+			die("bad op token %s", token);
+			return EVENT_ERROR;
+		}
+		switch (token[0]) {
+		case '!':
+		case '+':
+		case '-':
+			break;
+		default:
+			die("bad op token %s", token);
+			return EVENT_ERROR;
+		}
+
+		/* make an empty left */
+		left = malloc_or_die(sizeof(*left));
+		left->type = PRINT_NULL;
+		arg->op.left = left;
+
+		right = malloc_or_die(sizeof(*right));
+		arg->op.right = right;
+
+		type = process_arg(event, right, tok);
+
+	} else if (strcmp(token, "?") == 0) {
+
+		left = malloc_or_die(sizeof(*left));
+		/* copy the top arg to the left */
+		*left = *arg;
+
+		arg->type = PRINT_OP;
+		arg->op.op = token;
+		arg->op.left = left;
+		arg->op.prio = 0;
+
+		type = process_cond(event, arg, tok);
+
+	} else if (strcmp(token, ">>") == 0 ||
+		   strcmp(token, "<<") == 0 ||
+		   strcmp(token, "&") == 0 ||
+		   strcmp(token, "|") == 0 ||
+		   strcmp(token, "&&") == 0 ||
+		   strcmp(token, "||") == 0 ||
+		   strcmp(token, "-") == 0 ||
+		   strcmp(token, "+") == 0 ||
+		   strcmp(token, "*") == 0 ||
+		   strcmp(token, "^") == 0 ||
+		   strcmp(token, "/") == 0 ||
+		   strcmp(token, "<") == 0 ||
+		   strcmp(token, ">") == 0 ||
+		   strcmp(token, "==") == 0 ||
+		   strcmp(token, "!=") == 0) {
+
+		left = malloc_or_die(sizeof(*left));
+
+		/* copy the top arg to the left */
+		*left = *arg;
+
+		arg->type = PRINT_OP;
+		arg->op.op = token;
+		arg->op.left = left;
+
+		set_op_prio(arg);
+
+		right = malloc_or_die(sizeof(*right));
+
+		type = read_token_item(&token);
+		*tok = token;
+
+		/* could just be a type pointer */
+		if ((strcmp(arg->op.op, "*") == 0) &&
+		    type == EVENT_DELIM && (strcmp(token, ")") == 0)) {
+			if (left->type != PRINT_ATOM)
+				die("bad pointer type");
+			left->atom.atom = realloc(left->atom.atom,
+					    sizeof(left->atom.atom) + 3);
+			strcat(left->atom.atom, " *");
+			*arg = *left;
+			free(arg);
+
+			return type;
+		}
+
+		type = process_arg_token(event, right, tok, type);
+
+		arg->op.right = right;
+
+	} else if (strcmp(token, "[") == 0) {
+
+		left = malloc_or_die(sizeof(*left));
+		*left = *arg;
+
+		arg->type = PRINT_OP;
+		arg->op.op = token;
+		arg->op.left = left;
+
+		arg->op.prio = 0;
+		type = process_array(event, arg, tok);
+
+	} else {
+		warning("unknown op '%s'", token);
+		event->flags |= EVENT_FL_FAILED;
+		/* the arg is now the left side */
+		return EVENT_NONE;
+	}
+
+	if (type == EVENT_OP) {
+		int prio;
+
+		/* higher prios need to be closer to the root */
+		prio = get_op_prio(*tok);
+
+		if (prio > arg->op.prio)
+			return process_op(event, arg, tok);
+
+		return process_op(event, right, tok);
+	}
+
+	return type;
+}
+
+static enum event_type
+process_entry(struct event *event __unused, struct print_arg *arg,
+	      char **tok)
+{
+	enum event_type type;
+	char *field;
+	char *token;
+
+	if (read_expected(EVENT_OP, "->") < 0)
+		return EVENT_ERROR;
+
+	if (read_expect_type(EVENT_ITEM, &token) < 0)
+		goto fail;
+	field = token;
+
+	arg->type = PRINT_FIELD;
+	arg->field.name = field;
+
+	if (is_flag_field) {
+		arg->field.field = find_any_field(event, arg->field.name);
+		arg->field.field->flags |= FIELD_IS_FLAG;
+		is_flag_field = 0;
+	} else if (is_symbolic_field) {
+		arg->field.field = find_any_field(event, arg->field.name);
+		arg->field.field->flags |= FIELD_IS_SYMBOLIC;
+		is_symbolic_field = 0;
+	}
+
+	type = read_token(&token);
+	*tok = token;
+
+	return type;
+
+fail:
+	free_token(token);
+	return EVENT_ERROR;
+}
+
+static char *arg_eval (struct print_arg *arg);
+
+static long long arg_num_eval(struct print_arg *arg)
+{
+	long long left, right;
+	long long val = 0;
+
+	switch (arg->type) {
+	case PRINT_ATOM:
+		val = strtoll(arg->atom.atom, NULL, 0);
+		break;
+	case PRINT_TYPE:
+		val = arg_num_eval(arg->typecast.item);
+		break;
+	case PRINT_OP:
+		switch (arg->op.op[0]) {
+		case '|':
+			left = arg_num_eval(arg->op.left);
+			right = arg_num_eval(arg->op.right);
+			if (arg->op.op[1])
+				val = left || right;
+			else
+				val = left | right;
+			break;
+		case '&':
+			left = arg_num_eval(arg->op.left);
+			right = arg_num_eval(arg->op.right);
+			if (arg->op.op[1])
+				val = left && right;
+			else
+				val = left & right;
+			break;
+		case '<':
+			left = arg_num_eval(arg->op.left);
+			right = arg_num_eval(arg->op.right);
+			switch (arg->op.op[1]) {
+			case 0:
+				val = left < right;
+				break;
+			case '<':
+				val = left << right;
+				break;
+			case '=':
+				val = left <= right;
+				break;
+			default:
+				die("unknown op '%s'", arg->op.op);
+			}
+			break;
+		case '>':
+			left = arg_num_eval(arg->op.left);
+			right = arg_num_eval(arg->op.right);
+			switch (arg->op.op[1]) {
+			case 0:
+				val = left > right;
+				break;
+			case '>':
+				val = left >> right;
+				break;
+			case '=':
+				val = left >= right;
+				break;
+			default:
+				die("unknown op '%s'", arg->op.op);
+			}
+			break;
+		case '=':
+			left = arg_num_eval(arg->op.left);
+			right = arg_num_eval(arg->op.right);
+
+			if (arg->op.op[1] != '=')
+				die("unknown op '%s'", arg->op.op);
+
+			val = left == right;
+			break;
+		case '!':
+			left = arg_num_eval(arg->op.left);
+			right = arg_num_eval(arg->op.right);
+
+			switch (arg->op.op[1]) {
+			case '=':
+				val = left != right;
+				break;
+			default:
+				die("unknown op '%s'", arg->op.op);
+			}
+			break;
+		default:
+			die("unknown op '%s'", arg->op.op);
+		}
+		break;
+
+	case PRINT_NULL:
+	case PRINT_FIELD ... PRINT_SYMBOL:
+	case PRINT_STRING:
+	default:
+		die("invalid eval type %d", arg->type);
+
+	}
+	return val;
+}
+
+static char *arg_eval (struct print_arg *arg)
+{
+	long long val;
+	static char buf[20];
+
+	switch (arg->type) {
+	case PRINT_ATOM:
+		return arg->atom.atom;
+	case PRINT_TYPE:
+		return arg_eval(arg->typecast.item);
+	case PRINT_OP:
+		val = arg_num_eval(arg);
+		sprintf(buf, "%lld", val);
+		return buf;
+
+	case PRINT_NULL:
+	case PRINT_FIELD ... PRINT_SYMBOL:
+	case PRINT_STRING:
+	default:
+		die("invalid eval type %d", arg->type);
+		break;
+	}
+
+	return NULL;
+}
+
+static enum event_type
+process_fields(struct event *event, struct print_flag_sym **list, char **tok)
+{
+	enum event_type type;
+	struct print_arg *arg = NULL;
+	struct print_flag_sym *field;
+	char *token = NULL;
+	char *value;
+
+	do {
+		free_token(token);
+		type = read_token_item(&token);
+		if (test_type_token(type, token, EVENT_OP, "{"))
+			break;
+
+		arg = malloc_or_die(sizeof(*arg));
+
+		free_token(token);
+		type = process_arg(event, arg, &token);
+		if (test_type_token(type, token, EVENT_DELIM, ","))
+			goto out_free;
+
+		field = malloc_or_die(sizeof(*field));
+		memset(field, 0, sizeof(*field));
+
+		value = arg_eval(arg);
+		field->value = strdup(value);
+
+		free_token(token);
+		type = process_arg(event, arg, &token);
+		if (test_type_token(type, token, EVENT_OP, "}"))
+			goto out_free;
+
+		value = arg_eval(arg);
+		field->str = strdup(value);
+		free_arg(arg);
+		arg = NULL;
+
+		*list = field;
+		list = &field->next;
+
+		free_token(token);
+		type = read_token_item(&token);
+	} while (type == EVENT_DELIM && strcmp(token, ",") == 0);
+
+	*tok = token;
+	return type;
+
+out_free:
+	free_arg(arg);
+	free_token(token);
+
+	return EVENT_ERROR;
+}
+
+static enum event_type
+process_flags(struct event *event, struct print_arg *arg, char **tok)
+{
+	struct print_arg *field;
+	enum event_type type;
+	char *token;
+
+	memset(arg, 0, sizeof(*arg));
+	arg->type = PRINT_FLAGS;
+
+	if (read_expected_item(EVENT_DELIM, "(") < 0)
+		return EVENT_ERROR;
+
+	field = malloc_or_die(sizeof(*field));
+
+	type = process_arg(event, field, &token);
+	if (test_type_token(type, token, EVENT_DELIM, ","))
+		goto out_free;
+
+	arg->flags.field = field;
+
+	type = read_token_item(&token);
+	if (event_item_type(type)) {
+		arg->flags.delim = token;
+		type = read_token_item(&token);
+	}
+
+	if (test_type_token(type, token, EVENT_DELIM, ","))
+		goto out_free;
+
+	type = process_fields(event, &arg->flags.flags, &token);
+	if (test_type_token(type, token, EVENT_DELIM, ")"))
+		goto out_free;
+
+	free_token(token);
+	type = read_token_item(tok);
+	return type;
+
+out_free:
+	free_token(token);
+	return EVENT_ERROR;
+}
+
+static enum event_type
+process_symbols(struct event *event, struct print_arg *arg, char **tok)
+{
+	struct print_arg *field;
+	enum event_type type;
+	char *token;
+
+	memset(arg, 0, sizeof(*arg));
+	arg->type = PRINT_SYMBOL;
+
+	if (read_expected_item(EVENT_DELIM, "(") < 0)
+		return EVENT_ERROR;
+
+	field = malloc_or_die(sizeof(*field));
+
+	type = process_arg(event, field, &token);
+	if (test_type_token(type, token, EVENT_DELIM, ","))
+		goto out_free;
+
+	arg->symbol.field = field;
+
+	type = process_fields(event, &arg->symbol.symbols, &token);
+	if (test_type_token(type, token, EVENT_DELIM, ")"))
+		goto out_free;
+
+	free_token(token);
+	type = read_token_item(tok);
+	return type;
+
+out_free:
+	free_token(token);
+	return EVENT_ERROR;
+}
+
+static enum event_type
+process_paren(struct event *event, struct print_arg *arg, char **tok)
+{
+	struct print_arg *item_arg;
+	enum event_type type;
+	char *token;
+
+	type = process_arg(event, arg, &token);
+
+	if (type == EVENT_ERROR)
+		return EVENT_ERROR;
+
+	if (type == EVENT_OP)
+		type = process_op(event, arg, &token);
+
+	if (type == EVENT_ERROR)
+		return EVENT_ERROR;
+
+	if (test_type_token(type, token, EVENT_DELIM, ")")) {
+		free_token(token);
+		return EVENT_ERROR;
+	}
+
+	free_token(token);
+	type = read_token_item(&token);
+
+	/*
+	 * If the next token is an item or another open paren, then
+	 * this was a typecast.
+	 */
+	if (event_item_type(type) ||
+	    (type == EVENT_DELIM && strcmp(token, "(") == 0)) {
+
+		/* make this a typecast and contine */
+
+		/* prevous must be an atom */
+		if (arg->type != PRINT_ATOM)
+			die("previous needed to be PRINT_ATOM");
+
+		item_arg = malloc_or_die(sizeof(*item_arg));
+
+		arg->type = PRINT_TYPE;
+		arg->typecast.type = arg->atom.atom;
+		arg->typecast.item = item_arg;
+		type = process_arg_token(event, item_arg, &token, type);
+
+	}
+
+	*tok = token;
+	return type;
+}
+
+
+static enum event_type
+process_str(struct event *event __unused, struct print_arg *arg, char **tok)
+{
+	enum event_type type;
+	char *token;
+
+	if (read_expected(EVENT_DELIM, "(") < 0)
+		return EVENT_ERROR;
+
+	if (read_expect_type(EVENT_ITEM, &token) < 0)
+		goto fail;
+
+	arg->type = PRINT_STRING;
+	arg->string.string = token;
+	arg->string.offset = -1;
+
+	if (read_expected(EVENT_DELIM, ")") < 0)
+		return EVENT_ERROR;
+
+	type = read_token(&token);
+	*tok = token;
+
+	return type;
+fail:
+	free_token(token);
+	return EVENT_ERROR;
+}
+
+enum event_type
+process_arg_token(struct event *event, struct print_arg *arg,
+		  char **tok, enum event_type type)
+{
+	char *token;
+	char *atom;
+
+	token = *tok;
+
+	switch (type) {
+	case EVENT_ITEM:
+		if (strcmp(token, "REC") == 0) {
+			free_token(token);
+			type = process_entry(event, arg, &token);
+		} else if (strcmp(token, "__print_flags") == 0) {
+			free_token(token);
+			is_flag_field = 1;
+			type = process_flags(event, arg, &token);
+		} else if (strcmp(token, "__print_symbolic") == 0) {
+			free_token(token);
+			is_symbolic_field = 1;
+			type = process_symbols(event, arg, &token);
+		} else if (strcmp(token, "__get_str") == 0) {
+			free_token(token);
+			type = process_str(event, arg, &token);
+		} else {
+			atom = token;
+			/* test the next token */
+			type = read_token_item(&token);
+
+			/* atoms can be more than one token long */
+			while (type == EVENT_ITEM) {
+				atom = realloc(atom, strlen(atom) + strlen(token) + 2);
+				strcat(atom, " ");
+				strcat(atom, token);
+				free_token(token);
+				type = read_token_item(&token);
+			}
+
+			/* todo, test for function */
+
+			arg->type = PRINT_ATOM;
+			arg->atom.atom = atom;
+		}
+		break;
+	case EVENT_DQUOTE:
+	case EVENT_SQUOTE:
+		arg->type = PRINT_ATOM;
+		arg->atom.atom = token;
+		type = read_token_item(&token);
+		break;
+	case EVENT_DELIM:
+		if (strcmp(token, "(") == 0) {
+			free_token(token);
+			type = process_paren(event, arg, &token);
+			break;
+		}
+	case EVENT_OP:
+		/* handle single ops */
+		arg->type = PRINT_OP;
+		arg->op.op = token;
+		arg->op.left = NULL;
+		type = process_op(event, arg, &token);
+
+		break;
+
+	case EVENT_ERROR ... EVENT_NEWLINE:
+	default:
+		die("unexpected type %d", type);
+	}
+	*tok = token;
+
+	return type;
+}
+
+static int event_read_print_args(struct event *event, struct print_arg **list)
+{
+	enum event_type type = EVENT_ERROR;
+	struct print_arg *arg;
+	char *token;
+	int args = 0;
+
+	do {
+		if (type == EVENT_NEWLINE) {
+			free_token(token);
+			type = read_token_item(&token);
+			continue;
+		}
+
+		arg = malloc_or_die(sizeof(*arg));
+		memset(arg, 0, sizeof(*arg));
+
+		type = process_arg(event, arg, &token);
+
+		if (type == EVENT_ERROR) {
+			free_arg(arg);
+			return -1;
+		}
+
+		*list = arg;
+		args++;
+
+		if (type == EVENT_OP) {
+			type = process_op(event, arg, &token);
+			list = &arg->next;
+			continue;
+		}
+
+		if (type == EVENT_DELIM && strcmp(token, ",") == 0) {
+			free_token(token);
+			*list = arg;
+			list = &arg->next;
+			continue;
+		}
+		break;
+	} while (type != EVENT_NONE);
+
+	if (type != EVENT_NONE)
+		free_token(token);
+
+	return args;
+}
+
+static int event_read_print(struct event *event)
+{
+	enum event_type type;
+	char *token;
+	int ret;
+
+	if (read_expected_item(EVENT_ITEM, "print") < 0)
+		return -1;
+
+	if (read_expected(EVENT_ITEM, "fmt") < 0)
+		return -1;
+
+	if (read_expected(EVENT_OP, ":") < 0)
+		return -1;
+
+	if (read_expect_type(EVENT_DQUOTE, &token) < 0)
+		goto fail;
+
+ concat:
+	event->print_fmt.format = token;
+	event->print_fmt.args = NULL;
+
+	/* ok to have no arg */
+	type = read_token_item(&token);
+
+	if (type == EVENT_NONE)
+		return 0;
+
+	/* Handle concatination of print lines */
+	if (type == EVENT_DQUOTE) {
+		char *cat;
+
+		cat = malloc_or_die(strlen(event->print_fmt.format) +
+				    strlen(token) + 1);
+		strcpy(cat, event->print_fmt.format);
+		strcat(cat, token);
+		free_token(token);
+		free_token(event->print_fmt.format);
+		event->print_fmt.format = NULL;
+		token = cat;
+		goto concat;
+	}
+
+	if (test_type_token(type, token, EVENT_DELIM, ","))
+		goto fail;
+
+	free_token(token);
+
+	ret = event_read_print_args(event, &event->print_fmt.args);
+	if (ret < 0)
+		return -1;
+
+	return ret;
+
+ fail:
+	free_token(token);
+	return -1;
+}
+
+static struct format_field *
+find_common_field(struct event *event, const char *name)
+{
+	struct format_field *format;
+
+	for (format = event->format.common_fields;
+	     format; format = format->next) {
+		if (strcmp(format->name, name) == 0)
+			break;
+	}
+
+	return format;
+}
+
+static struct format_field *
+find_field(struct event *event, const char *name)
+{
+	struct format_field *format;
+
+	for (format = event->format.fields;
+	     format; format = format->next) {
+		if (strcmp(format->name, name) == 0)
+			break;
+	}
+
+	return format;
+}
+
+static struct format_field *
+find_any_field(struct event *event, const char *name)
+{
+	struct format_field *format;
+
+	format = find_common_field(event, name);
+	if (format)
+		return format;
+	return find_field(event, name);
+}
+
+unsigned long long read_size(void *ptr, int size)
+{
+	switch (size) {
+	case 1:
+		return *(unsigned char *)ptr;
+	case 2:
+		return data2host2(ptr);
+	case 4:
+		return data2host4(ptr);
+	case 8:
+		return data2host8(ptr);
+	default:
+		/* BUG! */
+		return 0;
+	}
+}
+
+unsigned long long
+raw_field_value(struct event *event, const char *name, void *data)
+{
+	struct format_field *field;
+
+	field = find_any_field(event, name);
+	if (!field)
+		return 0ULL;
+
+	return read_size(data + field->offset, field->size);
+}
+
+void *raw_field_ptr(struct event *event, const char *name, void *data)
+{
+	struct format_field *field;
+
+	field = find_any_field(event, name);
+	if (!field)
+		return NULL;
+
+	if (field->flags & FIELD_IS_DYNAMIC) {
+		int offset;
+
+		offset = *(int *)(data + field->offset);
+		offset &= 0xffff;
+
+		return data + offset;
+	}
+
+	return data + field->offset;
+}
+
+static int get_common_info(const char *type, int *offset, int *size)
+{
+	struct event *event;
+	struct format_field *field;
+
+	/*
+	 * All events should have the same common elements.
+	 * Pick any event to find where the type is;
+	 */
+	if (!event_list)
+		die("no event_list!");
+
+	event = event_list;
+	field = find_common_field(event, type);
+	if (!field)
+		die("field '%s' not found", type);
+
+	*offset = field->offset;
+	*size = field->size;
+
+	return 0;
+}
+
+static int __parse_common(void *data, int *size, int *offset,
+			  const char *name)
+{
+	int ret;
+
+	if (!*size) {
+		ret = get_common_info(name, offset, size);
+		if (ret < 0)
+			return ret;
+	}
+	return read_size(data + *offset, *size);
+}
+
+int trace_parse_common_type(void *data)
+{
+	static int type_offset;
+	static int type_size;
+
+	return __parse_common(data, &type_size, &type_offset,
+			      "common_type");
+}
+
+int trace_parse_common_pid(void *data)
+{
+	static int pid_offset;
+	static int pid_size;
+
+	return __parse_common(data, &pid_size, &pid_offset,
+			      "common_pid");
+}
+
+int parse_common_pc(void *data)
+{
+	static int pc_offset;
+	static int pc_size;
+
+	return __parse_common(data, &pc_size, &pc_offset,
+			      "common_preempt_count");
+}
+
+int parse_common_flags(void *data)
+{
+	static int flags_offset;
+	static int flags_size;
+
+	return __parse_common(data, &flags_size, &flags_offset,
+			      "common_flags");
+}
+
+int parse_common_lock_depth(void *data)
+{
+	static int ld_offset;
+	static int ld_size;
+	int ret;
+
+	ret = __parse_common(data, &ld_size, &ld_offset,
+			     "common_lock_depth");
+	if (ret < 0)
+		return -1;
+
+	return ret;
+}
+
+struct event *trace_find_event(int id)
+{
+	struct event *event;
+
+	for (event = event_list; event; event = event->next) {
+		if (event->id == id)
+			break;
+	}
+	return event;
+}
+
+struct event *trace_find_next_event(struct event *event)
+{
+	if (!event)
+		return event_list;
+
+	return event->next;
+}
+
+static unsigned long long eval_num_arg(void *data, int size,
+				   struct event *event, struct print_arg *arg)
+{
+	unsigned long long val = 0;
+	unsigned long long left, right;
+	struct print_arg *larg;
+
+	switch (arg->type) {
+	case PRINT_NULL:
+		/* ?? */
+		return 0;
+	case PRINT_ATOM:
+		return strtoull(arg->atom.atom, NULL, 0);
+	case PRINT_FIELD:
+		if (!arg->field.field) {
+			arg->field.field = find_any_field(event, arg->field.name);
+			if (!arg->field.field)
+				die("field %s not found", arg->field.name);
+		}
+		/* must be a number */
+		val = read_size(data + arg->field.field->offset,
+				arg->field.field->size);
+		break;
+	case PRINT_FLAGS:
+	case PRINT_SYMBOL:
+		break;
+	case PRINT_TYPE:
+		return eval_num_arg(data, size, event, arg->typecast.item);
+	case PRINT_STRING:
+		return 0;
+		break;
+	case PRINT_OP:
+		if (strcmp(arg->op.op, "[") == 0) {
+			/*
+			 * Arrays are special, since we don't want
+			 * to read the arg as is.
+			 */
+			if (arg->op.left->type != PRINT_FIELD)
+				goto default_op; /* oops, all bets off */
+			larg = arg->op.left;
+			if (!larg->field.field) {
+				larg->field.field =
+					find_any_field(event, larg->field.name);
+				if (!larg->field.field)
+					die("field %s not found", larg->field.name);
+			}
+			right = eval_num_arg(data, size, event, arg->op.right);
+			val = read_size(data + larg->field.field->offset +
+					right * long_size, long_size);
+			break;
+		}
+ default_op:
+		left = eval_num_arg(data, size, event, arg->op.left);
+		right = eval_num_arg(data, size, event, arg->op.right);
+		switch (arg->op.op[0]) {
+		case '|':
+			if (arg->op.op[1])
+				val = left || right;
+			else
+				val = left | right;
+			break;
+		case '&':
+			if (arg->op.op[1])
+				val = left && right;
+			else
+				val = left & right;
+			break;
+		case '<':
+			switch (arg->op.op[1]) {
+			case 0:
+				val = left < right;
+				break;
+			case '<':
+				val = left << right;
+				break;
+			case '=':
+				val = left <= right;
+				break;
+			default:
+				die("unknown op '%s'", arg->op.op);
+			}
+			break;
+		case '>':
+			switch (arg->op.op[1]) {
+			case 0:
+				val = left > right;
+				break;
+			case '>':
+				val = left >> right;
+				break;
+			case '=':
+				val = left >= right;
+				break;
+			default:
+				die("unknown op '%s'", arg->op.op);
+			}
+			break;
+		case '=':
+			if (arg->op.op[1] != '=')
+				die("unknown op '%s'", arg->op.op);
+			val = left == right;
+			break;
+		case '-':
+			val = left - right;
+			break;
+		case '+':
+			val = left + right;
+			break;
+		default:
+			die("unknown op '%s'", arg->op.op);
+		}
+		break;
+	default: /* not sure what to do there */
+		return 0;
+	}
+	return val;
+}
+
+struct flag {
+	const char *name;
+	unsigned long long value;
+};
+
+static const struct flag flags[] = {
+	{ "HI_SOFTIRQ", 0 },
+	{ "TIMER_SOFTIRQ", 1 },
+	{ "NET_TX_SOFTIRQ", 2 },
+	{ "NET_RX_SOFTIRQ", 3 },
+	{ "BLOCK_SOFTIRQ", 4 },
+	{ "BLOCK_IOPOLL_SOFTIRQ", 5 },
+	{ "TASKLET_SOFTIRQ", 6 },
+	{ "SCHED_SOFTIRQ", 7 },
+	{ "HRTIMER_SOFTIRQ", 8 },
+	{ "RCU_SOFTIRQ", 9 },
+
+	{ "HRTIMER_NORESTART", 0 },
+	{ "HRTIMER_RESTART", 1 },
+};
+
+unsigned long long eval_flag(const char *flag)
+{
+	int i;
+
+	/*
+	 * Some flags in the format files do not get converted.
+	 * If the flag is not numeric, see if it is something that
+	 * we already know about.
+	 */
+	if (isdigit(flag[0]))
+		return strtoull(flag, NULL, 0);
+
+	for (i = 0; i < (int)(sizeof(flags)/sizeof(flags[0])); i++)
+		if (strcmp(flags[i].name, flag) == 0)
+			return flags[i].value;
+
+	return 0;
+}
+
+static void print_str_arg(void *data, int size,
+			  struct event *event, struct print_arg *arg)
+{
+	struct print_flag_sym *flag;
+	unsigned long long val, fval;
+	char *str;
+	int print;
+
+	switch (arg->type) {
+	case PRINT_NULL:
+		/* ?? */
+		return;
+	case PRINT_ATOM:
+		printf("%s", arg->atom.atom);
+		return;
+	case PRINT_FIELD:
+		if (!arg->field.field) {
+			arg->field.field = find_any_field(event, arg->field.name);
+			if (!arg->field.field)
+				die("field %s not found", arg->field.name);
+		}
+		str = malloc_or_die(arg->field.field->size + 1);
+		memcpy(str, data + arg->field.field->offset,
+		       arg->field.field->size);
+		str[arg->field.field->size] = 0;
+		printf("%s", str);
+		free(str);
+		break;
+	case PRINT_FLAGS:
+		val = eval_num_arg(data, size, event, arg->flags.field);
+		print = 0;
+		for (flag = arg->flags.flags; flag; flag = flag->next) {
+			fval = eval_flag(flag->value);
+			if (!val && !fval) {
+				printf("%s", flag->str);
+				break;
+			}
+			if (fval && (val & fval) == fval) {
+				if (print && arg->flags.delim)
+					printf("%s", arg->flags.delim);
+				printf("%s", flag->str);
+				print = 1;
+				val &= ~fval;
+			}
+		}
+		break;
+	case PRINT_SYMBOL:
+		val = eval_num_arg(data, size, event, arg->symbol.field);
+		for (flag = arg->symbol.symbols; flag; flag = flag->next) {
+			fval = eval_flag(flag->value);
+			if (val == fval) {
+				printf("%s", flag->str);
+				break;
+			}
+		}
+		break;
+
+	case PRINT_TYPE:
+		break;
+	case PRINT_STRING: {
+		int str_offset;
+
+		if (arg->string.offset == -1) {
+			struct format_field *f;
+
+			f = find_any_field(event, arg->string.string);
+			arg->string.offset = f->offset;
+		}
+		str_offset = *(int *)(data + arg->string.offset);
+		str_offset &= 0xffff;
+		printf("%s", ((char *)data) + str_offset);
+		break;
+	}
+	case PRINT_OP:
+		/*
+		 * The only op for string should be ? :
+		 */
+		if (arg->op.op[0] != '?')
+			return;
+		val = eval_num_arg(data, size, event, arg->op.left);
+		if (val)
+			print_str_arg(data, size, event, arg->op.right->op.left);
+		else
+			print_str_arg(data, size, event, arg->op.right->op.right);
+		break;
+	default:
+		/* well... */
+		break;
+	}
+}
+
+static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struct event *event)
+{
+	static struct format_field *field, *ip_field;
+	struct print_arg *args, *arg, **next;
+	unsigned long long ip, val;
+	char *ptr;
+	void *bptr;
+
+	if (!field) {
+		field = find_field(event, "buf");
+		if (!field)
+			die("can't find buffer field for binary printk");
+		ip_field = find_field(event, "ip");
+		if (!ip_field)
+			die("can't find ip field for binary printk");
+	}
+
+	ip = read_size(data + ip_field->offset, ip_field->size);
+
+	/*
+	 * The first arg is the IP pointer.
+	 */
+	args = malloc_or_die(sizeof(*args));
+	arg = args;
+	arg->next = NULL;
+	next = &arg->next;
+
+	arg->type = PRINT_ATOM;
+	arg->atom.atom = malloc_or_die(32);
+	sprintf(arg->atom.atom, "%lld", ip);
+
+	/* skip the first "%pf : " */
+	for (ptr = fmt + 6, bptr = data + field->offset;
+	     bptr < data + size && *ptr; ptr++) {
+		int ls = 0;
+
+		if (*ptr == '%') {
+ process_again:
+			ptr++;
+			switch (*ptr) {
+			case '%':
+				break;
+			case 'l':
+				ls++;
+				goto process_again;
+			case 'L':
+				ls = 2;
+				goto process_again;
+			case '0' ... '9':
+				goto process_again;
+			case 'p':
+				ls = 1;
+				/* fall through */
+			case 'd':
+			case 'u':
+			case 'x':
+			case 'i':
+				/* the pointers are always 4 bytes aligned */
+				bptr = (void *)(((unsigned long)bptr + 3) &
+						~3);
+				switch (ls) {
+				case 0:
+				case 1:
+					ls = long_size;
+					break;
+				case 2:
+					ls = 8;
+				default:
+					break;
+				}
+				val = read_size(bptr, ls);
+				bptr += ls;
+				arg = malloc_or_die(sizeof(*arg));
+				arg->next = NULL;
+				arg->type = PRINT_ATOM;
+				arg->atom.atom = malloc_or_die(32);
+				sprintf(arg->atom.atom, "%lld", val);
+				*next = arg;
+				next = &arg->next;
+				break;
+			case 's':
+				arg = malloc_or_die(sizeof(*arg));
+				arg->next = NULL;
+				arg->type = PRINT_STRING;
+				arg->string.string = strdup(bptr);
+				bptr += strlen(bptr) + 1;
+				*next = arg;
+				next = &arg->next;
+			default:
+				break;
+			}
+		}
+	}
+
+	return args;
+}
+
+static void free_args(struct print_arg *args)
+{
+	struct print_arg *next;
+
+	while (args) {
+		next = args->next;
+
+		if (args->type == PRINT_ATOM)
+			free(args->atom.atom);
+		else
+			free(args->string.string);
+		free(args);
+		args = next;
+	}
+}
+
+static char *get_bprint_format(void *data, int size __unused, struct event *event)
+{
+	unsigned long long addr;
+	static struct format_field *field;
+	struct printk_map *printk;
+	char *format;
+	char *p;
+
+	if (!field) {
+		field = find_field(event, "fmt");
+		if (!field)
+			die("can't find format field for binary printk");
+		printf("field->offset = %d size=%d\n", field->offset, field->size);
+	}
+
+	addr = read_size(data + field->offset, field->size);
+
+	printk = find_printk(addr);
+	if (!printk) {
+		format = malloc_or_die(45);
+		sprintf(format, "%%pf : (NO FORMAT FOUND at %llx)\n",
+			addr);
+		return format;
+	}
+
+	p = printk->printk;
+	/* Remove any quotes. */
+	if (*p == '"')
+		p++;
+	format = malloc_or_die(strlen(p) + 10);
+	sprintf(format, "%s : %s", "%pf", p);
+	/* remove ending quotes and new line since we will add one too */
+	p = format + strlen(format) - 1;
+	if (*p == '"')
+		*p = 0;
+
+	p -= 2;
+	if (strcmp(p, "\\n") == 0)
+		*p = 0;
+
+	return format;
+}
+
+static void pretty_print(void *data, int size, struct event *event)
+{
+	struct print_fmt *print_fmt = &event->print_fmt;
+	struct print_arg *arg = print_fmt->args;
+	struct print_arg *args = NULL;
+	const char *ptr = print_fmt->format;
+	unsigned long long val;
+	struct func_map *func;
+	const char *saveptr;
+	char *bprint_fmt = NULL;
+	char format[32];
+	int show_func;
+	int len;
+	int ls;
+
+	if (event->flags & EVENT_FL_ISFUNC)
+		ptr = " %pF <-- %pF";
+
+	if (event->flags & EVENT_FL_ISBPRINT) {
+		bprint_fmt = get_bprint_format(data, size, event);
+		args = make_bprint_args(bprint_fmt, data, size, event);
+		arg = args;
+		ptr = bprint_fmt;
+	}
+
+	for (; *ptr; ptr++) {
+		ls = 0;
+		if (*ptr == '\\') {
+			ptr++;
+			switch (*ptr) {
+			case 'n':
+				printf("\n");
+				break;
+			case 't':
+				printf("\t");
+				break;
+			case 'r':
+				printf("\r");
+				break;
+			case '\\':
+				printf("\\");
+				break;
+			default:
+				printf("%c", *ptr);
+				break;
+			}
+
+		} else if (*ptr == '%') {
+			saveptr = ptr;
+			show_func = 0;
+ cont_process:
+			ptr++;
+			switch (*ptr) {
+			case '%':
+				printf("%%");
+				break;
+			case 'l':
+				ls++;
+				goto cont_process;
+			case 'L':
+				ls = 2;
+				goto cont_process;
+			case 'z':
+			case 'Z':
+			case '0' ... '9':
+				goto cont_process;
+			case 'p':
+				if (long_size == 4)
+					ls = 1;
+				else
+					ls = 2;
+
+				if (*(ptr+1) == 'F' ||
+				    *(ptr+1) == 'f') {
+					ptr++;
+					show_func = *ptr;
+				}
+
+				/* fall through */
+			case 'd':
+			case 'i':
+			case 'x':
+			case 'X':
+			case 'u':
+				if (!arg)
+					die("no argument match");
+
+				len = ((unsigned long)ptr + 1) -
+					(unsigned long)saveptr;
+
+				/* should never happen */
+				if (len > 32)
+					die("bad format!");
+
+				memcpy(format, saveptr, len);
+				format[len] = 0;
+
+				val = eval_num_arg(data, size, event, arg);
+				arg = arg->next;
+
+				if (show_func) {
+					func = find_func(val);
+					if (func) {
+						printf("%s", func->func);
+						if (show_func == 'F')
+							printf("+0x%llx",
+							       val - func->addr);
+						break;
+					}
+				}
+				switch (ls) {
+				case 0:
+					printf(format, (int)val);
+					break;
+				case 1:
+					printf(format, (long)val);
+					break;
+				case 2:
+					printf(format, (long long)val);
+					break;
+				default:
+					die("bad count (%d)", ls);
+				}
+				break;
+			case 's':
+				if (!arg)
+					die("no matching argument");
+
+				print_str_arg(data, size, event, arg);
+				arg = arg->next;
+				break;
+			default:
+				printf(">%c<", *ptr);
+
+			}
+		} else
+			printf("%c", *ptr);
+	}
+
+	if (args) {
+		free_args(args);
+		free(bprint_fmt);
+	}
+}
+
+static inline int log10_cpu(int nb)
+{
+	if (nb / 100)
+		return 3;
+	if (nb / 10)
+		return 2;
+	return 1;
+}
+
+static void print_lat_fmt(void *data, int size __unused)
+{
+	unsigned int lat_flags;
+	unsigned int pc;
+	int lock_depth;
+	int hardirq;
+	int softirq;
+
+	lat_flags = parse_common_flags(data);
+	pc = parse_common_pc(data);
+	lock_depth = parse_common_lock_depth(data);
+
+	hardirq = lat_flags & TRACE_FLAG_HARDIRQ;
+	softirq = lat_flags & TRACE_FLAG_SOFTIRQ;
+
+	printf("%c%c%c",
+	       (lat_flags & TRACE_FLAG_IRQS_OFF) ? 'd' :
+	       (lat_flags & TRACE_FLAG_IRQS_NOSUPPORT) ?
+	       'X' : '.',
+	       (lat_flags & TRACE_FLAG_NEED_RESCHED) ?
+	       'N' : '.',
+	       (hardirq && softirq) ? 'H' :
+	       hardirq ? 'h' : softirq ? 's' : '.');
+
+	if (pc)
+		printf("%x", pc);
+	else
+		printf(".");
+
+	if (lock_depth < 0)
+		printf(". ");
+	else
+		printf("%d ", lock_depth);
+}
+
+#define TRACE_GRAPH_INDENT	2
+
+static struct record *
+get_return_for_leaf(int cpu, int cur_pid, unsigned long long cur_func,
+		    struct record *next)
+{
+	struct format_field *field;
+	struct event *event;
+	unsigned long val;
+	int type;
+	int pid;
+
+	type = trace_parse_common_type(next->data);
+	event = trace_find_event(type);
+	if (!event)
+		return NULL;
+
+	if (!(event->flags & EVENT_FL_ISFUNCRET))
+		return NULL;
+
+	pid = trace_parse_common_pid(next->data);
+	field = find_field(event, "func");
+	if (!field)
+		die("function return does not have field func");
+
+	val = read_size(next->data + field->offset, field->size);
+
+	if (cur_pid != pid || cur_func != val)
+		return NULL;
+
+	/* this is a leaf, now advance the iterator */
+	return trace_read_data(cpu);
+}
+
+/* Signal a overhead of time execution to the output */
+static void print_graph_overhead(unsigned long long duration)
+{
+	/* Non nested entry or return */
+	if (duration == ~0ULL)
+		return (void)printf("  ");
+
+	/* Duration exceeded 100 msecs */
+	if (duration > 100000ULL)
+		return (void)printf("! ");
+
+	/* Duration exceeded 10 msecs */
+	if (duration > 10000ULL)
+		return (void)printf("+ ");
+
+	printf("  ");
+}
+
+static void print_graph_duration(unsigned long long duration)
+{
+	unsigned long usecs = duration / 1000;
+	unsigned long nsecs_rem = duration % 1000;
+	/* log10(ULONG_MAX) + '\0' */
+	char msecs_str[21];
+	char nsecs_str[5];
+	int len;
+	int i;
+
+	sprintf(msecs_str, "%lu", usecs);
+
+	/* Print msecs */
+	len = printf("%lu", usecs);
+
+	/* Print nsecs (we don't want to exceed 7 numbers) */
+	if (len < 7) {
+		snprintf(nsecs_str, 8 - len, "%03lu", nsecs_rem);
+		len += printf(".%s", nsecs_str);
+	}
+
+	printf(" us ");
+
+	/* Print remaining spaces to fit the row's width */
+	for (i = len; i < 7; i++)
+		printf(" ");
+
+	printf("|  ");
+}
+
+static void
+print_graph_entry_leaf(struct event *event, void *data, struct record *ret_rec)
+{
+	unsigned long long rettime, calltime;
+	unsigned long long duration, depth;
+	unsigned long long val;
+	struct format_field *field;
+	struct func_map *func;
+	struct event *ret_event;
+	int type;
+	int i;
+
+	type = trace_parse_common_type(ret_rec->data);
+	ret_event = trace_find_event(type);
+
+	field = find_field(ret_event, "rettime");
+	if (!field)
+		die("can't find rettime in return graph");
+	rettime = read_size(ret_rec->data + field->offset, field->size);
+
+	field = find_field(ret_event, "calltime");
+	if (!field)
+		die("can't find rettime in return graph");
+	calltime = read_size(ret_rec->data + field->offset, field->size);
+
+	duration = rettime - calltime;
+
+	/* Overhead */
+	print_graph_overhead(duration);
+
+	/* Duration */
+	print_graph_duration(duration);
+
+	field = find_field(event, "depth");
+	if (!field)
+		die("can't find depth in entry graph");
+	depth = read_size(data + field->offset, field->size);
+
+	/* Function */
+	for (i = 0; i < (int)(depth * TRACE_GRAPH_INDENT); i++)
+		printf(" ");
+
+	field = find_field(event, "func");
+	if (!field)
+		die("can't find func in entry graph");
+	val = read_size(data + field->offset, field->size);
+	func = find_func(val);
+
+	if (func)
+		printf("%s();", func->func);
+	else
+		printf("%llx();", val);
+}
+
+static void print_graph_nested(struct event *event, void *data)
+{
+	struct format_field *field;
+	unsigned long long depth;
+	unsigned long long val;
+	struct func_map *func;
+	int i;
+
+	/* No overhead */
+	print_graph_overhead(-1);
+
+	/* No time */
+	printf("           |  ");
+
+	field = find_field(event, "depth");
+	if (!field)
+		die("can't find depth in entry graph");
+	depth = read_size(data + field->offset, field->size);
+
+	/* Function */
+	for (i = 0; i < (int)(depth * TRACE_GRAPH_INDENT); i++)
+		printf(" ");
+
+	field = find_field(event, "func");
+	if (!field)
+		die("can't find func in entry graph");
+	val = read_size(data + field->offset, field->size);
+	func = find_func(val);
+
+	if (func)
+		printf("%s() {", func->func);
+	else
+		printf("%llx() {", val);
+}
+
+static void
+pretty_print_func_ent(void *data, int size, struct event *event,
+		      int cpu, int pid)
+{
+	struct format_field *field;
+	struct record *rec;
+	void *copy_data;
+	unsigned long val;
+
+	if (latency_format) {
+		print_lat_fmt(data, size);
+		printf(" | ");
+	}
+
+	field = find_field(event, "func");
+	if (!field)
+		die("function entry does not have func field");
+
+	val = read_size(data + field->offset, field->size);
+
+	/*
+	 * peek_data may unmap the data pointer. Copy it first.
+	 */
+	copy_data = malloc_or_die(size);
+	memcpy(copy_data, data, size);
+	data = copy_data;
+
+	rec = trace_peek_data(cpu);
+	if (rec) {
+		rec = get_return_for_leaf(cpu, pid, val, rec);
+		if (rec) {
+			print_graph_entry_leaf(event, data, rec);
+			goto out_free;
+		}
+	}
+	print_graph_nested(event, data);
+out_free:
+	free(data);
+}
+
+static void
+pretty_print_func_ret(void *data, int size __unused, struct event *event)
+{
+	unsigned long long rettime, calltime;
+	unsigned long long duration, depth;
+	struct format_field *field;
+	int i;
+
+	if (latency_format) {
+		print_lat_fmt(data, size);
+		printf(" | ");
+	}
+
+	field = find_field(event, "rettime");
+	if (!field)
+		die("can't find rettime in return graph");
+	rettime = read_size(data + field->offset, field->size);
+
+	field = find_field(event, "calltime");
+	if (!field)
+		die("can't find calltime in return graph");
+	calltime = read_size(data + field->offset, field->size);
+
+	duration = rettime - calltime;
+
+	/* Overhead */
+	print_graph_overhead(duration);
+
+	/* Duration */
+	print_graph_duration(duration);
+
+	field = find_field(event, "depth");
+	if (!field)
+		die("can't find depth in entry graph");
+	depth = read_size(data + field->offset, field->size);
+
+	/* Function */
+	for (i = 0; i < (int)(depth * TRACE_GRAPH_INDENT); i++)
+		printf(" ");
+
+	printf("}");
+}
+
+static void
+pretty_print_func_graph(void *data, int size, struct event *event,
+			int cpu, int pid)
+{
+	if (event->flags & EVENT_FL_ISFUNCENT)
+		pretty_print_func_ent(data, size, event, cpu, pid);
+	else if (event->flags & EVENT_FL_ISFUNCRET)
+		pretty_print_func_ret(data, size, event);
+	printf("\n");
+}
+
+void print_trace_event(int cpu, void *data, int size)
+{
+	struct event *event;
+	int type;
+	int pid;
+
+	type = trace_parse_common_type(data);
+
+	event = trace_find_event(type);
+	if (!event) {
+		warning("ug! no event found for type %d", type);
+		return;
+	}
+
+	pid = trace_parse_common_pid(data);
+
+	if (event->flags & (EVENT_FL_ISFUNCENT | EVENT_FL_ISFUNCRET))
+		return pretty_print_func_graph(data, size, event, cpu, pid);
+
+	if (latency_format)
+		print_lat_fmt(data, size);
+
+	if (event->flags & EVENT_FL_FAILED) {
+		printf("EVENT '%s' FAILED TO PARSE\n",
+		       event->name);
+		return;
+	}
+
+	pretty_print(data, size, event);
+}
+
+static void print_fields(struct print_flag_sym *field)
+{
+	printf("{ %s, %s }", field->value, field->str);
+	if (field->next) {
+		printf(", ");
+		print_fields(field->next);
+	}
+}
+
+static void print_args(struct print_arg *args)
+{
+	int print_paren = 1;
+
+	switch (args->type) {
+	case PRINT_NULL:
+		printf("null");
+		break;
+	case PRINT_ATOM:
+		printf("%s", args->atom.atom);
+		break;
+	case PRINT_FIELD:
+		printf("REC->%s", args->field.name);
+		break;
+	case PRINT_FLAGS:
+		printf("__print_flags(");
+		print_args(args->flags.field);
+		printf(", %s, ", args->flags.delim);
+		print_fields(args->flags.flags);
+		printf(")");
+		break;
+	case PRINT_SYMBOL:
+		printf("__print_symbolic(");
+		print_args(args->symbol.field);
+		printf(", ");
+		print_fields(args->symbol.symbols);
+		printf(")");
+		break;
+	case PRINT_STRING:
+		printf("__get_str(%s)", args->string.string);
+		break;
+	case PRINT_TYPE:
+		printf("(%s)", args->typecast.type);
+		print_args(args->typecast.item);
+		break;
+	case PRINT_OP:
+		if (strcmp(args->op.op, ":") == 0)
+			print_paren = 0;
+		if (print_paren)
+			printf("(");
+		print_args(args->op.left);
+		printf(" %s ", args->op.op);
+		print_args(args->op.right);
+		if (print_paren)
+			printf(")");
+		break;
+	default:
+		/* we should warn... */
+		return;
+	}
+	if (args->next) {
+		printf("\n");
+		print_args(args->next);
+	}
+}
+
+int parse_ftrace_file(char *buf, unsigned long size)
+{
+	struct format_field *field;
+	struct print_arg *arg, **list;
+	struct event *event;
+	int ret;
+
+	init_input_buf(buf, size);
+
+	event = alloc_event();
+	if (!event)
+		return -ENOMEM;
+
+	event->flags |= EVENT_FL_ISFTRACE;
+
+	event->name = event_read_name();
+	if (!event->name)
+		die("failed to read ftrace event name");
+
+	if (strcmp(event->name, "function") == 0)
+		event->flags |= EVENT_FL_ISFUNC;
+
+	else if (strcmp(event->name, "funcgraph_entry") == 0)
+		event->flags |= EVENT_FL_ISFUNCENT;
+
+	else if (strcmp(event->name, "funcgraph_exit") == 0)
+		event->flags |= EVENT_FL_ISFUNCRET;
+
+	else if (strcmp(event->name, "bprint") == 0)
+		event->flags |= EVENT_FL_ISBPRINT;
+
+	event->id = event_read_id();
+	if (event->id < 0)
+		die("failed to read ftrace event id");
+
+	add_event(event);
+
+	ret = event_read_format(event);
+	if (ret < 0)
+		die("failed to read ftrace event format");
+
+	ret = event_read_print(event);
+	if (ret < 0)
+		die("failed to read ftrace event print fmt");
+
+	/* New ftrace handles args */
+	if (ret > 0)
+		return 0;
+	/*
+	 * The arguments for ftrace files are parsed by the fields.
+	 * Set up the fields as their arguments.
+	 */
+	list = &event->print_fmt.args;
+	for (field = event->format.fields; field; field = field->next) {
+		arg = malloc_or_die(sizeof(*arg));
+		memset(arg, 0, sizeof(*arg));
+		*list = arg;
+		list = &arg->next;
+		arg->type = PRINT_FIELD;
+		arg->field.name = field->name;
+		arg->field.field = field;
+	}
+	return 0;
+}
+
+int parse_event_file(char *buf, unsigned long size, char *sys)
+{
+	struct event *event;
+	int ret;
+
+	init_input_buf(buf, size);
+
+	event = alloc_event();
+	if (!event)
+		return -ENOMEM;
+
+	event->name = event_read_name();
+	if (!event->name)
+		die("failed to read event name");
+
+	event->id = event_read_id();
+	if (event->id < 0)
+		die("failed to read event id");
+
+	ret = event_read_format(event);
+	if (ret < 0) {
+		warning("failed to read event format for %s", event->name);
+		goto event_failed;
+	}
+
+	ret = event_read_print(event);
+	if (ret < 0) {
+		warning("failed to read event print fmt for %s", event->name);
+		goto event_failed;
+	}
+
+	event->system = strdup(sys);
+
+#define PRINT_ARGS 0
+	if (PRINT_ARGS && event->print_fmt.args)
+		print_args(event->print_fmt.args);
+
+	add_event(event);
+	return 0;
+
+ event_failed:
+	event->flags |= EVENT_FL_FAILED;
+	/* still add it even if it failed */
+	add_event(event);
+	return -1;
+}
+
+void parse_set_info(int nr_cpus, int long_sz)
+{
+	cpus = nr_cpus;
+	long_size = long_sz;
+}
diff --git a/tools/perf/util/trace-parse-events.h b/tools/perf/util/trace-parse-events.h
new file mode 100644
index 0000000..794ec15
--- /dev/null
+++ b/tools/perf/util/trace-parse-events.h
@@ -0,0 +1,273 @@
+#ifndef __PERF_TRACE_EVENTS_H
+#define __PERF_TRACE_EVENTS_H
+
+#include <stdbool.h>
+#include <unistd.h>
+
+#define __unused __attribute__((unused))
+
+
+#ifndef PAGE_MASK
+#define PAGE_MASK (page_size - 1)
+#endif
+
+enum {
+	RINGBUF_TYPE_PADDING		= 29,
+	RINGBUF_TYPE_TIME_EXTEND	= 30,
+	RINGBUF_TYPE_TIME_STAMP		= 31,
+};
+
+#ifndef TS_SHIFT
+#define TS_SHIFT		27
+#endif
+
+#define NSECS_PER_SEC		1000000000ULL
+#define NSECS_PER_USEC		1000ULL
+
+enum format_flags {
+	FIELD_IS_ARRAY		= 1,
+	FIELD_IS_POINTER	= 2,
+	FIELD_IS_SIGNED		= 4,
+	FIELD_IS_STRING		= 8,
+	FIELD_IS_DYNAMIC	= 16,
+	FIELD_IS_FLAG		= 32,
+	FIELD_IS_SYMBOLIC	= 64,
+};
+
+struct format_field {
+	struct format_field	*next;
+	char			*type;
+	char			*name;
+	int			offset;
+	int			size;
+	unsigned long		flags;
+};
+
+struct format {
+	int			nr_common;
+	int			nr_fields;
+	struct format_field	*common_fields;
+	struct format_field	*fields;
+};
+
+struct print_arg_atom {
+	char			*atom;
+};
+
+struct print_arg_string {
+	char			*string;
+	int			offset;
+};
+
+struct print_arg_field {
+	char			*name;
+	struct format_field	*field;
+};
+
+struct print_flag_sym {
+	struct print_flag_sym	*next;
+	char			*value;
+	char			*str;
+};
+
+struct print_arg_typecast {
+	char			*type;
+	struct print_arg	*item;
+};
+
+struct print_arg_flags {
+	struct print_arg	*field;
+	char			*delim;
+	struct print_flag_sym	*flags;
+};
+
+struct print_arg_symbol {
+	struct print_arg	*field;
+	struct print_flag_sym	*symbols;
+};
+
+struct print_arg;
+
+struct print_arg_op {
+	char			*op;
+	int			prio;
+	struct print_arg	*left;
+	struct print_arg	*right;
+};
+
+struct print_arg_func {
+	char			*name;
+	struct print_arg	*args;
+};
+
+enum print_arg_type {
+	PRINT_NULL,
+	PRINT_ATOM,
+	PRINT_FIELD,
+	PRINT_FLAGS,
+	PRINT_SYMBOL,
+	PRINT_TYPE,
+	PRINT_STRING,
+	PRINT_OP,
+};
+
+struct print_arg {
+	struct print_arg		*next;
+	enum print_arg_type		type;
+	union {
+		struct print_arg_atom		atom;
+		struct print_arg_field		field;
+		struct print_arg_typecast	typecast;
+		struct print_arg_flags		flags;
+		struct print_arg_symbol		symbol;
+		struct print_arg_func		func;
+		struct print_arg_string		string;
+		struct print_arg_op		op;
+	};
+};
+
+struct print_fmt {
+	char			*format;
+	struct print_arg	*args;
+};
+
+struct event {
+	struct event		*next;
+	char			*name;
+	int			id;
+	int			flags;
+	struct format		format;
+	struct print_fmt	print_fmt;
+	char			*system;
+};
+
+enum {
+	EVENT_FL_ISFTRACE	= 0x01,
+	EVENT_FL_ISPRINT	= 0x02,
+	EVENT_FL_ISBPRINT	= 0x04,
+	EVENT_FL_ISFUNC		= 0x08,
+	EVENT_FL_ISFUNCENT	= 0x10,
+	EVENT_FL_ISFUNCRET	= 0x20,
+
+	EVENT_FL_FAILED		= 0x80000000
+};
+
+struct record {
+	unsigned long long ts;
+	int size;
+	void *data;
+};
+
+struct record *trace_peek_data(int cpu);
+struct record *trace_read_data(int cpu);
+
+void parse_set_info(int nr_cpus, int long_sz);
+
+ssize_t trace_report(int fd, bool repipe);
+
+void *malloc_or_die(unsigned int size);
+
+void parse_cmdlines(char *file, int size);
+void parse_proc_kallsyms(char *file, unsigned int size);
+void parse_ftrace_printk(char *file, unsigned int size);
+
+void print_funcs(void);
+void print_printk(void);
+
+int parse_ftrace_file(char *buf, unsigned long size);
+int parse_event_file(char *buf, unsigned long size, char *sys);
+void print_trace_event(int cpu, void *data, int size);
+
+extern int file_bigendian;
+extern int host_bigendian;
+
+int bigendian(void);
+
+static inline unsigned short __data2host2(unsigned short data)
+{
+	unsigned short swap;
+
+	if (host_bigendian == file_bigendian)
+		return data;
+
+	swap = ((data & 0xffULL) << 8) |
+		((data & (0xffULL << 8)) >> 8);
+
+	return swap;
+}
+
+static inline unsigned int __data2host4(unsigned int data)
+{
+	unsigned int swap;
+
+	if (host_bigendian == file_bigendian)
+		return data;
+
+	swap = ((data & 0xffULL) << 24) |
+		((data & (0xffULL << 8)) << 8) |
+		((data & (0xffULL << 16)) >> 8) |
+		((data & (0xffULL << 24)) >> 24);
+
+	return swap;
+}
+
+static inline unsigned long long __data2host8(unsigned long long data)
+{
+	unsigned long long swap;
+
+	if (host_bigendian == file_bigendian)
+		return data;
+
+	swap = ((data & 0xffULL) << 56) |
+		((data & (0xffULL << 8)) << 40) |
+		((data & (0xffULL << 16)) << 24) |
+		((data & (0xffULL << 24)) << 8) |
+		((data & (0xffULL << 32)) >> 8) |
+		((data & (0xffULL << 40)) >> 24) |
+		((data & (0xffULL << 48)) >> 40) |
+		((data & (0xffULL << 56)) >> 56);
+
+	return swap;
+}
+
+#define data2host2(ptr)		__data2host2(*(unsigned short *)ptr)
+#define data2host4(ptr)		__data2host4(*(unsigned int *)ptr)
+#define data2host8(ptr)		({				\
+	unsigned long long __val;				\
+								\
+	memcpy(&__val, (ptr), sizeof(unsigned long long));	\
+	__data2host8(__val);					\
+})
+
+extern int header_page_ts_offset;
+extern int header_page_ts_size;
+extern int header_page_size_offset;
+extern int header_page_size_size;
+extern int header_page_data_offset;
+extern int header_page_data_size;
+
+extern bool latency_format;
+
+int trace_parse_common_type(void *data);
+int trace_parse_common_pid(void *data);
+int parse_common_pc(void *data);
+int parse_common_flags(void *data);
+int parse_common_lock_depth(void *data);
+struct event *trace_find_event(int id);
+struct event *trace_find_next_event(struct event *event);
+unsigned long long read_size(void *ptr, int size);
+unsigned long long
+raw_field_value(struct event *event, const char *name, void *data);
+void *raw_field_ptr(struct event *event, const char *name, void *data);
+unsigned long long eval_flag(const char *flag);
+
+/* taken from kernel/trace/trace.h */
+enum trace_flag_type {
+	TRACE_FLAG_IRQS_OFF		= 0x01,
+	TRACE_FLAG_IRQS_NOSUPPORT	= 0x02,
+	TRACE_FLAG_NEED_RESCHED		= 0x04,
+	TRACE_FLAG_HARDIRQ		= 0x08,
+	TRACE_FLAG_SOFTIRQ		= 0x10,
+};
+
+#endif /* __PERF_TRACE_EVENTS_H */
-- 
1.7.5.4


  reply	other threads:[~2012-04-05 22:48 UTC|newest]

Thread overview: 51+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-04-05 22:47 [RFC][PATCH 00/15] tools: Unify perf and trace-cmd trace event format parsing v2 Frederic Weisbecker
2012-04-05 22:47 ` Frederic Weisbecker [this message]
2012-04-06 11:36   ` [PATCH 01/15] perf: Separate out trace-cmd parse-events from perf files Borislav Petkov
2012-04-06 15:23     ` Frederic Weisbecker
2012-04-05 22:47 ` [PATCH 02/15] tools/events: Add files to create libtraceevent.a Frederic Weisbecker
2012-04-06  0:08   ` David Ahern
2012-04-06  0:18     ` Steven Rostedt
2012-04-06  0:24       ` David Ahern
2012-04-06 11:40   ` Borislav Petkov
2012-04-06 13:21   ` Borislav Petkov
2012-04-06 22:15     ` Steven Rostedt
2012-04-07  9:08       ` Borislav Petkov
2012-04-11 15:20   ` Arnaldo Carvalho de Melo
2012-04-11 15:38     ` Steven Rostedt
2012-04-11 17:47       ` Frederic Weisbecker
2012-04-11 17:54       ` Arnaldo Carvalho de Melo
2012-04-05 22:47 ` [PATCH 03/15] perf: Build libtraceevent.a Frederic Weisbecker
2012-04-06 11:45   ` Borislav Petkov
2012-04-06 15:26     ` Frederic Weisbecker
2012-04-06 15:51       ` Borislav Petkov
2012-04-09 17:10         ` Frederic Weisbecker
2012-04-05 22:47 ` [PATCH 04/15] events: Update tools/lib/traceevent to work with perf Frederic Weisbecker
2012-04-06 11:48   ` Borislav Petkov
2012-04-09 17:11     ` Frederic Weisbecker
2012-04-05 22:47 ` [PATCH 05/15] perf: Have perf use the new libtraceevent.a library Frederic Weisbecker
2012-04-05 22:47 ` [PATCH 06/15] perf/events: Add flag to produce nsec output Frederic Weisbecker
2012-04-05 22:47 ` [PATCH 07/15] perf/events: Add flag/symbol format_flags Frederic Weisbecker
2012-04-05 22:47 ` [PATCH 08/15] perf/events: Correct size given to memset Frederic Weisbecker
2012-04-06 11:24   ` Borislav Petkov
2012-04-06 12:00     ` Borislav Petkov
2012-04-06 12:27       ` Steven Rostedt
2012-04-05 22:48 ` [PATCH 09/15] parse-events: Handle invalid opcode parsing gracefully Frederic Weisbecker
2012-04-05 22:48 ` [PATCH 10/15] parse-events: Handle opcode parsing error Frederic Weisbecker
2012-04-05 22:48 ` [PATCH 11/15] parse-events: Let pevent_free() take a NULL pointer Frederic Weisbecker
2012-04-05 22:48 ` [PATCH 12/15] parse-events: Support '+' opcode in print format Frederic Weisbecker
2012-04-05 22:48 ` [PATCH 13/15] parse-events: Allow '*' and '/' operations in TP_printk Frederic Weisbecker
2012-04-05 22:48 ` [PATCH 14/15] parse-event: Fix memset pointer size bug in handle Frederic Weisbecker
2012-04-05 22:48 ` [PATCH 15/15] parse-events: Rename struct record to struct pevent_record Frederic Weisbecker
2012-04-06  3:07 ` [RFC][PATCH 00/15] tools: Unify perf and trace-cmd trace event format parsing v2 David Sharp
2012-04-06 15:11   ` Frederic Weisbecker
2012-04-09 10:13 ` Namhyung Kim
2012-04-23 14:47 ` Our failure on tracing tools unification (Was: Re: [RFC][PATCH 00/15] tools: Unify perf and trace-cmd trace event format parsing v2) Frederic Weisbecker
2012-04-23 15:08   ` Peter Zijlstra
2012-04-23 15:31     ` Steven Rostedt
2012-04-23 16:07       ` Borislav Petkov
2012-04-24  9:10     ` Thomas Gleixner
2012-04-25  8:05     ` Ingo Molnar
2012-04-25 12:39       ` Frederic Weisbecker
2012-04-25 14:19       ` Our failure on tracing tools unification Frank Ch. Eigler
2012-04-25 16:37         ` Arnaldo Carvalho de Melo
2012-04-25 12:26 [PATCH 00/15] tools: Unify perf and trace-cmd trace event format parsing v3 Frederic Weisbecker
2012-04-25 12:26 ` [PATCH 01/15] perf: Separate out trace-cmd parse-events from perf files Frederic Weisbecker

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1333666086-6517-2-git-send-email-fweisbec@gmail.com \
    --to=fweisbec@gmail.com \
    --cc=acme@infradead.org \
    --cc=asharma@fb.com \
    --cc=bp@alien8.de \
    --cc=jolsa@redhat.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mingo@kernel.org \
    --cc=namhyung.kim@lge.com \
    --cc=peterz@infradead.org \
    --cc=rostedt@goodmis.org \
    --cc=srostedt@redhat.com \
    --cc=tglx@linutronix.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.