aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/trace/trace_events.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/trace/trace_events.c')
-rw-r--r--kernel/trace/trace_events.c208
1 files changed, 141 insertions, 67 deletions
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index 53cffc0b0801..45a8968707aa 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -29,6 +29,8 @@ DEFINE_MUTEX(event_mutex);
29 29
30LIST_HEAD(ftrace_events); 30LIST_HEAD(ftrace_events);
31 31
32#define COMMON_FIELD_COUNT 5
33
32struct list_head * 34struct list_head *
33trace_get_fields(struct ftrace_event_call *event_call) 35trace_get_fields(struct ftrace_event_call *event_call)
34{ 36{
@@ -544,85 +546,155 @@ out:
544 return ret; 546 return ret;
545} 547}
546 548
547static ssize_t 549enum {
548event_format_read(struct file *filp, char __user *ubuf, size_t cnt, 550 FORMAT_HEADER = 1,
549 loff_t *ppos) 551 FORMAT_PRINTFMT = 2,
552};
553
554static void *f_next(struct seq_file *m, void *v, loff_t *pos)
550{ 555{
551 struct ftrace_event_call *call = filp->private_data; 556 struct ftrace_event_call *call = m->private;
552 struct ftrace_event_field *field; 557 struct ftrace_event_field *field;
553 struct list_head *head; 558 struct list_head *head;
554 struct trace_seq *s; 559 loff_t index = *pos;
555 int common_field_count = 5;
556 char *buf;
557 int r = 0;
558
559 if (*ppos)
560 return 0;
561 560
562 s = kmalloc(sizeof(*s), GFP_KERNEL); 561 (*pos)++;
563 if (!s)
564 return -ENOMEM;
565 562
566 trace_seq_init(s); 563 head = trace_get_fields(call);
567 564
568 trace_seq_printf(s, "name: %s\n", call->name); 565 switch ((unsigned long)v) {
569 trace_seq_printf(s, "ID: %d\n", call->event.type); 566 case FORMAT_HEADER:
570 trace_seq_printf(s, "format:\n");
571 567
572 head = trace_get_fields(call); 568 if (unlikely(list_empty(head)))
573 list_for_each_entry_reverse(field, head, link) { 569 return NULL;
574 /*
575 * Smartly shows the array type(except dynamic array).
576 * Normal:
577 * field:TYPE VAR
578 * If TYPE := TYPE[LEN], it is shown:
579 * field:TYPE VAR[LEN]
580 */
581 const char *array_descriptor = strchr(field->type, '[');
582
583 if (!strncmp(field->type, "__data_loc", 10))
584 array_descriptor = NULL;
585
586 if (!array_descriptor) {
587 r = trace_seq_printf(s, "\tfield:%s %s;\toffset:%u;"
588 "\tsize:%u;\tsigned:%d;\n",
589 field->type, field->name, field->offset,
590 field->size, !!field->is_signed);
591 } else {
592 r = trace_seq_printf(s, "\tfield:%.*s %s%s;\toffset:%u;"
593 "\tsize:%u;\tsigned:%d;\n",
594 (int)(array_descriptor - field->type),
595 field->type, field->name,
596 array_descriptor, field->offset,
597 field->size, !!field->is_signed);
598 }
599 570
600 if (--common_field_count == 0) 571 field = list_entry(head->prev, struct ftrace_event_field, link);
601 r = trace_seq_printf(s, "\n"); 572 return field;
602 573
603 if (!r) 574 case FORMAT_PRINTFMT:
604 break; 575 /* all done */
576 return NULL;
605 } 577 }
606 578
607 if (r) 579 /*
608 r = trace_seq_printf(s, "\nprint fmt: %s\n", 580 * To separate common fields from event fields, the
609 call->print_fmt); 581 * LSB is set on the first event field. Clear it in case.
582 */
583 v = (void *)((unsigned long)v & ~1L);
610 584
611 if (!r) { 585 field = v;
612 /* 586 if (field->link.prev == head)
613 * ug! The format output is bigger than a PAGE!! 587 return (void *)FORMAT_PRINTFMT;
614 */ 588
615 buf = "FORMAT TOO BIG\n"; 589 field = list_entry(field->link.prev, struct ftrace_event_field, link);
616 r = simple_read_from_buffer(ubuf, cnt, ppos, 590
617 buf, strlen(buf)); 591 /* Set the LSB to notify f_show to print an extra newline */
618 goto out; 592 if (index == COMMON_FIELD_COUNT)
593 field = (struct ftrace_event_field *)
594 ((unsigned long)field | 1);
595
596 return field;
597}
598
599static void *f_start(struct seq_file *m, loff_t *pos)
600{
601 loff_t l = 0;
602 void *p;
603
604 /* Start by showing the header */
605 if (!*pos)
606 return (void *)FORMAT_HEADER;
607
608 p = (void *)FORMAT_HEADER;
609 do {
610 p = f_next(m, p, &l);
611 } while (p && l < *pos);
612
613 return p;
614}
615
616static int f_show(struct seq_file *m, void *v)
617{
618 struct ftrace_event_call *call = m->private;
619 struct ftrace_event_field *field;
620 const char *array_descriptor;
621
622 switch ((unsigned long)v) {
623 case FORMAT_HEADER:
624 seq_printf(m, "name: %s\n", call->name);
625 seq_printf(m, "ID: %d\n", call->event.type);
626 seq_printf(m, "format:\n");
627 return 0;
628
629 case FORMAT_PRINTFMT:
630 seq_printf(m, "\nprint fmt: %s\n",
631 call->print_fmt);
632 return 0;
619 } 633 }
620 634
621 r = simple_read_from_buffer(ubuf, cnt, ppos, 635 /*
622 s->buffer, s->len); 636 * To separate common fields from event fields, the
623 out: 637 * LSB is set on the first event field. Clear it and
624 kfree(s); 638 * print a newline if it is set.
625 return r; 639 */
640 if ((unsigned long)v & 1) {
641 seq_putc(m, '\n');
642 v = (void *)((unsigned long)v & ~1L);
643 }
644
645 field = v;
646
647 /*
648 * Smartly shows the array type(except dynamic array).
649 * Normal:
650 * field:TYPE VAR
651 * If TYPE := TYPE[LEN], it is shown:
652 * field:TYPE VAR[LEN]
653 */
654 array_descriptor = strchr(field->type, '[');
655
656 if (!strncmp(field->type, "__data_loc", 10))
657 array_descriptor = NULL;
658
659 if (!array_descriptor)
660 seq_printf(m, "\tfield:%s %s;\toffset:%u;\tsize:%u;\tsigned:%d;\n",
661 field->type, field->name, field->offset,
662 field->size, !!field->is_signed);
663 else
664 seq_printf(m, "\tfield:%.*s %s%s;\toffset:%u;\tsize:%u;\tsigned:%d;\n",
665 (int)(array_descriptor - field->type),
666 field->type, field->name,
667 array_descriptor, field->offset,
668 field->size, !!field->is_signed);
669
670 return 0;
671}
672
673static void f_stop(struct seq_file *m, void *p)
674{
675}
676
677static const struct seq_operations trace_format_seq_ops = {
678 .start = f_start,
679 .next = f_next,
680 .stop = f_stop,
681 .show = f_show,
682};
683
684static int trace_format_open(struct inode *inode, struct file *file)
685{
686 struct ftrace_event_call *call = inode->i_private;
687 struct seq_file *m;
688 int ret;
689
690 ret = seq_open(file, &trace_format_seq_ops);
691 if (ret < 0)
692 return ret;
693
694 m = file->private_data;
695 m->private = call;
696
697 return 0;
626} 698}
627 699
628static ssize_t 700static ssize_t
@@ -820,8 +892,10 @@ static const struct file_operations ftrace_enable_fops = {
820}; 892};
821 893
822static const struct file_operations ftrace_event_format_fops = { 894static const struct file_operations ftrace_event_format_fops = {
823 .open = tracing_open_generic, 895 .open = trace_format_open,
824 .read = event_format_read, 896 .read = seq_read,
897 .llseek = seq_lseek,
898 .release = seq_release,
825}; 899};
826 900
827static const struct file_operations ftrace_event_id_fops = { 901static const struct file_operations ftrace_event_id_fops = {