1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (C) 2014 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
4 *
5 */
6 #include <sys/types.h>
7 #include <sys/stat.h>
8 #include <stdlib.h>
9 #include <stdio.h>
10 #include <getopt.h>
11 #include <unistd.h>
12 #include <fcntl.h>
13 #include <ctype.h>
14
15 #include "tracefs.h"
16 #include "trace-local.h"
17
18 #ifndef BUFSIZ
19 #define BUFSIZ 1024
20 #endif
21
is_top_instance(struct buffer_instance * instance)22 static inline int is_top_instance(struct buffer_instance *instance)
23 {
24 return instance == &top_instance;
25 }
26
strstrip(char * str)27 char *strstrip(char *str)
28 {
29 char *s;
30
31 if (!str)
32 return NULL;
33
34 s = str + strlen(str) - 1;
35 while (s >= str && isspace(*s))
36 s--;
37 s++;
38 *s = '\0';
39
40 for (s = str; *s && isspace(*s); s++)
41 ;
42
43 return s;
44 }
45
46 /* FIXME: append_file() is duplicated and could be consolidated */
append_file(const char * dir,const char * name)47 char *append_file(const char *dir, const char *name)
48 {
49 char *file;
50 int ret;
51
52 ret = asprintf(&file, "%s/%s", dir, name);
53 if (ret < 0)
54 die("Failed to allocate %s/%s", dir, name);
55
56 return file;
57 }
58
get_fd_content(int fd,const char * file)59 static char *get_fd_content(int fd, const char *file)
60 {
61 size_t total = 0;
62 size_t alloc;
63 char *str = NULL;
64 int ret;
65
66 for (;;) {
67 alloc = ((total + BUFSIZ) / BUFSIZ) * BUFSIZ;
68 str = realloc(str, alloc + 1);
69 if (!str)
70 die("malloc");
71 ret = read(fd, str + total, alloc - total);
72 if (ret < 0)
73 die("reading %s\n", file);
74 total += ret;
75 if (!ret)
76 break;
77 }
78 str[total] = 0;
79
80 return str;
81 }
82
get_file_content(const char * file)83 char *get_file_content(const char *file)
84 {
85 char *str;
86 int fd;
87
88 fd = open(file, O_RDONLY);
89 if (fd < 0)
90 return NULL;
91
92 str = get_fd_content(fd, file);
93 close(fd);
94
95 return str;
96 }
97
report_file(struct buffer_instance * instance,char * name,char * def_value,char * description)98 static void report_file(struct buffer_instance *instance,
99 char *name, char *def_value, char *description)
100 {
101 char *str;
102 char *cont;
103
104 if (!tracefs_file_exists(instance->tracefs, name))
105 return;
106 str = tracefs_instance_file_read(instance->tracefs, name, NULL);
107 if (!str)
108 return;
109 cont = strstrip(str);
110 if (cont[0] && strcmp(cont, def_value) != 0)
111 printf("\n%s%s\n", description, cont);
112
113 free(str);
114 }
115
report_instance(const char * name,void * data)116 static int report_instance(const char *name, void *data)
117 {
118 bool *first = (bool *)data;
119
120 if (*first) {
121 *first = false;
122 printf("\nInstances:\n");
123 }
124 printf(" %s\n", name);
125 return 0;
126 }
127
report_instances(void)128 static void report_instances(void)
129 {
130 bool first = true;
131
132 tracefs_instances_walk(report_instance, &first);
133 }
134
trace_event_iter_alloc(const char * path)135 struct event_iter *trace_event_iter_alloc(const char *path)
136 {
137 struct event_iter *iter;
138
139 iter = malloc(sizeof(*iter));
140 if (!iter)
141 die("Failed to allocate event_iter for path %s", path);
142 memset(iter, 0, sizeof(*iter));
143
144 iter->system_dir = opendir(path);
145 if (!iter->system_dir)
146 die("opendir");
147
148 return iter;
149 }
150
151 enum event_iter_type
trace_event_iter_next(struct event_iter * iter,const char * path,const char * system)152 trace_event_iter_next(struct event_iter *iter, const char *path, const char *system)
153 {
154 struct dirent *dent;
155
156 if (system && !iter->event_dir) {
157 char *event;
158 struct stat st;
159
160 event = append_file(path, system);
161
162 stat(event, &st);
163 if (!S_ISDIR(st.st_mode)) {
164 free(event);
165 goto do_system;
166 }
167
168 iter->event_dir = opendir(event);
169 if (!iter->event_dir)
170 die("opendir %s", event);
171 free(event);
172 }
173
174 if (iter->event_dir) {
175 while ((dent = readdir(iter->event_dir))) {
176 const char *name = dent->d_name;
177
178 if (strcmp(name, ".") == 0 ||
179 strcmp(name, "..") == 0)
180 continue;
181
182 iter->event_dent = dent;
183 return EVENT_ITER_EVENT;
184 }
185 closedir(iter->event_dir);
186 iter->event_dir = NULL;
187 }
188
189 do_system:
190 while ((dent = readdir(iter->system_dir))) {
191 const char *name = dent->d_name;
192
193 if (strcmp(name, ".") == 0 ||
194 strcmp(name, "..") == 0)
195 continue;
196
197 iter->system_dent = dent;
198
199 return EVENT_ITER_SYSTEM;
200 }
201
202 return EVENT_ITER_NONE;
203 }
204
trace_event_iter_free(struct event_iter * iter)205 void trace_event_iter_free(struct event_iter *iter)
206 {
207 if (!iter)
208 return;
209
210 if (iter->event_dir)
211 closedir(iter->event_dir);
212
213 closedir(iter->system_dir);
214 free(iter);
215 }
216
reset_event_iter(struct event_iter * iter)217 static void reset_event_iter(struct event_iter *iter)
218 {
219 if (iter->event_dir) {
220 closedir(iter->event_dir);
221 iter->event_dir = NULL;
222 }
223
224 rewinddir(iter->system_dir);
225 }
226
process_individual_events(const char * path,struct event_iter * iter)227 static int process_individual_events(const char *path, struct event_iter *iter)
228 {
229 struct stat st;
230 const char *system = iter->system_dent->d_name;
231 char *file;
232 char *enable = NULL;
233 char *str;
234 int ret = 0;
235
236 file = append_file(path, system);
237
238 stat(file, &st);
239 if (!S_ISDIR(st.st_mode))
240 goto out;
241
242 enable = append_file(file, "enable");
243 str = get_file_content(enable);
244 if (!str)
245 goto out;
246
247 if (*str != '1' && *str != '0')
248 ret = 1;
249 free(str);
250
251 out:
252 free(enable);
253 free(file);
254
255 return ret;
256 }
257
258 static void
process_event_enable(char * path,const char * system,const char * name,enum event_process * processed)259 process_event_enable(char *path, const char *system, const char *name,
260 enum event_process *processed)
261 {
262 struct stat st;
263 char *enable = NULL;
264 char *file;
265 char *str;
266
267 if (system)
268 path = append_file(path, system);
269
270 file = append_file(path, name);
271
272 if (system)
273 free(path);
274
275 stat(file, &st);
276 if (!S_ISDIR(st.st_mode))
277 goto out;
278
279 enable = append_file(file, "enable");
280 str = get_file_content(enable);
281 if (!str)
282 goto out;
283
284 if (*str == '1') {
285 if (!system) {
286 if (!*processed)
287 printf(" Individual systems:\n");
288 printf( " %s\n", name);
289 *processed = PROCESSED_SYSTEM;
290 } else {
291 if (!*processed) {
292 printf(" Individual events:\n");
293 *processed = PROCESSED_SYSTEM;
294 }
295 if (*processed == PROCESSED_SYSTEM) {
296 printf(" %s\n", system);
297 *processed = PROCESSED_EVENT;
298 }
299 printf( " %s\n", name);
300 }
301 }
302 free(str);
303
304 out:
305 free(enable);
306 free(file);
307 }
308
report_events(struct buffer_instance * instance)309 static void report_events(struct buffer_instance *instance)
310 {
311 struct event_iter *iter;
312 char *str;
313 char *cont;
314 char *path;
315 char *system;
316 enum event_iter_type type;
317 enum event_process processed = PROCESSED_NONE;
318 enum event_process processed_part = PROCESSED_NONE;
319
320 str = tracefs_instance_file_read(instance->tracefs, "events/enable", NULL);
321 if (!str)
322 return;
323
324 cont = strstrip(str);
325
326 printf("\nEvents:\n");
327
328 switch(*cont) {
329 case '1':
330 printf(" All enabled\n");
331 free(str);
332 return;
333 case '0':
334 printf(" All disabled\n");
335 free(str);
336 return;
337 }
338
339 free(str);
340
341 path = tracefs_instance_get_file(instance->tracefs, "events");
342 if (!path)
343 die("malloc");
344
345 iter = trace_event_iter_alloc(path);
346
347 while (trace_event_iter_next(iter, path, NULL)) {
348 process_event_enable(path, NULL, iter->system_dent->d_name, &processed);
349 }
350
351 reset_event_iter(iter);
352
353 system = NULL;
354 while ((type = trace_event_iter_next(iter, path, system))) {
355
356 if (type == EVENT_ITER_SYSTEM) {
357
358 /* Only process systems that are not fully enabled */
359 if (!process_individual_events(path, iter))
360 continue;
361
362 system = iter->system_dent->d_name;
363 if (processed_part)
364 processed_part = PROCESSED_SYSTEM;
365 continue;
366 }
367
368 process_event_enable(path, iter->system_dent->d_name,
369 iter->event_dent->d_name, &processed_part);
370 }
371
372 trace_event_iter_free(iter);
373
374 if (!processed && !processed_part)
375 printf(" (none enabled)\n");
376
377 tracefs_put_tracing_file(path);
378 }
379
380 static void
process_event_filter(char * path,struct event_iter * iter,enum event_process * processed)381 process_event_filter(char *path, struct event_iter *iter, enum event_process *processed)
382 {
383 const char *system = iter->system_dent->d_name;
384 const char *event = iter->event_dent->d_name;
385 struct stat st;
386 char *filter = NULL;
387 char *file;
388 char *str;
389 char *cont;
390
391 path = append_file(path, system);
392 file = append_file(path, event);
393 free(path);
394
395 stat(file, &st);
396 if (!S_ISDIR(st.st_mode))
397 goto out;
398
399 filter = append_file(file, "filter");
400 str = get_file_content(filter);
401 if (!str)
402 goto out;
403
404 cont = strstrip(str);
405
406 if (strcmp(cont, "none") == 0) {
407 free(str);
408 goto out;
409 }
410
411 if (!*processed)
412 printf("\nFilters:\n");
413 printf( " %s:%s \"%s\"\n", system, event, cont);
414 *processed = PROCESSED_SYSTEM;
415 free(str);
416
417 out:
418 free(filter);
419 free(file);
420 }
421
report_event_filters(struct buffer_instance * instance)422 static void report_event_filters(struct buffer_instance *instance)
423 {
424 struct event_iter *iter;
425 char *path;
426 char *system;
427 enum event_iter_type type;
428 enum event_process processed = PROCESSED_NONE;
429
430 path = tracefs_instance_get_file(instance->tracefs, "events");
431 if (!path)
432 die("malloc");
433
434 iter = trace_event_iter_alloc(path);
435
436 processed = PROCESSED_NONE;
437 system = NULL;
438 while ((type = trace_event_iter_next(iter, path, system))) {
439
440 if (type == EVENT_ITER_SYSTEM) {
441 system = iter->system_dent->d_name;
442 continue;
443 }
444
445 process_event_filter(path, iter, &processed);
446 }
447
448 trace_event_iter_free(iter);
449
450 tracefs_put_tracing_file(path);
451 }
452
453 static void
process_event_trigger(char * path,struct event_iter * iter,enum event_process * processed)454 process_event_trigger(char *path, struct event_iter *iter, enum event_process *processed)
455 {
456 const char *system = iter->system_dent->d_name;
457 const char *event = iter->event_dent->d_name;
458 struct stat st;
459 char *trigger = NULL;
460 char *file;
461 char *str;
462 char *cont;
463
464 path = append_file(path, system);
465 file = append_file(path, event);
466 free(path);
467
468 stat(file, &st);
469 if (!S_ISDIR(st.st_mode))
470 goto out;
471
472 trigger = append_file(file, "trigger");
473 str = get_file_content(trigger);
474 if (!str)
475 goto out;
476
477 cont = strstrip(str);
478
479 if (cont[0] == '#') {
480 free(str);
481 goto out;
482 }
483
484 if (!*processed)
485 printf("\nTriggers:\n");
486 printf( " %s:%s \"%s\"\n", system, event, cont);
487 *processed = PROCESSED_SYSTEM;
488 free(str);
489
490 out:
491 free(trigger);
492 free(file);
493 }
494
report_event_triggers(struct buffer_instance * instance)495 static void report_event_triggers(struct buffer_instance *instance)
496 {
497 struct event_iter *iter;
498 char *path;
499 char *system;
500 enum event_iter_type type;
501 enum event_process processed = PROCESSED_NONE;
502
503 path = tracefs_instance_get_file(instance->tracefs, "events");
504 if (!path)
505 die("malloc");
506
507 iter = trace_event_iter_alloc(path);
508
509 processed = PROCESSED_NONE;
510 system = NULL;
511 while ((type = trace_event_iter_next(iter, path, system))) {
512
513 if (type == EVENT_ITER_SYSTEM) {
514 system = iter->system_dent->d_name;
515 continue;
516 }
517
518 process_event_trigger(path, iter, &processed);
519 }
520
521 trace_event_iter_free(iter);
522
523 tracefs_put_tracing_file(path);
524 }
525
526 enum func_states {
527 FUNC_STATE_START,
528 FUNC_STATE_SKIP,
529 FUNC_STATE_PRINT,
530 };
531
list_functions(const char * path,char * string)532 static void list_functions(const char *path, char *string)
533 {
534 enum func_states state;
535 struct stat st;
536 char *str;
537 int ret = 0;
538 int len;
539 int i;
540 int first = 0;
541
542 /* Ignore if it does not exist. */
543 ret = stat(path, &st);
544 if (ret < 0)
545 return;
546
547 str = get_file_content(path);
548 if (!str)
549 return;
550
551 len = strlen(str);
552
553 state = FUNC_STATE_START;
554
555 /* Skip all lines that start with '#' */
556 for (i = 0; i < len; i++) {
557
558 if (state == FUNC_STATE_PRINT)
559 putchar(str[i]);
560
561 if (str[i] == '\n') {
562 state = FUNC_STATE_START;
563 continue;
564 }
565
566 if (state == FUNC_STATE_SKIP)
567 continue;
568
569 if (state == FUNC_STATE_START && str[i] == '#') {
570 state = FUNC_STATE_SKIP;
571 continue;
572 }
573
574 if (!first) {
575 printf("\n%s:\n", string);
576 first = 1;
577 }
578
579 if (state != FUNC_STATE_PRINT) {
580 state = FUNC_STATE_PRINT;
581 printf(" ");
582 putchar(str[i]);
583 }
584 }
585 free(str);
586 }
587
report_graph_funcs(struct buffer_instance * instance)588 static void report_graph_funcs(struct buffer_instance *instance)
589 {
590 char *path;
591
592 path = tracefs_instance_get_file(instance->tracefs, "set_graph_function");
593 if (!path)
594 die("malloc");
595
596 list_functions(path, "Function Graph Filter");
597
598 tracefs_put_tracing_file(path);
599
600 path = tracefs_instance_get_file(instance->tracefs, "set_graph_notrace");
601 if (!path)
602 die("malloc");
603
604 list_functions(path, "Function Graph No Trace");
605
606 tracefs_put_tracing_file(path);
607 }
608
report_ftrace_filters(struct buffer_instance * instance)609 static void report_ftrace_filters(struct buffer_instance *instance)
610 {
611 char *path;
612
613 path = tracefs_instance_get_file(instance->tracefs, "set_ftrace_filter");
614 if (!path)
615 die("malloc");
616
617 list_functions(path, "Function Filter");
618
619 tracefs_put_tracing_file(path);
620
621 path = tracefs_instance_get_file(instance->tracefs, "set_ftrace_notrace");
622 if (!path)
623 die("malloc");
624
625 list_functions(path, "Function No Trace");
626
627 tracefs_put_tracing_file(path);
628 }
629
report_buffers(struct buffer_instance * instance)630 static void report_buffers(struct buffer_instance *instance)
631 {
632 #define FILE_SIZE 100
633 char *str;
634 char *cont;
635 char file[FILE_SIZE];
636 int pagesize;
637 int bufsize;
638 int cpu;
639
640 str = tracefs_instance_file_read(instance->tracefs, "buffer_size_kb", NULL);
641 if (!str)
642 return;
643
644 cont = strstrip(str);
645
646 /* If it's not expanded yet, just skip */
647 if (strstr(cont, "expanded") != NULL)
648 goto out;
649
650 if (strcmp(cont, "X") != 0) {
651 printf("\nBuffer size in kilobytes (per cpu):\n");
652 printf(" %s\n", str);
653 goto total;
654 }
655
656 /* Read the sizes of each CPU buffer */
657 for (cpu = 0; ; cpu++) {
658
659 snprintf(file, FILE_SIZE, "per_cpu/cpu%d/buffer_size_kb", cpu);
660 str = tracefs_instance_file_read(instance->tracefs, file, NULL);
661 if (!str)
662 break;
663
664 cont = strstrip(str);
665 if (!cpu)
666 putchar('\n');
667
668 printf("CPU %d buffer size (kb): %s\n", cpu, cont);
669 free(str);
670 }
671
672 total:
673 free(str);
674
675 str = tracefs_instance_file_read(instance->tracefs, "buffer_total_size_kb", NULL);
676 if (!str)
677 return;
678
679 cont = strstrip(str);
680 printf("\nBuffer total size in kilobytes:\n");
681 printf(" %s\n", str);
682
683 pagesize = getpagesize();
684 bufsize = tracefs_instance_get_subbuf_size(instance->tracefs);
685 if (bufsize > 0 && bufsize * 1024 != pagesize)
686 printf("\nSub-buffer size in kilobytes:\n %d\n", bufsize);
687
688 out:
689 free(str);
690 }
691
report_clock(struct buffer_instance * instance)692 static void report_clock(struct buffer_instance *instance)
693 {
694 struct tracefs_instance *tracefs = instance ? instance->tracefs : NULL;
695 char *clock;
696
697 clock = tracefs_get_clock(tracefs);
698
699 /* Default clock is "local", only show others */
700 if (clock && strcmp(clock, "local") != 0)
701 printf("\nClock: %s\n", clock);
702
703 free(clock);
704 }
705
report_cpumask(struct buffer_instance * instance)706 static void report_cpumask(struct buffer_instance *instance)
707 {
708 char *str;
709 char *cont;
710 int cpus;
711 int n;
712 int i;
713
714 str = tracefs_instance_file_read(instance->tracefs, "tracing_cpumask", NULL);
715 if (!str)
716 return;
717
718 cont = strstrip(str);
719
720 /* check to make sure all CPUs on this machine are set */
721 cpus = tracecmd_count_cpus();
722
723 for (i = strlen(cont) - 1; i >= 0 && cpus > 0; i--) {
724 if (cont[i] == ',')
725 continue;
726
727 if (cont[i] == 'f') {
728 cpus -= 4;
729 continue;
730 }
731
732 if (cpus >= 4)
733 break;
734
735 if (cont[i] >= '0' && cont[i] <= '9')
736 n = cont[i] - '0';
737 else
738 n = 10 + (cont[i] - 'a');
739
740 while (cpus > 0) {
741 if (!(n & 1))
742 break;
743 n >>= 1;
744 cpus--;
745 }
746 break;
747 }
748
749 /* If cpus is greater than zero, one isn't set */
750 if (cpus > 0)
751 printf("\nCPU mask: %s\n", cont);
752
753 free(str);
754 }
755
report_probes(struct buffer_instance * instance,const char * file,const char * string)756 static void report_probes(struct buffer_instance *instance,
757 const char *file, const char *string)
758 {
759 char *str;
760 char *cont;
761 int newline;
762 int i;
763
764 str = tracefs_instance_file_read(instance->tracefs, file, NULL);
765 if (!str)
766 return;
767
768 cont = strstrip(str);
769 if (strlen(cont) == 0)
770 goto out;
771
772 printf("\n%s:\n", string);
773
774 newline = 1;
775 for (i = 0; cont[i]; i++) {
776 if (newline)
777 printf(" ");
778 putchar(cont[i]);
779 if (cont[i] == '\n')
780 newline = 1;
781 else
782 newline = 0;
783 }
784 putchar('\n');
785 out:
786 free(str);
787 }
788
report_kprobes(struct buffer_instance * instance)789 static void report_kprobes(struct buffer_instance *instance)
790 {
791 report_probes(instance, "kprobe_events", "Kprobe events");
792 }
793
report_uprobes(struct buffer_instance * instance)794 static void report_uprobes(struct buffer_instance *instance)
795 {
796 report_probes(instance, "uprobe_events", "Uprobe events");
797 }
798
report_synthetic(struct buffer_instance * instance)799 static void report_synthetic(struct buffer_instance *instance)
800 {
801 report_probes(instance, "synthetic_events", "Synthetic events");
802 }
803
report_traceon(struct buffer_instance * instance)804 static void report_traceon(struct buffer_instance *instance)
805 {
806 char *str;
807 char *cont;
808
809 str = tracefs_instance_file_read(instance->tracefs, "tracing_on", NULL);
810 if (!str)
811 return;
812
813 cont = strstrip(str);
814
815 /* double newline as this is the last thing printed */
816 if (strcmp(cont, "0") == 0)
817 printf("\nTracing is disabled\n\n");
818 else
819 printf("\nTracing is enabled\n\n");
820
821 free(str);
822 }
823
stat_instance(struct buffer_instance * instance,bool opt)824 static void stat_instance(struct buffer_instance *instance, bool opt)
825 {
826 if (instance != &top_instance) {
827 if (instance != first_instance)
828 printf("---------------\n");
829 printf("Instance: %s\n",
830 tracefs_instance_get_name(instance->tracefs));
831 }
832
833 report_file(instance, "current_tracer", "nop", "Tracer: ");
834 report_events(instance);
835 report_event_filters(instance);
836 report_event_triggers(instance);
837 report_ftrace_filters(instance);
838 report_graph_funcs(instance);
839 report_buffers(instance);
840 report_clock(instance);
841 report_cpumask(instance);
842 report_file(instance, "tracing_max_latency", "0", "Max Latency: ");
843 report_kprobes(instance);
844 report_uprobes(instance);
845 report_synthetic(instance);
846 report_file(instance, "set_event_pid", "", "Filtered event PIDs:\n");
847 report_file(instance, "set_event_notrace_pid", "", "Filtered notrace event PIDs:\n");
848 report_file(instance, "set_ftrace_pid", "no pid",
849 "Filtered function tracer PIDs:\n");
850 report_file(instance, "set_ftrace_notrace_pid", "no pid",
851 "Filtered function tracer notrace PIDs:\n");
852 if (opt) {
853 printf("\nOptions:\n");
854 show_options(" ", instance);
855 }
856 report_traceon(instance);
857 report_file(instance, "error_log", "", "Error log:\n");
858 if (instance == &top_instance)
859 report_instances();
860 }
861
trace_stat(int argc,char ** argv)862 void trace_stat (int argc, char **argv)
863 {
864 struct buffer_instance *instance = &top_instance;
865 bool opt = false;
866 int topt = 0;
867 int status;
868 int c;
869
870 init_top_instance();
871
872 for (;;) {
873 c = getopt(argc-1, argv+1, "htoB:");
874 if (c == -1)
875 break;
876 switch (c) {
877 case 'h':
878 usage(argv);
879 break;
880 case 'B':
881 instance = allocate_instance(optarg);
882 if (!instance)
883 die("Failed to create instance");
884 add_instance(instance, tracecmd_count_cpus());
885 /* top instance requires direct access */
886 if (!topt && is_top_instance(first_instance))
887 first_instance = instance;
888 break;
889 case 't':
890 /* Force to use top instance */
891 topt = 1;
892 instance = &top_instance;
893 break;
894 case 'o':
895 opt = 1;
896 break;
897 default:
898 usage(argv);
899 }
900 }
901
902 update_first_instance(instance, topt);
903
904 for_all_instances(instance) {
905 stat_instance(instance, opt);
906 }
907
908 if (tracecmd_stack_tracer_status(&status) >= 0) {
909 if (status > 0)
910 printf("Stack tracing is enabled\n\n");
911 } else {
912 printf("Error reading stack tracer status\n\n");
913 }
914
915 exit(0);
916 }
917