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