linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC][PATCH 0/8] Having perf use libparsevent.a
@ 2011-08-05 20:59 Steven Rostedt
  2011-08-05 20:59 ` [RFC][PATCH 1/8] perf: Separate out trace-cmd parse-events from perf files Steven Rostedt
                   ` (10 more replies)
  0 siblings, 11 replies; 33+ messages in thread
From: Steven Rostedt @ 2011-08-05 20:59 UTC (permalink / raw)
  To: linux-kernel
  Cc: Ingo Molnar, Thomas Gleixner, Peter Zijlstra,
	Frederic Weisbecker, Arnaldo Carvalho de Melo, Borislav Petkov,
	Arjan van de Ven

Hi All,

I've spent the week working on getting libparsevent.a working with
perf. After several rewrites, hacking in both perf and the trace-cmd
code, and breaking both beyond repair, I finally got to a point that
it just works.

The library was originally going to be called libperf.so, but after
talking with Arnaldo, he wants the functionality of the libraries
separated more, not combined all in one binary. As this code deals
only with the parsing the event formats and creating a way to read
the binary data from it, we both agreed that it is best to keep its
original name that was in trace-cmd and call it libparsevent.so.

Note, because perf installs in the user's ~/bin and I did not want to
make it a requirement to add ~/bin to LD_LIBRARY_PATH, I kept the
library as a .a that is linked directly into perf.

In the beginning, I tried to work with the library code within the
tools/perf directory, and because of the CFLAGS of perf, it made
compiling the library code very nasty (namely the -Wswitch-enum).
I also talked with Arnaldo and Frederic about the placement of this
code, and we all agreed that tools/lib/events is a good place to
put it.

By keeping the code separate from perf, made the transition from
trace-cmd to tools much easier. I've wasted too many days trying to
get other ways working, and I don't want to rewrite perf to do so.

Thus, this is what I ended up with.

This patch set just gets the libparsevent.a/so working with perf.
New code would be required to get it packaged for distributions to
ship as a library itself. Once it gets there, I'll work on getting
this code to work with code like latencytrace.

Anyway, this is still in the RFC phase. Lets hear what people have to
say.

(some of the patches are quite large as they either insert full
files or remove them, and probably will not make LKML due to the
size constraint.)

This patches can be viewed from:

  git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-2.6-trace.git
tip/perf/parse-events

Head SHA1: 781d261ff8241243173cf996ceb068cb19bd5874


Julia Lawall (1):
      perf/events: Correct size given to memset

Steven Rostedt (6):
      perf: Separate out trace-cmd parse-events from perf files
      tools/events: Add files to create libparsevent.a
      perf: Build libparsevent.a
      events: Update tools/lib/events to work with perf
      perf: Have perf use the new libparsevent.a library
      perf/events: Add flag to produce nsec output

Tom Zanussi (1):
      perf/events: Add flag/symbol format_flags

----
 tools/lib/events/Makefile                          |  303 ++
 tools/lib/events/event-parse.c                     | 4991 ++++++++++++++++++++
 tools/lib/events/event-parse.h                     |  804 ++++
 tools/lib/events/event-utils.h                     |   80 +
 tools/lib/events/parse-filter.c                    | 2262 +++++++++
 tools/lib/events/parse-utils.c                     |  110 +
 tools/lib/events/trace-seq.c                       |  200 +
 tools/perf/Makefile                                |   17 +-
 tools/perf/builtin-kmem.c                          |    6 +-
 tools/perf/builtin-lock.c                          |   26 +-
 tools/perf/builtin-sched.c                         |   42 +-
 tools/perf/builtin-script.c                        |    2 +-
 .../util/scripting-engines/trace-event-python.c    |   16 +-
 tools/perf/util/trace-event-info.c                 |    4 +-
 tools/perf/util/trace-event-parse.c                | 3188 +------------
 tools/perf/util/trace-event-read.c                 |   34 +-
 tools/perf/util/trace-event.h                      |  268 +-
 17 files changed, 9070 insertions(+), 3283 deletions(-)

^ permalink raw reply	[flat|nested] 33+ messages in thread

* [RFC][PATCH 1/8] perf: Separate out trace-cmd parse-events from perf files
  2011-08-05 20:59 [RFC][PATCH 0/8] Having perf use libparsevent.a Steven Rostedt
@ 2011-08-05 20:59 ` Steven Rostedt
  2011-08-15 16:14   ` David Ahern
  2011-08-05 20:59 ` [RFC][PATCH 2/8] tools/events: Add files to create libparsevent.a Steven Rostedt
                   ` (9 subsequent siblings)
  10 siblings, 1 reply; 33+ messages in thread
From: Steven Rostedt @ 2011-08-05 20:59 UTC (permalink / raw)
  To: linux-kernel
  Cc: Ingo Molnar, Thomas Gleixner, Peter Zijlstra,
	Frederic Weisbecker, Arnaldo Carvalho de Melo, Borislav Petkov,
	Arjan van de Ven

[-- Attachment #1: 0001-perf-Separate-out-trace-cmd-parse-events-from-perf-f.patch --]
[-- Type: text/plain, Size: 146703 bytes --]

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>
---
 tools/perf/Makefile                  |    2 +
 tools/perf/util/trace-event-parse.c  | 3125 ---------------------------------
 tools/perf/util/trace-event.h        |  274 +---
 tools/perf/util/trace-parse-events.c | 3128 ++++++++++++++++++++++++++++++++++
 tools/perf/util/trace-parse-events.h |  273 +++
 5 files changed, 3407 insertions(+), 3395 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 940257b..ebf38c1 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -278,6 +278,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/probe-event.h
 LIB_H += util/pstack.h
@@ -332,6 +333,7 @@ LIB_OBJS += $(OUTPUT)util/trace-event-parse.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 0a7ed5b..9477519 100644
--- a/tools/perf/util/trace-event-parse.c
+++ b/tools/perf/util/trace-event-parse.c
@@ -1,3132 +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.
- */
-#define _GNU_SOURCE
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include <errno.h>
-
-#undef _GNU_SOURCE
 #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;
-
-	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;
-}
-
 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 f674dda..ed5e8ed 100644
--- a/tools/perf/util/trace-event.h
+++ b/tools/perf/util/trace-event.h
@@ -1,279 +1,13 @@
-#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"
 
-#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);
 ssize_t read_tracing_data_size(int fd, struct list_head *pattrs);
 
-/* 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);
@@ -299,4 +33,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..845cb00
--- /dev/null
+++ b/tools/perf/util/trace-parse-events.c
@@ -0,0 +1,3128 @@
+/*
+ * 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.
+ */
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+
+#undef _GNU_SOURCE
+#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 ret;
+	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;
+
+	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



