blob: 78adff189bbafcde68bc9aa19f320dbe6072f32d [file] [log] [blame]
Steven Rostedt520509432009-08-17 16:18:05 +02001/*
2 * Copyright (C) 2008,2009, 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 <dirent.h>
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26#include <stdarg.h>
27#include <sys/types.h>
28#include <sys/stat.h>
29#include <sys/wait.h>
30#include <pthread.h>
31#include <fcntl.h>
32#include <unistd.h>
33#include <ctype.h>
34#include <errno.h>
35
36#include "trace-event.h"
37
38
39#define VERSION "0.5"
40
41#define _STR(x) #x
42#define STR(x) _STR(x)
43#define MAX_PATH 256
44
45#define TRACE_CTRL "tracing_on"
46#define TRACE "trace"
47#define AVAILABLE "available_tracers"
48#define CURRENT "current_tracer"
49#define ITER_CTRL "trace_options"
50#define MAX_LATENCY "tracing_max_latency"
51
52unsigned int page_size;
53
54static const char *output_file = "trace.info";
55static int output_fd;
56
57struct event_list {
58 struct event_list *next;
59 const char *event;
60};
61
62struct events {
63 struct events *sibling;
64 struct events *children;
65 struct events *next;
66 char *name;
67};
68
69
70
71static void die(const char *fmt, ...)
72{
73 va_list ap;
74 int ret = errno;
75
76 if (errno)
77 perror("trace-cmd");
78 else
79 ret = -1;
80
81 va_start(ap, fmt);
82 fprintf(stderr, " ");
83 vfprintf(stderr, fmt, ap);
84 va_end(ap);
85
86 fprintf(stderr, "\n");
87 exit(ret);
88}
89
90void *malloc_or_die(unsigned int size)
91{
92 void *data;
93
94 data = malloc(size);
95 if (!data)
96 die("malloc");
97 return data;
98}
99
100static const char *find_debugfs(void)
101{
102 static char debugfs[MAX_PATH+1];
103 static int debugfs_found;
104 char type[100];
105 FILE *fp;
106
107 if (debugfs_found)
108 return debugfs;
109
110 if ((fp = fopen("/proc/mounts","r")) == NULL)
111 die("Can't open /proc/mounts for read");
112
113 while (fscanf(fp, "%*s %"
114 STR(MAX_PATH)
115 "s %99s %*s %*d %*d\n",
116 debugfs, type) == 2) {
117 if (strcmp(type, "debugfs") == 0)
118 break;
119 }
120 fclose(fp);
121
122 if (strcmp(type, "debugfs") != 0)
123 die("debugfs not mounted, please mount");
124
125 debugfs_found = 1;
126
127 return debugfs;
128}
129
130/*
131 * Finds the path to the debugfs/tracing
132 * Allocates the string and stores it.
133 */
134static const char *find_tracing_dir(void)
135{
136 static char *tracing;
137 static int tracing_found;
138 const char *debugfs;
139
140 if (tracing_found)
141 return tracing;
142
143 debugfs = find_debugfs();
144
145 tracing = malloc_or_die(strlen(debugfs) + 9);
146
147 sprintf(tracing, "%s/tracing", debugfs);
148
149 tracing_found = 1;
150 return tracing;
151}
152
153static char *get_tracing_file(const char *name)
154{
155 const char *tracing;
156 char *file;
157
158 tracing = find_tracing_dir();
159 if (!tracing)
160 return NULL;
161
162 file = malloc_or_die(strlen(tracing) + strlen(name) + 2);
163
164 sprintf(file, "%s/%s", tracing, name);
165 return file;
166}
167
168static void put_tracing_file(char *file)
169{
170 free(file);
171}
172
173static ssize_t write_or_die(const void *buf, size_t len)
174{
175 int ret;
176
177 ret = write(output_fd, buf, len);
178 if (ret < 0)
179 die("writing to '%s'", output_file);
180
181 return ret;
182}
183
184int bigendian(void)
185{
186 unsigned char str[] = { 0x1, 0x2, 0x3, 0x4, 0x0, 0x0, 0x0, 0x0};
187 unsigned int *ptr;
188
189 ptr = (unsigned int *)str;
190 return *ptr == 0x01020304;
191}
192
193static unsigned long long copy_file_fd(int fd)
194{
195 unsigned long long size = 0;
196 char buf[BUFSIZ];
197 int r;
198
199 do {
200 r = read(fd, buf, BUFSIZ);
201 if (r > 0) {
202 size += r;
203 write_or_die(buf, r);
204 }
205 } while (r > 0);
206
207 return size;
208}
209
210static unsigned long long copy_file(const char *file)
211{
212 unsigned long long size = 0;
213 int fd;
214
215 fd = open(file, O_RDONLY);
216 if (fd < 0)
217 die("Can't read '%s'", file);
218 size = copy_file_fd(fd);
219 close(fd);
220
221 return size;
222}
223
224static unsigned long get_size_fd(int fd)
225{
226 unsigned long long size = 0;
227 char buf[BUFSIZ];
228 int r;
229
230 do {
231 r = read(fd, buf, BUFSIZ);
232 if (r > 0)
233 size += r;
234 } while (r > 0);
235
236 lseek(fd, 0, SEEK_SET);
237
238 return size;
239}
240
241static unsigned long get_size(const char *file)
242{
243 unsigned long long size = 0;
244 int fd;
245
246 fd = open(file, O_RDONLY);
247 if (fd < 0)
248 die("Can't read '%s'", file);
249 size = get_size_fd(fd);
250 close(fd);
251
252 return size;
253}
254
255static void read_header_files(void)
256{
257 unsigned long long size, check_size;
258 char *path;
259 int fd;
260
261 path = get_tracing_file("events/header_page");
262 fd = open(path, O_RDONLY);
263 if (fd < 0)
264 die("can't read '%s'", path);
265
266 /* unfortunately, you can not stat debugfs files for size */
267 size = get_size_fd(fd);
268
269 write_or_die("header_page", 12);
270 write_or_die(&size, 8);
271 check_size = copy_file_fd(fd);
272 if (size != check_size)
273 die("wrong size for '%s' size=%lld read=%lld",
274 path, size, check_size);
275 put_tracing_file(path);
276
277 path = get_tracing_file("events/header_event");
278 fd = open(path, O_RDONLY);
279 if (fd < 0)
280 die("can't read '%s'", path);
281
282 size = get_size_fd(fd);
283
284 write_or_die("header_event", 13);
285 write_or_die(&size, 8);
286 check_size = copy_file_fd(fd);
287 if (size != check_size)
288 die("wrong size for '%s'", path);
289 put_tracing_file(path);
290}
291
292static void copy_event_system(const char *sys)
293{
294 unsigned long long size, check_size;
295 struct dirent *dent;
296 struct stat st;
297 char *format;
298 DIR *dir;
299 int count = 0;
300 int ret;
301
302 dir = opendir(sys);
303 if (!dir)
304 die("can't read directory '%s'", sys);
305
306 while ((dent = readdir(dir))) {
307 if (strcmp(dent->d_name, ".") == 0 ||
308 strcmp(dent->d_name, "..") == 0)
309 continue;
310 format = malloc_or_die(strlen(sys) + strlen(dent->d_name) + 10);
311 sprintf(format, "%s/%s/format", sys, dent->d_name);
312 ret = stat(format, &st);
313 free(format);
314 if (ret < 0)
315 continue;
316 count++;
317 }
318
319 write_or_die(&count, 4);
320
321 rewinddir(dir);
322 while ((dent = readdir(dir))) {
323 if (strcmp(dent->d_name, ".") == 0 ||
324 strcmp(dent->d_name, "..") == 0)
325 continue;
326 format = malloc_or_die(strlen(sys) + strlen(dent->d_name) + 10);
327 sprintf(format, "%s/%s/format", sys, dent->d_name);
328 ret = stat(format, &st);
329
330 if (ret >= 0) {
331 /* unfortunately, you can not stat debugfs files for size */
332 size = get_size(format);
333 write_or_die(&size, 8);
334 check_size = copy_file(format);
335 if (size != check_size)
336 die("error in size of file '%s'", format);
337 }
338
339 free(format);
340 }
341}
342
343static void read_ftrace_files(void)
344{
345 char *path;
346
347 path = get_tracing_file("events/ftrace");
348
349 copy_event_system(path);
350
351 put_tracing_file(path);
352}
353
354static void read_event_files(void)
355{
356 struct dirent *dent;
357 struct stat st;
358 char *path;
359 char *sys;
360 DIR *dir;
361 int count = 0;
362 int ret;
363
364 path = get_tracing_file("events");
365
366 dir = opendir(path);
367 if (!dir)
368 die("can't read directory '%s'", path);
369
370 while ((dent = readdir(dir))) {
371 if (strcmp(dent->d_name, ".") == 0 ||
372 strcmp(dent->d_name, "..") == 0 ||
373 strcmp(dent->d_name, "ftrace") == 0)
374 continue;
375 sys = malloc_or_die(strlen(path) + strlen(dent->d_name) + 2);
376 sprintf(sys, "%s/%s", path, dent->d_name);
377 ret = stat(sys, &st);
378 free(sys);
379 if (ret < 0)
380 continue;
381 if (S_ISDIR(st.st_mode))
382 count++;
383 }
384
385 write_or_die(&count, 4);
386
387 rewinddir(dir);
388 while ((dent = readdir(dir))) {
389 if (strcmp(dent->d_name, ".") == 0 ||
390 strcmp(dent->d_name, "..") == 0 ||
391 strcmp(dent->d_name, "ftrace") == 0)
392 continue;
393 sys = malloc_or_die(strlen(path) + strlen(dent->d_name) + 2);
394 sprintf(sys, "%s/%s", path, dent->d_name);
395 ret = stat(sys, &st);
396 if (ret >= 0) {
397 if (S_ISDIR(st.st_mode)) {
398 write_or_die(dent->d_name, strlen(dent->d_name) + 1);
399 copy_event_system(sys);
400 }
401 }
402 free(sys);
403 }
404
405 put_tracing_file(path);
406}
407
408static void read_proc_kallsyms(void)
409{
410 unsigned int size, check_size;
411 const char *path = "/proc/kallsyms";
412 struct stat st;
413 int ret;
414
415 ret = stat(path, &st);
416 if (ret < 0) {
417 /* not found */
418 size = 0;
419 write_or_die(&size, 4);
420 return;
421 }
422 size = get_size(path);
423 write_or_die(&size, 4);
424 check_size = copy_file(path);
425 if (size != check_size)
426 die("error in size of file '%s'", path);
427
428}
429
430static void read_ftrace_printk(void)
431{
432 unsigned int size, check_size;
433 const char *path;
434 struct stat st;
435 int ret;
436
437 path = get_tracing_file("printk_formats");
438 ret = stat(path, &st);
439 if (ret < 0) {
440 /* not found */
441 size = 0;
442 write_or_die(&size, 4);
443 return;
444 }
445 size = get_size(path);
446 write_or_die(&size, 4);
447 check_size = copy_file(path);
448 if (size != check_size)
449 die("error in size of file '%s'", path);
450
451}
452
453void read_tracing_data(void)
454{
455 char buf[BUFSIZ];
456
457 output_fd = open(output_file, O_WRONLY | O_CREAT | O_TRUNC | O_LARGEFILE, 0644);
458 if (output_fd < 0)
459 die("creating file '%s'", output_file);
460
461 buf[0] = 23;
462 buf[1] = 8;
463 buf[2] = 68;
464 memcpy(buf + 3, "tracing", 7);
465
466 write_or_die(buf, 10);
467
468 write_or_die(VERSION, strlen(VERSION) + 1);
469
470 /* save endian */
471 if (bigendian())
472 buf[0] = 1;
473 else
474 buf[0] = 0;
475
476 write_or_die(buf, 1);
477
478 /* save size of long */
479 buf[0] = sizeof(long);
480 write_or_die(buf, 1);
481
482 /* save page_size */
483 page_size = getpagesize();
484 write_or_die(&page_size, 4);
485
486 read_header_files();
487 read_ftrace_files();
488 read_event_files();
489 read_proc_kallsyms();
490 read_ftrace_printk();
491}