xref: /aosp_15_r20/external/trace-cmd/tracecmd/trace-stack.c (revision 58e6ee5f017f6a8912852c892d18457e4bafb554)
1*58e6ee5fSAndroid Build Coastguard Worker // SPDX-License-Identifier: GPL-2.0
2*58e6ee5fSAndroid Build Coastguard Worker /*
3*58e6ee5fSAndroid Build Coastguard Worker  * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <[email protected]>
4*58e6ee5fSAndroid Build Coastguard Worker  *
5*58e6ee5fSAndroid Build Coastguard Worker  */
6*58e6ee5fSAndroid Build Coastguard Worker #include <stdio.h>
7*58e6ee5fSAndroid Build Coastguard Worker #include <stdlib.h>
8*58e6ee5fSAndroid Build Coastguard Worker #include <string.h>
9*58e6ee5fSAndroid Build Coastguard Worker #include <limits.h>
10*58e6ee5fSAndroid Build Coastguard Worker #include <getopt.h>
11*58e6ee5fSAndroid Build Coastguard Worker #include <sys/types.h>
12*58e6ee5fSAndroid Build Coastguard Worker #include <sys/stat.h>
13*58e6ee5fSAndroid Build Coastguard Worker #include <sys/wait.h>
14*58e6ee5fSAndroid Build Coastguard Worker #include <fcntl.h>
15*58e6ee5fSAndroid Build Coastguard Worker #include <unistd.h>
16*58e6ee5fSAndroid Build Coastguard Worker #include <errno.h>
17*58e6ee5fSAndroid Build Coastguard Worker 
18*58e6ee5fSAndroid Build Coastguard Worker #include "tracefs.h"
19*58e6ee5fSAndroid Build Coastguard Worker #include "trace-local.h"
20*58e6ee5fSAndroid Build Coastguard Worker 
21*58e6ee5fSAndroid Build Coastguard Worker #define PROC_FILE "/proc/sys/kernel/stack_tracer_enabled"
22*58e6ee5fSAndroid Build Coastguard Worker 
23*58e6ee5fSAndroid Build Coastguard Worker enum stack_type {
24*58e6ee5fSAndroid Build Coastguard Worker 	STACK_START,
25*58e6ee5fSAndroid Build Coastguard Worker 	STACK_STOP,
26*58e6ee5fSAndroid Build Coastguard Worker 	STACK_RESET,
27*58e6ee5fSAndroid Build Coastguard Worker 	STACK_REPORT
28*58e6ee5fSAndroid Build Coastguard Worker };
29*58e6ee5fSAndroid Build Coastguard Worker 
test_available(void)30*58e6ee5fSAndroid Build Coastguard Worker static void test_available(void)
31*58e6ee5fSAndroid Build Coastguard Worker {
32*58e6ee5fSAndroid Build Coastguard Worker 	struct stat buf;
33*58e6ee5fSAndroid Build Coastguard Worker 	int fd;
34*58e6ee5fSAndroid Build Coastguard Worker 
35*58e6ee5fSAndroid Build Coastguard Worker 	fd = stat(PROC_FILE, &buf);
36*58e6ee5fSAndroid Build Coastguard Worker 	if (fd < 0)
37*58e6ee5fSAndroid Build Coastguard Worker 		die("stack tracer not configured on running kernel");
38*58e6ee5fSAndroid Build Coastguard Worker }
39*58e6ee5fSAndroid Build Coastguard Worker 
40*58e6ee5fSAndroid Build Coastguard Worker /* NOTE: this implementation only accepts new_status in the range [0..9]. */
change_stack_tracer_status(unsigned new_status)41*58e6ee5fSAndroid Build Coastguard Worker static void change_stack_tracer_status(unsigned new_status)
42*58e6ee5fSAndroid Build Coastguard Worker {
43*58e6ee5fSAndroid Build Coastguard Worker 	char buf[1];
44*58e6ee5fSAndroid Build Coastguard Worker 	int status;
45*58e6ee5fSAndroid Build Coastguard Worker 	int ret;
46*58e6ee5fSAndroid Build Coastguard Worker 	int fd;
47*58e6ee5fSAndroid Build Coastguard Worker 	int n;
48*58e6ee5fSAndroid Build Coastguard Worker 
49*58e6ee5fSAndroid Build Coastguard Worker 	if (new_status > 9) {
50*58e6ee5fSAndroid Build Coastguard Worker 		warning("invalid status %d\n", new_status);
51*58e6ee5fSAndroid Build Coastguard Worker 		return;
52*58e6ee5fSAndroid Build Coastguard Worker 	}
53*58e6ee5fSAndroid Build Coastguard Worker 
54*58e6ee5fSAndroid Build Coastguard Worker 	ret = tracecmd_stack_tracer_status(&status);
55*58e6ee5fSAndroid Build Coastguard Worker 	if (ret < 0)
56*58e6ee5fSAndroid Build Coastguard Worker 		die("error reading %s", PROC_FILE);
57*58e6ee5fSAndroid Build Coastguard Worker 
58*58e6ee5fSAndroid Build Coastguard Worker 	if (ret > 0 && status == new_status)
59*58e6ee5fSAndroid Build Coastguard Worker 		return; /* nothing to do */
60*58e6ee5fSAndroid Build Coastguard Worker 
61*58e6ee5fSAndroid Build Coastguard Worker 	fd = open(PROC_FILE, O_WRONLY);
62*58e6ee5fSAndroid Build Coastguard Worker 	if (fd < 0)
63*58e6ee5fSAndroid Build Coastguard Worker 		die("writing %s", PROC_FILE);
64*58e6ee5fSAndroid Build Coastguard Worker 
65*58e6ee5fSAndroid Build Coastguard Worker 	buf[0] = new_status + '0';
66*58e6ee5fSAndroid Build Coastguard Worker 
67*58e6ee5fSAndroid Build Coastguard Worker 	n = write(fd, buf, 1);
68*58e6ee5fSAndroid Build Coastguard Worker 	if (n < 0)
69*58e6ee5fSAndroid Build Coastguard Worker 		die("writing into %s", PROC_FILE);
70*58e6ee5fSAndroid Build Coastguard Worker 	close(fd);
71*58e6ee5fSAndroid Build Coastguard Worker }
72*58e6ee5fSAndroid Build Coastguard Worker 
start_trace(void)73*58e6ee5fSAndroid Build Coastguard Worker static void start_trace(void)
74*58e6ee5fSAndroid Build Coastguard Worker {
75*58e6ee5fSAndroid Build Coastguard Worker 	change_stack_tracer_status(1);
76*58e6ee5fSAndroid Build Coastguard Worker }
77*58e6ee5fSAndroid Build Coastguard Worker 
stop_trace(void)78*58e6ee5fSAndroid Build Coastguard Worker static void stop_trace(void)
79*58e6ee5fSAndroid Build Coastguard Worker {
80*58e6ee5fSAndroid Build Coastguard Worker 	change_stack_tracer_status(0);
81*58e6ee5fSAndroid Build Coastguard Worker }
82*58e6ee5fSAndroid Build Coastguard Worker 
reset_trace(void)83*58e6ee5fSAndroid Build Coastguard Worker static void reset_trace(void)
84*58e6ee5fSAndroid Build Coastguard Worker {
85*58e6ee5fSAndroid Build Coastguard Worker 	char *path;
86*58e6ee5fSAndroid Build Coastguard Worker 	char buf[1];
87*58e6ee5fSAndroid Build Coastguard Worker 	int fd;
88*58e6ee5fSAndroid Build Coastguard Worker 	int n;
89*58e6ee5fSAndroid Build Coastguard Worker 
90*58e6ee5fSAndroid Build Coastguard Worker 	path = tracefs_get_tracing_file("stack_max_size");
91*58e6ee5fSAndroid Build Coastguard Worker 	fd = open(path, O_WRONLY);
92*58e6ee5fSAndroid Build Coastguard Worker 	if (fd < 0)
93*58e6ee5fSAndroid Build Coastguard Worker 		die("writing %s", path);
94*58e6ee5fSAndroid Build Coastguard Worker 
95*58e6ee5fSAndroid Build Coastguard Worker 	buf[0] = '0';
96*58e6ee5fSAndroid Build Coastguard Worker 	n = write(fd, buf, 1);
97*58e6ee5fSAndroid Build Coastguard Worker 	if (n < 0)
98*58e6ee5fSAndroid Build Coastguard Worker 		die("writing into %s", path);
99*58e6ee5fSAndroid Build Coastguard Worker 	tracefs_put_tracing_file(path);
100*58e6ee5fSAndroid Build Coastguard Worker 	close(fd);
101*58e6ee5fSAndroid Build Coastguard Worker }
102*58e6ee5fSAndroid Build Coastguard Worker 
read_trace(void)103*58e6ee5fSAndroid Build Coastguard Worker static void read_trace(void)
104*58e6ee5fSAndroid Build Coastguard Worker {
105*58e6ee5fSAndroid Build Coastguard Worker 	char *buf = NULL;
106*58e6ee5fSAndroid Build Coastguard Worker 	int status;
107*58e6ee5fSAndroid Build Coastguard Worker 	char *path;
108*58e6ee5fSAndroid Build Coastguard Worker 	FILE *fp;
109*58e6ee5fSAndroid Build Coastguard Worker 	size_t n;
110*58e6ee5fSAndroid Build Coastguard Worker 	int r;
111*58e6ee5fSAndroid Build Coastguard Worker 
112*58e6ee5fSAndroid Build Coastguard Worker 	if (tracecmd_stack_tracer_status(&status) <= 0)
113*58e6ee5fSAndroid Build Coastguard Worker 		die("Invalid stack tracer state");
114*58e6ee5fSAndroid Build Coastguard Worker 
115*58e6ee5fSAndroid Build Coastguard Worker 	if (status > 0)
116*58e6ee5fSAndroid Build Coastguard Worker 		printf("(stack tracer running)\n");
117*58e6ee5fSAndroid Build Coastguard Worker 	else
118*58e6ee5fSAndroid Build Coastguard Worker 		printf("(stack tracer not running)\n");
119*58e6ee5fSAndroid Build Coastguard Worker 
120*58e6ee5fSAndroid Build Coastguard Worker 	path = tracefs_get_tracing_file("stack_trace");
121*58e6ee5fSAndroid Build Coastguard Worker 	fp = fopen(path, "r");
122*58e6ee5fSAndroid Build Coastguard Worker 	if (!fp)
123*58e6ee5fSAndroid Build Coastguard Worker 		die("reading to '%s'", path);
124*58e6ee5fSAndroid Build Coastguard Worker 	tracefs_put_tracing_file(path);
125*58e6ee5fSAndroid Build Coastguard Worker 
126*58e6ee5fSAndroid Build Coastguard Worker 	while ((r = getline(&buf, &n, fp)) >= 0) {
127*58e6ee5fSAndroid Build Coastguard Worker 		/*
128*58e6ee5fSAndroid Build Coastguard Worker 		 * Skip any line that starts with a '#'.
129*58e6ee5fSAndroid Build Coastguard Worker 		 * Those talk about how to enable stack tracing
130*58e6ee5fSAndroid Build Coastguard Worker 		 * within the debugfs system. We don't care about that.
131*58e6ee5fSAndroid Build Coastguard Worker 		 */
132*58e6ee5fSAndroid Build Coastguard Worker 		if (buf[0] != '#')
133*58e6ee5fSAndroid Build Coastguard Worker 			printf("%s", buf);
134*58e6ee5fSAndroid Build Coastguard Worker 
135*58e6ee5fSAndroid Build Coastguard Worker 		free(buf);
136*58e6ee5fSAndroid Build Coastguard Worker 		buf = NULL;
137*58e6ee5fSAndroid Build Coastguard Worker 	}
138*58e6ee5fSAndroid Build Coastguard Worker 
139*58e6ee5fSAndroid Build Coastguard Worker 	fclose(fp);
140*58e6ee5fSAndroid Build Coastguard Worker }
141*58e6ee5fSAndroid Build Coastguard Worker 
142*58e6ee5fSAndroid Build Coastguard Worker enum {
143*58e6ee5fSAndroid Build Coastguard Worker 	OPT_verbose	= 252,
144*58e6ee5fSAndroid Build Coastguard Worker 	OPT_reset	= 253,
145*58e6ee5fSAndroid Build Coastguard Worker 	OPT_stop	= 254,
146*58e6ee5fSAndroid Build Coastguard Worker 	OPT_start	= 255,
147*58e6ee5fSAndroid Build Coastguard Worker };
148*58e6ee5fSAndroid Build Coastguard Worker 
trace_stack(int argc,char ** argv)149*58e6ee5fSAndroid Build Coastguard Worker void trace_stack (int argc, char **argv)
150*58e6ee5fSAndroid Build Coastguard Worker {
151*58e6ee5fSAndroid Build Coastguard Worker 	enum stack_type trace_type = STACK_REPORT;
152*58e6ee5fSAndroid Build Coastguard Worker 	int c;
153*58e6ee5fSAndroid Build Coastguard Worker 
154*58e6ee5fSAndroid Build Coastguard Worker 	if (argc < 2)
155*58e6ee5fSAndroid Build Coastguard Worker 		usage(argv);
156*58e6ee5fSAndroid Build Coastguard Worker 
157*58e6ee5fSAndroid Build Coastguard Worker 	if (strcmp(argv[1], "stack") != 0)
158*58e6ee5fSAndroid Build Coastguard Worker 		usage(argv);
159*58e6ee5fSAndroid Build Coastguard Worker 
160*58e6ee5fSAndroid Build Coastguard Worker 	for (;;) {
161*58e6ee5fSAndroid Build Coastguard Worker 		int option_index = 0;
162*58e6ee5fSAndroid Build Coastguard Worker 		static struct option long_options[] = {
163*58e6ee5fSAndroid Build Coastguard Worker 			{"start", no_argument, NULL, OPT_start},
164*58e6ee5fSAndroid Build Coastguard Worker 			{"stop", no_argument, NULL, OPT_stop},
165*58e6ee5fSAndroid Build Coastguard Worker 			{"reset", no_argument, NULL, OPT_reset},
166*58e6ee5fSAndroid Build Coastguard Worker 			{"help", no_argument, NULL, '?'},
167*58e6ee5fSAndroid Build Coastguard Worker 			{"verbose", optional_argument, NULL, OPT_verbose},
168*58e6ee5fSAndroid Build Coastguard Worker 			{NULL, 0, NULL, 0}
169*58e6ee5fSAndroid Build Coastguard Worker 		};
170*58e6ee5fSAndroid Build Coastguard Worker 
171*58e6ee5fSAndroid Build Coastguard Worker 		c = getopt_long (argc-1, argv+1, "+h?",
172*58e6ee5fSAndroid Build Coastguard Worker 			long_options, &option_index);
173*58e6ee5fSAndroid Build Coastguard Worker 		if (c == -1)
174*58e6ee5fSAndroid Build Coastguard Worker 			break;
175*58e6ee5fSAndroid Build Coastguard Worker 
176*58e6ee5fSAndroid Build Coastguard Worker 		switch (c) {
177*58e6ee5fSAndroid Build Coastguard Worker 		case 'h':
178*58e6ee5fSAndroid Build Coastguard Worker 			usage(argv);
179*58e6ee5fSAndroid Build Coastguard Worker 			break;
180*58e6ee5fSAndroid Build Coastguard Worker 		case OPT_start:
181*58e6ee5fSAndroid Build Coastguard Worker 			trace_type = STACK_START;
182*58e6ee5fSAndroid Build Coastguard Worker 			break;
183*58e6ee5fSAndroid Build Coastguard Worker 		case OPT_stop:
184*58e6ee5fSAndroid Build Coastguard Worker 			trace_type = STACK_STOP;
185*58e6ee5fSAndroid Build Coastguard Worker 			break;
186*58e6ee5fSAndroid Build Coastguard Worker 		case OPT_reset:
187*58e6ee5fSAndroid Build Coastguard Worker 			trace_type = STACK_RESET;
188*58e6ee5fSAndroid Build Coastguard Worker 			break;
189*58e6ee5fSAndroid Build Coastguard Worker 		case OPT_verbose:
190*58e6ee5fSAndroid Build Coastguard Worker 			if (trace_set_verbose(optarg) < 0)
191*58e6ee5fSAndroid Build Coastguard Worker 				die("invalid verbose level %s", optarg);
192*58e6ee5fSAndroid Build Coastguard Worker 			break;
193*58e6ee5fSAndroid Build Coastguard Worker 		default:
194*58e6ee5fSAndroid Build Coastguard Worker 			usage(argv);
195*58e6ee5fSAndroid Build Coastguard Worker 		}
196*58e6ee5fSAndroid Build Coastguard Worker 	}
197*58e6ee5fSAndroid Build Coastguard Worker 
198*58e6ee5fSAndroid Build Coastguard Worker 	test_available();
199*58e6ee5fSAndroid Build Coastguard Worker 
200*58e6ee5fSAndroid Build Coastguard Worker 	switch (trace_type) {
201*58e6ee5fSAndroid Build Coastguard Worker 	case STACK_START:
202*58e6ee5fSAndroid Build Coastguard Worker 		start_trace();
203*58e6ee5fSAndroid Build Coastguard Worker 		break;
204*58e6ee5fSAndroid Build Coastguard Worker 	case STACK_STOP:
205*58e6ee5fSAndroid Build Coastguard Worker 		stop_trace();
206*58e6ee5fSAndroid Build Coastguard Worker 		break;
207*58e6ee5fSAndroid Build Coastguard Worker 	case STACK_RESET:
208*58e6ee5fSAndroid Build Coastguard Worker 		reset_trace();
209*58e6ee5fSAndroid Build Coastguard Worker 		break;
210*58e6ee5fSAndroid Build Coastguard Worker 	default:
211*58e6ee5fSAndroid Build Coastguard Worker 		read_trace();
212*58e6ee5fSAndroid Build Coastguard Worker 		break;
213*58e6ee5fSAndroid Build Coastguard Worker 	}
214*58e6ee5fSAndroid Build Coastguard Worker 
215*58e6ee5fSAndroid Build Coastguard Worker 	return;
216*58e6ee5fSAndroid Build Coastguard Worker }
217