diff options
Diffstat (limited to 'kernel/trace')
| -rw-r--r-- | kernel/trace/ftrace.c | 19 | ||||
| -rw-r--r-- | kernel/trace/ring_buffer.c | 5 | ||||
| -rw-r--r-- | kernel/trace/trace.c | 11 | ||||
| -rw-r--r-- | kernel/trace/trace_event_perf.c | 3 | ||||
| -rw-r--r-- | kernel/trace/trace_events.c | 207 | ||||
| -rw-r--r-- | kernel/trace/trace_functions_graph.c | 10 | ||||
| -rw-r--r-- | kernel/trace/trace_kprobe.c | 43 | ||||
| -rw-r--r-- | kernel/trace/trace_stack.c | 2 |
8 files changed, 206 insertions, 94 deletions
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 0d88ce9b9fb8..fa7ece649fe1 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c | |||
| @@ -381,12 +381,19 @@ static int function_stat_show(struct seq_file *m, void *v) | |||
| 381 | { | 381 | { |
| 382 | struct ftrace_profile *rec = v; | 382 | struct ftrace_profile *rec = v; |
| 383 | char str[KSYM_SYMBOL_LEN]; | 383 | char str[KSYM_SYMBOL_LEN]; |
| 384 | int ret = 0; | ||
| 384 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | 385 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER |
| 385 | static DEFINE_MUTEX(mutex); | ||
| 386 | static struct trace_seq s; | 386 | static struct trace_seq s; |
| 387 | unsigned long long avg; | 387 | unsigned long long avg; |
| 388 | unsigned long long stddev; | 388 | unsigned long long stddev; |
| 389 | #endif | 389 | #endif |
| 390 | mutex_lock(&ftrace_profile_lock); | ||
| 391 | |||
| 392 | /* we raced with function_profile_reset() */ | ||
| 393 | if (unlikely(rec->counter == 0)) { | ||
| 394 | ret = -EBUSY; | ||
| 395 | goto out; | ||
| 396 | } | ||
| 390 | 397 | ||
| 391 | kallsyms_lookup(rec->ip, NULL, NULL, NULL, str); | 398 | kallsyms_lookup(rec->ip, NULL, NULL, NULL, str); |
| 392 | seq_printf(m, " %-30.30s %10lu", str, rec->counter); | 399 | seq_printf(m, " %-30.30s %10lu", str, rec->counter); |
| @@ -408,7 +415,6 @@ static int function_stat_show(struct seq_file *m, void *v) | |||
| 408 | do_div(stddev, (rec->counter - 1) * 1000); | 415 | do_div(stddev, (rec->counter - 1) * 1000); |
| 409 | } | 416 | } |
| 410 | 417 | ||
| 411 | mutex_lock(&mutex); | ||
| 412 | trace_seq_init(&s); | 418 | trace_seq_init(&s); |
| 413 | trace_print_graph_duration(rec->time, &s); | 419 | trace_print_graph_duration(rec->time, &s); |
| 414 | trace_seq_puts(&s, " "); | 420 | trace_seq_puts(&s, " "); |
| @@ -416,11 +422,12 @@ static int function_stat_show(struct seq_file *m, void *v) | |||
| 416 | trace_seq_puts(&s, " "); | 422 | trace_seq_puts(&s, " "); |
| 417 | trace_print_graph_duration(stddev, &s); | 423 | trace_print_graph_duration(stddev, &s); |
| 418 | trace_print_seq(m, &s); | 424 | trace_print_seq(m, &s); |
| 419 | mutex_unlock(&mutex); | ||
| 420 | #endif | 425 | #endif |
| 421 | seq_putc(m, '\n'); | 426 | seq_putc(m, '\n'); |
| 427 | out: | ||
| 428 | mutex_unlock(&ftrace_profile_lock); | ||
| 422 | 429 | ||
| 423 | return 0; | 430 | return ret; |
| 424 | } | 431 | } |
| 425 | 432 | ||
| 426 | static void ftrace_profile_reset(struct ftrace_profile_stat *stat) | 433 | static void ftrace_profile_reset(struct ftrace_profile_stat *stat) |
| @@ -1503,6 +1510,8 @@ static void *t_start(struct seq_file *m, loff_t *pos) | |||
| 1503 | if (*pos > 0) | 1510 | if (*pos > 0) |
| 1504 | return t_hash_start(m, pos); | 1511 | return t_hash_start(m, pos); |
| 1505 | iter->flags |= FTRACE_ITER_PRINTALL; | 1512 | iter->flags |= FTRACE_ITER_PRINTALL; |
| 1513 | /* reset in case of seek/pread */ | ||
| 1514 | iter->flags &= ~FTRACE_ITER_HASH; | ||
| 1506 | return iter; | 1515 | return iter; |
| 1507 | } | 1516 | } |
| 1508 | 1517 | ||
| @@ -2409,7 +2418,7 @@ static const struct file_operations ftrace_filter_fops = { | |||
| 2409 | .open = ftrace_filter_open, | 2418 | .open = ftrace_filter_open, |
| 2410 | .read = seq_read, | 2419 | .read = seq_read, |
| 2411 | .write = ftrace_filter_write, | 2420 | .write = ftrace_filter_write, |
| 2412 | .llseek = ftrace_regex_lseek, | 2421 | .llseek = no_llseek, |
| 2413 | .release = ftrace_filter_release, | 2422 | .release = ftrace_filter_release, |
| 2414 | }; | 2423 | }; |
| 2415 | 2424 | ||
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index 3632ce87674f..492197e2f86c 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c | |||
| @@ -2985,13 +2985,11 @@ static void rb_advance_reader(struct ring_buffer_per_cpu *cpu_buffer) | |||
| 2985 | 2985 | ||
| 2986 | static void rb_advance_iter(struct ring_buffer_iter *iter) | 2986 | static void rb_advance_iter(struct ring_buffer_iter *iter) |
| 2987 | { | 2987 | { |
| 2988 | struct ring_buffer *buffer; | ||
| 2989 | struct ring_buffer_per_cpu *cpu_buffer; | 2988 | struct ring_buffer_per_cpu *cpu_buffer; |
| 2990 | struct ring_buffer_event *event; | 2989 | struct ring_buffer_event *event; |
| 2991 | unsigned length; | 2990 | unsigned length; |
| 2992 | 2991 | ||
| 2993 | cpu_buffer = iter->cpu_buffer; | 2992 | cpu_buffer = iter->cpu_buffer; |
| 2994 | buffer = cpu_buffer->buffer; | ||
| 2995 | 2993 | ||
| 2996 | /* | 2994 | /* |
| 2997 | * Check if we are at the end of the buffer. | 2995 | * Check if we are at the end of the buffer. |
| @@ -3846,6 +3844,9 @@ int ring_buffer_read_page(struct ring_buffer *buffer, | |||
| 3846 | rpos = reader->read; | 3844 | rpos = reader->read; |
| 3847 | pos += size; | 3845 | pos += size; |
| 3848 | 3846 | ||
| 3847 | if (rpos >= commit) | ||
| 3848 | break; | ||
| 3849 | |||
| 3849 | event = rb_reader_event(cpu_buffer); | 3850 | event = rb_reader_event(cpu_buffer); |
| 3850 | size = rb_event_length(event); | 3851 | size = rb_event_length(event); |
| 3851 | } while (len > size); | 3852 | } while (len > size); |
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index ba14a22be4cc..9ec59f541156 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c | |||
| @@ -3463,6 +3463,7 @@ tracing_mark_write(struct file *filp, const char __user *ubuf, | |||
| 3463 | size_t cnt, loff_t *fpos) | 3463 | size_t cnt, loff_t *fpos) |
| 3464 | { | 3464 | { |
| 3465 | char *buf; | 3465 | char *buf; |
| 3466 | size_t written; | ||
| 3466 | 3467 | ||
| 3467 | if (tracing_disabled) | 3468 | if (tracing_disabled) |
| 3468 | return -EINVAL; | 3469 | return -EINVAL; |
| @@ -3484,11 +3485,15 @@ tracing_mark_write(struct file *filp, const char __user *ubuf, | |||
| 3484 | } else | 3485 | } else |
| 3485 | buf[cnt] = '\0'; | 3486 | buf[cnt] = '\0'; |
| 3486 | 3487 | ||
| 3487 | cnt = mark_printk("%s", buf); | 3488 | written = mark_printk("%s", buf); |
| 3488 | kfree(buf); | 3489 | kfree(buf); |
| 3489 | *fpos += cnt; | 3490 | *fpos += written; |
| 3490 | 3491 | ||
| 3491 | return cnt; | 3492 | /* don't tell userspace we wrote more - it might confuse them */ |
| 3493 | if (written > cnt) | ||
| 3494 | written = cnt; | ||
| 3495 | |||
| 3496 | return written; | ||
| 3492 | } | 3497 | } |
| 3493 | 3498 | ||
| 3494 | static int tracing_clock_show(struct seq_file *m, void *v) | 3499 | static int tracing_clock_show(struct seq_file *m, void *v) |
diff --git a/kernel/trace/trace_event_perf.c b/kernel/trace/trace_event_perf.c index 000e6e85b445..31cc4cb0dbf2 100644 --- a/kernel/trace/trace_event_perf.c +++ b/kernel/trace/trace_event_perf.c | |||
| @@ -91,6 +91,8 @@ int perf_trace_init(struct perf_event *p_event) | |||
| 91 | tp_event->class && tp_event->class->reg && | 91 | tp_event->class && tp_event->class->reg && |
| 92 | try_module_get(tp_event->mod)) { | 92 | try_module_get(tp_event->mod)) { |
| 93 | ret = perf_trace_event_init(tp_event, p_event); | 93 | ret = perf_trace_event_init(tp_event, p_event); |
| 94 | if (ret) | ||
| 95 | module_put(tp_event->mod); | ||
| 94 | break; | 96 | break; |
| 95 | } | 97 | } |
| 96 | } | 98 | } |
| @@ -146,6 +148,7 @@ void perf_trace_destroy(struct perf_event *p_event) | |||
| 146 | } | 148 | } |
| 147 | } | 149 | } |
| 148 | out: | 150 | out: |
| 151 | module_put(tp_event->mod); | ||
| 149 | mutex_unlock(&event_mutex); | 152 | mutex_unlock(&event_mutex); |
| 150 | } | 153 | } |
| 151 | 154 | ||
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index 09b4fa6e4d3b..4c758f146328 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c | |||
| @@ -598,88 +598,165 @@ out: | |||
| 598 | return ret; | 598 | return ret; |
| 599 | } | 599 | } |
| 600 | 600 | ||
| 601 | static void print_event_fields(struct trace_seq *s, struct list_head *head) | 601 | enum { |
| 602 | FORMAT_HEADER = 1, | ||
| 603 | FORMAT_PRINTFMT = 2, | ||
| 604 | }; | ||
| 605 | |||
| 606 | static void *f_next(struct seq_file *m, void *v, loff_t *pos) | ||
| 602 | { | 607 | { |
| 608 | struct ftrace_event_call *call = m->private; | ||
| 603 | struct ftrace_event_field *field; | 609 | struct ftrace_event_field *field; |
| 610 | struct list_head *head; | ||
| 604 | 611 | ||
| 605 | list_for_each_entry_reverse(field, head, link) { | 612 | (*pos)++; |
| 606 | /* | ||
| 607 | * Smartly shows the array type(except dynamic array). | ||
| 608 | * Normal: | ||
| 609 | * field:TYPE VAR | ||
| 610 | * If TYPE := TYPE[LEN], it is shown: | ||
| 611 | * field:TYPE VAR[LEN] | ||
| 612 | */ | ||
| 613 | const char *array_descriptor = strchr(field->type, '['); | ||
| 614 | 613 | ||
| 615 | if (!strncmp(field->type, "__data_loc", 10)) | 614 | switch ((unsigned long)v) { |
| 616 | array_descriptor = NULL; | 615 | case FORMAT_HEADER: |
| 616 | head = &ftrace_common_fields; | ||
| 617 | 617 | ||
| 618 | if (!array_descriptor) { | 618 | if (unlikely(list_empty(head))) |
| 619 | trace_seq_printf(s, "\tfield:%s %s;\toffset:%u;" | 619 | return NULL; |
| 620 | "\tsize:%u;\tsigned:%d;\n", | 620 | |
| 621 | field->type, field->name, field->offset, | 621 | field = list_entry(head->prev, struct ftrace_event_field, link); |
| 622 | field->size, !!field->is_signed); | 622 | return field; |
| 623 | } else { | 623 | |
| 624 | trace_seq_printf(s, "\tfield:%.*s %s%s;\toffset:%u;" | 624 | case FORMAT_PRINTFMT: |
| 625 | "\tsize:%u;\tsigned:%d;\n", | 625 | /* all done */ |
| 626 | (int)(array_descriptor - field->type), | 626 | return NULL; |
| 627 | field->type, field->name, | 627 | } |
| 628 | array_descriptor, field->offset, | 628 | |
| 629 | field->size, !!field->is_signed); | 629 | head = trace_get_fields(call); |
| 630 | } | 630 | |
| 631 | /* | ||
| 632 | * To separate common fields from event fields, the | ||
| 633 | * LSB is set on the first event field. Clear it in case. | ||
| 634 | */ | ||
| 635 | v = (void *)((unsigned long)v & ~1L); | ||
| 636 | |||
| 637 | field = v; | ||
| 638 | /* | ||
| 639 | * If this is a common field, and at the end of the list, then | ||
| 640 | * continue with main list. | ||
| 641 | */ | ||
| 642 | if (field->link.prev == &ftrace_common_fields) { | ||
| 643 | if (unlikely(list_empty(head))) | ||
| 644 | return NULL; | ||
| 645 | field = list_entry(head->prev, struct ftrace_event_field, link); | ||
| 646 | /* Set the LSB to notify f_show to print an extra newline */ | ||
| 647 | field = (struct ftrace_event_field *) | ||
| 648 | ((unsigned long)field | 1); | ||
| 649 | return field; | ||
| 631 | } | 650 | } |
| 651 | |||
| 652 | /* If we are done tell f_show to print the format */ | ||
| 653 | if (field->link.prev == head) | ||
| 654 | return (void *)FORMAT_PRINTFMT; | ||
| 655 | |||
| 656 | field = list_entry(field->link.prev, struct ftrace_event_field, link); | ||
| 657 | |||
| 658 | return field; | ||
| 632 | } | 659 | } |
| 633 | 660 | ||
| 634 | static ssize_t | 661 | static void *f_start(struct seq_file *m, loff_t *pos) |
| 635 | event_format_read(struct file *filp, char __user *ubuf, size_t cnt, | ||
| 636 | loff_t *ppos) | ||
| 637 | { | 662 | { |
| 638 | struct ftrace_event_call *call = filp->private_data; | 663 | loff_t l = 0; |
| 639 | struct list_head *head; | 664 | void *p; |
| 640 | struct trace_seq *s; | ||
| 641 | char *buf; | ||
| 642 | int r; | ||
| 643 | 665 | ||
| 644 | if (*ppos) | 666 | /* Start by showing the header */ |
| 667 | if (!*pos) | ||
| 668 | return (void *)FORMAT_HEADER; | ||
| 669 | |||
| 670 | p = (void *)FORMAT_HEADER; | ||
| 671 | do { | ||
| 672 | p = f_next(m, p, &l); | ||
| 673 | } while (p && l < *pos); | ||
| 674 | |||
| 675 | return p; | ||
| 676 | } | ||
| 677 | |||
| 678 | static int f_show(struct seq_file *m, void *v) | ||
| 679 | { | ||
| 680 | struct ftrace_event_call *call = m->private; | ||
| 681 | struct ftrace_event_field *field; | ||
| 682 | const char *array_descriptor; | ||
| 683 | |||
| 684 | switch ((unsigned long)v) { | ||
| 685 | case FORMAT_HEADER: | ||
| 686 | seq_printf(m, "name: %s\n", call->name); | ||
| 687 | seq_printf(m, "ID: %d\n", call->event.type); | ||
| 688 | seq_printf(m, "format:\n"); | ||
| 645 | return 0; | 689 | return 0; |
| 646 | 690 | ||
| 647 | s = kmalloc(sizeof(*s), GFP_KERNEL); | 691 | case FORMAT_PRINTFMT: |
| 648 | if (!s) | 692 | seq_printf(m, "\nprint fmt: %s\n", |
| 649 | return -ENOMEM; | 693 | call->print_fmt); |
| 694 | return 0; | ||
| 695 | } | ||
| 650 | 696 | ||
| 651 | trace_seq_init(s); | 697 | /* |
| 698 | * To separate common fields from event fields, the | ||
| 699 | * LSB is set on the first event field. Clear it and | ||
| 700 | * print a newline if it is set. | ||
| 701 | */ | ||
| 702 | if ((unsigned long)v & 1) { | ||
| 703 | seq_putc(m, '\n'); | ||
| 704 | v = (void *)((unsigned long)v & ~1L); | ||
| 705 | } | ||
| 652 | 706 | ||
| 653 | trace_seq_printf(s, "name: %s\n", call->name); | 707 | field = v; |
| 654 | trace_seq_printf(s, "ID: %d\n", call->event.type); | ||
| 655 | trace_seq_printf(s, "format:\n"); | ||
| 656 | 708 | ||
| 657 | /* print common fields */ | 709 | /* |
| 658 | print_event_fields(s, &ftrace_common_fields); | 710 | * Smartly shows the array type(except dynamic array). |
| 711 | * Normal: | ||
| 712 | * field:TYPE VAR | ||
| 713 | * If TYPE := TYPE[LEN], it is shown: | ||
| 714 | * field:TYPE VAR[LEN] | ||
| 715 | */ | ||
| 716 | array_descriptor = strchr(field->type, '['); | ||
| 659 | 717 | ||
| 660 | trace_seq_putc(s, '\n'); | 718 | if (!strncmp(field->type, "__data_loc", 10)) |
| 719 | array_descriptor = NULL; | ||
| 661 | 720 | ||
| 662 | /* print event specific fields */ | 721 | if (!array_descriptor) |
| 663 | head = trace_get_fields(call); | 722 | seq_printf(m, "\tfield:%s %s;\toffset:%u;\tsize:%u;\tsigned:%d;\n", |
| 664 | print_event_fields(s, head); | 723 | field->type, field->name, field->offset, |
| 724 | field->size, !!field->is_signed); | ||
| 725 | else | ||
| 726 | seq_printf(m, "\tfield:%.*s %s%s;\toffset:%u;\tsize:%u;\tsigned:%d;\n", | ||
| 727 | (int)(array_descriptor - field->type), | ||
| 728 | field->type, field->name, | ||
| 729 | array_descriptor, field->offset, | ||
| 730 | field->size, !!field->is_signed); | ||
| 665 | 731 | ||
| 666 | r = trace_seq_printf(s, "\nprint fmt: %s\n", call->print_fmt); | 732 | return 0; |
| 733 | } | ||
| 667 | 734 | ||
| 668 | if (!r) { | 735 | static void f_stop(struct seq_file *m, void *p) |
| 669 | /* | 736 | { |
| 670 | * ug! The format output is bigger than a PAGE!! | 737 | } |
| 671 | */ | ||
| 672 | buf = "FORMAT TOO BIG\n"; | ||
| 673 | r = simple_read_from_buffer(ubuf, cnt, ppos, | ||
| 674 | buf, strlen(buf)); | ||
| 675 | goto out; | ||
| 676 | } | ||
| 677 | 738 | ||
| 678 | r = simple_read_from_buffer(ubuf, cnt, ppos, | 739 | static const struct seq_operations trace_format_seq_ops = { |
| 679 | s->buffer, s->len); | 740 | .start = f_start, |
| 680 | out: | 741 | .next = f_next, |
| 681 | kfree(s); | 742 | .stop = f_stop, |
| 682 | return r; | 743 | .show = f_show, |
| 744 | }; | ||
| 745 | |||
| 746 | static int trace_format_open(struct inode *inode, struct file *file) | ||
| 747 | { | ||
| 748 | struct ftrace_event_call *call = inode->i_private; | ||
| 749 | struct seq_file *m; | ||
| 750 | int ret; | ||
| 751 | |||
| 752 | ret = seq_open(file, &trace_format_seq_ops); | ||
| 753 | if (ret < 0) | ||
| 754 | return ret; | ||
| 755 | |||
| 756 | m = file->private_data; | ||
| 757 | m->private = call; | ||
| 758 | |||
| 759 | return 0; | ||
| 683 | } | 760 | } |
| 684 | 761 | ||
| 685 | static ssize_t | 762 | static ssize_t |
| @@ -877,8 +954,10 @@ static const struct file_operations ftrace_enable_fops = { | |||
| 877 | }; | 954 | }; |
| 878 | 955 | ||
| 879 | static const struct file_operations ftrace_event_format_fops = { | 956 | static const struct file_operations ftrace_event_format_fops = { |
| 880 | .open = tracing_open_generic, | 957 | .open = trace_format_open, |
| 881 | .read = event_format_read, | 958 | .read = seq_read, |
| 959 | .llseek = seq_lseek, | ||
| 960 | .release = seq_release, | ||
| 882 | }; | 961 | }; |
| 883 | 962 | ||
| 884 | static const struct file_operations ftrace_event_id_fops = { | 963 | static const struct file_operations ftrace_event_id_fops = { |
diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c index 6bff23625781..6f233698518e 100644 --- a/kernel/trace/trace_functions_graph.c +++ b/kernel/trace/trace_functions_graph.c | |||
| @@ -507,7 +507,15 @@ get_return_for_leaf(struct trace_iterator *iter, | |||
| 507 | * if the output fails. | 507 | * if the output fails. |
| 508 | */ | 508 | */ |
| 509 | data->ent = *curr; | 509 | data->ent = *curr; |
| 510 | data->ret = *next; | 510 | /* |
| 511 | * If the next event is not a return type, then | ||
| 512 | * we only care about what type it is. Otherwise we can | ||
| 513 | * safely copy the entire event. | ||
| 514 | */ | ||
| 515 | if (next->ent.type == TRACE_GRAPH_RET) | ||
| 516 | data->ret = *next; | ||
| 517 | else | ||
| 518 | data->ret.ent.type = next->ent.type; | ||
| 511 | } | 519 | } |
| 512 | } | 520 | } |
| 513 | 521 | ||
diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index 8b27c9849b42..544301d29dee 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c | |||
| @@ -514,8 +514,8 @@ static int kprobe_dispatcher(struct kprobe *kp, struct pt_regs *regs); | |||
| 514 | static int kretprobe_dispatcher(struct kretprobe_instance *ri, | 514 | static int kretprobe_dispatcher(struct kretprobe_instance *ri, |
| 515 | struct pt_regs *regs); | 515 | struct pt_regs *regs); |
| 516 | 516 | ||
| 517 | /* Check the name is good for event/group */ | 517 | /* Check the name is good for event/group/fields */ |
| 518 | static int check_event_name(const char *name) | 518 | static int is_good_name(const char *name) |
| 519 | { | 519 | { |
| 520 | if (!isalpha(*name) && *name != '_') | 520 | if (!isalpha(*name) && *name != '_') |
| 521 | return 0; | 521 | return 0; |
| @@ -557,7 +557,7 @@ static struct trace_probe *alloc_trace_probe(const char *group, | |||
| 557 | else | 557 | else |
| 558 | tp->rp.kp.pre_handler = kprobe_dispatcher; | 558 | tp->rp.kp.pre_handler = kprobe_dispatcher; |
| 559 | 559 | ||
| 560 | if (!event || !check_event_name(event)) { | 560 | if (!event || !is_good_name(event)) { |
| 561 | ret = -EINVAL; | 561 | ret = -EINVAL; |
| 562 | goto error; | 562 | goto error; |
| 563 | } | 563 | } |
| @@ -567,7 +567,7 @@ static struct trace_probe *alloc_trace_probe(const char *group, | |||
| 567 | if (!tp->call.name) | 567 | if (!tp->call.name) |
| 568 | goto error; | 568 | goto error; |
| 569 | 569 | ||
| 570 | if (!group || !check_event_name(group)) { | 570 | if (!group || !is_good_name(group)) { |
| 571 | ret = -EINVAL; | 571 | ret = -EINVAL; |
| 572 | goto error; | 572 | goto error; |
| 573 | } | 573 | } |
| @@ -883,7 +883,7 @@ static int create_trace_probe(int argc, char **argv) | |||
| 883 | int i, ret = 0; | 883 | int i, ret = 0; |
| 884 | int is_return = 0, is_delete = 0; | 884 | int is_return = 0, is_delete = 0; |
| 885 | char *symbol = NULL, *event = NULL, *group = NULL; | 885 | char *symbol = NULL, *event = NULL, *group = NULL; |
| 886 | char *arg, *tmp; | 886 | char *arg; |
| 887 | unsigned long offset = 0; | 887 | unsigned long offset = 0; |
| 888 | void *addr = NULL; | 888 | void *addr = NULL; |
| 889 | char buf[MAX_EVENT_NAME_LEN]; | 889 | char buf[MAX_EVENT_NAME_LEN]; |
| @@ -992,26 +992,36 @@ static int create_trace_probe(int argc, char **argv) | |||
| 992 | /* parse arguments */ | 992 | /* parse arguments */ |
| 993 | ret = 0; | 993 | ret = 0; |
| 994 | for (i = 0; i < argc && i < MAX_TRACE_ARGS; i++) { | 994 | for (i = 0; i < argc && i < MAX_TRACE_ARGS; i++) { |
| 995 | /* Increment count for freeing args in error case */ | ||
| 996 | tp->nr_args++; | ||
| 997 | |||
| 995 | /* Parse argument name */ | 998 | /* Parse argument name */ |
| 996 | arg = strchr(argv[i], '='); | 999 | arg = strchr(argv[i], '='); |
| 997 | if (arg) | 1000 | if (arg) { |
| 998 | *arg++ = '\0'; | 1001 | *arg++ = '\0'; |
| 999 | else | 1002 | tp->args[i].name = kstrdup(argv[i], GFP_KERNEL); |
| 1003 | } else { | ||
| 1000 | arg = argv[i]; | 1004 | arg = argv[i]; |
| 1005 | /* If argument name is omitted, set "argN" */ | ||
| 1006 | snprintf(buf, MAX_EVENT_NAME_LEN, "arg%d", i + 1); | ||
| 1007 | tp->args[i].name = kstrdup(buf, GFP_KERNEL); | ||
| 1008 | } | ||
| 1001 | 1009 | ||
| 1002 | tp->args[i].name = kstrdup(argv[i], GFP_KERNEL); | ||
| 1003 | if (!tp->args[i].name) { | 1010 | if (!tp->args[i].name) { |
| 1004 | pr_info("Failed to allocate argument%d name '%s'.\n", | 1011 | pr_info("Failed to allocate argument[%d] name.\n", i); |
| 1005 | i, argv[i]); | ||
| 1006 | ret = -ENOMEM; | 1012 | ret = -ENOMEM; |
| 1007 | goto error; | 1013 | goto error; |
| 1008 | } | 1014 | } |
| 1009 | tmp = strchr(tp->args[i].name, ':'); | 1015 | |
| 1010 | if (tmp) | 1016 | if (!is_good_name(tp->args[i].name)) { |
| 1011 | *tmp = '_'; /* convert : to _ */ | 1017 | pr_info("Invalid argument[%d] name: %s\n", |
| 1018 | i, tp->args[i].name); | ||
| 1019 | ret = -EINVAL; | ||
| 1020 | goto error; | ||
| 1021 | } | ||
| 1012 | 1022 | ||
| 1013 | if (conflict_field_name(tp->args[i].name, tp->args, i)) { | 1023 | if (conflict_field_name(tp->args[i].name, tp->args, i)) { |
| 1014 | pr_info("Argument%d name '%s' conflicts with " | 1024 | pr_info("Argument[%d] name '%s' conflicts with " |
| 1015 | "another field.\n", i, argv[i]); | 1025 | "another field.\n", i, argv[i]); |
| 1016 | ret = -EINVAL; | 1026 | ret = -EINVAL; |
| 1017 | goto error; | 1027 | goto error; |
| @@ -1020,12 +1030,9 @@ static int create_trace_probe(int argc, char **argv) | |||
| 1020 | /* Parse fetch argument */ | 1030 | /* Parse fetch argument */ |
| 1021 | ret = parse_probe_arg(arg, tp, &tp->args[i], is_return); | 1031 | ret = parse_probe_arg(arg, tp, &tp->args[i], is_return); |
| 1022 | if (ret) { | 1032 | if (ret) { |
| 1023 | pr_info("Parse error at argument%d. (%d)\n", i, ret); | 1033 | pr_info("Parse error at argument[%d]. (%d)\n", i, ret); |
| 1024 | kfree(tp->args[i].name); | ||
| 1025 | goto error; | 1034 | goto error; |
| 1026 | } | 1035 | } |
| 1027 | |||
| 1028 | tp->nr_args++; | ||
| 1029 | } | 1036 | } |
| 1030 | 1037 | ||
| 1031 | ret = register_trace_probe(tp); | 1038 | ret = register_trace_probe(tp); |
diff --git a/kernel/trace/trace_stack.c b/kernel/trace/trace_stack.c index 056468eae7cf..a6b7e0e0f3eb 100644 --- a/kernel/trace/trace_stack.c +++ b/kernel/trace/trace_stack.c | |||
| @@ -249,7 +249,7 @@ static int trace_lookup_stack(struct seq_file *m, long i) | |||
| 249 | { | 249 | { |
| 250 | unsigned long addr = stack_dump_trace[i]; | 250 | unsigned long addr = stack_dump_trace[i]; |
| 251 | 251 | ||
| 252 | return seq_printf(m, "%pF\n", (void *)addr); | 252 | return seq_printf(m, "%pS\n", (void *)addr); |
| 253 | } | 253 | } |
| 254 | 254 | ||
| 255 | static void print_disabled(struct seq_file *m) | 255 | static void print_disabled(struct seq_file *m) |