^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [RFC][PATCH 2/8] tools/events: Add files to create libparsevent.a
  2011-08-05 20:59 [RFC][PATCH 0/8] Having perf use libparsevent.a Steven Rostedt
  2011-08-05 20:59 ` [RFC][PATCH 1/8] perf: Separate out trace-cmd parse-events from perf files Steven Rostedt
@ 2011-08-05 20:59 ` Steven Rostedt
  2011-08-05 20:59 ` [RFC][PATCH 3/8] perf: Build libparsevent.a Steven Rostedt
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 33+ messages in thread
From: Steven Rostedt @ 2011-08-05 20:59 UTC (permalink / raw)
  To: linux-kernel
  Cc: Ingo Molnar, Thomas Gleixner, Peter Zijlstra,
	Frederic Weisbecker, Arnaldo Carvalho de Melo, Borislav Petkov,
	Arjan van de Ven

[-- Attachment #1: 0002-tools-events-Add-files-to-create-libparsevent.a.patch --]
[-- Type: text/plain, Size: 201073 bytes --]

From: Steven Rostedt <srostedt@redhat.com>

Copy over the files from trace-cmd to the Linux tools directory
such that applications like perf and latencytrace can use the
more advanced parsing code.

Because some of the file names of perf conflict with trace-cmd file
names, the trace-cmd files have been renamed as follows:

 parse-events.c ==> event-parse.c
 parse-events.h ==> event-parse.h
 utils.h        ==> event-utils.h

The files have been updated to handle the changes to the header files
but other than that, they are identical to what was in the trace-cmd
repository. The history of these files, including authorship is
available at the git repo:

 git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/trace-cmd.git

The Makefile was also copied over, but most of it was removed to
focus on the parse-events code first. The parts of the Makefile for
the plugins have also been removed, but will be added back when the
plugin code is copied over as well. But that may be in its own
separate directory.

Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
---
 tools/lib/events/Makefile       |  303 +++
 tools/lib/events/event-parse.c  | 4966 +++++++++++++++++++++++++++++++++++++++
 tools/lib/events/event-parse.h  |  806 +++++++
 tools/lib/events/event-utils.h  |   64 +
 tools/lib/events/parse-filter.c | 2262 ++++++++++++++++++
 tools/lib/events/parse-utils.c  |  110 +
 tools/lib/events/trace-seq.c    |  199 ++
 7 files changed, 8710 insertions(+), 0 deletions(-)
 create mode 100644 tools/lib/events/Makefile
 create mode 100644 tools/lib/events/event-parse.c
 create mode 100644 tools/lib/events/event-parse.h
 create mode 100644 tools/lib/events/event-utils.h
 create mode 100644 tools/lib/events/parse-filter.c
 create mode 100644 tools/lib/events/parse-utils.c
 create mode 100644 tools/lib/events/trace-seq.c

diff --git a/tools/lib/events/Makefile b/tools/lib/events/Makefile
new file mode 100644
index 0000000..0bebc85
--- /dev/null
+++ b/tools/lib/events/Makefile
@@ -0,0 +1,303 @@
+# trace-cmd version
+EP_VERSION = 1
+EP_PATCHLEVEL = 1
+EP_EXTRAVERSION = 0
+
+# file format version
+FILE_VERSION = 6
+
+MAKEFLAGS += --no-print-directory
+
+
+# Makefiles suck: This macro sets a default value of $(2) for the
+# variable named by $(1), unless the variable has been set by
+# environment or command line. This is necessary for CC and AR
+# because make sets default values, so the simpler ?= approach
+# won't work as expected.
+define allow-override
+  $(if $(or $(findstring environment,$(origin $(1))),\
+            $(findstring command line,$(origin $(1)))),,\
+    $(eval $(1) = $(2)))
+endef
+
+# Allow setting CC and AR, or setting CROSS_COMPILE as a prefix.
+$(call allow-override,CC,$(CROSS_COMPILE)gcc)
+$(call allow-override,AR,$(CROSS_COMPILE)ar)
+
+EXT = -std=gnu99
+INSTALL = install
+
+# Use DESTDIR for installing into a different root directory.
+# This is useful for building a package. The program will be
+# installed in this directory as if it was the root directory.
+# Then the build tool can move it later.
+DESTDIR ?=
+DESTDIR_SQ = '$(subst ','\'',$(DESTDIR))'
+
+prefix ?= /usr/local
+bindir_relative = bin
+bindir = $(prefix)/$(bindir_relative)
+man_dir = $(prefix)/share/man
+man_dir_SQ = '$(subst ','\'',$(man_dir))'
+html_install = $(prefix)/share/kernelshark/html
+html_install_SQ = '$(subst ','\'',$(html_install))'
+img_install = $(prefix)/share/kernelshark/html/images
+img_install_SQ = '$(subst ','\'',$(img_install))'
+
+export man_dir man_dir_SQ html_install html_install_SQ INSTALL
+export img_install img_install_SQ
+export DESTDIR DESTDIR_SQ
+
+# copy a bit from Linux kbuild
+
+ifeq ("$(origin V)", "command line")
+  VERBOSE = $(V)
+endif
+ifndef VERBOSE
+  VERBOSE = 0
+endif
+
+ifeq ("$(origin O)", "command line")
+  BUILD_OUTPUT := $(O)
+endif
+
+ifeq ($(BUILD_SRC),)
+ifneq ($(BUILD_OUTPUT),)
+
+define build_output
+	$(if $(VERBOSE:1=),@)$(MAKE) -C $(BUILD_OUTPUT) 	\
+	BUILD_SRC=$(CURDIR) -f $(CURDIR)/Makefile $1
+endef
+
+saved-output := $(BUILD_OUTPUT)
+BUILD_OUTPUT := $(shell cd $(BUILD_OUTPUT) && /bin/pwd)
+$(if $(BUILD_OUTPUT),, \
+     $(error output directory "$(saved-output)" does not exist))
+
+all: sub-make
+
+gui: force
+	$(call build_output, all_cmd)
+
+$(filter-out gui,$(MAKECMDGOALS)): sub-make
+
+sub-make: force
+	$(call build_output, $(MAKECMDGOALS))
+
+
+# Leave processing to above invocation of make
+skip-makefile := 1
+
+endif # BUILD_OUTPUT
+endif # BUILD_SRC
+
+# We process the rest of the Makefile if this is the final invocation of make
+ifeq ($(skip-makefile),)
+
+srctree		:= $(if $(BUILD_SRC),$(BUILD_SRC),$(CURDIR))
+objtree		:= $(CURDIR)
+src		:= $(srctree)
+obj		:= $(objtree)
+
+export prefix bindir src obj
+
+# Shell quotes
+bindir_SQ = $(subst ','\'',$(bindir))
+bindir_relative_SQ = $(subst ','\'',$(bindir_relative))
+
+LIB_FILE = libparsevent.a libparsevent.so
+
+CONFIG_INCLUDES = 
+CONFIG_LIBS	=
+CONFIG_FLAGS	=
+
+VERSION		= $(EP_VERSION)
+PATCHLEVEL	= $(EP_PATCHLEVEL)
+EXTRAVERSION	= $(EP_EXTRAVERSION)
+
+OBJ		= $@
+N		=
+
+export Q VERBOSE
+
+EVENT_PARSE_VERSION = $(EP_VERSION).$(EP_PATCHLEVEL).$(EP_EXTRAVERSION)
+
+INCLUDES = -I. -I/usr/local/include $(CONFIG_INCLUDES)
+
+# Set compile option CFLAGS if not set elsewhere
+CFLAGS ?= -g -Wall
+
+# Append required CFLAGS
+override CFLAGS += $(CONFIG_FLAGS) $(INCLUDES) $(PLUGIN_DIR_SQ)
+override CFLAGS += $(udis86-flags)
+
+ifeq ($(VERBOSE),1)
+  Q =
+  print_compile =
+  print_app_build =
+  print_fpic_compile =
+  print_shared_lib_compile =
+  print_plugin_obj_compile =
+  print_plugin_build =
+  print_install =
+else
+  Q = @
+  print_compile =		echo '  CC                 '$(OBJ);
+  print_app_build =		echo '  BUILD              '$(OBJ);
+  print_fpic_compile =		echo '  CC FPIC            '$(OBJ);
+  print_shared_lib_compile =	echo '  BUILD SHARED LIB   '$(OBJ);
+  print_plugin_obj_compile =	echo '  CC PLUGIN OBJ      '$(OBJ);
+  print_plugin_build =		echo '  CC PLUGI           '$(OBJ);
+  print_static_lib_build =	echo '  BUILD STATIC LIB   '$(OBJ);
+  print_install =		echo '  INSTALL     '$1'	to	$(DESTDIR_SQ)$2';
+endif
+
+do_fpic_compile =					\
+	($(print_fpic_compile)				\
+	$(CC) -c $(CFLAGS) $(EXT) -fPIC $< -o $@)
+
+do_app_build =						\
+	($(print_app_build)				\
+	$(CC) $^ -rdynamic -o $@ $(CONFIG_LIBS) $(LIBS))
+
+do_compile_shared_library =			\
+	($(print_shared_lib_compile)		\
+	$(CC) --shared $^ -o $@)
+
+do_compile_plugin_obj =				\
+	($(print_plugin_obj_compile)		\
+	$(CC) -c $(CFLAGS) -fPIC -o $@ $<)
+
+do_plugin_build =				\
+	($(print_plugin_build)			\
+	$(CC) $(CFLAGS) -shared -nostartfiles -o $@ $<)
+
+do_build_static_lib =				\
+	($(print_static_lib_build)		\
+	$(RM) $@;  $(AR) rcs $@ $^)
+
+
+define do_compile
+	$(print_compile)						\
+	$(CC) -c $(CFLAGS) $(EXT) $< -o $(obj)/$@;
+endef
+
+$(obj)/%.o: $(src)/%.c
+	$(Q)$(call do_compile)
+
+%.o: $(src)/%.c
+	$(Q)$(call do_compile)
+
+PEVENT_LIB_OBJS = event-parse.o trace-seq.o parse-filter.o parse-utils.o
+
+ALL_OBJS = $(PEVENT_LIB_OBJS)
+
+CMD_TARGETS = $(LIB_FILE)
+
+TARGETS = $(CMD_TARGETS)
+
+
+all: all_cmd
+
+all_cmd: $(CMD_TARGETS)
+
+libparsevent.so: $(PEVENT_LIB_OBJS)
+	$(Q)$(do_compile_shared_library)
+
+libparsevent.a: $(PEVENT_LIB_OBJS)
+	$(Q)$(do_build_static_lib)
+
+$(PEVENT_LIB_OBJS): %.o: $(src)/%.c
+	$(Q)$(do_fpic_compile)
+
+define make_version.h
+	(echo '/* This file is automatically generated. Do not modify. */';		\
+	echo \#define VERSION_CODE $(shell						\
+	expr $(VERSION) \* 256 + $(PATCHLEVEL));					\
+	echo '#define EXTRAVERSION ' $(EXTRAVERSION);					\
+	echo '#define VERSION_STRING "'$(VERSION).$(PATCHLEVEL).$(EXTRAVERSION)'"';	\
+	echo '#define FILE_VERSION '$(FILE_VERSION);					\
+	) > $1
+endef
+
+define update_version.h
+	($(call make_version.h, $@.tmp);		\
+	if [ -r $@ ] && cmp -s $@ $@.tmp; then		\
+		rm -f $@.tmp;				\
+	else						\
+		echo '  UPDATE                 $@';	\
+		mv -f $@.tmp $@;			\
+	fi);
+endef
+
+ep_version.h: force
+	$(Q)$(N)$(call update_version.h)
+
+VERSION_FILES = ep_version.h
+
+define update_dir
+	(echo $1 > $@.tmp;	\
+	if [ -r $@ ] && cmp -s $@ $@.tmp; then		\
+		rm -f $@.tmp;				\
+	else						\
+		echo '  UPDATE                 $@';	\
+		mv -f $@.tmp $@;			\
+	fi);
+endef
+
+## make deps
+
+all_objs := $(sort $(ALL_OBJS))
+all_deps := $(all_objs:%.o=.%.d)
+
+define check_deps
+		$(CC) -M $(CFLAGS) $< > $@;
+endef
+
+$(gui_deps): ks_version.h
+$(non_gui_deps): tc_version.h
+
+$(all_deps): .%.d: $(src)/%.c
+	$(Q)$(call check_deps)
+
+$(all_objs) : %.o : .%.d
+
+dep_includes := $(wildcard $(all_deps))
+
+ifneq ($(dep_includes),)
+ include $(dep_includes)
+endif
+
+tags:	force
+	$(RM) tags
+	find . -name '*.[ch]' | xargs ctags --extra=+f --c-kinds=+px
+
+TAGS:	force
+	$(RM) TAGS
+	find . -name '*.[ch]' | xargs etags
+
+define do_install
+	$(print_install)				\
+	if [ ! -d '$(DESTDIR_SQ)$2' ]; then		\
+		$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$2';	\
+	fi;						\
+	$(INSTALL) $1 '$(DESTDIR_SQ)$2'
+endef
+
+install_lib: all_cmd install_plugins install_python
+	$(Q)$(call do_install,$(LIB_FILE),$(bindir_SQ))
+
+install: install_lib
+
+clean:
+	$(RM) *.o *~ $(TARGETS) *.a *.so $(VERSION_FILES).*.d
+	$(RM) tags TAGS
+
+endif # skip-makefile
+
+PHONY += force
+force:
+
+# Declare the contents of the .PHONY variable as phony.  We keep that
+# information in a variable so we can use it in if_changed and friends.
+.PHONY: $(PHONY)
diff --git a/tools/lib/events/event-parse.c b/tools/lib/events/event-parse.c
new file mode 100644
index 0000000..01b8821
--- /dev/null
+++ b/tools/lib/events/event-parse.c
@@ -0,0 +1,4966 @@
+/*
+ * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  The parts for function graph printing was taken and modified from the
+ *  Linux Kernel that were written by
+ *    - Copyright (C) 2009  Frederic Weisbecker,
+ *  Frederic Weisbecker gave his permission to relicense the code to
+ *  the Lesser General Public License.
+ */
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include "event-parse.h"
+
+static const char *input_buf;
+static unsigned long long input_buf_ptr;
+static unsigned long long input_buf_siz;
+
+static int show_warning = 1;
+
+#define do_warning(fmt, ...)				\
+	do {						\
+		if (show_warning)			\
+			warning(fmt, ##__VA_ARGS__);	\
+	} while (0)
+
+static void init_input_buf(const char *buf, unsigned long long size)
+{
+	input_buf = buf;
+	input_buf_siz = size;
+	input_buf_ptr = 0;
+}
+
+const char *pevent_get_input_buf(void)
+{
+	return input_buf;
+}
+
+unsigned long long pevent_get_input_buf_ptr(void)
+{
+	return input_buf_ptr;
+}
+
+struct event_handler {
+	struct event_handler		*next;
+	int				id;
+	const char			*sys_name;
+	const char			*event_name;
+	pevent_event_handler_func	func;
+	void				*context;
+};
+
+struct pevent_func_params {
+	struct pevent_func_params	*next;
+	enum pevent_func_arg_type	type;
+};
+
+struct pevent_function_handler {
+	struct pevent_function_handler	*next;
+	enum pevent_func_arg_type	ret_type;
+	char				*name;
+	pevent_func_handler		func;
+	struct pevent_func_params	*params;
+	int				nr_args;
+};
+
+static unsigned long long
+process_defined_func(struct trace_seq *s, void *data, int size,
+		     struct event_format *event, struct print_arg *arg);
+
+static void free_func_handle(struct pevent_function_handler *func);
+
+/**
+ * pevent_buffer_init - init buffer for parsing
+ * @buf: buffer to parse
+ * @size: the size of the buffer
+ *
+ * For use with pevent_read_token(), this initializes the internal
+ * buffer that pevent_read_token() will parse.
+ */
+void pevent_buffer_init(const char *buf, unsigned long long size)
+{
+	init_input_buf(buf, size);
+}
+
+void breakpoint(void)
+{
+	static int x;
+	x++;
+}
+
+struct print_arg *alloc_arg(void)
+{
+	struct print_arg *arg;
+
+	arg = malloc_or_die(sizeof(*arg));
+	if (!arg)
+		return NULL;
+	memset(arg, 0, sizeof(*arg));
+
+	return arg;
+}
+
+struct cmdline {
+	char *comm;
+	int pid;
+};
+
+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;
+}
+
+struct cmdline_list {
+	struct cmdline_list	*next;
+	char			*comm;
+	int			pid;
+};
+
+static int cmdline_init(struct pevent *pevent)
+{
+	struct cmdline_list *cmdlist = pevent->cmdlist;
+	struct cmdline_list *item;
+	struct cmdline *cmdlines;
+	int i;
+
+	cmdlines = malloc_or_die(sizeof(*cmdlines) * pevent->cmdline_count);
+
+	i = 0;
+	while (cmdlist) {
+		cmdlines[i].pid = cmdlist->pid;
+		cmdlines[i].comm = cmdlist->comm;
+		i++;
+		item = cmdlist;
+		cmdlist = cmdlist->next;
+		free(item);
+	}
+
+	qsort(cmdlines, pevent->cmdline_count, sizeof(*cmdlines), cmdline_cmp);
+
+	pevent->cmdlines = cmdlines;
+	pevent->cmdlist = NULL;
+
+	return 0;
+}
+
+static char *find_cmdline(struct pevent *pevent, int pid)
+{
+	const struct cmdline *comm;
+	struct cmdline key;
+
+	if (!pid)
+		return "<idle>";
+
+	if (!pevent->cmdlines)
+		cmdline_init(pevent);
+
+	key.pid = pid;
+
+	comm = bsearch(&key, pevent->cmdlines, pevent->cmdline_count,
+		       sizeof(*pevent->cmdlines), cmdline_cmp);
+
+	if (comm)
+		return comm->comm;
+	return "<...>";
+}
+
+/**
+ * pevent_pid_is_registered - return if a pid has a cmdline registered
+ * @pevent: handle for the pevent
+ * @pid: The pid to check if it has a cmdline registered with.
+ *
+ * Returns 1 if the pid has a cmdline mapped to it
+ * 0 otherwise.
+ */
+int pevent_pid_is_registered(struct pevent *pevent, int pid)
+{
+	const struct cmdline *comm;
+	struct cmdline key;
+
+	if (!pid)
+		return 1;
+
+	if (!pevent->cmdlines)
+		cmdline_init(pevent);
+
+	key.pid = pid;
+
+	comm = bsearch(&key, pevent->cmdlines, pevent->cmdline_count,
+		       sizeof(*pevent->cmdlines), cmdline_cmp);
+
+	if (comm)
+		return 1;
+	return 0;
+}
+
+/*
+ * If the command lines have been converted to an array, then
+ * we must add this pid. This is much slower than when cmdlines
+ * are added before the array is initialized.
+ */
+static int add_new_comm(struct pevent *pevent, const char *comm, int pid)
+{
+	struct cmdline *cmdlines = pevent->cmdlines;
+	const struct cmdline *cmdline;
+	struct cmdline key;
+
+	if (!pid)
+		return 0;
+
+	/* avoid duplicates */
+	key.pid = pid;
+
+	cmdline = bsearch(&key, pevent->cmdlines, pevent->cmdline_count,
+		       sizeof(*pevent->cmdlines), cmdline_cmp);
+	if (cmdline) {
+		errno = EEXIST;
+		return -1;
+	}
+
+	cmdlines = realloc(cmdlines, sizeof(*cmdlines) * (pevent->cmdline_count + 1));
+	if (!cmdlines) {
+		errno = ENOMEM;
+		return -1;
+	}
+
+	cmdlines[pevent->cmdline_count].pid = pid;
+	cmdlines[pevent->cmdline_count].comm = strdup(comm);
+	if (!cmdlines[pevent->cmdline_count].comm)
+		die("malloc comm");
+		
+	if (cmdlines[pevent->cmdline_count].comm)
+		pevent->cmdline_count++;
+
+	qsort(cmdlines, pevent->cmdline_count, sizeof(*cmdlines), cmdline_cmp);
+	pevent->cmdlines = cmdlines;
+
+	return 0;
+}
+
+/**
+ * pevent_register_comm - register a pid / comm mapping
+ * @pevent: handle for the pevent
+ * @comm: the command line to register
+ * @pid: the pid to map the command line to
+ *
+ * This adds a mapping to search for command line names with
+ * a given pid. The comm is duplicated.
+ */
+int pevent_register_comm(struct pevent *pevent, const char *comm, int pid)
+{
+	struct cmdline_list *item;
+
+	if (pevent->cmdlines)
+		return add_new_comm(pevent, comm, pid);
+
+	item = malloc_or_die(sizeof(*item));
+	item->comm = strdup(comm);
+	if (!item->comm)
+		die("malloc comm");
+	item->pid = pid;
+	item->next = pevent->cmdlist;
+
+	pevent->cmdlist = item;
+	pevent->cmdline_count++;
+
+	return 0;
+}
+
+struct func_map {
+	unsigned long long		addr;
+	char				*func;
+	char				*mod;
+};
+
+struct func_list {
+	struct func_list	*next;
+	unsigned long long	addr;
+	char			*func;
+	char			*mod;
+};
+
+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;
+}
+
+/*
+ * 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 int func_map_init(struct pevent *pevent)
+{
+	struct func_list *funclist;
+	struct func_list *item;
+	struct func_map *func_map;
+	int i;
+
+	func_map = malloc_or_die(sizeof(*func_map) * (pevent->func_count + 1));
+	funclist = pevent->funclist;
+
+	i = 0;
+	while (funclist) {
+		func_map[i].func = funclist->func;
+		func_map[i].addr = funclist->addr;
+		func_map[i].mod = funclist->mod;
+		i++;
+		item = funclist;
+		funclist = funclist->next;
+		free(item);
+	}
+
+	qsort(func_map, pevent->func_count, sizeof(*func_map), func_cmp);
+
+	/*
+	 * Add a special record at the end.
+	 */
+	func_map[pevent->func_count].func = NULL;
+	func_map[pevent->func_count].addr = 0;
+	func_map[pevent->func_count].mod = NULL;
+
+	pevent->func_map = func_map;
+	pevent->funclist = NULL;
+
+	return 0;
+}
+
+static struct func_map *
+find_func(struct pevent *pevent, unsigned long long addr)
+{
+	struct func_map *func;
+	struct func_map key;
+
+	if (!pevent->func_map)
+		func_map_init(pevent);
+
+	key.addr = addr;
+
+	func = bsearch(&key, pevent->func_map, pevent->func_count,
+		       sizeof(*pevent->func_map), func_bcmp);
+
+	return func;
+}
+
+/**
+ * pevent_find_function - find a function by a given address
+ * @pevent: handle for the pevent
+ * @addr: the address to find the function with
+ *
+ * Returns a pointer to the function stored that has the given
+ * address. Note, the address does not have to be exact, it
+ * will select the function that would contain the address.
+ */
+const char *pevent_find_function(struct pevent *pevent, unsigned long long addr)
+{
+	struct func_map *map;
+
+	map = find_func(pevent, addr);
+	if (!map)
+		return NULL;
+
+	return map->func;
+}
+
+/**
+ * pevent_find_function_address - find a function address by a given address
+ * @pevent: handle for the pevent
+ * @addr: the address to find the function with
+ *
+ * Returns the address the function starts at. This can be used in
+ * conjunction with pevent_find_function to print both the function
+ * name and the function offset.
+ */
+unsigned long long
+pevent_find_function_address(struct pevent *pevent, unsigned long long addr)
+{
+	struct func_map *map;
+
+	map = find_func(pevent, addr);
+	if (!map)
+		return 0;
+
+	return map->addr;
+}
+
+/**
+ * pevent_register_function - register a function with a given address
+ * @pevent: handle for the pevent
+ * @function: the function name to register
+ * @addr: the address the function starts at
+ * @mod: the kernel module the function may be in (NULL for none)
+ *
+ * This registers a function name with an address and module.
+ * The @func passed in is duplicated.
+ */
+int pevent_register_function(struct pevent *pevent, char *func,
+			     unsigned long long addr, char *mod)
+{
+	struct func_list *item;
+
+	item = malloc_or_die(sizeof(*item));
+
+	item->next = pevent->funclist;
+	item->func = strdup(func);
+	if (mod)
+		item->mod = strdup(mod);
+	else
+		item->mod = NULL;
+	item->addr = addr;
+
+	pevent->funclist = item;
+
+	pevent->func_count++;
+
+	return 0;
+}
+
+/**
+ * pevent_print_funcs - print out the stored functions
+ * @pevent: handle for the pevent
+ *
+ * This prints out the stored functions.
+ */
+void pevent_print_funcs(struct pevent *pevent)
+{
+	int i;
+
+	if (!pevent->func_map)
+		func_map_init(pevent);
+
+	for (i = 0; i < (int)pevent->func_count; i++) {
+		printf("%016llx %s",
+		       pevent->func_map[i].addr,
+		       pevent->func_map[i].func);
+		if (pevent->func_map[i].mod)
+			printf(" [%s]\n", pevent->func_map[i].mod);
+		else
+			printf("\n");
+	}
+}
+
+struct printk_map {
+	unsigned long long		addr;
+	char				*printk;
+};
+
+struct printk_list {
+	struct printk_list	*next;
+	unsigned long long	addr;
+	char			*printk;
+};
+
+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 void printk_map_init(struct pevent *pevent)
+{
+	struct printk_list *printklist;
+	struct printk_list *item;
+	struct printk_map *printk_map;
+	int i;
+
+	printk_map = malloc_or_die(sizeof(*printk_map) * (pevent->printk_count + 1));
+
+	printklist = pevent->printklist;
+
+	i = 0;
+	while (printklist) {
+		printk_map[i].printk = printklist->printk;
+		printk_map[i].addr = printklist->addr;
+		i++;
+		item = printklist;
+		printklist = printklist->next;
+		free(item);
+	}
+
+	qsort(printk_map, pevent->printk_count, sizeof(*printk_map), printk_cmp);
+
+	pevent->printk_map = printk_map;
+	pevent->printklist = NULL;
+}
+
+static struct printk_map *
+find_printk(struct pevent *pevent, unsigned long long addr)
+{
+	struct printk_map *printk;
+	struct printk_map key;
+
+	if (!pevent->printk_map)
+		printk_map_init(pevent);
+
+	key.addr = addr;
+
+	printk = bsearch(&key, pevent->printk_map, pevent->printk_count,
+			 sizeof(*pevent->printk_map), printk_cmp);
+
+	return printk;
+}
+
+/**
+ * pevent_register_print_string - register a string by its address
+ * @pevent: handle for the pevent
+ * @fmt: the string format to register
+ * @addr: the address the string was located at
+ *
+ * This registers a string by the address it was stored in the kernel.
+ * The @fmt passed in is duplicated.
+ */
+int pevent_register_print_string(struct pevent *pevent, char *fmt,
+				 unsigned long long addr)
+{
+	struct printk_list *item;
+
+	item = malloc_or_die(sizeof(*item));
+
+	item->next = pevent->printklist;
+	pevent->printklist = item;
+	item->printk = strdup(fmt);
+	item->addr = addr;
+
+	pevent->printk_count++;
+
+	return 0;
+}
+
+/**
+ * pevent_print_printk - print out the stored strings
+ * @pevent: handle for the pevent
+ *
+ * This prints the string formats that were stored.
+ */
+void pevent_print_printk(struct pevent *pevent)
+{
+	int i;
+
+	if (!pevent->printk_map)
+		printk_map_init(pevent);
+
+	for (i = 0; i < (int)pevent->printk_count; i++) {
+		printf("%016llx %s\n",
+		       pevent->printk_map[i].addr,
+		       pevent->printk_map[i].printk);
+	}
+}
+
+static struct event_format *alloc_event(void)
+{
+	struct event_format *event;
+
+	event = malloc_or_die(sizeof(*event));
+	memset(event, 0, sizeof(*event));
+
+	return event;
+}
+
+static void add_event(struct pevent *pevent, struct event_format *event)
+{
+	int i;
+
+	if (!pevent->events)
+		pevent->events = malloc_or_die(sizeof(event));
+	else
+		pevent->events =
+			realloc(pevent->events, sizeof(event) *
+				(pevent->nr_events + 1));
+	if (!pevent->events)
+		die("Can not allocate events");
+
+	for (i = 0; i < pevent->nr_events; i++) {
+		if (pevent->events[i]->id > event->id)
+			break;
+	}
+	if (i < pevent->nr_events)
+		memmove(&pevent->events[i + 1],
+			&pevent->events[i],
+			sizeof(event) * (pevent->nr_events - i));
+
+	pevent->events[i] = event;
+	pevent->nr_events++;
+
+	event->pevent = pevent;
+}
+
+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_flag_sym(struct print_flag_sym *fsym)
+{
+	struct print_flag_sym *next;
+
+	while (fsym) {
+		next = fsym->next;
+		free(fsym->value);
+		free(fsym->str);
+		free(fsym);
+		fsym = next;
+	}
+}
+
+static void free_arg(struct print_arg *arg)
+{
+	struct print_arg *farg;
+
+	if (!arg)
+		return;
+
+	switch (arg->type) {
+	case PRINT_ATOM:
+		free(arg->atom.atom);
+		break;
+	case PRINT_FIELD:
+		free(arg->field.name);
+		break;
+	case PRINT_FLAGS:
+		free_arg(arg->flags.field);
+		free(arg->flags.delim);
+		free_flag_sym(arg->flags.flags);
+		break;
+	case PRINT_SYMBOL:
+		free_arg(arg->symbol.field);
+		free_flag_sym(arg->symbol.symbols);
+		break;
+	case PRINT_TYPE:
+		free(arg->typecast.type);
+		free_arg(arg->typecast.item);
+		break;
+	case PRINT_STRING:
+	case PRINT_BSTRING:
+		free(arg->string.string);
+		break;
+	case PRINT_DYNAMIC_ARRAY:
+		free(arg->dynarray.index);
+		break;
+	case PRINT_OP:
+		free(arg->op.op);
+		free_arg(arg->op.left);
+		free_arg(arg->op.right);
+		break;
+	case PRINT_FUNC:
+		while (arg->func.args) {
+			farg = arg->func.args;
+			arg->func.args = farg->next;
+			free_arg(farg);
+		}
+		break;
+
+	case PRINT_NULL:
+	default:
+		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];
+}
+
+/**
+ * pevent_peek_char - peek at the next character that will be read
+ *
+ * Returns the next character read, or -1 if end of buffer.
+ */
+int pevent_peek_char(void)
+{
+	return __peek_char();
+}
+
+static enum event_type force_token(const char *str, char **tok);
+
+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();
+		goto out;
+
+	case EVENT_DQUOTE:
+	case EVENT_SQUOTE:
+		/* don't keep quotes */
+		i--;
+		quote_ch = ch;
+		last_ch = 0;
+ concat:
+		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--;
+
+		/*
+		 * For strings (double quotes) check the next token.
+		 * If it is another string, concatinate the two.
+		 */
+		if (type == EVENT_DQUOTE) {
+			unsigned long long save_input_buf_ptr = input_buf_ptr;
+
+			do {
+				ch = __read_char();
+			} while (isspace(ch));
+			if (ch == '"')
+				goto concat;
+			input_buf_ptr = save_input_buf_ptr;
+		}
+
+		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;
+
+	if (type == EVENT_ITEM) {
+		/*
+		 * Older versions of the kernel has a bug that
+		 * creates invalid symbols and will break the mac80211
+		 * parsing. This is a work around to that bug.
+		 *
+		 * See Linux kernel commit:
+		 *  811cb50baf63461ce0bdb234927046131fc7fa8b
+		 */
+		if (strcmp(*tok, "LOCAL_PR_FMT") == 0) {
+			free(*tok);
+			*tok = NULL;
+			return force_token("\"\%s\" ", tok);
+		} else if (strcmp(*tok, "STA_PR_FMT") == 0) {
+			free(*tok);
+			*tok = NULL;
+			return force_token("\" sta:%pM\" ", tok);
+		} else if (strcmp(*tok, "VIF_PR_FMT") == 0) {
+			free(*tok);
+			*tok = NULL;
+			return force_token("\" vif:%p(%d)\" ", tok);
+		}
+	}
+
+	return type;
+}
+
+static enum event_type force_token(const char *str, char **tok)
+{
+	const char *save_input_buf;
+	unsigned long long save_input_buf_ptr;
+	unsigned long long save_input_buf_siz;
+	enum event_type type;
+	
+	/* save off the current input pointers */
+	save_input_buf = input_buf;
+	save_input_buf_ptr = input_buf_ptr;
+	save_input_buf_siz = input_buf_siz;
+
+	init_input_buf(str, strlen(str));
+
+	type = __read_token(tok);
+
+	/* reset back to original token */
+	input_buf = save_input_buf;
+	input_buf_ptr = save_input_buf_ptr;
+	input_buf_siz = save_input_buf_siz;
+
+	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 */
+	*tok = NULL;
+	return EVENT_NONE;
+}
+
+/**
+ * pevent_read_token - access to utilites to use the pevent parser
+ * @tok: The token to return
+ *
+ * This will parse tokens from the string given by
+ * pevent_init_data().
+ *
+ * Returns the token type.
+ */
+enum event_type pevent_read_token(char **tok)
+{
+	return read_token(tok);
+}
+
+/**
+ * pevent_free_token - free a token returned by pevent_read_token
+ * @token: the token to free
+ */
+void pevent_free_token(char *token)
+{
+	free_token(token);
+}
+
+/* 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);
+		*tok = NULL;
+	}
+
+	/* not reached */
+	*tok = NULL;
+	return EVENT_NONE;
+}
+
+static int test_type(enum event_type type, enum event_type expect)
+{
+	if (type != expect) {
+		do_warning("Error: expected type %d but read %d",
+		    expect, type);
+		return -1;
+	}
+	return 0;
+}
+
+static int test_type_token(enum event_type type, const char *token,
+		    enum event_type expect, const char *expect_tok)
+{
+	if (type != expect) {
+		do_warning("Error: expected type %d but read %d",
+		    expect, type);
+		return -1;
+	}
+
+	if (strcmp(token, expect_tok) != 0) {
+		do_warning("Error: expected '%s' but read '%s'",
+		    expect_tok, token);
+		return -1;
+	}
+	return 0;
+}
+
+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)
+{
+	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);
+
+	free_token(token);
+
+	return ret;
+}
+
+static int read_expected(enum event_type expect, const char *str)
+{
+	return __read_expected(expect, str, 1);
+}
+
+static int read_expected_item(enum event_type expect, const char *str)
+{
+	return __read_expected(expect, str, 0);
+}
+
+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) == 0)
+		return 1;
+
+	return 0;
+}
+
+static int field_is_long(struct format_field *field)
+{
+	/* includes long long */
+	if (strstr(field->type, "long"))
+		return 1;
+
+	return 0;
+}
+
+static int event_read_fields(struct event_format *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)
+			goto fail;
+
+		free_token(token);
+		if (read_expect_type(EVENT_ITEM, &token) < 0)
+			goto fail;
+
+		last_token = token;
+
+		field = malloc_or_die(sizeof(*field));
+		memset(field, 0, sizeof(*field));
+		field->event = event;
+
+		/* 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);
+					free(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);
+
+			if (type == EVENT_ITEM)
+				field->arraylen = strtoul(token, NULL, 0);
+			else
+				field->arraylen = 0;
+
+		        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);
+				/* We only care about the last token */
+				field->arraylen = strtoul(token, NULL, 0);
+				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 (field_is_long(field))
+			field->flags |= FIELD_IS_LONG;
+
+		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;
+
+			/* add signed type */
+
+			free_token(token);
+			if (read_expected(EVENT_OP, ";") < 0)
+				goto fail_expect;
+
+			if (read_expect_type(EVENT_NEWLINE, &token))
+				goto fail;
+		}
+
+		free_token(token);
+
+		if (field->flags & FIELD_IS_ARRAY) {
+			if (field->arraylen)
+				field->elementsize = field->size / field->arraylen;
+			else if (field->flags & FIELD_IS_STRING)
+				field->elementsize = 1;
+			else
+				field->elementsize = event->pevent->long_size;
+		} else
+			field->elementsize = field->size;
+
+		*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_format *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;
+}
+
+static enum event_type
+process_arg_token(struct event_format *event, struct print_arg *arg,
+		  char **tok, enum event_type type);
+
+static enum event_type
+process_arg(struct event_format *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_op(struct event_format *event, struct print_arg *arg, char **tok);
+
+static enum event_type
+process_cond(struct event_format *event, struct print_arg *top, char **tok)
+{
+	struct print_arg *arg, *left, *right;
+	enum event_type type;
+	char *token = NULL;
+
+	arg = alloc_arg();
+	left = alloc_arg();
+	right = alloc_arg();
+
+	arg->type = PRINT_OP;
+	arg->op.left = left;
+	arg->op.right = right;
+
+	*tok = NULL;
+	type = process_arg(event, left, &token);
+
+ again:
+	/* Handle other operations in the arguments */
+	if (type == EVENT_OP && strcmp(token, ":") != 0) {
+		type = process_op(event, left, &token);
+		goto again;
+	}
+
+	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:
+	/* Top may point to itself */
+	top->op.right = NULL;
+	free_token(token);
+	free_arg(arg);
+	return EVENT_ERROR;
+}
+
+static enum event_type
+process_array(struct event_format *event, struct print_arg *top, char **tok)
+{
+	struct print_arg *arg;
+	enum event_type type;
+	char *token = NULL;
+
+	arg = alloc_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);
+	*tok = NULL;
+	free_arg(arg);
+	return EVENT_ERROR;
+}
+
+static int get_op_prio(char *op)
+{
+	if (!op[1]) {
+		switch (op[0]) {
+		case '~':
+		case '!':
+			return 4;
+		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);
+}
+
+/* Note, *tok does not get freed, but will most likely be saved */
+static enum event_type
+process_op(struct event_format *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);
+			goto out_free;
+		}
+		switch (token[0]) {
+		case '~':
+		case '!':
+		case '+':
+		case '-':
+			break;
+		default:
+			do_warning("bad op token %s", token);
+			goto out_free;
+
+		}
+
+		/* make an empty left */
+		left = alloc_arg();
+		left->type = PRINT_NULL;
+		arg->op.left = left;
+
+		right = alloc_arg();
+		arg->op.right = right;
+
+		/* do not free the token, it belongs to an op */
+		*tok = NULL;
+		type = process_arg(event, right, tok);
+
+	} else if (strcmp(token, "?") == 0) {
+
+		left = alloc_arg();
+		/* 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 = alloc_arg();
+
+		/* 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);
+
+		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,
+					    strlen(left->atom.atom) + 3);
+			strcat(left->atom.atom, " *");
+			free(arg->op.op);
+			*arg = *left;
+			free(left);
+
+			return type;
+		}
+
+		right = alloc_arg();
+		type = process_arg_token(event, right, tok, type);
+		arg->op.right = right;
+
+	} else if (strcmp(token, "[") == 0) {
+
+		left = alloc_arg();
+		*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 {
+		do_warning("unknown op '%s'", token);
+		event->flags |= EVENT_FL_FAILED;
+		/* the arg is now the left side */
+		goto out_free;
+	}
+
+	if (type == EVENT_OP && strcmp(*tok, ":") != 0) {
+		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;
+
+ out_free:
+	free_token(token);
+	*tok = NULL;
+	return EVENT_ERROR;
+}
+
+static enum event_type
+process_entry(struct event_format *event __unused, struct print_arg *arg,
+	      char **tok)
+{
+	enum event_type type;
+	char *field;
+	char *token;
+
+	if (read_expected(EVENT_OP, "->") < 0)
+		goto out_err;
+
+	if (read_expect_type(EVENT_ITEM, &token) < 0)
+		goto out_free;
+	field = token;
+
+	arg->type = PRINT_FIELD;
+	arg->field.name = field;
+
+	type = read_token(&token);
+	*tok = token;
+
+	return type;
+
+ out_free:
+	free_token(token);
+ out_err:
+	*tok = NULL;
+	return EVENT_ERROR;
+}
+
+static char *arg_eval (struct print_arg *arg);
+
+static unsigned long long
+eval_type_str(unsigned long long val, const char *type, int pointer)
+{
+	int sign = 0;
+	char *ref;
+	int len;
+
+	len = strlen(type);
+
+	if (pointer) {
+
+		if (type[len-1] != '*') {
+			do_warning("pointer expected with non pointer type");
+			return val;
+		}
+
+		ref = malloc_or_die(len);
+		memcpy(ref, type, len);
+
+		/* chop off the " *" */
+		ref[len - 2] = 0;
+
+		val = eval_type_str(val, ref, 0);
+		free(ref);
+		return val;
+	}
+
+	/* check if this is a pointer */
+	if (type[len - 1] == '*')
+		return val;
+
+	/* Try to figure out the arg size*/
+	if (strncmp(type, "struct", 6) == 0)
+		/* all bets off */
+		return val;
+
+	if (strcmp(type, "u8") == 0)
+		return val & 0xff;
+
+	if (strcmp(type, "u16") == 0)
+		return val & 0xffff;
+
+	if (strcmp(type, "u32") == 0)
+		return val & 0xffffffff;
+
+	if (strcmp(type, "u64") == 0 ||
+	    strcmp(type, "s64"))
+		return val;
+
+	if (strcmp(type, "s8") == 0)
+		return (unsigned long long)(char)val & 0xff;
+
+	if (strcmp(type, "s16") == 0)
+		return (unsigned long long)(short)val & 0xffff;
+
+	if (strcmp(type, "s32") == 0)
+		return (unsigned long long)(int)val & 0xffffffff;
+
+	if (strncmp(type, "unsigned ", 9) == 0) {
+		sign = 0;
+		type += 9;
+	}
+
+	if (strcmp(type, "char") == 0) {
+		if (sign)
+			return (unsigned long long)(char)val & 0xff;
+		else
+			return val & 0xff;
+	}
+
+	if (strcmp(type, "short") == 0) {
+		if (sign)
+			return (unsigned long long)(short)val & 0xffff;
+		else
+			return val & 0xffff;
+	}
+
+	if (strcmp(type, "int") == 0) {
+		if (sign)
+			return (unsigned long long)(int)val & 0xffffffff;
+		else
+			return val & 0xffffffff;
+	}
+
+	return val;
+}
+
+/*
+ * Try to figure out the type.
+ */
+static unsigned long long
+eval_type(unsigned long long val, struct print_arg *arg, int pointer)
+{
+	if (arg->type != PRINT_TYPE)
+		die("expected type argument");
+
+	return eval_type_str(val, arg->typecast.type, pointer);
+}
+
+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);
+		val = eval_type(val, arg, 0);
+		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 '-':
+			/* check for negative */
+			if (arg->op.left->type == PRINT_NULL)
+				left = 0;
+			else
+				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:
+	case PRINT_BSTRING:
+	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:
+	case PRINT_BSTRING:
+	default:
+		die("invalid eval type %d", arg->type);
+		break;
+	}
+
+	return NULL;
+}
+
+static enum event_type
+process_fields(struct event_format *event, struct print_flag_sym **list, char **tok)
+{
+	enum event_type type;
+	struct print_arg *arg = NULL;
+	struct print_flag_sym *field;
+	char *token = *tok;
+	char *value;
+
+	do {
+		free_token(token);
+		type = read_token_item(&token);
+		if (test_type_token(type, token, EVENT_OP, "{"))
+			break;
+
+		arg = alloc_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_arg(arg);
+		arg = alloc_arg();
+
+		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);
+	*tok = NULL;
+
+	return EVENT_ERROR;
+}
+
+static enum event_type
+process_flags(struct event_format *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;
+
+	field = alloc_arg();
+
+	type = process_arg(event, field, &token);
+	if (test_type_token(type, token, EVENT_DELIM, ","))
+		goto out_free;
+	free_token(token);
+
+	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);
+	*tok = NULL;
+	return EVENT_ERROR;
+}
+
+static enum event_type
+process_symbols(struct event_format *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;
+
+	field = alloc_arg();
+
+	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);
+	*tok = NULL;
+	return EVENT_ERROR;
+}
+
+static enum event_type
+process_dynamic_array(struct event_format *event, struct print_arg *arg, char **tok)
+{
+	struct format_field *field;
+	enum event_type type;
+	char *token;
+
+	memset(arg, 0, sizeof(*arg));
+	arg->type = PRINT_DYNAMIC_ARRAY;
+
+	/*
+	 * The item within the parenthesis is another field that holds
+	 * the index into where the array starts.
+	 */
+	type = read_token(&token);
+	*tok = token;
+	if (type != EVENT_ITEM)
+		goto out_free;
+
+	/* Find the field */
+
+	field = pevent_find_field(event, token);
+	if (!field)
+		goto out_free;
+
+	arg->dynarray.field = field;
+	arg->dynarray.index = 0;
+
+	if (read_expected(EVENT_DELIM, ")") < 0)
+		goto out_free;
+
+	free_token(token);
+	type = read_token_item(&token);
+	*tok = token;
+	if (type != EVENT_OP || strcmp(token, "[") != 0)
+		return type;
+
+	free_token(token);
+	arg = alloc_arg();
+	type = process_arg(event, arg, &token);
+	if (type == EVENT_ERROR)
+		goto out_free;
+
+	if (!test_type_token(type, token, EVENT_OP, "]"))
+		goto out_free;
+
+	free_token(token);
+	type = read_token_item(tok);
+	return type;
+
+ out_free:
+	free(arg);
+	free_token(token);
+	*tok = NULL;
+	return EVENT_ERROR;
+}
+
+static enum event_type
+process_paren(struct event_format *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)
+		goto out_free;
+
+	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;
+
+	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 = alloc_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;
+
+ out_free:
+	free_token(token);
+	*tok = NULL;
+	return EVENT_ERROR;
+}
+
+
+static enum event_type
+process_str(struct event_format *event __unused, struct print_arg *arg, char **tok)
+{
+	enum event_type type;
+	char *token;
+
+	if (read_expect_type(EVENT_ITEM, &token) < 0)
+		goto out_free;
+
+	arg->type = PRINT_STRING;
+	arg->string.string = token;
+	arg->string.offset = -1;
+
+	if (read_expected(EVENT_DELIM, ")") < 0)
+		goto out_err;
+
+	type = read_token(&token);
+	*tok = token;
+
+	return type;
+
+ out_free:
+	free_token(token);
+ out_err:
+	*tok = NULL;
+	return EVENT_ERROR;
+}
+
+static struct pevent_function_handler *
+find_func_handler(struct pevent *pevent, char *func_name)
+{
+	struct pevent_function_handler *func;
+
+	for (func = pevent->func_handlers; func; func = func->next) {
+		if (strcmp(func->name, func_name) == 0)
+			break;
+	}
+
+	return func;
+}
+
+static void remove_func_handler(struct pevent *pevent, char *func_name)
+{
+	struct pevent_function_handler *func;
+	struct pevent_function_handler **next;
+
+	next = &pevent->func_handlers;
+	while ((func = *next)) {
+		if (strcmp(func->name, func_name) == 0) {
+			*next = func->next;
+			free_func_handle(func);
+			break;
+		}
+		next = &func->next;
+	}
+}
+
+static enum event_type
+process_func_handler(struct event_format *event, struct pevent_function_handler *func,
+		     struct print_arg *arg, char **tok)
+{
+	struct print_arg **next_arg;
+	struct print_arg *farg;
+	enum event_type type;
+	char *token;
+	char *test;
+	int i;
+
+	arg->type = PRINT_FUNC;
+	arg->func.func = func;
+
+	*tok = NULL;
+
+	next_arg = &(arg->func.args);
+	for (i = 0; i < func->nr_args; i++) {
+		farg = alloc_arg();
+		type = process_arg(event, farg, &token);
+		if (i < (func->nr_args - 1))
+			test = ",";
+		else
+			test = ")";
+
+		if (test_type_token(type, token, EVENT_DELIM, test)) {
+			free_arg(farg);
+			free_token(token);
+			return EVENT_ERROR;
+		}
+
+		*next_arg = farg;
+		next_arg = &(farg->next);
+		free_token(token);
+	}
+
+	type = read_token(&token);
+	*tok = token;
+
+	return type;
+}
+
+static enum event_type
+process_function(struct event_format *event, struct print_arg *arg,
+		 char *token, char **tok)
+{
+	struct pevent_function_handler *func;
+
+	if (strcmp(token, "__print_flags") == 0) {
+		free_token(token);
+		return process_flags(event, arg, tok);
+	}
+	if (strcmp(token, "__print_symbolic") == 0) {
+		free_token(token);
+		return process_symbols(event, arg, tok);
+	}
+	if (strcmp(token, "__get_str") == 0) {
+		free_token(token);
+		return process_str(event, arg, tok);
+	}
+	if (strcmp(token, "__get_dynamic_array") == 0) {
+		free_token(token);
+		return process_dynamic_array(event, arg, tok);
+	}
+
+	func = find_func_handler(event->pevent, token);
+	if (func) {
+		free_token(token);
+		return process_func_handler(event, func, arg, tok);
+	}
+
+	do_warning("function %s not defined", token);
+	free_token(token);
+	return EVENT_ERROR;
+}
+
+static enum event_type
+process_arg_token(struct event_format *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);
+			break;
+		}
+		atom = token;
+		/* test the next token */
+		type = read_token_item(&token);
+
+		/*
+		 * If the next token is a parenthesis, then this
+		 * is a function.
+		 */
+		if (type == EVENT_DELIM && strcmp(token, "(") == 0) {
+			free_token(token);
+			token = NULL;
+			/* this will free atom. */
+			type = process_function(event, arg, atom, &token);
+			break;
+		}
+		/* 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);
+		}
+
+		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);
+
+		/* On error, the op is freed */
+		if (type == EVENT_ERROR)
+			arg->op.op = NULL;
+
+		/* return error type if errored */
+		break;
+
+	case EVENT_ERROR ... EVENT_NEWLINE:
+	default:
+		die("unexpected type %d", type);
+	}
+	*tok = token;
+
+	return type;
+}
+
+static int event_read_print_args(struct event_format *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) {
+			type = read_token_item(&token);
+			continue;
+		}
+
+		arg = alloc_arg();
+
+		type = process_arg(event, arg, &token);
+
+		if (type == EVENT_ERROR) {
+			free_token(token);
+			free_arg(arg);
+			return -1;
+		}
+
+		*list = arg;
+		args++;
+
+		if (type == EVENT_OP) {
+			type = process_op(event, arg, &token);
+			free_token(token);
+			if (type == EVENT_ERROR) {
+				*list = NULL;
+				free_arg(arg);
+				return -1;
+			}
+			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 && type != EVENT_ERROR)
+		free_token(token);
+
+	return args;
+}
+
+static int event_read_print(struct event_format *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 concatenation 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;
+}
+
+/**
+ * pevent_find_common_field - return a common field by event
+ * @event: handle for the event
+ * @name: the name of the common field to return
+ *
+ * Returns a common field from the event by the given @name.
+ * This only searchs the common fields and not all field.
+ */
+struct format_field *
+pevent_find_common_field(struct event_format *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;
+}
+
+/**
+ * pevent_find_field - find a non-common field
+ * @event: handle for the event
+ * @name: the name of the non-common field
+ *
+ * Returns a non-common field by the given @name.
+ * This does not search common fields.
+ */
+struct format_field *
+pevent_find_field(struct event_format *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;
+}
+
+/**
+ * pevent_find_any_field - find any field by name
+ * @event: handle for the event
+ * @name: the name of the field
+ *
+ * Returns a field by the given @name.
+ * This searchs the common field names first, then
+ * the non-common ones if a common one was not found.
+ */
+struct format_field *
+pevent_find_any_field(struct event_format *event, const char *name)
+{
+	struct format_field *format;
+
+	format = pevent_find_common_field(event, name);
+	if (format)
+		return format;
+	return pevent_find_field(event, name);
+}
+
+/**
+ * pevent_read_number - read a number from data
+ * @pevent: handle for the pevent
+ * @ptr: the raw data
+ * @size: the size of the data that holds the number
+ *
+ * Returns the number (converted to host) from the
+ * raw data.
+ */
+unsigned long long pevent_read_number(struct pevent *pevent,
+				      const void *ptr, int size)
+{
+	switch (size) {
+	case 1:
+		return *(unsigned char *)ptr;
+	case 2:
+		return data2host2(pevent, ptr);
+	case 4:
+		return data2host4(pevent, ptr);
+	case 8:
+		return data2host8(pevent, ptr);
+	default:
+		/* BUG! */
+		return 0;
+	}
+}
+
+/**
+ * pevent_read_number_field - read a number from data
+ * @field: a handle to the field
+ * @data: the raw data to read
+ * @value: the value to place the number in
+ *
+ * Reads raw data according to a field offset and size,
+ * and translates it into @value.
+ *
+ * Returns 0 on success, -1 otherwise.
+ */
+int pevent_read_number_field(struct format_field *field, const void *data,
+			     unsigned long long *value)
+{
+	if (!field)
+		return -1;
+	switch (field->size) {
+	case 1:
+	case 2:
+	case 4:
+	case 8:
+		*value = pevent_read_number(field->event->pevent,
+					    data + field->offset, field->size);
+		return 0;
+	default:
+		return -1;
+	}
+}
+
+static int get_common_info(struct pevent *pevent,
+			   const char *type, int *offset, int *size)
+{
+	struct event_format *event;
+	struct format_field *field;
+
+	/*
+	 * All events should have the same common elements.
+	 * Pick any event to find where the type is;
+	 */
+	if (!pevent->events)
+		die("no event_list!");
+
+	event = pevent->events[0];
+	field = pevent_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(struct pevent *pevent, void *data,
+			  int *size, int *offset, const char *name)
+{
+	int ret;
+
+	if (!*size) {
+		ret = get_common_info(pevent, name, offset, size);
+		if (ret < 0)
+			return ret;
+	}
+	return pevent_read_number(pevent, data + *offset, *size);
+}
+
+static int trace_parse_common_type(struct pevent *pevent, void *data)
+{
+	return __parse_common(pevent, data,
+			      &pevent->type_size, &pevent->type_offset,
+			      "common_type");
+}
+
+static int parse_common_pid(struct pevent *pevent, void *data)
+{
+	return __parse_common(pevent, data,
+			      &pevent->pid_size, &pevent->pid_offset,
+			      "common_pid");
+}
+
+static int parse_common_pc(struct pevent *pevent, void *data)
+{
+	return __parse_common(pevent, data,
+			      &pevent->pc_size, &pevent->pc_offset,
+			      "common_preempt_count");
+}
+
+static int parse_common_flags(struct pevent *pevent, void *data)
+{
+	return __parse_common(pevent, data,
+			      &pevent->flags_size, &pevent->flags_offset,
+			      "common_flags");
+}
+
+static int parse_common_lock_depth(struct pevent *pevent, void *data)
+{
+	int ret;
+
+	ret = __parse_common(pevent, data,
+			     &pevent->ld_size, &pevent->ld_offset,
+			     "common_lock_depth");
+	if (ret < 0)
+		return -1;
+
+	return ret;
+}
+
+static int events_id_cmp(const void *a, const void *b);
+
+/**
+ * pevent_find_event - find an event by given id
+ * @pevent: a handle to the pevent
+ * @id: the id of the event
+ *
+ * Returns an event that has a given @id.
+ */
+struct event_format *pevent_find_event(struct pevent *pevent, int id)
+{
+	struct event_format **eventptr;
+	struct event_format key;
+	struct event_format *pkey = &key;
+
+	/* Check cache first */
+	if (pevent->last_event && pevent->last_event->id == id)
+		return pevent->last_event;
+
+	key.id = id;
+
+	eventptr = bsearch(&pkey, pevent->events, pevent->nr_events,
+			   sizeof(*pevent->events), events_id_cmp);
+
+	if (eventptr) {
+		pevent->last_event = *eventptr;
+		return *eventptr;
+	}
+
+	return NULL;
+}
+
+/**
+ * pevent_find_event_by_name - find an event by given name
+ * @pevent: a handle to the pevent
+ * @sys: the system name to search for
+ * @name: the name of the event to search for
+ *
+ * This returns an event with a given @name and under the system
+ * @sys. If @sys is NULL the first event with @name is returned.
+ */
+struct event_format *
+pevent_find_event_by_name(struct pevent *pevent,
+			  const char *sys, const char *name)
+{
+	struct event_format *event;
+	int i;
+
+	if (pevent->last_event &&
+	    strcmp(pevent->last_event->name, name) == 0 &&
+	    (!sys || strcmp(pevent->last_event->system, sys) == 0))
+		return pevent->last_event;
+
+	for (i = 0; i < pevent->nr_events; i++) {
+		event = pevent->events[i];
+		if (strcmp(event->name, name) == 0) {
+			if (!sys)
+				break;
+			if (strcmp(event->system, sys) == 0)
+				break;
+		}
+	}
+	if (i == pevent->nr_events)
+		event = NULL;
+
+	pevent->last_event = event;
+	return event;
+}
+
+static unsigned long long
+eval_num_arg(void *data, int size, struct event_format *event, struct print_arg *arg)
+{
+	struct pevent *pevent = event->pevent;
+	unsigned long long val = 0;
+	unsigned long long left, right;
+	struct print_arg *typearg = NULL;
+	struct print_arg *larg;
+	unsigned long offset;
+	unsigned int field_size;
+
+	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 = pevent_find_any_field(event, arg->field.name);
+			if (!arg->field.field)
+				die("field %s not found", arg->field.name);
+		}
+		/* must be a number */
+		val = pevent_read_number(pevent, data + arg->field.field->offset,
+				arg->field.field->size);
+		break;
+	case PRINT_FLAGS:
+	case PRINT_SYMBOL:
+		break;
+	case PRINT_TYPE:
+		val = eval_num_arg(data, size, event, arg->typecast.item);
+		return eval_type(val, arg, 0);
+	case PRINT_STRING:
+	case PRINT_BSTRING:
+		return 0;
+	case PRINT_FUNC: {
+		struct trace_seq s;
+		trace_seq_init(&s);
+		val = process_defined_func(&s, data, size, event, arg);
+		trace_seq_destroy(&s);
+		return val;
+	}
+	case PRINT_OP:
+		if (strcmp(arg->op.op, "[") == 0) {
+			/*
+			 * Arrays are special, since we don't want
+			 * to read the arg as is.
+			 */
+			right = eval_num_arg(data, size, event, arg->op.right);
+
+			/* handle typecasts */
+			larg = arg->op.left;
+			while (larg->type == PRINT_TYPE) {
+				if (!typearg)
+					typearg = larg;
+				larg = larg->typecast.item;
+			}
+
+			/* Default to long size */
+			field_size = pevent->long_size;
+
+			switch (larg->type) {
+			case PRINT_DYNAMIC_ARRAY:
+				offset = pevent_read_number(pevent,
+						   data + larg->dynarray.field->offset,
+						   larg->dynarray.field->size);
+				if (larg->dynarray.field->elementsize)
+					field_size = larg->dynarray.field->elementsize;
+				/*
+				 * The actual length of the dynamic array is stored
+				 * in the top half of the field, and the offset
+				 * is in the bottom half of the 32 bit field.
+				 */
+				offset &= 0xffff;
+				offset += right;
+				break;
+			case PRINT_FIELD:
+				if (!larg->field.field) {
+					larg->field.field =
+						pevent_find_any_field(event, larg->field.name);
+					if (!larg->field.field)
+						die("field %s not found", larg->field.name);
+				}
+				field_size = larg->field.field->elementsize;
+				offset = larg->field.field->offset +
+					right * larg->field.field->elementsize;
+				break;
+			default:
+				goto default_op; /* oops, all bets off */
+			}
+			val = pevent_read_number(pevent,
+						 data + offset, field_size);
+			if (typearg)
+				val = eval_type(val, typearg, 1);
+			break;
+		} else if (strcmp(arg->op.op, "?") == 0) {
+			left = eval_num_arg(data, size, event, arg->op.left);
+			arg = arg->op.right;
+			if (left)
+				val = eval_num_arg(data, size, event, arg->op.left);
+			else
+				val = eval_num_arg(data, size, event, arg->op.right);
+			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 '!':
+			switch (arg->op.op[1]) {
+			case 0:
+				val = !right;
+				break;
+			case '=':
+				val = left != right;
+				break;
+			default:
+				die("unknown op '%s'", arg->op.op);
+			}
+			break;
+		case '~':
+			val = ~right;
+			break;
+		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 },
+};
+
+static 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_to_seq(struct trace_seq *s, const char *format,
+			     int len_arg, const char *str)
+{
+	if (len_arg >= 0)
+		trace_seq_printf(s, format, len_arg, str);
+	else
+		trace_seq_printf(s, format, str);
+}
+
+static void print_str_arg(struct trace_seq *s, void *data, int size,
+			  struct event_format *event, const char *format,
+			  int len_arg, struct print_arg *arg)
+{
+	struct pevent *pevent = event->pevent;
+	struct print_flag_sym *flag;
+	unsigned long long val, fval;
+	unsigned long addr;
+	char *str;
+	int print;
+	int len;
+
+	switch (arg->type) {
+	case PRINT_NULL:
+		/* ?? */
+		return;
+	case PRINT_ATOM:
+		print_str_to_seq(s, format, len_arg, arg->atom.atom);
+		return;
+	case PRINT_FIELD:
+		if (!arg->field.field) {
+			arg->field.field = pevent_find_any_field(event, arg->field.name);
+			if (!arg->field.field)
+				die("field %s not found", arg->field.name);
+		}
+		/* Zero sized fields, mean the rest of the data */
+		len = arg->field.field->size ? : size - arg->field.field->offset;
+
+		/*
+		 * Some events pass in pointers. If this is not an array
+		 * and the size is the same as long_size, assume that it
+		 * is a pointer.
+		 */
+		if (!(arg->field.field->flags & FIELD_IS_ARRAY) &&
+		    arg->field.field->size == pevent->long_size) {
+			addr = *(unsigned long *)(data + arg->field.field->offset);
+			trace_seq_printf(s, "%lx", addr);
+			break;
+		}
+		str = malloc_or_die(len + 1);
+		memcpy(str, data + arg->field.field->offset, len);
+		str[len] = 0;
+		print_str_to_seq(s, format, len_arg, 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) {
+				print_str_to_seq(s, format, len_arg, flag->str);
+				break;
+			}
+			if (fval && (val & fval) == fval) {
+				if (print && arg->flags.delim)
+					trace_seq_puts(s, arg->flags.delim);
+				print_str_to_seq(s, format, len_arg, 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) {
+				print_str_to_seq(s, format, len_arg, flag->str);
+				break;
+			}
+		}
+		break;
+
+	case PRINT_TYPE:
+		break;
+	case PRINT_STRING: {
+		int str_offset;
+
+		if (arg->string.offset == -1) {
+			struct format_field *f;
+
+			f = pevent_find_any_field(event, arg->string.string);
+			arg->string.offset = f->offset;
+		}
+		str_offset = data2host4(pevent, data + arg->string.offset);
+		str_offset &= 0xffff;
+		print_str_to_seq(s, format, len_arg, ((char *)data) + str_offset);
+		break;
+	}
+	case PRINT_BSTRING:
+		trace_seq_printf(s, format, arg->string.string);
+		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(s, data, size, event,
+				      format, len_arg, arg->op.right->op.left);
+		else
+			print_str_arg(s, data, size, event,
+				      format, len_arg, arg->op.right->op.right);
+		break;
+	case PRINT_FUNC:
+		process_defined_func(s, data, size, event, arg);
+		break;
+	default:
+		/* well... */
+		break;
+	}
+}
+
+static unsigned long long
+process_defined_func(struct trace_seq *s, void *data, int size,
+		     struct event_format *event, struct print_arg *arg)
+{
+	struct pevent_function_handler *func_handle = arg->func.func;
+	struct pevent_func_params *param;
+	unsigned long long *args;
+	unsigned long long ret;
+	struct print_arg *farg;
+	struct trace_seq str;
+	struct save_str {
+		struct save_str *next;
+		char *str;
+	} *strings = NULL, *string;
+	int i;
+
+	if (!func_handle->nr_args) {
+		ret = (*func_handle->func)(s, NULL);
+		goto out;
+	}
+
+	farg = arg->func.args;
+	param = func_handle->params;
+
+	args = malloc_or_die(sizeof(*args) * func_handle->nr_args);
+	for (i = 0; i < func_handle->nr_args; i++) {
+		switch (param->type) {
+		case PEVENT_FUNC_ARG_INT:
+		case PEVENT_FUNC_ARG_LONG:
+		case PEVENT_FUNC_ARG_PTR:
+			args[i] = eval_num_arg(data, size, event, farg);
+			break;
+		case PEVENT_FUNC_ARG_STRING:
+			trace_seq_init(&str);
+			print_str_arg(&str, data, size, event, "%s", -1, farg);
+			trace_seq_terminate(&str);
+			string = malloc_or_die(sizeof(*string));
+			string->next = strings;
+			string->str = strdup(str.buffer);
+			strings = string;
+			trace_seq_destroy(&str);
+			break;
+		default:
+			/*
+			 * Something went totally wrong, this is not
+			 * an input error, something in this code broke.
+			 */
+			die("Unexpected end of arguments\n");
+			break;
+		}
+		farg = farg->next;
+	}
+
+	ret = (*func_handle->func)(s, args);
+	free(args);
+	while (strings) {
+		string = strings;
+		strings = string->next;
+		free(string->str);
+		free(string);
+	}
+
+ out:
+	/* TBD : handle return type here */
+	return ret;
+}
+
+static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struct event_format *event)
+{
+	struct pevent *pevent = event->pevent;
+	struct format_field *field, *ip_field;
+	struct print_arg *args, *arg, **next;
+	unsigned long long ip, val;
+	char *ptr;
+	void *bptr;
+
+	field = pevent->bprint_buf_field;
+	ip_field = pevent->bprint_ip_field;
+
+	if (!field) {
+		field = pevent_find_field(event, "buf");
+		if (!field)
+			die("can't find buffer field for binary printk");
+		ip_field = pevent_find_field(event, "ip");
+		if (!ip_field)
+			die("can't find ip field for binary printk");
+		pevent->bprint_buf_field = field;
+		pevent->bprint_ip_field = ip_field;
+	}
+
+	ip = pevent_read_number(pevent, data + ip_field->offset, ip_field->size);
+
+	/*
+	 * The first arg is the IP pointer.
+	 */
+	args = alloc_arg();
+	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:
+					ls = 4;
+					break;
+				case 1:
+					ls = pevent->long_size;
+					break;
+				case 2:
+					ls = 8;
+				default:
+					break;
+				}
+				val = pevent_read_number(pevent, bptr, ls);
+				bptr += ls;
+				arg = alloc_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 = alloc_arg();
+				arg->next = NULL;
+				arg->type = PRINT_BSTRING;
+				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;
+
+		free_arg(args);
+		args = next;
+	}
+}
+
+static char *
+get_bprint_format(void *data, int size __unused, struct event_format *event)
+{
+	struct pevent *pevent = event->pevent;
+	unsigned long long addr;
+	struct format_field *field;
+	struct printk_map *printk;
+	char *format;
+	char *p;
+
+	field = pevent->bprint_fmt_field;
+
+	if (!field) {
+		field = pevent_find_field(event, "fmt");
+		if (!field)
+			die("can't find format field for binary printk");
+		pevent->bprint_fmt_field = field;
+	}
+
+	addr = pevent_read_number(pevent, data + field->offset, field->size);
+
+	printk = find_printk(pevent, 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 print_mac_arg(struct trace_seq *s, int mac, void *data, int size,
+			  struct event_format *event, struct print_arg *arg)
+{
+	unsigned char *buf;
+	char *fmt = "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x";
+
+	if (arg->type == PRINT_FUNC) {
+		process_defined_func(s, data, size, event, arg);
+		return;
+	}
+
+	if (arg->type != PRINT_FIELD) {
+		trace_seq_printf(s, "ARG TYPE NOT FIELD BUT %d",
+				 arg->type);
+		return;
+	}
+
+	if (mac == 'm')
+		fmt = "%.2x%.2x%.2x%.2x%.2x%.2x";
+	if (!arg->field.field) {
+		arg->field.field =
+			pevent_find_any_field(event, arg->field.name);
+		if (!arg->field.field)
+			die("field %s not found", arg->field.name);
+	}
+	if (arg->field.field->size != 6) {
+		trace_seq_printf(s, "INVALIDMAC");
+		return;
+	}
+	buf = data + arg->field.field->offset;
+	trace_seq_printf(s, fmt, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
+}
+
+static void print_event_fields(struct trace_seq *s, void *data, int size,
+			       struct event_format *event)
+{
+	struct format_field *field;
+	unsigned long long val;
+	unsigned int offset, len, i;
+
+	field = event->format.fields;
+	while (field) {
+		trace_seq_printf(s, " %s=", field->name);
+		if (field->flags & FIELD_IS_ARRAY) {
+			offset = field->offset;
+			len = field->size;
+			if (field->flags & FIELD_IS_DYNAMIC) {
+				val = pevent_read_number(event->pevent, data + offset, len);
+				offset = val;
+				len = offset >> 16;
+				offset &= 0xffff;
+			}
+			if (field->flags & FIELD_IS_STRING) {
+				trace_seq_printf(s, "%s", (char *)data + offset);
+			} else {
+				trace_seq_puts(s, "ARRAY[");
+				for (i = 0; i < len; i++) {
+					if (i)
+						trace_seq_puts(s, ", ");
+					trace_seq_printf(s, "%02x",
+							 *((unsigned char *)data + offset + i));
+				}
+				trace_seq_putc(s, ']');
+			}
+		} else {
+			val = pevent_read_number(event->pevent, data + field->offset,
+						 field->size);
+			if (field->flags & FIELD_IS_POINTER) {
+				trace_seq_printf(s, "0x%llx", val);
+			} else if (field->flags & FIELD_IS_SIGNED) {
+				switch (field->size) {
+				case 4:
+					/*
+					 * If field is long then print it in hex.
+					 * A long usually stores pointers.
+					 */
+					if (field->flags & FIELD_IS_LONG)
+						trace_seq_printf(s, "0x%x", (int)val);
+					else
+						trace_seq_printf(s, "%d", (int)val);
+					break;
+				case 2:
+					trace_seq_printf(s, "%2d", (short)val);
+					break;
+				case 1:
+					trace_seq_printf(s, "%1d", (char)val);
+					break;
+				default:
+					trace_seq_printf(s, "%lld", val);
+				}
+			} else {
+				if (field->flags & FIELD_IS_LONG)
+					trace_seq_printf(s, "0x%llx", val);
+				else
+					trace_seq_printf(s, "%llu", val);
+			}
+		}
+		field = field->next;
+	}
+}
+
+static void pretty_print(struct trace_seq *s, void *data, int size, struct event_format *event)
+{
+	struct pevent *pevent = event->pevent;
+	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_as_arg;
+	int len_arg;
+	int len;
+	int ls;
+
+	if (event->flags & EVENT_FL_FAILED) {
+		trace_seq_printf(s, "[FAILED TO PARSE]");
+		print_event_fields(s, data, size, event);
+		return;
+	}
+
+	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':
+				trace_seq_putc(s, '\n');
+				break;
+			case 't':
+				trace_seq_putc(s, '\t');
+				break;
+			case 'r':
+				trace_seq_putc(s, '\r');
+				break;
+			case '\\':
+				trace_seq_putc(s, '\\');
+				break;
+			default:
+				trace_seq_putc(s, *ptr);
+				break;
+			}
+
+		} else if (*ptr == '%') {
+			saveptr = ptr;
+			show_func = 0;
+			len_as_arg = 0;
+ cont_process:
+			ptr++;
+			switch (*ptr) {
+			case '%':
+				trace_seq_putc(s, '%');
+				break;
+			case '#':
+				/* FIXME: need to handle properly */
+				goto cont_process;
+			case 'h':
+				ls--;
+				goto cont_process;
+			case 'l':
+				ls++;
+				goto cont_process;
+			case 'L':
+				ls = 2;
+				goto cont_process;
+			case '*':
+				/* The argument is the length. */
+				if (!arg)
+					die("no argument match");
+				len_arg = eval_num_arg(data, size, event, arg);
+				len_as_arg = 1;
+				arg = arg->next;
+				goto cont_process;
+			case '.':
+			case 'z':
+			case 'Z':
+			case '0' ... '9':
+				goto cont_process;
+			case 'p':
+				if (pevent->long_size == 4)
+					ls = 1;
+				else
+					ls = 2;
+
+				if (*(ptr+1) == 'F' ||
+				    *(ptr+1) == 'f') {
+					ptr++;
+					show_func = *ptr;
+				} else if (*(ptr+1) == 'M' || *(ptr+1) == 'm') {
+					print_mac_arg(s, *(ptr+1), data, size, event, arg);
+					ptr++;
+					break;
+				}
+
+				/* 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 > 31)
+					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(pevent, val);
+					if (func) {
+						trace_seq_puts(s, func->func);
+						if (show_func == 'F')
+							trace_seq_printf(s,
+							       "+0x%llx",
+							       val - func->addr);
+						break;
+					}
+				}
+				if (pevent->long_size == 8 && ls) {
+					char *p;
+
+					ls = 2;
+					/* make %l into %ll */
+					p = strchr(format, 'l');
+					if (p)
+						memmove(p, p+1, strlen(p)+1);
+					else if (strcmp(format, "%p") == 0)
+						strcpy(format, "0x%llx");
+				}
+				switch (ls) {
+				case -2:
+					if (len_as_arg)
+						trace_seq_printf(s, format, len_arg, (char)val);
+					else
+						trace_seq_printf(s, format, (char)val);
+					break;
+				case -1:
+					if (len_as_arg)
+						trace_seq_printf(s, format, len_arg, (short)val);
+					else
+						trace_seq_printf(s, format, (short)val);
+					break;
+				case 0:
+					if (len_as_arg)
+						trace_seq_printf(s, format, len_arg, (int)val);
+					else
+						trace_seq_printf(s, format, (int)val);
+					break;
+				case 1:
+					if (len_as_arg)
+						trace_seq_printf(s, format, len_arg, (long)val);
+					else
+						trace_seq_printf(s, format, (long)val);
+					break;
+				case 2:
+					if (len_as_arg)
+						trace_seq_printf(s, format, len_arg,
+								 (long long)val);
+					else
+						trace_seq_printf(s, format, (long long)val);
+					break;
+				default:
+					die("bad count (%d)", ls);
+				}
+				break;
+			case 's':
+				if (!arg)
+					die("no matching argument");
+
+				len = ((unsigned long)ptr + 1) -
+					(unsigned long)saveptr;
+
+				/* should never happen */
+				if (len > 31)
+					die("bad format!");
+
+				memcpy(format, saveptr, len);
+				format[len] = 0;
+				if (!len_as_arg)
+					len_arg = -1;
+				print_str_arg(s, data, size, event,
+					      format, len_arg, arg);
+				arg = arg->next;
+				break;
+			default:
+				trace_seq_printf(s, ">%c<", *ptr);
+
+			}
+		} else
+			trace_seq_putc(s, *ptr);
+	}
+
+	if (args) {
+		free_args(args);
+		free(bprint_fmt);
+	}
+}
+
+/**
+ * pevent_data_lat_fmt - parse the data for the latency format
+ * @pevent: a handle to the pevent
+ * @s: the trace_seq to write to
+ * @data: the raw data to read from
+ * @size: currently unused.
+ *
+ * This parses out the Latency format (interrupts disabled,
+ * need rescheduling, in hard/soft interrupt, preempt count
+ * and lock depth) and places it into the trace_seq.
+ */
+void pevent_data_lat_fmt(struct pevent *pevent,
+			 struct trace_seq *s, struct record *record)
+{
+	static int check_lock_depth = 1;
+	static int lock_depth_exists;
+	unsigned int lat_flags;
+	unsigned int pc;
+	int lock_depth;
+	int hardirq;
+	int softirq;
+	void *data = record->data;
+
+	lat_flags = parse_common_flags(pevent, data);
+	pc = parse_common_pc(pevent, data);
+	/* lock_depth may not always exist */
+	if (check_lock_depth) {
+		struct format_field *field;
+		struct event_format *event;
+
+		check_lock_depth = 0;
+		event = pevent->events[0];
+		field = pevent_find_common_field(event, "common_lock_depth");
+		if (field)
+			lock_depth_exists = 1;
+	}
+	if (lock_depth_exists)
+		lock_depth = parse_common_lock_depth(pevent, data);
+
+	hardirq = lat_flags & TRACE_FLAG_HARDIRQ;
+	softirq = lat_flags & TRACE_FLAG_SOFTIRQ;
+
+	trace_seq_printf(s, "%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)
+		trace_seq_printf(s, "%x", pc);
+	else
+		trace_seq_putc(s, '.');
+
+	if (lock_depth_exists) {
+		if (lock_depth < 0)
+			trace_seq_putc(s, '.');
+		else
+			trace_seq_printf(s, "%d", lock_depth);
+	}
+
+	trace_seq_terminate(s);
+}
+
+/**
+ * pevent_data_type - parse out the given event type
+ * @pevent: a handle to the pevent
+ * @rec: the record to read from
+ *
+ * This returns the event id from the @rec.
+ */
+int pevent_data_type(struct pevent *pevent, struct record *rec)
+{
+	return trace_parse_common_type(pevent, rec->data);
+}
+
+/**
+ * pevent_data_event_from_type - find the event by a given type
+ * @pevent: a handle to the pevent
+ * @type: the type of the event.
+ *
+ * This returns the event form a given @type;
+ */
+struct event_format *pevent_data_event_from_type(struct pevent *pevent, int type)
+{
+	return pevent_find_event(pevent, type);
+}
+
+/**
+ * pevent_data_pid - parse the PID from raw data
+ * @pevent: a handle to the pevent
+ * @rec: the record to parse
+ *
+ * This returns the PID from a raw data.
+ */
+int pevent_data_pid(struct pevent *pevent, struct record *rec)
+{
+	return parse_common_pid(pevent, rec->data);
+}
+
+/**
+ * pevent_data_comm_from_pid - return the command line from PID
+ * @pevent: a handle to the pevent
+ * @pid: the PID of the task to search for
+ *
+ * This returns a pointer to the command line that has the given
+ * @pid.
+ */
+const char *pevent_data_comm_from_pid(struct pevent *pevent, int pid)
+{
+	const char *comm;
+
+	comm = find_cmdline(pevent, pid);
+	return comm;
+}
+
+/**
+ * pevent_data_comm_from_pid - parse the data into the print format
+ * @s: the trace_seq to write to
+ * @event: the handle to the event
+ * @cpu: the cpu the event was recorded on
+ * @data: the raw data
+ * @size: the size of the raw data
+ * @nsecs: the timestamp of the event
+ *
+ * This parses the raw @data using the given @event information and
+ * writes the print format into the trace_seq.
+ */
+void pevent_event_info(struct trace_seq *s, struct event_format *event,
+		       struct record *record)
+{
+	int print_pretty = 1;
+
+	if (event->pevent->print_raw)
+		print_event_fields(s, record->data, record->size, event);
+	else {
+
+		if (event->handler)
+			print_pretty = event->handler(s, record, event,
+						      event->context);
+
+		if (print_pretty)
+			pretty_print(s, record->data, record->size, event);
+	}
+
+	trace_seq_terminate(s);
+}
+
+void pevent_print_event(struct pevent *pevent, struct trace_seq *s,
+			struct record *record)
+{
+	static char *spaces = "                    "; /* 20 spaces */
+	struct event_format *event;
+	unsigned long secs;
+	unsigned long usecs;
+	const char *comm;
+	void *data = record->data;
+	int type;
+	int pid;
+	int len;
+
+	secs = record->ts / NSECS_PER_SEC;
+	usecs = record->ts - secs * NSECS_PER_SEC;
+	usecs = (usecs + 500) / NSECS_PER_USEC;
+
+	if (record->size < 0) {
+		do_warning("ug! negative record size %d", record->size);
+		return;
+	}
+
+	type = trace_parse_common_type(pevent, data);
+
+	event = pevent_find_event(pevent, type);
+	if (!event) {
+		do_warning("ug! no event found for type %d", type);
+		return;
+	}
+
+	pid = parse_common_pid(pevent, data);
+	comm = find_cmdline(pevent, pid);
+
+	if (pevent->latency_format) {
+		trace_seq_printf(s, "%8.8s-%-5d %3d",
+		       comm, pid, record->cpu);
+		pevent_data_lat_fmt(pevent, s, record);
+	} else
+		trace_seq_printf(s, "%16s-%-5d [%03d]", comm, pid, record->cpu);
+
+	trace_seq_printf(s, " %5lu.%06lu: %s: ", secs, usecs, event->name);
+
+	/* Space out the event names evenly. */
+	len = strlen(event->name);
+	if (len < 20)
+		trace_seq_printf(s, "%.*s", 20 - len, spaces);
+
+	pevent_event_info(s, event, record);
+}
+
+static int events_id_cmp(const void *a, const void *b)
+{
+	struct event_format * const * ea = a;
+	struct event_format * const * eb = b;
+
+	if ((*ea)->id < (*eb)->id)
+		return -1;
+
+	if ((*ea)->id > (*eb)->id)
+		return 1;
+
+	return 0;
+}
+
+static int events_name_cmp(const void *a, const void *b)
+{
+	struct event_format * const * ea = a;
+	struct event_format * const * eb = b;
+	int res;
+
+	res = strcmp((*ea)->name, (*eb)->name);
+	if (res)
+		return res;
+
+	res = strcmp((*ea)->system, (*eb)->system);
+	if (res)
+		return res;
+
+	return events_id_cmp(a, b);
+}
+
+static int events_system_cmp(const void *a, const void *b)
+{
+	struct event_format * const * ea = a;
+	struct event_format * const * eb = b;
+	int res;
+
+	res = strcmp((*ea)->system, (*eb)->system);
+	if (res)
+		return res;
+
+	res = strcmp((*ea)->name, (*eb)->name);
+	if (res)
+		return res;
+
+	return events_id_cmp(a, b);
+}
+
+struct event_format **pevent_list_events(struct pevent *pevent, enum event_sort_type sort_type)
+{
+	struct event_format **events;
+	int (*sort)(const void *a, const void *b);
+
+	events = pevent->sort_events;
+
+	if (events && pevent->last_type == sort_type)
+		return events;
+
+	if (!events) {
+		events = malloc(sizeof(*events) * (pevent->nr_events + 1));
+		if (!events)
+			return NULL;
+
+		memcpy(events, pevent->events, sizeof(*events) * pevent->nr_events);
+		events[pevent->nr_events] = NULL;
+
+		pevent->sort_events = events;
+
+		/* the internal events are sorted by id */
+		if (sort_type == EVENT_SORT_ID) {
+			pevent->last_type = sort_type;
+			return events;
+		}
+	}
+
+	switch (sort_type) {
+	case EVENT_SORT_ID:
+		sort = events_id_cmp;
+		break;
+	case EVENT_SORT_NAME:
+		sort = events_name_cmp;
+		break;
+	case EVENT_SORT_SYSTEM:
+		sort = events_system_cmp;
+		break;
+	default:
+		return events;
+	}
+
+	qsort(events, pevent->nr_events, sizeof(*events), sort);
+	pevent->last_type = sort_type;
+
+	return events;
+}
+
+static struct format_field **
+get_event_fields(const char *type, const char *name,
+		 int count, struct format_field *list)
+{
+	struct format_field **fields;
+	struct format_field *field;
+	int i = 0;
+
+	fields = malloc_or_die(sizeof(*fields) * (count + 1));
+	for (field = list; field; field = field->next) {
+		fields[i++] = field;
+		if (i == count + 1) {
+			do_warning("event %s has more %s fields than specified",
+				name, type);
+			i--;
+			break;
+		}
+	}
+
+	if (i != count)
+		do_warning("event %s has less %s fields than specified",
+			name, type);
+
+	fields[i] = NULL;
+
+	return fields;
+}
+
+/**
+ * pevent_event_common_fields - return a list of common fields for an event
+ * @event: the event to return the common fields of.
+ *
+ * Returns an allocated array of fields. The last item in the array is NULL.
+ * The array must be freed with free().
+ */
+struct format_field **pevent_event_common_fields(struct event_format *event)
+{
+	return get_event_fields("common", event->name,
+				event->format.nr_common,
+				event->format.common_fields);
+}
+
+/**
+ * pevent_event_fields - return a list of event specific fields for an event
+ * @event: the event to return the fields of.
+ *
+ * Returns an allocated array of fields. The last item in the array is NULL.
+ * The array must be freed with free().
+ */
+struct format_field **pevent_event_fields(struct event_format *event)
+{
+	return get_event_fields("event", event->name,
+				event->format.nr_fields,
+				event->format.fields);
+}
+
+static void print_fields(struct trace_seq *s, struct print_flag_sym *field)
+{
+	trace_seq_printf(s, "{ %s, %s }", field->value, field->str);
+	if (field->next) {
+		trace_seq_puts(s, ", ");
+		print_fields(s, field->next);
+	}
+}
+
+/* for debugging */
+static void print_args(struct print_arg *args)
+{
+	int print_paren = 1;
+	struct trace_seq s;
+
+	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);
+		trace_seq_init(&s);
+		print_fields(&s, args->flags.flags);
+		trace_seq_do_printf(&s);
+		trace_seq_destroy(&s);
+		printf(")");
+		break;
+	case PRINT_SYMBOL:
+		printf("__print_symbolic(");
+		print_args(args->symbol.field);
+		printf(", ");
+		trace_seq_init(&s);
+		print_fields(&s, args->symbol.symbols);
+		trace_seq_do_printf(&s);
+		trace_seq_destroy(&s);
+		printf(")");
+		break;
+	case PRINT_STRING:
+	case PRINT_BSTRING:
+		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);
+	}
+}
+
+static void parse_header_field(const char *field,
+			       int *offset, int *size, int mandatory)
+{
+	unsigned long long save_input_buf_ptr;
+	unsigned long long save_input_buf_siz;
+	char *token;
+	int type;
+
+	save_input_buf_ptr = input_buf_ptr;
+	save_input_buf_siz = input_buf_siz;
+
+	if (read_expected(EVENT_ITEM, "field") < 0)
+		return;
+	if (read_expected(EVENT_OP, ":") < 0)
+		return;
+
+	/* type */
+	if (read_expect_type(EVENT_ITEM, &token) < 0)
+		goto fail;
+	free_token(token);
+
+	/*
+	 * If this is not a mandatory field, then test it first.
+	 */
+	if (mandatory) {
+		if (read_expected(EVENT_ITEM, field) < 0)
+			return;
+	} else {
+		if (read_expect_type(EVENT_ITEM, &token) < 0)
+			goto fail;
+		if (strcmp(token, field) != 0)
+			goto discard;
+		free_token(token);
+	}
+
+	if (read_expected(EVENT_OP, ";") < 0)
+		return;
+	if (read_expected(EVENT_ITEM, "offset") < 0)
+		return;
+	if (read_expected(EVENT_OP, ":") < 0)
+		return;
+	if (read_expect_type(EVENT_ITEM, &token) < 0)
+		goto fail;
+	*offset = atoi(token);
+	free_token(token);
+	if (read_expected(EVENT_OP, ";") < 0)
+		return;
+	if (read_expected(EVENT_ITEM, "size") < 0)
+		return;
+	if (read_expected(EVENT_OP, ":") < 0)
+		return;
+	if (read_expect_type(EVENT_ITEM, &token) < 0)
+		goto fail;
+	*size = atoi(token);
+	free_token(token);
+	if (read_expected(EVENT_OP, ";") < 0)
+		return;
+	type = read_token(&token);
+	if (type != EVENT_NEWLINE) {
+		/* newer versions of the kernel have a "signed" type */
+		if (type != EVENT_ITEM)
+			goto fail;
+
+		if (strcmp(token, "signed") != 0)
+			goto fail;
+
+		free_token(token);
+
+		if (read_expected(EVENT_OP, ":") < 0)
+			return;
+
+		if (read_expect_type(EVENT_ITEM, &token))
+			goto fail;
+
+		free_token(token);
+		if (read_expected(EVENT_OP, ";") < 0)
+			return;
+
+		if (read_expect_type(EVENT_NEWLINE, &token))
+			goto fail;
+	}
+ fail:
+	free_token(token);
+	return;
+
+ discard:
+	input_buf_ptr = save_input_buf_ptr;
+	input_buf_siz = save_input_buf_siz;
+	*offset = 0;
+	*size = 0;
+	free_token(token);
+}
+
+/**
+ * pevent_parse_header_page - parse the data stored in the header page
+ * @pevent: the handle to the pevent
+ * @buf: the buffer storing the header page format string
+ * @size: the size of @buf
+ * @long_size: the long size to use if there is no header
+ *
+ * This parses the header page format for information on the
+ * ring buffer used. The @buf should be copied from
+ *
+ * /sys/kernel/debug/tracing/events/header_page
+ */
+int pevent_parse_header_page(struct pevent *pevent, char *buf, unsigned long size,
+			     int long_size)
+{
+	int ignore;
+
+	if (!size) {
+		/*
+		 * Old kernels did not have header page info.
+		 * Sorry but we just use what we find here in user space.
+		 */
+		pevent->header_page_ts_size = sizeof(long long);
+		pevent->header_page_size_size = long_size;
+		pevent->header_page_data_offset = sizeof(long long) + long_size;
+		pevent->old_format = 1;
+		return -1;
+	}
+	init_input_buf(buf, size);
+
+	parse_header_field("timestamp", &pevent->header_page_ts_offset,
+			   &pevent->header_page_ts_size, 1);
+	parse_header_field("commit", &pevent->header_page_size_offset,
+			   &pevent->header_page_size_size, 1);
+	parse_header_field("overwrite", &pevent->header_page_overwrite,
+			   &ignore, 0);
+	parse_header_field("data", &pevent->header_page_data_offset,
+			   &pevent->header_page_data_size, 1);
+
+	return 0;
+}
+
+static int event_matches(struct event_format *event,
+			 int id, const char *sys_name,
+			 const char *event_name)
+{
+	if (id >= 0 && id != event->id)
+		return 0;
+
+	if (event_name && (strcmp(event_name, event->name) != 0))
+		return 0;
+
+	if (sys_name && (strcmp(sys_name, event->system) != 0))
+		return 0;
+
+	return 1;
+}
+
+static void free_handler(struct event_handler *handle)
+{
+	free((void *)handle->sys_name);
+	free((void *)handle->event_name);
+	free(handle);
+}
+
+static int find_event_handle(struct pevent *pevent, struct event_format *event)
+{
+	struct event_handler *handle, **next;
+
+	for (next = &pevent->handlers; *next;
+	     next = &(*next)->next) {
+		handle = *next;
+		if (event_matches(event, handle->id,
+				  handle->sys_name,
+				  handle->event_name))
+			break;
+	}
+
+	if (!(*next))
+		return 0;
+
+	pr_stat("overriding event (%d) %s:%s with new print handler",
+		event->id, event->system, event->name);
+
+	event->handler = handle->func;
+	event->context = handle->context;
+
+	*next = handle->next;
+	free_handler(handle);
+
+	return 1;
+}
+
+/**
+ * pevent_parse_event - parse the event format
+ * @pevent: the handle to the pevent
+ * @buf: the buffer storing the event format string
+ * @size: the size of @buf
+ * @sys: the system the event belongs to
+ *
+ * This parses the event format and creates an event structure
+ * to quickly parse raw data for a given event.
+ *
+ * These files currently come from:
+ *
+ * /sys/kernel/debug/tracing/events/.../.../format
+ */
+int pevent_parse_event(struct pevent *pevent,
+		       const char *buf, unsigned long size,
+		       const char *sys)
+{
+	struct event_format *event;
+	int ret;
+
+	init_input_buf(buf, size);
+
+	event = alloc_event();
+	if (!event)
+		return -ENOMEM;
+
+	event->name = event_read_name();
+	if (!event->name) {
+		/* Bad event? */
+		free(event);
+		return -1;
+	}
+
+	if (strcmp(sys, "ftrace") == 0) {
+
+		event->flags |= EVENT_FL_ISFTRACE;
+
+		if (strcmp(event->name, "bprint") == 0)
+			event->flags |= EVENT_FL_ISBPRINT;
+	}
+		
+	event->id = event_read_id();
+	if (event->id < 0)
+		die("failed to read event id");
+
+	event->system = strdup(sys);
+
+	/* Add pevent to event so that it can be referenced */
+	event->pevent = pevent;
+
+	ret = event_read_format(event);
+	if (ret < 0) {
+		do_warning("failed to read event format for %s", event->name);
+		goto event_failed;
+	}
+
+	/*
+	 * If the event has an override, don't print warnings if the event
+	 * print format fails to parse.
+	 */
+	if (find_event_handle(pevent, event))
+		show_warning = 0;
+
+	ret = event_read_print(event);
+	if (ret < 0) {
+		do_warning("failed to read event print fmt for %s",
+			   event->name);
+		show_warning = 1;
+		goto event_failed;
+	}
+	show_warning = 1;
+
+	add_event(pevent, event);
+
+	if (!ret && (event->flags & EVENT_FL_ISFTRACE)) {
+		struct format_field *field;
+		struct print_arg *arg, **list;
+
+		/* old ftrace had no args */
+
+		list = &event->print_fmt.args;
+		for (field = event->format.fields; field; field = field->next) {
+			arg = alloc_arg();
+			*list = arg;
+			list = &arg->next;
+			arg->type = PRINT_FIELD;
+			arg->field.name = strdup(field->name);
+			arg->field.field = field;
+		}
+		return 0;
+	}
+
+#define PRINT_ARGS 0
+	if (PRINT_ARGS && event->print_fmt.args)
+		print_args(event->print_fmt.args);
+
+	return 0;
+
+ event_failed:
+	event->flags |= EVENT_FL_FAILED;
+	/* still add it even if it failed */
+	add_event(pevent, event);
+	return -1;
+}
+
+int get_field_val(struct trace_seq *s, struct format_field *field,
+		  const char *name, struct record *record,
+		  unsigned long long *val, int err)
+{
+	if (!field) {
+		if (err)
+			trace_seq_printf(s, "<CANT FIND FIELD %s>", name);
+		return -1;
+	}
+
+	if (pevent_read_number_field(field, record->data, val)) {
+		if (err)
+			trace_seq_printf(s, " %s=INVALID", name);
+		return -1;
+	}
+
+	return 0;
+}
+
+/**
+ * pevent_get_field_raw - return the raw pointer into the data field
+ * @s: The seq to print to on error
+ * @event: the event that the field is for
+ * @name: The name of the field
+ * @record: The record with the field name.
+ * @len: place to store the field length.
+ * @err: print default error if failed.
+ *
+ * Returns a pointer into record->data of the field and places
+ * the length of the field in @len.
+ *
+ * On failure, it returns NULL.
+ */
+void *pevent_get_field_raw(struct trace_seq *s, struct event_format *event,
+			   const char *name, struct record *record,
+			   int *len, int err)
+{
+	struct format_field *field;
+	void *data = record->data;
+	unsigned offset;
+	int dummy;
+
+	if (!event)
+		return NULL;
+
+	field = pevent_find_field(event, name);
+
+	if (!field) {
+		if (err)
+			trace_seq_printf(s, "<CANT FIND FIELD %s>", name);
+		return NULL;
+	}
+
+	/* Allow @len to be NULL */
+	if (!len)
+		len = &dummy;
+
+	offset = field->offset;
+	if (field->flags & FIELD_IS_DYNAMIC) {
+		offset = pevent_read_number(event->pevent,
+					    data + offset, field->size);
+		*len = offset >> 16;
+		offset &= 0xffff;
+	} else
+		*len = field->size;
+
+	return data + offset;
+}
+
+/**
+ * pevent_get_field_val - find a field and return its value
+ * @s: The seq to print to on error
+ * @event: the event that the field is for
+ * @name: The name of the field
+ * @record: The record with the field name.
+ * @val: place to store the value of the field.
+ * @err: print default error if failed.
+ *
+ * Returns 0 on success -1 on field not found.
+ */
+int pevent_get_field_val(struct trace_seq *s, struct event_format *event,
+			 const char *name, struct record *record,
+			 unsigned long long *val, int err)
+{
+	struct format_field *field;
+
+	if (!event)
+		return -1;
+
+	field = pevent_find_field(event, name);
+
+	return get_field_val(s, field, name, record, val, err);
+}
+
+/**
+ * pevent_get_common_field_val - find a common field and return its value
+ * @s: The seq to print to on error
+ * @event: the event that the field is for
+ * @name: The name of the field
+ * @record: The record with the field name.
+ * @val: place to store the value of the field.
+ * @err: print default error if failed.
+ *
+ * Returns 0 on success -1 on field not found.
+ */
+int pevent_get_common_field_val(struct trace_seq *s, struct event_format *event,
+				const char *name, struct record *record,
+				unsigned long long *val, int err)
+{
+	struct format_field *field;
+
+	if (!event)
+		return -1;
+
+	field = pevent_find_common_field(event, name);
+
+	return get_field_val(s, field, name, record, val, err);
+}
+
+/**
+ * pevent_get_any_field_val - find a any field and return its value
+ * @s: The seq to print to on error
+ * @event: the event that the field is for
+ * @name: The name of the field
+ * @record: The record with the field name.
+ * @val: place to store the value of the field.
+ * @err: print default error if failed.
+ *
+ * Returns 0 on success -1 on field not found.
+ */
+int pevent_get_any_field_val(struct trace_seq *s, struct event_format *event,
+			     const char *name, struct record *record,
+			     unsigned long long *val, int err)
+{
+	struct format_field *field;
+
+	if (!event)
+		return -1;
+
+	field = pevent_find_any_field(event, name);
+
+	return get_field_val(s, field, name, record, val, err);
+}
+
+/**
+ * pevent_print_num_field - print a field and a format
+ * @s: The seq to print to
+ * @fmt: The printf format to print the field with.
+ * @event: the event that the field is for
+ * @name: The name of the field
+ * @record: The record with the field name.
+ * @err: print default error if failed.
+ *
+ * Returns: 0 on success, -1 field not fould, or 1 if buffer is full.
+ */
+int pevent_print_num_field(struct trace_seq *s, const char *fmt,
+			   struct event_format *event, const char *name,
+			   struct record *record, int err)
+{
+	struct format_field *field = pevent_find_field(event, name);
+	unsigned long long val;
+
+	if (!field)
+		goto failed;
+
+	if (pevent_read_number_field(field, record->data, &val))
+		goto failed;
+
+	return trace_seq_printf(s, fmt, val);
+
+ failed:
+	if (err)
+		trace_seq_printf(s, "CAN'T FIND FIELD \"%s\"", name);
+	return -1;
+}
+
+static void free_func_handle(struct pevent_function_handler *func)
+{
+	struct pevent_func_params *params;
+
+	free(func->name);
+
+	while (func->params) {
+		params = func->params;
+		func->params = params->next;
+		free(params);
+	}
+
+	free(func);
+}
+
+/**
+ * pevent_register_print_function - register a helper function
+ * @pevent: the handle to the pevent
+ * @func: the function to process the helper function
+ * @name: the name of the helper function
+ * @parameters: A list of enum pevent_func_arg_type
+ *
+ * Some events may have helper functions in the print format arguments.
+ * This allows a plugin to dynmically create a way to process one
+ * of these functions.
+ *
+ * The @parameters is a variable list of pevent_func_arg_type enums that
+ * must end with PEVENT_FUNC_ARG_VOID.
+ */
+int pevent_register_print_function(struct pevent *pevent,
+				   pevent_func_handler func,
+				   enum pevent_func_arg_type ret_type,
+				   char *name, ...)
+{
+	struct pevent_function_handler *func_handle;
+	struct pevent_func_params **next_param;
+	struct pevent_func_params *param;
+	enum pevent_func_arg_type type;
+	va_list ap;
+
+	func_handle = find_func_handler(pevent, name);
+	if (func_handle) {
+		/*
+		 * This is most like caused by the users own
+		 * plugins updating the function. This overrides the
+		 * system defaults.
+		 */
+		pr_stat("override of function helper '%s'", name);
+		remove_func_handler(pevent, name);
+	}
+
+	func_handle = malloc_or_die(sizeof(*func_handle));
+	memset(func_handle, 0, sizeof(*func_handle));
+
+	func_handle->ret_type = ret_type;
+	func_handle->name = strdup(name);
+	func_handle->func = func;
+	if (!func_handle->name)
+		die("Failed to allocate function name");
+
+	next_param = &(func_handle->params);
+	va_start(ap, name);
+	for (;;) {
+		type = va_arg(ap, enum pevent_func_arg_type);
+		if (type == PEVENT_FUNC_ARG_VOID)
+			break;
+
+		if (type < 0 || type >= PEVENT_FUNC_ARG_MAX_TYPES) {
+			warning("Invalid argument type %d", type);
+			goto out_free;
+		}
+
+		param = malloc_or_die(sizeof(*param));
+		param->type = type;
+		param->next = NULL;
+
+		*next_param = param;
+		next_param = &(param->next);
+
+		func_handle->nr_args++;
+	}
+	va_end(ap);
+
+	func_handle->next = pevent->func_handlers;
+	pevent->func_handlers = func_handle;
+
+	return 0;
+ out_free:
+	va_end(ap);
+	free_func_handle(func_handle);
+	return -1;
+}
+
+/**
+ * pevent_register_event_handle - register a way to parse an event
+ * @pevent: the handle to the pevent
+ * @id: the id of the event to register
+ * @sys_name: the system name the event belongs to
+ * @event_name: the name of the event
+ * @func: the function to call to parse the event information
+ *
+ * This function allows a developer to override the parsing of
+ * a given event. If for some reason the default print format
+ * is not sufficient, this function will register a function
+ * for an event to be used to parse the data instead.
+ *
+ * If @id is >= 0, then it is used to find the event.
+ * else @sys_name and @event_name are used.
+ */
+int pevent_register_event_handler(struct pevent *pevent,
+				  int id, char *sys_name, char *event_name,
+				  pevent_event_handler_func func,
+				  void *context)
+{
+	struct event_format *event;
+	struct event_handler *handle;
+
+	if (id >= 0) {
+		/* search by id */
+		event = pevent_find_event(pevent, id);
+		if (!event)
+			goto not_found;
+		if (event_name && (strcmp(event_name, event->name) != 0))
+			goto not_found;
+		if (sys_name && (strcmp(sys_name, event->system) != 0))
+			goto not_found;
+	} else {
+		event = pevent_find_event_by_name(pevent, sys_name, event_name);
+		if (!event)
+			goto not_found;
+	}
+
+	pr_stat("overriding event (%d) %s:%s with new print handler",
+		event->id, event->system, event->name);
+
+	event->handler = func;
+	event->context = context;
+	return 0;
+
+ not_found:
+	/* Save for later use. */
+	handle = malloc_or_die(sizeof(*handle));
+	memset(handle, 0, sizeof(handle));
+	handle->id = id;
+	if (event_name)
+		handle->event_name = strdup(event_name);
+	if (sys_name)
+		handle->sys_name = strdup(sys_name);
+
+	handle->func = func;
+	handle->next = pevent->handlers;
+	pevent->handlers = handle;
+	handle->context = context;
+
+	return -1;
+}
+
+/**
+ * pevent_alloc - create a pevent handle
+ */
+struct pevent *pevent_alloc(void)
+{
+	struct pevent *pevent;
+
+	pevent = malloc(sizeof(*pevent));
+	if (!pevent)
+		return NULL;
+	memset(pevent, 0, sizeof(*pevent));
+	pevent->ref_count = 1;
+
+	return pevent;
+}
+
+void pevent_ref(struct pevent *pevent)
+{
+	pevent->ref_count++;
+}
+
+static void free_format_fields(struct format_field *field)
+{
+	struct format_field *next;
+
+	while (field) {
+		next = field->next;
+		free(field->type);
+		free(field->name);
+		free(field);
+		field = next;
+	}
+}
+
+static void free_formats(struct format *format)
+{
+	free_format_fields(format->common_fields);
+	free_format_fields(format->fields);
+}
+
+static void free_event(struct event_format *event)
+{
+	free(event->name);
+	free(event->system);
+
+	free_formats(&event->format);
+
+	free(event->print_fmt.format);
+	free_args(event->print_fmt.args);
+
+	free(event);
+}
+
+/**
+ * pevent_free - free a pevent handle
+ * @pevent: the pevent handle to free
+ */
+void pevent_free(struct pevent *pevent)
+{
+	struct cmdline_list *cmdlist = pevent->cmdlist, *cmdnext;
+	struct func_list *funclist = pevent->funclist, *funcnext;
+	struct printk_list *printklist = pevent->printklist, *printknext;
+	struct pevent_function_handler *func_handler;
+	struct event_handler *handle;
+	int i;
+
+	pevent->ref_count--;
+	if (pevent->ref_count)
+		return;
+
+	if (pevent->cmdlines) {
+		for (i = 0; i < pevent->cmdline_count; i++)
+			free(pevent->cmdlines[i].comm);
+		free(pevent->cmdlines);
+	}
+
+	while (cmdlist) {
+		cmdnext = cmdlist->next;
+		free(cmdlist->comm);
+		free(cmdlist);
+		cmdlist = cmdnext;
+	}
+
+	if (pevent->func_map) {
+		for (i = 0; i < pevent->func_count; i++) {
+			free(pevent->func_map[i].func);
+			free(pevent->func_map[i].mod);
+		}
+		free(pevent->func_map);
+	}
+
+	while (funclist) {
+		funcnext = funclist->next;
+		free(funclist->func);
+		free(funclist->mod);
+		free(funclist);
+		funclist = funcnext;
+	}
+
+	while (pevent->func_handlers) {
+		func_handler = pevent->func_handlers;
+		pevent->func_handlers = func_handler->next;
+		free_func_handle(func_handler);
+	}
+
+	if (pevent->printk_map) {
+		for (i = 0; i < pevent->printk_count; i++)
+			free(pevent->printk_map[i].printk);
+		free(pevent->printk_map);
+	}
+
+	while (printklist) {
+		printknext = printklist->next;
+		free(printklist->printk);
+		free(printklist);
+		printklist = printknext;
+	}
+
+	for (i = 0; i < pevent->nr_events; i++)
+		free_event(pevent->events[i]);
+
+	while (pevent->handlers) {
+		handle = pevent->handlers;
+		pevent->handlers = handle->next;
+		free_handler(handle);
+	}
+
+	free(pevent->events);
+	free(pevent->sort_events);
+
+	free(pevent);
+}
+
+void pevent_unref(struct pevent *pevent)
+{
+	pevent_free(pevent);
+}
diff --git a/tools/lib/events/event-parse.h b/tools/lib/events/event-parse.h
new file mode 100644
index 0000000..c32d715
--- /dev/null
+++ b/tools/lib/events/event-parse.h
@@ -0,0 +1,806 @@
+/*
+ * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#ifndef _PARSE_EVENTS_H
+#define _PARSE_EVENTS_H
+
+#include <stdarg.h>
+#include <regex.h>
+
+#ifndef __unused
+#define __unused __attribute__ ((unused))
+#endif
+
+/* ----------------------- trace_seq ----------------------- */
+
+
+#ifndef TRACE_SEQ_BUF_SIZE
+#define TRACE_SEQ_BUF_SIZE 4096
+#endif
+
+#ifndef DEBUG_RECORD
+#define DEBUG_RECORD 0
+#endif
+
+struct record {
+	unsigned long long	ts;
+	unsigned long long	offset;
+	long long		missed_events;	/* buffer dropped events before */
+	int			record_size;	/* size of binary record */
+	int			size;		/* size of data */
+	void			*data;
+	int			cpu;
+	int			ref_count;
+	int			locked;		/* Do not free, even if ref_count is zero */
+	void			*private;
+#if DEBUG_RECORD
+	struct record		*prev;
+	struct record		*next;
+	long			alloc_addr;
+#endif
+};
+
+/*
+ * Trace sequences are used to allow a function to call several other functions
+ * to create a string of data to use (up to a max of PAGE_SIZE).
+ */
+
+struct trace_seq {
+	char			*buffer;
+	unsigned int		buffer_size;
+	unsigned int		len;
+	unsigned int		readpos;
+};
+
+void trace_seq_init(struct trace_seq *s);
+void trace_seq_destroy(struct trace_seq *s);
+
+extern int trace_seq_printf(struct trace_seq *s, const char *fmt, ...)
+	__attribute__ ((format (printf, 2, 3)));
+extern int trace_seq_vprintf(struct trace_seq *s, const char *fmt, va_list args)
+	__attribute__ ((format (printf, 2, 0)));
+
+extern int trace_seq_puts(struct trace_seq *s, const char *str);
+extern int trace_seq_putc(struct trace_seq *s, unsigned char c);
+
+extern void trace_seq_terminate(struct trace_seq *s);
+
+extern int trace_seq_do_printf(struct trace_seq *s);
+
+
+/* ----------------------- pevent ----------------------- */
+
+struct pevent;
+struct event_format;
+
+typedef int (*pevent_event_handler_func)(struct trace_seq *s,
+					 struct record *record,
+					 struct event_format *event,
+					 void *context);
+
+typedef int (*pevent_plugin_load_func)(struct pevent *pevent);
+typedef int (*pevent_plugin_unload_func)(void);
+
+struct plugin_option {
+	struct plugin_option		*next;
+	void				*handle;
+	char				*file;
+	char				*name;
+	char				*plugin_alias;
+	char				*description;
+	char				*value;
+	void				*private;
+	int				set;
+};
+
+/*
+ * Plugin hooks that can be called:
+ *
+ * PEVENT_PLUGIN_LOADER:  (required)
+ *   The function name to initialized the plugin.
+ *
+ *   int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
+ *
+ * PEVENT_PLUGIN_UNLOADER:  (optional)
+ *   The function called just before unloading
+ *
+ *   int PEVENT_PLUGIN_UNLOADER(void)
+ *
+ * PEVENT_PLUGIN_OPTIONS:  (optional)
+ *   Plugin options that can be set before loading
+ *
+ *   struct plugin_option PEVENT_PLUGIN_OPTIONS[] = {
+ *	{
+ *		.name = "option-name",
+ *		.plugin_alias = "overide-file-name", (optional)
+ *		.description = "description of option to show users",
+ *	},
+ *	{
+ *		.name = NULL,
+ *	},
+ *   };
+ *
+ *   Array must end with .name = NULL;
+ *
+ *
+ *   .plugin_alias is used to give a shorter name to access
+ *   the vairable. Useful if a plugin handles more than one event.
+ *
+ * PEVENT_PLUGIN_ALIAS: (optional)
+ *   The name to use for finding options (uses filename if not defined)
+ */
+#define PEVENT_PLUGIN_LOADER pevent_plugin_loader
+#define PEVENT_PLUGIN_UNLOADER pevent_plugin_unloader
+#define PEVENT_PLUGIN_OPTIONS pevent_plugin_options
+#define PEVENT_PLUGIN_ALIAS pevent_plugin_alias
+#define _MAKE_STR(x)	#x
+#define MAKE_STR(x)	_MAKE_STR(x)
+#define PEVENT_PLUGIN_LOADER_NAME MAKE_STR(PEVENT_PLUGIN_LOADER)
+#define PEVENT_PLUGIN_UNLOADER_NAME MAKE_STR(PEVENT_PLUGIN_UNLOADER)
+#define PEVENT_PLUGIN_OPTIONS_NAME MAKE_STR(PEVENT_PLUGIN_OPTIONS)
+#define PEVENT_PLUGIN_ALIAS_NAME MAKE_STR(PEVENT_PLUGIN_ALIAS)
+
+#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_LONG		= 32,
+};
+
+struct format_field {
+	struct format_field	*next;
+	struct event_format	*event;
+	char			*type;
+	char			*name;
+	int			offset;
+	int			size;
+	unsigned int		arraylen;
+	unsigned int		elementsize;
+	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_dynarray {
+	struct format_field	*field;
+	struct print_arg	*index;
+};
+
+struct print_arg;
+
+struct print_arg_op {
+	char			*op;
+	int			prio;
+	struct print_arg	*left;
+	struct print_arg	*right;
+};
+
+struct pevent_function_handler;
+
+struct print_arg_func {
+	struct pevent_function_handler	*func;
+	struct print_arg		*args;
+};
+
+enum print_arg_type {
+	PRINT_NULL,
+	PRINT_ATOM,
+	PRINT_FIELD,
+	PRINT_FLAGS,
+	PRINT_SYMBOL,
+	PRINT_TYPE,
+	PRINT_STRING,
+	PRINT_BSTRING,
+	PRINT_DYNAMIC_ARRAY,
+	PRINT_OP,
+	PRINT_FUNC,
+};
+
+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_arg_dynarray	dynarray;
+	};
+};
+
+struct print_fmt {
+	char			*format;
+	struct print_arg	*args;
+};
+
+struct event_format {
+	struct pevent		*pevent;
+	char			*name;
+	int			id;
+	int			flags;
+	struct format		format;
+	struct print_fmt	print_fmt;
+	char			*system;
+	pevent_event_handler_func handler;
+	void			*context;
+};
+
+enum {
+	EVENT_FL_ISFTRACE	= 0x01,
+	EVENT_FL_ISPRINT	= 0x02,
+	EVENT_FL_ISBPRINT	= 0x04,
+	EVENT_FL_ISFUNCENT	= 0x10,
+	EVENT_FL_ISFUNCRET	= 0x20,
+
+	EVENT_FL_FAILED		= 0x80000000
+};
+
+enum event_sort_type {
+	EVENT_SORT_ID,
+	EVENT_SORT_NAME,
+	EVENT_SORT_SYSTEM,
+};
+
+enum event_type {
+	EVENT_ERROR,
+	EVENT_NONE,
+	EVENT_SPACE,
+	EVENT_NEWLINE,
+	EVENT_OP,
+	EVENT_DELIM,
+	EVENT_ITEM,
+	EVENT_DQUOTE,
+	EVENT_SQUOTE,
+};
+
+typedef unsigned long long (*pevent_func_handler)(struct trace_seq *s,
+					     unsigned long long *args);
+
+enum pevent_func_arg_type {
+	PEVENT_FUNC_ARG_VOID,
+	PEVENT_FUNC_ARG_INT,
+	PEVENT_FUNC_ARG_LONG,
+	PEVENT_FUNC_ARG_STRING,
+	PEVENT_FUNC_ARG_PTR,
+	PEVENT_FUNC_ARG_MAX_TYPES
+};
+
+struct cmdline;
+struct cmdline_list;
+struct func_map;
+struct func_list;
+struct event_handler;
+
+struct pevent {
+	int ref_count;
+
+	int header_page_ts_offset;
+	int header_page_ts_size;
+	int header_page_size_offset;
+	int header_page_size_size;
+	int header_page_data_offset;
+	int header_page_data_size;
+	int header_page_overwrite;
+
+	int file_bigendian;
+	int host_bigendian;
+
+	int latency_format;
+
+	int old_format;
+
+	int cpus;
+	int long_size;
+
+	struct cmdline *cmdlines;
+	struct cmdline_list *cmdlist;
+	int cmdline_count;
+
+	struct func_map *func_map;
+	struct func_list *funclist;
+	unsigned int func_count;
+
+	struct printk_map *printk_map;
+	struct printk_list *printklist;
+	unsigned int printk_count;
+
+	struct event_format **events;
+	int nr_events;
+	struct event_format **sort_events;
+	enum event_sort_type last_type;
+
+	int type_offset;
+	int type_size;
+
+	int pid_offset;
+	int pid_size;
+
+ 	int pc_offset;
+	int pc_size;
+
+	int flags_offset;
+	int flags_size;
+
+	int ld_offset;
+	int ld_size;
+
+	int print_raw;
+
+	int test_filters;
+
+	struct format_field *bprint_ip_field;
+	struct format_field *bprint_fmt_field;
+	struct format_field *bprint_buf_field;
+
+	struct event_handler *handlers;
+	struct pevent_function_handler *func_handlers;
+
+	/* cache */
+	struct event_format *last_event;
+};
+
+/* Can be overridden */
+void die(const char *fmt, ...);
+void *malloc_or_die(unsigned int size);
+void warning(const char *fmt, ...);
+void pr_stat(const char *fmt, ...);
+void vpr_stat(const char *fmt, va_list ap);
+
+/* Always available */
+void __die(const char *fmt, ...);
+void __warning(const char *fmt, ...);
+void __pr_stat(const char *fmt, ...);
+
+void __vdie(const char *fmt, ...);
+void __vwarning(const char *fmt, ...);
+void __vpr_stat(const char *fmt, ...);
+
+static inline unsigned short
+__data2host2(struct pevent *pevent, unsigned short data)
+{
+	unsigned short swap;
+
+	if (pevent->host_bigendian == pevent->file_bigendian)
+		return data;
+
+	swap = ((data & 0xffULL) << 8) |
+		((data & (0xffULL << 8)) >> 8);
+
+	return swap;
+}
+
+static inline unsigned int
+__data2host4(struct pevent *pevent, unsigned int data)
+{
+	unsigned int swap;
+
+	if (pevent->host_bigendian == pevent->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(struct pevent *pevent, unsigned long long data)
+{
+	unsigned long long swap;
+
+	if (pevent->host_bigendian == pevent->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(pevent, ptr)		__data2host2(pevent, *(unsigned short *)(ptr))
+#define data2host4(pevent, ptr)		__data2host4(pevent, *(unsigned int *)(ptr))
+#define data2host8(pevent, ptr)					\
+({								\
+	unsigned long long __val;				\
+								\
+	memcpy(&__val, (ptr), sizeof(unsigned long long));	\
+	__data2host8(pevent, __val);				\
+})
+
+/* 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,
+};
+
+int pevent_register_comm(struct pevent *pevent, const char *comm, int pid);
+int pevent_register_function(struct pevent *pevent, char *name,
+			     unsigned long long addr, char *mod);
+int pevent_register_print_string(struct pevent *pevent, char *fmt,
+				 unsigned long long addr);
+int pevent_pid_is_registered(struct pevent *pevent, int pid);
+
+void pevent_print_event(struct pevent *pevent, struct trace_seq *s,
+			struct record *record);
+
+int pevent_parse_header_page(struct pevent *pevent, char *buf, unsigned long size,
+			     int long_size);
+
+int pevent_parse_event(struct pevent *pevent, const char *buf,
+		       unsigned long size, const char *sys);
+
+void *pevent_get_field_raw(struct trace_seq *s, struct event_format *event,
+			   const char *name, struct record *record,
+			   int *len, int err);
+
+int pevent_get_field_val(struct trace_seq *s, struct event_format *event,
+			 const char *name, struct record *record,
+			 unsigned long long *val, int err);
+int pevent_get_common_field_val(struct trace_seq *s, struct event_format *event,
+				const char *name, struct record *record,
+				unsigned long long *val, int err);
+int pevent_get_any_field_val(struct trace_seq *s, struct event_format *event,
+			     const char *name, struct record *record,
+			     unsigned long long *val, int err);
+
+int pevent_print_num_field(struct trace_seq *s, const char *fmt,
+			   struct event_format *event, const char *name,
+			   struct record *record, int err);
+
+int pevent_register_event_handler(struct pevent *pevent, int id, char *sys_name, char *event_name,
+				  pevent_event_handler_func func, void *context);
+int pevent_register_print_function(struct pevent *pevent,
+				   pevent_func_handler func,
+				   enum pevent_func_arg_type ret_type,
+				   char *name, ...);
+
+struct format_field *pevent_find_common_field(struct event_format *event, const char *name);
+struct format_field *pevent_find_field(struct event_format *event, const char *name);
+struct format_field *pevent_find_any_field(struct event_format *event, const char *name);
+
+const char *pevent_find_function(struct pevent *pevent, unsigned long long addr);
+unsigned long long
+pevent_find_function_address(struct pevent *pevent, unsigned long long addr);
+unsigned long long pevent_read_number(struct pevent *pevent, const void *ptr, int size);
+int pevent_read_number_field(struct format_field *field, const void *data,
+			     unsigned long long *value);
+
+struct event_format *pevent_find_event(struct pevent *pevent, int id);
+
+struct event_format *
+pevent_find_event_by_name(struct pevent *pevent, const char *sys, const char *name);
+
+void pevent_data_lat_fmt(struct pevent *pevent,
+			 struct trace_seq *s, struct record *record);
+int pevent_data_type(struct pevent *pevent, struct record *rec);
+struct event_format *pevent_data_event_from_type(struct pevent *pevent, int type);
+int pevent_data_pid(struct pevent *pevent, struct record *rec);
+const char *pevent_data_comm_from_pid(struct pevent *pevent, int pid);
+void pevent_event_info(struct trace_seq *s, struct event_format *event,
+		       struct record *record);
+
+struct event_format **pevent_list_events(struct pevent *pevent, enum event_sort_type);
+struct format_field **pevent_event_common_fields(struct event_format *event);
+struct format_field **pevent_event_fields(struct event_format *event);
+
+static inline int pevent_get_cpus(struct pevent *pevent)
+{
+	return pevent->cpus;
+}
+
+static inline void pevent_set_cpus(struct pevent *pevent, int cpus)
+{
+	pevent->cpus = cpus;
+}
+
+static inline int pevent_get_long_size(struct pevent *pevent)
+{
+	return pevent->long_size;
+}
+
+static inline void pevent_set_long_size(struct pevent *pevent, int long_size)
+{
+	pevent->long_size = long_size;
+}
+
+static inline int pevent_is_file_bigendian(struct pevent *pevent)
+{
+	return pevent->file_bigendian;
+}
+
+static inline void pevent_set_file_bigendian(struct pevent *pevent, int endian)
+{
+	pevent->file_bigendian = endian;
+}
+
+static inline int pevent_is_host_bigendian(struct pevent *pevent)
+{
+	return pevent->host_bigendian;
+}
+
+static inline void pevent_set_host_bigendian(struct pevent *pevent, int endian)
+{
+	pevent->host_bigendian = endian;
+}
+
+static inline int pevent_is_latency_format(struct pevent *pevent)
+{
+	return pevent->latency_format;
+}
+
+static inline void pevent_set_latency_format(struct pevent *pevent, int lat)
+{
+	pevent->latency_format = lat;
+}
+
+struct pevent *pevent_alloc(void);
+void pevent_free(struct pevent *pevent);
+void pevent_ref(struct pevent *pevent);
+void pevent_unref(struct pevent *pevent);
+
+/* access to the internal parser */
+void pevent_buffer_init(const char *buf, unsigned long long size);
+enum event_type pevent_read_token(char **tok);
+void pevent_free_token(char *token);
+int pevent_peek_char(void);
+const char *pevent_get_input_buf(void);
+unsigned long long pevent_get_input_buf_ptr(void);
+
+/* for debugging */
+void pevent_print_funcs(struct pevent *pevent);
+void pevent_print_printk(struct pevent *pevent);
+
+/* ----------------------- filtering ----------------------- */
+
+enum filter_boolean_type {
+	FILTER_FALSE,
+	FILTER_TRUE,
+};
+
+enum filter_op_type {
+	FILTER_OP_AND = 1,
+	FILTER_OP_OR,
+	FILTER_OP_NOT,
+};
+
+enum filter_cmp_type {
+	FILTER_CMP_NONE,
+	FILTER_CMP_EQ,
+	FILTER_CMP_NE,
+	FILTER_CMP_GT,
+	FILTER_CMP_LT,
+	FILTER_CMP_GE,
+	FILTER_CMP_LE,
+	FILTER_CMP_MATCH,
+	FILTER_CMP_NOT_MATCH,
+	FILTER_CMP_REGEX,
+	FILTER_CMP_NOT_REGEX,
+};
+
+enum filter_exp_type {
+	FILTER_EXP_NONE,
+	FILTER_EXP_ADD,
+	FILTER_EXP_SUB,
+	FILTER_EXP_MUL,
+	FILTER_EXP_DIV,
+	FILTER_EXP_MOD,
+	FILTER_EXP_RSHIFT,
+	FILTER_EXP_LSHIFT,
+	FILTER_EXP_AND,
+	FILTER_EXP_OR,
+	FILTER_EXP_XOR,
+	FILTER_EXP_NOT,
+};
+
+enum filter_arg_type {
+	FILTER_ARG_NONE,
+	FILTER_ARG_BOOLEAN,
+	FILTER_ARG_VALUE,
+	FILTER_ARG_FIELD,
+	FILTER_ARG_EXP,
+	FILTER_ARG_OP,
+	FILTER_ARG_NUM,
+	FILTER_ARG_STR,
+};
+
+enum filter_value_type {
+	FILTER_NUMBER,
+	FILTER_STRING,
+	FILTER_CHAR
+};
+
+struct fliter_arg;
+
+struct filter_arg_boolean {
+	enum filter_boolean_type	value;
+};
+
+struct filter_arg_field {
+	struct format_field	*field;
+};
+
+struct filter_arg_value {
+	enum filter_value_type	type;
+	union {
+		char			*str;
+		unsigned long long	val;
+	};
+};
+
+struct filter_arg_op {
+	enum filter_op_type	type;
+	struct filter_arg	*left;
+	struct filter_arg	*right;
+};
+
+struct filter_arg_exp {
+	enum filter_exp_type	type;
+	struct filter_arg	*left;
+	struct filter_arg	*right;
+};
+
+struct filter_arg_num {
+	enum filter_cmp_type	type;
+	struct filter_arg	*left;
+	struct filter_arg	*right;
+};
+
+struct filter_arg_str {
+	enum filter_cmp_type	type;
+	struct format_field	*field;
+	char			*val;
+	char			*buffer;
+	regex_t			reg;
+};
+
+struct filter_arg {
+	enum filter_arg_type	type;
+	union {
+		struct filter_arg_boolean	bool;
+		struct filter_arg_field		field;
+		struct filter_arg_value		value;
+		struct filter_arg_op		op;
+		struct filter_arg_exp		exp;
+		struct filter_arg_num		num;
+		struct filter_arg_str		str;
+	};
+};
+
+struct filter_type {
+	int			event_id;
+	struct event_format	*event;
+	struct filter_arg	*filter;
+};
+
+struct event_filter {
+	struct pevent		*pevent;
+	int			filters;
+	struct filter_type	*event_filters;
+};
+
+struct event_filter *pevent_filter_alloc(struct pevent *pevent);
+
+#define FILTER_NONE		-2
+#define FILTER_NOEXIST		-1
+#define FILTER_MISS		0
+#define FILTER_MATCH		1
+
+enum filter_trivial_type {
+	FILTER_TRIVIAL_FALSE,
+	FILTER_TRIVIAL_TRUE,
+	FILTER_TRIVIAL_BOTH,
+};
+
+int pevent_filter_add_filter_str(struct event_filter *filter,
+				 const char *filter_str,
+				 char **error_str);
+
+
+int pevent_filter_match(struct event_filter *filter,
+			struct record *record);
+
+int pevent_event_filtered(struct event_filter *filter,
+			  int event_id);
+
+void pevent_filter_reset(struct event_filter *filter);
+
+void pevent_filter_clear_trivial(struct event_filter *filter,
+				 enum filter_trivial_type type);
+
+void pevent_filter_free(struct event_filter *filter);
+
+char *pevent_filter_make_string(struct event_filter *filter, int event_id);
+
+int pevent_filter_remove_event(struct event_filter *filter,
+			       int event_id);
+
+int pevent_filter_event_has_trivial(struct event_filter *filter,
+				    int event_id,
+				    enum filter_trivial_type type);
+
+int pevent_filter_copy(struct event_filter *dest, struct event_filter *source);
+
+int pevent_update_trivial(struct event_filter *dest, struct event_filter *source,
+			  enum filter_trivial_type type);
+
+int pevent_filter_compare(struct event_filter *filter1, struct event_filter *filter2);
+
+#endif /* _PARSE_EVENTS_H */
diff --git a/tools/lib/events/event-utils.h b/tools/lib/events/event-utils.h
new file mode 100644
index 0000000..a8fb48f
--- /dev/null
+++ b/tools/lib/events/event-utils.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#ifndef __UTIL_H
+#define __UTIL_H
+
+#include <ctype.h>
+
+static inline char *strim(char *string)
+{
+	char *ret;
+
+	if (!string)
+		return NULL;
+	while (*string) {
+		if (!isspace(*string))
+			break;
+		string++;
+	}
+	ret = string;
+
+	string = ret + strlen(ret) - 1;
+	while (string > ret) {
+		if (!isspace(*string))
+			break;
+		string--;
+	}
+	string[1] = 0;
+
+	return ret;
+}
+
+static inline int has_text(const char *text)
+{
+	if (!text)
+		return 0;
+
+	while (*text) {
+		if (!isspace(*text))
+			return 1;
+		text++;
+	}
+
+	return 0;
+}
+
+#endif
diff --git a/tools/lib/events/parse-filter.c b/tools/lib/events/parse-filter.c
new file mode 100644
index 0000000..1df9966
--- /dev/null
+++ b/tools/lib/events/parse-filter.c
@@ -0,0 +1,2262 @@
+/*
+ * Copyright (C) 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <sys/types.h>
+
+#include "event-parse.h"
+#include "event-utils.h"
+
+#define COMM "COMM"
+
+static struct format_field comm = {
+	.name = "COMM",
+};
+
+struct event_list {
+	struct event_list	*next;
+	struct event_format	*event;
+};
+
+#define MAX_ERR_STR_SIZE 256
+
+static void show_error(char **error_str, const char *fmt, ...)
+{
+	unsigned long long index;
+	const char *input;
+	char *error;
+	va_list ap;
+	int len;
+	int i;
+
+	if (!error_str)
+		return;
+
+	input = pevent_get_input_buf();
+	index = pevent_get_input_buf_ptr();
+	len = input ? strlen(input) : 0;
+
+	error = malloc_or_die(MAX_ERR_STR_SIZE + (len*2) + 3);
+
+	if (len) {
+		strcpy(error, input);
+		error[len] = '\n';
+		for (i = 1; i < len && i < index; i++)
+			error[len+i] = ' ';
+		error[len + i] = '^';
+		error[len + i + 1] = '\n';
+		len += i+2;
+	}
+
+	va_start(ap, fmt);
+	vsnprintf(error + len, MAX_ERR_STR_SIZE, fmt, ap);
+	va_end(ap);
+
+	*error_str = error;
+}
+
+static void free_token(char *token)
+{
+	pevent_free_token(token);
+}
+
+static enum event_type read_token(char **tok)
+{
+	enum event_type type;
+	char *token = NULL;
+
+	do {
+		free_token(token);
+		type = pevent_read_token(&token);
+	} while (type == EVENT_NEWLINE || type == EVENT_SPACE);
+
+	/* If token is = or ! check to see if the next char is ~ */
+	if (token &&
+	    (strcmp(token, "=") == 0 || strcmp(token, "!") == 0) &&
+	    pevent_peek_char() == '~') {
+		/* append it */
+		*tok = malloc(3);
+		sprintf(*tok, "%c%c", *token, '~');
+		free_token(token);
+		/* Now remove the '~' from the buffer */
+		pevent_read_token(&token);
+		free_token(token);
+	} else
+		*tok = token;
+
+	return type;
+}
+
+static int filter_cmp(const void *a, const void *b)
+{
+	const struct filter_type *ea = a;
+	const struct filter_type *eb = b;
+
+	if (ea->event_id < eb->event_id)
+		return -1;
+
+	if (ea->event_id > eb->event_id)
+		return 1;
+
+	return 0;
+}
+
+static struct filter_type *
+find_filter_type(struct event_filter *filter, int id)
+{
+	struct filter_type *filter_type;
+	struct filter_type key;
+
+	key.event_id = id;
+
+	filter_type = bsearch(&key, filter->event_filters,
+			      filter->filters,
+			      sizeof(*filter->event_filters),
+			      filter_cmp);
+
+	return filter_type;
+}
+
+static struct filter_type *
+add_filter_type(struct event_filter *filter, int id)
+{
+	struct filter_type *filter_type;
+	int i;
+
+	filter_type = find_filter_type(filter, id);
+	if (filter_type)
+		return filter_type;
+
+	if (!filter->filters)
+		filter->event_filters =
+			malloc_or_die(sizeof(*filter->event_filters));
+	else {
+		filter->event_filters =
+			realloc(filter->event_filters,
+				sizeof(*filter->event_filters) *
+				(filter->filters + 1));
+		if (!filter->event_filters)
+			die("Could not allocate filter");
+	}
+
+	for (i = 0; i < filter->filters; i++) {
+		if (filter->event_filters[i].event_id > id)
+			break;
+	}
+
+	if (i < filter->filters)
+		memmove(&filter->event_filters[i+1],
+			&filter->event_filters[i],
+			sizeof(*filter->event_filters) *
+			(filter->filters - i));
+
+	filter_type = &filter->event_filters[i];
+	filter_type->event_id = id;
+	filter_type->event = pevent_find_event(filter->pevent, id);
+	filter_type->filter = NULL;
+
+	filter->filters++;
+
+	return filter_type;
+}
+
+/**
+ * pevent_filter_alloc - create a new event filter
+ * @pevent: The pevent that this filter is associated with
+ */
+struct event_filter *pevent_filter_alloc(struct pevent *pevent)
+{
+	struct event_filter *filter;
+
+	filter = malloc_or_die(sizeof(*filter));
+	memset(filter, 0, sizeof(*filter));
+	filter->pevent = pevent;
+	pevent_ref(pevent);
+
+	return filter;
+}
+
+static struct filter_arg *allocate_arg(void)
+{
+	struct filter_arg *arg;
+
+	arg = malloc_or_die(sizeof(*arg));
+	memset(arg, 0, sizeof(*arg));
+
+	return arg;
+}
+
+static void free_arg(struct filter_arg *arg)
+{
+	if (!arg)
+		return;
+
+	switch (arg->type) {
+	case FILTER_ARG_NONE:
+	case FILTER_ARG_BOOLEAN:
+	case FILTER_ARG_NUM:
+		break;
+
+	case FILTER_ARG_STR:
+		free(arg->str.val);
+		regfree(&arg->str.reg);
+		free(arg->str.buffer);
+		break;
+
+	case FILTER_ARG_OP:
+		free_arg(arg->op.left);
+		free_arg(arg->op.right);
+	default:
+		break;
+	}
+
+	free(arg);
+}
+
+static void add_event(struct event_list **events,
+		      struct event_format *event)
+{
+	struct event_list *list;
+
+	list = malloc_or_die(sizeof(*list));
+	list->next = *events;
+	*events = list;
+	list->event = event;
+}
+
+static int event_match(struct event_format *event,
+		       regex_t *sreg, regex_t *ereg)
+{
+	if (sreg) {
+		return !regexec(sreg, event->system, 0, NULL, 0) &&
+			!regexec(ereg, event->name, 0, NULL, 0);
+	}
+
+	return !regexec(ereg, event->system, 0, NULL, 0) ||
+		!regexec(ereg, event->name, 0, NULL, 0);
+}
+
+static int
+find_event(struct pevent *pevent, struct event_list **events,
+	   char *sys_name, char *event_name)
+{
+	struct event_format *event;
+	regex_t ereg;
+	regex_t sreg;
+	int match = 0;
+	char *reg;
+	int ret;
+	int i;
+
+	if (!event_name) {
+		/* if no name is given, then swap sys and name */
+		event_name = sys_name;
+		sys_name = NULL;
+	}
+
+	reg = malloc_or_die(strlen(event_name) + 3);
+	sprintf(reg, "^%s$", event_name);
+
+	ret = regcomp(&ereg, reg, REG_ICASE|REG_NOSUB);
+	free(reg);
+
+	if (ret)
+		return -1;
+
+	if (sys_name) {
+		reg = malloc_or_die(strlen(sys_name) + 3);
+		sprintf(reg, "^%s$", sys_name);
+		ret = regcomp(&sreg, reg, REG_ICASE|REG_NOSUB);
+		free(reg);
+		if (ret) {
+			regfree(&ereg);
+			return -1;
+		}
+	}
+
+	for (i = 0; i < pevent->nr_events; i++) {
+		event = pevent->events[i];
+		if (event_match(event, sys_name ? &sreg : NULL, &ereg)) {
+			match = 1;
+			add_event(events, event);
+		}
+	}
+
+	regfree(&ereg);
+	if (sys_name)
+		regfree(&sreg);
+
+	if (!match)
+		return -1;
+
+	return 0;
+}
+
+static void free_events(struct event_list *events)
+{
+	struct event_list *event;
+
+	while (events) {
+		event = events;
+		events = events->next;
+		free(event);
+	}
+}
+
+static struct filter_arg *
+create_arg_item(struct event_format *event,
+		const char *token, enum filter_arg_type type,
+		char **error_str)
+{
+	struct format_field *field;
+	struct filter_arg *arg;
+
+	arg = allocate_arg();
+
+	switch (type) {
+
+	case EVENT_SQUOTE:
+	case EVENT_DQUOTE:
+		arg->type = FILTER_ARG_VALUE;
+		arg->value.type =
+			type == EVENT_DQUOTE ? FILTER_STRING : FILTER_CHAR;
+		arg->value.str = strdup(token);
+		if (!arg->value.str)
+			die("malloc string");
+		break;
+	case EVENT_ITEM:
+		/* if it is a number, then convert it */
+		if (isdigit(token[0])) {
+			arg->type = FILTER_ARG_VALUE;
+			arg->value.type = FILTER_NUMBER;
+			arg->value.val = strtoull(token, NULL, 0);
+			break;
+		}
+		/* Consider this a field */
+		field = pevent_find_any_field(event, token);
+		if (!field) {
+			if (strcmp(token, COMM) != 0) {
+				/* not a field, Make it false */
+				arg->type = FILTER_ARG_BOOLEAN;
+				arg->bool.value = FILTER_FALSE;
+				break;
+			}
+			/* If token is 'COMM' then it is special */
+			field = &comm;
+		}
+		arg->type = FILTER_ARG_FIELD;
+		arg->field.field = field;
+		break;
+	default:
+		free_arg(arg);
+		show_error(error_str, "expected a value but found %s",
+			   token);
+		return NULL;
+	}
+	return arg;
+}
+
+static struct filter_arg *
+create_arg_op(enum filter_op_type btype)
+{
+	struct filter_arg *arg;
+
+	arg = allocate_arg();
+	arg->type = FILTER_ARG_OP;
+	arg->op.type = btype;
+
+	return arg;
+}
+
+static struct filter_arg *
+create_arg_exp(enum filter_exp_type etype)
+{
+	struct filter_arg *arg;
+
+	arg = allocate_arg();
+	arg->type = FILTER_ARG_EXP;
+	arg->op.type = etype;
+
+	return arg;
+}
+
+static struct filter_arg *
+create_arg_cmp(enum filter_exp_type etype)
+{
+	struct filter_arg *arg;
+
+	arg = allocate_arg();
+	/* Use NUM and change if necessary */
+	arg->type = FILTER_ARG_NUM;
+	arg->op.type = etype;
+
+	return arg;
+}
+
+static int add_right(struct filter_arg *op, struct filter_arg *arg,
+		     char **error_str)
+{
+	struct filter_arg *left;
+	char *str;
+	int op_type;
+	int ret;
+
+	switch (op->type) {
+	case FILTER_ARG_EXP:
+		if (op->exp.right)
+			goto out_fail;
+		op->exp.right = arg;
+		break;
+
+	case FILTER_ARG_OP:
+		if (op->op.right)
+			goto out_fail;
+		op->op.right = arg;
+		break;
+
+	case FILTER_ARG_NUM:
+		if (op->op.right)
+			goto out_fail;
+		/*
+		 * The arg must be num, str, or field
+		 */
+		switch (arg->type) {
+		case FILTER_ARG_VALUE:
+		case FILTER_ARG_FIELD:
+			break;
+		default:
+			show_error(error_str,
+				   "Illegal rvalue");
+			return -1;
+		}
+
+		/*
+		 * Depending on the type, we may need to
+		 * convert this to a string or regex.
+		 */
+		switch (arg->value.type) {
+		case FILTER_CHAR:
+			/*
+			 * A char should be converted to number if
+			 * the string is 1 byte, and the compare
+			 * is not a REGEX.
+			 */
+			if (strlen(arg->value.str) == 1 &&
+			    op->num.type != FILTER_CMP_REGEX &&
+			    op->num.type != FILTER_CMP_NOT_REGEX) {
+				arg->value.type = FILTER_NUMBER;
+				goto do_int;
+			}
+			/* fall through */
+		case FILTER_STRING:
+
+			/* convert op to a string arg */
+			op_type = op->num.type;
+			left = op->num.left;
+			str = arg->value.str;
+
+			/* reset the op for the new field */
+			memset(op, 0, sizeof(*op));
+
+			/*
+			 * If left arg was a field not found then
+			 * NULL the entire op.
+			 */
+			if (left->type == FILTER_ARG_BOOLEAN) {
+				free_arg(left);
+				free_arg(arg);
+				op->type = FILTER_ARG_BOOLEAN;
+				op->bool.value = FILTER_FALSE;
+				break;
+			}
+
+			/* Left arg must be a field */
+			if (left->type != FILTER_ARG_FIELD) {
+				show_error(error_str,
+					   "Illegal lvalue for string comparison");
+				return -1;
+			}
+
+			/* Make sure this is a valid string compare */
+			switch (op_type) {
+			case FILTER_CMP_EQ:
+				op_type = FILTER_CMP_MATCH;
+				break;
+			case FILTER_CMP_NE:
+				op_type = FILTER_CMP_NOT_MATCH;
+				break;
+
+			case FILTER_CMP_REGEX:
+			case FILTER_CMP_NOT_REGEX:
+				ret = regcomp(&op->str.reg, str, REG_ICASE|REG_NOSUB);
+				if (ret) {
+					show_error(error_str,
+						   "RegEx '%s' did not compute",
+						   str);
+					return -1;
+				}
+				break;
+			default:
+				show_error(error_str,
+					   "Illegal comparison for string");
+				return -1;
+			}
+
+			op->type = FILTER_ARG_STR;
+			op->str.type = op_type;
+			op->str.field = left->field.field;
+			op->str.val = strdup(str);
+			if (!op->str.val)
+				die("malloc string");
+			/*
+			 * Need a buffer to copy data for tests
+			 */
+			op->str.buffer = malloc_or_die(op->str.field->size + 1);
+			/* Null terminate this buffer */
+			op->str.buffer[op->str.field->size] = 0;
+
+			/* We no longer have left or right args */
+			free_arg(arg);
+			free_arg(left);
+
+			break;
+
+		case FILTER_NUMBER:
+
+ do_int:
+			switch (op->num.type) {
+			case FILTER_CMP_REGEX:
+			case FILTER_CMP_NOT_REGEX:
+				show_error(error_str,
+					   "Op not allowed with integers");
+				return -1;
+
+			default:
+				break;
+			}
+
+			/* numeric compare */
+			op->num.right = arg;
+			break;
+		default:
+			goto out_fail;
+		}
+		break;
+	default:
+		goto out_fail;
+	}
+
+	return 0;
+
+ out_fail:
+	show_error(error_str,
+		   "Syntax error");
+	return -1;
+}
+
+static struct filter_arg *
+rotate_op_right(struct filter_arg *a, struct filter_arg *b)
+{
+	struct filter_arg *arg;
+
+	arg = a->op.right;
+	a->op.right = b;
+	return arg;
+}
+
+static int add_left(struct filter_arg *op, struct filter_arg *arg)
+{
+	switch (op->type) {
+	case FILTER_ARG_EXP:
+		if (arg->type == FILTER_ARG_OP)
+			arg = rotate_op_right(arg, op);
+		op->exp.left = arg;
+		break;
+
+	case FILTER_ARG_OP:
+		op->op.left = arg;
+		break;
+	case FILTER_ARG_NUM:
+		if (arg->type == FILTER_ARG_OP)
+			arg = rotate_op_right(arg, op);
+
+		/* left arg of compares must be a field */
+		if (arg->type != FILTER_ARG_FIELD &&
+		    arg->type != FILTER_ARG_BOOLEAN)
+			return -1;
+		op->num.left = arg;
+		break;
+	default:
+		return -1;
+	}
+	return 0;
+}
+
+enum op_type {
+	OP_NONE,
+	OP_BOOL,
+	OP_NOT,
+	OP_EXP,
+	OP_CMP,
+};
+
+static enum op_type process_op(const char *token,
+			       enum filter_op_type *btype,
+			       enum filter_cmp_type *ctype,
+			       enum filter_exp_type *etype)
+{
+	*btype = FILTER_OP_NOT;
+	*etype = FILTER_EXP_NONE;
+	*ctype = FILTER_CMP_NONE;
+
+	if (strcmp(token, "&&") == 0)
+		*btype = FILTER_OP_AND;
+	else if (strcmp(token, "||") == 0)
+		*btype = FILTER_OP_OR;
+	else if (strcmp(token, "!") == 0)
+		return OP_NOT;
+
+	if (*btype != FILTER_OP_NOT)
+		return OP_BOOL;
+
+	/* Check for value expressions */
+	if (strcmp(token, "+") == 0) {
+		*etype = FILTER_EXP_ADD;
+	} else if (strcmp(token, "-") == 0) {
+		*etype = FILTER_EXP_SUB;
+	} else if (strcmp(token, "*") == 0) {
+		*etype = FILTER_EXP_MUL;
+	} else if (strcmp(token, "/") == 0) {
+		*etype = FILTER_EXP_DIV;
+	} else if (strcmp(token, "%") == 0) {
+		*etype = FILTER_EXP_MOD;
+	} else if (strcmp(token, ">>") == 0) {
+		*etype = FILTER_EXP_RSHIFT;
+	} else if (strcmp(token, "<<") == 0) {
+		*etype = FILTER_EXP_LSHIFT;
+	} else if (strcmp(token, "&") == 0) {
+		*etype = FILTER_EXP_AND;
+	} else if (strcmp(token, "|") == 0) {
+		*etype = FILTER_EXP_OR;
+	} else if (strcmp(token, "^") == 0) {
+		*etype = FILTER_EXP_XOR;
+	} else if (strcmp(token, "~") == 0)
+		*etype = FILTER_EXP_NOT;
+
+	if (*etype != FILTER_EXP_NONE)
+		return OP_EXP;
+
+	/* Check for compares */
+	if (strcmp(token, "==") == 0)
+		*ctype = FILTER_CMP_EQ;
+	else if (strcmp(token, "!=") == 0)
+		*ctype = FILTER_CMP_NE;
+	else if (strcmp(token, "<") == 0)
+		*ctype = FILTER_CMP_LT;
+	else if (strcmp(token, ">") == 0)
+		*ctype = FILTER_CMP_GT;
+	else if (strcmp(token, "<=") == 0)
+		*ctype = FILTER_CMP_LE;
+	else if (strcmp(token, ">=") == 0)
+		*ctype = FILTER_CMP_GE;
+	else if (strcmp(token, "=~") == 0)
+		*ctype = FILTER_CMP_REGEX;
+	else if (strcmp(token, "!~") == 0)
+		*ctype = FILTER_CMP_NOT_REGEX;
+	else
+		return OP_NONE;
+
+	return OP_CMP;
+}
+
+static int check_op_done(struct filter_arg *arg)
+{
+	switch (arg->type) {
+	case FILTER_ARG_EXP:
+		return arg->exp.right != NULL;
+
+	case FILTER_ARG_OP:
+		return arg->op.right != NULL;
+
+	case FILTER_ARG_NUM:
+		return arg->num.right != NULL;
+
+	case FILTER_ARG_STR:
+		/* A string conversion is always done */
+		return 1;
+
+	case FILTER_ARG_BOOLEAN:
+		/* field not found, is ok */
+		return 1;
+
+	default:
+		return 0;
+	}
+}
+
+enum filter_vals {
+	FILTER_VAL_NORM,
+	FILTER_VAL_FALSE,
+	FILTER_VAL_TRUE,
+};
+
+void reparent_op_arg(struct filter_arg *parent, struct filter_arg *old_child,
+		  struct filter_arg *arg)
+{
+	struct filter_arg *other_child;
+	struct filter_arg **ptr;
+
+	if (parent->type != FILTER_ARG_OP &&
+	    arg->type != FILTER_ARG_OP)
+		die("can not reparent other than OP");
+
+	/* Get the sibling */
+	if (old_child->op.right == arg) {
+		ptr = &old_child->op.right;
+		other_child = old_child->op.left;
+	} else if (old_child->op.left == arg) {
+		ptr = &old_child->op.left;
+		other_child = old_child->op.right;
+	} else
+		die("Error in reparent op, find other child");
+
+	/* Detach arg from old_child */
+	*ptr = NULL;
+
+	/* Check for root */
+	if (parent == old_child) {
+		free_arg(other_child);
+		*parent = *arg;
+		/* Free arg without recussion */
+		free(arg);
+		return;
+	}
+
+	if (parent->op.right == old_child)
+		ptr = &parent->op.right;
+	else if (parent->op.left == old_child)
+		ptr = &parent->op.left;
+	else
+		die("Error in reparent op");
+	*ptr = arg;
+
+	free_arg(old_child);
+}
+
+enum filter_vals test_arg(struct filter_arg *parent, struct filter_arg *arg)
+{
+	enum filter_vals lval, rval;
+
+	switch (arg->type) {
+
+		/* bad case */
+	case FILTER_ARG_BOOLEAN:
+		return FILTER_VAL_FALSE + arg->bool.value;
+
+		/* good cases: */
+	case FILTER_ARG_STR:
+	case FILTER_ARG_VALUE:
+	case FILTER_ARG_FIELD:
+		return FILTER_VAL_NORM;
+
+	case FILTER_ARG_EXP:
+		lval = test_arg(arg, arg->exp.left);
+		if (lval != FILTER_VAL_NORM)
+			return lval;
+		rval = test_arg(arg, arg->exp.right);
+		if (rval != FILTER_VAL_NORM)
+			return rval;
+		return FILTER_VAL_NORM;
+
+	case FILTER_ARG_NUM:
+		lval = test_arg(arg, arg->num.left);
+		if (lval != FILTER_VAL_NORM)
+			return lval;
+		rval = test_arg(arg, arg->num.right);
+		if (rval != FILTER_VAL_NORM)
+			return rval;
+		return FILTER_VAL_NORM;
+
+	case FILTER_ARG_OP:
+		if (arg->op.type != FILTER_OP_NOT) {
+			lval = test_arg(arg, arg->op.left);
+			switch (lval) {
+			case FILTER_VAL_NORM:
+				break;
+			case FILTER_VAL_TRUE:
+				if (arg->op.type == FILTER_OP_OR)
+					return FILTER_VAL_TRUE;
+				rval = test_arg(arg, arg->op.right);
+				if (rval != FILTER_VAL_NORM)
+					return rval;
+
+				reparent_op_arg(parent, arg, arg->op.right);
+				return FILTER_VAL_NORM;
+
+			case FILTER_VAL_FALSE:
+				if (arg->op.type == FILTER_OP_AND)
+					return FILTER_VAL_FALSE;
+				rval = test_arg(arg, arg->op.right);
+				if (rval != FILTER_VAL_NORM)
+					return rval;
+
+				reparent_op_arg(parent, arg, arg->op.right);
+				return FILTER_VAL_NORM;
+			}
+		}
+
+		rval = test_arg(arg, arg->op.right);
+		switch (rval) {
+		case FILTER_VAL_NORM:
+			break;
+		case FILTER_VAL_TRUE:
+			if (arg->op.type == FILTER_OP_OR)
+				return FILTER_VAL_TRUE;
+			if (arg->op.type == FILTER_OP_NOT)
+				return FILTER_VAL_FALSE;
+
+			reparent_op_arg(parent, arg, arg->op.left);
+			return FILTER_VAL_NORM;
+
+		case FILTER_VAL_FALSE:
+			if (arg->op.type == FILTER_OP_AND)
+				return FILTER_VAL_FALSE;
+			if (arg->op.type == FILTER_OP_NOT)
+				return FILTER_VAL_TRUE;
+
+			reparent_op_arg(parent, arg, arg->op.left);
+			return FILTER_VAL_NORM;
+		}
+
+		return FILTER_VAL_NORM;
+	default:
+		die("bad arg in filter tree");
+	}
+	return FILTER_VAL_NORM;
+}
+
+/* Remove any unknown event fields */
+static struct filter_arg *collapse_tree(struct filter_arg *arg)
+{
+	enum filter_vals ret;
+
+	ret = test_arg(arg, arg);
+	switch (ret) {
+	case FILTER_VAL_NORM:
+		return arg;
+
+	case FILTER_VAL_TRUE:
+	case FILTER_VAL_FALSE:
+		free_arg(arg);
+		arg = allocate_arg();
+		arg->type = FILTER_ARG_BOOLEAN;
+		arg->bool.value = ret == FILTER_VAL_TRUE;
+	}
+
+	return arg;
+}
+
+static int
+process_filter(struct event_format *event, struct filter_arg **parg,
+	       char **error_str, int not)
+{
+	enum event_type type;
+	char *token = NULL;
+	struct filter_arg *current_op = NULL;
+	struct filter_arg *current_exp = NULL;
+	struct filter_arg *left_item = NULL;
+	struct filter_arg *arg = NULL;
+	enum op_type op_type;
+	enum filter_op_type btype;
+	enum filter_exp_type etype;
+	enum filter_cmp_type ctype;
+	int ret;
+
+	*parg = NULL;
+
+	do {
+		free(token);
+		type = read_token(&token);
+		switch (type) {
+		case EVENT_SQUOTE:
+		case EVENT_DQUOTE:
+		case EVENT_ITEM:
+			arg = create_arg_item(event, token, type, error_str);
+			if (!arg)
+				goto fail;
+			if (!left_item)
+				left_item = arg;
+			else if (current_exp) {
+				ret = add_right(current_exp, arg, error_str);
+				if (ret < 0)
+					goto fail;
+				left_item = NULL;
+				/* Not's only one one expression */
+				if (not) {
+					arg = NULL;
+					if (current_op)
+						goto fail_print;
+					free(token);
+					*parg = current_exp;
+					return 0;
+				}
+			} else
+				goto fail_print;
+			arg = NULL;
+			break;
+
+		case EVENT_DELIM:
+			if (*token == ',') {
+				show_error(error_str,
+					   "Illegal token ','");
+				goto fail;
+			}
+
+			if (*token == '(') {
+				if (left_item) {
+					show_error(error_str,
+						   "Open paren can not come after item");
+					goto fail;
+				}
+				if (current_exp) {
+					show_error(error_str,
+						   "Open paren can not come after expression");
+					goto fail;
+				}
+
+				ret = process_filter(event, &arg, error_str, 0);
+				if (ret != 1) {
+					if (ret == 0)
+						show_error(error_str,
+							   "Unbalanced number of '('");
+					goto fail;
+				}
+				ret = 0;
+
+				/* A not wants just one expression */
+				if (not) {
+					if (current_op)
+						goto fail_print;
+					*parg = arg;
+					return 0;
+				}
+
+				if (current_op)
+					ret = add_right(current_op, arg, error_str);
+				else
+					current_exp = arg;
+
+				if (ret < 0)
+					goto fail;
+
+			} else { /* ')' */
+				if (!current_op && !current_exp)
+					goto fail_print;
+
+				/* Make sure everything is finished at this level */
+				if (current_exp && !check_op_done(current_exp))
+					goto fail_print;
+				if (current_op && !check_op_done(current_op))
+					goto fail_print;
+
+				if (current_op)
+					*parg = current_op;
+				else
+					*parg = current_exp;
+				return 1;
+			}
+			break;
+
+		case EVENT_OP:
+			op_type = process_op(token, &btype, &ctype, &etype);
+
+			/* All expect a left arg except for NOT */
+			switch (op_type) {
+			case OP_BOOL:
+				/* Logic ops need a left expression */
+				if (!current_exp && !current_op)
+					goto fail_print;
+				/* fall through */
+			case OP_NOT:
+				/* logic only processes ops and exp */
+				if (left_item)
+					goto fail_print;
+				break;
+			case OP_EXP:
+			case OP_CMP:
+				if (!left_item)
+					goto fail_print;
+				break;
+			case OP_NONE:
+				show_error(error_str,
+					   "Unknown op token %s", token);
+				goto fail;
+			}
+
+			ret = 0;
+			switch (op_type) {
+			case OP_BOOL:
+				arg = create_arg_op(btype);
+				if (current_op)
+					ret = add_left(arg, current_op);
+				else
+					ret = add_left(arg, current_exp);
+				current_op = arg;
+				current_exp = NULL;
+				break;
+
+			case OP_NOT:
+				arg = create_arg_op(btype);
+				if (current_op)
+					ret = add_right(current_op, arg, error_str);
+				if (ret < 0)
+					goto fail;
+				current_exp = arg;
+				ret = process_filter(event, &arg, error_str, 1);
+				if (ret < 0)
+					goto fail;
+				ret = add_right(current_exp, arg, error_str);
+				if (ret < 0)
+					goto fail;
+				break;
+
+			case OP_EXP:
+			case OP_CMP:
+				if (op_type == OP_EXP)
+					arg = create_arg_exp(etype);
+				else
+					arg = create_arg_cmp(ctype);
+
+				if (current_op)
+					ret = add_right(current_op, arg, error_str);
+				if (ret < 0)
+					goto fail;
+				ret = add_left(arg, left_item);
+				if (ret < 0) {
+					arg = NULL;
+					goto fail_print;
+				}
+				current_exp = arg;
+				break;
+			default:
+				break;
+			}
+			arg = NULL;
+			if (ret < 0)
+				goto fail_print;
+			break;
+		case EVENT_NONE:
+			break;
+		default:
+			goto fail_print;
+		}
+	} while (type != EVENT_NONE);
+
+	if (!current_op && !current_exp)
+		goto fail_print;
+
+	if (!current_op)
+		current_op = current_exp;
+
+	current_op = collapse_tree(current_op);
+
+	*parg = current_op;
+
+	return 0;
+
+ fail_print:
+	show_error(error_str, "Syntax error");
+ fail:
+	free_arg(current_op);
+	free_arg(current_exp);
+	free_arg(arg);
+	free(token);
+	return -1;
+}
+
+static int
+process_event(struct event_format *event, const char *filter_str,
+	      struct filter_arg **parg, char **error_str)
+{
+	int ret;
+
+	pevent_buffer_init(filter_str, strlen(filter_str));
+
+	ret = process_filter(event, parg, error_str, 0);
+	if (ret == 1) {
+		show_error(error_str,
+			   "Unbalanced number of ')'");
+		return -1;
+	}
+	if (ret < 0)
+		return ret;
+
+	/* If parg is NULL, then make it into FALSE */
+	if (!*parg) {
+		*parg = allocate_arg();
+		(*parg)->type = FILTER_ARG_BOOLEAN;
+		(*parg)->bool.value = FILTER_FALSE;
+	}
+
+	return 0;
+}
+
+static int filter_event(struct event_filter *filter,
+			struct event_format *event,
+			const char *filter_str, char **error_str)
+{
+	struct filter_type *filter_type;
+	struct filter_arg *arg;
+	int ret;
+
+	if (filter_str) {
+		ret = process_event(event, filter_str, &arg, error_str);
+		if (ret < 0)
+			return ret;
+
+	} else {
+		/* just add a TRUE arg */
+		arg = allocate_arg();
+		arg->type = FILTER_ARG_BOOLEAN;
+		arg->bool.value = FILTER_TRUE;
+	}
+
+	filter_type = add_filter_type(filter, event->id);
+	if (filter_type->filter)
+		free_arg(filter_type->filter);
+	filter_type->filter = arg;
+
+	return 0;
+}
+
+/**
+ * pevent_filter_add_filter_str - add a new filter
+ * @filter: the event filter to add to
+ * @filter_str: the filter string that contains the filter
+ * @error_str: string containing reason for failed filter
+ *
+ * Returns 0 if the filter was successfully added
+ *   -1 if there was an error.
+ *
+ * On error, if @error_str points to a string pointer,
+ * it is set to the reason that the filter failed.
+ * This string must be freed with "free".
+ */
+int pevent_filter_add_filter_str(struct event_filter *filter,
+				 const char *filter_str,
+				 char **error_str)
+{
+	struct pevent *pevent = filter->pevent;
+	struct event_list *event;
+	struct event_list *events = NULL;
+	const char *filter_start;
+	const char *next_event;
+	char *this_event;
+	char *event_name = NULL;
+	char *sys_name = NULL;
+	char *sp;
+	int rtn = 0;
+	int len;
+	int ret;
+
+	/* clear buffer to reset show error */
+	pevent_buffer_init("", 0);
+
+	if (error_str)
+		*error_str = NULL;
+
+	filter_start = strchr(filter_str, ':');
+	if (filter_start)
+		len = filter_start - filter_str;
+	else
+		len = strlen(filter_str);
+
+
+	do {
+		next_event = strchr(filter_str, ',');
+		if (next_event &&
+		    (!filter_start || next_event < filter_start))
+			len = next_event - filter_str;
+		else if (filter_start)
+			len = filter_start - filter_str;
+		else
+			len = strlen(filter_str);
+
+		this_event = malloc_or_die(len + 1);
+		memcpy(this_event, filter_str, len);
+		this_event[len] = 0;
+
+		if (next_event)
+			next_event++;
+
+		filter_str = next_event;
+
+		sys_name = strtok_r(this_event, "/", &sp);
+		event_name = strtok_r(NULL, "/", &sp);
+
+		if (!sys_name) {
+			show_error(error_str, "No filter found");
+			/* This can only happen when events is NULL, but still */
+			free_events(events);
+			free(this_event);
+			return -1;
+		}
+
+		/* Find this event */
+		ret = find_event(pevent, &events, strim(sys_name), strim(event_name));
+		if (ret < 0) {
+			if (event_name)
+				show_error(error_str,
+					   "No event found under '%s.%s'",
+					   sys_name, event_name);
+			else
+				show_error(error_str,
+					   "No event found under '%s'",
+					   sys_name);
+			free_events(events);
+			free(this_event);
+			return -1;
+		}
+		free(this_event);
+	} while (filter_str);
+
+	/* Skip the ':' */
+	if (filter_start)
+		filter_start++;
+
+	/* filter starts here */
+	for (event = events; event; event = event->next) {
+		ret = filter_event(filter, event->event, filter_start,
+				   error_str);
+		/* Failures are returned if a parse error happened */
+		if (ret < 0)
+			rtn = ret;
+
+		if (ret >= 0 && pevent->test_filters) {
+			char *test;
+			test = pevent_filter_make_string(filter, event->event->id);
+			printf(" '%s: %s'\n", event->event->name, test);
+			free(test);
+		}
+	}
+
+	free_events(events);
+
+	if (rtn >= 0 && pevent->test_filters)
+		exit(0);
+
+	return rtn;
+}
+
+static void free_filter_type(struct filter_type *filter_type)
+{
+	free_arg(filter_type->filter);
+}
+
+/**
+ * pevent_filter_remove_event - remove a filter for an event
+ * @filter: the event filter to remove from
+ * @event_id: the event to remove a filter for
+ *
+ * Removes the filter saved for an event defined by @event_id
+ * from the @filter.
+ *
+ * Returns 1: if an event was removed
+ *   0: if the event was not found
+ */
+int pevent_filter_remove_event(struct event_filter *filter,
+			       int event_id)
+{
+	struct filter_type *filter_type;
+	unsigned long len;
+
+	if (!filter->filters)
+		return 0;
+
+	filter_type = find_filter_type(filter, event_id);
+
+	if (!filter_type)
+		return 0;
+
+	free_filter_type(filter_type);
+
+	/* The filter_type points into the event_filters array */
+	len = (unsigned long)(filter->event_filters + filter->filters) -
+		(unsigned long)(filter_type + 1);
+
+	memmove(filter_type, filter_type + 1, len);
+	filter->filters--;
+
+	memset(&filter->event_filters[filter->filters], 0,
+	       sizeof(*filter_type));
+
+	return 1;
+}
+
+/**
+ * pevent_filter_reset - clear all filters in a filter
+ * @filter: the event filter to reset
+ *
+ * Removes all filters from a filter and resets it.
+ */
+void pevent_filter_reset(struct event_filter *filter)
+{
+	int i;
+
+	for (i = 0; i < filter->filters; i++)
+		free_filter_type(&filter->event_filters[i]);
+
+	free(filter->event_filters);
+	filter->filters = 0;
+	filter->event_filters = NULL;
+}
+
+void pevent_filter_free(struct event_filter *filter)
+{
+	pevent_unref(filter->pevent);
+
+	pevent_filter_reset(filter);
+
+	free(filter);
+}
+
+static char *arg_to_str(struct event_filter *filter, struct filter_arg *arg);
+
+static int copy_filter_type(struct event_filter *filter,
+			     struct event_filter *source,
+			     struct filter_type *filter_type)
+{
+	struct filter_arg *arg;
+	struct event_format *event;
+	const char *sys;
+	const char *name;
+	char *str;
+
+	/* Can't assume that the pevent's are the same */
+	sys = filter_type->event->system;
+	name = filter_type->event->name;
+	event = pevent_find_event_by_name(filter->pevent, sys, name);
+	if (!event)
+		return -1;
+
+	str = arg_to_str(source, filter_type->filter);
+	if (!str)
+		return -1;
+
+	if (strcmp(str, "TRUE") == 0 || strcmp(str, "FALSE") == 0) {
+		/* Add trivial event */
+		arg = allocate_arg();
+		arg->type = FILTER_ARG_BOOLEAN;
+		if (strcmp(str, "TRUE") == 0)
+			arg->bool.value = 1;
+		else
+			arg->bool.value = 0;
+
+		filter_type = add_filter_type(filter, event->id);
+		filter_type->filter = arg;
+
+		free(str);
+		return 0;
+	}
+
+	filter_event(filter, event, str, NULL);
+	free(str);
+
+	return 0;
+}
+
+/**
+ * pevent_filter_copy - copy a filter using another filter
+ * @dest - the filter to copy to
+ * @source - the filter to copy from
+ *
+ * Returns 0 on success and -1 if not all filters were copied
+ */
+int pevent_filter_copy(struct event_filter *dest, struct event_filter *source)
+{
+	int ret = 0;
+	int i;
+
+	pevent_filter_reset(dest);
+
+	for (i = 0; i < source->filters; i++) {
+		if (copy_filter_type(dest, source, &source->event_filters[i]))
+			ret = -1;
+	}
+	return ret;
+}
+
+
+/**
+ * pevent_update_trivial - update the trivial filters with the given filter
+ * @dest - the filter to update
+ * @source - the filter as the source of the update
+ * @type - the type of trivial filter to update.
+ *
+ * Scan dest for trivial events matching @type to replace with the source.
+ *
+ * Returns 0 on success and -1 if there was a problem updating, but
+ *   events may have still been updated on error.
+ */
+int pevent_update_trivial(struct event_filter *dest, struct event_filter *source,
+			  enum filter_trivial_type type)
+{
+	struct pevent *src_pevent;
+	struct pevent *dest_pevent;
+	struct event_format *event;
+	struct filter_type *filter_type;
+	struct filter_arg *arg;
+	char *str;
+	int i;
+
+	src_pevent = source->pevent;
+	dest_pevent = dest->pevent;
+
+	/* Do nothing if either of the filters has nothing to filter */
+	if (!dest->filters || !source->filters)
+		return 0;
+
+	for (i = 0; i < dest->filters; i++) {
+		filter_type = &dest->event_filters[i];
+		arg = filter_type->filter;
+		if (arg->type != FILTER_ARG_BOOLEAN)
+			continue;
+		if ((arg->bool.value && type == FILTER_TRIVIAL_FALSE) ||
+		    (!arg->bool.value && type == FILTER_TRIVIAL_TRUE))
+			continue;
+
+		event = filter_type->event;
+
+		if (src_pevent != dest_pevent) {
+			/* do a look up */
+			event = pevent_find_event_by_name(src_pevent,
+							  event->system,
+							  event->name);
+			if (!event)
+				return -1;
+		}
+
+		str = pevent_filter_make_string(source, event->id);
+		if (!str)
+			continue;
+
+		/* Don't bother if the filter is trivial too */
+		if (strcmp(str, "TRUE") != 0 && strcmp(str, "FALSE") != 0)
+			filter_event(dest, event, str, NULL);
+		free(str);
+	}
+	return 0;
+}
+
+/**
+ * pevent_filter_clear_trivial - clear TRUE and FALSE filters
+ * @filter: the filter to remove trivial filters from
+ * @type: remove only true, false, or both
+ *
+ * Removes filters that only contain a TRUE or FALES boolean arg.
+ */
+void pevent_filter_clear_trivial(struct event_filter *filter,
+				 enum filter_trivial_type type)
+{
+	struct filter_type *filter_type;
+	int count = 0;
+	int *ids;
+	int i;
+
+	if (!filter->filters)
+		return;
+
+	/*
+	 * Two steps, first get all ids with trivial filters.
+	 *  then remove those ids.
+	 */
+	for (i = 0; i < filter->filters; i++) {
+		filter_type = &filter->event_filters[i];
+		if (filter_type->filter->type != FILTER_ARG_BOOLEAN)
+			continue;
+		switch (type) {
+		case FILTER_TRIVIAL_FALSE:
+			if (filter_type->filter->bool.value)
+				continue;
+		case FILTER_TRIVIAL_TRUE:
+			if (!filter_type->filter->bool.value)
+				continue;
+		default:
+			break;
+		}
+		if (count)
+			ids = realloc(ids, sizeof(*ids) * (count + 1));
+		else
+			ids = malloc(sizeof(*ids));
+		if (!ids)
+			die("Can't allocate ids");
+		ids[count++] = filter_type->event_id;
+	}
+
+	if (!count)
+		return;
+
+	for (i = 0; i < count; i++)
+		pevent_filter_remove_event(filter, ids[i]);
+
+	free(ids);
+}
+
+/**
+ * pevent_filter_event_has_trivial - return true event contains trivial filter
+ * @filter: the filter with the information
+ * @event_id: the id of the event to test
+ * @type: trivial type to test for (TRUE, FALSE, EITHER)
+ *
+ * Returns 1 if the event contains a matching trivial type
+ *  otherwise 0.
+ */
+int pevent_filter_event_has_trivial(struct event_filter *filter,
+				    int event_id,
+				    enum filter_trivial_type type)
+{
+	struct filter_type *filter_type;
+
+	if (!filter->filters)
+		return 0;
+
+	filter_type = find_filter_type(filter, event_id);
+
+	if (!filter_type)
+		return 0;
+
+	if (filter_type->filter->type != FILTER_ARG_BOOLEAN)
+		return 0;
+
+	switch (type) {
+	case FILTER_TRIVIAL_FALSE:
+		return !filter_type->filter->bool.value;
+
+	case FILTER_TRIVIAL_TRUE:
+		return filter_type->filter->bool.value;
+	default:
+		return 1;
+	}
+}
+
+static int test_filter(struct event_format *event,
+		       struct filter_arg *arg, struct record *record);
+
+static const char *
+get_comm(struct event_format *event, struct record *record)
+{
+	const char *comm;
+	int pid;
+
+	pid = pevent_data_pid(event->pevent, record);
+	comm = pevent_data_comm_from_pid(event->pevent, pid);
+	return comm;
+}
+
+static unsigned long long
+get_value(struct event_format *event,
+	  struct format_field *field, struct record *record)
+{
+	unsigned long long val;
+
+	/* Handle our dummy "comm" field */
+	if (field == &comm) {
+		const char *name;
+
+		name = get_comm(event, record);
+		return (unsigned long long)name;
+	}
+
+	pevent_read_number_field(field, record->data, &val);
+
+	if (!(field->flags & FIELD_IS_SIGNED))
+		return val;
+
+	switch (field->size) {
+	case 1:
+		return (char)val;
+	case 2:
+		return (short)val;
+	case 4:
+		return (int)val;
+	case 8:
+		return (long long)val;
+	}
+	return val;
+}
+
+static unsigned long long
+get_arg_value(struct event_format *event, struct filter_arg *arg, struct record *record);
+
+static unsigned long long
+get_exp_value(struct event_format *event, struct filter_arg *arg, struct record *record)
+{
+	unsigned long long lval, rval;
+
+	lval = get_arg_value(event, arg->exp.left, record);
+	rval = get_arg_value(event, arg->exp.right, record);
+
+	switch (arg->exp.type) {
+	case FILTER_EXP_ADD:
+		return lval + rval;
+
+	case FILTER_EXP_SUB:
+		return lval - rval;
+
+	case FILTER_EXP_MUL:
+		return lval * rval;
+
+	case FILTER_EXP_DIV:
+		return lval / rval;
+
+	case FILTER_EXP_MOD:
+		return lval % rval;
+
+	case FILTER_EXP_RSHIFT:
+		return lval >> rval;
+
+	case FILTER_EXP_LSHIFT:
+		return lval << rval;
+
+	case FILTER_EXP_AND:
+		return lval & rval;
+
+	case FILTER_EXP_OR:
+		return lval | rval;
+
+	case FILTER_EXP_XOR:
+		return lval ^ rval;
+
+	case FILTER_EXP_NOT:
+	default:
+		die("error in exp");
+	}
+	return 0;
+}
+
+static unsigned long long
+get_arg_value(struct event_format *event, struct filter_arg *arg, struct record *record)
+{
+	switch (arg->type) {
+	case FILTER_ARG_FIELD:
+		return get_value(event, arg->field.field, record);
+
+	case FILTER_ARG_VALUE:
+		if (arg->value.type != FILTER_NUMBER)
+			die("must have number field!");
+		return arg->value.val;
+
+	case FILTER_ARG_EXP:
+		return get_exp_value(event, arg, record);
+
+	default:
+		die("oops in filter");
+	}
+	return 0;
+}
+
+static int test_num(struct event_format *event,
+		    struct filter_arg *arg, struct record *record)
+{
+	unsigned long long lval, rval;
+
+	lval = get_arg_value(event, arg->num.left, record);
+	rval = get_arg_value(event, arg->num.right, record);
+
+	switch (arg->num.type) {
+	case FILTER_CMP_EQ:
+		return lval == rval;
+
+	case FILTER_CMP_NE:
+		return lval != rval;
+
+	case FILTER_CMP_GT:
+		return lval > rval;
+
+	case FILTER_CMP_LT:
+		return lval < rval;
+
+	case FILTER_CMP_GE:
+		return lval >= rval;
+
+	case FILTER_CMP_LE:
+		return lval <= rval;
+
+	default:
+		/* ?? */
+		return 0;
+	}
+}
+
+static const char *get_field_str(struct filter_arg *arg, struct record *record)
+{
+	const char *val = record->data + arg->str.field->offset;
+
+	/*
+	 * We need to copy the data since we can't be sure the field
+	 * is null terminated.
+	 */
+	if (*(val + arg->str.field->size - 1)) {
+		/* copy it */
+		memcpy(arg->str.buffer, val, arg->str.field->size);
+		/* the buffer is already NULL terminated */
+		val = arg->str.buffer;
+	}
+	return val;
+}
+
+static int test_str(struct event_format *event,
+		    struct filter_arg *arg, struct record *record)
+{
+	const char *val;
+
+	if (arg->str.field == &comm)
+		val = get_comm(event, record);
+	else
+		val = get_field_str(arg, record);
+
+	switch (arg->str.type) {
+	case FILTER_CMP_MATCH:
+		return strcmp(val, arg->str.val) == 0;
+
+	case FILTER_CMP_NOT_MATCH:
+		return strcmp(val, arg->str.val) != 0;
+
+	case FILTER_CMP_REGEX:
+		/* Returns zero on match */
+		return !regexec(&arg->str.reg, val, 0, NULL, 0);
+
+	case FILTER_CMP_NOT_REGEX:
+		return regexec(&arg->str.reg, val, 0, NULL, 0);
+
+	default:
+		/* ?? */
+		return 0;
+	}
+}
+
+static int test_op(struct event_format *event,
+		   struct filter_arg *arg, struct record *record)
+{
+	switch (arg->op.type) {
+	case FILTER_OP_AND:
+		return test_filter(event, arg->op.left, record) &&
+			test_filter(event, arg->op.right, record);
+
+	case FILTER_OP_OR:
+		return test_filter(event, arg->op.left, record) ||
+			test_filter(event, arg->op.right, record);
+
+	case FILTER_OP_NOT:
+		return !test_filter(event, arg->op.right, record);
+
+	default:
+		/* ?? */
+		return 0;
+	}
+}
+
+static int test_filter(struct event_format *event,
+		       struct filter_arg *arg, struct record *record)
+{
+	switch (arg->type) {
+	case FILTER_ARG_BOOLEAN:
+		/* easy case */
+		return arg->bool.value;
+
+	case FILTER_ARG_OP:
+		return test_op(event, arg, record);
+
+	case FILTER_ARG_NUM:
+		return test_num(event, arg, record);
+
+	case FILTER_ARG_STR:
+		return test_str(event, arg, record);
+
+	case FILTER_ARG_EXP:
+	case FILTER_ARG_VALUE:
+	case FILTER_ARG_FIELD:
+		/*
+		 * Expressions, fields and values evaluate
+		 * to true if they return non zero
+		 */
+		return !!get_arg_value(event, arg, record);
+
+	default:
+		die("oops!");
+		/* ?? */
+		return 0;
+	}
+}
+
+/**
+ * pevent_event_filtered - return true if event has filter
+ * @filter: filter struct with filter information
+ * @event_id: event id to test if filter exists
+ *
+ * Returns 1 if filter found for @event_id
+ *   otherwise 0;
+ */
+int pevent_event_filtered(struct event_filter *filter,
+			  int event_id)
+{
+	struct filter_type *filter_type;
+
+	if (!filter->filters)
+		return 0;
+
+	filter_type = find_filter_type(filter, event_id);
+
+	return filter_type ? 1 : 0;
+}
+
+/**
+ * pevent_filter_match - test if a record matches a filter
+ * @filter: filter struct with filter information
+ * @record: the record to test against the filter
+ *
+ * Returns:
+ *  1 - filter found for event and @record matches
+ *  0 - filter found for event and @record does not match
+ * -1 - no filter found for @record's event
+ * -2 - if no filters exist
+ */
+int pevent_filter_match(struct event_filter *filter,
+			struct record *record)
+{
+	struct pevent *pevent = filter->pevent;
+	struct filter_type *filter_type;
+	int event_id;
+
+	if (!filter->filters)
+		return FILTER_NONE;
+
+	event_id = pevent_data_type(pevent, record);
+
+	filter_type = find_filter_type(filter, event_id);
+
+	if (!filter_type)
+		return FILTER_NOEXIST;
+
+	return test_filter(filter_type->event, filter_type->filter, record) ?
+		FILTER_MATCH : FILTER_MISS;
+}
+
+static char *op_to_str(struct event_filter *filter, struct filter_arg *arg)
+{
+	char *str = NULL;
+	char *left = NULL;
+	char *right = NULL;
+	char *op = NULL;
+	int left_val = -1;
+	int right_val = -1;
+	int val;
+	int len;
+
+	switch (arg->op.type) {
+	case FILTER_OP_AND:
+		op = "&&";
+		/* fall through */
+	case FILTER_OP_OR:
+		if (!op)
+			op = "||";
+
+		left = arg_to_str(filter, arg->op.left);
+		right = arg_to_str(filter, arg->op.right);
+		if (!left || !right)
+			break;
+
+		/* Try to consolidate boolean values */
+		if (strcmp(left, "TRUE") == 0)
+			left_val = 1;
+		else if (strcmp(left, "FALSE") == 0)
+			left_val = 0;
+
+		if (strcmp(right, "TRUE") == 0)
+			right_val = 1;
+		else if (strcmp(right, "FALSE") == 0)
+			right_val = 0;
+
+		if (left_val >= 0) {
+			if ((arg->op.type == FILTER_OP_AND && !left_val) ||
+			    (arg->op.type == FILTER_OP_OR && left_val)) {
+				/* Just return left value */
+				str = left;
+				left = NULL;
+				break;
+			}
+			if (right_val >= 0) {
+				/* just evaluate this. */
+				val = 0;
+				switch (arg->op.type) {
+				case FILTER_OP_AND:
+					val = left_val && right_val;
+					break;
+				case FILTER_OP_OR:
+					val = left_val || right_val;
+					break;
+				default:
+					break;
+				}
+				str = malloc_or_die(6);
+				if (val)
+					strcpy(str, "TRUE");
+				else
+					strcpy(str, "FALSE");
+				break;
+			}
+		}
+		if (right_val >= 0) {
+			if ((arg->op.type == FILTER_OP_AND && !right_val) ||
+			    (arg->op.type == FILTER_OP_OR && right_val)) {
+				/* Just return right value */
+				str = right;
+				right = NULL;
+				break;
+			}
+			/* The right value is meaningless */
+			str = left;
+			left = NULL;
+			break;
+		}
+
+		len = strlen(left) + strlen(right) + strlen(op) + 10;
+		str = malloc_or_die(len);
+		snprintf(str, len, "(%s) %s (%s)",
+			 left, op, right);
+		break;
+
+	case FILTER_OP_NOT:
+		op = "!";
+		right = arg_to_str(filter, arg->op.right);
+		if (!right)
+			break;
+
+		/* See if we can consolidate */
+		if (strcmp(right, "TRUE") == 0)
+			right_val = 1;
+		else if (strcmp(right, "FALSE") == 0)
+			right_val = 0;
+		if (right_val >= 0) {
+			/* just return the opposite */
+			str = malloc_or_die(6);
+			if (right_val)
+				strcpy(str, "FALSE");
+			else
+				strcpy(str, "TRUE");
+			break;
+		}
+		len = strlen(right) + strlen(op) + 3;
+		str = malloc_or_die(len);
+		snprintf(str, len, "%s(%s)", op, right);
+		break;
+
+	default:
+		/* ?? */
+		break;
+	}
+	free(left);
+	free(right);
+	return str;
+}
+
+static char *val_to_str(struct event_filter *filter, struct filter_arg *arg)
+{
+	char *str;
+
+	str = malloc_or_die(30);
+
+	snprintf(str, 30, "%lld", arg->value.val);
+
+	return str;
+}
+
+static char *field_to_str(struct event_filter *filter, struct filter_arg *arg)
+{
+	return strdup(arg->field.field->name);
+}
+
+static char *exp_to_str(struct event_filter *filter, struct filter_arg *arg)
+{
+	char *lstr;
+	char *rstr;
+	char *op;
+	char *str;
+	int len;
+
+	lstr = arg_to_str(filter, arg->exp.left);
+	rstr = arg_to_str(filter, arg->exp.right);
+
+	switch (arg->exp.type) {
+	case FILTER_EXP_ADD:
+		op = "+";
+		break;
+	case FILTER_EXP_SUB:
+		op = "-";
+		break;
+	case FILTER_EXP_MUL:
+		op = "*";
+		break;
+	case FILTER_EXP_DIV:
+		op = "/";
+		break;
+	case FILTER_EXP_MOD:
+		op = "%";
+		break;
+	case FILTER_EXP_RSHIFT:
+		op = ">>";
+		break;
+	case FILTER_EXP_LSHIFT:
+		op = "<<";
+		break;
+	case FILTER_EXP_AND:
+		op = "&";
+		break;
+	case FILTER_EXP_OR:
+		op = "|";
+		break;
+	case FILTER_EXP_XOR:
+		op = "^";
+		break;
+	default:
+		die("oops in exp");
+	}
+
+	len = strlen(op) + strlen(lstr) + strlen(rstr) + 4;
+	str = malloc_or_die(len);
+	snprintf(str, len, "%s %s %s", lstr, op, rstr);
+	free(lstr);
+	free(rstr);
+
+	return str;
+}
+
+static char *num_to_str(struct event_filter *filter, struct filter_arg *arg)
+{
+	char *lstr;
+	char *rstr;
+	char *str = NULL;
+	char *op = NULL;
+	int len;
+
+	lstr = arg_to_str(filter, arg->num.left);
+	rstr = arg_to_str(filter, arg->num.right);
+
+	switch (arg->num.type) {
+	case FILTER_CMP_EQ:
+		op = "==";
+		/* fall through */
+	case FILTER_CMP_NE:
+		if (!op)
+			op = "!=";
+		/* fall through */
+	case FILTER_CMP_GT:
+		if (!op)
+			op = ">";
+		/* fall through */
+	case FILTER_CMP_LT:
+		if (!op)
+			op = "<";
+		/* fall through */
+	case FILTER_CMP_GE:
+		if (!op)
+			op = ">=";
+		/* fall through */
+	case FILTER_CMP_LE:
+		if (!op)
+			op = "<=";
+
+		len = strlen(lstr) + strlen(op) + strlen(rstr) + 4;
+		str = malloc_or_die(len);
+		sprintf(str, "%s %s %s", lstr, op, rstr);
+
+		break;
+
+	default:
+		/* ?? */
+		break;
+	}
+
+	free(lstr);
+	free(rstr);
+	return str;
+}
+
+static char *str_to_str(struct event_filter *filter, struct filter_arg *arg)
+{
+	char *str = NULL;
+	char *op = NULL;
+	int len;
+
+	switch (arg->str.type) {
+	case FILTER_CMP_MATCH:
+		op = "==";
+		/* fall through */
+	case FILTER_CMP_NOT_MATCH:
+		if (!op)
+			op = "!=";
+		/* fall through */
+	case FILTER_CMP_REGEX:
+		if (!op)
+			op = "=~";
+		/* fall through */
+	case FILTER_CMP_NOT_REGEX:
+		if (!op)
+			op = "!~";
+
+		len = strlen(arg->str.field->name) + strlen(op) +
+			strlen(arg->str.val) + 6;
+		str = malloc_or_die(len);
+		snprintf(str, len, "%s %s \"%s\"",
+			 arg->str.field->name,
+			 op, arg->str.val);
+		break;
+
+	default:
+		/* ?? */
+		break;
+	}
+	return str;
+}
+
+static char *arg_to_str(struct event_filter *filter, struct filter_arg *arg)
+{
+	char *str;
+
+	switch (arg->type) {
+	case FILTER_ARG_BOOLEAN:
+		str = malloc_or_die(6);
+		if (arg->bool.value)
+			strcpy(str, "TRUE");
+		else
+			strcpy(str, "FALSE");
+		return str;
+
+	case FILTER_ARG_OP:
+		return op_to_str(filter, arg);
+
+	case FILTER_ARG_NUM:
+		return num_to_str(filter, arg);
+
+	case FILTER_ARG_STR:
+		return str_to_str(filter, arg);
+
+	case FILTER_ARG_VALUE:
+		return val_to_str(filter, arg);
+
+	case FILTER_ARG_FIELD:
+		return field_to_str(filter, arg);
+
+	case FILTER_ARG_EXP:
+		return exp_to_str(filter, arg);
+
+	default:
+		/* ?? */
+		return NULL;
+	}
+
+}
+
+/**
+ * pevent_filter_make_string - return a string showing the filter
+ * @filter: filter struct with filter information
+ * @event_id: the event id to return the filter string with
+ *
+ * Returns a string that displays the filter contents.
+ *  This string must be freed with free(str).
+ *  NULL is returned if no filter is found.
+ */
+char *
+pevent_filter_make_string(struct event_filter *filter, int event_id)
+{
+	struct filter_type *filter_type;
+
+	if (!filter->filters)
+		return NULL;
+
+	filter_type = find_filter_type(filter, event_id);
+
+	if (!filter_type)
+		return NULL;
+
+	return arg_to_str(filter, filter_type->filter);
+}
+
+/**
+ * pevent_filter_compare - compare two filters and return if they are the same
+ * @filter1: Filter to compare with @filter2
+ * @filter2: Filter to compare with @filter1
+ *
+ * Returns:
+ *  1 if the two filters hold the same content.
+ *  0 if they do not.
+ */
+int pevent_filter_compare(struct event_filter *filter1, struct event_filter *filter2)
+{
+	struct filter_type *filter_type1;
+	struct filter_type *filter_type2;
+	char *str1, *str2;
+	int result;
+	int i;
+
+	/* Do the easy checks first */
+	if (filter1->filters != filter2->filters)
+		return 0;
+	if (!filter1->filters && !filter2->filters)
+		return 1;
+
+	/*
+	 * Now take a look at each of the events to see if they have the same
+	 * filters to them.
+	 */
+	for (i = 0; i < filter1->filters; i++) {
+		filter_type1 = &filter1->event_filters[i];
+		filter_type2 = find_filter_type(filter2, filter_type1->event_id);
+		if (!filter_type2)
+			break;
+		if (filter_type1->filter->type != filter_type2->filter->type)
+			break;
+		switch (filter_type1->filter->type) {
+		case FILTER_TRIVIAL_FALSE:
+		case FILTER_TRIVIAL_TRUE:
+			/* trivial types just need the type compared */
+			continue;
+		default:
+			break;
+		}
+		/* The best way to compare complex filters is with strings */
+		str1 = arg_to_str(filter1, filter_type1->filter);
+		str2 = arg_to_str(filter2, filter_type2->filter);
+		result = strcmp(str1, str2) != 0;
+		free(str1);
+		free(str2);
+		if (result)
+			break;
+	}
+
+	if (i < filter1->filters)
+		return 0;
+	return 1;
+}
+
diff --git a/tools/lib/events/parse-utils.c b/tools/lib/events/parse-utils.c
new file mode 100644
index 0000000..f023a13
--- /dev/null
+++ b/tools/lib/events/parse-utils.c
@@ -0,0 +1,110 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <errno.h>
+
+#define __weak __attribute__((weak))
+
+void __vdie(const char *fmt, va_list ap)
+{
+	int ret = errno;
+
+	if (errno)
+		perror("trace-cmd");
+	else
+		ret = -1;
+
+	fprintf(stderr, "  ");
+	vfprintf(stderr, fmt, ap);
+
+	fprintf(stderr, "\n");
+	exit(ret);
+}
+
+void __die(const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	__vdie(fmt, ap);
+	va_end(ap);
+}
+
+void __weak die(const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	__vdie(fmt, ap);
+	va_end(ap);
+}
+
+void __vwarning(const char *fmt, va_list ap)
+{
+	if (errno)
+		perror("trace-cmd");
+	errno = 0;
+
+	fprintf(stderr, "  ");
+	vfprintf(stderr, fmt, ap);
+
+	fprintf(stderr, "\n");
+}
+
+void __warning(const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	__vwarning(fmt, ap);
+	va_end(ap);
+}
+
+void __weak warning(const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	__vwarning(fmt, ap);
+	va_end(ap);
+}
+
+void __vpr_stat(const char *fmt, va_list ap)
+{
+	vprintf(fmt, ap);
+	printf("\n");
+}
+
+void __pr_stat(const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	__vpr_stat(fmt, ap);
+	va_end(ap);
+}
+
+void __weak vpr_stat(const char *fmt, va_list ap)
+{
+	__vpr_stat(fmt, ap);
+}
+
+void __weak pr_stat(const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	__vpr_stat(fmt, ap);
+	va_end(ap);
+}
+
+void __weak *malloc_or_die(unsigned int size)
+{
+	void *data;
+
+	data = malloc(size);
+	if (!data)
+		die("malloc");
+	return data;
+}
diff --git a/tools/lib/events/trace-seq.c b/tools/lib/events/trace-seq.c
new file mode 100644
index 0000000..d2f265b
--- /dev/null
+++ b/tools/lib/events/trace-seq.c
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2009 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include "event-parse.h"
+
+/*
+ * The TRACE_SEQ_POISON is to catch the use of using
+ * a trace_seq structure after it was destroyed.
+ */
+#define TRACE_SEQ_POISON	((void *)0xdeadbeef)
+#define TRACE_SEQ_CHECK(s)						\
+do {									\
+	if ((s)->buffer == TRACE_SEQ_POISON)			\
+		die("Usage of trace_seq after it was destroyed");	\
+} while (0)
+
+/**
+ * trace_seq_init - initialize the trace_seq structure
+ * @s: a pointer to the trace_seq structure to initialize
+ */
+void trace_seq_init(struct trace_seq *s)
+{
+	s->len = 0;
+	s->readpos = 0;
+	s->buffer_size = TRACE_SEQ_BUF_SIZE;
+	s->buffer = malloc_or_die(s->buffer_size);
+}
+
+/**
+ * trace_seq_destroy - free up memory of a trace_seq
+ * @s: a pointer to the trace_seq to free the buffer
+ *
+ * Only frees the buffer, not the trace_seq struct itself.
+ */
+void trace_seq_destroy(struct trace_seq *s)
+{
+	if (!s)
+		return;
+	TRACE_SEQ_CHECK(s);
+	free(s->buffer);
+	s->buffer = TRACE_SEQ_POISON;
+}
+
+static void expand_buffer(struct trace_seq *s)
+{
+	s->buffer_size += TRACE_SEQ_BUF_SIZE;
+	s->buffer = realloc(s->buffer, s->buffer_size);
+	if (!s->buffer)
+		die("Can't allocate trace_seq buffer memory");
+}
+
+/**
+ * trace_seq_printf - sequence printing of trace information
+ * @s: trace sequence descriptor
+ * @fmt: printf format string
+ *
+ * It returns 0 if the trace oversizes the buffer's free
+ * space, 1 otherwise.
+ *
+ * The tracer may use either sequence operations or its own
+ * copy to user routines. To simplify formating of a trace
+ * trace_seq_printf is used to store strings into a special
+ * buffer (@s). Then the output may be either used by
+ * the sequencer or pulled into another buffer.
+ */
+int
+trace_seq_printf(struct trace_seq *s, const char *fmt, ...)
+{
+	va_list ap;
+	int len;
+	int ret;
+
+	TRACE_SEQ_CHECK(s);
+
+ try_again:
+	len = (s->buffer_size - 1) - s->len;
+
+	va_start(ap, fmt);
+	ret = vsnprintf(s->buffer + s->len, len, fmt, ap);
+	va_end(ap);
+
+	if (ret >= len) {
+		expand_buffer(s);
+		goto try_again;
+	}
+
+	s->len += ret;
+
+	return 1;
+}
+
+/**
+ * trace_seq_vprintf - sequence printing of trace information
+ * @s: trace sequence descriptor
+ * @fmt: printf format string
+ *
+ * The tracer may use either sequence operations or its own
+ * copy to user routines. To simplify formating of a trace
+ * trace_seq_printf is used to store strings into a special
+ * buffer (@s). Then the output may be either used by
+ * the sequencer or pulled into another buffer.
+ */
+int
+trace_seq_vprintf(struct trace_seq *s, const char *fmt, va_list args)
+{
+	int len;
+	int ret;
+
+	TRACE_SEQ_CHECK(s);
+
+ try_again:
+	len = (s->buffer_size - 1) - s->len;
+
+	ret = vsnprintf(s->buffer + s->len, len, fmt, args);
+
+	if (ret >= len) {
+		expand_buffer(s);
+		goto try_again;
+	}
+
+	s->len += ret;
+
+	return len;
+}
+
+/**
+ * trace_seq_puts - trace sequence printing of simple string
+ * @s: trace sequence descriptor
+ * @str: simple string to record
+ *
+ * The tracer may use either the sequence operations or its own
+ * copy to user routines. This function records a simple string
+ * into a special buffer (@s) for later retrieval by a sequencer
+ * or other mechanism.
+ */
+int trace_seq_puts(struct trace_seq *s, const char *str)
+{
+	int len;
+
+	TRACE_SEQ_CHECK(s);
+
+	len = strlen(str);
+
+	while (len > ((s->buffer_size - 1) - s->len))
+		expand_buffer(s);
+
+	memcpy(s->buffer + s->len, str, len);
+	s->len += len;
+
+	return len;
+}
+
+int trace_seq_putc(struct trace_seq *s, unsigned char c)
+{
+	TRACE_SEQ_CHECK(s);
+
+	while (s->len >= (s->buffer_size - 1))
+		expand_buffer(s);
+
+	s->buffer[s->len++] = c;
+
+	return 1;
+}
+
+void trace_seq_terminate(struct trace_seq *s)
+{
+	TRACE_SEQ_CHECK(s);
+
+	/* There's always one character left on the buffer */
+	s->buffer[s->len] = 0;
+}
+
+int trace_seq_do_printf(struct trace_seq *s)
+{
+	TRACE_SEQ_CHECK(s);
+	return printf("%.*s", s->len, s->buffer);
+}
-- 
1.7.5.4



^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [RFC][PATCH 3/8] perf: Build libparsevent.a
  2011-08-05 20:59 [RFC][PATCH 0/8] Having perf use libparsevent.a Steven Rostedt
  2011-08-05 20:59 ` [RFC][PATCH 1/8] perf: Separate out trace-cmd parse-events from perf files Steven Rostedt
  2011-08-05 20:59 ` [RFC][PATCH 2/8] tools/events: Add files to create libparsevent.a Steven Rostedt
@ 2011-08-05 20:59 ` Steven Rostedt
  2011-08-05 20:59 ` [RFC][PATCH 4/8] events: Update tools/lib/events to work with perf Steven Rostedt
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 33+ messages in thread
From: Steven Rostedt @ 2011-08-05 20:59 UTC (permalink / raw)
  To: linux-kernel
  Cc: Ingo Molnar, Thomas Gleixner, Peter Zijlstra,
	Frederic Weisbecker, Arnaldo Carvalho de Melo, Borislav Petkov,
	Arjan van de Ven

[-- Attachment #1: 0003-perf-Build-libparsevent.a.patch --]
[-- Type: text/plain, Size: 1832 bytes --]

From: Steven Rostedt <srostedt@redhat.com>

Have building perf also build libparsevent.a. Currently, perf does
not use the code within libparsevent.a, but it soon will.

Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
---
 tools/perf/Makefile |   11 ++++++++++-
 1 files changed, 10 insertions(+), 1 deletions(-)

diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index ebf38c1..0ea25c9 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -1,5 +1,6 @@
 ifeq ("$(origin O)", "command line")
 	OUTPUT := $(O)/
+	COMMAND_O := O=$(O)
 endif
 
 # The default target of this Makefile is...
@@ -187,6 +188,9 @@ $(OUTPUT)python/perf.so: $(PYRF_OBJS)
 
 SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH))
 
+EVENT_PARSE_DIR = ../lib/events/
+LIBPARSEVENT = $(OUTPUT)$(EVENT_PARSE_DIR)libparsevent.a
+
 #
 # Single 'perf' binary right now:
 #
@@ -286,6 +290,7 @@ LIB_H += util/cpumap.h
 LIB_H += util/top.h
 LIB_H += $(ARCH_INCLUDE)
 LIB_H += util/cgroup.h
+LIB_H += $(EVENT_PARSE_DIR)event-parse.h
 
 LIB_OBJS += $(OUTPUT)util/abspath.o
 LIB_OBJS += $(OUTPUT)util/alias.o
@@ -663,7 +668,7 @@ $(OUTPUT)perf.o: perf.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS
 		'-DPERF_HTML_PATH="$(htmldir_SQ)"' \
 		$(ALL_CFLAGS) -c $(filter %.c,$^) -o $@
 
-$(OUTPUT)perf: $(OUTPUT)perf.o $(BUILTIN_OBJS) $(PERFLIBS)
+$(OUTPUT)perf: $(OUTPUT)perf.o $(BUILTIN_OBJS) $(PERFLIBS) $(LIBPARSEVENT)
 	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) $(OUTPUT)perf.o \
                $(BUILTIN_OBJS) $(LIBS) -o $@
 
@@ -756,6 +761,10 @@ $(sort $(dir $(DIRECTORY_DEPS))):
 $(LIB_FILE): $(LIB_OBJS)
 	$(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIB_OBJS)
 
+# libparsevent.a
+$(LIBPARSEVENT):
+	make -C $(EVENT_PARSE_DIR) $(COMMAND_O) libparsevent.a
+
 help:
 	@echo 'Perf make targets:'
 	@echo '  doc		- make *all* documentation (see below)'
-- 
1.7.5.4



^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [RFC][PATCH 4/8] events: Update tools/lib/events to work with perf
  2011-08-05 20:59 [RFC][PATCH 0/8] Having perf use libparsevent.a Steven Rostedt
                   ` (2 preceding siblings ...)
  2011-08-05 20:59 ` [RFC][PATCH 3/8] perf: Build libparsevent.a Steven Rostedt
@ 2011-08-05 20:59 ` Steven Rostedt
  2011-08-05 20:59 ` [RFC][PATCH 5/8] perf: Have perf use the new libparsevent.a library Steven Rostedt
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 33+ messages in thread
From: Steven Rostedt @ 2011-08-05 20:59 UTC (permalink / raw)
  To: linux-kernel
  Cc: Ingo Molnar, Thomas Gleixner, Peter Zijlstra,
	Frederic Weisbecker, Arnaldo Carvalho de Melo, Borislav Petkov,
	Arjan van de Ven

[-- Attachment #1: 0004-events-Update-tools-lib-events-to-work-with-perf.patch --]
[-- Type: text/plain, Size: 7499 bytes --]

From: Steven Rostedt <srostedt@redhat.com>

Some of the util functions of libparsevent.a conflict with perf,
such as die(), warning() and others. Move them into event-util.h
that is not included by the perf tools.

Also, as perf compiles with 'bool' the filter_arg->bool needs to
be renamed to filter_arg->boolean.

Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
---
 tools/lib/events/event-parse.c  |    1 +
 tools/lib/events/event-parse.h  |   20 +++-----------------
 tools/lib/events/event-utils.h  |   16 ++++++++++++++++
 tools/lib/events/parse-filter.c |   32 ++++++++++++++++----------------
 tools/lib/events/trace-seq.c    |    1 +
 5 files changed, 37 insertions(+), 33 deletions(-)

diff --git a/tools/lib/events/event-parse.c b/tools/lib/events/event-parse.c
index 01b8821..3b4fac3 100644
--- a/tools/lib/events/event-parse.c
+++ b/tools/lib/events/event-parse.c
@@ -33,6 +33,7 @@
 #include <errno.h>
 
 #include "event-parse.h"
+#include "event-utils.h"
 
 static const char *input_buf;
 static unsigned long long input_buf_ptr;
diff --git a/tools/lib/events/event-parse.h b/tools/lib/events/event-parse.h
index c32d715..2e0222d 100644
--- a/tools/lib/events/event-parse.h
+++ b/tools/lib/events/event-parse.h
@@ -167,6 +167,8 @@ enum format_flags {
 	FIELD_IS_STRING		= 8,
 	FIELD_IS_DYNAMIC	= 16,
 	FIELD_IS_LONG		= 32,
+	FIELD_IS_FLAG		= 64,
+	FIELD_IS_SYMBOLIC	= 128,
 };
 
 struct format_field {
@@ -406,22 +408,6 @@ struct pevent {
 	struct event_format *last_event;
 };
 
-/* Can be overridden */
-void die(const char *fmt, ...);
-void *malloc_or_die(unsigned int size);
-void warning(const char *fmt, ...);
-void pr_stat(const char *fmt, ...);
-void vpr_stat(const char *fmt, va_list ap);
-
-/* Always available */
-void __die(const char *fmt, ...);
-void __warning(const char *fmt, ...);
-void __pr_stat(const char *fmt, ...);
-
-void __vdie(const char *fmt, ...);
-void __vwarning(const char *fmt, ...);
-void __vpr_stat(const char *fmt, ...);
-
 static inline unsigned short
 __data2host2(struct pevent *pevent, unsigned short data)
 {
@@ -734,7 +720,7 @@ struct filter_arg_str {
 struct filter_arg {
 	enum filter_arg_type	type;
 	union {
-		struct filter_arg_boolean	bool;
+		struct filter_arg_boolean	boolean;
 		struct filter_arg_field		field;
 		struct filter_arg_value		value;
 		struct filter_arg_op		op;
diff --git a/tools/lib/events/event-utils.h b/tools/lib/events/event-utils.h
index a8fb48f..0829638 100644
--- a/tools/lib/events/event-utils.h
+++ b/tools/lib/events/event-utils.h
@@ -23,6 +23,22 @@
 
 #include <ctype.h>
 
+/* Can be overridden */
+void die(const char *fmt, ...);
+void *malloc_or_die(unsigned int size);
+void warning(const char *fmt, ...);
+void pr_stat(const char *fmt, ...);
+void vpr_stat(const char *fmt, va_list ap);
+
+/* Always available */
+void __die(const char *fmt, ...);
+void __warning(const char *fmt, ...);
+void __pr_stat(const char *fmt, ...);
+
+void __vdie(const char *fmt, ...);
+void __vwarning(const char *fmt, ...);
+void __vpr_stat(const char *fmt, ...);
+
 static inline char *strim(char *string)
 {
 	char *ret;
diff --git a/tools/lib/events/parse-filter.c b/tools/lib/events/parse-filter.c
index 1df9966..fe37182 100644
--- a/tools/lib/events/parse-filter.c
+++ b/tools/lib/events/parse-filter.c
@@ -359,7 +359,7 @@ create_arg_item(struct event_format *event,
 			if (strcmp(token, COMM) != 0) {
 				/* not a field, Make it false */
 				arg->type = FILTER_ARG_BOOLEAN;
-				arg->bool.value = FILTER_FALSE;
+				arg->boolean.value = FILTER_FALSE;
 				break;
 			}
 			/* If token is 'COMM' then it is special */
@@ -487,7 +487,7 @@ static int add_right(struct filter_arg *op, struct filter_arg *arg,
 				free_arg(left);
 				free_arg(arg);
 				op->type = FILTER_ARG_BOOLEAN;
-				op->bool.value = FILTER_FALSE;
+				op->boolean.value = FILTER_FALSE;
 				break;
 			}
 
@@ -772,7 +772,7 @@ enum filter_vals test_arg(struct filter_arg *parent, struct filter_arg *arg)
 
 		/* bad case */
 	case FILTER_ARG_BOOLEAN:
-		return FILTER_VAL_FALSE + arg->bool.value;
+		return FILTER_VAL_FALSE + arg->boolean.value;
 
 		/* good cases: */
 	case FILTER_ARG_STR:
@@ -871,7 +871,7 @@ static struct filter_arg *collapse_tree(struct filter_arg *arg)
 		free_arg(arg);
 		arg = allocate_arg();
 		arg->type = FILTER_ARG_BOOLEAN;
-		arg->bool.value = ret == FILTER_VAL_TRUE;
+		arg->boolean.value = ret == FILTER_VAL_TRUE;
 	}
 
 	return arg;
@@ -1116,7 +1116,7 @@ process_event(struct event_format *event, const char *filter_str,
 	if (!*parg) {
 		*parg = allocate_arg();
 		(*parg)->type = FILTER_ARG_BOOLEAN;
-		(*parg)->bool.value = FILTER_FALSE;
+		(*parg)->boolean.value = FILTER_FALSE;
 	}
 
 	return 0;
@@ -1139,7 +1139,7 @@ static int filter_event(struct event_filter *filter,
 		/* just add a TRUE arg */
 		arg = allocate_arg();
 		arg->type = FILTER_ARG_BOOLEAN;
-		arg->bool.value = FILTER_TRUE;
+		arg->boolean.value = FILTER_TRUE;
 	}
 
 	filter_type = add_filter_type(filter, event->id);
@@ -1369,9 +1369,9 @@ static int copy_filter_type(struct event_filter *filter,
 		arg = allocate_arg();
 		arg->type = FILTER_ARG_BOOLEAN;
 		if (strcmp(str, "TRUE") == 0)
-			arg->bool.value = 1;
+			arg->boolean.value = 1;
 		else
-			arg->bool.value = 0;
+			arg->boolean.value = 0;
 
 		filter_type = add_filter_type(filter, event->id);
 		filter_type->filter = arg;
@@ -1442,8 +1442,8 @@ int pevent_update_trivial(struct event_filter *dest, struct event_filter *source
 		arg = filter_type->filter;
 		if (arg->type != FILTER_ARG_BOOLEAN)
 			continue;
-		if ((arg->bool.value && type == FILTER_TRIVIAL_FALSE) ||
-		    (!arg->bool.value && type == FILTER_TRIVIAL_TRUE))
+		if ((arg->boolean.value && type == FILTER_TRIVIAL_FALSE) ||
+		    (!arg->boolean.value && type == FILTER_TRIVIAL_TRUE))
 			continue;
 
 		event = filter_type->event;
@@ -1497,10 +1497,10 @@ void pevent_filter_clear_trivial(struct event_filter *filter,
 			continue;
 		switch (type) {
 		case FILTER_TRIVIAL_FALSE:
-			if (filter_type->filter->bool.value)
+			if (filter_type->filter->boolean.value)
 				continue;
 		case FILTER_TRIVIAL_TRUE:
-			if (!filter_type->filter->bool.value)
+			if (!filter_type->filter->boolean.value)
 				continue;
 		default:
 			break;
@@ -1551,10 +1551,10 @@ int pevent_filter_event_has_trivial(struct event_filter *filter,
 
 	switch (type) {
 	case FILTER_TRIVIAL_FALSE:
-		return !filter_type->filter->bool.value;
+		return !filter_type->filter->boolean.value;
 
 	case FILTER_TRIVIAL_TRUE:
-		return filter_type->filter->bool.value;
+		return filter_type->filter->boolean.value;
 	default:
 		return 1;
 	}
@@ -1783,7 +1783,7 @@ static int test_filter(struct event_format *event,
 	switch (arg->type) {
 	case FILTER_ARG_BOOLEAN:
 		/* easy case */
-		return arg->bool.value;
+		return arg->boolean.value;
 
 	case FILTER_ARG_OP:
 		return test_op(event, arg, record);
@@ -2147,7 +2147,7 @@ static char *arg_to_str(struct event_filter *filter, struct filter_arg *arg)
 	switch (arg->type) {
 	case FILTER_ARG_BOOLEAN:
 		str = malloc_or_die(6);
-		if (arg->bool.value)
+		if (arg->boolean.value)
 			strcpy(str, "TRUE");
 		else
 			strcpy(str, "FALSE");
diff --git a/tools/lib/events/trace-seq.c b/tools/lib/events/trace-seq.c
index d2f265b..b1ccc92 100644
--- a/tools/lib/events/trace-seq.c
+++ b/tools/lib/events/trace-seq.c
@@ -24,6 +24,7 @@
 #include <stdarg.h>
 
 #include "event-parse.h"
+#include "event-utils.h"
 
 /*
  * The TRACE_SEQ_POISON is to catch the use of using
-- 
1.7.5.4



^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [RFC][PATCH 5/8] perf: Have perf use the new libparsevent.a library
  2011-08-05 20:59 [RFC][PATCH 0/8] Having perf use libparsevent.a Steven Rostedt
                   ` (3 preceding siblings ...)
  2011-08-05 20:59 ` [RFC][PATCH 4/8] events: Update tools/lib/events to work with perf Steven Rostedt
@ 2011-08-05 20:59 ` Steven Rostedt
  2011-08-05 20:59 ` [RFC][PATCH 6/8] perf/events: Add flag to produce nsec output Steven Rostedt
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 33+ messages in thread
From: Steven Rostedt @ 2011-08-05 20:59 UTC (permalink / raw)
  To: linux-kernel
  Cc: Ingo Molnar, Thomas Gleixner, Peter Zijlstra,
	Frederic Weisbecker, Arnaldo Carvalho de Melo, Borislav Petkov,
	Arjan van de Ven

[-- Attachment #1: 0005-perf-Have-perf-use-the-new-libparsevent.a-library.patch --]
[-- Type: text/plain, Size: 103764 bytes --]

From: Steven Rostedt <srostedt@redhat.com>

The event parsing code in perf was originally copied from trace-cmd
but never was kept up-to-date with the changes that was done there.
The trace-cmd libparsevent.a code is much more mature than what is
currently in perf.

This updates the code to use wrappers to handle the calls to the
new event parsing code. The new code requires a handle to be pass
around, which removes the global event variables and allows
more than one event structure to be read from different files
(and different machines).

But perf still has the old global events and the code throughout
perf does not yet have a nice way to pass around a handle.
A global 'pevent' has been made for perf and the old calls have
been created as wrappers to the new event parsing code that uses
the global pevent.

With this change, perf can later incorporate the pevent handle into
the perf structures and allow more than one file to be read and
compared, that contains different events.

Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
---
 tools/perf/Makefile                                |   14 +-
 tools/perf/builtin-kmem.c                          |    6 +-
 tools/perf/builtin-lock.c                          |   26 +-
 tools/perf/builtin-sched.c                         |   42 +-
 tools/perf/builtin-script.c                        |    2 +-
 .../util/scripting-engines/trace-event-python.c    |   16 +-
 tools/perf/util/trace-event-info.c                 |    4 +-
 tools/perf/util/trace-event-parse.c                |  358 +++-
 tools/perf/util/trace-event-read.c                 |   34 +-
 tools/perf/util/trace-event.h                      |   50 +-
 tools/perf/util/trace-parse-events.c               | 3128 --------------------
 tools/perf/util/trace-parse-events.h               |  273 --
 12 files changed, 484 insertions(+), 3469 deletions(-)
 delete mode 100644 tools/perf/util/trace-parse-events.c
 delete mode 100644 tools/perf/util/trace-parse-events.h

diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 0ea25c9..0a9a9a5 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -1,6 +1,9 @@
 ifeq ("$(origin O)", "command line")
 	OUTPUT := $(O)/
 	COMMAND_O := O=$(O)
+	EP_PATH = $(OUTPUT)/
+else
+	EP_PATH = $(EVENT_PARSE_DIR)/
 endif
 
 # The default target of this Makefile is...
@@ -162,7 +165,7 @@ endif
 # Those must not be GNU-specific; they are shared with perl/ which may
 # be built by a different compiler. (Note that this is an artifact now
 # but it still might be nice to keep that distinction.)
-BASIC_CFLAGS = -Iutil/include -Iarch/$(ARCH)/include
+BASIC_CFLAGS = -Iutil/include -Iarch/$(ARCH)/include -I$(EVENT_PARSE_DIR)
 BASIC_LDFLAGS =
 
 # Guard against environment variables
@@ -189,7 +192,8 @@ $(OUTPUT)python/perf.so: $(PYRF_OBJS)
 SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH))
 
 EVENT_PARSE_DIR = ../lib/events/
-LIBPARSEVENT = $(OUTPUT)$(EVENT_PARSE_DIR)libparsevent.a
+LIBPARSEVENT = $(EP_PATH)libparsevent.a
+EP_LIB := -L$(EP_PATH) -lparsevent
 
 #
 # Single 'perf' binary right now:
@@ -282,7 +286,6 @@ 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/probe-event.h
 LIB_H += util/pstack.h
@@ -338,7 +341,6 @@ LIB_OBJS += $(OUTPUT)util/trace-event-parse.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
@@ -380,7 +382,7 @@ BUILTIN_OBJS += $(OUTPUT)builtin-kvm.o
 BUILTIN_OBJS += $(OUTPUT)builtin-test.o
 BUILTIN_OBJS += $(OUTPUT)builtin-inject.o
 
-PERFLIBS = $(LIB_FILE)
+PERFLIBS = $(LIB_FILE) $(LIBPARSEVENT)
 
 # Files needed for the python binding, perf.so
 # pyrf is just an internal name needed for all those wrappers.
@@ -668,7 +670,7 @@ $(OUTPUT)perf.o: perf.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS
 		'-DPERF_HTML_PATH="$(htmldir_SQ)"' \
 		$(ALL_CFLAGS) -c $(filter %.c,$^) -o $@
 
-$(OUTPUT)perf: $(OUTPUT)perf.o $(BUILTIN_OBJS) $(PERFLIBS) $(LIBPARSEVENT)
+$(OUTPUT)perf: $(OUTPUT)perf.o $(BUILTIN_OBJS) $(PERFLIBS)
 	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) $(OUTPUT)perf.o \
                $(BUILTIN_OBJS) $(LIBS) -o $@
 
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index 225e963..0f36a3f 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -189,7 +189,7 @@ static void insert_caller_stat(unsigned long call_site,
 }
 
 static void process_alloc_event(void *data,
-				struct event *event,
+				struct event_format *event,
 				int cpu,
 				u64 timestamp __used,
 				struct thread *thread __used,
@@ -250,7 +250,7 @@ static struct alloc_stat *search_alloc_stat(unsigned long ptr,
 }
 
 static void process_free_event(void *data,
-			       struct event *event,
+			       struct event_format *event,
 			       int cpu,
 			       u64 timestamp __used,
 			       struct thread *thread __used)
@@ -278,7 +278,7 @@ static void process_free_event(void *data,
 static void process_raw_event(union perf_event *raw_event __used, void *data,
 			      int cpu, u64 timestamp, struct thread *thread)
 {
-	struct event *event;
+	struct event_format *event;
 	int type;
 
 	type = trace_parse_common_type(data);
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c
index 9ac05aa..7ea4b8a 100644
--- a/tools/perf/builtin-lock.c
+++ b/tools/perf/builtin-lock.c
@@ -355,25 +355,25 @@ struct trace_release_event {
 
 struct trace_lock_handler {
 	void (*acquire_event)(struct trace_acquire_event *,
-			      struct event *,
+			      struct event_format *,
 			      int cpu,
 			      u64 timestamp,
 			      struct thread *thread);
 
 	void (*acquired_event)(struct trace_acquired_event *,
-			       struct event *,
+			       struct event_format *,
 			       int cpu,
 			       u64 timestamp,
 			       struct thread *thread);
 
 	void (*contended_event)(struct trace_contended_event *,
-				struct event *,
+				struct event_format *,
 				int cpu,
 				u64 timestamp,
 				struct thread *thread);
 
 	void (*release_event)(struct trace_release_event *,
-			      struct event *,
+			      struct event_format *,
 			      int cpu,
 			      u64 timestamp,
 			      struct thread *thread);
@@ -415,7 +415,7 @@ enum acquire_flags {
 
 static void
 report_lock_acquire_event(struct trace_acquire_event *acquire_event,
-			struct event *__event __used,
+			struct event_format *__event __used,
 			int cpu __used,
 			u64 timestamp __used,
 			struct thread *thread __used)
@@ -479,7 +479,7 @@ end:
 
 static void
 report_lock_acquired_event(struct trace_acquired_event *acquired_event,
-			 struct event *__event __used,
+			 struct event_format *__event __used,
 			 int cpu __used,
 			 u64 timestamp __used,
 			 struct thread *thread __used)
@@ -535,7 +535,7 @@ end:
 
 static void
 report_lock_contended_event(struct trace_contended_event *contended_event,
-			  struct event *__event __used,
+			  struct event_format *__event __used,
 			  int cpu __used,
 			  u64 timestamp __used,
 			  struct thread *thread __used)
@@ -582,7 +582,7 @@ end:
 
 static void
 report_lock_release_event(struct trace_release_event *release_event,
-			struct event *__event __used,
+			struct event_format *__event __used,
 			int cpu __used,
 			u64 timestamp __used,
 			struct thread *thread __used)
@@ -646,7 +646,7 @@ static struct trace_lock_handler *trace_handler;
 
 static void
 process_lock_acquire_event(void *data,
-			   struct event *event __used,
+			   struct event_format *event __used,
 			   int cpu __used,
 			   u64 timestamp __used,
 			   struct thread *thread __used)
@@ -665,7 +665,7 @@ process_lock_acquire_event(void *data,
 
 static void
 process_lock_acquired_event(void *data,
-			    struct event *event __used,
+			    struct event_format *event __used,
 			    int cpu __used,
 			    u64 timestamp __used,
 			    struct thread *thread __used)
@@ -683,7 +683,7 @@ process_lock_acquired_event(void *data,
 
 static void
 process_lock_contended_event(void *data,
-			     struct event *event __used,
+			     struct event_format *event __used,
 			     int cpu __used,
 			     u64 timestamp __used,
 			     struct thread *thread __used)
@@ -701,7 +701,7 @@ process_lock_contended_event(void *data,
 
 static void
 process_lock_release_event(void *data,
-			   struct event *event __used,
+			   struct event_format *event __used,
 			   int cpu __used,
 			   u64 timestamp __used,
 			   struct thread *thread __used)
@@ -720,7 +720,7 @@ process_lock_release_event(void *data,
 static void
 process_raw_event(void *data, int cpu, u64 timestamp, struct thread *thread)
 {
-	struct event *event;
+	struct event_format *event;
 	int type;
 
 	type = trace_parse_common_type(data);
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index dcfe887..ee14ffc 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -724,34 +724,34 @@ struct trace_migrate_task_event {
 struct trace_sched_handler {
 	void (*switch_event)(struct trace_switch_event *,
 			     struct perf_session *,
-			     struct event *,
+			     struct event_format *,
 			     int cpu,
 			     u64 timestamp,
 			     struct thread *thread);
 
 	void (*runtime_event)(struct trace_runtime_event *,
 			      struct perf_session *,
-			      struct event *,
+			      struct event_format *,
 			      int cpu,
 			      u64 timestamp,
 			      struct thread *thread);
 
 	void (*wakeup_event)(struct trace_wakeup_event *,
 			     struct perf_session *,
-			     struct event *,
+			     struct event_format *,
 			     int cpu,
 			     u64 timestamp,
 			     struct thread *thread);
 
 	void (*fork_event)(struct trace_fork_event *,
-			   struct event *,
+			   struct event_format *,
 			   int cpu,
 			   u64 timestamp,
 			   struct thread *thread);
 
 	void (*migrate_task_event)(struct trace_migrate_task_event *,
 			   struct perf_session *session,
-			   struct event *,
+			   struct event_format *,
 			   int cpu,
 			   u64 timestamp,
 			   struct thread *thread);
@@ -761,7 +761,7 @@ struct trace_sched_handler {
 static void
 replay_wakeup_event(struct trace_wakeup_event *wakeup_event,
 		    struct perf_session *session __used,
-		    struct event *event,
+		    struct event_format *event,
 		    int cpu __used,
 		    u64 timestamp __used,
 		    struct thread *thread __used)
@@ -788,7 +788,7 @@ static u64 cpu_last_switched[MAX_CPUS];
 static void
 replay_switch_event(struct trace_switch_event *switch_event,
 		    struct perf_session *session __used,
-		    struct event *event,
+		    struct event_format *event,
 		    int cpu,
 		    u64 timestamp,
 		    struct thread *thread __used)
@@ -831,7 +831,7 @@ replay_switch_event(struct trace_switch_event *switch_event,
 
 static void
 replay_fork_event(struct trace_fork_event *fork_event,
-		  struct event *event,
+		  struct event_format *event,
 		  int cpu __used,
 		  u64 timestamp __used,
 		  struct thread *thread __used)
@@ -940,7 +940,7 @@ static void thread_atoms_insert(struct thread *thread)
 
 static void
 latency_fork_event(struct trace_fork_event *fork_event __used,
-		   struct event *event __used,
+		   struct event_format *event __used,
 		   int cpu __used,
 		   u64 timestamp __used,
 		   struct thread *thread __used)
@@ -1022,7 +1022,7 @@ add_sched_in_event(struct work_atoms *atoms, u64 timestamp)
 static void
 latency_switch_event(struct trace_switch_event *switch_event,
 		     struct perf_session *session,
-		     struct event *event __used,
+		     struct event_format *event __used,
 		     int cpu,
 		     u64 timestamp,
 		     struct thread *thread __used)
@@ -1075,7 +1075,7 @@ latency_switch_event(struct trace_switch_event *switch_event,
 static void
 latency_runtime_event(struct trace_runtime_event *runtime_event,
 		     struct perf_session *session,
-		     struct event *event __used,
+		     struct event_format *event __used,
 		     int cpu,
 		     u64 timestamp,
 		     struct thread *this_thread __used)
@@ -1098,7 +1098,7 @@ latency_runtime_event(struct trace_runtime_event *runtime_event,
 static void
 latency_wakeup_event(struct trace_wakeup_event *wakeup_event,
 		     struct perf_session *session,
-		     struct event *__event __used,
+		     struct event_format *__event __used,
 		     int cpu __used,
 		     u64 timestamp,
 		     struct thread *thread __used)
@@ -1146,7 +1146,7 @@ latency_wakeup_event(struct trace_wakeup_event *wakeup_event,
 static void
 latency_migrate_task_event(struct trace_migrate_task_event *migrate_task_event,
 		     struct perf_session *session,
-		     struct event *__event __used,
+		     struct event_format *__event __used,
 		     int cpu __used,
 		     u64 timestamp,
 		     struct thread *thread __used)
@@ -1357,7 +1357,7 @@ static struct trace_sched_handler *trace_handler;
 
 static void
 process_sched_wakeup_event(void *data, struct perf_session *session,
-			   struct event *event,
+			   struct event_format *event,
 			   int cpu __used,
 			   u64 timestamp __used,
 			   struct thread *thread __used)
@@ -1393,7 +1393,7 @@ static char next_shortname2 = '0';
 static void
 map_switch_event(struct trace_switch_event *switch_event,
 		 struct perf_session *session,
-		 struct event *event __used,
+		 struct event_format *event __used,
 		 int this_cpu,
 		 u64 timestamp,
 		 struct thread *thread __used)
@@ -1472,7 +1472,7 @@ map_switch_event(struct trace_switch_event *switch_event,
 
 static void
 process_sched_switch_event(void *data, struct perf_session *session,
-			   struct event *event,
+			   struct event_format *event,
 			   int this_cpu,
 			   u64 timestamp __used,
 			   struct thread *thread __used)
@@ -1506,7 +1506,7 @@ process_sched_switch_event(void *data, struct perf_session *session,
 
 static void
 process_sched_runtime_event(void *data, struct perf_session *session,
-			   struct event *event,
+			   struct event_format *event,
 			   int cpu __used,
 			   u64 timestamp __used,
 			   struct thread *thread __used)
@@ -1524,7 +1524,7 @@ process_sched_runtime_event(void *data, struct perf_session *session,
 
 static void
 process_sched_fork_event(void *data,
-			 struct event *event,
+			 struct event_format *event,
 			 int cpu __used,
 			 u64 timestamp __used,
 			 struct thread *thread __used)
@@ -1544,7 +1544,7 @@ process_sched_fork_event(void *data,
 }
 
 static void
-process_sched_exit_event(struct event *event,
+process_sched_exit_event(struct event_format *event,
 			 int cpu __used,
 			 u64 timestamp __used,
 			 struct thread *thread __used)
@@ -1555,7 +1555,7 @@ process_sched_exit_event(struct event *event,
 
 static void
 process_sched_migrate_task_event(void *data, struct perf_session *session,
-			   struct event *event,
+			   struct event_format *event,
 			   int cpu __used,
 			   u64 timestamp __used,
 			   struct thread *thread __used)
@@ -1578,7 +1578,7 @@ static void process_raw_event(union perf_event *raw_event __used,
 			      struct perf_session *session, void *data, int cpu,
 			      u64 timestamp, struct thread *thread)
 {
-	struct event *event;
+	struct event_format *event;
 	int type;
 
 
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index 22747de..5e195dd 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -221,7 +221,7 @@ static void print_sample_start(struct perf_sample *sample,
 			       struct perf_event_attr *attr)
 {
 	int type;
-	struct event *event;
+	struct event_format *event;
 	const char *evname = NULL;
 	unsigned long secs;
 	unsigned long usecs;
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index 6ccf70e..e5a770d 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -36,7 +36,7 @@ PyMODINIT_FUNC initperf_trace_context(void);
 #define FTRACE_MAX_EVENT				\
 	((1 << (sizeof(unsigned short) * 8)) - 1)
 
-struct event *events[FTRACE_MAX_EVENT];
+struct event_format *events[FTRACE_MAX_EVENT];
 
 #define MAX_FIELDS	64
 #define N_COMMON_FIELDS	7
@@ -135,7 +135,7 @@ static void define_field(enum print_arg_type field_type,
 	Py_DECREF(t);
 }
 
-static void define_event_symbols(struct event *event,
+static void define_event_symbols(struct event_format *event,
 				 const char *ev_name,
 				 struct print_arg *args)
 {
@@ -177,6 +177,10 @@ static void define_event_symbols(struct event *event,
 		define_event_symbols(event, ev_name, args->op.right);
 		break;
 	default:
+		/* gcc warns for these? */
+	case PRINT_BSTRING:
+	case PRINT_DYNAMIC_ARRAY:
+	case PRINT_FUNC:
 		/* we should warn... */
 		return;
 	}
@@ -185,10 +189,10 @@ static void define_event_symbols(struct event *event,
 		define_event_symbols(event, ev_name, args->next);
 }
 
-static inline struct event *find_cache_event(int type)
+static inline struct event_format *find_cache_event(int type)
 {
 	static char ev_name[256];
-	struct event *event;
+	struct event_format *event;
 
 	if (events[type])
 		return events[type];
@@ -215,7 +219,7 @@ static void python_process_event(union perf_event *pevent __unused,
 	struct format_field *field;
 	unsigned long long val;
 	unsigned long s, ns;
-	struct event *event;
+	struct event_format *event;
 	unsigned n = 0;
 	int type;
 	int pid;
@@ -435,7 +439,7 @@ out:
 
 static int python_generate_script(const char *outfile)
 {
-	struct event *event = NULL;
+	struct event_format *event = NULL;
 	struct format_field *f;
 	char fname[PATH_MAX];
 	int not_first, count;
diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c
index 35729f4..813997c 100644
--- a/tools/perf/util/trace-event-info.c
+++ b/tools/perf/util/trace-event-info.c
@@ -93,7 +93,7 @@ static void die(const char *fmt, ...)
 	exit(ret);
 }
 
-void *malloc_or_die(unsigned int size)
+static void *malloc_or_die(unsigned int size)
 {
 	void *data;
 
@@ -529,6 +529,8 @@ int read_tracing_data(int fd, struct list_head *pattrs)
 	else
 		buf[0] = 0;
 
+	read_trace_init(buf[0], buf[0]);
+
 	write_or_die(buf, 1);
 
 	/* save size of long */
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c
index 9477519..ca3e5cd 100644
--- a/tools/perf/util/trace-event-parse.c
+++ b/tools/perf/util/trace-event-parse.c
@@ -1,18 +1,366 @@
+/*
+ * 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
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+
+#undef _GNU_SOURCE
 #include "../perf.h"
 #include "util.h"
 #include "trace-event.h"
 
-int common_pc(struct scripting_context *context)
+int header_page_size_size;
+int header_page_ts_size;
+int header_page_data_offset;
+
+struct pevent *perf_pevent;
+static struct pevent *pevent;
+
+bool latency_format;
+
+int read_trace_init(int file_bigendian, int host_bigendian)
 {
-	return parse_common_pc(context->event_data);
+	if (pevent)
+		return 0;
+
+	perf_pevent = pevent_alloc();
+	pevent = perf_pevent;
+
+	pevent_set_file_bigendian(pevent, file_bigendian);
+	pevent_set_host_bigendian(pevent, host_bigendian);
+
+	return 0;
 }
 
-int common_flags(struct scripting_context *context)
+static int get_common_field(struct scripting_context *context,
+			    int *offset, int *size, const char *type)
 {
-	return parse_common_flags(context->event_data);
+	struct event_format *event;
+	struct format_field *field;
+
+	if (!*size) {
+		if (!pevent->events)
+			return 0;
+
+		event = pevent->events[0];
+		field = pevent_find_common_field(event, type);
+		if (!field)
+			return 0;
+		*offset = field->offset;
+		*size = field->size;
+	}
+
+	return pevent_read_number(pevent, context->event_data + *offset, *size);
 }
 
 int common_lock_depth(struct scripting_context *context)
 {
-	return parse_common_lock_depth(context->event_data);
+	static int offset;
+	static int size;
+	int ret;
+
+	ret = get_common_field(context, &size, &offset,
+			       "common_lock_depth");
+	if (ret < 0)
+		return -1;
+
+	return ret;
+}
+
+int common_flags(struct scripting_context *context)
+{
+	static int offset;
+	static int size;
+	int ret;
+
+	ret = get_common_field(context, &size, &offset,
+			       "common_flags");
+	if (ret < 0)
+		return -1;
+
+	return ret;
+}
+
+int common_pc(struct scripting_context *context)
+{
+	static int offset;
+	static int size;
+	int ret;
+
+	ret = get_common_field(context, &size, &offset,
+			       "common_preempt_count");
+	if (ret < 0)
+		return -1;
+
+	return ret;
+}
+
+unsigned long long
+raw_field_value(struct event_format *event, const char *name, void *data)
+{
+	struct format_field *field;
+	unsigned long long val;
+
+	field = pevent_find_any_field(event, name);
+	if (!field)
+		return 0ULL;
+
+	pevent_read_number_field(field, data, &val);
+
+	return val;
+}
+
+void *raw_field_ptr(struct event_format *event, const char *name, void *data)
+{
+	struct format_field *field;
+
+	field = pevent_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;
+}
+
+int trace_parse_common_type(void *data)
+{
+	struct record record;
+
+	record.data = data;
+	return pevent_data_type(pevent, &record);
+}
+
+int trace_parse_common_pid(void *data)
+{
+	struct record record;
+
+	record.data = data;
+	return pevent_data_pid(pevent, &record);
+}
+
+unsigned long long read_size(void *ptr, int size)
+{
+	return pevent_read_number(pevent, ptr, size);
+}
+
+struct event_format *trace_find_event(int type)
+{
+	return pevent_find_event(pevent, type);
+}
+
+
+void print_trace_event(int cpu, void *data, int size)
+{
+	struct event_format *event;
+	struct record record;
+	struct trace_seq s;
+	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;
+	}
+
+	memset(&record, 0, sizeof(record));
+	record.cpu = cpu;
+	record.size = size;
+	record.data = data;
+
+	pid = pevent_data_pid(pevent, &record);
+
+	trace_seq_init(&s);
+	pevent_print_event(pevent, &s, &record);
+	trace_seq_do_printf(&s);
+	printf("\n");
+}
+
+void print_event(int cpu, void *data, int size, unsigned long long nsecs,
+		  char *comm)
+{
+	struct record record;
+	struct trace_seq s;
+	int pid;
+
+	pevent->latency_format = latency_format;
+
+	record.ts = nsecs;
+	record.cpu = cpu;
+	record.size = size;
+	record.data = data;
+	pid = pevent_data_pid(pevent, &record);
+
+	if (!pevent_pid_is_registered(pevent, pid))
+		pevent_register_comm(pevent, comm, pid);
+
+	trace_seq_init(&s);
+	pevent_print_event(pevent, &s, &record);
+	trace_seq_do_printf(&s);
+	printf("\n");
+}
+
+void parse_proc_kallsyms(char *file, unsigned int size __unused)
+{
+	unsigned long long addr;
+	char *func;
+	char *line;
+	char *next = NULL;
+	char *addr_str;
+	char *mod;
+	char ch;
+	int ret;
+
+	line = strtok_r(file, "\n", &next);
+	while (line) {
+		mod = NULL;
+		ret = sscanf(line, "%as %c %as\t[%as",
+			     (float *)(void *)&addr_str, /* workaround gcc warning */
+			     &ch,
+			     (float *)(void *)&func,
+			     (float *)(void *)&mod);
+		addr = strtoull(addr_str, NULL, 16);
+		free(addr_str);
+
+		/* truncate the extra ']' */
+		if (mod)
+			mod[strlen(mod) - 1] = 0;
+
+		pevent_register_function(pevent, func, addr, mod);
+		free(func);
+		free(mod);
+
+		line = strtok_r(NULL, "\n", &next);
+	}
+}
+
+void parse_ftrace_printk(char *file, unsigned int size __unused)
+{
+	unsigned long long addr;
+	char *printk;
+	char *line;
+	char *next = NULL;
+	char *addr_str;
+	char *fmt;
+
+	line = strtok_r(file, "\n", &next);
+	while (line) {
+		addr_str = strtok_r(line, ":", &fmt);
+		if (!addr_str) {
+			warning("printk format with empty entry");
+			break;
+		}
+		addr = strtoull(addr_str, NULL, 16);
+		/* fmt still has a space, skip it */
+		printk = strdup(fmt+1);
+		line = strtok_r(NULL, "\n", &next);
+		pevent_register_print_string(pevent, printk, addr);
+	}
+}
+
+int parse_ftrace_file(char *buf, unsigned long size)
+{
+	return pevent_parse_event(pevent, buf, size, "ftrace");
+}
+
+int parse_event_file(char *buf, unsigned long size, char *sys)
+{
+	return pevent_parse_event(pevent, buf, size, sys);
+}
+
+struct event_format *trace_find_next_event(struct event_format *event)
+{
+	static int idx;
+
+	if (!pevent->events)
+		return NULL;
+
+	if (!event) {
+		idx = 0;
+		return pevent->events[0];
+	}
+
+	if (idx < pevent->nr_events && event == pevent->events[idx]) {
+		idx++;
+		if (idx == pevent->nr_events)
+			return NULL;
+		return pevent->events[idx];
+	}
+
+	for (idx = 1; idx < pevent->nr_events; idx++) {
+		if (event == pevent->events[idx - 1])
+			return pevent->events[idx];
+	}
+	return NULL;
+}
+
+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;
 }
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c
index f55cc3a..9511fd3 100644
--- a/tools/perf/util/trace-event-read.c
+++ b/tools/perf/util/trace-event-read.c
@@ -53,6 +53,16 @@ static unsigned long	page_size;
 static ssize_t calc_data_size;
 static bool repipe;
 
+static void *malloc_or_die(int size)
+{
+	void *ret;
+
+	ret = malloc(size);
+	if (!ret)
+		die("malloc");
+	return ret;
+}
+
 static int do_read(int fd, void *buf, int size)
 {
 	int rsize = size;
@@ -110,7 +120,7 @@ static unsigned int read4(void)
 	unsigned int data;
 
 	read_or_die(&data, 4);
-	return __data2host4(data);
+	return __data2host4(perf_pevent, data);
 }
 
 static unsigned long long read8(void)
@@ -118,7 +128,7 @@ static unsigned long long read8(void)
 	unsigned long long data;
 
 	read_or_die(&data, 8);
-	return __data2host8(data);
+	return __data2host8(perf_pevent, data);
 }
 
 static char *read_string(void)
@@ -390,15 +400,15 @@ struct record *trace_peek_data(int cpu)
 		/* FIXME: handle header page */
 		if (header_page_ts_size != 8)
 			die("expected a long long type for timestamp");
-		cpu_data[cpu].timestamp = data2host8(ptr);
+		cpu_data[cpu].timestamp = data2host8(perf_pevent, ptr);
 		ptr += 8;
 		switch (header_page_size_size) {
 		case 4:
-			cpu_data[cpu].page_size = data2host4(ptr);
+			cpu_data[cpu].page_size = data2host4(perf_pevent, ptr);
 			ptr += 4;
 			break;
 		case 8:
-			cpu_data[cpu].page_size = data2host8(ptr);
+			cpu_data[cpu].page_size = data2host8(perf_pevent, ptr);
 			ptr += 8;
 			break;
 		default:
@@ -415,7 +425,7 @@ read_again:
 		return trace_peek_data(cpu);
 	}
 
-	type_len_ts = data2host4(ptr);
+	type_len_ts = data2host4(perf_pevent, ptr);
 	ptr += 4;
 
 	type_len = type_len4host(type_len_ts);
@@ -425,14 +435,14 @@ read_again:
 	case RINGBUF_TYPE_PADDING:
 		if (!delta)
 			die("error, hit unexpected end of page");
-		length = data2host4(ptr);
+		length = data2host4(perf_pevent, ptr);
 		ptr += 4;
 		length *= 4;
 		ptr += length;
 		goto read_again;
 
 	case RINGBUF_TYPE_TIME_EXTEND:
-		extend = data2host4(ptr);
+		extend = data2host4(perf_pevent, ptr);
 		ptr += 4;
 		extend <<= TS_SHIFT;
 		extend += delta;
@@ -443,7 +453,7 @@ read_again:
 		ptr += 12;
 		break;
 	case 0:
-		length = data2host4(ptr);
+		length = data2host4(perf_pevent, ptr);
 		ptr += 4;
 		die("here! length=%d", length);
 		break;
@@ -510,6 +520,8 @@ ssize_t trace_report(int fd, bool __repipe)
 	file_bigendian = buf[0];
 	host_bigendian = bigendian();
 
+	read_trace_init(file_bigendian, host_bigendian);
+
 	read_or_die(buf, 1);
 	long_size = buf[0];
 
@@ -527,11 +539,11 @@ ssize_t trace_report(int fd, bool __repipe)
 	repipe = false;
 
 	if (show_funcs) {
-		print_funcs();
+		pevent_print_funcs(perf_pevent);
 		return size;
 	}
 	if (show_printk) {
-		print_printk();
+		pevent_print_printk(perf_pevent);
 		return size;
 	}
 
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
index ed5e8ed..ac6d5aa 100644
--- a/tools/perf/util/trace-event.h
+++ b/tools/perf/util/trace-event.h
@@ -2,9 +2,57 @@
 #define _PERF_UTIL_TRACE_EVENT_H
 
 #include "parse-events.h"
-#include "trace-parse-events.h"
+#include "event-parse.h"
 #include "session.h"
 
+extern int header_page_size_size;
+extern int header_page_ts_size;
+extern int header_page_data_offset;
+
+extern bool latency_format;
+extern struct pevent *perf_pevent;
+
+enum {
+	RINGBUF_TYPE_PADDING		= 29,
+	RINGBUF_TYPE_TIME_EXTEND	= 30,
+	RINGBUF_TYPE_TIME_STAMP		= 31,
+};
+
+#ifndef TS_SHIFT
+#define TS_SHIFT		27
+#endif
+
+int bigendian(void);
+
+int read_trace_init(int file_bigendian, int host_bigendian);
+void print_trace_event(int cpu, void *data, int size);
+
+void print_event(int cpu, void *data, int size, unsigned long long nsecs,
+		  char *comm);
+
+int parse_ftrace_file(char *buf, unsigned long size);
+int parse_event_file(char *buf, unsigned long size, char *sys);
+
+struct record *trace_peek_data(int cpu);
+struct event_format *trace_find_event(int type);
+
+unsigned long long
+raw_field_value(struct event_format *event, const char *name, void *data);
+void *raw_field_ptr(struct event_format *event, const char *name, void *data);
+
+void parse_proc_kallsyms(char *file, unsigned int size __unused);
+void parse_ftrace_printk(char *file, unsigned int size __unused);
+
+ssize_t trace_report(int fd, bool repipe);
+
+int trace_parse_common_type(void *data);
+int trace_parse_common_pid(void *data);
+
+struct event_format *trace_find_next_event(struct event_format *event);
+unsigned long long read_size(void *ptr, int size);
+unsigned long long eval_flag(const char *flag);
+
+struct record *trace_read_data(int cpu);
 int read_tracing_data(int fd, struct list_head *pattrs);
 ssize_t read_tracing_data_size(int fd, struct list_head *pattrs);
 
diff --git a/tools/perf/util/trace-parse-events.c b/tools/perf/util/trace-parse-events.c
deleted file mode 100644
index 845cb00..0000000
--- a/tools/perf/util/trace-parse-events.c
+++ /dev/null
@@ -1,3128 +0,0 @@
-/*
- * 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.
- */
-#define _GNU_SOURCE
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include <errno.h>
-
-#undef _GNU_SOURCE
-#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 ret;
-	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;
-
-	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
deleted file mode 100644
index 794ec15..0000000
--- a/tools/perf/util/trace-parse-events.h
+++ /dev/null
@@ -1,273 +0,0 @@
-#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



^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [RFC][PATCH 6/8] perf/events: Add flag to produce nsec output
  2011-08-05 20:59 [RFC][PATCH 0/8] Having perf use libparsevent.a Steven Rostedt
                   ` (4 preceding siblings ...)
  2011-08-05 20:59 ` [RFC][PATCH 5/8] perf: Have perf use the new libparsevent.a library Steven Rostedt
@ 2011-08-05 20:59 ` Steven Rostedt
  2011-08-05 20:59 ` [RFC][PATCH 7/8] perf/events: Add flag/symbol format_flags Steven Rostedt
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 33+ messages in thread
From: Steven Rostedt @ 2011-08-05 20:59 UTC (permalink / raw)
  To: linux-kernel
  Cc: Ingo Molnar, Thomas Gleixner, Peter Zijlstra,
	Frederic Weisbecker, Arnaldo Carvalho de Melo, Borislav Petkov,
	Arjan van de Ven

[-- Attachment #1: 0006-perf-events-Add-flag-to-produce-nsec-output.patch --]
[-- Type: text/plain, Size: 3277 bytes --]

From: Steven Rostedt <srostedt@redhat.com>

libparsevent library prints out in usecs but perf wants to print out
in nsecs. Add a flag that lets the user decide to print out in usec
or nsec times.

Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
---
 tools/lib/events/event-parse.c      |   15 ++++++++++++---
 tools/lib/events/event-parse.h      |   12 ++++++++++++
 tools/perf/util/trace-event-parse.c |    1 +
 3 files changed, 25 insertions(+), 3 deletions(-)

diff --git a/tools/lib/events/event-parse.c b/tools/lib/events/event-parse.c
index 3b4fac3..dff66ad 100644
--- a/tools/lib/events/event-parse.c
+++ b/tools/lib/events/event-parse.c
@@ -3935,15 +3935,16 @@ void pevent_print_event(struct pevent *pevent, struct trace_seq *s,
 	struct event_format *event;
 	unsigned long secs;
 	unsigned long usecs;
+	unsigned long nsecs;
 	const char *comm;
 	void *data = record->data;
 	int type;
 	int pid;
 	int len;
+	int p;
 
 	secs = record->ts / NSECS_PER_SEC;
-	usecs = record->ts - secs * NSECS_PER_SEC;
-	usecs = (usecs + 500) / NSECS_PER_USEC;
+	nsecs = record->ts - secs * NSECS_PER_SEC;
 
 	if (record->size < 0) {
 		do_warning("ug! negative record size %d", record->size);
@@ -3968,7 +3969,15 @@ void pevent_print_event(struct pevent *pevent, struct trace_seq *s,
 	} else
 		trace_seq_printf(s, "%16s-%-5d [%03d]", comm, pid, record->cpu);
 
-	trace_seq_printf(s, " %5lu.%06lu: %s: ", secs, usecs, event->name);
+	if (pevent->flags & PEVENT_NSEC_OUTPUT) {
+		usecs = nsecs;
+		p = 9;
+	} else {
+		usecs = (nsecs + 500) / NSECS_PER_USEC;
+		p = 6;
+	}
+
+	trace_seq_printf(s, " %5lu.%0*lu: %s: ", secs, p, usecs, event->name);
 
 	/* Space out the event names evenly. */
 	len = strlen(event->name);
diff --git a/tools/lib/events/event-parse.h b/tools/lib/events/event-parse.h
index 2e0222d..8852827 100644
--- a/tools/lib/events/event-parse.h
+++ b/tools/lib/events/event-parse.h
@@ -334,6 +334,10 @@ enum pevent_func_arg_type {
 	PEVENT_FUNC_ARG_MAX_TYPES
 };
 
+enum pevent_flag {
+	PEVENT_NSEC_OUTPUT		= 1,	/* output in NSECS */
+};
+
 struct cmdline;
 struct cmdline_list;
 struct func_map;
@@ -373,6 +377,7 @@ struct pevent {
 	struct printk_list *printklist;
 	unsigned int printk_count;
 
+
 	struct event_format **events;
 	int nr_events;
 	struct event_format **sort_events;
@@ -397,6 +402,8 @@ struct pevent {
 
 	int test_filters;
 
+	int flags;
+
 	struct format_field *bprint_ip_field;
 	struct format_field *bprint_fmt_field;
 	struct format_field *bprint_buf_field;
@@ -408,6 +415,11 @@ struct pevent {
 	struct event_format *last_event;
 };
 
+static inline void pevent_set_flag(struct pevent *pevent, int flag)
+{
+	pevent->flags |= flag;
+}
+
 static inline unsigned short
 __data2host2(struct pevent *pevent, unsigned short data)
 {
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c
index ca3e5cd..f9604f1 100644
--- a/tools/perf/util/trace-event-parse.c
+++ b/tools/perf/util/trace-event-parse.c
@@ -47,6 +47,7 @@ int read_trace_init(int file_bigendian, int host_bigendian)
 	perf_pevent = pevent_alloc();
 	pevent = perf_pevent;
 
+	pevent_set_flag(pevent, PEVENT_NSEC_OUTPUT);
 	pevent_set_file_bigendian(pevent, file_bigendian);
 	pevent_set_host_bigendian(pevent, host_bigendian);
 
-- 
1.7.5.4



^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [RFC][PATCH 7/8] perf/events: Add flag/symbol format_flags
  2011-08-05 20:59 [RFC][PATCH 0/8] Having perf use libparsevent.a Steven Rostedt
                   ` (5 preceding siblings ...)
  2011-08-05 20:59 ` [RFC][PATCH 6/8] perf/events: Add flag to produce nsec output Steven Rostedt
@ 2011-08-05 20:59 ` Steven Rostedt
  2011-08-05 20:59 ` [RFC][PATCH 8/8] perf/events: Correct size given to memset Steven Rostedt
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 33+ messages in thread
From: Steven Rostedt @ 2011-08-05 20:59 UTC (permalink / raw)
  To: linux-kernel
  Cc: Ingo Molnar, Thomas Gleixner, Peter Zijlstra,
	Frederic Weisbecker, Arnaldo Carvalho de Melo, Borislav Petkov,
	Arjan van de Ven, Tom Zanussi

[-- Attachment #1: 0007-perf-events-Add-flag-symbol-format_flags.patch --]
[-- Type: text/plain, Size: 1874 bytes --]

From: Tom Zanussi <tzanussi@gmail.com>

This is a port of commit eb9a42caa7a92
 perf trace: Add flag/symbolic format_flags
of the old trace-event-parse.c to the new event-parse.c that
was written by Tom Zanussi and forward ported by Steven Rostedt.

Signed-off-by: Tom Zanussi <tzanussi@gmail.com>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
---
 tools/lib/events/event-parse.c |   15 +++++++++++++++
 1 files changed, 15 insertions(+), 0 deletions(-)

diff --git a/tools/lib/events/event-parse.c b/tools/lib/events/event-parse.c
index dff66ad..3e9af2c 100644
--- a/tools/lib/events/event-parse.c
+++ b/tools/lib/events/event-parse.c
@@ -39,6 +39,9 @@ static const char *input_buf;
 static unsigned long long input_buf_ptr;
 static unsigned long long input_buf_siz;
 
+static int is_flag_field;
+static int is_symbolic_field;
+
 static int show_warning = 1;
 
 #define do_warning(fmt, ...)				\
@@ -1789,6 +1792,16 @@ process_entry(struct event_format *event __unused, struct print_arg *arg,
 	arg->type = PRINT_FIELD;
 	arg->field.name = field;
 
+	if (is_flag_field) {
+		arg->field.field = pevent_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 = pevent_find_any_field(event, arg->field.name);
+		arg->field.field->flags |= FIELD_IS_SYMBOLIC;
+		is_symbolic_field = 0;
+	}
+
 	type = read_token(&token);
 	*tok = token;
 
@@ -2393,10 +2406,12 @@ process_function(struct event_format *event, struct print_arg *arg,
 
 	if (strcmp(token, "__print_flags") == 0) {
 		free_token(token);
+		is_flag_field = 1;
 		return process_flags(event, arg, tok);
 	}
 	if (strcmp(token, "__print_symbolic") == 0) {
 		free_token(token);
+		is_symbolic_field = 1;
 		return process_symbols(event, arg, tok);
 	}
 	if (strcmp(token, "__get_str") == 0) {
-- 
1.7.5.4



^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [RFC][PATCH 8/8] perf/events: Correct size given to memset
  2011-08-05 20:59 [RFC][PATCH 0/8] Having perf use libparsevent.a Steven Rostedt
                   ` (6 preceding siblings ...)
  2011-08-05 20:59 ` [RFC][PATCH 7/8] perf/events: Add flag/symbol format_flags Steven Rostedt
@ 2011-08-05 20:59 ` Steven Rostedt
  2011-08-05 21:24 ` [RFC][PATCH 0/8] Having perf use libparsevent.a Ingo Molnar
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 33+ messages in thread
From: Steven Rostedt @ 2011-08-05 20:59 UTC (permalink / raw)
  To: linux-kernel
  Cc: Ingo Molnar, Thomas Gleixner, Peter Zijlstra,
	Frederic Weisbecker, Arnaldo Carvalho de Melo, Borislav Petkov,
	Arjan van de Ven, Julia Lawall

[-- Attachment #1: 0008-perf-events-Correct-size-given-to-memset.patch --]
[-- Type: text/plain, Size: 875 bytes --]

From: Julia Lawall <julia@diku.dk>

This is a forward port of commit 5660ce34241ab
perf tools: Correct size given to memset
written by Julia Lawall and forward ported by Steven Rostedt.

Signed-off-by: Julia Lawall <julia@diku.dk>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
---
 tools/lib/events/event-parse.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/tools/lib/events/event-parse.c b/tools/lib/events/event-parse.c
index 3e9af2c..10e936f 100644
--- a/tools/lib/events/event-parse.c
+++ b/tools/lib/events/event-parse.c
@@ -2076,7 +2076,7 @@ process_fields(struct event_format *event, struct print_flag_sym **list, char **
 			goto out_free;
 
 		field = malloc_or_die(sizeof(*field));
-		memset(field, 0, sizeof(field));
+		memset(field, 0, sizeof(*field));
 
 		value = arg_eval(arg);
 		field->value = strdup(value);
-- 
1.7.5.4



^ permalink raw reply related	[flat|nested] 33+ messages in thread

* Re: [RFC][PATCH 0/8] Having perf use libparsevent.a
  2011-08-05 20:59 [RFC][PATCH 0/8] Having perf use libparsevent.a Steven Rostedt
                   ` (7 preceding siblings ...)
  2011-08-05 20:59 ` [RFC][PATCH 8/8] perf/events: Correct size given to memset Steven Rostedt
@ 2011-08-05 21:24 ` Ingo Molnar
  2011-08-06  0:43   ` Frederic Weisbecker
  2011-08-06  1:01   ` Steven Rostedt
  2011-08-06  0:07 ` David Ahern
  2011-08-06 15:23 ` Colin Walters
  10 siblings, 2 replies; 33+ messages in thread
