diff options
Diffstat (limited to 'src/event-parse.c')
-rw-r--r-- | src/event-parse.c | 896 |
1 files changed, 700 insertions, 196 deletions
diff --git a/src/event-parse.c b/src/event-parse.c index f862f49..e655087 100644 --- a/src/event-parse.c +++ b/src/event-parse.c @@ -28,10 +28,6 @@ #include "event-utils.h" #include "trace-seq.h" -static const char *input_buf; -static unsigned long long input_buf_ptr; -static unsigned long long input_buf_siz; - static int is_flag_field; static int is_symbolic_field; @@ -62,21 +58,22 @@ static int show_warning = 1; * * Initializes the internal buffer that tep_read_token() will parse. */ -__hidden void init_input_buf(const char *buf, unsigned long long size) +__hidden void init_input_buf(struct tep_handle *tep, const char *buf, + unsigned long long size) { - input_buf = buf; - input_buf_siz = size; - input_buf_ptr = 0; + tep->input_buf = buf; + tep->input_buf_siz = size; + tep->input_buf_ptr = 0; } -__hidden const char *get_input_buf(void) +__hidden const char *get_input_buf(struct tep_handle *tep) { - return input_buf; + return tep->input_buf; } -__hidden unsigned long long get_input_buf_ptr(void) +__hidden unsigned long long get_input_buf_ptr(struct tep_handle *tep) { - return input_buf_ptr; + return tep->input_buf_ptr; } struct event_handler { @@ -614,6 +611,43 @@ find_func(struct tep_handle *tep, unsigned long long addr) } /** + * tep_find_function_info - find a function by a given address + * @tep: a handle to the trace event parser context + * @addr: the address to find the function with + * @name: Return the name of the function (if found) + * @start: Return the start of the function (if found) + * @size: Return the size of the function (if found) + * + * Returns 1 if found, and 0 if it is not. + * If found then @name will point to the name of the function. + * @start: will contain the starting address of the function. + * @size: will contain the size of the function. + */ +int tep_find_function_info(struct tep_handle *tep, unsigned long long addr, + const char **name, unsigned long long *start, + unsigned long *size) +{ + struct func_map *map; + + map = find_func(tep, addr); + if (!map) + return 0; + + if (name) + *name = map->func; + if (start) + *start = map->addr; + if (size) { + if (!tep->func_resolver) + *size = map[1].addr - map->addr; + else + *size = 0; + } + + return 1; +} + +/** * tep_find_function - find a function by a given address * @tep: a handle to the trace event parser context * @addr: the address to find the function with @@ -739,8 +773,11 @@ int tep_parse_kallsyms(struct tep_handle *tep, const char *kallsyms) if (errno) goto out; - if (n != 2 || !func_end) + if (n != 2 || !func_end) { + tep_warning("Failed to parse kallsyms n=%d func_end=%d", + n, func_end); goto out; + } func = line + func_start; /* @@ -1080,6 +1117,7 @@ static void free_arg(struct tep_print_arg *arg) free(arg->string.string); break; case TEP_PRINT_BITMASK: + case TEP_PRINT_CPUMASK: free(arg->bitmask.bitmask); break; case TEP_PRINT_DYNAMIC_ARRAY: @@ -1127,12 +1165,12 @@ static enum tep_event_type get_type(int ch) return TEP_EVENT_OP; } -static int __read_char(void) +static int __read_char(struct tep_handle *tep) { - if (input_buf_ptr >= input_buf_siz) + if (tep->input_buf_ptr >= tep->input_buf_siz) return -1; - return input_buf[input_buf_ptr++]; + return tep->input_buf[tep->input_buf_ptr++]; } /** @@ -1140,12 +1178,12 @@ static int __read_char(void) * * Returns the next character read, or -1 if end of buffer. */ -__hidden int peek_char(void) +__hidden int peek_char(struct tep_handle *tep) { - if (input_buf_ptr >= input_buf_siz) + if (tep->input_buf_ptr >= tep->input_buf_siz) return -1; - return input_buf[input_buf_ptr]; + return tep->input_buf[tep->input_buf_ptr]; } static int extend_token(char **tok, char *buf, int size) @@ -1167,9 +1205,10 @@ static int extend_token(char **tok, char *buf, int size) return 0; } -static enum tep_event_type force_token(const char *str, char **tok); +static enum tep_event_type force_token(struct tep_handle *tep, const char *str, + char **tok); -static enum tep_event_type __read_token(char **tok) +static enum tep_event_type __read_token(struct tep_handle *tep, char **tok) { char buf[BUFSIZ]; int ch, last_ch, quote_ch, next_ch; @@ -1180,7 +1219,7 @@ static enum tep_event_type __read_token(char **tok) *tok = NULL; - ch = __read_char(); + ch = __read_char(tep); if (ch < 0) return TEP_EVENT_NONE; @@ -1201,9 +1240,9 @@ static enum tep_event_type __read_token(char **tok) case TEP_EVENT_OP: switch (ch) { case '-': - next_ch = peek_char(); + next_ch = peek_char(tep); if (next_ch == '>') { - buf[i++] = __read_char(); + buf[i++] = __read_char(tep); break; } /* fall through */ @@ -1213,10 +1252,10 @@ static enum tep_event_type __read_token(char **tok) case '>': case '<': last_ch = ch; - ch = peek_char(); + ch = peek_char(tep); if (ch != last_ch) goto test_equal; - buf[i++] = __read_char(); + buf[i++] = __read_char(tep); switch (last_ch) { case '>': case '<': @@ -1236,9 +1275,9 @@ static enum tep_event_type __read_token(char **tok) return type; test_equal: - ch = peek_char(); + ch = peek_char(tep); if (ch == '=') - buf[i++] = __read_char(); + buf[i++] = __read_char(tep); goto out; case TEP_EVENT_DQUOTE: @@ -1258,29 +1297,34 @@ static enum tep_event_type __read_token(char **tok) i = 0; } last_ch = ch; - ch = __read_char(); + ch = __read_char(tep); buf[i++] = ch; /* the '\' '\' will cancel itself */ if (ch == '\\' && last_ch == '\\') last_ch = 0; /* Break out if the file is corrupted and giving non print chars */ + if (ch <= 0) + break; } while ((ch != quote_ch && isprint(ch)) || last_ch == '\\' || ch == '\n'); /* remove the last quote */ i--; + if (ch <= 0) + type = TEP_EVENT_NONE; + /* * For strings (double quotes) check the next token. * If it is another string, concatinate the two. */ if (type == TEP_EVENT_DQUOTE) { - unsigned long long save_input_buf_ptr = input_buf_ptr; + unsigned long long save_input_buf_ptr = tep->input_buf_ptr; do { - ch = __read_char(); + ch = __read_char(tep); } while (isspace(ch)); if (ch == '"') goto concat; - input_buf_ptr = save_input_buf_ptr; + tep->input_buf_ptr = save_input_buf_ptr; } goto out; @@ -1291,7 +1335,7 @@ static enum tep_event_type __read_token(char **tok) break; } - while (get_type(peek_char()) == type) { + while (get_type(peek_char(tep)) == type) { if (i == (BUFSIZ - 1)) { buf[i] = 0; tok_size += BUFSIZ; @@ -1300,7 +1344,7 @@ static enum tep_event_type __read_token(char **tok) return TEP_EVENT_NONE; i = 0; } - ch = __read_char(); + ch = __read_char(tep); buf[i++] = ch; } @@ -1321,22 +1365,23 @@ static enum tep_event_type __read_token(char **tok) if (strcmp(*tok, "LOCAL_PR_FMT") == 0) { free(*tok); *tok = NULL; - return force_token("\"%s\" ", tok); + return force_token(tep, "\"%s\" ", tok); } else if (strcmp(*tok, "STA_PR_FMT") == 0) { free(*tok); *tok = NULL; - return force_token("\" sta:%pM\" ", tok); + return force_token(tep, "\" sta:%pM\" ", tok); } else if (strcmp(*tok, "VIF_PR_FMT") == 0) { free(*tok); *tok = NULL; - return force_token("\" vif:%p(%d)\" ", tok); + return force_token(tep, "\" vif:%p(%d)\" ", tok); } } return type; } -static enum tep_event_type force_token(const char *str, char **tok) +static enum tep_event_type force_token(struct tep_handle *tep, const char *str, + char **tok) { const char *save_input_buf; unsigned long long save_input_buf_ptr; @@ -1344,18 +1389,18 @@ static enum tep_event_type force_token(const char *str, char **tok) enum tep_event_type type; /* save off the current input pointers */ - save_input_buf = input_buf; - save_input_buf_ptr = input_buf_ptr; - save_input_buf_siz = input_buf_siz; + save_input_buf = tep->input_buf; + save_input_buf_ptr = tep->input_buf_ptr; + save_input_buf_siz = tep->input_buf_siz; - init_input_buf(str, strlen(str)); + init_input_buf(tep, str, strlen(str)); - type = __read_token(tok); + type = __read_token(tep, tok); /* reset back to original token */ - input_buf = save_input_buf; - input_buf_ptr = save_input_buf_ptr; - input_buf_siz = save_input_buf_siz; + tep->input_buf = save_input_buf; + tep->input_buf_ptr = save_input_buf_ptr; + tep->input_buf_siz = save_input_buf_siz; return type; } @@ -1379,12 +1424,12 @@ __hidden void free_token(char *tok) * * Returns the token type. */ -__hidden enum tep_event_type read_token(char **tok) +__hidden enum tep_event_type read_token(struct tep_handle *tep, char **tok) { enum tep_event_type type; for (;;) { - type = __read_token(tok); + type = __read_token(tep, tok); if (type != TEP_EVENT_SPACE) return type; @@ -1397,12 +1442,12 @@ __hidden enum tep_event_type read_token(char **tok) } /* no newline */ -static enum tep_event_type read_token_item(char **tok) +static enum tep_event_type read_token_item(struct tep_handle *tep, char **tok) { enum tep_event_type type; for (;;) { - type = __read_token(tok); + type = __read_token(tep, tok); if (type != TEP_EVENT_SPACE && type != TEP_EVENT_NEWLINE) return type; free_token(*tok); @@ -1443,33 +1488,35 @@ static int test_type_token(enum tep_event_type type, const char *token, return 0; } -static int __read_expect_type(enum tep_event_type expect, char **tok, int newline_ok) +static int __read_expect_type(struct tep_handle *tep, enum tep_event_type expect, + char **tok, int newline_ok) { enum tep_event_type type; if (newline_ok) - type = read_token(tok); + type = read_token(tep, tok); else - type = read_token_item(tok); + type = read_token_item(tep, tok); return test_type(type, expect); } -static int read_expect_type(enum tep_event_type expect, char **tok) +static int read_expect_type(struct tep_handle *tep, enum tep_event_type expect, + char **tok) { - return __read_expect_type(expect, tok, 1); + return __read_expect_type(tep, expect, tok, 1); } -static int __read_expected(enum tep_event_type expect, const char *str, - int newline_ok) +static int __read_expected(struct tep_handle *tep, enum tep_event_type expect, + const char *str, int newline_ok) { enum tep_event_type type; char *token; int ret; if (newline_ok) - type = read_token(&token); + type = read_token(tep, &token); else - type = read_token_item(&token); + type = read_token_item(tep, &token); ret = test_type_token(type, token, expect, str); @@ -1478,27 +1525,29 @@ static int __read_expected(enum tep_event_type expect, const char *str, return ret; } -static int read_expected(enum tep_event_type expect, const char *str) +static int read_expected(struct tep_handle *tep, enum tep_event_type expect, + const char *str) { - return __read_expected(expect, str, 1); + return __read_expected(tep, expect, str, 1); } -static int read_expected_item(enum tep_event_type expect, const char *str) +static int read_expected_item(struct tep_handle *tep, enum tep_event_type expect, + const char *str) { - return __read_expected(expect, str, 0); + return __read_expected(tep, expect, str, 0); } -static char *event_read_name(void) +static char *event_read_name(struct tep_handle *tep) { char *token; - if (read_expected(TEP_EVENT_ITEM, "name") < 0) + if (read_expected(tep, TEP_EVENT_ITEM, "name") < 0) return NULL; - if (read_expected(TEP_EVENT_OP, ":") < 0) + if (read_expected(tep, TEP_EVENT_OP, ":") < 0) return NULL; - if (read_expect_type(TEP_EVENT_ITEM, &token) < 0) + if (read_expect_type(tep, TEP_EVENT_ITEM, &token) < 0) goto fail; return token; @@ -1508,18 +1557,18 @@ static char *event_read_name(void) return NULL; } -static int event_read_id(void) +static int event_read_id(struct tep_handle *tep) { char *token; int id; - if (read_expected_item(TEP_EVENT_ITEM, "ID") < 0) + if (read_expected_item(tep, TEP_EVENT_ITEM, "ID") < 0) return -1; - if (read_expected(TEP_EVENT_OP, ":") < 0) + if (read_expected(tep, TEP_EVENT_OP, ":") < 0) return -1; - if (read_expect_type(TEP_EVENT_ITEM, &token) < 0) + if (read_expect_type(tep, TEP_EVENT_ITEM, &token) < 0) goto fail; id = strtoul(token, NULL, 0); @@ -1607,7 +1656,8 @@ static int append(char **buf, const char *delim, const char *str) return 0; } -static int event_read_fields(struct tep_event *event, struct tep_format_field **fields) +static int event_read_fields(struct tep_handle *tep, struct tep_event *event, + struct tep_format_field **fields) { struct tep_format_field *field = NULL; enum tep_event_type type; @@ -1620,7 +1670,7 @@ static int event_read_fields(struct tep_event *event, struct tep_format_field ** do { unsigned int size_dynamic = 0; - type = read_token(&token); + type = read_token(tep, &token); if (type == TEP_EVENT_NEWLINE) { free_token(token); return count; @@ -1632,7 +1682,7 @@ static int event_read_fields(struct tep_event *event, struct tep_format_field ** goto fail; free_token(token); - type = read_token(&token); + type = read_token(tep, &token); /* * The ftrace fields may still use the "special" name. * Just ignore it. @@ -1640,14 +1690,14 @@ static int event_read_fields(struct tep_event *event, struct tep_format_field ** if (event->flags & TEP_EVENT_FL_ISFTRACE && type == TEP_EVENT_ITEM && strcmp(token, "special") == 0) { free_token(token); - type = read_token(&token); + type = read_token(tep, &token); } if (test_type_token(type, token, TEP_EVENT_OP, ":") < 0) goto fail; free_token(token); - if (read_expect_type(TEP_EVENT_ITEM, &token) < 0) + if (read_expect_type(tep, TEP_EVENT_ITEM, &token) < 0) goto fail; last_token = token; @@ -1660,7 +1710,7 @@ static int event_read_fields(struct tep_event *event, struct tep_format_field ** /* read the rest of the type */ for (;;) { - type = read_token(&token); + type = read_token(tep, &token); if (type == TEP_EVENT_ITEM || (type == TEP_EVENT_OP && strcmp(token, "*") == 0) || /* @@ -1698,7 +1748,7 @@ static int event_read_fields(struct tep_event *event, struct tep_format_field ** goto fail; delim = " "; - while ((type = read_token(&token)) != TEP_EVENT_NONE) { + while ((type = read_token(tep, &token)) != TEP_EVENT_NONE) { if (type == TEP_EVENT_DELIM) { if (token[0] == '(') depth++; @@ -1737,7 +1787,7 @@ static int event_read_fields(struct tep_event *event, struct tep_format_field ** field->flags |= TEP_FIELD_IS_ARRAY; - type = read_token(&token); + type = read_token(tep, &token); if (type == TEP_EVENT_ITEM) field->arraylen = strtoul(token, NULL, 0); @@ -1763,7 +1813,7 @@ static int event_read_fields(struct tep_event *event, struct tep_format_field ** /* We only care about the last token */ field->arraylen = strtoul(token, NULL, 0); free_token(token); - type = read_token(&token); + type = read_token(tep, &token); if (type == TEP_EVENT_NONE) { free(brackets); do_warning_event(event, "failed to find token"); @@ -1776,12 +1826,12 @@ static int event_read_fields(struct tep_event *event, struct tep_format_field ** ret = append(&brackets, "", "]"); if (ret < 0) { free(brackets); - goto fail; + goto fail_expect; } /* add brackets to type */ - type = read_token(&token); + type = read_token(tep, &token); /* * If the next token is not an OP, then it is of * the format: type [] item; @@ -1797,7 +1847,7 @@ static int event_read_fields(struct tep_event *event, struct tep_format_field ** size_dynamic = type_size(field->name); free_token(field->name); field->name = field->alias = token; - type = read_token(&token); + type = read_token(tep, &token); } else { ret = append(&field->type, "", brackets); if (ret < 0) { @@ -1821,27 +1871,27 @@ static int event_read_fields(struct tep_event *event, struct tep_format_field ** goto fail; free_token(token); - if (read_expected(TEP_EVENT_ITEM, "offset") < 0) + if (read_expected(tep, TEP_EVENT_ITEM, "offset") < 0) goto fail_expect; - if (read_expected(TEP_EVENT_OP, ":") < 0) + if (read_expected(tep, TEP_EVENT_OP, ":") < 0) goto fail_expect; - if (read_expect_type(TEP_EVENT_ITEM, &token)) + if (read_expect_type(tep, TEP_EVENT_ITEM, &token)) goto fail; field->offset = strtoul(token, NULL, 0); free_token(token); - if (read_expected(TEP_EVENT_OP, ";") < 0) + if (read_expected(tep, TEP_EVENT_OP, ";") < 0) goto fail_expect; - if (read_expected(TEP_EVENT_ITEM, "size") < 0) + if (read_expected(tep, TEP_EVENT_ITEM, "size") < 0) goto fail_expect; - if (read_expected(TEP_EVENT_OP, ":") < 0) + if (read_expected(tep, TEP_EVENT_OP, ":") < 0) goto fail_expect; - if (read_expect_type(TEP_EVENT_ITEM, &token)) + if (read_expect_type(tep, TEP_EVENT_ITEM, &token)) goto fail; field->size = strtoul(token, NULL, 0); free_token(token); @@ -1856,10 +1906,10 @@ static int event_read_fields(struct tep_event *event, struct tep_format_field ** if ((field->flags & TEP_FIELD_IS_DYNAMIC) && field->size == 2) field->flags |= TEP_FIELD_IS_STRING | TEP_FIELD_IS_ARRAY; - if (read_expected(TEP_EVENT_OP, ";") < 0) + if (read_expected(tep, TEP_EVENT_OP, ";") < 0) goto fail_expect; - type = read_token(&token); + type = read_token(tep, &token); if (type != TEP_EVENT_NEWLINE) { /* newer versions of the kernel have a "signed" type */ if (test_type_token(type, token, TEP_EVENT_ITEM, "signed")) @@ -1867,26 +1917,26 @@ static int event_read_fields(struct tep_event *event, struct tep_format_field ** free_token(token); - if (read_expected(TEP_EVENT_OP, ":") < 0) + if (read_expected(tep, TEP_EVENT_OP, ":") < 0) goto fail_expect; - if (read_expect_type(TEP_EVENT_ITEM, &token)) + if (read_expect_type(tep, TEP_EVENT_ITEM, &token)) goto fail; if (strtoul(token, NULL, 0)) field->flags |= TEP_FIELD_IS_SIGNED; free_token(token); - if (read_expected(TEP_EVENT_OP, ";") < 0) + if (read_expected(tep, TEP_EVENT_OP, ";") < 0) goto fail_expect; - if (read_expect_type(TEP_EVENT_NEWLINE, &token)) + if (read_expect_type(tep, TEP_EVENT_NEWLINE, &token)) goto fail; } free_token(token); - if (field->flags & TEP_FIELD_IS_ARRAY) { + if (field->flags & (TEP_FIELD_IS_ARRAY | TEP_FIELD_IS_DYNAMIC)) { if (field->arraylen) field->elementsize = field->size / field->arraylen; else if (field->flags & TEP_FIELD_IS_DYNAMIC) @@ -1902,6 +1952,7 @@ static int event_read_fields(struct tep_event *event, struct tep_format_field ** *fields = field; fields = &field->next; + field = NULL; } while (1); @@ -1923,22 +1974,22 @@ static int event_read_format(struct tep_event *event) char *token; int ret; - if (read_expected_item(TEP_EVENT_ITEM, "format") < 0) + if (read_expected_item(event->tep, TEP_EVENT_ITEM, "format") < 0) return -1; - if (read_expected(TEP_EVENT_OP, ":") < 0) + if (read_expected(event->tep, TEP_EVENT_OP, ":") < 0) return -1; - if (read_expect_type(TEP_EVENT_NEWLINE, &token)) + if (read_expect_type(event->tep, TEP_EVENT_NEWLINE, &token)) goto fail; free_token(token); - ret = event_read_fields(event, &event->format.common_fields); + ret = event_read_fields(event->tep, event, &event->format.common_fields); if (ret < 0) return ret; event->format.nr_common = ret; - ret = event_read_fields(event, &event->format.fields); + ret = event_read_fields(event->tep, event, &event->format.fields); if (ret < 0) return ret; event->format.nr_fields = ret; @@ -1960,7 +2011,7 @@ process_arg(struct tep_event *event, struct tep_print_arg *arg, char **tok) enum tep_event_type type; char *token; - type = read_token(&token); + type = read_token(event->tep, &token); *tok = token; return process_arg_token(event, arg, tok, type); @@ -2066,7 +2117,7 @@ process_array(struct tep_event *event, struct tep_print_arg *top, char **tok) top->op.right = arg; free_token(token); - type = read_token_item(&token); + type = read_token_item(event->tep, &token); *tok = token; return type; @@ -2144,6 +2195,120 @@ static int set_op_prio(struct tep_print_arg *arg) return arg->op.prio; } +static int consolidate_op_arg(struct tep_print_arg *arg) +{ + unsigned long long val, left, right; + int ret = 0; + + if (arg->type != TEP_PRINT_OP) + return 0; + + if (arg->op.left) + ret = consolidate_op_arg(arg->op.left); + if (ret < 0) + return ret; + + if (arg->op.right) + ret = consolidate_op_arg(arg->op.right); + if (ret < 0) + return ret; + + if (!arg->op.left || !arg->op.right) + return 0; + + if (arg->op.left->type != TEP_PRINT_ATOM || + arg->op.right->type != TEP_PRINT_ATOM) + return 0; + + /* Two atoms, we can do the operation now. */ + left = strtoull(arg->op.left->atom.atom, NULL, 0); + right = strtoull(arg->op.right->atom.atom, NULL, 0); + + switch (arg->op.op[0]) { + case '>': + switch (arg->op.op[1]) { + case '>': + val = left >> right; + break; + case '=': + val = left >= right; + break; + default: + val = left > right; + break; + } + break; + case '<': + switch (arg->op.op[1]) { + case '<': + val = left << right; + break; + case '=': + val = left <= right; + break; + default: + val = left < right; + break; + } + break; + case '&': + switch (arg->op.op[1]) { + case '&': + val = left && right; + break; + default: + val = left & right; + break; + } + break; + case '|': + switch (arg->op.op[1]) { + case '|': + val = left || right; + break; + default: + val = left | right; + break; + } + break; + case '-': + val = left - right; + break; + case '+': + val = left + right; + break; + case '*': + val = left * right; + break; + case '^': + val = left ^ right; + break; + case '/': + val = left / right; + break; + case '%': + val = left % right; + break; + case '=': + /* Only '==' is called here */ + val = left == right; + break; + case '!': + /* Only '!=' is called here. */ + val = left != right; + break; + default: + return 0; + } + + free_arg(arg->op.left); + free_arg(arg->op.right); + + arg->type = TEP_PRINT_ATOM; + free(arg->op.op); + return asprintf(&arg->atom.atom, "%lld", val) < 0 ? -1 : 0; +} + /* Note, *tok does not get freed, but will most likely be saved */ static enum tep_event_type process_op(struct tep_event *event, struct tep_print_arg *arg, char **tok) @@ -2203,6 +2368,7 @@ process_op(struct tep_event *event, struct tep_print_arg *arg, char **tok) arg->type = TEP_PRINT_OP; arg->op.op = token; arg->op.left = left; + arg->op.right = NULL; arg->op.prio = 0; /* it will set arg->op.right */ @@ -2246,7 +2412,7 @@ process_op(struct tep_event *event, struct tep_print_arg *arg, char **tok) goto out_free; } - type = read_token_item(&token); + type = read_token_item(event->tep, &token); *tok = token; /* could just be a type pointer */ @@ -2308,6 +2474,7 @@ process_op(struct tep_event *event, struct tep_print_arg *arg, char **tok) arg->type = TEP_PRINT_OP; arg->op.op = token; arg->op.left = left; + arg->op.right = NULL; arg->op.prio = 0; @@ -2351,7 +2518,7 @@ process_entry(struct tep_event *event __maybe_unused, struct tep_print_arg *arg, char *field; char *token; - type = read_token_item(&token); + type = read_token_item(event->tep, &token); /* * Check if REC happens to be surrounded by parenthesis, and * return if that's the case, as "(REC)->" is valid. @@ -2367,7 +2534,7 @@ process_entry(struct tep_event *event __maybe_unused, struct tep_print_arg *arg, free_token(token); - if (read_expect_type(TEP_EVENT_ITEM, &token) < 0) + if (read_expect_type(event->tep, TEP_EVENT_ITEM, &token) < 0) goto out_free; field = token; @@ -2384,7 +2551,7 @@ process_entry(struct tep_event *event __maybe_unused, struct tep_print_arg *arg, is_symbolic_field = 0; } - type = read_token(&token); + type = read_token(event->tep, &token); *tok = token; return type; @@ -2412,19 +2579,31 @@ static int alloc_and_process_delim(struct tep_event *event, char *next_token, type = process_arg(event, field, &token); - if (test_type_token(type, token, TEP_EVENT_DELIM, next_token)) { - errno = EINVAL; - ret = -1; - free_arg(field); - goto out_free_token; + /* We do allow operators */ + if (type == TEP_EVENT_OP) { + type = process_op(event, field, &token); + + if (consolidate_op_arg(field) < 0) + type = TEP_EVENT_ERROR; + + if (type == TEP_EVENT_ERROR) + goto out_error; } + if (test_type_token(type, token, TEP_EVENT_DELIM, next_token)) + goto out_error; + *print_arg = field; out_free_token: free_token(token); return ret; +out_error: + errno = EINVAL; + ret = -1; + free_arg(field); + goto out_free_token; } static char *arg_eval (struct tep_print_arg *arg); @@ -2437,6 +2616,10 @@ eval_type_str(unsigned long long val, const char *type, int pointer) int len; len = strlen(type); + if (len < 2) { + do_warning("invalid type: %s", type); + return val; + } if (pointer) { @@ -2692,6 +2875,7 @@ static int arg_num_eval(struct tep_print_arg *arg, long long *val) case TEP_PRINT_STRING: case TEP_PRINT_BSTRING: case TEP_PRINT_BITMASK: + case TEP_PRINT_CPUMASK: default: do_warning("invalid eval type %d", arg->type); ret = 0; @@ -2721,6 +2905,7 @@ static char *arg_eval (struct tep_print_arg *arg) case TEP_PRINT_STRING: case TEP_PRINT_BSTRING: case TEP_PRINT_BITMASK: + case TEP_PRINT_CPUMASK: default: do_warning("invalid eval type %d", arg->type); break; @@ -2740,7 +2925,7 @@ process_fields(struct tep_event *event, struct tep_print_flag_sym **list, char * do { free_token(token); - type = read_token_item(&token); + type = read_token_item(event->tep, &token); if (test_type_token(type, token, TEP_EVENT_OP, "{")) break; @@ -2794,7 +2979,7 @@ process_fields(struct tep_event *event, struct tep_print_flag_sym **list, char * list = &field->next; free_token(token); - type = read_token_item(&token); + type = read_token_item(event->tep, &token); } while (type == TEP_EVENT_DELIM && strcmp(token, ",") == 0); *tok = token; @@ -2838,10 +3023,10 @@ process_flags(struct tep_event *event, struct tep_print_arg *arg, char **tok) arg->flags.field = field; - type = read_token_item(&token); + type = read_token_item(event->tep, &token); if (event_item_type(type)) { arg->flags.delim = token; - type = read_token_item(&token); + type = read_token_item(event->tep, &token); } if (test_type_token(type, token, TEP_EVENT_DELIM, ",")) @@ -2852,7 +3037,7 @@ process_flags(struct tep_event *event, struct tep_print_arg *arg, char **tok) goto out_free; free_token(token); - type = read_token_item(tok); + type = read_token_item(event->tep, tok); return type; out_free_field: @@ -2891,7 +3076,7 @@ process_symbols(struct tep_event *event, struct tep_print_arg *arg, char **tok) goto out_free; free_token(token); - type = read_token_item(tok); + type = read_token_item(event->tep, tok); return type; out_free_field: @@ -2915,7 +3100,7 @@ process_hex_common(struct tep_event *event, struct tep_print_arg *arg, if (alloc_and_process_delim(event, ")", &arg->hex.size)) goto free_field; - return read_token_item(tok); + return read_token_item(event->tep, tok); free_field: free_arg(arg->hex.field); @@ -2953,7 +3138,7 @@ process_int_array(struct tep_event *event, struct tep_print_arg *arg, char **tok if (alloc_and_process_delim(event, ")", &arg->int_array.el_size)) goto free_size; - return read_token_item(tok); + return read_token_item(event->tep, tok); free_size: free_arg(arg->int_array.count); @@ -2980,7 +3165,7 @@ process_dynamic_array(struct tep_event *event, struct tep_print_arg *arg, char * * The item within the parenthesis is another field that holds * the index into where the array starts. */ - type = read_token(&token); + type = read_token(event->tep, &token); *tok = token; if (type != TEP_EVENT_ITEM) goto out_free; @@ -2994,11 +3179,11 @@ process_dynamic_array(struct tep_event *event, struct tep_print_arg *arg, char * arg->dynarray.field = field; arg->dynarray.index = 0; - if (read_expected(TEP_EVENT_DELIM, ")") < 0) + if (read_expected(event->tep, TEP_EVENT_DELIM, ")") < 0) goto out_free; free_token(token); - type = read_token_item(&token); + type = read_token_item(event->tep, &token); *tok = token; if (type != TEP_EVENT_OP || strcmp(token, "[") != 0) return type; @@ -3019,7 +3204,7 @@ process_dynamic_array(struct tep_event *event, struct tep_print_arg *arg, char * goto out_free_arg; free_token(token); - type = read_token_item(tok); + type = read_token_item(event->tep, tok); return type; out_free_arg: @@ -3038,7 +3223,7 @@ process_dynamic_array_len(struct tep_event *event, struct tep_print_arg *arg, enum tep_event_type type; char *token; - if (read_expect_type(TEP_EVENT_ITEM, &token) < 0) + if (read_expect_type(event->tep, TEP_EVENT_ITEM, &token) < 0) goto out_free; arg->type = TEP_PRINT_DYNAMIC_ARRAY_LEN; @@ -3051,11 +3236,11 @@ process_dynamic_array_len(struct tep_event *event, struct tep_print_arg *arg, arg->dynarray.field = field; arg->dynarray.index = 0; - if (read_expected(TEP_EVENT_DELIM, ")") < 0) + if (read_expected(event->tep, TEP_EVENT_DELIM, ")") < 0) goto out_err; free_token(token); - type = read_token(&token); + type = read_token(event->tep, &token); *tok = token; return type; @@ -3100,7 +3285,7 @@ process_paren(struct tep_event *event, struct tep_print_arg *arg, char **tok) goto out_free; free_token(token); - type = read_token_item(&token); + type = read_token_item(event->tep, &token); /* * If the next token is an item or another open paren, then @@ -3142,13 +3327,12 @@ process_paren(struct tep_event *event, struct tep_print_arg *arg, char **tok) static enum tep_event_type -process_str(struct tep_event *event __maybe_unused, struct tep_print_arg *arg, - char **tok) +process_str(struct tep_event *event, struct tep_print_arg *arg, char **tok) { enum tep_event_type type; char *token; - if (read_expect_type(TEP_EVENT_ITEM, &token) < 0) + if (read_expect_type(event->tep, TEP_EVENT_ITEM, &token) < 0) goto out_free; arg->type = TEP_PRINT_STRING; @@ -3156,10 +3340,10 @@ process_str(struct tep_event *event __maybe_unused, struct tep_print_arg *arg, arg->string.offset = -1; arg->string.field = NULL; - if (read_expected(TEP_EVENT_DELIM, ")") < 0) + if (read_expected(event->tep, TEP_EVENT_DELIM, ")") < 0) goto out_err; - type = read_token(&token); + type = read_token(event->tep, &token); *tok = token; return type; @@ -3172,13 +3356,12 @@ process_str(struct tep_event *event __maybe_unused, struct tep_print_arg *arg, } static enum tep_event_type -process_bitmask(struct tep_event *event __maybe_unused, struct tep_print_arg *arg, - char **tok) +process_bitmask(struct tep_event *event, struct tep_print_arg *arg, char **tok) { enum tep_event_type type; char *token; - if (read_expect_type(TEP_EVENT_ITEM, &token) < 0) + if (read_expect_type(event->tep, TEP_EVENT_ITEM, &token) < 0) goto out_free; arg->type = TEP_PRINT_BITMASK; @@ -3186,10 +3369,10 @@ process_bitmask(struct tep_event *event __maybe_unused, struct tep_print_arg *ar arg->bitmask.offset = -1; arg->bitmask.field = NULL; - if (read_expected(TEP_EVENT_DELIM, ")") < 0) + if (read_expected(event->tep, TEP_EVENT_DELIM, ")") < 0) goto out_err; - type = read_token(&token); + type = read_token(event->tep, &token); *tok = token; return type; @@ -3201,6 +3384,17 @@ process_bitmask(struct tep_event *event __maybe_unused, struct tep_print_arg *ar return TEP_EVENT_ERROR; } +static enum tep_event_type +process_cpumask(struct tep_event *event __maybe_unused, struct tep_print_arg *arg, + char **tok) +{ + enum tep_event_type type = process_bitmask(event, arg, tok); + if (type != TEP_EVENT_ERROR) + arg->type = TEP_PRINT_CPUMASK; + + return type; +} + static struct tep_function_handler * find_func_handler(struct tep_handle *tep, char *func_name) { @@ -3280,7 +3474,7 @@ process_func_handler(struct tep_event *event, struct tep_function_handler *func, free_token(token); } - type = read_token(&token); + type = read_token(event->tep, &token); *tok = token; return type; @@ -3306,14 +3500,14 @@ process_builtin_expect(struct tep_event *event, struct tep_print_arg *arg, char free_token(token); /* We don't care what the second parameter is of the __builtin_expect() */ - if (read_expect_type(TEP_EVENT_ITEM, &token) < 0) + if (read_expect_type(event->tep, TEP_EVENT_ITEM, &token) < 0) goto out_free; - if (read_expected(TEP_EVENT_DELIM, ")") < 0) + if (read_expected(event->tep, TEP_EVENT_DELIM, ")") < 0) goto out_free; free_token(token); - type = read_token_item(tok); + type = read_token_item(event->tep, tok); return type; out_free: @@ -3323,6 +3517,95 @@ out_free: } static enum tep_event_type +process_sizeof(struct tep_event *event, struct tep_print_arg *arg, char **tok) +{ + struct tep_format_field *field; + enum tep_event_type type; + char *token = NULL; + bool ok = false; + int ret; + + type = read_token_item(event->tep, &token); + + arg->type = TEP_PRINT_ATOM; + + /* We handle some sizeof types */ + if (strcmp(token, "unsigned") == 0) { + free_token(token); + type = read_token_item(event->tep, &token); + + if (type == TEP_EVENT_ERROR) + goto error; + + if (type != TEP_EVENT_ITEM) + ok = true; + } + + if (ok || strcmp(token, "int") == 0) { + arg->atom.atom = strdup("4"); + + } else if (strcmp(token, "long") == 0) { + free_token(token); + type = read_token_item(event->tep, &token); + + if (token && strcmp(token, "long") == 0) { + arg->atom.atom = strdup("8"); + } else { + switch (event->tep->long_size) { + case 4: + arg->atom.atom = strdup("4"); + break; + case 8: + arg->atom.atom = strdup("8"); + break; + default: + /* long size not defined yet, fail to parse it */ + goto error; + } + /* The token is the next token */ + ok = true; + } + } else if (strcmp(token, "REC") == 0) { + + free_token(token); + type = read_token_item(event->tep, &token); + + if (test_type_token(type, token, TEP_EVENT_OP, "->")) + goto error; + free_token(token); + + if (read_expect_type(event->tep, TEP_EVENT_ITEM, &token) < 0) + goto error; + + field = tep_find_any_field(event, token); + /* Can't handle arrays (yet) */ + if (!field || field->flags & TEP_FIELD_IS_ARRAY) + goto error; + + ret = asprintf(&arg->atom.atom, "%d", field->size); + if (ret < 0) + goto error; + + } else if (!ok) { + goto error; + } + + if (!ok) { + free_token(token); + type = read_token_item(event->tep, tok); + } + if (test_type_token(type, token, TEP_EVENT_DELIM, ")")) + goto error; + + free_token(token); + return read_token_item(event->tep, tok); +error: + free_token(token); + *tok = NULL; + return TEP_EVENT_ERROR; +} + +static enum tep_event_type process_function(struct tep_event *event, struct tep_print_arg *arg, char *token, char **tok) { @@ -3360,8 +3643,15 @@ process_function(struct tep_event *event, struct tep_print_arg *arg, free_token(token); return process_bitmask(event, arg, tok); } + if (strcmp(token, "__get_cpumask") == 0 || + strcmp(token, "__get_rel_cpumask") == 0) { + free_token(token); + return process_cpumask(event, arg, tok); + } if (strcmp(token, "__get_dynamic_array") == 0 || - strcmp(token, "__get_rel_dynamic_array") == 0) { + strcmp(token, "__get_rel_dynamic_array") == 0 || + strcmp(token, "__get_sockaddr") == 0 || + strcmp(token, "__get_sockaddr_rel") == 0) { free_token(token); return process_dynamic_array(event, arg, tok); } @@ -3374,6 +3664,10 @@ process_function(struct tep_event *event, struct tep_print_arg *arg, free_token(token); return process_builtin_expect(event, arg, tok); } + if (strcmp(token, "sizeof") == 0) { + free_token(token); + return process_sizeof(event, arg, tok); + } func = find_func_handler(event->tep, token); if (func) { @@ -3404,7 +3698,7 @@ process_arg_token(struct tep_event *event, struct tep_print_arg *arg, } atom = token; /* test the next token */ - type = read_token_item(&token); + type = read_token_item(event->tep, &token); /* * If the next token is a parenthesis, then this @@ -3429,7 +3723,7 @@ process_arg_token(struct tep_event *event, struct tep_print_arg *arg, return TEP_EVENT_ERROR; } free_token(token); - type = read_token_item(&token); + type = read_token_item(event->tep, &token); } arg->type = TEP_PRINT_ATOM; @@ -3440,7 +3734,7 @@ process_arg_token(struct tep_event *event, struct tep_print_arg *arg, case TEP_EVENT_SQUOTE: arg->type = TEP_PRINT_ATOM; arg->atom.atom = token; - type = read_token_item(&token); + type = read_token_item(event->tep, &token); break; case TEP_EVENT_DELIM: if (strcmp(token, "(") == 0) { @@ -3481,7 +3775,7 @@ static int event_read_print_args(struct tep_event *event, struct tep_print_arg * do { if (type == TEP_EVENT_NEWLINE) { - type = read_token_item(&token); + type = read_token_item(event->tep, &token); continue; } @@ -3506,6 +3800,10 @@ static int event_read_print_args(struct tep_event *event, struct tep_print_arg * if (type == TEP_EVENT_OP) { type = process_op(event, arg, &token); free_token(token); + + if (consolidate_op_arg(arg) < 0) + type = TEP_EVENT_ERROR; + if (type == TEP_EVENT_ERROR) { *list = NULL; free_arg(arg); @@ -3536,16 +3834,16 @@ static int event_read_print(struct tep_event *event) char *token; int ret; - if (read_expected_item(TEP_EVENT_ITEM, "print") < 0) + if (read_expected_item(event->tep, TEP_EVENT_ITEM, "print") < 0) return -1; - if (read_expected(TEP_EVENT_ITEM, "fmt") < 0) + if (read_expected(event->tep, TEP_EVENT_ITEM, "fmt") < 0) return -1; - if (read_expected(TEP_EVENT_OP, ":") < 0) + if (read_expected(event->tep, TEP_EVENT_OP, ":") < 0) return -1; - if (read_expect_type(TEP_EVENT_DQUOTE, &token) < 0) + if (read_expect_type(event->tep, TEP_EVENT_DQUOTE, &token) < 0) goto fail; concat: @@ -3553,7 +3851,7 @@ static int event_read_print(struct tep_event *event) event->print_fmt.args = NULL; /* ok to have no arg */ - type = read_token_item(&token); + type = read_token_item(event->tep, &token); if (type == TEP_EVENT_NONE) return 0; @@ -3943,9 +4241,9 @@ static inline void dynamic_offset_field(struct tep_handle *tep, { /* Test for overflow */ if (field->offset + field->size > size) { - if (*offset) + if (offset) *offset = 0; - if (*len) + if (len) *len = 0; return; } @@ -3954,6 +4252,18 @@ static inline void dynamic_offset_field(struct tep_handle *tep, *offset += field->offset + field->size; } +static bool check_data_offset_size(struct tep_event *event, const char *field_name, + int data_size, int field_offset, int field_size) +{ + /* Check to make sure the field is within the data */ + if (field_offset + field_size <= data_size) + return false; + + tep_warning("Event '%s' field '%s' goes beyond the size of the event (%d > %d)", + event->name, field_name, field_offset + field_size, data_size); + return true; +} + static unsigned long long eval_num_arg(void *data, int size, struct tep_event *event, struct tep_print_arg *arg) { @@ -3980,6 +4290,12 @@ eval_num_arg(void *data, int size, struct tep_event *event, struct tep_print_arg if (!arg->field.field) goto out_warning_field; } + if (check_data_offset_size(event, arg->field.name, size, + arg->field.field->offset, + arg->field.field->size)) { + val = 0; + break; + } /* must be a number */ val = tep_read_number(tep, data + arg->field.field->offset, arg->field.field->size); @@ -3996,6 +4312,7 @@ eval_num_arg(void *data, int size, struct tep_event *event, struct tep_print_arg case TEP_PRINT_STRING: case TEP_PRINT_BSTRING: case TEP_PRINT_BITMASK: + case TEP_PRINT_CPUMASK: return 0; case TEP_PRINT_FUNC: { struct trace_seq s; @@ -4047,6 +4364,11 @@ eval_num_arg(void *data, int size, struct tep_event *event, struct tep_print_arg default: goto default_op; /* oops, all bets off */ } + if (check_data_offset_size(event, arg->field.name, size, + offset, field_size)) { + val = 0; + break; + } val = tep_read_number(tep, data + offset, field_size); if (typearg) @@ -4156,7 +4478,11 @@ eval_num_arg(void *data, int size, struct tep_event *event, struct tep_print_arg /* Without [], we pass the address to the dynamic data */ dynamic_offset_field(tep, arg->dynarray.field, data, size, &offset, NULL); - val = (unsigned long long)((unsigned long)data + offset); + if (check_data_offset_size(event, arg->field.name, size, + offset, 0)) { + val = (unsigned long)data; + break; + } val = (unsigned long)data + offset; break; default: /* not sure what to do there */ @@ -4277,6 +4603,161 @@ static void print_bitmask_to_seq(struct tep_handle *tep, free(str); } +#define log10(n) \ +( \ + n < 10UL ? 0 : \ + n < 100UL ? 1 : \ + n < 1000UL ? 2 : \ + n < 10000UL ? 3 : \ + n < 100000UL ? 4 : \ + n < 1000000UL ? 5 : \ + n < 10000000UL ? 6 : \ + n < 100000000UL ? 7 : \ + n < 1000000000UL ? 8 : \ + 9 \ +) + +/* ilog10(0) should be 1 but the 0 simplifies below math */ +#define ilog10(n) \ +( \ + n == 0 ? 0UL : \ + n == 1 ? 10UL : \ + n == 2 ? 100UL : \ + n == 3 ? 1000UL : \ + n == 4 ? 10000UL : \ + n == 5 ? 100000UL : \ + n == 6 ? 1000000UL : \ + n == 7 ? 10000000UL : \ + n == 8 ? 100000000UL : \ + 1000000000UL \ +) + +static unsigned int cpumask_worst_size(unsigned int nr_bits) +{ + /* + * Printing all the CPUs separated by a comma is a decent bound for the + * maximum memory required to print a cpumask (a slightly better bound + * is chunks of 2 bits set, i.e. 0-1,3-4,6-7...). + * + * e.g. for nr_bits=132: + * - 131 commas + * - 10 * 1 chars for CPUS [0, 9] + * - 90 * 2 chars for CPUS [10-99] + * - 32 * 3 chars for CPUS [100-131] + */ + unsigned int last_cpu = nr_bits - 1; + unsigned int nr_chars = nr_bits - 1; + int last_lvl = log10(last_cpu); + + /* All log10 levels before the last one have all values used */ + for (int lvl = 0; lvl < last_lvl; lvl++) { + int nr_values = ilog10(lvl + 1) - ilog10(lvl); + + nr_chars += nr_values * (lvl + 1); + } + /* Last level is incomplete */ + nr_chars += (nr_bits - ilog10(last_lvl)) * (last_lvl + 1); + + return nr_chars; +} + +static void print_cpumask_to_seq(struct tep_handle *tep, + struct trace_seq *s, const char *format, + int len_arg, const void *data, int size) +{ + int firstone = -1, firstzero = -1; + int nr_bits = size * 8; + bool first = true; + int str_size = 0; + char buf[12]; /* '-' + log10(2^32) + 1 digits + '\0' */ + char *str; + int index; + int i; + + str = malloc(cpumask_worst_size(nr_bits) + 1); + if (!str) { + do_warning("%s: not enough memory!", __func__); + return; + } + + for (i = 0; i < size; i++) { + unsigned char byte; + int fmtsize; + + if (tep->file_bigendian) + index = size - (i + 1); + else + index = i; + + /* Byte by byte scan, not the best... */ + byte = *(((unsigned char *)data) + index); +more: + /* First find a bit set to one...*/ + if (firstone < 0 && byte) { + /* + * Set all lower bits, so a later ffz on this same byte + * is guaranteed to find a later bit. + */ + firstone = ffs(byte) - 1; + byte |= (1 << firstone) - 1; + firstone += i * 8; + } + + if (firstone < 0) + continue; + + /* ...Then find a bit set to zero */ + if ((~byte) & 0xFF) { + /* + * Clear all lower bits, so a later ffs on this same + * byte is guaranteed to find a later bit. + */ + firstzero = ffs(~byte) - 1; + byte &= ~((1 << (firstzero)) - 1); + firstzero += i * 8; + } else if (i == size - 1) { /* ...Or reach the end of the mask */ + firstzero = nr_bits; + byte = 0; + } else { + continue; + } + + /* We've found a bit set to one, and a later bit set to zero. */ + if (!first) { + str[str_size] = ','; + str_size++; + } + first = false; + + /* It takes {log10(number) + 1} chars to format a number */ + fmtsize = log10(firstone) + 1; + snprintf(buf, fmtsize + 1, "%d", firstone); + memcpy(str + str_size, buf, fmtsize); + str_size += fmtsize; + + if (firstzero > firstone + 1) { + fmtsize = log10(firstzero - 1) + 2; + snprintf(buf, fmtsize + 1, "-%d", firstzero - 1); + memcpy(str + str_size, buf, fmtsize); + str_size += fmtsize; + } + + firstzero = firstone = -1; + if (byte) + goto more; + } + + str[str_size] = 0; + str_size++; + + if (len_arg >= 0) + trace_seq_printf(s, format, len_arg, str); + else + trace_seq_printf(s, format, str); + + free(str); +} + static void print_str_arg(struct trace_seq *s, void *data, int size, struct tep_event *event, const char *format, int len_arg, struct tep_print_arg *arg) @@ -4466,10 +4947,10 @@ static void print_str_arg(struct trace_seq *s, void *data, int size, case TEP_PRINT_STRING: { if (!arg->string.field) { arg->string.field = tep_find_any_field(event, arg->string.string); + if (!arg->string.field) + break; arg->string.offset = arg->string.field->offset; } - if (!arg->string.field) - break; dynamic_offset_field(tep, arg->string.field, data, size, &offset, &len); /* Do not attempt to save zero length dynamic strings */ if (!len) @@ -4483,12 +4964,24 @@ static void print_str_arg(struct trace_seq *s, void *data, int size, case TEP_PRINT_BITMASK: { if (!arg->bitmask.field) { arg->bitmask.field = tep_find_any_field(event, arg->bitmask.bitmask); + if (!arg->bitmask.field) + break; + arg->bitmask.offset = arg->bitmask.field->offset; + } + dynamic_offset_field(tep, arg->bitmask.field, data, size, &offset, &len); + print_bitmask_to_seq(tep, s, format, len_arg, + data + offset, len); + break; + } + case TEP_PRINT_CPUMASK: { + if (!arg->bitmask.field) { + arg->bitmask.field = tep_find_any_field(event, arg->bitmask.bitmask); arg->bitmask.offset = arg->bitmask.field->offset; } if (!arg->bitmask.field) break; dynamic_offset_field(tep, arg->bitmask.field, data, size, &offset, &len); - print_bitmask_to_seq(tep, s, format, len_arg, + print_cpumask_to_seq(tep, s, format, len_arg, data + offset, len); break; } @@ -4790,8 +5283,10 @@ static struct tep_print_arg *make_bprint_args(char *fmt, void *data, int size, s arg->next = NULL; arg->type = TEP_PRINT_BSTRING; arg->string.string = strdup(bptr); - if (!arg->string.string) + if (!arg->string.string) { + free(arg); goto out_free; + } bptr += strlen(bptr) + 1; *next = arg; next = &arg->next; @@ -5485,6 +5980,7 @@ static void print_field_raw(struct trace_seq *s, void *data, int size, trace_seq_printf(s, "%llu", val); } } + trace_seq_terminate(s); } static int print_parse_data(struct tep_print_parse *parse, struct trace_seq *s, @@ -5498,7 +5994,7 @@ static inline void print_field(struct trace_seq *s, void *data, int size, struct tep_print_parse *start_parse; struct tep_print_parse *parse; struct tep_print_arg *arg; - bool has_0x; + bool has_0x = false; parse = parse_ptr ? *parse_ptr : event->print_fmt.print_cache; @@ -5536,7 +6032,7 @@ static inline void print_field(struct trace_seq *s, void *data, int size, if (has_0x) trace_seq_puts(s, "0x"); - print_parse_data(parse, s, data, field->size, event); + print_parse_data(parse, s, data, size, event); if (parse_ptr) *parse_ptr = parse->next; @@ -6272,8 +6768,13 @@ static void data_latency_format(struct tep_handle *tep, struct trace_seq *s, (hardirq && softirq) ? 'H' : hardirq ? 'h' : softirq ? 's' : '.'); - if (pc) - trace_seq_printf(&sq, "%x", pc); + if (pc & 0xf) + trace_seq_printf(&sq, "%x", pc & 0xf); + else + trace_seq_printf(&sq, "."); + + if (pc & 0xf0) + trace_seq_printf(&sq, "%x", pc >> 4); else trace_seq_printf(&sq, "."); @@ -6999,6 +7500,9 @@ static void print_args(struct tep_print_arg *args) case TEP_PRINT_BITMASK: printf("__get_bitmask(%s)", args->bitmask.bitmask); break; + case TEP_PRINT_CPUMASK: + printf("__get_cpumask(%s)", args->bitmask.bitmask); + break; case TEP_PRINT_TYPE: printf("(%s)", args->typecast.type); print_args(args->typecast.item); @@ -7024,7 +7528,7 @@ static void print_args(struct tep_print_arg *args) } } -static void parse_header_field(const char *field, +static void parse_header_field(struct tep_handle *tep, const char *field, int *offset, int *size, int mandatory) { unsigned long long save_input_buf_ptr; @@ -7032,16 +7536,16 @@ static void parse_header_field(const char *field, char *token; int type; - save_input_buf_ptr = input_buf_ptr; - save_input_buf_siz = input_buf_siz; + save_input_buf_ptr = tep->input_buf_ptr; + save_input_buf_siz = tep->input_buf_siz; - if (read_expected(TEP_EVENT_ITEM, "field") < 0) + if (read_expected(tep, TEP_EVENT_ITEM, "field") < 0) return; - if (read_expected(TEP_EVENT_OP, ":") < 0) + if (read_expected(tep, TEP_EVENT_OP, ":") < 0) return; /* type */ - if (read_expect_type(TEP_EVENT_ITEM, &token) < 0) + if (read_expect_type(tep, TEP_EVENT_ITEM, &token) < 0) goto fail; free_token(token); @@ -7049,39 +7553,39 @@ static void parse_header_field(const char *field, * If this is not a mandatory field, then test it first. */ if (mandatory) { - if (read_expected(TEP_EVENT_ITEM, field) < 0) + if (read_expected(tep, TEP_EVENT_ITEM, field) < 0) return; } else { - if (read_expect_type(TEP_EVENT_ITEM, &token) < 0) + if (read_expect_type(tep, TEP_EVENT_ITEM, &token) < 0) goto fail; if (strcmp(token, field) != 0) goto discard; free_token(token); } - if (read_expected(TEP_EVENT_OP, ";") < 0) + if (read_expected(tep, TEP_EVENT_OP, ";") < 0) return; - if (read_expected(TEP_EVENT_ITEM, "offset") < 0) + if (read_expected(tep, TEP_EVENT_ITEM, "offset") < 0) return; - if (read_expected(TEP_EVENT_OP, ":") < 0) + if (read_expected(tep, TEP_EVENT_OP, ":") < 0) return; - if (read_expect_type(TEP_EVENT_ITEM, &token) < 0) + if (read_expect_type(tep, TEP_EVENT_ITEM, &token) < 0) goto fail; *offset = atoi(token); free_token(token); - if (read_expected(TEP_EVENT_OP, ";") < 0) + if (read_expected(tep, TEP_EVENT_OP, ";") < 0) return; - if (read_expected(TEP_EVENT_ITEM, "size") < 0) + if (read_expected(tep, TEP_EVENT_ITEM, "size") < 0) return; - if (read_expected(TEP_EVENT_OP, ":") < 0) + if (read_expected(tep, TEP_EVENT_OP, ":") < 0) return; - if (read_expect_type(TEP_EVENT_ITEM, &token) < 0) + if (read_expect_type(tep, TEP_EVENT_ITEM, &token) < 0) goto fail; *size = atoi(token); free_token(token); - if (read_expected(TEP_EVENT_OP, ";") < 0) + if (read_expected(tep, TEP_EVENT_OP, ";") < 0) return; - type = read_token(&token); + type = read_token(tep, &token); if (type != TEP_EVENT_NEWLINE) { /* newer versions of the kernel have a "signed" type */ if (type != TEP_EVENT_ITEM) @@ -7092,17 +7596,17 @@ static void parse_header_field(const char *field, free_token(token); - if (read_expected(TEP_EVENT_OP, ":") < 0) + if (read_expected(tep, TEP_EVENT_OP, ":") < 0) return; - if (read_expect_type(TEP_EVENT_ITEM, &token)) + if (read_expect_type(tep, TEP_EVENT_ITEM, &token)) goto fail; free_token(token); - if (read_expected(TEP_EVENT_OP, ";") < 0) + if (read_expected(tep, TEP_EVENT_OP, ";") < 0) return; - if (read_expect_type(TEP_EVENT_NEWLINE, &token)) + if (read_expect_type(tep, TEP_EVENT_NEWLINE, &token)) goto fail; } fail: @@ -7110,8 +7614,8 @@ static void parse_header_field(const char *field, return; discard: - input_buf_ptr = save_input_buf_ptr; - input_buf_siz = save_input_buf_siz; + tep->input_buf_ptr = save_input_buf_ptr; + tep->input_buf_siz = save_input_buf_siz; *offset = 0; *size = 0; free_token(token); @@ -7146,15 +7650,15 @@ int tep_parse_header_page(struct tep_handle *tep, char *buf, unsigned long size, tep->old_format = 1; return -1; } - init_input_buf(buf, size); + init_input_buf(tep, buf, size); - parse_header_field("timestamp", &tep->header_page_ts_offset, + parse_header_field(tep, "timestamp", &tep->header_page_ts_offset, &tep->header_page_ts_size, 1); - parse_header_field("commit", &tep->header_page_size_offset, + parse_header_field(tep, "commit", &tep->header_page_size_offset, &tep->header_page_size_size, 1); - parse_header_field("overwrite", &tep->header_page_overwrite, + parse_header_field(tep, "overwrite", &tep->header_page_overwrite, &ignore, 0); - parse_header_field("data", &tep->header_page_data_offset, + parse_header_field(tep, "data", &tep->header_page_data_offset, &tep->header_page_data_size, 1); return 0; @@ -7231,13 +7735,13 @@ static enum tep_errno parse_format(struct tep_event **eventp, struct tep_event *event; int ret; - init_input_buf(buf, size); + init_input_buf(tep, buf, size); *eventp = event = alloc_event(); if (!event) return TEP_ERRNO__MEM_ALLOC_FAILED; - event->name = event_read_name(); + event->name = event_read_name(tep); if (!event->name) { /* Bad event? */ ret = TEP_ERRNO__MEM_ALLOC_FAILED; @@ -7251,7 +7755,7 @@ static enum tep_errno parse_format(struct tep_event **eventp, event->flags |= TEP_EVENT_FL_ISBPRINT; } - event->id = event_read_id(); + event->id = event_read_id(tep); if (event->id < 0) { ret = TEP_ERRNO__READ_ID_FAILED; /* |