aboutsummaryrefslogtreecommitdiffstats
path: root/trace-stack.c
diff options
context:
space:
mode:
Diffstat (limited to 'trace-stack.c')
-rw-r--r--trace-stack.c224
1 files changed, 224 insertions, 0 deletions
diff --git a/trace-stack.c b/trace-stack.c
new file mode 100644
index 0000000..3d9f392
--- /dev/null
+++ b/trace-stack.c
@@ -0,0 +1,224 @@
1/*
2 * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
3 *
4 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License (not later!)
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20 */
21#define _GNU_SOURCE
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <getopt.h>
26#include <sys/types.h>
27#include <sys/stat.h>
28#include <sys/wait.h>
29#include <fcntl.h>
30#include <unistd.h>
31#include <errno.h>
32
33#include "trace-local.h"
34
35#define PROC_FILE "/proc/sys/kernel/stack_tracer_enabled"
36
37enum stack_type {
38 STACK_START,
39 STACK_STOP,
40 STACK_RESET,
41 STACK_REPORT
42};
43
44static void test_available(void)
45{
46 struct stat buf;
47 int fd;
48
49 fd = stat(PROC_FILE, &buf);
50 if (fd < 0)
51 die("stack tracer not configured on running kernel");
52}
53
54static char read_proc(void)
55{
56 char buf[1];
57 int fd;
58 int n;
59
60 fd = open(PROC_FILE, O_RDONLY);
61 if (fd < 0)
62 die("reading %s", PROC_FILE);
63 n = read(fd, buf, 1);
64 close(fd);
65 if (n != 1)
66 die("error reading %s", PROC_FILE);
67
68 return buf[0];
69}
70
71static void start_stop_trace(char val)
72{
73 char buf[1];
74 int fd;
75 int n;
76
77 buf[0] = read_proc();
78 if (buf[0] == val)
79 return;
80
81 fd = open(PROC_FILE, O_WRONLY);
82 if (fd < 0)
83 die("writing %s", PROC_FILE);
84 buf[0] = val;
85 n = write(fd, buf, 1);
86 if (n < 0)
87 die("writing into %s", PROC_FILE);
88 close(fd);
89}
90
91static void start_trace(void)
92{
93 start_stop_trace('1');
94}
95
96static void stop_trace(void)
97{
98 start_stop_trace('0');
99}
100
101static void reset_trace(void)
102{
103 char *path;
104 char buf[1];
105 int fd;
106 int n;
107
108 path = tracecmd_get_tracing_file("stack_max_size");
109 fd = open(path, O_WRONLY);
110 if (fd < 0)
111 die("writing %s", path);
112
113 buf[0] = '0';
114 n = write(fd, buf, 1);
115 if (n < 0)
116 die("writing into %s", path);
117 tracecmd_put_tracing_file(path);
118 close(fd);
119}
120
121static void read_trace(void)
122{
123 FILE *fp;
124 char *path;
125 char *buf = NULL;
126 size_t n;
127 int r;
128
129 if (read_proc() == '1')
130 printf("(stack tracer running)\n");
131 else
132 printf("(stack tracer not running)\n");
133
134 path = tracecmd_get_tracing_file("stack_trace");
135 fp = fopen(path, "r");
136 if (!fp)
137 die("reading to '%s'", path);
138 tracecmd_put_tracing_file(path);
139
140 while ((r = getline(&buf, &n, fp)) >= 0) {
141 /*
142 * Skip any line that starts with a '#'.
143 * Those talk about how to enable stack tracing
144 * within the debugfs system. We don't care about that.
145 */
146 if (buf[0] != '#')
147 printf("%s", buf);
148
149 free(buf);
150 buf = NULL;
151 }
152
153 fclose(fp);
154}
155
156void trace_stack (int argc, char **argv)
157{
158 enum stack_type trace_type = STACK_REPORT;
159 int c;
160
161 if (argc < 2)
162 usage(argv);
163
164 if (strcmp(argv[1], "stack") != 0)
165 usage(argv);
166
167 for (;;) {
168 int option_index = 0;
169 static struct option long_options[] = {
170 {"start", no_argument, NULL, 0},
171 {"stop", no_argument, NULL, 0},
172 {"reset", no_argument, NULL, 0},
173 {"help", no_argument, NULL, '?'},
174 {NULL, 0, NULL, 0}
175 };
176
177 c = getopt_long (argc-1, argv+1, "+h?",
178 long_options, &option_index);
179 if (c == -1)
180 break;
181
182 switch (c) {
183 case 'h':
184 usage(argv);
185 break;
186 case 0:
187 switch(option_index) {
188 case 0:
189 trace_type = STACK_START;
190 break;
191 case 1:
192 trace_type = STACK_STOP;
193 break;
194 case 2:
195 trace_type = STACK_RESET;
196 break;
197 default:
198 usage(argv);
199 }
200 break;
201 default:
202 usage(argv);
203 }
204 }
205
206 test_available();
207
208 switch (trace_type) {
209 case STACK_START:
210 start_trace();
211 break;
212 case STACK_STOP:
213 stop_trace();
214 break;
215 case STACK_RESET:
216 reset_trace();
217 break;
218 default:
219 read_trace();
220 break;
221 }
222
223 return;
224}