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