From: Ingo Molnar @ 2011-08-05 21:24 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: linux-kernel, Thomas Gleixner, Peter Zijlstra,
	Frederic Weisbecker, Arnaldo Carvalho de Melo, Borislav Petkov,
	Arjan van de Ven


* Steven Rostedt <rostedt@goodmis.org> wrote:

> By keeping the code separate from perf, made the transition from 
> trace-cmd to tools much easier. I've wasted too many days trying to 
> get other ways working, and I don't want to rewrite perf to do so.

But we want to move tools together, not further apart. Every code 
activity i see from you is trying to tear apart instrumentation 
tooling - while previously you agreed that it should be unified. So 
why not do tools/perf/lib/ as you agreed before?

I'm really not interested in seeing the libdrm/libdri mess repeated. 
Libraries have their uses when there's some very important external 
interface, but here it's actively harmful as it complicates and 
hardcodes APIs into ABIs that are clearly not finished yet.

Really, lets not be stupid here.

Thanks,

	Ingo

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [RFC][PATCH 0/8] Having perf use libparsevent.a
  2011-08-05 20:59 [RFC][PATCH 0/8] Having perf use libparsevent.a Steven Rostedt
                   ` (8 preceding siblings ...)
  2011-08-05 21:24 ` [RFC][PATCH 0/8] Having perf use libparsevent.a Ingo Molnar
