Skip to content
Snippets Groups Projects
builtin-script.c 33.3 KiB
Newer Older
  • Learn to ignore specific revisions
  • 	scripts_dir = opendir(scripts_path);
    	if (!scripts_dir)
    		return -1;
    
    
    	for_each_lang(scripts_path, scripts_dir, lang_dirent, lang_next) {
    
    		snprintf(lang_path, MAXPATHLEN, "%s/%s/bin", scripts_path,
    			 lang_dirent.d_name);
    		lang_dir = opendir(lang_path);
    		if (!lang_dir)
    			continue;
    
    
    		for_each_script(lang_path, lang_dir, script_dirent, script_next) {
    
    			script_root = get_script_root(&script_dirent, REPORT_SUFFIX);
    			if (script_root) {
    
    				desc = script_desc__findnew(script_root);
    				snprintf(script_path, MAXPATHLEN, "%s/%s",
    					 lang_path, script_dirent.d_name);
    				read_script_info(desc, script_path);
    
    			}
    		}
    	}
    
    	fprintf(stdout, "List of available trace scripts:\n");
    	list_for_each_entry(desc, &script_descs, node) {
    		sprintf(first_half, "%s %s", desc->name,
    			desc->args ? desc->args : "");
    		fprintf(stdout, "  %-36s %s\n", first_half,
    			desc->half_liner ? desc->half_liner : "");
    	}
    
    	exit(0);
    }
    
    
    static char *get_script_path(const char *script_root, const char *suffix)
    {
    	struct dirent *script_next, *lang_next, script_dirent, lang_dirent;
    	char scripts_path[MAXPATHLEN];
    	char script_path[MAXPATHLEN];
    	DIR *scripts_dir, *lang_dir;
    	char lang_path[MAXPATHLEN];
    
    
    	snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path());
    
    	scripts_dir = opendir(scripts_path);
    	if (!scripts_dir)
    		return NULL;
    
    
    	for_each_lang(scripts_path, scripts_dir, lang_dirent, lang_next) {
    
    		snprintf(lang_path, MAXPATHLEN, "%s/%s/bin", scripts_path,
    			 lang_dirent.d_name);
    		lang_dir = opendir(lang_path);
    		if (!lang_dir)
    			continue;
    
    
    		for_each_script(lang_path, lang_dir, script_dirent, script_next) {
    
    			__script_root = get_script_root(&script_dirent, suffix);
    			if (__script_root && !strcmp(script_root, __script_root)) {
    				free(__script_root);
    
    				closedir(lang_dir);
    				closedir(scripts_dir);
    
    				snprintf(script_path, MAXPATHLEN, "%s/%s",
    					 lang_path, script_dirent.d_name);
    
    		closedir(lang_dir);
    
    	closedir(scripts_dir);
    
    static bool is_top_script(const char *script_path)
    {
    
    	return ends_with(script_path, "top") == NULL ? false : true;
    
    }
    
    static int has_required_arg(char *script_path)
    {
    	struct script_desc *desc;
    	int n_args = 0;
    	char *p;
    
    	desc = script_desc__new(NULL);
    
    	if (read_script_info(desc, script_path))
    		goto out;
    
    	if (!desc->args)
    		goto out;
    
    	for (p = desc->args; *p; p++)
    		if (*p == '<')
    			n_args++;
    out:
    	script_desc__delete(desc);
    
    	return n_args;
    }
    
    
    static const char * const script_usage[] = {
    	"perf script [<options>]",
    	"perf script [<options>] record <script> [<record-options>] <command>",
    	"perf script [<options>] report <script> [script-args]",
    	"perf script [<options>] <script> [<record-options>] <command>",
    	"perf script [<options>] <top-script> [script-args]",
    
    	NULL
    };
    
    static const struct option options[] = {
    	OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
    		    "dump raw trace in ASCII"),
    
    		    "be more verbose (show symbol address, etc)"),
    
    	OPT_BOOLEAN('L', "Latency", &latency_format,
    
    		    "show latency attributes (irqs/preemption disabled, etc)"),
    
    	OPT_CALLBACK_NOOPT('l', "list", NULL, NULL, "list available scripts",
    			   list_available_scripts),
    
    	OPT_CALLBACK('s', "script", NULL, "name",
    		     "script file name (lang:script name, script name, or *)",
    		     parse_scriptname),
    	OPT_STRING('g', "gen-script", &generate_script_lang, "lang",
    
    		   "generate perf-script.xx script in specified language"),
    
    	OPT_STRING('i', "input", &input_name, "file",
    		    "input file name"),
    
    	OPT_BOOLEAN('d', "debug-mode", &debug_mode,
    		   "do various checks like samples ordering and lost events"),
    
    	OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
    		   "file", "vmlinux pathname"),
    	OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name,
    		   "file", "kallsyms pathname"),
    	OPT_BOOLEAN('G', "hide-call-graph", &no_callchain,
    		    "When printing symbols do not display call chain"),
    	OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
    		    "Look for files with symbols relative to this directory"),
    
    	OPT_CALLBACK('f', "fields", NULL, "str",
    
    		     "comma separated output fields prepend with 'type:'. "
    		     "Valid types: hw,sw,trace,raw. "
    		     "Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso,"
    		     "addr,symoff",
    
    	OPT_BOOLEAN('a', "all-cpus", &system_wide,
    		     "system-wide collection from all CPUs"),
    
    	OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",
    		   "only consider these symbols"),
    
    	OPT_STRING('C', "cpu", &cpu_list, "cpu", "list of cpus to profile"),
    
    	OPT_STRING('c', "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
    		   "only display events for these comms"),
    
    	OPT_BOOLEAN('I', "show-info", &show_full_info,
    		    "display extended information from perf.data file"),
    
    	OPT_BOOLEAN('\0', "show-kernel-path", &symbol_conf.show_kernel_path,
    		    "Show the path of [kernel.kallsyms]"),
    
    
    static int have_cmd(int argc, const char **argv)
    
    {
    	char **__argv = malloc(sizeof(const char *) * argc);
    
    
    	if (!__argv) {
    		pr_err("malloc failed\n");
    		return -1;
    	}
    
    
    	memcpy(__argv, argv, sizeof(const char *) * argc);
    	argc = parse_options(argc, (const char **)__argv, record_options,
    			     NULL, PARSE_OPT_STOP_AT_NON_OPTION);
    	free(__argv);
    
    
    	system_wide = (argc == 0);
    
    	return 0;
    
    int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
    
    	char *rec_script_path = NULL;
    	char *rep_script_path = NULL;
    
    	char *script_path = NULL;
    
    	int i, j, err;
    
    	argc = parse_options(argc, argv, options, script_usage,
    
    			     PARSE_OPT_STOP_AT_NON_OPTION);
    
    	if (argc > 1 && !strncmp(argv[0], "rec", strlen("rec"))) {
    		rec_script_path = get_script_path(argv[1], RECORD_SUFFIX);
    		if (!rec_script_path)
    			return cmd_record(argc, argv, NULL);
    
    	if (argc > 1 && !strncmp(argv[0], "rep", strlen("rep"))) {
    		rep_script_path = get_script_path(argv[1], REPORT_SUFFIX);
    		if (!rep_script_path) {
    
    				"Please specify a valid report script"
    
    				"(see 'perf script -l' for listing)\n");
    
    	/* make sure PERF_EXEC_PATH is set for scripts */
    	perf_set_argv_exec_path(perf_exec_path());
    
    
    	if (argc && !script_name && !rec_script_path && !rep_script_path) {
    
    		rec_script_path = get_script_path(argv[0], RECORD_SUFFIX);
    		rep_script_path = get_script_path(argv[0], REPORT_SUFFIX);
    
    		if (!rec_script_path && !rep_script_path) {
    			fprintf(stderr, " Couldn't find script %s\n\n See perf"
    
    				" script -l for available scripts.\n", argv[0]);
    			usage_with_options(script_usage, options);
    
    		if (is_top_script(argv[0])) {
    			rep_args = argc - 1;
    		} else {
    			int rec_args;
    
    			rep_args = has_required_arg(rep_script_path);
    			rec_args = (argc - 1) - rep_args;
    			if (rec_args < 0) {
    				fprintf(stderr, " %s script requires options."
    
    					"\n\n See perf script -l for available "
    
    					"scripts and options.\n", argv[0]);
    
    				usage_with_options(script_usage, options);
    
    		}
    
    		if (pipe(live_pipe) < 0) {
    			perror("failed to create pipe");
    
    			return -1;
    
    		}
    
    		pid = fork();
    		if (pid < 0) {
    			perror("failed to fork");
    
    			return -1;
    
    			if (is_top_script(argv[0])) {
    				system_wide = true;
    			} else if (!system_wide) {
    
    				if (have_cmd(argc - rep_args, &argv[rep_args]) != 0) {
    					err = -1;
    					goto out;
    				}
    
    
    			__argv = malloc((argc + 6) * sizeof(const char *));
    
    			if (!__argv) {
    				pr_err("malloc failed\n");
    				err = -ENOMEM;
    				goto out;
    			}
    
    			__argv[j++] = "/bin/sh";
    			__argv[j++] = rec_script_path;
    			if (system_wide)
    				__argv[j++] = "-a";
    			__argv[j++] = "-q";
    			__argv[j++] = "-o";
    			__argv[j++] = "-";
    			for (i = rep_args + 1; i < argc; i++)
    				__argv[j++] = argv[i];
    			__argv[j++] = NULL;
    
    		__argv = malloc((argc + 4) * sizeof(const char *));
    
    		if (!__argv) {
    			pr_err("malloc failed\n");
    			err = -ENOMEM;
    			goto out;
    		}
    
    
    		j = 0;
    		__argv[j++] = "/bin/sh";
    		__argv[j++] = rep_script_path;
    		for (i = 1; i < rep_args + 1; i++)
    			__argv[j++] = argv[i];
    		__argv[j++] = "-i";
    		__argv[j++] = "-";
    		__argv[j++] = NULL;
    
    	if (rec_script_path)
    		script_path = rec_script_path;
    	if (rep_script_path)
    		script_path = rep_script_path;
    
    	if (script_path) {
    		j = 0;
    
    		if (!rec_script_path)
    			system_wide = false;
    
    		else if (!system_wide) {
    			if (have_cmd(argc - 1, &argv[1]) != 0) {
    				err = -1;
    				goto out;
    			}
    		}
    
    		__argv = malloc((argc + 2) * sizeof(const char *));
    
    		if (!__argv) {
    			pr_err("malloc failed\n");
    			err = -ENOMEM;
    			goto out;
    		}
    
    
    		__argv[j++] = "/bin/sh";
    		__argv[j++] = script_path;
    		if (system_wide)
    			__argv[j++] = "-a";
    
    		for (i = 2; i < argc; i++)
    
    			__argv[j++] = argv[i];
    		__argv[j++] = NULL;
    
    
    		execvp("/bin/sh", (char **)__argv);
    
    	if (symbol__init() < 0)
    		return -1;
    
    	if (!script_name)
    		setup_pager();
    
    	session = perf_session__new(input_name, O_RDONLY, 0, false,
    
    	if (cpu_list) {
    		if (perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap))
    			return -1;
    	}
    
    
    	perf_session__fprintf_info(session, stdout, show_full_info);
    
    
    	if (!no_callchain)
    
    		symbol_conf.use_callchain = true;
    	else
    		symbol_conf.use_callchain = false;
    
    
    	if (generate_script_lang) {
    		struct stat perf_stat;
    
    		if (output_set_by_user()) {
    
    			fprintf(stderr,
    				"custom fields not supported for generated scripts");
    			return -1;
    		}
    
    		input = open(session->filename, O_RDONLY);	/* input_name */
    
    		if (input < 0) {
    			perror("failed to open file");
    
    			return -1;
    
    		}
    
    		err = fstat(input, &perf_stat);
    		if (err < 0) {
    			perror("failed to stat file");
    
    			return -1;
    
    		}
    
    		if (!perf_stat.st_size) {
    			fprintf(stderr, "zero-sized file, nothing to do!\n");
    
    			return 0;
    
    		}
    
    		scripting_ops = script_spec__lookup(generate_script_lang);
    		if (!scripting_ops) {
    			fprintf(stderr, "invalid language specifier");
    			return -1;
    		}
    
    
    		err = scripting_ops->generate_script(session->pevent,
    						     "perf-script");
    
    		goto out;
    	}
    
    	if (script_name) {
    
    		err = scripting_ops->start_script(script_name, argc, argv);
    
    		if (err)
    			goto out;
    
    		pr_debug("perf script started with script %s\n\n", script_name);
    
    
    	err = perf_session__check_output_opt(session);
    	if (err < 0)
    		goto out;
    
    
    	err = __cmd_script(session);
    
    	cleanup_scripting();
    out:
    	return err;