]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - tools/perf/util/trace-event-parse.c
perf tools: Handle arrays in print fields for trace parsing
[net-next-2.6.git] / tools / perf / util / trace-event-parse.c
index f6a8437141c8f464de406e1947d0a3c557716607..7aeedb09ea7d39a55feba7b254be961483cbf391 100644 (file)
@@ -522,7 +522,10 @@ static enum event_type __read_token(char **tok)
                        last_ch = ch;
                        ch = __read_char();
                        buf[i++] = ch;
-               } while (ch != quote_ch && last_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;
@@ -618,7 +621,7 @@ static int test_type(enum event_type type, enum event_type expect)
 }
 
 static int test_type_token(enum event_type type, char *token,
-                   enum event_type expect, char *expect_tok)
+                   enum event_type expect, const char *expect_tok)
 {
        if (type != expect) {
                die("Error: expected type %d but read %d",
@@ -650,7 +653,7 @@ 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, char *str, int newline_ok)
+static int __read_expected(enum event_type expect, const char *str, int newline_ok)
 {
        enum event_type type;
        char *token;
@@ -668,12 +671,12 @@ static int __read_expected(enum event_type expect, char *str, int newline_ok)
        return 0;
 }
 
-static int read_expected(enum event_type expect, char *str)
+static int read_expected(enum event_type expect, const char *str)
 {
        return __read_expected(expect, str, 1);
 }
 
-static int read_expected_item(enum event_type expect, char *str)
+static int read_expected_item(enum event_type expect, const char *str)
 {
        return __read_expected(expect, str, 0);
 }
@@ -721,6 +724,24 @@ static int event_read_id(void)
        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 (!strcmp(field->type, "__data_loc"))
+               return 1;
+
+       return 0;
+}
+
 static int event_read_fields(struct event *event, struct format_field **fields)
 {
        struct format_field *field = NULL;
@@ -865,6 +886,12 @@ static int event_read_fields(struct event *event, struct format_field **fields)
                        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, (char *)";"))
                        goto fail;
                free_token(token);
@@ -894,6 +921,21 @@ static int event_read_fields(struct event *event, struct format_field **fields)
                field->size = strtoul(token, NULL, 0);
                free_token(token);
 
+               if (read_expected(EVENT_OP, (char *)";") < 0)
+                       goto fail_expect;
+
+               if (read_expected(EVENT_ITEM, (char *)"signed") < 0)
+                       goto fail_expect;
+
+               if (read_expected(EVENT_OP, (char *)":") < 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, (char *)";") < 0)
                        goto fail_expect;
 
@@ -1004,6 +1046,35 @@ out_free:
        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, (char *)"]"))
+               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]) {
@@ -1128,6 +1199,8 @@ process_op(struct event *event, struct print_arg *arg, char **tok)
                   strcmp(token, "*") == 0 ||
                   strcmp(token, "^") == 0 ||
                   strcmp(token, "/") == 0 ||
+                  strcmp(token, "<") == 0 ||
+                  strcmp(token, ">") == 0 ||
                   strcmp(token, "==") == 0 ||
                   strcmp(token, "!=") == 0) {
 
@@ -1148,6 +1221,18 @@ process_op(struct event *event, struct print_arg *arg, char **tok)
 
                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 {
                die("unknown op '%s'", token);
                /* the arg is now the left side */
@@ -1695,6 +1780,7 @@ static int event_read_print(struct event *event)
        if (read_expect_type(EVENT_DQUOTE, &token) < 0)
                goto fail;
 
+ concat:
        event->print_fmt.format = token;
        event->print_fmt.args = NULL;
 
@@ -1704,6 +1790,21 @@ static int event_read_print(struct event *event)
        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, (char *)","))
                goto fail;
 
@@ -1871,6 +1972,7 @@ static unsigned long long eval_num_arg(void *data, int size,
 {
        unsigned long long val = 0;
        unsigned long long left, right;
+       struct print_arg *larg;
 
        switch (arg->type) {
        case PRINT_NULL:
@@ -1897,6 +1999,26 @@ static unsigned long long eval_num_arg(void *data, int size,
                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]) {
@@ -1968,10 +2090,11 @@ static const struct flag flags[] = {
        { "NET_TX_SOFTIRQ", 2 },
        { "NET_RX_SOFTIRQ", 3 },
        { "BLOCK_SOFTIRQ", 4 },
-       { "TASKLET_SOFTIRQ", 5 },
-       { "SCHED_SOFTIRQ", 6 },
-       { "HRTIMER_SOFTIRQ", 7 },
-       { "RCU_SOFTIRQ", 8 },
+       { "BLOCK_IOPOLL_SOFTIRQ", 5 },
+       { "TASKLET_SOFTIRQ", 6 },
+       { "SCHED_SOFTIRQ", 7 },
+       { "HRTIMER_SOFTIRQ", 8 },
+       { "RCU_SOFTIRQ", 9 },
 
        { "HRTIMER_NORESTART", 0 },
        { "HRTIMER_RESTART", 1 },
@@ -2269,7 +2392,27 @@ static void pretty_print(void *data, int size, struct event *event)
 
        for (; *ptr; ptr++) {
                ls = 0;
-               if (*ptr == '%') {
+               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:
@@ -2842,6 +2985,15 @@ static void parse_header_field(char *type,
                return;
        *size = atoi(token);
        free_token(token);
+       if (read_expected(EVENT_OP, (char *)";") < 0)
+               return;
+       if (read_expected(EVENT_ITEM, (char *)"signed") < 0)
+               return;
+       if (read_expected(EVENT_OP, (char *)":") < 0)
+               return;
+       if (read_expect_type(EVENT_ITEM, &token) < 0)
+               return;
+       free_token(token);
        if (read_expected(EVENT_OP, (char *)";") < 0)
                return;
        if (read_expect_type(EVENT_NEWLINE, &token) < 0)
@@ -2925,7 +3077,7 @@ int parse_ftrace_file(char *buf, unsigned long size)
        return 0;
 }
 
-int parse_event_file(char *buf, unsigned long size, char *system__unused __unused)
+int parse_event_file(char *buf, unsigned long size, char *sys)
 {
        struct event *event;
        int ret;
@@ -2952,6 +3104,8 @@ int parse_event_file(char *buf, unsigned long size, char *system__unused __unuse
        if (ret < 0)
                die("failed to read event print fmt");
 
+       event->system = strdup(sys);
+
 #define PRINT_ARGS 0
        if (PRINT_ARGS && event->print_fmt.args)
                print_args(event->print_fmt.args);