@ 2011-08-06  0:07 ` David Ahern
  2011-08-06  1:05   ` Steven Rostedt
  2011-08-06 15:23 ` Colin Walters
  10 siblings, 1 reply; 33+ messages in thread
From: David Ahern @ 2011-08-06  0:07 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: linux-kernel, Ingo Molnar, Thomas Gleixner, Peter Zijlstra,
	Frederic Weisbecker, Arnaldo Carvalho de Melo, Borislav Petkov,
	Arjan van de Ven

On 08/05/2011 02:59 PM, Steven Rostedt wrote:
> Hi All,
> 
> I've spent the week working on getting libparsevent.a working with
> perf. After several rewrites, hacking in both perf and the trace-cmd
> code, and breaking both beyond repair, I finally got to a point that
> it just works.

Does this version allow use of the trace-cmd plugins with perf?
Specifically, kvm tracing is not compatible with perf (perf barfs on the
kvm_exit traces); I suspect the plugins would fix that - as well as have
the pretty format for the exit reasons.

I want to try out the patch set, but will not have time until the week
of the kvm forum/linuxcon.

David

> 
> The library was originally going to be called libperf.so, but after
> talking with Arnaldo, he wants the functionality of the libraries
> separated more, not combined all in one binary. As this code deals
> only with the parsing the event formats and creating a way to read
> the binary data from it, we both agreed that it is best to keep its
> original name that was in trace-cmd and call it libparsevent.so.
> 
> Note, because perf installs in the user's ~/bin and I did not want to
> make it a requirement to add ~/bin to LD_LIBRARY_PATH, I kept the
> library as a .a that is linked directly into perf.
> 
> In the beginning, I tried to work with the library code within the
> tools/perf directory, and because of the CFLAGS of perf, it made
> compiling the library code very nasty (namely the -Wswitch-enum).
> I also talked with Arnaldo and Frederic about the placement of this
> code, and we all agreed that tools/lib/events is a good place to
> put it.
> 
> By keeping the code separate from perf, made the transition from
> trace-cmd to tools much easier. I've wasted too many days trying to
> get other ways working, and I don't want to rewrite perf to do so.
> 
> Thus, this is what I ended up with.
> 
> This patch set just gets the libparsevent.a/so working with perf.
> New code would be required to get it packaged for distributions to
> ship as a library itself. Once it gets there, I'll work on getting
> this code to work with code like latencytrace.
> 
> Anyway, this is still in the RFC phase. Lets hear what people have to
> say.
> 
> (some of the patches are quite large as they either insert full
> files or remove them, and probably will not make LKML due to the
> size constraint.)
> 
> This patches can be viewed from:
> 
>   git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-2.6-trace.git
> tip/perf/parse-events
> 
> Head SHA1: 781d261ff8241243173cf996ceb068cb19bd5874
> 
> 
> Julia Lawall (1):
>       perf/events: Correct size given to memset
> 
> Steven Rostedt (6):
>       perf: Separate out trace-cmd parse-events from perf files
>       tools/events: Add files to create libparsevent.a
>       perf: Build libparsevent.a
>       events: Update tools/lib/events to work with perf
>       perf: Have perf use the new libparsevent.a library
>       perf/events: Add flag to produce nsec output
> 
> Tom Zanussi (1):
>       perf/events: Add flag/symbol format_flags
> 
> ----
>  tools/lib/events/Makefile                          |  303 ++
>  tools/lib/events/event-parse.c                     | 4991 ++++++++++++++++++++
>  tools/lib/events/event-parse.h                     |  804 ++++
>  tools/lib/events/event-utils.h                     |   80 +
>  tools/lib/events/parse-filter.c                    | 2262 +++++++++
>  tools/lib/events/parse-utils.c                     |  110 +
>  tools/lib/events/trace-seq.c                       |  200 +
>  tools/perf/Makefile                                |   17 +-
>  tools/perf/builtin-kmem.c                          |    6 +-
>  tools/perf/builtin-lock.c                          |   26 +-
>  tools/perf/builtin-sched.c                         |   42 +-
>  tools/perf/builtin-script.c                        |    2 +-
>  .../util/scripting-engines/trace-event-python.c    |   16 +-
>  tools/perf/util/trace-event-info.c                 |    4 +-
>  tools/perf/util/trace-event-parse.c                | 3188 +------------
>  tools/perf/util/trace-event-read.c                 |   34 +-
>  tools/perf/util/trace-event.h                      |  268 +-
>  17 files changed, 9070 insertions(+), 3283 deletions(-)
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [RFC][PATCH 0/8] Having perf use libparsevent.a
  2011-08-05 21:24 ` [RFC][PATCH 0/8] Having perf use libparsevent.a Ingo Molnar
