xref: /aosp_15_r20/external/trace-cmd/tracecmd/trace-list.c (revision 58e6ee5f017f6a8912852c892d18457e4bafb554)
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(&reg, 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(&reg, buf, 0, NULL, 0) == 0)
101 			func(buf, n, flags);
102 	} while (n > 0);
103 	free(buf);
104 	fclose(fp);
105 
106 	regfree(&reg);
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