xref: /aosp_15_r20/external/trace-cmd/tracecmd/trace-stat.c (revision 58e6ee5f017f6a8912852c892d18457e4bafb554)
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