@ 2011-08-06  0:43   ` Frederic Weisbecker
  2011-08-06  6:48     ` Ingo Molnar
  2011-08-06  1:01   ` Steven Rostedt
  1 sibling, 1 reply; 33+ messages in thread
From: Frederic Weisbecker @ 2011-08-06  0:43 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Steven Rostedt, linux-kernel, Thomas Gleixner, Peter Zijlstra,
	Arnaldo Carvalho de Melo, Borislav Petkov, Arjan van de Ven

On Fri, Aug 05, 2011 at 11:24:09PM +0200, Ingo Molnar wrote:
> 
> * Steven Rostedt <rostedt@goodmis.org> wrote:
> 
> > By keeping the code separate from perf, made the transition from 
> > trace-cmd to tools much easier. I've wasted too many days trying to 
> > get other ways working, and I don't want to rewrite perf to do so.
> 
> But we want to move tools together, not further apart. Every code 
> activity i see from you is trying to tear apart instrumentation 
> tooling - while previously you agreed that it should be unified. So 
> why not do tools/perf/lib/ as you agreed before?
> 
> I'm really not interested in seeing the libdrm/libdri mess repeated. 
> Libraries have their uses when there's some very important external 
> interface, but here it's actively harmful as it complicates and 
> hardcodes APIs into ABIs that are clearly not finished yet.
> 
> Really, lets not be stupid here.
> 
> Thanks,
> 
> 	Ingo

The trace events format is a general interface that not only
perf and trace-cmd use but also powertop and pytimechart, and
may be others?

And given the breakage we had with powertop, for example, that broke
because it was relying on an ad-hoc static layout of the trace event,
or pytimechart that relies(ed?) on the event string output, I think that library
is needed outside perf.

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [RFC][PATCH 0/8] Having perf use libparsevent.a
  2011-08-05 21:24 ` [RFC][PATCH 0/8] Having perf use libparsevent.a Ingo Molnar
  2011-08-06  0:43   ` Frederic Weisbecker
@ 2011-08-06  1:01   ` Steven Rostedt
  2011-08-06  6:51     ` Ingo Molnar
  2011-08-06  9:14     ` Borislav Petkov
  1 sibling, 2 replies; 33+ messages in thread
