18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * perf.c
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Performance analysis utility.
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * This is the main hub from which the sub-commands (perf stat,
78c2ecf20Sopenharmony_ci * perf top, perf record, perf report, etc.) are started.
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci#include "builtin.h"
108c2ecf20Sopenharmony_ci#include "perf.h"
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include "util/build-id.h"
138c2ecf20Sopenharmony_ci#include "util/cache.h"
148c2ecf20Sopenharmony_ci#include "util/env.h"
158c2ecf20Sopenharmony_ci#include <internal/lib.h> // page_size
168c2ecf20Sopenharmony_ci#include <subcmd/exec-cmd.h>
178c2ecf20Sopenharmony_ci#include "util/config.h"
188c2ecf20Sopenharmony_ci#include <subcmd/run-command.h>
198c2ecf20Sopenharmony_ci#include "util/parse-events.h"
208c2ecf20Sopenharmony_ci#include <subcmd/parse-options.h>
218c2ecf20Sopenharmony_ci#include "util/bpf-loader.h"
228c2ecf20Sopenharmony_ci#include "util/debug.h"
238c2ecf20Sopenharmony_ci#include "util/event.h"
248c2ecf20Sopenharmony_ci#include "util/util.h" // usage()
258c2ecf20Sopenharmony_ci#include "ui/ui.h"
268c2ecf20Sopenharmony_ci#include "perf-sys.h"
278c2ecf20Sopenharmony_ci#include <api/fs/fs.h>
288c2ecf20Sopenharmony_ci#include <api/fs/tracing_path.h>
298c2ecf20Sopenharmony_ci#include <perf/core.h>
308c2ecf20Sopenharmony_ci#include <errno.h>
318c2ecf20Sopenharmony_ci#include <pthread.h>
328c2ecf20Sopenharmony_ci#include <signal.h>
338c2ecf20Sopenharmony_ci#include <stdlib.h>
348c2ecf20Sopenharmony_ci#include <time.h>
358c2ecf20Sopenharmony_ci#include <sys/types.h>
368c2ecf20Sopenharmony_ci#include <sys/stat.h>
378c2ecf20Sopenharmony_ci#include <unistd.h>
388c2ecf20Sopenharmony_ci#include <linux/kernel.h>
398c2ecf20Sopenharmony_ci#include <linux/string.h>
408c2ecf20Sopenharmony_ci#include <linux/zalloc.h>
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ciconst char perf_usage_string[] =
438c2ecf20Sopenharmony_ci	"perf [--version] [--help] [OPTIONS] COMMAND [ARGS]";
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ciconst char perf_more_info_string[] =
468c2ecf20Sopenharmony_ci	"See 'perf help COMMAND' for more information on a specific command.";
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_cistatic int use_pager = -1;
498c2ecf20Sopenharmony_ciconst char *input_name;
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_cistruct cmd_struct {
528c2ecf20Sopenharmony_ci	const char *cmd;
538c2ecf20Sopenharmony_ci	int (*fn)(int, const char **);
548c2ecf20Sopenharmony_ci	int option;
558c2ecf20Sopenharmony_ci};
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_cistatic struct cmd_struct commands[] = {
588c2ecf20Sopenharmony_ci	{ "buildid-cache", cmd_buildid_cache, 0 },
598c2ecf20Sopenharmony_ci	{ "buildid-list", cmd_buildid_list, 0 },
608c2ecf20Sopenharmony_ci	{ "config",	cmd_config,	0 },
618c2ecf20Sopenharmony_ci	{ "c2c",	cmd_c2c,	0 },
628c2ecf20Sopenharmony_ci	{ "diff",	cmd_diff,	0 },
638c2ecf20Sopenharmony_ci	{ "evlist",	cmd_evlist,	0 },
648c2ecf20Sopenharmony_ci	{ "help",	cmd_help,	0 },
658c2ecf20Sopenharmony_ci	{ "kallsyms",	cmd_kallsyms,	0 },
668c2ecf20Sopenharmony_ci	{ "list",	cmd_list,	0 },
678c2ecf20Sopenharmony_ci	{ "record",	cmd_record,	0 },
688c2ecf20Sopenharmony_ci	{ "report",	cmd_report,	0 },
698c2ecf20Sopenharmony_ci	{ "bench",	cmd_bench,	0 },
708c2ecf20Sopenharmony_ci	{ "stat",	cmd_stat,	0 },
718c2ecf20Sopenharmony_ci	{ "timechart",	cmd_timechart,	0 },
728c2ecf20Sopenharmony_ci	{ "top",	cmd_top,	0 },
738c2ecf20Sopenharmony_ci	{ "annotate",	cmd_annotate,	0 },
748c2ecf20Sopenharmony_ci	{ "version",	cmd_version,	0 },
758c2ecf20Sopenharmony_ci	{ "script",	cmd_script,	0 },
768c2ecf20Sopenharmony_ci	{ "sched",	cmd_sched,	0 },
778c2ecf20Sopenharmony_ci#ifdef HAVE_LIBELF_SUPPORT
788c2ecf20Sopenharmony_ci	{ "probe",	cmd_probe,	0 },
798c2ecf20Sopenharmony_ci#endif
808c2ecf20Sopenharmony_ci	{ "kmem",	cmd_kmem,	0 },
818c2ecf20Sopenharmony_ci	{ "lock",	cmd_lock,	0 },
828c2ecf20Sopenharmony_ci	{ "kvm",	cmd_kvm,	0 },
838c2ecf20Sopenharmony_ci	{ "test",	cmd_test,	0 },
848c2ecf20Sopenharmony_ci#if defined(HAVE_LIBAUDIT_SUPPORT) || defined(HAVE_SYSCALL_TABLE_SUPPORT)
858c2ecf20Sopenharmony_ci	{ "trace",	cmd_trace,	0 },
868c2ecf20Sopenharmony_ci#endif
878c2ecf20Sopenharmony_ci	{ "inject",	cmd_inject,	0 },
888c2ecf20Sopenharmony_ci	{ "mem",	cmd_mem,	0 },
898c2ecf20Sopenharmony_ci	{ "data",	cmd_data,	0 },
908c2ecf20Sopenharmony_ci	{ "ftrace",	cmd_ftrace,	0 },
918c2ecf20Sopenharmony_ci};
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_cistruct pager_config {
948c2ecf20Sopenharmony_ci	const char *cmd;
958c2ecf20Sopenharmony_ci	int val;
968c2ecf20Sopenharmony_ci};
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_cistatic int pager_command_config(const char *var, const char *value, void *data)
998c2ecf20Sopenharmony_ci{
1008c2ecf20Sopenharmony_ci	struct pager_config *c = data;
1018c2ecf20Sopenharmony_ci	if (strstarts(var, "pager.") && !strcmp(var + 6, c->cmd))
1028c2ecf20Sopenharmony_ci		c->val = perf_config_bool(var, value);
1038c2ecf20Sopenharmony_ci	return 0;
1048c2ecf20Sopenharmony_ci}
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci/* returns 0 for "no pager", 1 for "use pager", and -1 for "not specified" */
1078c2ecf20Sopenharmony_cistatic int check_pager_config(const char *cmd)
1088c2ecf20Sopenharmony_ci{
1098c2ecf20Sopenharmony_ci	int err;
1108c2ecf20Sopenharmony_ci	struct pager_config c;
1118c2ecf20Sopenharmony_ci	c.cmd = cmd;
1128c2ecf20Sopenharmony_ci	c.val = -1;
1138c2ecf20Sopenharmony_ci	err = perf_config(pager_command_config, &c);
1148c2ecf20Sopenharmony_ci	return err ?: c.val;
1158c2ecf20Sopenharmony_ci}
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_cistatic int browser_command_config(const char *var, const char *value, void *data)
1188c2ecf20Sopenharmony_ci{
1198c2ecf20Sopenharmony_ci	struct pager_config *c = data;
1208c2ecf20Sopenharmony_ci	if (strstarts(var, "tui.") && !strcmp(var + 4, c->cmd))
1218c2ecf20Sopenharmony_ci		c->val = perf_config_bool(var, value);
1228c2ecf20Sopenharmony_ci	if (strstarts(var, "gtk.") && !strcmp(var + 4, c->cmd))
1238c2ecf20Sopenharmony_ci		c->val = perf_config_bool(var, value) ? 2 : 0;
1248c2ecf20Sopenharmony_ci	return 0;
1258c2ecf20Sopenharmony_ci}
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci/*
1288c2ecf20Sopenharmony_ci * returns 0 for "no tui", 1 for "use tui", 2 for "use gtk",
1298c2ecf20Sopenharmony_ci * and -1 for "not specified"
1308c2ecf20Sopenharmony_ci */
1318c2ecf20Sopenharmony_cistatic int check_browser_config(const char *cmd)
1328c2ecf20Sopenharmony_ci{
1338c2ecf20Sopenharmony_ci	int err;
1348c2ecf20Sopenharmony_ci	struct pager_config c;
1358c2ecf20Sopenharmony_ci	c.cmd = cmd;
1368c2ecf20Sopenharmony_ci	c.val = -1;
1378c2ecf20Sopenharmony_ci	err = perf_config(browser_command_config, &c);
1388c2ecf20Sopenharmony_ci	return err ?: c.val;
1398c2ecf20Sopenharmony_ci}
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_cistatic void commit_pager_choice(void)
1428c2ecf20Sopenharmony_ci{
1438c2ecf20Sopenharmony_ci	switch (use_pager) {
1448c2ecf20Sopenharmony_ci	case 0:
1458c2ecf20Sopenharmony_ci		setenv(PERF_PAGER_ENVIRONMENT, "cat", 1);
1468c2ecf20Sopenharmony_ci		break;
1478c2ecf20Sopenharmony_ci	case 1:
1488c2ecf20Sopenharmony_ci		/* setup_pager(); */
1498c2ecf20Sopenharmony_ci		break;
1508c2ecf20Sopenharmony_ci	default:
1518c2ecf20Sopenharmony_ci		break;
1528c2ecf20Sopenharmony_ci	}
1538c2ecf20Sopenharmony_ci}
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_cistruct option options[] = {
1568c2ecf20Sopenharmony_ci	OPT_ARGUMENT("help", "help"),
1578c2ecf20Sopenharmony_ci	OPT_ARGUMENT("version", "version"),
1588c2ecf20Sopenharmony_ci	OPT_ARGUMENT("exec-path", "exec-path"),
1598c2ecf20Sopenharmony_ci	OPT_ARGUMENT("html-path", "html-path"),
1608c2ecf20Sopenharmony_ci	OPT_ARGUMENT("paginate", "paginate"),
1618c2ecf20Sopenharmony_ci	OPT_ARGUMENT("no-pager", "no-pager"),
1628c2ecf20Sopenharmony_ci	OPT_ARGUMENT("debugfs-dir", "debugfs-dir"),
1638c2ecf20Sopenharmony_ci	OPT_ARGUMENT("buildid-dir", "buildid-dir"),
1648c2ecf20Sopenharmony_ci	OPT_ARGUMENT("list-cmds", "list-cmds"),
1658c2ecf20Sopenharmony_ci	OPT_ARGUMENT("list-opts", "list-opts"),
1668c2ecf20Sopenharmony_ci	OPT_ARGUMENT("debug", "debug"),
1678c2ecf20Sopenharmony_ci	OPT_END()
1688c2ecf20Sopenharmony_ci};
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_cistatic int handle_options(const char ***argv, int *argc, int *envchanged)
1718c2ecf20Sopenharmony_ci{
1728c2ecf20Sopenharmony_ci	int handled = 0;
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	while (*argc > 0) {
1758c2ecf20Sopenharmony_ci		const char *cmd = (*argv)[0];
1768c2ecf20Sopenharmony_ci		if (cmd[0] != '-')
1778c2ecf20Sopenharmony_ci			break;
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci		/*
1808c2ecf20Sopenharmony_ci		 * For legacy reasons, the "version" and "help"
1818c2ecf20Sopenharmony_ci		 * commands can be written with "--" prepended
1828c2ecf20Sopenharmony_ci		 * to make them look like flags.
1838c2ecf20Sopenharmony_ci		 */
1848c2ecf20Sopenharmony_ci		if (!strcmp(cmd, "--help") || !strcmp(cmd, "--version"))
1858c2ecf20Sopenharmony_ci			break;
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci		/*
1888c2ecf20Sopenharmony_ci		 * Shortcut for '-h' and '-v' options to invoke help
1898c2ecf20Sopenharmony_ci		 * and version command.
1908c2ecf20Sopenharmony_ci		 */
1918c2ecf20Sopenharmony_ci		if (!strcmp(cmd, "-h")) {
1928c2ecf20Sopenharmony_ci			(*argv)[0] = "--help";
1938c2ecf20Sopenharmony_ci			break;
1948c2ecf20Sopenharmony_ci		}
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci		if (!strcmp(cmd, "-v")) {
1978c2ecf20Sopenharmony_ci			(*argv)[0] = "--version";
1988c2ecf20Sopenharmony_ci			break;
1998c2ecf20Sopenharmony_ci		}
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci		if (!strcmp(cmd, "-vv")) {
2028c2ecf20Sopenharmony_ci			(*argv)[0] = "version";
2038c2ecf20Sopenharmony_ci			version_verbose = 1;
2048c2ecf20Sopenharmony_ci			break;
2058c2ecf20Sopenharmony_ci		}
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci		/*
2088c2ecf20Sopenharmony_ci		 * Check remaining flags.
2098c2ecf20Sopenharmony_ci		 */
2108c2ecf20Sopenharmony_ci		if (strstarts(cmd, CMD_EXEC_PATH)) {
2118c2ecf20Sopenharmony_ci			cmd += strlen(CMD_EXEC_PATH);
2128c2ecf20Sopenharmony_ci			if (*cmd == '=')
2138c2ecf20Sopenharmony_ci				set_argv_exec_path(cmd + 1);
2148c2ecf20Sopenharmony_ci			else {
2158c2ecf20Sopenharmony_ci				puts(get_argv_exec_path());
2168c2ecf20Sopenharmony_ci				exit(0);
2178c2ecf20Sopenharmony_ci			}
2188c2ecf20Sopenharmony_ci		} else if (!strcmp(cmd, "--html-path")) {
2198c2ecf20Sopenharmony_ci			puts(system_path(PERF_HTML_PATH));
2208c2ecf20Sopenharmony_ci			exit(0);
2218c2ecf20Sopenharmony_ci		} else if (!strcmp(cmd, "-p") || !strcmp(cmd, "--paginate")) {
2228c2ecf20Sopenharmony_ci			use_pager = 1;
2238c2ecf20Sopenharmony_ci		} else if (!strcmp(cmd, "--no-pager")) {
2248c2ecf20Sopenharmony_ci			use_pager = 0;
2258c2ecf20Sopenharmony_ci			if (envchanged)
2268c2ecf20Sopenharmony_ci				*envchanged = 1;
2278c2ecf20Sopenharmony_ci		} else if (!strcmp(cmd, "--debugfs-dir")) {
2288c2ecf20Sopenharmony_ci			if (*argc < 2) {
2298c2ecf20Sopenharmony_ci				fprintf(stderr, "No directory given for --debugfs-dir.\n");
2308c2ecf20Sopenharmony_ci				usage(perf_usage_string);
2318c2ecf20Sopenharmony_ci			}
2328c2ecf20Sopenharmony_ci			tracing_path_set((*argv)[1]);
2338c2ecf20Sopenharmony_ci			if (envchanged)
2348c2ecf20Sopenharmony_ci				*envchanged = 1;
2358c2ecf20Sopenharmony_ci			(*argv)++;
2368c2ecf20Sopenharmony_ci			(*argc)--;
2378c2ecf20Sopenharmony_ci		} else if (!strcmp(cmd, "--buildid-dir")) {
2388c2ecf20Sopenharmony_ci			if (*argc < 2) {
2398c2ecf20Sopenharmony_ci				fprintf(stderr, "No directory given for --buildid-dir.\n");
2408c2ecf20Sopenharmony_ci				usage(perf_usage_string);
2418c2ecf20Sopenharmony_ci			}
2428c2ecf20Sopenharmony_ci			set_buildid_dir((*argv)[1]);
2438c2ecf20Sopenharmony_ci			if (envchanged)
2448c2ecf20Sopenharmony_ci				*envchanged = 1;
2458c2ecf20Sopenharmony_ci			(*argv)++;
2468c2ecf20Sopenharmony_ci			(*argc)--;
2478c2ecf20Sopenharmony_ci		} else if (strstarts(cmd, CMD_DEBUGFS_DIR)) {
2488c2ecf20Sopenharmony_ci			tracing_path_set(cmd + strlen(CMD_DEBUGFS_DIR));
2498c2ecf20Sopenharmony_ci			fprintf(stderr, "dir: %s\n", tracing_path_mount());
2508c2ecf20Sopenharmony_ci			if (envchanged)
2518c2ecf20Sopenharmony_ci				*envchanged = 1;
2528c2ecf20Sopenharmony_ci		} else if (!strcmp(cmd, "--list-cmds")) {
2538c2ecf20Sopenharmony_ci			unsigned int i;
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci			for (i = 0; i < ARRAY_SIZE(commands); i++) {
2568c2ecf20Sopenharmony_ci				struct cmd_struct *p = commands+i;
2578c2ecf20Sopenharmony_ci				printf("%s ", p->cmd);
2588c2ecf20Sopenharmony_ci			}
2598c2ecf20Sopenharmony_ci			putchar('\n');
2608c2ecf20Sopenharmony_ci			exit(0);
2618c2ecf20Sopenharmony_ci		} else if (!strcmp(cmd, "--list-opts")) {
2628c2ecf20Sopenharmony_ci			unsigned int i;
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci			for (i = 0; i < ARRAY_SIZE(options)-1; i++) {
2658c2ecf20Sopenharmony_ci				struct option *p = options+i;
2668c2ecf20Sopenharmony_ci				printf("--%s ", p->long_name);
2678c2ecf20Sopenharmony_ci			}
2688c2ecf20Sopenharmony_ci			putchar('\n');
2698c2ecf20Sopenharmony_ci			exit(0);
2708c2ecf20Sopenharmony_ci		} else if (!strcmp(cmd, "--debug")) {
2718c2ecf20Sopenharmony_ci			if (*argc < 2) {
2728c2ecf20Sopenharmony_ci				fprintf(stderr, "No variable specified for --debug.\n");
2738c2ecf20Sopenharmony_ci				usage(perf_usage_string);
2748c2ecf20Sopenharmony_ci			}
2758c2ecf20Sopenharmony_ci			if (perf_debug_option((*argv)[1]))
2768c2ecf20Sopenharmony_ci				usage(perf_usage_string);
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci			(*argv)++;
2798c2ecf20Sopenharmony_ci			(*argc)--;
2808c2ecf20Sopenharmony_ci		} else {
2818c2ecf20Sopenharmony_ci			fprintf(stderr, "Unknown option: %s\n", cmd);
2828c2ecf20Sopenharmony_ci			usage(perf_usage_string);
2838c2ecf20Sopenharmony_ci		}
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci		(*argv)++;
2868c2ecf20Sopenharmony_ci		(*argc)--;
2878c2ecf20Sopenharmony_ci		handled++;
2888c2ecf20Sopenharmony_ci	}
2898c2ecf20Sopenharmony_ci	return handled;
2908c2ecf20Sopenharmony_ci}
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci#define RUN_SETUP	(1<<0)
2938c2ecf20Sopenharmony_ci#define USE_PAGER	(1<<1)
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_cistatic int run_builtin(struct cmd_struct *p, int argc, const char **argv)
2968c2ecf20Sopenharmony_ci{
2978c2ecf20Sopenharmony_ci	int status;
2988c2ecf20Sopenharmony_ci	struct stat st;
2998c2ecf20Sopenharmony_ci	char sbuf[STRERR_BUFSIZE];
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	if (use_browser == -1)
3028c2ecf20Sopenharmony_ci		use_browser = check_browser_config(p->cmd);
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	if (use_pager == -1 && p->option & RUN_SETUP)
3058c2ecf20Sopenharmony_ci		use_pager = check_pager_config(p->cmd);
3068c2ecf20Sopenharmony_ci	if (use_pager == -1 && p->option & USE_PAGER)
3078c2ecf20Sopenharmony_ci		use_pager = 1;
3088c2ecf20Sopenharmony_ci	commit_pager_choice();
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	perf_env__init(&perf_env);
3118c2ecf20Sopenharmony_ci	perf_env__set_cmdline(&perf_env, argc, argv);
3128c2ecf20Sopenharmony_ci	status = p->fn(argc, argv);
3138c2ecf20Sopenharmony_ci	perf_config__exit();
3148c2ecf20Sopenharmony_ci	exit_browser(status);
3158c2ecf20Sopenharmony_ci	perf_env__exit(&perf_env);
3168c2ecf20Sopenharmony_ci	bpf__clear();
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	if (status)
3198c2ecf20Sopenharmony_ci		return status & 0xff;
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	/* Somebody closed stdout? */
3228c2ecf20Sopenharmony_ci	if (fstat(fileno(stdout), &st))
3238c2ecf20Sopenharmony_ci		return 0;
3248c2ecf20Sopenharmony_ci	/* Ignore write errors for pipes and sockets.. */
3258c2ecf20Sopenharmony_ci	if (S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode))
3268c2ecf20Sopenharmony_ci		return 0;
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	status = 1;
3298c2ecf20Sopenharmony_ci	/* Check for ENOSPC and EIO errors.. */
3308c2ecf20Sopenharmony_ci	if (fflush(stdout)) {
3318c2ecf20Sopenharmony_ci		fprintf(stderr, "write failure on standard output: %s",
3328c2ecf20Sopenharmony_ci			str_error_r(errno, sbuf, sizeof(sbuf)));
3338c2ecf20Sopenharmony_ci		goto out;
3348c2ecf20Sopenharmony_ci	}
3358c2ecf20Sopenharmony_ci	if (ferror(stdout)) {
3368c2ecf20Sopenharmony_ci		fprintf(stderr, "unknown write failure on standard output");
3378c2ecf20Sopenharmony_ci		goto out;
3388c2ecf20Sopenharmony_ci	}
3398c2ecf20Sopenharmony_ci	if (fclose(stdout)) {
3408c2ecf20Sopenharmony_ci		fprintf(stderr, "close failed on standard output: %s",
3418c2ecf20Sopenharmony_ci			str_error_r(errno, sbuf, sizeof(sbuf)));
3428c2ecf20Sopenharmony_ci		goto out;
3438c2ecf20Sopenharmony_ci	}
3448c2ecf20Sopenharmony_ci	status = 0;
3458c2ecf20Sopenharmony_ciout:
3468c2ecf20Sopenharmony_ci	return status;
3478c2ecf20Sopenharmony_ci}
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_cistatic void handle_internal_command(int argc, const char **argv)
3508c2ecf20Sopenharmony_ci{
3518c2ecf20Sopenharmony_ci	const char *cmd = argv[0];
3528c2ecf20Sopenharmony_ci	unsigned int i;
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	/* Turn "perf cmd --help" into "perf help cmd" */
3558c2ecf20Sopenharmony_ci	if (argc > 1 && !strcmp(argv[1], "--help")) {
3568c2ecf20Sopenharmony_ci		argv[1] = argv[0];
3578c2ecf20Sopenharmony_ci		argv[0] = cmd = "help";
3588c2ecf20Sopenharmony_ci	}
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(commands); i++) {
3618c2ecf20Sopenharmony_ci		struct cmd_struct *p = commands+i;
3628c2ecf20Sopenharmony_ci		if (strcmp(p->cmd, cmd))
3638c2ecf20Sopenharmony_ci			continue;
3648c2ecf20Sopenharmony_ci		exit(run_builtin(p, argc, argv));
3658c2ecf20Sopenharmony_ci	}
3668c2ecf20Sopenharmony_ci}
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_cistatic void execv_dashed_external(const char **argv)
3698c2ecf20Sopenharmony_ci{
3708c2ecf20Sopenharmony_ci	char *cmd;
3718c2ecf20Sopenharmony_ci	const char *tmp;
3728c2ecf20Sopenharmony_ci	int status;
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci	if (asprintf(&cmd, "perf-%s", argv[0]) < 0)
3758c2ecf20Sopenharmony_ci		goto do_die;
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	/*
3788c2ecf20Sopenharmony_ci	 * argv[0] must be the perf command, but the argv array
3798c2ecf20Sopenharmony_ci	 * belongs to the caller, and may be reused in
3808c2ecf20Sopenharmony_ci	 * subsequent loop iterations. Save argv[0] and
3818c2ecf20Sopenharmony_ci	 * restore it on error.
3828c2ecf20Sopenharmony_ci	 */
3838c2ecf20Sopenharmony_ci	tmp = argv[0];
3848c2ecf20Sopenharmony_ci	argv[0] = cmd;
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci	/*
3878c2ecf20Sopenharmony_ci	 * if we fail because the command is not found, it is
3888c2ecf20Sopenharmony_ci	 * OK to return. Otherwise, we just pass along the status code.
3898c2ecf20Sopenharmony_ci	 */
3908c2ecf20Sopenharmony_ci	status = run_command_v_opt(argv, 0);
3918c2ecf20Sopenharmony_ci	if (status != -ERR_RUN_COMMAND_EXEC) {
3928c2ecf20Sopenharmony_ci		if (IS_RUN_COMMAND_ERR(status)) {
3938c2ecf20Sopenharmony_cido_die:
3948c2ecf20Sopenharmony_ci			pr_err("FATAL: unable to run '%s'", argv[0]);
3958c2ecf20Sopenharmony_ci			status = -128;
3968c2ecf20Sopenharmony_ci		}
3978c2ecf20Sopenharmony_ci		exit(-status);
3988c2ecf20Sopenharmony_ci	}
3998c2ecf20Sopenharmony_ci	errno = ENOENT; /* as if we called execvp */
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	argv[0] = tmp;
4028c2ecf20Sopenharmony_ci	zfree(&cmd);
4038c2ecf20Sopenharmony_ci}
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_cistatic int run_argv(int *argcp, const char ***argv)
4068c2ecf20Sopenharmony_ci{
4078c2ecf20Sopenharmony_ci	/* See if it's an internal command */
4088c2ecf20Sopenharmony_ci	handle_internal_command(*argcp, *argv);
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci	/* .. then try the external ones */
4118c2ecf20Sopenharmony_ci	execv_dashed_external(*argv);
4128c2ecf20Sopenharmony_ci	return 0;
4138c2ecf20Sopenharmony_ci}
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_cistatic void pthread__block_sigwinch(void)
4168c2ecf20Sopenharmony_ci{
4178c2ecf20Sopenharmony_ci	sigset_t set;
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	sigemptyset(&set);
4208c2ecf20Sopenharmony_ci	sigaddset(&set, SIGWINCH);
4218c2ecf20Sopenharmony_ci	pthread_sigmask(SIG_BLOCK, &set, NULL);
4228c2ecf20Sopenharmony_ci}
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_civoid pthread__unblock_sigwinch(void)
4258c2ecf20Sopenharmony_ci{
4268c2ecf20Sopenharmony_ci	sigset_t set;
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	sigemptyset(&set);
4298c2ecf20Sopenharmony_ci	sigaddset(&set, SIGWINCH);
4308c2ecf20Sopenharmony_ci	pthread_sigmask(SIG_UNBLOCK, &set, NULL);
4318c2ecf20Sopenharmony_ci}
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_cistatic int libperf_print(enum libperf_print_level level,
4348c2ecf20Sopenharmony_ci			 const char *fmt, va_list ap)
4358c2ecf20Sopenharmony_ci{
4368c2ecf20Sopenharmony_ci	return veprintf(level, verbose, fmt, ap);
4378c2ecf20Sopenharmony_ci}
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ciint main(int argc, const char **argv)
4408c2ecf20Sopenharmony_ci{
4418c2ecf20Sopenharmony_ci	int err;
4428c2ecf20Sopenharmony_ci	const char *cmd;
4438c2ecf20Sopenharmony_ci	char sbuf[STRERR_BUFSIZE];
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci	/* libsubcmd init */
4468c2ecf20Sopenharmony_ci	exec_cmd_init("perf", PREFIX, PERF_EXEC_PATH, EXEC_PATH_ENVIRONMENT);
4478c2ecf20Sopenharmony_ci	pager_init(PERF_PAGER_ENVIRONMENT);
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci	libperf_init(libperf_print);
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci	cmd = extract_argv0_path(argv[0]);
4528c2ecf20Sopenharmony_ci	if (!cmd)
4538c2ecf20Sopenharmony_ci		cmd = "perf-help";
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	srandom(time(NULL));
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	/* Setting $PERF_CONFIG makes perf read _only_ the given config file. */
4588c2ecf20Sopenharmony_ci	config_exclusive_filename = getenv("PERF_CONFIG");
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci	err = perf_config(perf_default_config, NULL);
4618c2ecf20Sopenharmony_ci	if (err)
4628c2ecf20Sopenharmony_ci		return err;
4638c2ecf20Sopenharmony_ci	set_buildid_dir(NULL);
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci	/*
4668c2ecf20Sopenharmony_ci	 * "perf-xxxx" is the same as "perf xxxx", but we obviously:
4678c2ecf20Sopenharmony_ci	 *
4688c2ecf20Sopenharmony_ci	 *  - cannot take flags in between the "perf" and the "xxxx".
4698c2ecf20Sopenharmony_ci	 *  - cannot execute it externally (since it would just do
4708c2ecf20Sopenharmony_ci	 *    the same thing over again)
4718c2ecf20Sopenharmony_ci	 *
4728c2ecf20Sopenharmony_ci	 * So we just directly call the internal command handler. If that one
4738c2ecf20Sopenharmony_ci	 * fails to handle this, then maybe we just run a renamed perf binary
4748c2ecf20Sopenharmony_ci	 * that contains a dash in its name. To handle this scenario, we just
4758c2ecf20Sopenharmony_ci	 * fall through and ignore the "xxxx" part of the command string.
4768c2ecf20Sopenharmony_ci	 */
4778c2ecf20Sopenharmony_ci	if (strstarts(cmd, "perf-")) {
4788c2ecf20Sopenharmony_ci		cmd += 5;
4798c2ecf20Sopenharmony_ci		argv[0] = cmd;
4808c2ecf20Sopenharmony_ci		handle_internal_command(argc, argv);
4818c2ecf20Sopenharmony_ci		/*
4828c2ecf20Sopenharmony_ci		 * If the command is handled, the above function does not
4838c2ecf20Sopenharmony_ci		 * return undo changes and fall through in such a case.
4848c2ecf20Sopenharmony_ci		 */
4858c2ecf20Sopenharmony_ci		cmd -= 5;
4868c2ecf20Sopenharmony_ci		argv[0] = cmd;
4878c2ecf20Sopenharmony_ci	}
4888c2ecf20Sopenharmony_ci	if (strstarts(cmd, "trace")) {
4898c2ecf20Sopenharmony_ci#if defined(HAVE_LIBAUDIT_SUPPORT) || defined(HAVE_SYSCALL_TABLE_SUPPORT)
4908c2ecf20Sopenharmony_ci		setup_path();
4918c2ecf20Sopenharmony_ci		argv[0] = "trace";
4928c2ecf20Sopenharmony_ci		return cmd_trace(argc, argv);
4938c2ecf20Sopenharmony_ci#else
4948c2ecf20Sopenharmony_ci		fprintf(stderr,
4958c2ecf20Sopenharmony_ci			"trace command not available: missing audit-libs devel package at build time.\n");
4968c2ecf20Sopenharmony_ci		goto out;
4978c2ecf20Sopenharmony_ci#endif
4988c2ecf20Sopenharmony_ci	}
4998c2ecf20Sopenharmony_ci	/* Look for flags.. */
5008c2ecf20Sopenharmony_ci	argv++;
5018c2ecf20Sopenharmony_ci	argc--;
5028c2ecf20Sopenharmony_ci	handle_options(&argv, &argc, NULL);
5038c2ecf20Sopenharmony_ci	commit_pager_choice();
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci	if (argc > 0) {
5068c2ecf20Sopenharmony_ci		if (strstarts(argv[0], "--"))
5078c2ecf20Sopenharmony_ci			argv[0] += 2;
5088c2ecf20Sopenharmony_ci	} else {
5098c2ecf20Sopenharmony_ci		/* The user didn't specify a command; give them help */
5108c2ecf20Sopenharmony_ci		printf("\n usage: %s\n\n", perf_usage_string);
5118c2ecf20Sopenharmony_ci		list_common_cmds_help();
5128c2ecf20Sopenharmony_ci		printf("\n %s\n\n", perf_more_info_string);
5138c2ecf20Sopenharmony_ci		goto out;
5148c2ecf20Sopenharmony_ci	}
5158c2ecf20Sopenharmony_ci	cmd = argv[0];
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci	test_attr__init();
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci	/*
5208c2ecf20Sopenharmony_ci	 * We use PATH to find perf commands, but we prepend some higher
5218c2ecf20Sopenharmony_ci	 * precedence paths: the "--exec-path" option, the PERF_EXEC_PATH
5228c2ecf20Sopenharmony_ci	 * environment, and the $(perfexecdir) from the Makefile at build
5238c2ecf20Sopenharmony_ci	 * time.
5248c2ecf20Sopenharmony_ci	 */
5258c2ecf20Sopenharmony_ci	setup_path();
5268c2ecf20Sopenharmony_ci	/*
5278c2ecf20Sopenharmony_ci	 * Block SIGWINCH notifications so that the thread that wants it can
5288c2ecf20Sopenharmony_ci	 * unblock and get syscalls like select interrupted instead of waiting
5298c2ecf20Sopenharmony_ci	 * forever while the signal goes to some other non interested thread.
5308c2ecf20Sopenharmony_ci	 */
5318c2ecf20Sopenharmony_ci	pthread__block_sigwinch();
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci	perf_debug_setup();
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci	while (1) {
5368c2ecf20Sopenharmony_ci		static int done_help;
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_ci		run_argv(&argc, &argv);
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci		if (errno != ENOENT)
5418c2ecf20Sopenharmony_ci			break;
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci		if (!done_help) {
5448c2ecf20Sopenharmony_ci			cmd = argv[0] = help_unknown_cmd(cmd);
5458c2ecf20Sopenharmony_ci			done_help = 1;
5468c2ecf20Sopenharmony_ci		} else
5478c2ecf20Sopenharmony_ci			break;
5488c2ecf20Sopenharmony_ci	}
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci	fprintf(stderr, "Failed to run command '%s': %s\n",
5518c2ecf20Sopenharmony_ci		cmd, str_error_r(errno, sbuf, sizeof(sbuf)));
5528c2ecf20Sopenharmony_ciout:
5538c2ecf20Sopenharmony_ci	return 1;
5548c2ecf20Sopenharmony_ci}
555