diff options
-rw-r--r-- | tools/perf/builtin-trace.c | 165 |
1 files changed, 108 insertions, 57 deletions
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 0de7fcb90965..0483e28fa60d 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c | |||
@@ -330,7 +330,7 @@ static struct script_desc *script_desc__new(const char *name) | |||
330 | { | 330 | { |
331 | struct script_desc *s = zalloc(sizeof(*s)); | 331 | struct script_desc *s = zalloc(sizeof(*s)); |
332 | 332 | ||
333 | if (s != NULL) | 333 | if (s != NULL && name) |
334 | s->name = strdup(name); | 334 | s->name = strdup(name); |
335 | 335 | ||
336 | return s; | 336 | return s; |
@@ -541,6 +541,34 @@ static char *get_script_path(const char *script_root, const char *suffix) | |||
541 | return path; | 541 | return path; |
542 | } | 542 | } |
543 | 543 | ||
544 | static bool is_top_script(const char *script_path) | ||
545 | { | ||
546 | return ends_with((char *)script_path, "top") == NULL ? false : true; | ||
547 | } | ||
548 | |||
549 | static int has_required_arg(char *script_path) | ||
550 | { | ||
551 | struct script_desc *desc; | ||
552 | int n_args = 0; | ||
553 | char *p; | ||
554 | |||
555 | desc = script_desc__new(NULL); | ||
556 | |||
557 | if (read_script_info(desc, script_path)) | ||
558 | goto out; | ||
559 | |||
560 | if (!desc->args) | ||
561 | goto out; | ||
562 | |||
563 | for (p = desc->args; *p; p++) | ||
564 | if (*p == '<') | ||
565 | n_args++; | ||
566 | out: | ||
567 | script_desc__delete(desc); | ||
568 | |||
569 | return n_args; | ||
570 | } | ||
571 | |||
544 | static const char * const trace_usage[] = { | 572 | static const char * const trace_usage[] = { |
545 | "perf trace [<options>] <command>", | 573 | "perf trace [<options>] <command>", |
546 | NULL | 574 | NULL |
@@ -584,48 +612,65 @@ static bool have_cmd(int argc, const char **argv) | |||
584 | 612 | ||
585 | int cmd_trace(int argc, const char **argv, const char *prefix __used) | 613 | int cmd_trace(int argc, const char **argv, const char *prefix __used) |
586 | { | 614 | { |
615 | char *rec_script_path = NULL; | ||
616 | char *rep_script_path = NULL; | ||
587 | struct perf_session *session; | 617 | struct perf_session *session; |
588 | const char *suffix = NULL; | 618 | char *script_path = NULL; |
589 | const char **__argv; | 619 | const char **__argv; |
590 | char *script_path; | 620 | bool system_wide; |
591 | int i, err; | 621 | int i, j, err; |
592 | 622 | ||
593 | if (argc >= 2 && strncmp(argv[1], "rec", strlen("rec")) == 0) { | 623 | setup_scripting(); |
594 | if (argc < 3) { | 624 | |
595 | fprintf(stderr, | 625 | argc = parse_options(argc, argv, options, trace_usage, |
596 | "Please specify a record script\n"); | 626 | PARSE_OPT_STOP_AT_NON_OPTION); |
597 | return -1; | 627 | |
598 | } | 628 | if (argc > 1 && !strncmp(argv[0], "rec", strlen("rec"))) { |
599 | suffix = RECORD_SUFFIX; | 629 | rec_script_path = get_script_path(argv[1], RECORD_SUFFIX); |
630 | if (!rec_script_path) | ||
631 | return cmd_record(argc, argv, NULL); | ||
600 | } | 632 | } |
601 | 633 | ||
602 | if (argc >= 2 && strncmp(argv[1], "rep", strlen("rep")) == 0) { | 634 | if (argc > 1 && !strncmp(argv[0], "rep", strlen("rep"))) { |
603 | if (argc < 3) { | 635 | rep_script_path = get_script_path(argv[1], REPORT_SUFFIX); |
636 | if (!rep_script_path) { | ||
604 | fprintf(stderr, | 637 | fprintf(stderr, |
605 | "Please specify a report script\n"); | 638 | "Please specify a valid report script" |
639 | "(see 'perf trace -l' for listing)\n"); | ||
606 | return -1; | 640 | return -1; |
607 | } | 641 | } |
608 | suffix = REPORT_SUFFIX; | ||
609 | } | 642 | } |
610 | 643 | ||
611 | /* make sure PERF_EXEC_PATH is set for scripts */ | 644 | /* make sure PERF_EXEC_PATH is set for scripts */ |
612 | perf_set_argv_exec_path(perf_exec_path()); | 645 | perf_set_argv_exec_path(perf_exec_path()); |
613 | 646 | ||
614 | if (!suffix && argc >= 2 && strncmp(argv[1], "-", strlen("-")) != 0) { | 647 | if (argc && !script_name && !rec_script_path && !rep_script_path) { |
615 | char *record_script_path, *report_script_path; | ||
616 | int live_pipe[2]; | 648 | int live_pipe[2]; |
649 | int rep_args; | ||
617 | pid_t pid; | 650 | pid_t pid; |
618 | 651 | ||
619 | record_script_path = get_script_path(argv[1], RECORD_SUFFIX); | 652 | rec_script_path = get_script_path(argv[0], RECORD_SUFFIX); |
620 | if (!record_script_path) { | 653 | rep_script_path = get_script_path(argv[0], REPORT_SUFFIX); |
621 | fprintf(stderr, "record script not found\n"); | 654 | |
622 | return -1; | 655 | if (!rec_script_path && !rep_script_path) { |
656 | fprintf(stderr, " Couldn't find script %s\n\n See perf" | ||
657 | " trace -l for available scripts.\n", argv[0]); | ||
658 | usage_with_options(trace_usage, options); | ||
623 | } | 659 | } |
624 | 660 | ||
625 | report_script_path = get_script_path(argv[1], REPORT_SUFFIX); | 661 | if (is_top_script(argv[0])) { |
626 | if (!report_script_path) { | 662 | rep_args = argc - 1; |
627 | fprintf(stderr, "report script not found\n"); | 663 | } else { |
628 | return -1; | 664 | int rec_args; |
665 | |||
666 | rep_args = has_required_arg(rep_script_path); | ||
667 | rec_args = (argc - 1) - rep_args; | ||
668 | if (rec_args < 0) { | ||
669 | fprintf(stderr, " %s script requires options." | ||
670 | "\n\n See perf trace -l for available " | ||
671 | "scripts and options.\n", argv[0]); | ||
672 | usage_with_options(trace_usage, options); | ||
673 | } | ||
629 | } | 674 | } |
630 | 675 | ||
631 | if (pipe(live_pipe) < 0) { | 676 | if (pipe(live_pipe) < 0) { |
@@ -640,19 +685,30 @@ int cmd_trace(int argc, const char **argv, const char *prefix __used) | |||
640 | } | 685 | } |
641 | 686 | ||
642 | if (!pid) { | 687 | if (!pid) { |
688 | system_wide = true; | ||
689 | j = 0; | ||
690 | |||
643 | dup2(live_pipe[1], 1); | 691 | dup2(live_pipe[1], 1); |
644 | close(live_pipe[0]); | 692 | close(live_pipe[0]); |
645 | 693 | ||
646 | __argv = malloc(6 * sizeof(const char *)); | 694 | if (!is_top_script(argv[0])) |
695 | system_wide = !have_cmd(argc - rep_args, | ||
696 | &argv[rep_args]); | ||
697 | |||
698 | __argv = malloc((argc + 6) * sizeof(const char *)); | ||
647 | if (!__argv) | 699 | if (!__argv) |
648 | die("malloc"); | 700 | die("malloc"); |
649 | 701 | ||
650 | __argv[0] = "/bin/sh"; | 702 | __argv[j++] = "/bin/sh"; |
651 | __argv[1] = record_script_path; | 703 | __argv[j++] = rec_script_path; |
652 | __argv[2] = "-q"; | 704 | if (system_wide) |
653 | __argv[3] = "-o"; | 705 | __argv[j++] = "-a"; |
654 | __argv[4] = "-"; | 706 | __argv[j++] = "-q"; |
655 | __argv[5] = NULL; | 707 | __argv[j++] = "-o"; |
708 | __argv[j++] = "-"; | ||
709 | for (i = rep_args + 1; i < argc; i++) | ||
710 | __argv[j++] = argv[i]; | ||
711 | __argv[j++] = NULL; | ||
656 | 712 | ||
657 | execvp("/bin/sh", (char **)__argv); | 713 | execvp("/bin/sh", (char **)__argv); |
658 | free(__argv); | 714 | free(__argv); |
@@ -662,43 +718,43 @@ int cmd_trace(int argc, const char **argv, const char *prefix __used) | |||
662 | dup2(live_pipe[0], 0); | 718 | dup2(live_pipe[0], 0); |
663 | close(live_pipe[1]); | 719 | close(live_pipe[1]); |
664 | 720 | ||
665 | __argv = malloc((argc + 3) * sizeof(const char *)); | 721 | __argv = malloc((argc + 4) * sizeof(const char *)); |
666 | if (!__argv) | 722 | if (!__argv) |
667 | die("malloc"); | 723 | die("malloc"); |
668 | __argv[0] = "/bin/sh"; | 724 | j = 0; |
669 | __argv[1] = report_script_path; | 725 | __argv[j++] = "/bin/sh"; |
670 | for (i = 2; i < argc; i++) | 726 | __argv[j++] = rep_script_path; |
671 | __argv[i] = argv[i]; | 727 | for (i = 1; i < rep_args + 1; i++) |
672 | __argv[i++] = "-i"; | 728 | __argv[j++] = argv[i]; |
673 | __argv[i++] = "-"; | 729 | __argv[j++] = "-i"; |
674 | __argv[i++] = NULL; | 730 | __argv[j++] = "-"; |
731 | __argv[j++] = NULL; | ||
675 | 732 | ||
676 | execvp("/bin/sh", (char **)__argv); | 733 | execvp("/bin/sh", (char **)__argv); |
677 | free(__argv); | 734 | free(__argv); |
678 | exit(-1); | 735 | exit(-1); |
679 | } | 736 | } |
680 | 737 | ||
681 | if (suffix) { | 738 | if (rec_script_path) |
682 | bool system_wide = false; | 739 | script_path = rec_script_path; |
683 | int j = 0; | 740 | if (rep_script_path) |
741 | script_path = rep_script_path; | ||
684 | 742 | ||
685 | script_path = get_script_path(argv[2], suffix); | 743 | if (script_path) { |
686 | if (!script_path) { | 744 | system_wide = false; |
687 | fprintf(stderr, "script not found\n"); | 745 | j = 0; |
688 | return -1; | ||
689 | } | ||
690 | 746 | ||
691 | if (!strcmp(suffix, RECORD_SUFFIX)) | 747 | if (rec_script_path) |
692 | system_wide = !have_cmd(argc - 2, &argv[2]); | 748 | system_wide = !have_cmd(argc - 1, &argv[1]); |
693 | 749 | ||
694 | __argv = malloc((argc + 1) * sizeof(const char *)); | 750 | __argv = malloc((argc + 2) * sizeof(const char *)); |
695 | if (!__argv) | 751 | if (!__argv) |
696 | die("malloc"); | 752 | die("malloc"); |
697 | __argv[j++] = "/bin/sh"; | 753 | __argv[j++] = "/bin/sh"; |
698 | __argv[j++] = script_path; | 754 | __argv[j++] = script_path; |
699 | if (system_wide) | 755 | if (system_wide) |
700 | __argv[j++] = "-a"; | 756 | __argv[j++] = "-a"; |
701 | for (i = 3; i < argc; i++) | 757 | for (i = 2; i < argc; i++) |
702 | __argv[j++] = argv[i]; | 758 | __argv[j++] = argv[i]; |
703 | __argv[j++] = NULL; | 759 | __argv[j++] = NULL; |
704 | 760 | ||
@@ -707,11 +763,6 @@ int cmd_trace(int argc, const char **argv, const char *prefix __used) | |||
707 | exit(-1); | 763 | exit(-1); |
708 | } | 764 | } |
709 | 765 | ||
710 | setup_scripting(); | ||
711 | |||
712 | argc = parse_options(argc, argv, options, trace_usage, | ||
713 | PARSE_OPT_STOP_AT_NON_OPTION); | ||
714 | |||
715 | if (symbol__init() < 0) | 766 | if (symbol__init() < 0) |
716 | return -1; | 767 | return -1; |
717 | if (!script_name) | 768 | if (!script_name) |