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