From: Steven Rostedt @ 2011-08-06  1:01 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: linux-kernel, Thomas Gleixner, Peter Zijlstra,
	Frederic Weisbecker, Arnaldo Carvalho de Melo, Borislav Petkov,
	Arjan van de Ven

On Fri, 2011-08-05 at 23:24 +0200, Ingo Molnar wrote:
> * Steven Rostedt <rostedt@goodmis.org> wrote:
> 
> > By keeping the code separate from perf, made the transition from 
> > trace-cmd to tools much easier. I've wasted too many days trying to 
> > get other ways working, and I don't want to rewrite perf to do so.
> 
> But we want to move tools together, not further apart. Every code 
> activity i see from you is trying to tear apart instrumentation 

Ouch!

Ingo, I was trying to do as you said, but to do so would require a lot
of restructuring of the perf code base. I started talking with Arnaldo,
as he's doing a lot of the work in the tools/perf code, and he's the one
that suggested that I do it this way. It made things a lot easier.

Seriously, I wasted Mon-Wed trying to see how it would work in
tools/perf. I went through iteration after iteration, and each time I
either rewrote the tools/perf/Makefile, or hacked apart the libparsevent
code to be strictly perf specific, and not very useful for anything
else.

It took me half of Thursday to get something working with this method.
It made sense and was easy to do. I don't have much more time to spend
on this. Red Hat does not pay me to do tracing/perf work. There's other
things that I need to focus on, and there's other aspects of ftrace that
needs to get done too (-mfentry for one).


