|
@@ -40,6 +40,8 @@ int header_page_size_size;
|
|
|
int header_page_data_offset;
|
|
|
int header_page_data_size;
|
|
|
|
|
|
+int latency_format;
|
|
|
+
|
|
|
static char *input_buf;
|
|
|
static unsigned long long input_buf_ptr;
|
|
|
static unsigned long long input_buf_siz;
|
|
@@ -284,18 +286,19 @@ void parse_ftrace_printk(char *file, unsigned int size __unused)
|
|
|
char *line;
|
|
|
char *next = NULL;
|
|
|
char *addr_str;
|
|
|
- int ret;
|
|
|
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));
|
|
|
- ret = sscanf(line, "%as : %as",
|
|
|
- (float *)(void *)&addr_str, /* workaround gcc warning */
|
|
|
- (float *)(void *)&item->printk);
|
|
|
item->addr = strtoull(addr_str, NULL, 16);
|
|
|
- free(addr_str);
|
|
|
-
|
|
|
+ /* fmt still has a space, skip it */
|
|
|
+ item->printk = strdup(line+1);
|
|
|
item->next = list;
|
|
|
list = item;
|
|
|
line = strtok_r(NULL, "\n", &next);
|
|
@@ -522,7 +525,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;
|
|
@@ -610,7 +616,7 @@ static enum event_type read_token_item(char **tok)
|
|
|
static int test_type(enum event_type type, enum event_type expect)
|
|
|
{
|
|
|
if (type != expect) {
|
|
|
- die("Error: expected type %d but read %d",
|
|
|
+ warning("Error: expected type %d but read %d",
|
|
|
expect, type);
|
|
|
return -1;
|
|
|
}
|
|
@@ -621,13 +627,13 @@ static int test_type_token(enum event_type type, char *token,
|
|
|
enum event_type expect, const char *expect_tok)
|
|
|
{
|
|
|
if (type != expect) {
|
|
|
- die("Error: expected type %d but read %d",
|
|
|
+ warning("Error: expected type %d but read %d",
|
|
|
expect, type);
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
|
if (strcmp(token, expect_tok) != 0) {
|
|
|
- die("Error: expected '%s' but read '%s'",
|
|
|
+ warning("Error: expected '%s' but read '%s'",
|
|
|
expect_tok, token);
|
|
|
return -1;
|
|
|
}
|
|
@@ -665,7 +671,7 @@ static int __read_expected(enum event_type expect, const char *str, int newline_
|
|
|
|
|
|
free_token(token);
|
|
|
|
|
|
- return 0;
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
static int read_expected(enum event_type expect, const char *str)
|
|
@@ -682,10 +688,10 @@ static char *event_read_name(void)
|
|
|
{
|
|
|
char *token;
|
|
|
|
|
|
- if (read_expected(EVENT_ITEM, (char *)"name") < 0)
|
|
|
+ if (read_expected(EVENT_ITEM, "name") < 0)
|
|
|
return NULL;
|
|
|
|
|
|
- if (read_expected(EVENT_OP, (char *)":") < 0)
|
|
|
+ if (read_expected(EVENT_OP, ":") < 0)
|
|
|
return NULL;
|
|
|
|
|
|
if (read_expect_type(EVENT_ITEM, &token) < 0)
|
|
@@ -703,10 +709,10 @@ static int event_read_id(void)
|
|
|
char *token;
|
|
|
int id;
|
|
|
|
|
|
- if (read_expected_item(EVENT_ITEM, (char *)"ID") < 0)
|
|
|
+ if (read_expected_item(EVENT_ITEM, "ID") < 0)
|
|
|
return -1;
|
|
|
|
|
|
- if (read_expected(EVENT_OP, (char *)":") < 0)
|
|
|
+ if (read_expected(EVENT_OP, ":") < 0)
|
|
|
return -1;
|
|
|
|
|
|
if (read_expect_type(EVENT_ITEM, &token) < 0)
|
|
@@ -721,6 +727,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;
|
|
@@ -738,7 +762,7 @@ static int event_read_fields(struct event *event, struct format_field **fields)
|
|
|
|
|
|
count++;
|
|
|
|
|
|
- if (test_type_token(type, token, EVENT_ITEM, (char *)"field"))
|
|
|
+ if (test_type_token(type, token, EVENT_ITEM, "field"))
|
|
|
goto fail;
|
|
|
free_token(token);
|
|
|
|
|
@@ -753,7 +777,7 @@ static int event_read_fields(struct event *event, struct format_field **fields)
|
|
|
type = read_token(&token);
|
|
|
}
|
|
|
|
|
|
- if (test_type_token(type, token, EVENT_OP, (char *)":") < 0)
|
|
|
+ if (test_type_token(type, token, EVENT_OP, ":") < 0)
|
|
|
return -1;
|
|
|
|
|
|
if (read_expect_type(EVENT_ITEM, &token) < 0)
|
|
@@ -865,14 +889,20 @@ static int event_read_fields(struct event *event, struct format_field **fields)
|
|
|
free(brackets);
|
|
|
}
|
|
|
|
|
|
- if (test_type_token(type, token, EVENT_OP, (char *)";"))
|
|
|
+ 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, (char *)"offset") < 0)
|
|
|
+ if (read_expected(EVENT_ITEM, "offset") < 0)
|
|
|
goto fail_expect;
|
|
|
|
|
|
- if (read_expected(EVENT_OP, (char *)":") < 0)
|
|
|
+ if (read_expected(EVENT_OP, ":") < 0)
|
|
|
goto fail_expect;
|
|
|
|
|
|
if (read_expect_type(EVENT_ITEM, &token))
|
|
@@ -880,13 +910,13 @@ static int event_read_fields(struct event *event, struct format_field **fields)
|
|
|
field->offset = strtoul(token, NULL, 0);
|
|
|
free_token(token);
|
|
|
|
|
|
- if (read_expected(EVENT_OP, (char *)";") < 0)
|
|
|
+ if (read_expected(EVENT_OP, ";") < 0)
|
|
|
goto fail_expect;
|
|
|
|
|
|
- if (read_expected(EVENT_ITEM, (char *)"size") < 0)
|
|
|
+ if (read_expected(EVENT_ITEM, "size") < 0)
|
|
|
goto fail_expect;
|
|
|
|
|
|
- if (read_expected(EVENT_OP, (char *)":") < 0)
|
|
|
+ if (read_expected(EVENT_OP, ":") < 0)
|
|
|
goto fail_expect;
|
|
|
|
|
|
if (read_expect_type(EVENT_ITEM, &token))
|
|
@@ -894,11 +924,33 @@ 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)
|
|
|
+ if (read_expected(EVENT_OP, ";") < 0)
|
|
|
goto fail_expect;
|
|
|
|
|
|
- if (read_expect_type(EVENT_NEWLINE, &token) < 0)
|
|
|
- goto fail;
|
|
|
+ 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;
|
|
|
+
|
|
|
+ /* add signed type */
|
|
|
+
|
|
|
+ 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;
|
|
@@ -921,10 +973,10 @@ static int event_read_format(struct event *event)
|
|
|
char *token;
|
|
|
int ret;
|
|
|
|
|
|
- if (read_expected_item(EVENT_ITEM, (char *)"format") < 0)
|
|
|
+ if (read_expected_item(EVENT_ITEM, "format") < 0)
|
|
|
return -1;
|
|
|
|
|
|
- if (read_expected(EVENT_OP, (char *)":") < 0)
|
|
|
+ if (read_expected(EVENT_OP, ":") < 0)
|
|
|
return -1;
|
|
|
|
|
|
if (read_expect_type(EVENT_NEWLINE, &token))
|
|
@@ -984,7 +1036,7 @@ process_cond(struct event *event, struct print_arg *top, char **tok)
|
|
|
|
|
|
*tok = NULL;
|
|
|
type = process_arg(event, left, &token);
|
|
|
- if (test_type_token(type, token, EVENT_OP, (char *)":"))
|
|
|
+ if (test_type_token(type, token, EVENT_OP, ":"))
|
|
|
goto out_free;
|
|
|
|
|
|
arg->op.op = token;
|
|
@@ -1004,6 +1056,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, "]"))
|
|
|
+ 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 +1209,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) {
|
|
|
|
|
@@ -1144,17 +1227,46 @@ process_op(struct event *event, struct print_arg *arg, char **tok)
|
|
|
|
|
|
right = malloc_or_die(sizeof(*right));
|
|
|
|
|
|
- type = process_arg(event, right, tok);
|
|
|
+ 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 {
|
|
|
- die("unknown op '%s'", token);
|
|
|
+ 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;
|
|
|
|
|
@@ -1178,7 +1290,7 @@ process_entry(struct event *event __unused, struct print_arg *arg,
|
|
|
char *field;
|
|
|
char *token;
|
|
|
|
|
|
- if (read_expected(EVENT_OP, (char *)"->") < 0)
|
|
|
+ if (read_expected(EVENT_OP, "->") < 0)
|
|
|
return EVENT_ERROR;
|
|
|
|
|
|
if (read_expect_type(EVENT_ITEM, &token) < 0)
|
|
@@ -1338,14 +1450,14 @@ process_fields(struct event *event, struct print_flag_sym **list, char **tok)
|
|
|
do {
|
|
|
free_token(token);
|
|
|
type = read_token_item(&token);
|
|
|
- if (test_type_token(type, token, EVENT_OP, (char *)"{"))
|
|
|
+ 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, (char *)","))
|
|
|
+ if (test_type_token(type, token, EVENT_DELIM, ","))
|
|
|
goto out_free;
|
|
|
|
|
|
field = malloc_or_die(sizeof(*field));
|
|
@@ -1356,7 +1468,7 @@ process_fields(struct event *event, struct print_flag_sym **list, char **tok)
|
|
|
|
|
|
free_token(token);
|
|
|
type = process_arg(event, arg, &token);
|
|
|
- if (test_type_token(type, token, EVENT_OP, (char *)"}"))
|
|
|
+ if (test_type_token(type, token, EVENT_OP, "}"))
|
|
|
goto out_free;
|
|
|
|
|
|
value = arg_eval(arg);
|
|
@@ -1391,13 +1503,13 @@ process_flags(struct event *event, struct print_arg *arg, char **tok)
|
|
|
memset(arg, 0, sizeof(*arg));
|
|
|
arg->type = PRINT_FLAGS;
|
|
|
|
|
|
- if (read_expected_item(EVENT_DELIM, (char *)"(") < 0)
|
|
|
+ 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, (char *)","))
|
|
|
+ if (test_type_token(type, token, EVENT_DELIM, ","))
|
|
|
goto out_free;
|
|
|
|
|
|
arg->flags.field = field;
|
|
@@ -1408,11 +1520,11 @@ process_flags(struct event *event, struct print_arg *arg, char **tok)
|
|
|
type = read_token_item(&token);
|
|
|
}
|
|
|
|
|
|
- if (test_type_token(type, token, EVENT_DELIM, (char *)","))
|
|
|
+ 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, (char *)")"))
|
|
|
+ if (test_type_token(type, token, EVENT_DELIM, ")"))
|
|
|
goto out_free;
|
|
|
|
|
|
free_token(token);
|
|
@@ -1434,19 +1546,19 @@ process_symbols(struct event *event, struct print_arg *arg, char **tok)
|
|
|
memset(arg, 0, sizeof(*arg));
|
|
|
arg->type = PRINT_SYMBOL;
|
|
|
|
|
|
- if (read_expected_item(EVENT_DELIM, (char *)"(") < 0)
|
|
|
+ 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, (char *)","))
|
|
|
+ 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, (char *)")"))
|
|
|
+ if (test_type_token(type, token, EVENT_DELIM, ")"))
|
|
|
goto out_free;
|
|
|
|
|
|
free_token(token);
|
|
@@ -1463,7 +1575,6 @@ process_paren(struct event *event, struct print_arg *arg, char **tok)
|
|
|
{
|
|
|
struct print_arg *item_arg;
|
|
|
enum event_type type;
|
|
|
- int ptr_cast = 0;
|
|
|
char *token;
|
|
|
|
|
|
type = process_arg(event, arg, &token);
|
|
@@ -1471,28 +1582,13 @@ process_paren(struct event *event, struct print_arg *arg, char **tok)
|
|
|
if (type == EVENT_ERROR)
|
|
|
return EVENT_ERROR;
|
|
|
|
|
|
- if (type == EVENT_OP) {
|
|
|
- /* handle the ptr casts */
|
|
|
- if (!strcmp(token, "*")) {
|
|
|
- /*
|
|
|
- * FIXME: should we zapp whitespaces before ')' ?
|
|
|
- * (may require a peek_token_item())
|
|
|
- */
|
|
|
- if (__peek_char() == ')') {
|
|
|
- ptr_cast = 1;
|
|
|
- free_token(token);
|
|
|
- type = read_token_item(&token);
|
|
|
- }
|
|
|
- }
|
|
|
- if (!ptr_cast) {
|
|
|
- type = process_op(event, arg, &token);
|
|
|
+ if (type == EVENT_OP)
|
|
|
+ type = process_op(event, arg, &token);
|
|
|
|
|
|
- if (type == EVENT_ERROR)
|
|
|
- return EVENT_ERROR;
|
|
|
- }
|
|
|
- }
|
|
|
+ if (type == EVENT_ERROR)
|
|
|
+ return EVENT_ERROR;
|
|
|
|
|
|
- if (test_type_token(type, token, EVENT_DELIM, (char *)")")) {
|
|
|
+ if (test_type_token(type, token, EVENT_DELIM, ")")) {
|
|
|
free_token(token);
|
|
|
return EVENT_ERROR;
|
|
|
}
|
|
@@ -1516,13 +1612,6 @@ process_paren(struct event *event, struct print_arg *arg, char **tok)
|
|
|
item_arg = malloc_or_die(sizeof(*item_arg));
|
|
|
|
|
|
arg->type = PRINT_TYPE;
|
|
|
- if (ptr_cast) {
|
|
|
- char *old = arg->atom.atom;
|
|
|
-
|
|
|
- arg->atom.atom = malloc_or_die(strlen(old + 3));
|
|
|
- sprintf(arg->atom.atom, "%s *", old);
|
|
|
- free(old);
|
|
|
- }
|
|
|
arg->typecast.type = arg->atom.atom;
|
|
|
arg->typecast.item = item_arg;
|
|
|
type = process_arg_token(event, item_arg, &token, type);
|
|
@@ -1540,7 +1629,7 @@ process_str(struct event *event __unused, struct print_arg *arg, char **tok)
|
|
|
enum event_type type;
|
|
|
char *token;
|
|
|
|
|
|
- if (read_expected(EVENT_DELIM, (char *)"(") < 0)
|
|
|
+ if (read_expected(EVENT_DELIM, "(") < 0)
|
|
|
return EVENT_ERROR;
|
|
|
|
|
|
if (read_expect_type(EVENT_ITEM, &token) < 0)
|
|
@@ -1550,7 +1639,7 @@ process_str(struct event *event __unused, struct print_arg *arg, char **tok)
|
|
|
arg->string.string = token;
|
|
|
arg->string.offset = -1;
|
|
|
|
|
|
- if (read_expected(EVENT_DELIM, (char *)")") < 0)
|
|
|
+ if (read_expected(EVENT_DELIM, ")") < 0)
|
|
|
return EVENT_ERROR;
|
|
|
|
|
|
type = read_token(&token);
|
|
@@ -1637,12 +1726,18 @@ process_arg_token(struct event *event, struct print_arg *arg,
|
|
|
|
|
|
static int event_read_print_args(struct event *event, struct print_arg **list)
|
|
|
{
|
|
|
- enum event_type type;
|
|
|
+ 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));
|
|
|
|
|
@@ -1683,18 +1778,19 @@ static int event_read_print(struct event *event)
|
|
|
char *token;
|
|
|
int ret;
|
|
|
|
|
|
- if (read_expected_item(EVENT_ITEM, (char *)"print") < 0)
|
|
|
+ if (read_expected_item(EVENT_ITEM, "print") < 0)
|
|
|
return -1;
|
|
|
|
|
|
- if (read_expected(EVENT_ITEM, (char *)"fmt") < 0)
|
|
|
+ if (read_expected(EVENT_ITEM, "fmt") < 0)
|
|
|
return -1;
|
|
|
|
|
|
- if (read_expected(EVENT_OP, (char *)":") < 0)
|
|
|
+ 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;
|
|
|
|
|
@@ -1704,7 +1800,22 @@ static int event_read_print(struct event *event)
|
|
|
if (type == EVENT_NONE)
|
|
|
return 0;
|
|
|
|
|
|
- if (test_type_token(type, token, EVENT_DELIM, (char *)","))
|
|
|
+ /* 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);
|
|
@@ -1713,7 +1824,7 @@ static int event_read_print(struct event *event)
|
|
|
if (ret < 0)
|
|
|
return -1;
|
|
|
|
|
|
- return 0;
|
|
|
+ return ret;
|
|
|
|
|
|
fail:
|
|
|
free_token(token);
|
|
@@ -1822,37 +1933,67 @@ static int get_common_info(const char *type, int *offset, int *size)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-int trace_parse_common_type(void *data)
|
|
|
+static int __parse_common(void *data, int *size, int *offset,
|
|
|
+ const char *name)
|
|
|
{
|
|
|
- static int type_offset;
|
|
|
- static int type_size;
|
|
|
int ret;
|
|
|
|
|
|
- if (!type_size) {
|
|
|
- ret = get_common_info("common_type",
|
|
|
- &type_offset,
|
|
|
- &type_size);
|
|
|
+ if (!*size) {
|
|
|
+ ret = get_common_info(name, offset, size);
|
|
|
if (ret < 0)
|
|
|
return ret;
|
|
|
}
|
|
|
- return read_size(data + type_offset, type_size);
|
|
|
+ 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");
|
|
|
}
|
|
|
|
|
|
static int parse_common_pid(void *data)
|
|
|
{
|
|
|
static int pid_offset;
|
|
|
static int pid_size;
|
|
|
+
|
|
|
+ return __parse_common(data, &pid_size, &pid_offset,
|
|
|
+ "common_pid");
|
|
|
+}
|
|
|
+
|
|
|
+static 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");
|
|
|
+}
|
|
|
+
|
|
|
+static int parse_common_flags(void *data)
|
|
|
+{
|
|
|
+ static int flags_offset;
|
|
|
+ static int flags_size;
|
|
|
+
|
|
|
+ return __parse_common(data, &flags_size, &flags_offset,
|
|
|
+ "common_flags");
|
|
|
+}
|
|
|
+
|
|
|
+static int parse_common_lock_depth(void *data)
|
|
|
+{
|
|
|
+ static int ld_offset;
|
|
|
+ static int ld_size;
|
|
|
int ret;
|
|
|
|
|
|
- if (!pid_size) {
|
|
|
- ret = get_common_info("common_pid",
|
|
|
- &pid_offset,
|
|
|
- &pid_size);
|
|
|
- if (ret < 0)
|
|
|
- return ret;
|
|
|
- }
|
|
|
+ ret = __parse_common(data, &ld_size, &ld_offset,
|
|
|
+ "common_lock_depth");
|
|
|
+ if (ret < 0)
|
|
|
+ return -1;
|
|
|
|
|
|
- return read_size(data + pid_offset, pid_size);
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
struct event *trace_find_event(int id)
|
|
@@ -1871,6 +2012,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 +2039,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]) {
|
|
@@ -1947,6 +2109,12 @@ static unsigned long long eval_num_arg(void *data, int size,
|
|
|
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);
|
|
|
}
|
|
@@ -2145,8 +2313,9 @@ static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struc
|
|
|
case 'u':
|
|
|
case 'x':
|
|
|
case 'i':
|
|
|
- bptr = (void *)(((unsigned long)bptr + (long_size - 1)) &
|
|
|
- ~(long_size - 1));
|
|
|
+ /* the pointers are always 4 bytes aligned */
|
|
|
+ bptr = (void *)(((unsigned long)bptr + 3) &
|
|
|
+ ~3);
|
|
|
switch (ls) {
|
|
|
case 0:
|
|
|
case 1:
|
|
@@ -2270,7 +2439,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:
|
|
@@ -2377,6 +2566,41 @@ static inline int log10_cpu(int nb)
|
|
|
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);
|
|
|
+}
|
|
|
+
|
|
|
/* taken from Linux, written by Frederic Weisbecker */
|
|
|
static void print_graph_cpu(int cpu)
|
|
|
{
|
|
@@ -2620,6 +2844,11 @@ pretty_print_func_ent(void *data, int size, struct event *event,
|
|
|
|
|
|
printf(" | ");
|
|
|
|
|
|
+ if (latency_format) {
|
|
|
+ print_lat_fmt(data, size);
|
|
|
+ printf(" | ");
|
|
|
+ }
|
|
|
+
|
|
|
field = find_field(event, "func");
|
|
|
if (!field)
|
|
|
die("function entry does not have func field");
|
|
@@ -2663,6 +2892,11 @@ pretty_print_func_ret(void *data, int size __unused, struct event *event,
|
|
|
|
|
|
printf(" | ");
|
|
|
|
|
|
+ if (latency_format) {
|
|
|
+ print_lat_fmt(data, size);
|
|
|
+ printf(" | ");
|
|
|
+ }
|
|
|
+
|
|
|
field = find_field(event, "rettime");
|
|
|
if (!field)
|
|
|
die("can't find rettime in return graph");
|
|
@@ -2724,7 +2958,7 @@ void print_event(int cpu, void *data, int size, unsigned long long nsecs,
|
|
|
|
|
|
event = trace_find_event(type);
|
|
|
if (!event) {
|
|
|
- printf("ug! no event found for type %d\n", type);
|
|
|
+ warning("ug! no event found for type %d", type);
|
|
|
return;
|
|
|
}
|
|
|
|
|
@@ -2734,9 +2968,20 @@ void print_event(int cpu, void *data, int size, unsigned long long nsecs,
|
|
|
return pretty_print_func_graph(data, size, event, cpu,
|
|
|
pid, comm, secs, usecs);
|
|
|
|
|
|
- printf("%16s-%-5d [%03d] %5lu.%09Lu: %s: ",
|
|
|
- comm, pid, cpu,
|
|
|
- secs, nsecs, event->name);
|
|
|
+ if (latency_format) {
|
|
|
+ printf("%8.8s-%-5d %3d",
|
|
|
+ comm, pid, cpu);
|
|
|
+ print_lat_fmt(data, size);
|
|
|
+ } else
|
|
|
+ printf("%16s-%-5d [%03d]", comm, pid, cpu);
|
|
|
+
|
|
|
+ printf(" %5lu.%06lu: %s: ", secs, usecs, event->name);
|
|
|
+
|
|
|
+ if (event->flags & EVENT_FL_FAILED) {
|
|
|
+ printf("EVENT '%s' FAILED TO PARSE\n",
|
|
|
+ event->name);
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
pretty_print(data, size, event);
|
|
|
printf("\n");
|
|
@@ -2807,46 +3052,71 @@ static void print_args(struct print_arg *args)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static void parse_header_field(char *type,
|
|
|
+static void parse_header_field(const char *field,
|
|
|
int *offset, int *size)
|
|
|
{
|
|
|
char *token;
|
|
|
+ int type;
|
|
|
|
|
|
- if (read_expected(EVENT_ITEM, (char *)"field") < 0)
|
|
|
+ if (read_expected(EVENT_ITEM, "field") < 0)
|
|
|
return;
|
|
|
- if (read_expected(EVENT_OP, (char *)":") < 0)
|
|
|
+ if (read_expected(EVENT_OP, ":") < 0)
|
|
|
return;
|
|
|
+
|
|
|
/* type */
|
|
|
if (read_expect_type(EVENT_ITEM, &token) < 0)
|
|
|
- return;
|
|
|
+ goto fail;
|
|
|
free_token(token);
|
|
|
|
|
|
- if (read_expected(EVENT_ITEM, type) < 0)
|
|
|
+ if (read_expected(EVENT_ITEM, field) < 0)
|
|
|
return;
|
|
|
- if (read_expected(EVENT_OP, (char *)";") < 0)
|
|
|
+ if (read_expected(EVENT_OP, ";") < 0)
|
|
|
return;
|
|
|
- if (read_expected(EVENT_ITEM, (char *)"offset") < 0)
|
|
|
+ if (read_expected(EVENT_ITEM, "offset") < 0)
|
|
|
return;
|
|
|
- if (read_expected(EVENT_OP, (char *)":") < 0)
|
|
|
+ if (read_expected(EVENT_OP, ":") < 0)
|
|
|
return;
|
|
|
if (read_expect_type(EVENT_ITEM, &token) < 0)
|
|
|
- return;
|
|
|
+ goto fail;
|
|
|
*offset = atoi(token);
|
|
|
free_token(token);
|
|
|
- if (read_expected(EVENT_OP, (char *)";") < 0)
|
|
|
+ if (read_expected(EVENT_OP, ";") < 0)
|
|
|
return;
|
|
|
- if (read_expected(EVENT_ITEM, (char *)"size") < 0)
|
|
|
+ if (read_expected(EVENT_ITEM, "size") < 0)
|
|
|
return;
|
|
|
- if (read_expected(EVENT_OP, (char *)":") < 0)
|
|
|
+ if (read_expected(EVENT_OP, ":") < 0)
|
|
|
return;
|
|
|
if (read_expect_type(EVENT_ITEM, &token) < 0)
|
|
|
- return;
|
|
|
+ goto fail;
|
|
|
*size = atoi(token);
|
|
|
free_token(token);
|
|
|
- if (read_expected(EVENT_OP, (char *)";") < 0)
|
|
|
- return;
|
|
|
- if (read_expect_type(EVENT_NEWLINE, &token) < 0)
|
|
|
+ if (read_expected(EVENT_OP, ";") < 0)
|
|
|
return;
|
|
|
+ type = read_token(&token);
|
|
|
+ if (type != EVENT_NEWLINE) {
|
|
|
+ /* newer versions of the kernel have a "signed" type */
|
|
|
+ if (type != EVENT_ITEM)
|
|
|
+ goto fail;
|
|
|
+
|
|
|
+ if (strcmp(token, "signed") != 0)
|
|
|
+ goto fail;
|
|
|
+
|
|
|
+ free_token(token);
|
|
|
+
|
|
|
+ if (read_expected(EVENT_OP, ":") < 0)
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (read_expect_type(EVENT_ITEM, &token))
|
|
|
+ goto fail;
|
|
|
+
|
|
|
+ free_token(token);
|
|
|
+ if (read_expected(EVENT_OP, ";") < 0)
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (read_expect_type(EVENT_NEWLINE, &token))
|
|
|
+ goto fail;
|
|
|
+ }
|
|
|
+ fail:
|
|
|
free_token(token);
|
|
|
}
|
|
|
|
|
@@ -2854,11 +3124,11 @@ int parse_header_page(char *buf, unsigned long size)
|
|
|
{
|
|
|
init_input_buf(buf, size);
|
|
|
|
|
|
- parse_header_field((char *)"timestamp", &header_page_ts_offset,
|
|
|
+ parse_header_field("timestamp", &header_page_ts_offset,
|
|
|
&header_page_ts_size);
|
|
|
- parse_header_field((char *)"commit", &header_page_size_offset,
|
|
|
+ parse_header_field("commit", &header_page_size_offset,
|
|
|
&header_page_size_size);
|
|
|
- parse_header_field((char *)"data", &header_page_data_offset,
|
|
|
+ parse_header_field("data", &header_page_data_offset,
|
|
|
&header_page_data_size);
|
|
|
|
|
|
return 0;
|
|
@@ -2909,6 +3179,9 @@ int parse_ftrace_file(char *buf, unsigned long size)
|
|
|
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.
|
|
@@ -2926,7 +3199,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;
|
|
@@ -2946,12 +3219,18 @@ int parse_event_file(char *buf, unsigned long size, char *system__unused __unuse
|
|
|
die("failed to read event id");
|
|
|
|
|
|
ret = event_read_format(event);
|
|
|
- if (ret < 0)
|
|
|
- die("failed to read event format");
|
|
|
+ if (ret < 0) {
|
|
|
+ warning("failed to read event format for %s", event->name);
|
|
|
+ goto event_failed;
|
|
|
+ }
|
|
|
|
|
|
ret = event_read_print(event);
|
|
|
- if (ret < 0)
|
|
|
- die("failed to read event print fmt");
|
|
|
+ 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)
|
|
@@ -2959,6 +3238,12 @@ int parse_event_file(char *buf, unsigned long size, char *system__unused __unuse
|
|
|
|
|
|
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)
|