1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <[email protected]>
4 *
5 */
6
7 #include <stdlib.h>
8 #include <sys/stat.h>
9
10 #include "tracefs.h"
11 #include "trace-local.h"
12
13
dump_file_content(const char * path)14 static void dump_file_content(const char *path)
15 {
16 char buf[BUFSIZ];
17 ssize_t n;
18 FILE *fp;
19
20 fp = fopen(path, "r");
21 if (!fp)
22 die("reading %s", path);
23
24 do {
25 n = fread(buf, 1, BUFSIZ, fp);
26 if (n > 0)
27 fwrite(buf, 1, n, stdout);
28 } while (n > 0);
29 fclose(fp);
30 }
31
32
33
show_instance_file(struct buffer_instance * instance,const char * name)34 void show_instance_file(struct buffer_instance *instance, const char *name)
35 {
36 char *path;
37
38 path = tracefs_instance_get_file(instance->tracefs, name);
39 dump_file_content(path);
40 tracefs_put_tracing_file(path);
41 }
42
43 enum {
44 SHOW_EVENT_FORMAT = 1 << 0,
45 SHOW_EVENT_FILTER = 1 << 1,
46 SHOW_EVENT_TRIGGER = 1 << 2,
47 SHOW_EVENT_FULL = 1 << 3,
48 };
49
50
show_file(const char * name)51 void show_file(const char *name)
52 {
53 char *path;
54
55 path = tracefs_get_tracing_file(name);
56 dump_file_content(path);
57 tracefs_put_tracing_file(path);
58 }
59
60 typedef int (*process_file_func)(char *buf, int len, int flags);
61
process_file_re(process_file_func func,const char * name,const char * re,int flags)62 static void process_file_re(process_file_func func,
63 const char *name, const char *re, int flags)
64 {
65 regex_t reg;
66 char *path;
67 char *buf = NULL;
68 char *str;
69 FILE *fp;
70 ssize_t n;
71 size_t l = strlen(re);
72
73 /* Just in case :-p */
74 if (!re || l == 0) {
75 show_file(name);
76 return;
77 }
78
79 /* Handle the newline at end of names for the user */
80 str = malloc(l + 3);
81 if (!str)
82 die("Failed to allocate reg ex %s", re);
83 strcpy(str, re);
84 if (re[l-1] == '$')
85 strcpy(&str[l-1], "\n*$");
86
87 if (regcomp(®, str, REG_ICASE|REG_NOSUB))
88 die("invalid function regex '%s'", re);
89
90 free(str);
91
92 path = tracefs_get_tracing_file(name);
93 fp = fopen(path, "r");
94 if (!fp)
95 die("reading %s", path);
96 tracefs_put_tracing_file(path);
97
98 do {
99 n = getline(&buf, &l, fp);
100 if (n > 0 && regexec(®, buf, 0, NULL, 0) == 0)
101 func(buf, n, flags);
102 } while (n > 0);
103 free(buf);
104 fclose(fp);
105
106 regfree(®);
107 }
108
show_event(process_file_func func,const char * system,const char * event,int flags)109 static void show_event(process_file_func func, const char *system,
110 const char *event, int flags)
111 {
112 char *buf;
113 int ret;
114
115 ret = asprintf(&buf, "%s:%s", system, event);
116 if (ret < 0)
117 die("Can not allocate event");
118 func(buf, strlen(buf), flags);
119 free(buf);
120 }
121
show_system(process_file_func func,const char * system,int flags)122 static void show_system(process_file_func func, const char *system, int flags)
123 {
124 char **events;
125 int e;
126
127 events = tracefs_system_events(NULL, system);
128 if (!events) /* die? */
129 return;
130
131 for (e = 0; events[e]; e++)
132 show_event(func, system, events[e], flags);
133 }
134
show_event_systems(process_file_func func,char ** systems,int flags)135 static void show_event_systems(process_file_func func, char **systems, int flags)
136 {
137 int s;
138
139 for (s = 0; systems[s]; s++)
140 show_system(func, systems[s], flags);
141 }
142
match_system_events(process_file_func func,const char * system,regex_t * reg,int flags)143 static void match_system_events(process_file_func func, const char *system,
144 regex_t *reg, int flags)
145 {
146 char **events;
147 int e;
148
149 events = tracefs_system_events(NULL, system);
150 if (!events) /* die? */
151 return;
152 for (e = 0; events[e]; e++) {
153 if (regexec(reg, events[e], 0, NULL, 0) == 0)
154 show_event(func, system, events[e], flags);
155 }
156 tracefs_list_free(events);
157 }
158
process_events(process_file_func func,const char * re,int flags)159 static void process_events(process_file_func func, const char *re, int flags)
160 {
161 const char *ftrace = "ftrace";
162 regex_t system_reg;
163 regex_t event_reg;
164 char *str;
165 size_t l = strlen(re);
166 bool just_systems = true;
167 char **systems;
168 char *system;
169 char *event;
170 int s;
171
172 systems = tracefs_event_systems(NULL);
173 if (!systems)
174 return process_file_re(func, "available_events", re, flags);
175
176 if (!re || l == 0) {
177 show_event_systems(func, systems, flags);
178 return;
179 }
180
181 str = strdup(re);
182 if (!str)
183 die("Can not allocate momory for regex");
184
185 system = strtok(str, ":");
186 event = strtok(NULL, "");
187
188 if (regcomp(&system_reg, system, REG_ICASE|REG_NOSUB))
189 die("invalid regex '%s'", system);
190
191 if (event) {
192 if (regcomp(&event_reg, event, REG_ICASE|REG_NOSUB))
193 die("invalid regex '%s'", event);
194 } else {
195 /*
196 * If the regex ends with ":", then event would be null,
197 * but we do not want to match events.
198 */
199 if (re[l-1] != ':')
200 just_systems = false;
201 }
202 free(str);
203
204 /*
205 * See if this matches the special ftrace system, as ftrace is not included
206 * in the systems list, but can get events from tracefs_system_events().
207 */
208 if (regexec(&system_reg, ftrace, 0, NULL, 0) == 0) {
209 if (!event)
210 show_system(func, ftrace, flags);
211 else
212 match_system_events(func, ftrace, &event_reg, flags);
213 } else if (!just_systems) {
214 match_system_events(func, ftrace, &system_reg, flags);
215 }
216
217 for (s = 0; systems[s]; s++) {
218
219 if (regexec(&system_reg, systems[s], 0, NULL, 0) == 0) {
220 if (!event) {
221 show_system(func, systems[s], flags);
222 continue;
223 }
224 match_system_events(func, systems[s], &event_reg, flags);
225 continue;
226 }
227 if (just_systems)
228 continue;
229
230 match_system_events(func, systems[s], &system_reg, flags);
231 }
232 tracefs_list_free(systems);
233
234 regfree(&system_reg);
235 if (event)
236 regfree(&event_reg);
237 }
238
show_file_write(char * buf,int len,int flags)239 static int show_file_write(char *buf, int len, int flags)
240 {
241 return fwrite(buf, 1, len, stdout);
242 }
243
show_file_re(const char * name,const char * re)244 static void show_file_re(const char *name, const char *re)
245 {
246 process_file_re(show_file_write, name, re, 0);
247 }
248
get_event_file(const char * type,char * buf,int len)249 static char *get_event_file(const char *type, char *buf, int len)
250 {
251 char *system;
252 char *event;
253 char *path;
254 char *file;
255 int ret;
256
257 if (buf[len-1] == '\n')
258 buf[len-1] = '\0';
259
260 system = strtok(buf, ":");
261 if (!system)
262 die("no system found in %s", buf);
263
264 event = strtok(NULL, ":");
265 if (!event)
266 die("no event found in %s\n", buf);
267
268 path = tracefs_get_tracing_file("events");
269 ret = asprintf(&file, "%s/%s/%s/%s", path, system, event, type);
270 if (ret < 0)
271 die("Failed to allocate event file %s %s", system, event);
272
273 tracefs_put_tracing_file(path);
274
275 return file;
276 }
277
event_filter_write(char * buf,int len,int flags)278 static int event_filter_write(char *buf, int len, int flags)
279 {
280 char *file;
281
282 if (buf[len-1] == '\n')
283 buf[len-1] = '\0';
284
285 printf("%s\n", buf);
286
287 file = get_event_file("filter", buf, len);
288 dump_file_content(file);
289 free(file);
290 printf("\n");
291
292 return 0;
293 }
294
event_trigger_write(char * buf,int len,int flags)295 static int event_trigger_write(char *buf, int len, int flags)
296 {
297 char *file;
298
299 if (buf[len-1] == '\n')
300 buf[len-1] = '\0';
301
302 printf("%s\n", buf);
303
304 file = get_event_file("trigger", buf, len);
305 dump_file_content(file);
306 free(file);
307 printf("\n");
308
309 return 0;
310 }
311
event_format_write(char * fbuf,int len,int flags)312 static int event_format_write(char *fbuf, int len, int flags)
313 {
314 char *file = get_event_file("format", fbuf, len);
315 char *buf = NULL;
316 size_t l;
317 FILE *fp;
318 bool full;
319 int n;
320
321 full = flags & SHOW_EVENT_FULL;
322
323 /* The get_event_file() crops system in fbuf */
324 printf("system: %s\n", fbuf);
325
326 /* Don't print the print fmt, it's ugly */
327
328 fp = fopen(file, "r");
329 if (!fp)
330 die("reading %s", file);
331
332 do {
333 n = getline(&buf, &l, fp);
334 if (n > 0) {
335 if (!full && strncmp(buf, "print fmt", 9) == 0)
336 break;
337 fwrite(buf, 1, n, stdout);
338 }
339 } while (n > 0);
340 fclose(fp);
341 free(buf);
342 free(file);
343
344 return 0;
345 }
346
event_name(char * buf,int len,int flags)347 static int event_name(char *buf, int len, int flags)
348 {
349 printf("%s\n", buf);
350
351 return 0;
352 }
353
show_event_filter_re(const char * re)354 static void show_event_filter_re(const char *re)
355 {
356 process_events(event_filter_write, re, 0);
357 }
358
359
show_event_trigger_re(const char * re)360 static void show_event_trigger_re(const char *re)
361 {
362 process_events(event_trigger_write, re, 0);
363 }
364
365
show_event_format_re(const char * re,int flags)366 static void show_event_format_re(const char *re, int flags)
367 {
368 process_events(event_format_write, re, flags);
369 }
370
show_event_names_re(const char * re)371 static void show_event_names_re(const char *re)
372 {
373 process_events(event_name, re, 0);
374 }
375
show_events(const char * eventre,int flags)376 static void show_events(const char *eventre, int flags)
377 {
378 if (flags && !eventre)
379 die("When specifying event files, an event must be named");
380
381 if (eventre) {
382 if (flags & SHOW_EVENT_FORMAT)
383 show_event_format_re(eventre, flags);
384
385 else if (flags & SHOW_EVENT_FILTER)
386 show_event_filter_re(eventre);
387
388 else if (flags & SHOW_EVENT_TRIGGER)
389 show_event_trigger_re(eventre);
390 else
391 show_event_names_re(eventre);
392 } else
393 show_file("available_events");
394 }
395
396
show_tracers(void)397 static void show_tracers(void)
398 {
399 show_file("available_tracers");
400 }
401
show_options(const char * prefix,struct buffer_instance * buffer)402 void show_options(const char *prefix, struct buffer_instance *buffer)
403 {
404 struct tracefs_instance *instance = buffer ? buffer->tracefs : NULL;
405 struct dirent *dent;
406 struct stat st;
407 char *path;
408 DIR *dir;
409
410 if (!prefix)
411 prefix = "";
412
413 path = tracefs_instance_get_file(instance, "options");
414 if (!path)
415 goto show_file;
416 if (stat(path, &st) < 0)
417 goto show_file;
418
419 if ((st.st_mode & S_IFMT) != S_IFDIR)
420 goto show_file;
421
422 dir = opendir(path);
423 if (!dir)
424 die("Can not read instance directory");
425
426 while ((dent = readdir(dir))) {
427 const char *name = dent->d_name;
428 long long val;
429 char *file;
430 int ret;
431
432 if (strcmp(name, ".") == 0 ||
433 strcmp(name, "..") == 0)
434 continue;
435
436 ret = asprintf(&file, "options/%s", name);
437 if (ret < 0)
438 die("Failed to allocate file name");
439 ret = tracefs_instance_file_read_number(instance, file, &val);
440 if (!ret) {
441 if (val)
442 printf("%s%s\n", prefix, name);
443 else
444 printf("%sno%s\n", prefix, name);
445 }
446 free(file);
447 }
448 closedir(dir);
449 tracefs_put_tracing_file(path);
450 return;
451
452 show_file:
453 tracefs_put_tracing_file(path);
454 show_file("trace_options");
455 }
456
show_clocks(void)457 static void show_clocks(void)
458 {
459 char *clocks;
460 int size;
461
462 clocks = tracefs_instance_file_read(NULL, "trace_clock", &size);
463 if (!clocks)
464 die("getting clocks");
465 if (clocks[size - 1] == '\n')
466 clocks[size - 1] = 0;
467
468 if (trace_tsc2nsec_is_supported())
469 printf("%s %s\n", clocks, TSCNSEC_CLOCK);
470 else
471 printf("%s\n", clocks);
472
473 free(clocks);
474 }
475
476
show_functions(const char * funcre)477 static void show_functions(const char *funcre)
478 {
479 if (funcre)
480 show_file_re("available_filter_functions", funcre);
481 else
482 show_file("available_filter_functions");
483 }
484
485
show_buffers(void)486 static void show_buffers(void)
487 {
488 struct dirent *dent;
489 DIR *dir;
490 char *path;
491 int printed = 0;
492
493 path = tracefs_get_tracing_file("instances");
494 dir = opendir(path);
495 tracefs_put_tracing_file(path);
496 if (!dir)
497 die("Can not read instance directory");
498
499 while ((dent = readdir(dir))) {
500 const char *name = dent->d_name;
501
502 if (strcmp(name, ".") == 0 ||
503 strcmp(name, "..") == 0)
504 continue;
505
506 printf("%s\n", name);
507 printed = 1;
508 }
509 closedir(dir);
510
511 if (!printed)
512 printf("No buffer instances defined\n");
513 }
514
515
show_systems(void)516 static void show_systems(void)
517 {
518 struct dirent *dent;
519 char *path;
520 DIR *dir;
521
522 path = tracefs_get_tracing_file("events");
523 dir = opendir(path);
524
525 if (!dir)
526 die("Can not read events directory");
527
528 while ((dent = readdir(dir))) {
529 const char *name = dent->d_name;
530 struct stat st;
531 char *spath;
532 int ret;
533
534 if (strcmp(name, ".") == 0 ||
535 strcmp(name, "..") == 0)
536 continue;
537
538 if (asprintf(&spath, "%s/%s", path, name) < 0)
539 continue;
540 ret = stat(spath, &st);
541 if (!ret && S_ISDIR(st.st_mode))
542 printf("%s\n", name);
543
544 free(spath);
545 }
546
547 printf("\n");
548 closedir(dir);
549 tracefs_put_tracing_file(path);
550 }
551
show_plugin_options(void)552 static void show_plugin_options(void)
553 {
554 struct tep_handle *pevent;
555 struct tep_plugin_list *list;
556 struct trace_seq s;
557
558 tracecmd_ftrace_load_options();
559
560 pevent = tep_alloc();
561 if (!pevent)
562 die("Can not allocate pevent\n");
563
564 trace_seq_init(&s);
565
566 list = trace_load_plugins(pevent, 0);
567 tep_plugin_print_options(&s);
568 trace_seq_do_printf(&s);
569 tep_unload_plugins(list, pevent);
570 tep_free(pevent);
571 }
572
573
trace_option(int argc,char ** argv)574 void trace_option(int argc, char **argv)
575 {
576 show_plugin_options();
577 }
578
579
show_plugins(void)580 static void show_plugins(void)
581 {
582 struct tep_handle *pevent;
583 struct tep_plugin_list *list;
584 struct trace_seq s;
585
586 pevent = tep_alloc();
587 if (!pevent)
588 die("Can not allocate pevent\n");
589
590 trace_seq_init(&s);
591
592 list = trace_load_plugins(pevent, 0);
593 tep_print_plugins(&s, " ", "\n", list);
594
595 trace_seq_do_printf(&s);
596 tep_unload_plugins(list, pevent);
597 tep_free(pevent);
598 }
599
show_compression(void)600 static void show_compression(void)
601 {
602 char **versions, **names;
603 int c, i;
604
605 c = tracecmd_compress_protos_get(&names, &versions);
606 if (c <= 0) {
607 printf("No compression algorithms are supported\n");
608 return;
609 }
610 printf("Supported compression algorithms:\n");
611 for (i = 0; i < c; i++)
612 printf("\t%s, %s\n", names[i], versions[i]);
613
614 free(names);
615 free(versions);
616 }
617
trace_list(int argc,char ** argv)618 void trace_list(int argc, char **argv)
619 {
620 int events = 0;
621 int tracer = 0;
622 int options = 0;
623 int funcs = 0;
624 int buffers = 0;
625 int clocks = 0;
626 int plug = 0;
627 int plug_op = 0;
628 int flags = 0;
629 int systems = 0;
630 int show_all = 1;
631 int compression = 0;
632 int i;
633 const char *arg;
634 const char *funcre = NULL;
635 const char *eventre = NULL;
636
637 for (i = 2; i < argc; i++) {
638 arg = NULL;
639 if (argv[i][0] == '-') {
640 if (i < argc - 1) {
641 if (argv[i+1][0] != '-')
642 arg = argv[i+1];
643 }
644 switch (argv[i][1]) {
645 case 'h':
646 usage(argv);
647 break;
648 case 'e':
649 events = 1;
650 eventre = arg;
651 show_all = 0;
652 break;
653 case 'B':
654 buffers = 1;
655 show_all = 0;
656 break;
657 case 'C':
658 clocks = 1;
659 show_all = 0;
660 break;
661 case 'F':
662 flags |= SHOW_EVENT_FORMAT;
663 break;
664 case 'R':
665 flags |= SHOW_EVENT_TRIGGER;
666 break;
667 case 'l':
668 flags |= SHOW_EVENT_FILTER;
669 break;
670 case 'p':
671 case 't':
672 tracer = 1;
673 show_all = 0;
674 break;
675 case 'P':
676 plug = 1;
677 show_all = 0;
678 break;
679 case 'O':
680 plug_op = 1;
681 show_all = 0;
682 break;
683 case 'o':
684 options = 1;
685 show_all = 0;
686 break;
687 case 'f':
688 funcs = 1;
689 funcre = arg;
690 show_all = 0;
691 break;
692 case 's':
693 systems = 1;
694 show_all = 0;
695 break;
696 case 'c':
697 compression = 1;
698 show_all = 0;
699 break;
700 case '-':
701 if (strcmp(argv[i], "--debug") == 0) {
702 tracecmd_set_debug(true);
703 break;
704 }
705 if (strcmp(argv[i], "--full") == 0) {
706 flags |= SHOW_EVENT_FULL;
707 break;
708 }
709 fprintf(stderr, "list: invalid option -- '%s'\n",
710 argv[i]);
711 default:
712 fprintf(stderr, "list: invalid option -- '%c'\n",
713 argv[i][1]);
714 usage(argv);
715 }
716 }
717 }
718
719 if (events)
720 show_events(eventre, flags);
721
722 if (tracer)
723 show_tracers();
724
725 if (options)
726 show_options(NULL, NULL);
727
728 if (plug)
729 show_plugins();
730
731 if (plug_op)
732 show_plugin_options();
733
734 if (funcs)
735 show_functions(funcre);
736
737 if (buffers)
738 show_buffers();
739
740 if (clocks)
741 show_clocks();
742 if (systems)
743 show_systems();
744 if (compression)
745 show_compression();
746 if (show_all) {
747 printf("event systems:\n");
748 show_systems();
749 printf("events:\n");
750 show_events(NULL, 0);
751 printf("\ntracers:\n");
752 show_tracers();
753 printf("\noptions:\n");
754 show_options(NULL, NULL);
755 show_compression();
756 }
757
758 return;
759
760 }
761