> tooling - while previously you agreed that it should be unified. So 
> why not do tools/perf/lib/ as you agreed before?

Because Arnaldo and Frederic convinced me the tools/lib made more sense.

> 
> I'm really not interested in seeing the libdrm/libdri mess repeated. 
> Libraries have their uses when there's some very important external 
> interface, but here it's actively harmful as it complicates and 
> hardcodes APIs into ABIs that are clearly not finished yet.

What API/ABI is being hardcoded here?

-- Steve



^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [RFC][PATCH 0/8] Having perf use libparsevent.a
  2011-08-06  0:07 ` David Ahern
@ 2011-08-06  1:05   ` Steven Rostedt
  0 siblings, 0 replies; 33+ messages in thread
From: Steven Rostedt @ 2011-08-06  1:05 UTC (permalink / raw)
  To: David Ahern
  Cc: linux-kernel, Ingo Molnar, Thomas Gleixner, Peter Zijlstra,
	Frederic Weisbecker, Arnaldo Carvalho de Melo, Borislav Petkov,
	Arjan van de Ven

On Fri, 2011-08-05 at 18:07 -0600, David Ahern wrote:
> On 08/05/2011 02:59 PM, Steven Rostedt wrote:
> > Hi All,
> > 
> > I've spent the week working on getting libparsevent.a working with
> > perf. After several rewrites, hacking in both perf and the trace-cmd
> > code, and breaking both beyond repair, I finally got to a point that
> > it just works.
> 
> Does this version allow use of the trace-cmd plugins with perf?
> Specifically, kvm tracing is not compatible with perf (perf barfs on the
> kvm_exit traces); I suspect the plugins would fix that - as well as have
> the pretty format for the exit reasons.
> 
> I want to try out the patch set, but will not have time until the week
> of the kvm forum/linuxcon.
> 

I posted this patch set as an RFC as I don't have time to waste on doing
more work, and I knew it would cause some controversy.

That said, this patch set does not yet add the plugins, but it lays the
ground work for adding plugins to perf in the next step. I probably
could get plugins working with perf by next week. If we keep going in
this direction, otherwise, probably not till next year.

-- Steve



