diff options
Diffstat (limited to 'tools/lib')
-rw-r--r-- | tools/lib/traceevent/event-parse.c | 165 | ||||
-rw-r--r-- | tools/lib/traceevent/event-parse.h | 14 |
2 files changed, 136 insertions, 43 deletions
diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c index d1c2a6a4cd32..8f450adaa9c2 100644 --- a/tools/lib/traceevent/event-parse.c +++ b/tools/lib/traceevent/event-parse.c | |||
@@ -305,6 +305,11 @@ int pevent_register_comm(struct pevent *pevent, const char *comm, int pid) | |||
305 | return 0; | 305 | return 0; |
306 | } | 306 | } |
307 | 307 | ||
308 | void pevent_register_trace_clock(struct pevent *pevent, char *trace_clock) | ||
309 | { | ||
310 | pevent->trace_clock = trace_clock; | ||
311 | } | ||
312 | |||
308 | struct func_map { | 313 | struct func_map { |
309 | unsigned long long addr; | 314 | unsigned long long addr; |
310 | char *func; | 315 | char *func; |
@@ -599,10 +604,11 @@ find_printk(struct pevent *pevent, unsigned long long addr) | |||
599 | * This registers a string by the address it was stored in the kernel. | 604 | * This registers a string by the address it was stored in the kernel. |
600 | * The @fmt passed in is duplicated. | 605 | * The @fmt passed in is duplicated. |
601 | */ | 606 | */ |
602 | int pevent_register_print_string(struct pevent *pevent, char *fmt, | 607 | int pevent_register_print_string(struct pevent *pevent, const char *fmt, |
603 | unsigned long long addr) | 608 | unsigned long long addr) |
604 | { | 609 | { |
605 | struct printk_list *item = malloc(sizeof(*item)); | 610 | struct printk_list *item = malloc(sizeof(*item)); |
611 | char *p; | ||
606 | 612 | ||
607 | if (!item) | 613 | if (!item) |
608 | return -1; | 614 | return -1; |
@@ -610,10 +616,21 @@ int pevent_register_print_string(struct pevent *pevent, char *fmt, | |||
610 | item->next = pevent->printklist; | 616 | item->next = pevent->printklist; |
611 | item->addr = addr; | 617 | item->addr = addr; |
612 | 618 | ||
619 | /* Strip off quotes and '\n' from the end */ | ||
620 | if (fmt[0] == '"') | ||
621 | fmt++; | ||
613 | item->printk = strdup(fmt); | 622 | item->printk = strdup(fmt); |
614 | if (!item->printk) | 623 | if (!item->printk) |
615 | goto out_free; | 624 | goto out_free; |
616 | 625 | ||
626 | p = item->printk + strlen(item->printk) - 1; | ||
627 | if (*p == '"') | ||
628 | *p = 0; | ||
629 | |||
630 | p -= 2; | ||
631 | if (strcmp(p, "\\n") == 0) | ||
632 | *p = 0; | ||
633 | |||
617 | pevent->printklist = item; | 634 | pevent->printklist = item; |
618 | pevent->printk_count++; | 635 | pevent->printk_count++; |
619 | 636 | ||
@@ -3488,6 +3505,7 @@ static void print_str_arg(struct trace_seq *s, void *data, int size, | |||
3488 | struct pevent *pevent = event->pevent; | 3505 | struct pevent *pevent = event->pevent; |
3489 | struct print_flag_sym *flag; | 3506 | struct print_flag_sym *flag; |
3490 | struct format_field *field; | 3507 | struct format_field *field; |
3508 | struct printk_map *printk; | ||
3491 | unsigned long long val, fval; | 3509 | unsigned long long val, fval; |
3492 | unsigned long addr; | 3510 | unsigned long addr; |
3493 | char *str; | 3511 | char *str; |
@@ -3523,7 +3541,12 @@ static void print_str_arg(struct trace_seq *s, void *data, int size, | |||
3523 | if (!(field->flags & FIELD_IS_ARRAY) && | 3541 | if (!(field->flags & FIELD_IS_ARRAY) && |
3524 | field->size == pevent->long_size) { | 3542 | field->size == pevent->long_size) { |
3525 | addr = *(unsigned long *)(data + field->offset); | 3543 | addr = *(unsigned long *)(data + field->offset); |
3526 | trace_seq_printf(s, "%lx", addr); | 3544 | /* Check if it matches a print format */ |
3545 | printk = find_printk(pevent, addr); | ||
3546 | if (printk) | ||
3547 | trace_seq_puts(s, printk->printk); | ||
3548 | else | ||
3549 | trace_seq_printf(s, "%lx", addr); | ||
3527 | break; | 3550 | break; |
3528 | } | 3551 | } |
3529 | str = malloc(len + 1); | 3552 | str = malloc(len + 1); |
@@ -3565,15 +3588,23 @@ static void print_str_arg(struct trace_seq *s, void *data, int size, | |||
3565 | } | 3588 | } |
3566 | break; | 3589 | break; |
3567 | case PRINT_HEX: | 3590 | case PRINT_HEX: |
3568 | field = arg->hex.field->field.field; | 3591 | if (arg->hex.field->type == PRINT_DYNAMIC_ARRAY) { |
3569 | if (!field) { | 3592 | unsigned long offset; |
3570 | str = arg->hex.field->field.name; | 3593 | offset = pevent_read_number(pevent, |
3571 | field = pevent_find_any_field(event, str); | 3594 | data + arg->hex.field->dynarray.field->offset, |
3572 | if (!field) | 3595 | arg->hex.field->dynarray.field->size); |
3573 | goto out_warning_field; | 3596 | hex = data + (offset & 0xffff); |
3574 | arg->hex.field->field.field = field; | 3597 | } else { |
3598 | field = arg->hex.field->field.field; | ||
3599 | if (!field) { | ||
3600 | str = arg->hex.field->field.name; | ||
3601 | field = pevent_find_any_field(event, str); | ||
3602 | if (!field) | ||
3603 | goto out_warning_field; | ||
3604 | arg->hex.field->field.field = field; | ||
3605 | } | ||
3606 | hex = data + field->offset; | ||
3575 | } | 3607 | } |
3576 | hex = data + field->offset; | ||
3577 | len = eval_num_arg(data, size, event, arg->hex.size); | 3608 | len = eval_num_arg(data, size, event, arg->hex.size); |
3578 | for (i = 0; i < len; i++) { | 3609 | for (i = 0; i < len; i++) { |
3579 | if (i) | 3610 | if (i) |
@@ -3771,8 +3802,8 @@ static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struc | |||
3771 | if (asprintf(&arg->atom.atom, "%lld", ip) < 0) | 3802 | if (asprintf(&arg->atom.atom, "%lld", ip) < 0) |
3772 | goto out_free; | 3803 | goto out_free; |
3773 | 3804 | ||
3774 | /* skip the first "%pf : " */ | 3805 | /* skip the first "%pf: " */ |
3775 | for (ptr = fmt + 6, bptr = data + field->offset; | 3806 | for (ptr = fmt + 5, bptr = data + field->offset; |
3776 | bptr < data + size && *ptr; ptr++) { | 3807 | bptr < data + size && *ptr; ptr++) { |
3777 | int ls = 0; | 3808 | int ls = 0; |
3778 | 3809 | ||
@@ -3882,7 +3913,6 @@ get_bprint_format(void *data, int size __maybe_unused, | |||
3882 | struct format_field *field; | 3913 | struct format_field *field; |
3883 | struct printk_map *printk; | 3914 | struct printk_map *printk; |
3884 | char *format; | 3915 | char *format; |
3885 | char *p; | ||
3886 | 3916 | ||
3887 | field = pevent->bprint_fmt_field; | 3917 | field = pevent->bprint_fmt_field; |
3888 | 3918 | ||
@@ -3899,25 +3929,13 @@ get_bprint_format(void *data, int size __maybe_unused, | |||
3899 | 3929 | ||
3900 | printk = find_printk(pevent, addr); | 3930 | printk = find_printk(pevent, addr); |
3901 | if (!printk) { | 3931 | if (!printk) { |
3902 | if (asprintf(&format, "%%pf : (NO FORMAT FOUND at %llx)\n", addr) < 0) | 3932 | if (asprintf(&format, "%%pf: (NO FORMAT FOUND at %llx)\n", addr) < 0) |
3903 | return NULL; | 3933 | return NULL; |
3904 | return format; | 3934 | return format; |
3905 | } | 3935 | } |
3906 | 3936 | ||
3907 | p = printk->printk; | 3937 | if (asprintf(&format, "%s: %s", "%pf", printk->printk) < 0) |
3908 | /* Remove any quotes. */ | ||
3909 | if (*p == '"') | ||
3910 | p++; | ||
3911 | if (asprintf(&format, "%s : %s", "%pf", p) < 0) | ||
3912 | return NULL; | 3938 | return NULL; |
3913 | /* remove ending quotes and new line since we will add one too */ | ||
3914 | p = format + strlen(format) - 1; | ||
3915 | if (*p == '"') | ||
3916 | *p = 0; | ||
3917 | |||
3918 | p -= 2; | ||
3919 | if (strcmp(p, "\\n") == 0) | ||
3920 | *p = 0; | ||
3921 | 3939 | ||
3922 | return format; | 3940 | return format; |
3923 | } | 3941 | } |
@@ -3963,7 +3981,7 @@ static int is_printable_array(char *p, unsigned int len) | |||
3963 | unsigned int i; | 3981 | unsigned int i; |
3964 | 3982 | ||
3965 | for (i = 0; i < len && p[i]; i++) | 3983 | for (i = 0; i < len && p[i]; i++) |
3966 | if (!isprint(p[i])) | 3984 | if (!isprint(p[i]) && !isspace(p[i])) |
3967 | return 0; | 3985 | return 0; |
3968 | return 1; | 3986 | return 1; |
3969 | } | 3987 | } |
@@ -4428,11 +4446,11 @@ void pevent_event_info(struct trace_seq *s, struct event_format *event, | |||
4428 | { | 4446 | { |
4429 | int print_pretty = 1; | 4447 | int print_pretty = 1; |
4430 | 4448 | ||
4431 | if (event->pevent->print_raw) | 4449 | if (event->pevent->print_raw || (event->flags & EVENT_FL_PRINTRAW)) |
4432 | print_event_fields(s, record->data, record->size, event); | 4450 | print_event_fields(s, record->data, record->size, event); |
4433 | else { | 4451 | else { |
4434 | 4452 | ||
4435 | if (event->handler) | 4453 | if (event->handler && !(event->flags & EVENT_FL_NOHANDLE)) |
4436 | print_pretty = event->handler(s, record, event, | 4454 | print_pretty = event->handler(s, record, event, |
4437 | event->context); | 4455 | event->context); |
4438 | 4456 | ||
@@ -4443,8 +4461,21 @@ void pevent_event_info(struct trace_seq *s, struct event_format *event, | |||
4443 | trace_seq_terminate(s); | 4461 | trace_seq_terminate(s); |
4444 | } | 4462 | } |
4445 | 4463 | ||
4464 | static bool is_timestamp_in_us(char *trace_clock, bool use_trace_clock) | ||
4465 | { | ||
4466 | if (!use_trace_clock) | ||
4467 | return true; | ||
4468 | |||
4469 | if (!strcmp(trace_clock, "local") || !strcmp(trace_clock, "global") | ||
4470 | || !strcmp(trace_clock, "uptime") || !strcmp(trace_clock, "perf")) | ||
4471 | return true; | ||
4472 | |||
4473 | /* trace_clock is setting in tsc or counter mode */ | ||
4474 | return false; | ||
4475 | } | ||
4476 | |||
4446 | void pevent_print_event(struct pevent *pevent, struct trace_seq *s, | 4477 | void pevent_print_event(struct pevent *pevent, struct trace_seq *s, |
4447 | struct pevent_record *record) | 4478 | struct pevent_record *record, bool use_trace_clock) |
4448 | { | 4479 | { |
4449 | static const char *spaces = " "; /* 20 spaces */ | 4480 | static const char *spaces = " "; /* 20 spaces */ |
4450 | struct event_format *event; | 4481 | struct event_format *event; |
@@ -4457,9 +4488,14 @@ void pevent_print_event(struct pevent *pevent, struct trace_seq *s, | |||
4457 | int pid; | 4488 | int pid; |
4458 | int len; | 4489 | int len; |
4459 | int p; | 4490 | int p; |
4491 | bool use_usec_format; | ||
4460 | 4492 | ||
4461 | secs = record->ts / NSECS_PER_SEC; | 4493 | use_usec_format = is_timestamp_in_us(pevent->trace_clock, |
4462 | nsecs = record->ts - secs * NSECS_PER_SEC; | 4494 | use_trace_clock); |
4495 | if (use_usec_format) { | ||
4496 | secs = record->ts / NSECS_PER_SEC; | ||
4497 | nsecs = record->ts - secs * NSECS_PER_SEC; | ||
4498 | } | ||
4463 | 4499 | ||
4464 | if (record->size < 0) { | 4500 | if (record->size < 0) { |
4465 | do_warning("ug! negative record size %d", record->size); | 4501 | do_warning("ug! negative record size %d", record->size); |
@@ -4484,15 +4520,20 @@ void pevent_print_event(struct pevent *pevent, struct trace_seq *s, | |||
4484 | } else | 4520 | } else |
4485 | trace_seq_printf(s, "%16s-%-5d [%03d]", comm, pid, record->cpu); | 4521 | trace_seq_printf(s, "%16s-%-5d [%03d]", comm, pid, record->cpu); |
4486 | 4522 | ||
4487 | if (pevent->flags & PEVENT_NSEC_OUTPUT) { | 4523 | if (use_usec_format) { |
4488 | usecs = nsecs; | 4524 | if (pevent->flags & PEVENT_NSEC_OUTPUT) { |
4489 | p = 9; | 4525 | usecs = nsecs; |
4490 | } else { | 4526 | p = 9; |
4491 | usecs = (nsecs + 500) / NSECS_PER_USEC; | 4527 | } else { |
4492 | p = 6; | 4528 | usecs = (nsecs + 500) / NSECS_PER_USEC; |
4493 | } | 4529 | p = 6; |
4530 | } | ||
4494 | 4531 | ||
4495 | trace_seq_printf(s, " %5lu.%0*lu: %s: ", secs, p, usecs, event->name); | 4532 | trace_seq_printf(s, " %5lu.%0*lu: %s: ", |
4533 | secs, p, usecs, event->name); | ||
4534 | } else | ||
4535 | trace_seq_printf(s, " %12llu: %s: ", | ||
4536 | record->ts, event->name); | ||
4496 | 4537 | ||
4497 | /* Space out the event names evenly. */ | 4538 | /* Space out the event names evenly. */ |
4498 | len = strlen(event->name); | 4539 | len = strlen(event->name); |
@@ -5326,6 +5367,48 @@ int pevent_print_num_field(struct trace_seq *s, const char *fmt, | |||
5326 | return -1; | 5367 | return -1; |
5327 | } | 5368 | } |
5328 | 5369 | ||
5370 | /** | ||
5371 | * pevent_print_func_field - print a field and a format for function pointers | ||
5372 | * @s: The seq to print to | ||
5373 | * @fmt: The printf format to print the field with. | ||
5374 | * @event: the event that the field is for | ||
5375 | * @name: The name of the field | ||
5376 | * @record: The record with the field name. | ||
5377 | * @err: print default error if failed. | ||
5378 | * | ||
5379 | * Returns: 0 on success, -1 field not found, or 1 if buffer is full. | ||
5380 | */ | ||
5381 | int pevent_print_func_field(struct trace_seq *s, const char *fmt, | ||
5382 | struct event_format *event, const char *name, | ||
5383 | struct pevent_record *record, int err) | ||
5384 | { | ||
5385 | struct format_field *field = pevent_find_field(event, name); | ||
5386 | struct pevent *pevent = event->pevent; | ||
5387 | unsigned long long val; | ||
5388 | struct func_map *func; | ||
5389 | char tmp[128]; | ||
5390 | |||
5391 | if (!field) | ||
5392 | goto failed; | ||
5393 | |||
5394 | if (pevent_read_number_field(field, record->data, &val)) | ||
5395 | goto failed; | ||
5396 | |||
5397 | func = find_func(pevent, val); | ||
5398 | |||
5399 | if (func) | ||
5400 | snprintf(tmp, 128, "%s/0x%llx", func->func, func->addr - val); | ||
5401 | else | ||
5402 | sprintf(tmp, "0x%08llx", val); | ||
5403 | |||
5404 | return trace_seq_printf(s, fmt, tmp); | ||
5405 | |||
5406 | failed: | ||
5407 | if (err) | ||
5408 | trace_seq_printf(s, "CAN'T FIND FIELD \"%s\"", name); | ||
5409 | return -1; | ||
5410 | } | ||
5411 | |||
5329 | static void free_func_handle(struct pevent_function_handler *func) | 5412 | static void free_func_handle(struct pevent_function_handler *func) |
5330 | { | 5413 | { |
5331 | struct pevent_func_params *params; | 5414 | struct pevent_func_params *params; |
diff --git a/tools/lib/traceevent/event-parse.h b/tools/lib/traceevent/event-parse.h index c37b2026d04a..8d73d2594f65 100644 --- a/tools/lib/traceevent/event-parse.h +++ b/tools/lib/traceevent/event-parse.h | |||
@@ -20,6 +20,7 @@ | |||
20 | #ifndef _PARSE_EVENTS_H | 20 | #ifndef _PARSE_EVENTS_H |
21 | #define _PARSE_EVENTS_H | 21 | #define _PARSE_EVENTS_H |
22 | 22 | ||
23 | #include <stdbool.h> | ||
23 | #include <stdarg.h> | 24 | #include <stdarg.h> |
24 | #include <regex.h> | 25 | #include <regex.h> |
25 | 26 | ||
@@ -307,6 +308,8 @@ enum { | |||
307 | EVENT_FL_ISBPRINT = 0x04, | 308 | EVENT_FL_ISBPRINT = 0x04, |
308 | EVENT_FL_ISFUNCENT = 0x10, | 309 | EVENT_FL_ISFUNCENT = 0x10, |
309 | EVENT_FL_ISFUNCRET = 0x20, | 310 | EVENT_FL_ISFUNCRET = 0x20, |
311 | EVENT_FL_NOHANDLE = 0x40, | ||
312 | EVENT_FL_PRINTRAW = 0x80, | ||
310 | 313 | ||
311 | EVENT_FL_FAILED = 0x80000000 | 314 | EVENT_FL_FAILED = 0x80000000 |
312 | }; | 315 | }; |
@@ -450,6 +453,8 @@ struct pevent { | |||
450 | 453 | ||
451 | /* cache */ | 454 | /* cache */ |
452 | struct event_format *last_event; | 455 | struct event_format *last_event; |
456 | |||
457 | char *trace_clock; | ||
453 | }; | 458 | }; |
454 | 459 | ||
455 | static inline void pevent_set_flag(struct pevent *pevent, int flag) | 460 | static inline void pevent_set_flag(struct pevent *pevent, int flag) |
@@ -527,14 +532,15 @@ enum trace_flag_type { | |||
527 | }; | 532 | }; |
528 | 533 | ||
529 | int pevent_register_comm(struct pevent *pevent, const char *comm, int pid); | 534 | int pevent_register_comm(struct pevent *pevent, const char *comm, int pid); |
535 | void pevent_register_trace_clock(struct pevent *pevent, char *trace_clock); | ||
530 | int pevent_register_function(struct pevent *pevent, char *name, | 536 | int pevent_register_function(struct pevent *pevent, char *name, |
531 | unsigned long long addr, char *mod); | 537 | unsigned long long addr, char *mod); |
532 | int pevent_register_print_string(struct pevent *pevent, char *fmt, | 538 | int pevent_register_print_string(struct pevent *pevent, const char *fmt, |
533 | unsigned long long addr); | 539 | unsigned long long addr); |
534 | int pevent_pid_is_registered(struct pevent *pevent, int pid); | 540 | int pevent_pid_is_registered(struct pevent *pevent, int pid); |
535 | 541 | ||
536 | void pevent_print_event(struct pevent *pevent, struct trace_seq *s, | 542 | void pevent_print_event(struct pevent *pevent, struct trace_seq *s, |
537 | struct pevent_record *record); | 543 | struct pevent_record *record, bool use_trace_clock); |
538 | 544 | ||
539 | int pevent_parse_header_page(struct pevent *pevent, char *buf, unsigned long size, | 545 | int pevent_parse_header_page(struct pevent *pevent, char *buf, unsigned long size, |
540 | int long_size); | 546 | int long_size); |
@@ -563,6 +569,10 @@ int pevent_print_num_field(struct trace_seq *s, const char *fmt, | |||
563 | struct event_format *event, const char *name, | 569 | struct event_format *event, const char *name, |
564 | struct pevent_record *record, int err); | 570 | struct pevent_record *record, int err); |
565 | 571 | ||
572 | int pevent_print_func_field(struct trace_seq *s, const char *fmt, | ||
573 | struct event_format *event, const char *name, | ||
574 | struct pevent_record *record, int err); | ||
575 | |||
566 | int pevent_register_event_handler(struct pevent *pevent, int id, | 576 | int pevent_register_event_handler(struct pevent *pevent, int id, |
567 | const char *sys_name, const char *event_name, | 577 | const char *sys_name, const char *event_name, |
568 | pevent_event_handler_func func, void *context); | 578 | pevent_event_handler_func func, void *context); |