xref: /OK3568_Linux_fs/kernel/tools/perf/perf.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * perf.c
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Performance analysis utility.
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * This is the main hub from which the sub-commands (perf stat,
7*4882a593Smuzhiyun  * perf top, perf record, perf report, etc.) are started.
8*4882a593Smuzhiyun  */
9*4882a593Smuzhiyun #include "builtin.h"
10*4882a593Smuzhiyun #include "perf.h"
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun #include "util/build-id.h"
13*4882a593Smuzhiyun #include "util/cache.h"
14*4882a593Smuzhiyun #include "util/env.h"
15*4882a593Smuzhiyun #include <internal/lib.h> // page_size
16*4882a593Smuzhiyun #include <subcmd/exec-cmd.h>
17*4882a593Smuzhiyun #include "util/config.h"
18*4882a593Smuzhiyun #include <subcmd/run-command.h>
19*4882a593Smuzhiyun #include "util/parse-events.h"
20*4882a593Smuzhiyun #include <subcmd/parse-options.h>
21*4882a593Smuzhiyun #include "util/bpf-loader.h"
22*4882a593Smuzhiyun #include "util/debug.h"
23*4882a593Smuzhiyun #include "util/event.h"
24*4882a593Smuzhiyun #include "util/util.h" // usage()
25*4882a593Smuzhiyun #include "ui/ui.h"
26*4882a593Smuzhiyun #include "perf-sys.h"
27*4882a593Smuzhiyun #include <api/fs/fs.h>
28*4882a593Smuzhiyun #include <api/fs/tracing_path.h>
29*4882a593Smuzhiyun #include <perf/core.h>
30*4882a593Smuzhiyun #include <errno.h>
31*4882a593Smuzhiyun #include <pthread.h>
32*4882a593Smuzhiyun #include <signal.h>
33*4882a593Smuzhiyun #include <stdlib.h>
34*4882a593Smuzhiyun #include <time.h>
35*4882a593Smuzhiyun #include <sys/types.h>
36*4882a593Smuzhiyun #include <sys/stat.h>
37*4882a593Smuzhiyun #include <unistd.h>
38*4882a593Smuzhiyun #include <linux/kernel.h>
39*4882a593Smuzhiyun #include <linux/string.h>
40*4882a593Smuzhiyun #include <linux/zalloc.h>
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun const char perf_usage_string[] =
43*4882a593Smuzhiyun 	"perf [--version] [--help] [OPTIONS] COMMAND [ARGS]";
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun const char perf_more_info_string[] =
46*4882a593Smuzhiyun 	"See 'perf help COMMAND' for more information on a specific command.";
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun static int use_pager = -1;
49*4882a593Smuzhiyun const char *input_name;
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun struct cmd_struct {
52*4882a593Smuzhiyun 	const char *cmd;
53*4882a593Smuzhiyun 	int (*fn)(int, const char **);
54*4882a593Smuzhiyun 	int option;
55*4882a593Smuzhiyun };
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun static struct cmd_struct commands[] = {
58*4882a593Smuzhiyun 	{ "buildid-cache", cmd_buildid_cache, 0 },
59*4882a593Smuzhiyun 	{ "buildid-list", cmd_buildid_list, 0 },
60*4882a593Smuzhiyun 	{ "config",	cmd_config,	0 },
61*4882a593Smuzhiyun 	{ "c2c",	cmd_c2c,	0 },
62*4882a593Smuzhiyun 	{ "diff",	cmd_diff,	0 },
63*4882a593Smuzhiyun 	{ "evlist",	cmd_evlist,	0 },
64*4882a593Smuzhiyun 	{ "help",	cmd_help,	0 },
65*4882a593Smuzhiyun 	{ "kallsyms",	cmd_kallsyms,	0 },
66*4882a593Smuzhiyun 	{ "list",	cmd_list,	0 },
67*4882a593Smuzhiyun 	{ "record",	cmd_record,	0 },
68*4882a593Smuzhiyun 	{ "report",	cmd_report,	0 },
69*4882a593Smuzhiyun 	{ "bench",	cmd_bench,	0 },
70*4882a593Smuzhiyun 	{ "stat",	cmd_stat,	0 },
71*4882a593Smuzhiyun 	{ "timechart",	cmd_timechart,	0 },
72*4882a593Smuzhiyun 	{ "top",	cmd_top,	0 },
73*4882a593Smuzhiyun 	{ "annotate",	cmd_annotate,	0 },
74*4882a593Smuzhiyun 	{ "version",	cmd_version,	0 },
75*4882a593Smuzhiyun 	{ "script",	cmd_script,	0 },
76*4882a593Smuzhiyun 	{ "sched",	cmd_sched,	0 },
77*4882a593Smuzhiyun #ifdef HAVE_LIBELF_SUPPORT
78*4882a593Smuzhiyun 	{ "probe",	cmd_probe,	0 },
79*4882a593Smuzhiyun #endif
80*4882a593Smuzhiyun 	{ "kmem",	cmd_kmem,	0 },
81*4882a593Smuzhiyun 	{ "lock",	cmd_lock,	0 },
82*4882a593Smuzhiyun 	{ "kvm",	cmd_kvm,	0 },
83*4882a593Smuzhiyun 	{ "test",	cmd_test,	0 },
84*4882a593Smuzhiyun #if defined(HAVE_LIBAUDIT_SUPPORT) || defined(HAVE_SYSCALL_TABLE_SUPPORT)
85*4882a593Smuzhiyun 	{ "trace",	cmd_trace,	0 },
86*4882a593Smuzhiyun #endif
87*4882a593Smuzhiyun 	{ "inject",	cmd_inject,	0 },
88*4882a593Smuzhiyun 	{ "mem",	cmd_mem,	0 },
89*4882a593Smuzhiyun 	{ "data",	cmd_data,	0 },
90*4882a593Smuzhiyun 	{ "ftrace",	cmd_ftrace,	0 },
91*4882a593Smuzhiyun };
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun struct pager_config {
94*4882a593Smuzhiyun 	const char *cmd;
95*4882a593Smuzhiyun 	int val;
96*4882a593Smuzhiyun };
97*4882a593Smuzhiyun 
pager_command_config(const char * var,const char * value,void * data)98*4882a593Smuzhiyun static int pager_command_config(const char *var, const char *value, void *data)
99*4882a593Smuzhiyun {
100*4882a593Smuzhiyun 	struct pager_config *c = data;
101*4882a593Smuzhiyun 	if (strstarts(var, "pager.") && !strcmp(var + 6, c->cmd))
102*4882a593Smuzhiyun 		c->val = perf_config_bool(var, value);
103*4882a593Smuzhiyun 	return 0;
104*4882a593Smuzhiyun }
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun /* returns 0 for "no pager", 1 for "use pager", and -1 for "not specified" */
check_pager_config(const char * cmd)107*4882a593Smuzhiyun static int check_pager_config(const char *cmd)
108*4882a593Smuzhiyun {
109*4882a593Smuzhiyun 	int err;
110*4882a593Smuzhiyun 	struct pager_config c;
111*4882a593Smuzhiyun 	c.cmd = cmd;
112*4882a593Smuzhiyun 	c.val = -1;
113*4882a593Smuzhiyun 	err = perf_config(pager_command_config, &c);
114*4882a593Smuzhiyun 	return err ?: c.val;
115*4882a593Smuzhiyun }
116*4882a593Smuzhiyun 
browser_command_config(const char * var,const char * value,void * data)117*4882a593Smuzhiyun static int browser_command_config(const char *var, const char *value, void *data)
118*4882a593Smuzhiyun {
119*4882a593Smuzhiyun 	struct pager_config *c = data;
120*4882a593Smuzhiyun 	if (strstarts(var, "tui.") && !strcmp(var + 4, c->cmd))
121*4882a593Smuzhiyun 		c->val = perf_config_bool(var, value);
122*4882a593Smuzhiyun 	if (strstarts(var, "gtk.") && !strcmp(var + 4, c->cmd))
123*4882a593Smuzhiyun 		c->val = perf_config_bool(var, value) ? 2 : 0;
124*4882a593Smuzhiyun 	return 0;
125*4882a593Smuzhiyun }
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun /*
128*4882a593Smuzhiyun  * returns 0 for "no tui", 1 for "use tui", 2 for "use gtk",
129*4882a593Smuzhiyun  * and -1 for "not specified"
130*4882a593Smuzhiyun  */
check_browser_config(const char * cmd)131*4882a593Smuzhiyun static int check_browser_config(const char *cmd)
132*4882a593Smuzhiyun {
133*4882a593Smuzhiyun 	int err;
134*4882a593Smuzhiyun 	struct pager_config c;
135*4882a593Smuzhiyun 	c.cmd = cmd;
136*4882a593Smuzhiyun 	c.val = -1;
137*4882a593Smuzhiyun 	err = perf_config(browser_command_config, &c);
138*4882a593Smuzhiyun 	return err ?: c.val;
139*4882a593Smuzhiyun }
140*4882a593Smuzhiyun 
commit_pager_choice(void)141*4882a593Smuzhiyun static void commit_pager_choice(void)
142*4882a593Smuzhiyun {
143*4882a593Smuzhiyun 	switch (use_pager) {
144*4882a593Smuzhiyun 	case 0:
145*4882a593Smuzhiyun 		setenv(PERF_PAGER_ENVIRONMENT, "cat", 1);
146*4882a593Smuzhiyun 		break;
147*4882a593Smuzhiyun 	case 1:
148*4882a593Smuzhiyun 		/* setup_pager(); */
149*4882a593Smuzhiyun 		break;
150*4882a593Smuzhiyun 	default:
151*4882a593Smuzhiyun 		break;
152*4882a593Smuzhiyun 	}
153*4882a593Smuzhiyun }
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun struct option options[] = {
156*4882a593Smuzhiyun 	OPT_ARGUMENT("help", "help"),
157*4882a593Smuzhiyun 	OPT_ARGUMENT("version", "version"),
158*4882a593Smuzhiyun 	OPT_ARGUMENT("exec-path", "exec-path"),
159*4882a593Smuzhiyun 	OPT_ARGUMENT("html-path", "html-path"),
160*4882a593Smuzhiyun 	OPT_ARGUMENT("paginate", "paginate"),
161*4882a593Smuzhiyun 	OPT_ARGUMENT("no-pager", "no-pager"),
162*4882a593Smuzhiyun 	OPT_ARGUMENT("debugfs-dir", "debugfs-dir"),
163*4882a593Smuzhiyun 	OPT_ARGUMENT("buildid-dir", "buildid-dir"),
164*4882a593Smuzhiyun 	OPT_ARGUMENT("list-cmds", "list-cmds"),
165*4882a593Smuzhiyun 	OPT_ARGUMENT("list-opts", "list-opts"),
166*4882a593Smuzhiyun 	OPT_ARGUMENT("debug", "debug"),
167*4882a593Smuzhiyun 	OPT_END()
168*4882a593Smuzhiyun };
169*4882a593Smuzhiyun 
handle_options(const char *** argv,int * argc,int * envchanged)170*4882a593Smuzhiyun static int handle_options(const char ***argv, int *argc, int *envchanged)
171*4882a593Smuzhiyun {
172*4882a593Smuzhiyun 	int handled = 0;
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun 	while (*argc > 0) {
175*4882a593Smuzhiyun 		const char *cmd = (*argv)[0];
176*4882a593Smuzhiyun 		if (cmd[0] != '-')
177*4882a593Smuzhiyun 			break;
178*4882a593Smuzhiyun 
179*4882a593Smuzhiyun 		/*
180*4882a593Smuzhiyun 		 * For legacy reasons, the "version" and "help"
181*4882a593Smuzhiyun 		 * commands can be written with "--" prepended
182*4882a593Smuzhiyun 		 * to make them look like flags.
183*4882a593Smuzhiyun 		 */
184*4882a593Smuzhiyun 		if (!strcmp(cmd, "--help") || !strcmp(cmd, "--version"))
185*4882a593Smuzhiyun 			break;
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun 		/*
188*4882a593Smuzhiyun 		 * Shortcut for '-h' and '-v' options to invoke help
189*4882a593Smuzhiyun 		 * and version command.
190*4882a593Smuzhiyun 		 */
191*4882a593Smuzhiyun 		if (!strcmp(cmd, "-h")) {
192*4882a593Smuzhiyun 			(*argv)[0] = "--help";
193*4882a593Smuzhiyun 			break;
194*4882a593Smuzhiyun 		}
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun 		if (!strcmp(cmd, "-v")) {
197*4882a593Smuzhiyun 			(*argv)[0] = "--version";
198*4882a593Smuzhiyun 			break;
199*4882a593Smuzhiyun 		}
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun 		if (!strcmp(cmd, "-vv")) {
202*4882a593Smuzhiyun 			(*argv)[0] = "version";
203*4882a593Smuzhiyun 			version_verbose = 1;
204*4882a593Smuzhiyun 			break;
205*4882a593Smuzhiyun 		}
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun 		/*
208*4882a593Smuzhiyun 		 * Check remaining flags.
209*4882a593Smuzhiyun 		 */
210*4882a593Smuzhiyun 		if (strstarts(cmd, CMD_EXEC_PATH)) {
211*4882a593Smuzhiyun 			cmd += strlen(CMD_EXEC_PATH);
212*4882a593Smuzhiyun 			if (*cmd == '=')
213*4882a593Smuzhiyun 				set_argv_exec_path(cmd + 1);
214*4882a593Smuzhiyun 			else {
215*4882a593Smuzhiyun 				puts(get_argv_exec_path());
216*4882a593Smuzhiyun 				exit(0);
217*4882a593Smuzhiyun 			}
218*4882a593Smuzhiyun 		} else if (!strcmp(cmd, "--html-path")) {
219*4882a593Smuzhiyun 			puts(system_path(PERF_HTML_PATH));
220*4882a593Smuzhiyun 			exit(0);
221*4882a593Smuzhiyun 		} else if (!strcmp(cmd, "-p") || !strcmp(cmd, "--paginate")) {
222*4882a593Smuzhiyun 			use_pager = 1;
223*4882a593Smuzhiyun 		} else if (!strcmp(cmd, "--no-pager")) {
224*4882a593Smuzhiyun 			use_pager = 0;
225*4882a593Smuzhiyun 			if (envchanged)
226*4882a593Smuzhiyun 				*envchanged = 1;
227*4882a593Smuzhiyun 		} else if (!strcmp(cmd, "--debugfs-dir")) {
228*4882a593Smuzhiyun 			if (*argc < 2) {
229*4882a593Smuzhiyun 				fprintf(stderr, "No directory given for --debugfs-dir.\n");
230*4882a593Smuzhiyun 				usage(perf_usage_string);
231*4882a593Smuzhiyun 			}
232*4882a593Smuzhiyun 			tracing_path_set((*argv)[1]);
233*4882a593Smuzhiyun 			if (envchanged)
234*4882a593Smuzhiyun 				*envchanged = 1;
235*4882a593Smuzhiyun 			(*argv)++;
236*4882a593Smuzhiyun 			(*argc)--;
237*4882a593Smuzhiyun 		} else if (!strcmp(cmd, "--buildid-dir")) {
238*4882a593Smuzhiyun 			if (*argc < 2) {
239*4882a593Smuzhiyun 				fprintf(stderr, "No directory given for --buildid-dir.\n");
240*4882a593Smuzhiyun 				usage(perf_usage_string);
241*4882a593Smuzhiyun 			}
242*4882a593Smuzhiyun 			set_buildid_dir((*argv)[1]);
243*4882a593Smuzhiyun 			if (envchanged)
244*4882a593Smuzhiyun 				*envchanged = 1;
245*4882a593Smuzhiyun 			(*argv)++;
246*4882a593Smuzhiyun 			(*argc)--;
247*4882a593Smuzhiyun 		} else if (strstarts(cmd, CMD_DEBUGFS_DIR)) {
248*4882a593Smuzhiyun 			tracing_path_set(cmd + strlen(CMD_DEBUGFS_DIR));
249*4882a593Smuzhiyun 			fprintf(stderr, "dir: %s\n", tracing_path_mount());
250*4882a593Smuzhiyun 			if (envchanged)
251*4882a593Smuzhiyun 				*envchanged = 1;
252*4882a593Smuzhiyun 		} else if (!strcmp(cmd, "--list-cmds")) {
253*4882a593Smuzhiyun 			unsigned int i;
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun 			for (i = 0; i < ARRAY_SIZE(commands); i++) {
256*4882a593Smuzhiyun 				struct cmd_struct *p = commands+i;
257*4882a593Smuzhiyun 				printf("%s ", p->cmd);
258*4882a593Smuzhiyun 			}
259*4882a593Smuzhiyun 			putchar('\n');
260*4882a593Smuzhiyun 			exit(0);
261*4882a593Smuzhiyun 		} else if (!strcmp(cmd, "--list-opts")) {
262*4882a593Smuzhiyun 			unsigned int i;
263*4882a593Smuzhiyun 
264*4882a593Smuzhiyun 			for (i = 0; i < ARRAY_SIZE(options)-1; i++) {
265*4882a593Smuzhiyun 				struct option *p = options+i;
266*4882a593Smuzhiyun 				printf("--%s ", p->long_name);
267*4882a593Smuzhiyun 			}
268*4882a593Smuzhiyun 			putchar('\n');
269*4882a593Smuzhiyun 			exit(0);
270*4882a593Smuzhiyun 		} else if (!strcmp(cmd, "--debug")) {
271*4882a593Smuzhiyun 			if (*argc < 2) {
272*4882a593Smuzhiyun 				fprintf(stderr, "No variable specified for --debug.\n");
273*4882a593Smuzhiyun 				usage(perf_usage_string);
274*4882a593Smuzhiyun 			}
275*4882a593Smuzhiyun 			if (perf_debug_option((*argv)[1]))
276*4882a593Smuzhiyun 				usage(perf_usage_string);
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun 			(*argv)++;
279*4882a593Smuzhiyun 			(*argc)--;
280*4882a593Smuzhiyun 		} else {
281*4882a593Smuzhiyun 			fprintf(stderr, "Unknown option: %s\n", cmd);
282*4882a593Smuzhiyun 			usage(perf_usage_string);
283*4882a593Smuzhiyun 		}
284*4882a593Smuzhiyun 
285*4882a593Smuzhiyun 		(*argv)++;
286*4882a593Smuzhiyun 		(*argc)--;
287*4882a593Smuzhiyun 		handled++;
288*4882a593Smuzhiyun 	}
289*4882a593Smuzhiyun 	return handled;
290*4882a593Smuzhiyun }
291*4882a593Smuzhiyun 
292*4882a593Smuzhiyun #define RUN_SETUP	(1<<0)
293*4882a593Smuzhiyun #define USE_PAGER	(1<<1)
294*4882a593Smuzhiyun 
run_builtin(struct cmd_struct * p,int argc,const char ** argv)295*4882a593Smuzhiyun static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
296*4882a593Smuzhiyun {
297*4882a593Smuzhiyun 	int status;
298*4882a593Smuzhiyun 	struct stat st;
299*4882a593Smuzhiyun 	char sbuf[STRERR_BUFSIZE];
300*4882a593Smuzhiyun 
301*4882a593Smuzhiyun 	if (use_browser == -1)
302*4882a593Smuzhiyun 		use_browser = check_browser_config(p->cmd);
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun 	if (use_pager == -1 && p->option & RUN_SETUP)
305*4882a593Smuzhiyun 		use_pager = check_pager_config(p->cmd);
306*4882a593Smuzhiyun 	if (use_pager == -1 && p->option & USE_PAGER)
307*4882a593Smuzhiyun 		use_pager = 1;
308*4882a593Smuzhiyun 	commit_pager_choice();
309*4882a593Smuzhiyun 
310*4882a593Smuzhiyun 	perf_env__init(&perf_env);
311*4882a593Smuzhiyun 	perf_env__set_cmdline(&perf_env, argc, argv);
312*4882a593Smuzhiyun 	status = p->fn(argc, argv);
313*4882a593Smuzhiyun 	perf_config__exit();
314*4882a593Smuzhiyun 	exit_browser(status);
315*4882a593Smuzhiyun 	perf_env__exit(&perf_env);
316*4882a593Smuzhiyun 	bpf__clear();
317*4882a593Smuzhiyun 
318*4882a593Smuzhiyun 	if (status)
319*4882a593Smuzhiyun 		return status & 0xff;
320*4882a593Smuzhiyun 
321*4882a593Smuzhiyun 	/* Somebody closed stdout? */
322*4882a593Smuzhiyun 	if (fstat(fileno(stdout), &st))
323*4882a593Smuzhiyun 		return 0;
324*4882a593Smuzhiyun 	/* Ignore write errors for pipes and sockets.. */
325*4882a593Smuzhiyun 	if (S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode))
326*4882a593Smuzhiyun 		return 0;
327*4882a593Smuzhiyun 
328*4882a593Smuzhiyun 	status = 1;
329*4882a593Smuzhiyun 	/* Check for ENOSPC and EIO errors.. */
330*4882a593Smuzhiyun 	if (fflush(stdout)) {
331*4882a593Smuzhiyun 		fprintf(stderr, "write failure on standard output: %s",
332*4882a593Smuzhiyun 			str_error_r(errno, sbuf, sizeof(sbuf)));
333*4882a593Smuzhiyun 		goto out;
334*4882a593Smuzhiyun 	}
335*4882a593Smuzhiyun 	if (ferror(stdout)) {
336*4882a593Smuzhiyun 		fprintf(stderr, "unknown write failure on standard output");
337*4882a593Smuzhiyun 		goto out;
338*4882a593Smuzhiyun 	}
339*4882a593Smuzhiyun 	if (fclose(stdout)) {
340*4882a593Smuzhiyun 		fprintf(stderr, "close failed on standard output: %s",
341*4882a593Smuzhiyun 			str_error_r(errno, sbuf, sizeof(sbuf)));
342*4882a593Smuzhiyun 		goto out;
343*4882a593Smuzhiyun 	}
344*4882a593Smuzhiyun 	status = 0;
345*4882a593Smuzhiyun out:
346*4882a593Smuzhiyun 	return status;
347*4882a593Smuzhiyun }
348*4882a593Smuzhiyun 
handle_internal_command(int argc,const char ** argv)349*4882a593Smuzhiyun static void handle_internal_command(int argc, const char **argv)
350*4882a593Smuzhiyun {
351*4882a593Smuzhiyun 	const char *cmd = argv[0];
352*4882a593Smuzhiyun 	unsigned int i;
353*4882a593Smuzhiyun 
354*4882a593Smuzhiyun 	/* Turn "perf cmd --help" into "perf help cmd" */
355*4882a593Smuzhiyun 	if (argc > 1 && !strcmp(argv[1], "--help")) {
356*4882a593Smuzhiyun 		argv[1] = argv[0];
357*4882a593Smuzhiyun 		argv[0] = cmd = "help";
358*4882a593Smuzhiyun 	}
359*4882a593Smuzhiyun 
360*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(commands); i++) {
361*4882a593Smuzhiyun 		struct cmd_struct *p = commands+i;
362*4882a593Smuzhiyun 		if (strcmp(p->cmd, cmd))
363*4882a593Smuzhiyun 			continue;
364*4882a593Smuzhiyun 		exit(run_builtin(p, argc, argv));
365*4882a593Smuzhiyun 	}
366*4882a593Smuzhiyun }
367*4882a593Smuzhiyun 
execv_dashed_external(const char ** argv)368*4882a593Smuzhiyun static void execv_dashed_external(const char **argv)
369*4882a593Smuzhiyun {
370*4882a593Smuzhiyun 	char *cmd;
371*4882a593Smuzhiyun 	const char *tmp;
372*4882a593Smuzhiyun 	int status;
373*4882a593Smuzhiyun 
374*4882a593Smuzhiyun 	if (asprintf(&cmd, "perf-%s", argv[0]) < 0)
375*4882a593Smuzhiyun 		goto do_die;
376*4882a593Smuzhiyun 
377*4882a593Smuzhiyun 	/*
378*4882a593Smuzhiyun 	 * argv[0] must be the perf command, but the argv array
379*4882a593Smuzhiyun 	 * belongs to the caller, and may be reused in
380*4882a593Smuzhiyun 	 * subsequent loop iterations. Save argv[0] and
381*4882a593Smuzhiyun 	 * restore it on error.
382*4882a593Smuzhiyun 	 */
383*4882a593Smuzhiyun 	tmp = argv[0];
384*4882a593Smuzhiyun 	argv[0] = cmd;
385*4882a593Smuzhiyun 
386*4882a593Smuzhiyun 	/*
387*4882a593Smuzhiyun 	 * if we fail because the command is not found, it is
388*4882a593Smuzhiyun 	 * OK to return. Otherwise, we just pass along the status code.
389*4882a593Smuzhiyun 	 */
390*4882a593Smuzhiyun 	status = run_command_v_opt(argv, 0);
391*4882a593Smuzhiyun 	if (status != -ERR_RUN_COMMAND_EXEC) {
392*4882a593Smuzhiyun 		if (IS_RUN_COMMAND_ERR(status)) {
393*4882a593Smuzhiyun do_die:
394*4882a593Smuzhiyun 			pr_err("FATAL: unable to run '%s'", argv[0]);
395*4882a593Smuzhiyun 			status = -128;
396*4882a593Smuzhiyun 		}
397*4882a593Smuzhiyun 		exit(-status);
398*4882a593Smuzhiyun 	}
399*4882a593Smuzhiyun 	errno = ENOENT; /* as if we called execvp */
400*4882a593Smuzhiyun 
401*4882a593Smuzhiyun 	argv[0] = tmp;
402*4882a593Smuzhiyun 	zfree(&cmd);
403*4882a593Smuzhiyun }
404*4882a593Smuzhiyun 
run_argv(int * argcp,const char *** argv)405*4882a593Smuzhiyun static int run_argv(int *argcp, const char ***argv)
406*4882a593Smuzhiyun {
407*4882a593Smuzhiyun 	/* See if it's an internal command */
408*4882a593Smuzhiyun 	handle_internal_command(*argcp, *argv);
409*4882a593Smuzhiyun 
410*4882a593Smuzhiyun 	/* .. then try the external ones */
411*4882a593Smuzhiyun 	execv_dashed_external(*argv);
412*4882a593Smuzhiyun 	return 0;
413*4882a593Smuzhiyun }
414*4882a593Smuzhiyun 
pthread__block_sigwinch(void)415*4882a593Smuzhiyun static void pthread__block_sigwinch(void)
416*4882a593Smuzhiyun {
417*4882a593Smuzhiyun 	sigset_t set;
418*4882a593Smuzhiyun 
419*4882a593Smuzhiyun 	sigemptyset(&set);
420*4882a593Smuzhiyun 	sigaddset(&set, SIGWINCH);
421*4882a593Smuzhiyun 	pthread_sigmask(SIG_BLOCK, &set, NULL);
422*4882a593Smuzhiyun }
423*4882a593Smuzhiyun 
pthread__unblock_sigwinch(void)424*4882a593Smuzhiyun void pthread__unblock_sigwinch(void)
425*4882a593Smuzhiyun {
426*4882a593Smuzhiyun 	sigset_t set;
427*4882a593Smuzhiyun 
428*4882a593Smuzhiyun 	sigemptyset(&set);
429*4882a593Smuzhiyun 	sigaddset(&set, SIGWINCH);
430*4882a593Smuzhiyun 	pthread_sigmask(SIG_UNBLOCK, &set, NULL);
431*4882a593Smuzhiyun }
432*4882a593Smuzhiyun 
libperf_print(enum libperf_print_level level,const char * fmt,va_list ap)433*4882a593Smuzhiyun static int libperf_print(enum libperf_print_level level,
434*4882a593Smuzhiyun 			 const char *fmt, va_list ap)
435*4882a593Smuzhiyun {
436*4882a593Smuzhiyun 	return veprintf(level, verbose, fmt, ap);
437*4882a593Smuzhiyun }
438*4882a593Smuzhiyun 
main(int argc,const char ** argv)439*4882a593Smuzhiyun int main(int argc, const char **argv)
440*4882a593Smuzhiyun {
441*4882a593Smuzhiyun 	int err;
442*4882a593Smuzhiyun 	const char *cmd;
443*4882a593Smuzhiyun 	char sbuf[STRERR_BUFSIZE];
444*4882a593Smuzhiyun 
445*4882a593Smuzhiyun 	/* libsubcmd init */
446*4882a593Smuzhiyun 	exec_cmd_init("perf", PREFIX, PERF_EXEC_PATH, EXEC_PATH_ENVIRONMENT);
447*4882a593Smuzhiyun 	pager_init(PERF_PAGER_ENVIRONMENT);
448*4882a593Smuzhiyun 
449*4882a593Smuzhiyun 	libperf_init(libperf_print);
450*4882a593Smuzhiyun 
451*4882a593Smuzhiyun 	cmd = extract_argv0_path(argv[0]);
452*4882a593Smuzhiyun 	if (!cmd)
453*4882a593Smuzhiyun 		cmd = "perf-help";
454*4882a593Smuzhiyun 
455*4882a593Smuzhiyun 	srandom(time(NULL));
456*4882a593Smuzhiyun 
457*4882a593Smuzhiyun 	/* Setting $PERF_CONFIG makes perf read _only_ the given config file. */
458*4882a593Smuzhiyun 	config_exclusive_filename = getenv("PERF_CONFIG");
459*4882a593Smuzhiyun 
460*4882a593Smuzhiyun 	err = perf_config(perf_default_config, NULL);
461*4882a593Smuzhiyun 	if (err)
462*4882a593Smuzhiyun 		return err;
463*4882a593Smuzhiyun 	set_buildid_dir(NULL);
464*4882a593Smuzhiyun 
465*4882a593Smuzhiyun 	/*
466*4882a593Smuzhiyun 	 * "perf-xxxx" is the same as "perf xxxx", but we obviously:
467*4882a593Smuzhiyun 	 *
468*4882a593Smuzhiyun 	 *  - cannot take flags in between the "perf" and the "xxxx".
469*4882a593Smuzhiyun 	 *  - cannot execute it externally (since it would just do
470*4882a593Smuzhiyun 	 *    the same thing over again)
471*4882a593Smuzhiyun 	 *
472*4882a593Smuzhiyun 	 * So we just directly call the internal command handler. If that one
473*4882a593Smuzhiyun 	 * fails to handle this, then maybe we just run a renamed perf binary
474*4882a593Smuzhiyun 	 * that contains a dash in its name. To handle this scenario, we just
475*4882a593Smuzhiyun 	 * fall through and ignore the "xxxx" part of the command string.
476*4882a593Smuzhiyun 	 */
477*4882a593Smuzhiyun 	if (strstarts(cmd, "perf-")) {
478*4882a593Smuzhiyun 		cmd += 5;
479*4882a593Smuzhiyun 		argv[0] = cmd;
480*4882a593Smuzhiyun 		handle_internal_command(argc, argv);
481*4882a593Smuzhiyun 		/*
482*4882a593Smuzhiyun 		 * If the command is handled, the above function does not
483*4882a593Smuzhiyun 		 * return undo changes and fall through in such a case.
484*4882a593Smuzhiyun 		 */
485*4882a593Smuzhiyun 		cmd -= 5;
486*4882a593Smuzhiyun 		argv[0] = cmd;
487*4882a593Smuzhiyun 	}
488*4882a593Smuzhiyun 	if (strstarts(cmd, "trace")) {
489*4882a593Smuzhiyun #if defined(HAVE_LIBAUDIT_SUPPORT) || defined(HAVE_SYSCALL_TABLE_SUPPORT)
490*4882a593Smuzhiyun 		setup_path();
491*4882a593Smuzhiyun 		argv[0] = "trace";
492*4882a593Smuzhiyun 		return cmd_trace(argc, argv);
493*4882a593Smuzhiyun #else
494*4882a593Smuzhiyun 		fprintf(stderr,
495*4882a593Smuzhiyun 			"trace command not available: missing audit-libs devel package at build time.\n");
496*4882a593Smuzhiyun 		goto out;
497*4882a593Smuzhiyun #endif
498*4882a593Smuzhiyun 	}
499*4882a593Smuzhiyun 	/* Look for flags.. */
500*4882a593Smuzhiyun 	argv++;
501*4882a593Smuzhiyun 	argc--;
502*4882a593Smuzhiyun 	handle_options(&argv, &argc, NULL);
503*4882a593Smuzhiyun 	commit_pager_choice();
504*4882a593Smuzhiyun 
505*4882a593Smuzhiyun 	if (argc > 0) {
506*4882a593Smuzhiyun 		if (strstarts(argv[0], "--"))
507*4882a593Smuzhiyun 			argv[0] += 2;
508*4882a593Smuzhiyun 	} else {
509*4882a593Smuzhiyun 		/* The user didn't specify a command; give them help */
510*4882a593Smuzhiyun 		printf("\n usage: %s\n\n", perf_usage_string);
511*4882a593Smuzhiyun 		list_common_cmds_help();
512*4882a593Smuzhiyun 		printf("\n %s\n\n", perf_more_info_string);
513*4882a593Smuzhiyun 		goto out;
514*4882a593Smuzhiyun 	}
515*4882a593Smuzhiyun 	cmd = argv[0];
516*4882a593Smuzhiyun 
517*4882a593Smuzhiyun 	test_attr__init();
518*4882a593Smuzhiyun 
519*4882a593Smuzhiyun 	/*
520*4882a593Smuzhiyun 	 * We use PATH to find perf commands, but we prepend some higher
521*4882a593Smuzhiyun 	 * precedence paths: the "--exec-path" option, the PERF_EXEC_PATH
522*4882a593Smuzhiyun 	 * environment, and the $(perfexecdir) from the Makefile at build
523*4882a593Smuzhiyun 	 * time.
524*4882a593Smuzhiyun 	 */
525*4882a593Smuzhiyun 	setup_path();
526*4882a593Smuzhiyun 	/*
527*4882a593Smuzhiyun 	 * Block SIGWINCH notifications so that the thread that wants it can
528*4882a593Smuzhiyun 	 * unblock and get syscalls like select interrupted instead of waiting
529*4882a593Smuzhiyun 	 * forever while the signal goes to some other non interested thread.
530*4882a593Smuzhiyun 	 */
531*4882a593Smuzhiyun 	pthread__block_sigwinch();
532*4882a593Smuzhiyun 
533*4882a593Smuzhiyun 	perf_debug_setup();
534*4882a593Smuzhiyun 
535*4882a593Smuzhiyun 	while (1) {
536*4882a593Smuzhiyun 		static int done_help;
537*4882a593Smuzhiyun 
538*4882a593Smuzhiyun 		run_argv(&argc, &argv);
539*4882a593Smuzhiyun 
540*4882a593Smuzhiyun 		if (errno != ENOENT)
541*4882a593Smuzhiyun 			break;
542*4882a593Smuzhiyun 
543*4882a593Smuzhiyun 		if (!done_help) {
544*4882a593Smuzhiyun 			cmd = argv[0] = help_unknown_cmd(cmd);
545*4882a593Smuzhiyun 			done_help = 1;
546*4882a593Smuzhiyun 		} else
547*4882a593Smuzhiyun 			break;
548*4882a593Smuzhiyun 	}
549*4882a593Smuzhiyun 
550*4882a593Smuzhiyun 	fprintf(stderr, "Failed to run command '%s': %s\n",
551*4882a593Smuzhiyun 		cmd, str_error_r(errno, sbuf, sizeof(sbuf)));
552*4882a593Smuzhiyun out:
553*4882a593Smuzhiyun 	return 1;
554*4882a593Smuzhiyun }
555