From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752772Ab1HOQPK (ORCPT ); Mon, 15 Aug 2011 12:15:10 -0400 Received: from mail-gw0-f46.google.com ([74.125.83.46]:57474 "EHLO mail-gw0-f46.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750790Ab1HOQPI (ORCPT ); Mon, 15 Aug 2011 12:15:08 -0400 Message-ID: <4E4945F8.2080004@gmail.com> Date: Mon, 15 Aug 2011 10:14:48 -0600 From: David Ahern User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:5.0) Gecko/20110707 Thunderbird/5.0 MIME-Version: 1.0 To: Steven Rostedt CC: linux-kernel@vger.kernel.org, Ingo Molnar , Thomas Gleixner , Peter Zijlstra , Frederic Weisbecker , Arnaldo Carvalho de Melo , Borislav Petkov , Arjan van de Ven Subject: Re: [RFC][PATCH 1/8] perf: Separate out trace-cmd parse-events from perf files References: <20110805205921.909038487@goodmis.org> <20110805211300.324726820@goodmis.org> In-Reply-To: <20110805211300.324726820@goodmis.org> Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Hi Steve: On 08/05/2011 02:59 PM, Steven Rostedt wrote: > From: Steven Rostedt > > Move the trace-event-parse.c code that originally came from trace-cmd into > their own files. The new file will be called trace-parse-events.c, as > the name of trace-cmd's file was parse-events.c too, but it conflicted > with the parse-events.c file in perf that parses the command line. > > This tries to update the code with mimimal changes. > > Perf specific code stays in the trace-event-parse.[ch] files and > the common parsing code is now in trace-parse-events.c and > trace-parse-events.h. What branch should these apply cleanly to? David > > Signed-off-by: Steven Rostedt > --- > 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 > - * > - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ > - * > - * 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 > -#include > -#include > -#include > -#include > - > -#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 > #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 > + * > + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ > + * > + * 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 > +#include > +#include > +#include > +#include > + > +#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 > +#include > + > +#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 */