^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [RFC][PATCH 0/8] Having perf use libparsevent.a
  2011-08-06  0:43   ` Frederic Weisbecker
@ 2011-08-06  6:48     ` Ingo Molnar
  2011-08-06 14:56       ` Frederic Weisbecker
  0 siblings, 1 reply; 33+ messages in thread
From: Ingo Molnar @ 2011-08-06  6:48 UTC (permalink / raw)
  To: Frederic Weisbecker
  Cc: Steven Rostedt, linux-kernel, Thomas Gleixner, Peter Zijlstra,
	Arnaldo Carvalho de Melo, Borislav Petkov, Arjan van de Ven


* Frederic Weisbecker <fweisbec@gmail.com> wrote:

> On Fri, Aug 05, 2011 at 11:24:09PM +0200, Ingo Molnar wrote:
> > 
> > * Steven Rostedt <rostedt@goodmis.org> wrote:
> > 
> > > By keeping the code separate from perf, made the transition from 
> > > trace-cmd to tools much easier. I've wasted too many days trying to 
> > > get other ways working, and I don't want to rewrite perf to do so.
> > 
> > But we want to move tools together, not further apart. Every code 
> > activity i see from you is trying to tear apart instrumentation 
> > tooling - while previously you agreed that it should be unified. So 
> > why not do tools/perf/lib/ as you agreed before?
> > 
> > I'm really not interested in seeing the libdrm/libdri mess repeated. 
> > Libraries have their uses when there's some very important external 
> > interface, but here it's actively harmful as it complicates and 
> > hardcodes APIs into ABIs that are clearly not finished yet.
> > 
> > Really, lets not be stupid here.
> > 
> > Thanks,
> > 
> > 	Ingo
> 
> The trace events format is a general interface that not only perf 
> and trace-cmd use but also powertop and pytimechart, and may be 
> others?
> 
> And given the breakage we had with powertop, for example, that 
> broke because it was relying on an ad-hoc static layout of the 
> trace event, or pytimechart that relies(ed?) on the event string 
> output, I think that library is needed outside perf.

That is why i suggested libperf.so - this will handle the cases you 
mention, plus any future case - while still allow more flexible code 
sharing between libperf and the perf tools themselves.

Thanks,

	Ingo

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [RFC][PATCH 0/8] Having perf use libparsevent.a
  2011-08-06  1:01   ` Steven Rostedt
@ 2011-08-06  6:51     ` Ingo Molnar
  2011-08-08 21:30       ` Steven Rostedt
  2011-08-06  9:14     ` Borislav Petkov
  1 sibling, 1 reply; 33+ messages in thread
From: Ingo Molnar @ 2011-08-06  6:51 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: linux-kernel, Thomas Gleixner, Peter Zijlstra,
	Frederic Weisbecker, Arnaldo Carvalho de Melo, Borislav Petkov,
	Arjan van de Ven


* Steven Rostedt <rostedt@goodmis.org> wrote:

> Ingo, I was trying to do as you said, but to do so would require a 
> lot of restructuring of the perf code base. I started talking with 
> Arnaldo, as he's doing a lot of the work in the tools/perf code, 
> and he's the one that suggested that I do it this way. It made 
> things a lot easier.

Could you guys please talk some more and clear it up? There's 
absolutely no technical reason why tools/perf/lib/ (or 
tools/perf/libperf/) should be harder than tools/lib/.

Thanks,

	Ingo

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [RFC][PATCH 0/8] Having perf use libparsevent.a
  2011-08-06  1:01   ` Steven Rostedt
  2011-08-06  6:51     ` Ingo Molnar
@ 2011-08-06  9:14     ` Borislav Petkov
  1 sibling, 0 replies; 33+ messages in thread
From: Borislav Petkov @ 2011-08-06  9:14 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: Ingo Molnar, linux-kernel, Thomas Gleixner, Peter Zijlstra,
	Frederic Weisbecker, Arnaldo Carvalho de Melo, Arjan van de Ven

On Fri, Aug 05, 2011 at 09:01:28PM -0400, Steven Rostedt wrote:
> On Fri, 2011-08-05 at 23:24 +0200, Ingo Molnar wrote:
> > * Steven Rostedt <rostedt@goodmis.org> wrote:
> > 
> > > By keeping the code separate from perf, made the transition from 
> > > trace-cmd to tools much easier. I've wasted too many days trying to 
> > > get other ways working, and I don't want to rewrite perf to do so.
> > 
> > But we want to move tools together, not further apart. Every code 
> > activity i see from you is trying to tear apart instrumentation 
> 
> Ouch!
> 
> Ingo, I was trying to do as you said, but to do so would require a lot
> of restructuring of the perf code base. I started talking with Arnaldo,
> as he's doing a lot of the work in the tools/perf code, and he's the one
> that suggested that I do it this way. It made things a lot easier.
> 
> Seriously, I wasted Mon-Wed trying to see how it would work in
> tools/perf. I went through iteration after iteration, and each time I
> either rewrote the tools/perf/Makefile, or hacked apart the libparsevent
> code to be strictly perf specific, and not very useful for anything
> else.

Now you feel exactly how I felt when preparing the RAS daemon stuff :-)

I think we should first agree on the design of libperf or whatever other
libraries and then start working towards it. Then we'd all know where
we're going so coding it up would be almost a routine task. And then,
other people who've done it for a couple of times already (hint: me)
could help so Steve won't have to do it alone.

Thanks.

-- 
Regards/Gruss,
    Boris.

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [RFC][PATCH 0/8] Having perf use libparsevent.a
  2011-08-06  6:48     ` Ingo Molnar
@ 2011-08-06 14:56       ` Frederic Weisbecker
       [not found]         ` <CAKYOsXw+Q+h2D++LxAoCUJ3tFVEhczBgDWNjwXzuJ0mNDav_Rw@mail.gmail.com>
  0 siblings, 1 reply; 33+ messages in thread
From: Frederic Weisbecker @ 2011-08-06 14:56 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Steven Rostedt, linux-kernel, Thomas Gleixner, Peter Zijlstra,
	Arnaldo Carvalho de Melo, Borislav Petkov, Arjan van de Ven

On Sat, Aug 06, 2011 at 08:48:47AM +0200, Ingo Molnar wrote:
> 
> * Frederic Weisbecker <fweisbec@gmail.com> wrote:
> 
> > On Fri, Aug 05, 2011 at 11:24:09PM +0200, Ingo Molnar wrote:
> > > 
> > > * Steven Rostedt <rostedt@goodmis.org> wrote:
> > > 
> > > > By keeping the code separate from perf, made the transition from 
> > > > trace-cmd to tools much easier. I've wasted too many days trying to 
> > > > get other ways working, and I don't want to rewrite perf to do so.
> > > 
> > > But we want to move tools together, not further apart. Every code 
> > > activity i see from you is trying to tear apart instrumentation 
> > > tooling - while previously you agreed that it should be unified. So 
> > > why not do tools/perf/lib/ as you agreed before?
> > > 
> > > I'm really not interested in seeing the libdrm/libdri mess repeated. 
> > > Libraries have their uses when there's some very important external 
> > > interface, but here it's actively harmful as it complicates and 
> > > hardcodes APIs into ABIs that are clearly not finished yet.
> > > 
> > > Really, lets not be stupid here.
> > > 
> > > Thanks,
> > > 
> > > 	Ingo
> > 
> > The trace events format is a general interface that not only perf 
> > and trace-cmd use but also powertop and pytimechart, and may be 
> > others?
> > 
> > And given the breakage we had with powertop, for example, that 
> > broke because it was relying on an ad-hoc static layout of the 
> > trace event, or pytimechart that relies(ed?) on the event string 
> > output, I think that library is needed outside perf.
> 
> That is why i suggested libperf.so - this will handle the cases you 
> mention, plus any future case - while still allow more flexible code 
> sharing between libperf and the perf tools themselves.

But what would you want inside libperf.o, further the trace event
library?

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [RFC][PATCH 0/8] Having perf use libparsevent.a
       [not found]         ` <CAKYOsXw+Q+h2D++LxAoCUJ3tFVEhczBgDWNjwXzuJ0mNDav_Rw@mail.gmail.com>
@ 2011-08-06 15:18           ` Frederic Weisbecker
  2011-08-06 15:35           ` Steven Rostedt
  1 sibling, 0 replies; 33+ messages in thread
From: Frederic Weisbecker @ 2011-08-06 15:18 UTC (permalink / raw)
  To: David Ahern
  Cc: Ingo Molnar, Steven Rostedt, linux-kernel, Thomas Gleixner,
	Peter Zijlstra, Arnaldo Carvalho de Melo, Borislav Petkov,
	Arjan van de Ven

On Sat, Aug 06, 2011 at 09:16:58AM -0600, David Ahern wrote:
> On Sat, Aug 6, 2011 at 8:56 AM, Frederic Weisbecker <fweisbec@gmail.com>wrote:
> 
> > On Sat, Aug 06, 2011 at 08:48:47AM +0200, Ingo Molnar wrote:
> > > That is why i suggested libperf.so - this will handle the cases you
> > > mention, plus any future case - while still allow more flexible code
> > > sharing between libperf and the perf tools themselves.
> >
> > But what would you want inside libperf.o, further the trace event
> > library?
> >
> 
> 
> If the library is just for parsing trace events why not call it
> libtraceparse or libtrace? This isn't perf specific functionality.
> 
> David

This is what I don't understand yeah.

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [RFC][PATCH 0/8] Having perf use libparsevent.a
  2011-08-05 20:59 [RFC][PATCH 0/8] Having perf use libparsevent.a Steven Rostedt
                   ` (9 preceding siblings ...)
  2011-08-06  0:07 ` David Ahern
@ 2011-08-06 15:23 ` Colin Walters
  10 siblings, 0 replies; 33+ messages in thread
From: Colin Walters @ 2011-08-06 15:23 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: linux-kernel, Ingo Molnar, Thomas Gleixner, Peter Zijlstra,
	Frederic Weisbecker, Arnaldo Carvalho de Melo, Borislav Petkov,
	Arjan van de Ven

On Fri, Aug 5, 2011 at 4:59 PM, Steven Rostedt <rostedt@goodmis.org> wrote:
>
> Note, because perf installs in the user's ~/bin and I did not want to
> make it a requirement to add ~/bin to LD_LIBRARY_PATH, I kept the
> library as a .a that is linked directly into perf.

Note you can add an rpath to avoid having to modify LD_LIBRARY_PATH;
rpath is just better for this kind of thing.  As a general rule of
thumb, if you're installing somewhere outside of the target system's
/etc/ld.so.conf, add an rpath.  And for this purpose ignore e.g.
Fedora's broken tendency to put private libraries in
/etc/ld.so.conf.d.

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [RFC][PATCH 0/8] Having perf use libparsevent.a
       [not found]         ` <CAKYOsXw+Q+h2D++LxAoCUJ3tFVEhczBgDWNjwXzuJ0mNDav_Rw@mail.gmail.com>
  2011-08-06 15:18           ` Frederic Weisbecker
@ 2011-08-06 15:35           ` Steven Rostedt
  1 sibling, 0 replies; 33+ messages in thread
From: Steven Rostedt @ 2011-08-06 15:35 UTC (permalink / raw)
  To: David Ahern
  Cc: Frederic Weisbecker, Ingo Molnar, linux-kernel, Thomas Gleixner,
	Peter Zijlstra, Arnaldo Carvalho de Melo, Borislav Petkov,
	Arjan van de Ven

On Sat, 2011-08-06 at 09:16 -0600, David Ahern wrote:

> If the library is just for parsing trace events why not call it
> libtraceparse or libtrace? This isn't perf specific functionality.

Actually, I'm thinking libevents would probably be most appropriate. It
has less to do with perf in general, and more about events. Even reading
the events goes under this category.

-- Steve

> 



^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [RFC][PATCH 0/8] Having perf use libparsevent.a
  2011-08-06  6:51     ` Ingo Molnar
@ 2011-08-08 21:30       ` Steven Rostedt
  0 siblings, 0 replies; 33+ messages in thread
From: Steven Rostedt @ 2011-08-08 21:30 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: linux-kernel, Thomas Gleixner, Peter Zijlstra,
	Frederic Weisbecker, Arnaldo Carvalho de Melo, Borislav Petkov,
	Arjan van de Ven

On Sat, 2011-08-06 at 08:51 +0200, Ingo Molnar wrote:
> * Steven Rostedt <rostedt@goodmis.org> wrote:
> 
> > Ingo, I was trying to do as you said, but to do so would require a 
> > lot of restructuring of the perf code base. I started talking with 
> > Arnaldo, as he's doing a lot of the work in the tools/perf code, 
> > and he's the one that suggested that I do it this way. It made 
> > things a lot easier.
> 
> Could you guys please talk some more and clear it up? There's 
> absolutely no technical reason why tools/perf/lib/ (or 
> tools/perf/libperf/) should be harder than tools/lib/.

The issue was trying to use the Makefile within perf for the building.
There was issues with the warning flags and also the deps that are
automatically made with libparsevent.

But you are correct, if I were to just move the pointers over to
tools/perf/lib/events instead of tools/lib/events and had it be a
separate entity in the build process, then it would not be any different
between the two locations.

But there are two non-technical issues with that. Is it wise to have a
different type of build process within the tools/perf directory. The
libparsevents follows the Linux build system more than the git build
system.

The other being, is the parse events a perf only thing? Maybe having a
tools/lib would be nice even if it is. Because we can put things in
tools/lib that will go as a separate package. perf could depend on
tools/lib but there's no reason that tools/lib should depend on perf.

-- Steve



^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [RFC][PATCH 1/8] perf: Separate out trace-cmd parse-events from perf files
  2011-08-05 20:59 ` [RFC][PATCH 1/8] perf: Separate out trace-cmd parse-events from perf files Steven Rostedt
@ 2011-08-15 16:14   ` David Ahern
  2011-08-15 16:22     ` Steven Rostedt
  0 siblings, 1 reply; 33+ messages in thread
From: David Ahern @ 2011-08-15 16:14 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: linux-kernel, Ingo Molnar, Thomas Gleixner, Peter Zijlstra,
	Frederic Weisbecker, Arnaldo Carvalho de Melo, Borislav Petkov,
	Arjan van de Ven

Hi Steve:

On 08/05/2011 02:59 PM, Steven Rostedt wrote:
> 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.

What branch should these apply cleanly to?
David


> 
> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
> ---
>  tools/perf/Makefile                  |    2 +
>  tools/perf/util/trace-event-parse.c  | 3125 ---------------------------------
>  tools/perf/util/trace-event.h        |  274 +---
>  tools/perf/util/trace-parse-events.c | 3128 ++++++++++++++++++++++++++++++++++
>  tools/perf/util/trace-parse-events.h |  273 +++
>  5 files changed, 3407 insertions(+), 3395 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 940257b..ebf38c1 100644
> --- a/tools/perf/Makefile
> +++ b/tools/perf/Makefile
> @@ -278,6 +278,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/probe-event.h
>  LIB_H += util/pstack.h
> @@ -332,6 +333,7 @@ LIB_OBJS += $(OUTPUT)util/trace-event-parse.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 0a7ed5b..9477519 100644
> --- a/tools/perf/util/trace-event-parse.c
> +++ b/tools/perf/util/trace-event-parse.c
> @@ -1,3132 +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.
> - */
> -#define _GNU_SOURCE
> -#include <stdio.h>
> -#include <stdlib.h>
> -#include <string.h>
> -#include <ctype.h>
> -#include <errno.h>
> -
> -#undef _GNU_SOURCE
>  #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;
> -
> -	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;
> -}
> -
>  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 f674dda..ed5e8ed 100644
> --- a/tools/perf/util/trace-event.h
> +++ b/tools/perf/util/trace-event.h
> @@ -1,279 +1,13 @@
> -#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"
>  
> -#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);
>  ssize_t read_tracing_data_size(int fd, struct list_head *pattrs);
>  
> -/* 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);
> @@ -299,4 +33,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..845cb00
> --- /dev/null
> +++ b/tools/perf/util/trace-parse-events.c
> @@ -0,0 +1,3128 @@
> +/*
> + * 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.
> + */
> +#define _GNU_SOURCE
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <ctype.h>
> +#include <errno.h>
> +
> +#undef _GNU_SOURCE
> +#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 ret;
> +	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;
> +
> +	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 */

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [RFC][PATCH 1/8] perf: Separate out trace-cmd parse-events from perf files
  2011-08-15 16:14   ` David Ahern
@ 2011-08-15 16:22     ` Steven Rostedt
  2011-08-17  0:08       ` David Ahern
  0 siblings, 1 reply; 33+ messages in thread
From: Steven Rostedt @ 2011-08-15 16:22 UTC (permalink / raw)
  To: David Ahern
  Cc: linux-kernel, Ingo Molnar, Thomas Gleixner, Peter Zijlstra,
	Frederic Weisbecker, Arnaldo Carvalho de Melo, Borislav Petkov,
	Arjan van de Ven

On Mon, 2011-08-15 at 10:14 -0600, David Ahern wrote:
> Hi Steve:
> 
> On 08/05/2011 02:59 PM, Steven Rostedt wrote:
> > 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.
> 
> What branch should these apply cleanly to?

They are based off of v3.0. You can get these patches from my repo as
described in the 0/8 announce email.

-- Steve

> 
> > 
> > Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
> > ---
> >  tools/perf/Makefile                  |    2 +
> >  tools/perf/util/trace-event-parse.c  | 3125 ---------------------------------
> >  tools/perf/util/trace-event.h        |  274 +---
> >  tools/perf/util/trace-parse-events.c | 3128 ++++++++++++++++++++++++++++++++++
> >  tools/perf/util/trace-parse-events.h |  273 +++
> >  5 files changed, 3407 insertions(+), 3395 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 940257b..ebf38c1 100644
> > --- a/tools/perf/Makefile
> > +++ b/tools/perf/Makefile
> > @@ -278,6 +278,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/probe-event.h
> >  LIB_H += util/pstack.h
> > @@ -332,6 +333,7 @@ LIB_OBJS += $(OUTPUT)util/trace-event-parse.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 0a7ed5b..9477519 100644
> > --- a/tools/perf/util/trace-event-parse.c
> > +++ b/tools/perf/util/trace-event-parse.c
> > @@ -1,3132 +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.
> > - */
> > -#define _GNU_SOURCE
> > -#include <stdio.h>
> > -#include <stdlib.h>
> > -#include <string.h>
> > -#include <ctype.h>
> > -#include <errno.h>
> > -
> > -#undef _GNU_SOURCE
> >  #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;
> > -
> > -	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;
> > -}
> > -
> >  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 f674dda..ed5e8ed 100644
> > --- a/tools/perf/util/trace-event.h
> > +++ b/tools/perf/util/trace-event.h
> > @@ -1,279 +1,13 @@
> > -#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"
> >  
> > -#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);
> >  ssize_t read_tracing_data_size(int fd, struct list_head *pattrs);
> >  
> > -/* 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);
> > @@ -299,4 +33,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..845cb00
> > --- /dev/null
> > +++ b/tools/perf/util/trace-parse-events.c
> > @@ -0,0 +1,3128 @@
> > +/*
> > + * 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.
> > + */
> > +#define _GNU_SOURCE
> > +#include <stdio.h>
> > +#include <stdlib.h>
> > +#include <string.h>
> > +#include <ctype.h>
> > +#include <errno.h>
> > +
> > +#undef _GNU_SOURCE
> > +#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 ret;
> > +	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;
> > +
> > +	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 */



^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [RFC][PATCH 1/8] perf: Separate out trace-cmd parse-events from perf files
  2011-08-15 16:22     ` Steven Rostedt
@ 2011-08-17  0:08       ` David Ahern
  2011-08-17  0:31         ` Steven Rostedt
  2011-08-18 13:51         ` Frederic Weisbecker
  0 siblings, 2 replies; 33+ messages in thread
From: David Ahern @ 2011-08-17  0:08 UTC (permalink / raw)
  To: Steven Rostedt, Ingo Molnar, Frederic Weisbecker
  Cc: linux-kernel, Thomas Gleixner, Peter Zijlstra,
	Arnaldo Carvalho de Melo, Borislav Petkov, Arjan van de Ven

On 08/15/2011 10:22 AM, Steven Rostedt wrote:
> On Mon, 2011-08-15 at 10:14 -0600, David Ahern wrote:
>> Hi Steve:
>>
>> On 08/05/2011 02:59 PM, Steven Rostedt wrote:
>>> 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.
>>
>> What branch should these apply cleanly to?
> 
> They are based off of v3.0. You can get these patches from my repo as
> described in the 0/8 announce email.

Unfortunately I hastily deleted the 0/8 thread while on vacation last
week (gmail on Android thing), so I apologize for shifting the discussion.

With a little bit of hacking on top of your patches I was able to get
the trace-cmd plugins working with perf. e.g.,
        qemu-kvm 11971 [001] 30401.777391: kvm_apic_accept_irq: apicid 0
vec 239 (Fixed|edge)
        qemu-kvm 11971 [001] 30401.777405: kvm_inj_virq: irq 239
        qemu-kvm 11971 [001] 30401.777415: kvm_entry: vcpu 0
        qemu-kvm 11971 [001] 30401.777430: kvm_exit: reason APIC_ACCESS
rip 0xffffffff8101dbe4 info 10b0 0

So, what is the next step for making this a reality -- i.e., getting the
common code into a lib in tools?

David

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [RFC][PATCH 1/8] perf: Separate out trace-cmd parse-events from perf files
  2011-08-17  0:08       ` David Ahern
@ 2011-08-17  0:31         ` Steven Rostedt
  2011-08-18 13:51         ` Frederic Weisbecker
  1 sibling, 0 replies; 33+ messages in thread
From: Steven Rostedt @ 2011-08-17  0:31 UTC (permalink / raw)
  To: David Ahern
  Cc: Ingo Molnar, Frederic Weisbecker, linux-kernel, Thomas Gleixner,
	Peter Zijlstra, Arnaldo Carvalho de Melo, Borislav Petkov,
	Arjan van de Ven

On Tue, 2011-08-16 at 18:08 -0600, David Ahern wrote:

> > They are based off of v3.0. You can get these patches from my repo as
> > described in the 0/8 announce email.
> 
> Unfortunately I hastily deleted the 0/8 thread while on vacation last
> week (gmail on Android thing), so I apologize for shifting the discussion.

Understood.

> 
> With a little bit of hacking on top of your patches I was able to get
> the trace-cmd plugins working with perf. e.g.,
>         qemu-kvm 11971 [001] 30401.777391: kvm_apic_accept_irq: apicid 0
> vec 239 (Fixed|edge)
>         qemu-kvm 11971 [001] 30401.777405: kvm_inj_virq: irq 239
>         qemu-kvm 11971 [001] 30401.777415: kvm_entry: vcpu 0
>         qemu-kvm 11971 [001] 30401.777430: kvm_exit: reason APIC_ACCESS
> rip 0xffffffff8101dbe4 info 10b0 0

That's awesome!

> 
> So, what is the next step for making this a reality -- i.e., getting the
> common code into a lib in tools?

Yeah, once everyone agrees with everything. I personally prefer things
to be in tools/lib/... and have all other tools depend on it. For the
names of these libraries, I'm game for anything.

Arnaldo, what's your preference, as you were the one that suggested that
it not be called libperf?

But I think this is a great step forward in making ftrace and perf work
better together :)

-- Steve



^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [RFC][PATCH 1/8] perf: Separate out trace-cmd parse-events from perf files
  2011-08-17  0:08       ` David Ahern
  2011-08-17  0:31         ` Steven Rostedt
@ 2011-08-18 13:51         ` Frederic Weisbecker
  2011-08-18 16:37           ` David Ahern
  1 sibling, 1 reply; 33+ messages in thread
From: Frederic Weisbecker @ 2011-08-18 13:51 UTC (permalink / raw)
  To: David Ahern
  Cc: Steven Rostedt, Ingo Molnar, linux-kernel, Thomas Gleixner,
	Peter Zijlstra, Arnaldo Carvalho de Melo, Borislav Petkov,
	Arjan van de Ven

On Tue, Aug 16, 2011 at 06:08:07PM -0600, David Ahern wrote:
> On 08/15/2011 10:22 AM, Steven Rostedt wrote:
> > On Mon, 2011-08-15 at 10:14 -0600, David Ahern wrote:
> >> Hi Steve:
> >>
> >> On 08/05/2011 02:59 PM, Steven Rostedt wrote:
> >>> 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.
> >>
> >> What branch should these apply cleanly to?
> > 
> > They are based off of v3.0. You can get these patches from my repo as
> > described in the 0/8 announce email.
> 
> Unfortunately I hastily deleted the 0/8 thread while on vacation last
> week (gmail on Android thing), so I apologize for shifting the discussion.
> 
> With a little bit of hacking on top of your patches I was able to get
> the trace-cmd plugins working with perf. e.g.,
>         qemu-kvm 11971 [001] 30401.777391: kvm_apic_accept_irq: apicid 0
> vec 239 (Fixed|edge)
>         qemu-kvm 11971 [001] 30401.777405: kvm_inj_virq: irq 239
>         qemu-kvm 11971 [001] 30401.777415: kvm_entry: vcpu 0
>         qemu-kvm 11971 [001] 30401.777430: kvm_exit: reason APIC_ACCESS
> rip 0xffffffff8101dbe4 info 10b0 0
> 
> So, what is the next step for making this a reality -- i.e., getting the
> common code into a lib in tools?

I hope. Otherwise we'll simply get stuck with a buggy format parsing in perf.

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [RFC][PATCH 1/8] perf: Separate out trace-cmd parse-events from perf files
  2011-08-18 13:51         ` Frederic Weisbecker
@ 2011-08-18 16:37           ` David Ahern
  2011-08-18 16:59             ` Steven Rostedt
  0 siblings, 1 reply; 33+ messages in thread
From: David Ahern @ 2011-08-18 16:37 UTC (permalink / raw)
  To: Frederic Weisbecker, Steven Rostedt, Ingo Molnar
  Cc: linux-kernel, Thomas Gleixner, Peter Zijlstra,
	Arnaldo Carvalho de Melo, Borislav Petkov, Arjan van de Ven

On 08/18/2011 07:51 AM, Frederic Weisbecker wrote:
> On Tue, Aug 16, 2011 at 06:08:07PM -0600, David Ahern wrote:
>> On 08/15/2011 10:22 AM, Steven Rostedt wrote:
>>> On Mon, 2011-08-15 at 10:14 -0600, David Ahern wrote:
>>>> Hi Steve:
>>>>
>>>> On 08/05/2011 02:59 PM, Steven Rostedt wrote:
>>>>> 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.
>>>>
>>>> What branch should these apply cleanly to?
>>>
>>> They are based off of v3.0. You can get these patches from my repo as
>>> described in the 0/8 announce email.
>>
>> Unfortunately I hastily deleted the 0/8 thread while on vacation last
>> week (gmail on Android thing), so I apologize for shifting the discussion.
>>
>> With a little bit of hacking on top of your patches I was able to get
>> the trace-cmd plugins working with perf. e.g.,
>>         qemu-kvm 11971 [001] 30401.777391: kvm_apic_accept_irq: apicid 0
>> vec 239 (Fixed|edge)
>>         qemu-kvm 11971 [001] 30401.777405: kvm_inj_virq: irq 239
>>         qemu-kvm 11971 [001] 30401.777415: kvm_entry: vcpu 0
>>         qemu-kvm 11971 [001] 30401.777430: kvm_exit: reason APIC_ACCESS
>> rip 0xffffffff8101dbe4 info 10b0 0
>>
>> So, what is the next step for making this a reality -- i.e., getting the
>> common code into a lib in tools?
> 
> I hope. Otherwise we'll simply get stuck with a buggy format parsing in perf.

I guess to be more specific about next steps:
- should trace-cmd be moved to the tools directory in the kernel repo?
that would allow code movement to a lib directory and work to be done on
both trace-cmd and perf
- what's the conclusion about the name and path for the common parsing
code? seems like libtraceevent or libtraceparse had the fewest collisions
- should the plugin code be moved into its own directory - e.g.,
tools/lib/trace-plugins. I am working on plugin changes too (eg.,
resolving guest RIPs to symbols in the kvm plugin).

The current patch set from Steve needs some updates (in addition to what
is needed for perf to use the plugins) to handle trace-cmd and perf
differences, but this is getting far down the path.

David

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [RFC][PATCH 1/8] perf: Separate out trace-cmd parse-events from perf files
  2011-08-18 16:37           ` David Ahern
@ 2011-08-18 16:59             ` Steven Rostedt
  0 siblings, 0 replies; 33+ messages in thread
From: Steven Rostedt @ 2011-08-18 16:59 UTC (permalink / raw)
  To: David Ahern
  Cc: Frederic Weisbecker, Ingo Molnar, linux-kernel, Thomas Gleixner,
	Peter Zijlstra, Arnaldo Carvalho de Melo, Borislav Petkov,
	Arjan van de Ven

On Thu, 2011-08-18 at 10:37 -0600, David Ahern wrote:
> On 08/18/2011 07:51 AM, Frederic Weisbecker wrote:

> I guess to be more specific about next steps:
> - should trace-cmd be moved to the tools directory in the kernel repo?

Nah, I rather keep it out of the kernel for now.

> that would allow code movement to a lib directory and work to be done on
> both trace-cmd and perf
> - what's the conclusion about the name and path for the common parsing
> code? seems like libtraceevent or libtraceparse had the fewest collisions

I guess libtraceparse is fine. Or maybe even libtraceparser.


> - should the plugin code be moved into its own directory - e.g.,
> tools/lib/trace-plugins. I am working on plugin changes too (eg.,
> resolving guest RIPs to symbols in the kvm plugin).

I think it should have its own directory. Or maybe even have it within
the kernel proper itself?  Have it install like modules:

/lib/modules/v3.0-rc2/plugins/

??


> 
> The current patch set from Steve needs some updates (in addition to what
> is needed for perf to use the plugins) to handle trace-cmd and perf
> differences, but this is getting far down the path.

I'm currently working on other things, and I'm waiting for consensus
before I waste more time on it.

Don't worry about trace-cmd. If libtraceparser becomes an installed
library, I'll have trace-cmd use it directly. As long as the library
stays generic (which it should) this should not cause any issues. For
now, trace-cmd will keep its original libparsevents, and I can update
that until we have this library in distributions.

Thanks!

-- Steve



^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [RFC][PATCH 0/8] Having perf use libparsevent.a
  2011-08-08  9:34   ` Américo Wang
@ 2011-08-08 13:42     ` Steven Rostedt
  0 siblings, 0 replies; 33+ messages in thread
From: Steven Rostedt @ 2011-08-08 13:42 UTC (permalink / raw)
  To: Américo Wang
  Cc: Kyle Moffett, Arnaldo Carvalho de Melo, Frederic Weisbecker,
	David Ahern, Arjan van de Ven, Borislav Petkov, Peter Zijlstra,
	Thomas Gleixner, Ingo Molnar, linux-kernel

On Mon, 2011-08-08 at 17:34 +0800, Américo Wang wrote:

> libkevent is still too generic, how about libtraceevent?

Hmm, I wanted to make it more generic than tracing, as it can be
profiling as well. But they do hook to tracepoints in the kernel, so
maybe libtracevent may be fine. Or libtracepoint.

-- Steve




^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [RFC][PATCH 0/8] Having perf use libparsevent.a
  2011-08-06 21:40 ` Steven Rostedt
  2011-08-06 23:14   ` Kyle Moffett
@ 2011-08-08  9:34   ` Américo Wang
  2011-08-08 13:42     ` Steven Rostedt
  1 sibling, 1 reply; 33+ messages in thread
From: Américo Wang @ 2011-08-08  9:34 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: Kyle Moffett, Arnaldo Carvalho de Melo, Frederic Weisbecker,
	David Ahern, Arjan van de Ven, Borislav Petkov, Peter Zijlstra,
	Thomas Gleixner, Ingo Molnar, linux-kernel

On Sun, Aug 7, 2011 at 5:40 AM, Steven Rostedt <rostedt@goodmis.org> wrote:
> On Sat, 2011-08-06 at 14:47 -0400, Kyle Moffett wrote:
>> On Aug 6, 2011 11:35 AM, "Steven Rostedt" <rostedt@goodmis.org> wrote:
>> >
>> > On Sat, 2011-08-06 at 09:16 -0600, David Ahern wrote:
>> >
>> > > If the library is just for parsing trace events why not call it
>> > > libtraceparse or libtrace? This isn't perf specific functionality.
>> >
>> > Actually, I'm thinking libevents would probably be most appropriate.
>> It
>> > has less to do with perf in general, and more about events. Even
>> reading
>> > the events goes under this category.
>>
>> Ooh, please don't... "libevent" is already an epoll() event-based
>> application helper library and this would be overly confusing.
>
> OK, what about libkevent, as this has to do with kernel events.
>

libkevent is still too generic, how about libtraceevent?

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [RFC][PATCH 0/8] Having perf use libparsevent.a
  2011-08-06 21:40 ` Steven Rostedt
@ 2011-08-06 23:14   ` Kyle Moffett
  2011-08-08  9:34   ` Américo Wang
  1 sibling, 0 replies; 33+ messages in thread
From: Kyle Moffett @ 2011-08-06 23:14 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: Arnaldo Carvalho de Melo, Frederic Weisbecker, David Ahern,
	Arjan van de Ven, Borislav Petkov, Peter Zijlstra,
	Thomas Gleixner, Ingo Molnar, linux-kernel

On Sat, Aug 6, 2011 at 17:40, Steven Rostedt <rostedt@goodmis.org> wrote:
> On Sat, 2011-08-06 at 14:47 -0400, Kyle Moffett wrote:
>> On Aug 6, 2011 11:35 AM, "Steven Rostedt" <rostedt@goodmis.org> wrote:
>>> On Sat, 2011-08-06 at 09:16 -0600, David Ahern wrote:
>>>> If the library is just for parsing trace events why not call it
>>>> libtraceparse or libtrace? This isn't perf specific functionality.
>>>
>>> Actually, I'm thinking libevents would probably be most appropriate.
>>> It has less to do with perf in general, and more about events. Even
>>> reading the events goes under this category.
>>
>> Ooh, please don't... "libevent" is already an epoll() event-based
>> application helper library and this would be overly confusing.
>
> OK, what about libkevent, as this has to do with kernel events.

Hmm, well "kevent()" is a BSD syscall that does the same kinds of things
as "epoll()" does on Linux.  It's used by libevent, in fact.

Maybe "libkernevent"?  A quick google doesn't find anything problematic
there...  Other options with minimal chance of confusion are:
  libkernelevent
  liblinuxevent
  libinuxevent (Linked with option "-linuxevent")

To be honest I don't really see anything wrong with a name involving
"trace"...  Perhaps something like libevtrace/libtraceevent/etc?

Cheers,
Kyle Moffett

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [RFC][PATCH 0/8] Having perf use libparsevent.a
       [not found] <CAGZ=bq+mJ-9pf0Y22b9LLey0Em2Y7SAA5FnQ5cPsde6GB_aqgw@mail.gmail.com>
@ 2011-08-06 21:40 ` Steven Rostedt
  2011-08-06 23:14   ` Kyle Moffett
  2011-08-08  9:34   ` Américo Wang
  0 siblings, 2 replies; 33+ messages in thread
From: Steven Rostedt @ 2011-08-06 21:40 UTC (permalink / raw)
  To: Kyle Moffett
  Cc: Arnaldo Carvalho de Melo, Frederic Weisbecker, David Ahern,
	Arjan van de Ven, Borislav Petkov, Peter Zijlstra,
	Thomas Gleixner, Ingo Molnar, linux-kernel

On Sat, 2011-08-06 at 14:47 -0400, Kyle Moffett wrote:
> On Aug 6, 2011 11:35 AM, "Steven Rostedt" <rostedt@goodmis.org> wrote:
> >
> > On Sat, 2011-08-06 at 09:16 -0600, David Ahern wrote:
> >
> > > If the library is just for parsing trace events why not call it
> > > libtraceparse or libtrace? This isn't perf specific functionality.
> >
> > Actually, I'm thinking libevents would probably be most appropriate.
> It
> > has less to do with perf in general, and more about events. Even
> reading
> > the events goes under this category.
> 
> Ooh, please don't... "libevent" is already an epoll() event-based
> application helper library and this would be overly confusing.

OK, what about libkevent, as this has to do with kernel events.

-- Steve



^ permalink raw reply	[flat|nested] 33+ messages in thread

end of thread, other threads:[~2011-08-18 16:59 UTC | newest]

Thread overview: 33+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-08-05 20:59 [RFC][PATCH 0/8] Having perf use libparsevent.a Steven Rostedt
2011-08-05 20:59 ` [RFC][PATCH 1/8] perf: Separate out trace-cmd parse-events from perf files Steven Rostedt
2011-08-15 16:14   ` David Ahern
2011-08-15 16:22     ` Steven Rostedt
2011-08-17  0:08       ` David Ahern
2011-08-17  0:31         ` Steven Rostedt
2011-08-18 13:51         ` Frederic Weisbecker
2011-08-18 16:37           ` David Ahern
2011-08-18 16:59             ` Steven Rostedt
2011-08-05 20:59 ` [RFC][PATCH 2/8] tools/events: Add files to create libparsevent.a Steven Rostedt
2011-08-05 20:59 ` [RFC][PATCH 3/8] perf: Build libparsevent.a Steven Rostedt
2011-08-05 20:59 ` [RFC][PATCH 4/8] events: Update tools/lib/events to work with perf Steven Rostedt
2011-08-05 20:59 ` [RFC][PATCH 5/8] perf: Have perf use the new libparsevent.a library Steven Rostedt
2011-08-05 20:59 ` [RFC][PATCH 6/8] perf/events: Add flag to produce nsec output Steven Rostedt
2011-08-05 20:59 ` [RFC][PATCH 7/8] perf/events: Add flag/symbol format_flags Steven Rostedt
2011-08-05 20:59 ` [RFC][PATCH 8/8] perf/events: Correct size given to memset Steven Rostedt
2011-08-05 21:24 ` [RFC][PATCH 0/8] Having perf use libparsevent.a Ingo Molnar
2011-08-06  0:43   ` Frederic Weisbecker
2011-08-06  6:48     ` Ingo Molnar
2011-08-06 14:56       ` Frederic Weisbecker
     [not found]         ` <CAKYOsXw+Q+h2D++LxAoCUJ3tFVEhczBgDWNjwXzuJ0mNDav_Rw@mail.gmail.com>
2011-08-06 15:18           ` Frederic Weisbecker
2011-08-06 15:35           ` Steven Rostedt
2011-08-06  1:01   ` Steven Rostedt
2011-08-06  6:51     ` Ingo Molnar
2011-08-08 21:30       ` Steven Rostedt
2011-08-06  9:14     ` Borislav Petkov
2011-08-06  0:07 ` David Ahern
2011-08-06  1:05   ` Steven Rostedt
2011-08-06 15:23 ` Colin Walters
     [not found] <CAGZ=bq+mJ-9pf0Y22b9LLey0Em2Y7SAA5FnQ5cPsde6GB_aqgw@mail.gmail.com>
2011-08-06 21:40 ` Steven Rostedt
2011-08-06 23:14   ` Kyle Moffett
2011-08-08  9:34   ` Américo Wang
2011-08-08 13:42     ` Steven Rostedt

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).