]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
perf: Separate out trace-cmd parse-events from perf files
authorSteven Rostedt <srostedt@redhat.com>
Thu, 5 Apr 2012 22:47:52 +0000 (00:47 +0200)
committerFrederic Weisbecker <fweisbec@gmail.com>
Wed, 25 Apr 2012 10:28:18 +0000 (12:28 +0200)
Move the trace-event-parse.c code that originally came from trace-cmd into
their own files. The new file will be called trace-parse-events.c, as
the name of trace-cmd's file was parse-events.c too, but it conflicted
with the parse-events.c file in perf that parses the command line.

This tries to update the code with mimimal changes.

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

Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Arnaldo Carvalho de Melo <acme@infradead.org>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Arun Sharma <asharma@fb.com>
Cc: Namhyung Kim <namhyung.kim@lge.com>
Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
tools/perf/Makefile
tools/perf/util/trace-event-parse.c
tools/perf/util/trace-event.h
tools/perf/util/trace-parse-events.c [new file with mode: 0644]
tools/perf/util/trace-parse-events.h [new file with mode: 0644]

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