1 // SPDX-License-Identifier: LGPL-2.1
2 /*
3 * Copyright (C) 2008, 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
4 *
5 * Updates:
6 * Copyright (C) 2019, VMware, Tzvetomir Stoyanov <tz.stoyanov@gmail.com>
7 *
8 */
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <dirent.h>
12 #include <unistd.h>
13 #include <errno.h>
14 #include <sys/stat.h>
15 #include <fcntl.h>
16 #include <limits.h>
17
18 #include <kbuffer.h>
19
20 #include "tracefs.h"
21 #include "tracefs-local.h"
22
23 static struct follow_event *root_followers;
24 static int nr_root_followers;
25
26 static struct follow_event *root_missed_followers;
27 static int nr_root_missed_followers;
28
29 struct cpu_iterate {
30 struct tracefs_cpu *tcpu;
31 struct tep_record record;
32 struct tep_event *event;
33 struct kbuffer *kbuf;
34 void *page;
35 int psize;
36 int cpu;
37 };
38
read_kbuf_record(struct cpu_iterate * cpu)39 static int read_kbuf_record(struct cpu_iterate *cpu)
40 {
41 unsigned long long ts;
42 void *ptr;
43
44 if (!cpu || !cpu->kbuf)
45 return -1;
46 ptr = kbuffer_read_event(cpu->kbuf, &ts);
47 if (!ptr)
48 return -1;
49
50 memset(&cpu->record, 0, sizeof(cpu->record));
51 cpu->record.ts = ts;
52 cpu->record.size = kbuffer_event_size(cpu->kbuf);
53 cpu->record.record_size = kbuffer_curr_size(cpu->kbuf);
54 cpu->record.missed_events = kbuffer_missed_events(cpu->kbuf);
55 cpu->record.cpu = cpu->cpu;
56 cpu->record.data = ptr;
57 cpu->record.ref_count = 1;
58
59 kbuffer_next_event(cpu->kbuf, NULL);
60
61 return 0;
62 }
63
read_next_page(struct tep_handle * tep,struct cpu_iterate * cpu)64 int read_next_page(struct tep_handle *tep, struct cpu_iterate *cpu)
65 {
66 enum kbuffer_long_size long_size;
67 enum kbuffer_endian endian;
68 int r;
69
70 if (!cpu->tcpu)
71 return -1;
72
73 r = tracefs_cpu_buffered_read(cpu->tcpu, cpu->page, true);
74 /*
75 * tracefs_cpu_buffered_read() only reads in full subbuffer size,
76 * but this wants partial buffers as well. If the function returns
77 * empty (-1 for EAGAIN), try tracefs_cpu_read() next, as that can
78 * read partially filled buffers too, but isn't as efficient.
79 */
80 if (r <= 0)
81 r = tracefs_cpu_read(cpu->tcpu, cpu->page, true);
82 if (r <= 0)
83 return -1;
84
85 if (!cpu->kbuf) {
86 if (tep_is_file_bigendian(tep))
87 endian = KBUFFER_ENDIAN_BIG;
88 else
89 endian = KBUFFER_ENDIAN_LITTLE;
90
91 if (tep_get_header_page_size(tep) == 8)
92 long_size = KBUFFER_LSIZE_8;
93 else
94 long_size = KBUFFER_LSIZE_4;
95
96 cpu->kbuf = kbuffer_alloc(long_size, endian);
97 if (!cpu->kbuf)
98 return -1;
99 }
100
101 kbuffer_load_subbuffer(cpu->kbuf, cpu->page);
102 if (kbuffer_subbuffer_size(cpu->kbuf) > r) {
103 tracefs_warning("%s: page_size > %d", __func__, r);
104 return -1;
105 }
106
107 return 0;
108 }
109
read_next_record(struct tep_handle * tep,struct cpu_iterate * cpu)110 int read_next_record(struct tep_handle *tep, struct cpu_iterate *cpu)
111 {
112 int id;
113
114 do {
115 while (!read_kbuf_record(cpu)) {
116 id = tep_data_type(tep, &(cpu->record));
117 cpu->event = tep_find_event(tep, id);
118 if (cpu->event)
119 return 0;
120 }
121 } while (!read_next_page(tep, cpu));
122
123 return -1;
124 }
125
126 /**
127 * tracefs_follow_missed_events - Add callback for missed events for iterators
128 * @instance: The instance to follow
129 * @callback: The function to call when missed events is detected
130 * @callback_data: The data to pass to @callback
131 *
132 * This attaches a callback to an @instance or the root instance if @instance
133 * is NULL, where if tracefs_iterate_raw_events() is called, that if missed
134 * events are detected, it will call @callback, with the following parameters:
135 * @event: The event pointer of the record with the missing events
136 * @record; The event instance of @event.
137 * @cpu: The cpu that the event happened on.
138 * @callback_data: The same as @callback_data passed to the function.
139 *
140 * If the count of missing events is available, @record->missed_events
141 * will have a positive number holding the number of missed events since
142 * the last event on the same CPU, or just -1 if that number is unknown
143 * but missed events did happen.
144 *
145 * Returns 0 on success and -1 on error.
146 */
tracefs_follow_missed_events(struct tracefs_instance * instance,int (* callback)(struct tep_event *,struct tep_record *,int,void *),void * callback_data)147 int tracefs_follow_missed_events(struct tracefs_instance *instance,
148 int (*callback)(struct tep_event *,
149 struct tep_record *,
150 int, void *),
151 void *callback_data)
152 {
153 struct follow_event **followers;
154 struct follow_event *follower;
155 struct follow_event follow;
156 int *nr_followers;
157
158 follow.event = NULL;
159 follow.callback = callback;
160 follow.callback_data = callback_data;
161
162 if (instance) {
163 followers = &instance->missed_followers;
164 nr_followers = &instance->nr_missed_followers;
165 } else {
166 followers = &root_missed_followers;
167 nr_followers = &nr_root_missed_followers;
168 }
169 follower = realloc(*followers, sizeof(*follower) *
170 ((*nr_followers) + 1));
171 if (!follower)
172 return -1;
173
174 *followers = follower;
175 follower[(*nr_followers)++] = follow;
176
177 return 0;
178 }
179
call_missed_events(struct tracefs_instance * instance,struct tep_event * event,struct tep_record * record,int cpu)180 static int call_missed_events(struct tracefs_instance *instance,
181 struct tep_event *event, struct tep_record *record, int cpu)
182 {
183 struct follow_event *followers;
184 int nr_followers;
185 int ret = 0;
186 int i;
187
188 if (instance) {
189 followers = instance->missed_followers;
190 nr_followers = instance->nr_missed_followers;
191 } else {
192 followers = root_missed_followers;
193 nr_followers = nr_root_missed_followers;
194 }
195
196 if (!followers)
197 return 0;
198
199 for (i = 0; i < nr_followers; i++) {
200 ret |= followers[i].callback(event, record,
201 cpu, followers[i].callback_data);
202 }
203
204 return ret;
205 }
206
call_followers(struct tracefs_instance * instance,struct tep_event * event,struct tep_record * record,int cpu)207 static int call_followers(struct tracefs_instance *instance,
208 struct tep_event *event, struct tep_record *record, int cpu)
209 {
210 struct follow_event *followers;
211 int nr_followers;
212 int ret = 0;
213 int i;
214
215 if (record->missed_events)
216 ret = call_missed_events(instance, event, record, cpu);
217 if (ret)
218 return ret;
219
220 if (instance) {
221 followers = instance->followers;
222 nr_followers = instance->nr_followers;
223 } else {
224 followers = root_followers;
225 nr_followers = nr_root_followers;
226 }
227
228 if (!followers)
229 return 0;
230
231 for (i = 0; i < nr_followers; i++) {
232 if (followers[i].event == event)
233 ret |= followers[i].callback(event, record,
234 cpu, followers[i].callback_data);
235 }
236
237 return ret;
238 }
239
read_cpu_pages(struct tep_handle * tep,struct tracefs_instance * instance,struct cpu_iterate * cpus,int count,int (* callback)(struct tep_event *,struct tep_record *,int,void *),void * callback_context,bool * keep_going)240 static int read_cpu_pages(struct tep_handle *tep, struct tracefs_instance *instance,
241 struct cpu_iterate *cpus, int count,
242 int (*callback)(struct tep_event *,
243 struct tep_record *,
244 int, void *),
245 void *callback_context,
246 bool *keep_going)
247 {
248 bool has_data = false;
249 int ret;
250 int i, j;
251
252 for (i = 0; i < count; i++) {
253 ret = read_next_record(tep, cpus + i);
254 if (!ret)
255 has_data = true;
256 }
257
258 while (has_data && *(volatile bool *)keep_going) {
259 j = count;
260 for (i = 0; i < count; i++) {
261 if (!cpus[i].event)
262 continue;
263 if (j == count || cpus[j].record.ts > cpus[i].record.ts)
264 j = i;
265 }
266 if (j < count) {
267 if (call_followers(instance, cpus[j].event, &cpus[j].record, cpus[j].cpu))
268 break;
269 if (callback &&
270 callback(cpus[j].event, &cpus[j].record, cpus[j].cpu, callback_context))
271 break;
272 cpus[j].event = NULL;
273 read_next_record(tep, cpus + j);
274 } else {
275 has_data = false;
276 }
277 }
278
279 return 0;
280 }
281
open_cpu_files(struct tracefs_instance * instance,cpu_set_t * cpus,int cpu_size,struct cpu_iterate ** all_cpus,int * count)282 static int open_cpu_files(struct tracefs_instance *instance, cpu_set_t *cpus,
283 int cpu_size, struct cpu_iterate **all_cpus, int *count)
284 {
285 struct tracefs_cpu *tcpu;
286 struct cpu_iterate *tmp;
287 int nr_cpus;
288 int cpu;
289 int i = 0;
290
291 *all_cpus = NULL;
292
293 nr_cpus = sysconf(_SC_NPROCESSORS_CONF);
294 for (cpu = 0; cpu < nr_cpus; cpu++) {
295 if (cpus && !CPU_ISSET_S(cpu, cpu_size, cpus))
296 continue;
297 tcpu = tracefs_cpu_open(instance, cpu, true);
298 tmp = realloc(*all_cpus, (i + 1) * sizeof(*tmp));
299 if (!tmp) {
300 i--;
301 goto error;
302 }
303
304 *all_cpus = tmp;
305
306 memset(tmp + i, 0, sizeof(*tmp));
307
308 if (!tcpu)
309 goto error;
310
311 tmp[i].tcpu = tcpu;
312 tmp[i].cpu = cpu;
313 tmp[i].psize = tracefs_cpu_read_size(tcpu);
314 tmp[i].page = malloc(tmp[i].psize);
315
316 if (!tmp[i++].page)
317 goto error;
318 }
319 *count = i;
320 return 0;
321 error:
322 tmp = *all_cpus;
323 for (; i >= 0; i--) {
324 tracefs_cpu_close(tmp[i].tcpu);
325 free(tmp[i].page);
326 }
327 free(tmp);
328 *all_cpus = NULL;
329 return -1;
330 }
331
332 /**
333 * tracefs_follow_event - Add callback for specific events for iterators
334 * @tep: a handle to the trace event parser context
335 * @instance: The instance to follow
336 * @system: The system of the event to track
337 * @event_name: The name of the event to track
338 * @callback: The function to call when the event is hit in an iterator
339 * @callback_data: The data to pass to @callback
340 *
341 * This attaches a callback to an @instance or the root instance if @instance
342 * is NULL, where if tracefs_iterate_raw_events() is called, that if the specified
343 * event is hit, it will call @callback, with the following parameters:
344 * @event: The event pointer that was found by @system and @event_name.
345 * @record; The event instance of @event.
346 * @cpu: The cpu that the event happened on.
347 * @callback_data: The same as @callback_data passed to the function.
348 *
349 * Returns 0 on success and -1 on error.
350 */
tracefs_follow_event(struct tep_handle * tep,struct tracefs_instance * instance,const char * system,const char * event_name,int (* callback)(struct tep_event *,struct tep_record *,int,void *),void * callback_data)351 int tracefs_follow_event(struct tep_handle *tep, struct tracefs_instance *instance,
352 const char *system, const char *event_name,
353 int (*callback)(struct tep_event *,
354 struct tep_record *,
355 int, void *),
356 void *callback_data)
357 {
358 struct follow_event **followers;
359 struct follow_event *follower;
360 struct follow_event follow;
361 int *nr_followers;
362
363 if (!tep) {
364 errno = EINVAL;
365 return -1;
366 }
367
368 follow.event = tep_find_event_by_name(tep, system, event_name);
369 if (!follow.event) {
370 errno = ENOENT;
371 return -1;
372 }
373
374 follow.callback = callback;
375 follow.callback_data = callback_data;
376
377 if (instance) {
378 followers = &instance->followers;
379 nr_followers = &instance->nr_followers;
380 } else {
381 followers = &root_followers;
382 nr_followers = &nr_root_followers;
383 }
384 follower = realloc(*followers, sizeof(*follower) *
385 ((*nr_followers) + 1));
386 if (!follower)
387 return -1;
388
389 *followers = follower;
390 follower[(*nr_followers)++] = follow;
391
392 return 0;
393 }
394
395 static bool top_iterate_keep_going;
396
397 /*
398 * tracefs_iterate_raw_events - Iterate through events in trace_pipe_raw,
399 * per CPU trace buffers
400 * @tep: a handle to the trace event parser context
401 * @instance: ftrace instance, can be NULL for the top instance
402 * @cpus: Iterate only through the buffers of CPUs, set in the mask.
403 * If NULL, iterate through all CPUs.
404 * @cpu_size: size of @cpus set
405 * @callback: A user function, called for each record from the file
406 * @callback_context: A custom context, passed to the user callback function
407 *
408 * If the @callback returns non-zero, the iteration stops - in that case all
409 * records from the current page will be lost from future reads
410 * The events are iterated in sorted order, oldest first.
411 *
412 * Returns -1 in case of an error, or 0 otherwise
413 */
tracefs_iterate_raw_events(struct tep_handle * tep,struct tracefs_instance * instance,cpu_set_t * cpus,int cpu_size,int (* callback)(struct tep_event *,struct tep_record *,int,void *),void * callback_context)414 int tracefs_iterate_raw_events(struct tep_handle *tep,
415 struct tracefs_instance *instance,
416 cpu_set_t *cpus, int cpu_size,
417 int (*callback)(struct tep_event *,
418 struct tep_record *,
419 int, void *),
420 void *callback_context)
421 {
422 bool *keep_going = instance ? &instance->iterate_keep_going :
423 &top_iterate_keep_going;
424 struct follow_event *followers;
425 struct cpu_iterate *all_cpus;
426 int count = 0;
427 int ret;
428 int i;
429
430 (*(volatile bool *)keep_going) = true;
431
432 if (!tep)
433 return -1;
434
435 if (instance)
436 followers = instance->followers;
437 else
438 followers = root_followers;
439 if (!callback && !followers)
440 return -1;
441
442 ret = open_cpu_files(instance, cpus, cpu_size, &all_cpus, &count);
443 if (ret < 0)
444 goto out;
445 ret = read_cpu_pages(tep, instance, all_cpus, count,
446 callback, callback_context,
447 keep_going);
448
449 out:
450 if (all_cpus) {
451 for (i = 0; i < count; i++) {
452 kbuffer_free(all_cpus[i].kbuf);
453 tracefs_cpu_close(all_cpus[i].tcpu);
454 free(all_cpus[i].page);
455 }
456 free(all_cpus);
457 }
458
459 return ret;
460 }
461
462 /**
463 * tracefs_iterate_stop - stop the iteration over the raw events.
464 * @instance: ftrace instance, can be NULL for top tracing instance.
465 */
tracefs_iterate_stop(struct tracefs_instance * instance)466 void tracefs_iterate_stop(struct tracefs_instance *instance)
467 {
468 if (instance)
469 instance->iterate_keep_going = false;
470 else
471 top_iterate_keep_going = false;
472 }
473
add_list_string(char *** list,const char * name)474 static int add_list_string(char ***list, const char *name)
475 {
476 char **tmp;
477
478 tmp = tracefs_list_add(*list, name);
479 if (!tmp) {
480 tracefs_list_free(*list);
481 *list = NULL;
482 return -1;
483 }
484
485 *list = tmp;
486 return 0;
487 }
488
trace_append_file(const char * dir,const char * name)489 __hidden char *trace_append_file(const char *dir, const char *name)
490 {
491 char *file;
492 int ret;
493
494 ret = asprintf(&file, "%s/%s", dir, name);
495
496 return ret < 0 ? NULL : file;
497 }
498
event_file(char ** path,const char * system,const char * event,const char * file)499 static int event_file(char **path, const char *system,
500 const char *event, const char *file)
501 {
502 if (!system || !event || !file)
503 return -1;
504
505 return asprintf(path, "events/%s/%s/%s",
506 system, event, file);
507 }
508
509 /**
510 * tracefs_event_get_file - return a file in an event directory
511 * @instance: The instance the event is in (NULL for top level)
512 * @system: The system name that the event file is in
513 * @event: The event name of the event
514 * @file: The name of the file in the event directory.
515 *
516 * Returns a path to a file in the event director.
517 * or NULL on error. The path returned must be freed with
518 * tracefs_put_tracing_file().
519 */
tracefs_event_get_file(struct tracefs_instance * instance,const char * system,const char * event,const char * file)520 char *tracefs_event_get_file(struct tracefs_instance *instance,
521 const char *system, const char *event,
522 const char *file)
523 {
524 char *instance_path;
525 char *path;
526 int ret;
527
528 ret = event_file(&path, system, event, file);
529 if (ret < 0)
530 return NULL;
531
532 instance_path = tracefs_instance_get_file(instance, path);
533 free(path);
534
535 return instance_path;
536 }
537
538 /**
539 * tracefs_event_file_read - read the content from an event file
540 * @instance: The instance the event is in (NULL for top level)
541 * @system: The system name that the event file is in
542 * @event: The event name of the event
543 * @file: The name of the file in the event directory.
544 * @psize: the size of the content read.
545 *
546 * Reads the content of the event file that is passed via the
547 * arguments and returns the content.
548 *
549 * Return a string containing the content of the file or NULL
550 * on error. The string returned must be freed with free().
551 */
tracefs_event_file_read(struct tracefs_instance * instance,const char * system,const char * event,const char * file,int * psize)552 char *tracefs_event_file_read(struct tracefs_instance *instance,
553 const char *system, const char *event,
554 const char *file, int *psize)
555 {
556 char *content;
557 char *path;
558 int ret;
559
560 ret = event_file(&path, system, event, file);
561 if (ret < 0)
562 return NULL;
563
564 content = tracefs_instance_file_read(instance, path, psize);
565 free(path);
566 return content;
567 }
568
569 /**
570 * tracefs_event_file_write - write to an event file
571 * @instance: The instance the event is in (NULL for top level)
572 * @system: The system name that the event file is in
573 * @event: The event name of the event
574 * @file: The name of the file in the event directory.
575 * @str: The string to write into the file
576 *
577 * Writes the content of @str to a file in the instance directory.
578 * The content of the file will be overwritten by @str.
579 *
580 * Return 0 on success, and -1 on error.
581 */
tracefs_event_file_write(struct tracefs_instance * instance,const char * system,const char * event,const char * file,const char * str)582 int tracefs_event_file_write(struct tracefs_instance *instance,
583 const char *system, const char *event,
584 const char *file, const char *str)
585 {
586 char *path;
587 int ret;
588
589 ret = event_file(&path, system, event, file);
590 if (ret < 0)
591 return -1;
592
593 ret = tracefs_instance_file_write(instance, path, str);
594 free(path);
595 return ret;
596 }
597
598 /**
599 * tracefs_event_file_append - write to an event file
600 * @instance: The instance the event is in (NULL for top level)
601 * @system: The system name that the event file is in
602 * @event: The event name of the event
603 * @file: The name of the file in the event directory.
604 * @str: The string to write into the file
605 *
606 * Writes the content of @str to a file in the instance directory.
607 * The content of @str will be appended to the content of the file.
608 * The current content should not be lost.
609 *
610 * Return 0 on success, and -1 on error.
611 */
tracefs_event_file_append(struct tracefs_instance * instance,const char * system,const char * event,const char * file,const char * str)612 int tracefs_event_file_append(struct tracefs_instance *instance,
613 const char *system, const char *event,
614 const char *file, const char *str)
615 {
616 char *path;
617 int ret;
618
619 ret = event_file(&path, system, event, file);
620 if (ret < 0)
621 return -1;
622
623 ret = tracefs_instance_file_append(instance, path, str);
624 free(path);
625 return ret;
626 }
627
628 /**
629 * tracefs_event_file_clear - clear an event file
630 * @instance: The instance the event is in (NULL for top level)
631 * @system: The system name that the event file is in
632 * @event: The event name of the event
633 * @file: The name of the file in the event directory.
634 *
635 * Clears the content of the event file. That is, it is opened
636 * with O_TRUNC and then closed.
637 *
638 * Return 0 on success, and -1 on error.
639 */
tracefs_event_file_clear(struct tracefs_instance * instance,const char * system,const char * event,const char * file)640 int tracefs_event_file_clear(struct tracefs_instance *instance,
641 const char *system, const char *event,
642 const char *file)
643 {
644 char *path;
645 int ret;
646
647 ret = event_file(&path, system, event, file);
648 if (ret < 0)
649 return -1;
650
651 ret = tracefs_instance_file_clear(instance, path);
652 free(path);
653 return ret;
654 }
655
656 /**
657 * tracefs_event_file_exits - test if a file exists
658 * @instance: The instance the event is in (NULL for top level)
659 * @system: The system name that the event file is in
660 * @event: The event name of the event
661 * @file: The name of the file in the event directory.
662 *
663 * Return true if the file exists, false if it odes not or
664 * an error occurred.
665 */
tracefs_event_file_exists(struct tracefs_instance * instance,const char * system,const char * event,const char * file)666 bool tracefs_event_file_exists(struct tracefs_instance *instance,
667 const char *system, const char *event,
668 const char *file)
669 {
670 char *path;
671 bool ret;
672
673 if (event_file(&path, system, event, file) < 0)
674 return false;
675
676 ret = tracefs_file_exists(instance, path);
677 free(path);
678 return ret;
679 }
680
681 /**
682 * tracefs_event_systems - return list of systems for tracing
683 * @tracing_dir: directory holding the "events" directory
684 * if NULL, top tracing directory is used
685 *
686 * Returns an allocated list of system names. Both the names and
687 * the list must be freed with tracefs_list_free()
688 * The list returned ends with a "NULL" pointer
689 */
tracefs_event_systems(const char * tracing_dir)690 char **tracefs_event_systems(const char *tracing_dir)
691 {
692 struct dirent *dent;
693 char **systems = NULL;
694 char *events_dir;
695 struct stat st;
696 DIR *dir;
697 int ret;
698
699 if (!tracing_dir)
700 tracing_dir = tracefs_tracing_dir();
701
702 if (!tracing_dir)
703 return NULL;
704
705 events_dir = trace_append_file(tracing_dir, "events");
706 if (!events_dir)
707 return NULL;
708
709 /*
710 * Search all the directories in the events directory,
711 * and collect the ones that have the "enable" file.
712 */
713 ret = stat(events_dir, &st);
714 if (ret < 0 || !S_ISDIR(st.st_mode))
715 goto out_free;
716
717 dir = opendir(events_dir);
718 if (!dir)
719 goto out_free;
720
721 while ((dent = readdir(dir))) {
722 const char *name = dent->d_name;
723 char *enable;
724 char *sys;
725
726 if (strcmp(name, ".") == 0 ||
727 strcmp(name, "..") == 0)
728 continue;
729
730 sys = trace_append_file(events_dir, name);
731 ret = stat(sys, &st);
732 if (ret < 0 || !S_ISDIR(st.st_mode)) {
733 free(sys);
734 continue;
735 }
736
737 enable = trace_append_file(sys, "enable");
738
739 ret = stat(enable, &st);
740 if (ret >= 0) {
741 if (add_list_string(&systems, name) < 0)
742 goto out_free;
743 }
744 free(enable);
745 free(sys);
746 }
747
748 closedir(dir);
749
750 out_free:
751 free(events_dir);
752 return systems;
753 }
754
755 /**
756 * tracefs_system_events - return list of events for system
757 * @tracing_dir: directory holding the "events" directory
758 * @system: the system to return the events for
759 *
760 * Returns an allocated list of event names. Both the names and
761 * the list must be freed with tracefs_list_free()
762 * The list returned ends with a "NULL" pointer
763 */
tracefs_system_events(const char * tracing_dir,const char * system)764 char **tracefs_system_events(const char *tracing_dir, const char *system)
765 {
766 struct dirent *dent;
767 char **events = NULL;
768 char *system_dir = NULL;
769 struct stat st;
770 DIR *dir;
771 int ret;
772
773 if (!tracing_dir)
774 tracing_dir = tracefs_tracing_dir();
775
776 if (!tracing_dir || !system)
777 return NULL;
778
779 asprintf(&system_dir, "%s/events/%s", tracing_dir, system);
780 if (!system_dir)
781 return NULL;
782
783 ret = stat(system_dir, &st);
784 if (ret < 0 || !S_ISDIR(st.st_mode))
785 goto out_free;
786
787 dir = opendir(system_dir);
788 if (!dir)
789 goto out_free;
790
791 while ((dent = readdir(dir))) {
792 const char *name = dent->d_name;
793 char *event;
794
795 if (strcmp(name, ".") == 0 ||
796 strcmp(name, "..") == 0)
797 continue;
798
799 event = trace_append_file(system_dir, name);
800 ret = stat(event, &st);
801 if (ret < 0 || !S_ISDIR(st.st_mode)) {
802 free(event);
803 continue;
804 }
805
806 if (add_list_string(&events, name) < 0)
807 goto out_free;
808
809 free(event);
810 }
811
812 closedir(dir);
813
814 out_free:
815 free(system_dir);
816
817 return events;
818 }
819
820 /**
821 * tracefs_tracers - returns an array of available tracers
822 * @tracing_dir: The directory that contains the tracing directory
823 *
824 * Returns an allocate list of plugins. The array ends with NULL
825 * Both the plugin names and array must be freed with tracefs_list_free()
826 */
tracefs_tracers(const char * tracing_dir)827 char **tracefs_tracers(const char *tracing_dir)
828 {
829 char *available_tracers;
830 struct stat st;
831 char **plugins = NULL;
832 char *buf;
833 char *str, *saveptr;
834 char *plugin;
835 int slen;
836 int len;
837 int ret;
838
839 if (!tracing_dir)
840 tracing_dir = tracefs_tracing_dir();
841
842 if (!tracing_dir)
843 return NULL;
844
845 available_tracers = trace_append_file(tracing_dir, "available_tracers");
846 if (!available_tracers)
847 return NULL;
848
849 ret = stat(available_tracers, &st);
850 if (ret < 0)
851 goto out_free;
852
853 len = str_read_file(available_tracers, &buf, true);
854 if (len <= 0)
855 goto out_free;
856
857 for (str = buf; ; str = NULL) {
858 plugin = strtok_r(str, " ", &saveptr);
859 if (!plugin)
860 break;
861 slen = strlen(plugin);
862 if (!slen)
863 continue;
864
865 /* chop off any newlines */
866 if (plugin[slen - 1] == '\n')
867 plugin[slen - 1] = '\0';
868
869 /* Skip the non tracers */
870 if (strcmp(plugin, "nop") == 0 ||
871 strcmp(plugin, "none") == 0)
872 continue;
873
874 if (add_list_string(&plugins, plugin) < 0)
875 break;
876 }
877 free(buf);
878
879 out_free:
880 free(available_tracers);
881
882 return plugins;
883 }
884
load_events(struct tep_handle * tep,const char * tracing_dir,const char * system,bool check)885 static int load_events(struct tep_handle *tep,
886 const char *tracing_dir, const char *system, bool check)
887 {
888 int ret = 0, failure = 0;
889 char **events = NULL;
890 struct stat st;
891 int len = 0;
892 int i;
893
894 if (!tracing_dir)
895 tracing_dir = tracefs_tracing_dir();
896
897 events = tracefs_system_events(tracing_dir, system);
898 if (!events)
899 return -ENOENT;
900
901 for (i = 0; events[i]; i++) {
902 char *format;
903 char *buf;
904
905 ret = asprintf(&format, "%s/events/%s/%s/format",
906 tracing_dir, system, events[i]);
907 if (ret < 0) {
908 failure = -ENOMEM;
909 break;
910 }
911
912 ret = stat(format, &st);
913 if (ret < 0)
914 goto next_event;
915
916 /* check if event is already added, to avoid duplicates */
917 if (check && tep_find_event_by_name(tep, system, events[i]))
918 goto next_event;
919
920 len = str_read_file(format, &buf, true);
921 if (len <= 0)
922 goto next_event;
923
924 ret = tep_parse_event(tep, buf, len, system);
925 free(buf);
926 next_event:
927 free(format);
928 if (ret)
929 failure = ret;
930 }
931
932 tracefs_list_free(events);
933 return failure;
934 }
935
trace_rescan_events(struct tep_handle * tep,const char * tracing_dir,const char * system)936 __hidden int trace_rescan_events(struct tep_handle *tep,
937 const char *tracing_dir, const char *system)
938 {
939 /* ToDo: add here logic for deleting removed events from tep handle */
940 return load_events(tep, tracing_dir, system, true);
941 }
942
trace_load_events(struct tep_handle * tep,const char * tracing_dir,const char * system)943 __hidden int trace_load_events(struct tep_handle *tep,
944 const char *tracing_dir, const char *system)
945 {
946 return load_events(tep, tracing_dir, system, false);
947 }
948
get_tep_event(struct tep_handle * tep,const char * system,const char * name)949 __hidden struct tep_event *get_tep_event(struct tep_handle *tep,
950 const char *system, const char *name)
951 {
952 struct tep_event *event;
953
954 /* Check if event exists in the system */
955 if (!tracefs_event_file_exists(NULL, system, name, "format"))
956 return NULL;
957
958 /* If the event is already loaded in the tep, return it */
959 event = tep_find_event_by_name(tep, system, name);
960 if (event)
961 return event;
962
963 /* Try to load any new events from the given system */
964 if (trace_rescan_events(tep, NULL, system))
965 return NULL;
966
967 return tep_find_event_by_name(tep, system, name);
968 }
969
read_header(struct tep_handle * tep,const char * tracing_dir)970 static int read_header(struct tep_handle *tep, const char *tracing_dir)
971 {
972 struct stat st;
973 char *header;
974 char *buf;
975 int len;
976 int ret = -1;
977
978 header = trace_append_file(tracing_dir, "events/header_page");
979
980 ret = stat(header, &st);
981 if (ret < 0)
982 goto out;
983
984 len = str_read_file(header, &buf, true);
985 if (len <= 0)
986 goto out;
987
988 tep_parse_header_page(tep, buf, len, sizeof(long));
989
990 free(buf);
991
992 ret = 0;
993 out:
994 free(header);
995 return ret;
996 }
997
contains(const char * name,const char * const * names)998 static bool contains(const char *name, const char * const *names)
999 {
1000 if (!names)
1001 return false;
1002 for (; *names; names++)
1003 if (strcmp(name, *names) == 0)
1004 return true;
1005 return false;
1006 }
1007
load_kallsyms(struct tep_handle * tep)1008 static void load_kallsyms(struct tep_handle *tep)
1009 {
1010 char *buf;
1011
1012 if (str_read_file("/proc/kallsyms", &buf, false) <= 0)
1013 return;
1014
1015 tep_parse_kallsyms(tep, buf);
1016 free(buf);
1017 }
1018
load_saved_cmdlines(const char * tracing_dir,struct tep_handle * tep,bool warn)1019 static int load_saved_cmdlines(const char *tracing_dir,
1020 struct tep_handle *tep, bool warn)
1021 {
1022 char *path;
1023 char *buf;
1024 int ret;
1025
1026 path = trace_append_file(tracing_dir, "saved_cmdlines");
1027 if (!path)
1028 return -1;
1029
1030 ret = str_read_file(path, &buf, false);
1031 free(path);
1032 if (ret <= 0)
1033 return -1;
1034
1035 ret = tep_parse_saved_cmdlines(tep, buf);
1036 free(buf);
1037
1038 return ret;
1039 }
1040
load_printk_formats(const char * tracing_dir,struct tep_handle * tep)1041 static void load_printk_formats(const char *tracing_dir,
1042 struct tep_handle *tep)
1043 {
1044 char *path;
1045 char *buf;
1046 int ret;
1047
1048 path = trace_append_file(tracing_dir, "printk_formats");
1049 if (!path)
1050 return;
1051
1052 ret = str_read_file(path, &buf, false);
1053 free(path);
1054 if (ret <= 0)
1055 return;
1056
1057 tep_parse_printk_formats(tep, buf);
1058 free(buf);
1059 }
1060
1061 /*
1062 * Do a best effort attempt to load kallsyms, saved_cmdlines and
1063 * printk_formats. If they can not be loaded, then this will not
1064 * do the mappings. But this does not fail the loading of events.
1065 */
load_mappings(const char * tracing_dir,struct tep_handle * tep)1066 static void load_mappings(const char *tracing_dir,
1067 struct tep_handle *tep)
1068 {
1069 load_kallsyms(tep);
1070
1071 /* If there's no tracing_dir no reason to go further */
1072 if (!tracing_dir)
1073 tracing_dir = tracefs_tracing_dir();
1074
1075 if (!tracing_dir)
1076 return;
1077
1078 load_saved_cmdlines(tracing_dir, tep, false);
1079 load_printk_formats(tracing_dir, tep);
1080 }
1081
tracefs_load_cmdlines(const char * tracing_dir,struct tep_handle * tep)1082 int tracefs_load_cmdlines(const char *tracing_dir, struct tep_handle *tep)
1083 {
1084
1085 if (!tracing_dir)
1086 tracing_dir = tracefs_tracing_dir();
1087
1088 if (!tracing_dir)
1089 return -1;
1090
1091 return load_saved_cmdlines(tracing_dir, tep, true);
1092 }
1093
fill_local_events_system(const char * tracing_dir,struct tep_handle * tep,const char * const * sys_names,int * parsing_failures)1094 static int fill_local_events_system(const char *tracing_dir,
1095 struct tep_handle *tep,
1096 const char * const *sys_names,
1097 int *parsing_failures)
1098 {
1099 char **systems = NULL;
1100 int ret;
1101 int i;
1102
1103 if (!tracing_dir)
1104 tracing_dir = tracefs_tracing_dir();
1105 if (!tracing_dir)
1106 return -1;
1107
1108 systems = tracefs_event_systems(tracing_dir);
1109 if (!systems)
1110 return -1;
1111
1112 ret = read_header(tep, tracing_dir);
1113 if (ret < 0) {
1114 ret = -1;
1115 goto out;
1116 }
1117
1118 if (parsing_failures)
1119 *parsing_failures = 0;
1120
1121 for (i = 0; systems[i]; i++) {
1122 if (sys_names && !contains(systems[i], sys_names))
1123 continue;
1124 ret = trace_load_events(tep, tracing_dir, systems[i]);
1125 if (ret && parsing_failures)
1126 (*parsing_failures)++;
1127 }
1128
1129 /* Include ftrace, as it is excluded for not having "enable" file */
1130 if (!sys_names || contains("ftrace", sys_names))
1131 trace_load_events(tep, tracing_dir, "ftrace");
1132
1133 load_mappings(tracing_dir, tep);
1134
1135 /* always succeed because parsing failures are not critical */
1136 ret = 0;
1137 out:
1138 tracefs_list_free(systems);
1139 return ret;
1140 }
1141
set_tep_cpus(const char * tracing_dir,struct tep_handle * tep)1142 static void set_tep_cpus(const char *tracing_dir, struct tep_handle *tep)
1143 {
1144 struct stat st;
1145 char path[PATH_MAX];
1146 int cpus = sysconf(_SC_NPROCESSORS_CONF);
1147 int max_cpu = 0;
1148 int ret;
1149 int i;
1150
1151 if (!tracing_dir)
1152 tracing_dir = tracefs_tracing_dir();
1153
1154 /*
1155 * Paranoid: in case sysconf() above does not work.
1156 * And we also only care about the number of tracing
1157 * buffers that exist. If cpus is 32, but the top half
1158 * is offline, there may only be 16 tracing buffers.
1159 * That's what we want to know.
1160 */
1161 for (i = 0; !cpus || i < cpus; i++) {
1162 snprintf(path, PATH_MAX, "%s/per_cpu/cpu%d", tracing_dir, i);
1163 ret = stat(path, &st);
1164 if (!ret && S_ISDIR(st.st_mode))
1165 max_cpu = i + 1;
1166 else if (i >= cpus)
1167 break;
1168 }
1169
1170 if (!max_cpu)
1171 max_cpu = cpus;
1172
1173 tep_set_cpus(tep, max_cpu);
1174 }
1175
1176 /**
1177 * tracefs_local_events_system - create a tep from the events of the specified subsystem.
1178 *
1179 * @tracing_dir: The directory that contains the events.
1180 * @sys_name: Array of system names, to load the events from.
1181 * The last element from the array must be NULL
1182 *
1183 * Returns a tep structure that contains the tep local to
1184 * the system.
1185 */
tracefs_local_events_system(const char * tracing_dir,const char * const * sys_names)1186 struct tep_handle *tracefs_local_events_system(const char *tracing_dir,
1187 const char * const *sys_names)
1188 {
1189 struct tep_handle *tep = NULL;
1190
1191 tep = tep_alloc();
1192 if (!tep)
1193 return NULL;
1194
1195 if (fill_local_events_system(tracing_dir, tep, sys_names, NULL)) {
1196 tep_free(tep);
1197 tep = NULL;
1198 }
1199
1200 set_tep_cpus(tracing_dir, tep);
1201
1202 /* Set the long size for this tep handle */
1203 tep_set_long_size(tep, tep_get_header_page_size(tep));
1204
1205 return tep;
1206 }
1207
1208 /**
1209 * tracefs_local_events - create a tep from the events on system
1210 * @tracing_dir: The directory that contains the events.
1211 *
1212 * Returns a tep structure that contains the teps local to
1213 * the system.
1214 */
tracefs_local_events(const char * tracing_dir)1215 struct tep_handle *tracefs_local_events(const char *tracing_dir)
1216 {
1217 return tracefs_local_events_system(tracing_dir, NULL);
1218 }
1219
1220 /**
1221 * tracefs_fill_local_events - Fill a tep with the events on system
1222 * @tracing_dir: The directory that contains the events.
1223 * @tep: Allocated tep handler which will be filled
1224 * @parsing_failures: return number of failures while parsing the event files
1225 *
1226 * Returns whether the operation succeeded
1227 */
tracefs_fill_local_events(const char * tracing_dir,struct tep_handle * tep,int * parsing_failures)1228 int tracefs_fill_local_events(const char *tracing_dir,
1229 struct tep_handle *tep, int *parsing_failures)
1230 {
1231 return fill_local_events_system(tracing_dir, tep,
1232 NULL, parsing_failures);
1233 }
1234
match(const char * str,regex_t * re)1235 static bool match(const char *str, regex_t *re)
1236 {
1237 return regexec(re, str, 0, NULL, 0) == 0;
1238 }
1239
1240 enum event_state {
1241 STATE_INIT,
1242 STATE_ENABLED,
1243 STATE_DISABLED,
1244 STATE_MIXED,
1245 STATE_ERROR,
1246 };
1247
read_event_state(struct tracefs_instance * instance,const char * file,enum event_state * state)1248 static int read_event_state(struct tracefs_instance *instance, const char *file,
1249 enum event_state *state)
1250 {
1251 char *val;
1252 int ret = 0;
1253
1254 if (*state == STATE_ERROR)
1255 return -1;
1256
1257 val = tracefs_instance_file_read(instance, file, NULL);
1258 if (!val)
1259 return -1;
1260
1261 switch (val[0]) {
1262 case '0':
1263 switch (*state) {
1264 case STATE_INIT:
1265 *state = STATE_DISABLED;
1266 break;
1267 case STATE_ENABLED:
1268 *state = STATE_MIXED;
1269 break;
1270 default:
1271 break;
1272 }
1273 break;
1274 case '1':
1275 switch (*state) {
1276 case STATE_INIT:
1277 *state = STATE_ENABLED;
1278 break;
1279 case STATE_DISABLED:
1280 *state = STATE_MIXED;
1281 break;
1282 default:
1283 break;
1284 }
1285 break;
1286 case 'X':
1287 *state = STATE_MIXED;
1288 break;
1289 default:
1290 *state = TRACEFS_ERROR;
1291 ret = -1;
1292 break;
1293 }
1294 free(val);
1295
1296 return ret;
1297 }
1298
enable_disable_event(struct tracefs_instance * instance,const char * system,const char * event,bool enable,enum event_state * state)1299 static int enable_disable_event(struct tracefs_instance *instance,
1300 const char *system, const char *event,
1301 bool enable, enum event_state *state)
1302 {
1303 const char *str = enable ? "1" : "0";
1304 char *system_event;
1305 int ret;
1306
1307 ret = asprintf(&system_event, "events/%s/%s/enable", system, event);
1308 if (ret < 0)
1309 return ret;
1310
1311 if (state)
1312 ret = read_event_state(instance, system_event, state);
1313 else
1314 ret = tracefs_instance_file_write(instance, system_event, str);
1315 free(system_event);
1316
1317 return ret;
1318 }
1319
enable_disable_system(struct tracefs_instance * instance,const char * system,bool enable,enum event_state * state)1320 static int enable_disable_system(struct tracefs_instance *instance,
1321 const char *system, bool enable,
1322 enum event_state *state)
1323 {
1324 const char *str = enable ? "1" : "0";
1325 char *system_path;
1326 int ret;
1327
1328 ret = asprintf(&system_path, "events/%s/enable", system);
1329 if (ret < 0)
1330 return ret;
1331
1332 if (state)
1333 ret = read_event_state(instance, system_path, state);
1334 else
1335 ret = tracefs_instance_file_write(instance, system_path, str);
1336 free(system_path);
1337
1338 return ret;
1339 }
1340
enable_disable_all(struct tracefs_instance * instance,bool enable)1341 static int enable_disable_all(struct tracefs_instance *instance,
1342 bool enable)
1343 {
1344 const char *str = enable ? "1" : "0";
1345 int ret;
1346
1347 ret = tracefs_instance_file_write(instance, "events/enable", str);
1348 return ret < 0 ? ret : 0;
1349 }
1350
make_regex(regex_t * re,const char * match)1351 static int make_regex(regex_t *re, const char *match)
1352 {
1353 int len = strlen(match);
1354 char str[len + 3];
1355 char *p = &str[0];
1356
1357 if (!len || match[0] != '^')
1358 *(p++) = '^';
1359
1360 strcpy(p, match);
1361 p += len;
1362
1363 if (!len || match[len-1] != '$')
1364 *(p++) = '$';
1365
1366 *p = '\0';
1367
1368 return regcomp(re, str, REG_ICASE|REG_NOSUB);
1369 }
1370
event_enable_disable(struct tracefs_instance * instance,const char * system,const char * event,bool enable,enum event_state * state)1371 static int event_enable_disable(struct tracefs_instance *instance,
1372 const char *system, const char *event,
1373 bool enable, enum event_state *state)
1374 {
1375 regex_t system_re, event_re;
1376 char **systems;
1377 char **events = NULL;
1378 int ret = -1;
1379 int s, e;
1380
1381 /* Handle all events first */
1382 if (!system && !event)
1383 return enable_disable_all(instance, enable);
1384
1385 systems = tracefs_event_systems(NULL);
1386 if (!systems)
1387 goto out_free;
1388
1389 if (system) {
1390 ret = make_regex(&system_re, system);
1391 if (ret < 0)
1392 goto out_free;
1393 }
1394 if (event) {
1395 ret = make_regex(&event_re, event);
1396 if (ret < 0) {
1397 if (system)
1398 regfree(&system_re);
1399 goto out_free;
1400 }
1401 }
1402
1403 ret = -1;
1404 for (s = 0; systems[s]; s++) {
1405 if (system && !match(systems[s], &system_re))
1406 continue;
1407
1408 /* Check for the short cut first */
1409 if (!event) {
1410 ret = enable_disable_system(instance, systems[s], enable, state);
1411 if (ret < 0)
1412 break;
1413 ret = 0;
1414 continue;
1415 }
1416
1417 events = tracefs_system_events(NULL, systems[s]);
1418 if (!events)
1419 continue; /* Error? */
1420
1421 for (e = 0; events[e]; e++) {
1422 if (!match(events[e], &event_re))
1423 continue;
1424 ret = enable_disable_event(instance, systems[s],
1425 events[e], enable, state);
1426 if (ret < 0)
1427 break;
1428 ret = 0;
1429 }
1430 tracefs_list_free(events);
1431 events = NULL;
1432 }
1433 if (system)
1434 regfree(&system_re);
1435 if (event)
1436 regfree(&event_re);
1437
1438 out_free:
1439 tracefs_list_free(systems);
1440 tracefs_list_free(events);
1441 return ret;
1442 }
1443
1444 /**
1445 * tracefs_event_enable - enable specified events
1446 * @instance: ftrace instance, can be NULL for the top instance
1447 * @system: A regex of a system (NULL to match all systems)
1448 * @event: A regex of the event in the system (NULL to match all events)
1449 *
1450 * This will enable events that match the @system and @event.
1451 * If both @system and @event are NULL, then it will enable all events.
1452 * If @system is NULL, it will look at all systems for matching events
1453 * to @event.
1454 * If @event is NULL, then it will enable all events in the systems
1455 * that match @system.
1456 *
1457 * Returns 0 on success, and -1 if it encountered an error,
1458 * or if no events matched. If no events matched, then -1 is set
1459 * but errno will not be.
1460 */
tracefs_event_enable(struct tracefs_instance * instance,const char * system,const char * event)1461 int tracefs_event_enable(struct tracefs_instance *instance,
1462 const char *system, const char *event)
1463 {
1464 return event_enable_disable(instance, system, event, true, NULL);
1465 }
1466
tracefs_event_disable(struct tracefs_instance * instance,const char * system,const char * event)1467 int tracefs_event_disable(struct tracefs_instance *instance,
1468 const char *system, const char *event)
1469 {
1470 return event_enable_disable(instance, system, event, false, NULL);
1471 }
1472
1473 /**
1474 * tracefs_event_is_enabled - return if the event is enabled or not
1475 * @instance: ftrace instance, can be NULL for the top instance
1476 * @system: The name of the system to check
1477 * @event: The name of the event to check
1478 *
1479 * Checks is an event or multiple events are enabled.
1480 *
1481 * If @system is NULL, then it will check all the systems where @event is
1482 * a match.
1483 *
1484 * If @event is NULL, then it will check all events where @system is a match.
1485 *
1486 * If both @system and @event are NULL, then it will check all events
1487 *
1488 * Returns TRACEFS_ALL_ENABLED if all matching are enabled.
1489 * Returns TRACEFS_SOME_ENABLED if some are enabled and some are not
1490 * Returns TRACEFS_ALL_DISABLED if none of the events are enabled.
1491 * Returns TRACEFS_ERROR if there is an error reading the events.
1492 */
1493 enum tracefs_enable_state
tracefs_event_is_enabled(struct tracefs_instance * instance,const char * system,const char * event)1494 tracefs_event_is_enabled(struct tracefs_instance *instance,
1495 const char *system, const char *event)
1496 {
1497 enum event_state state = STATE_INIT;
1498 int ret;
1499
1500 ret = event_enable_disable(instance, system, event, false, &state);
1501
1502 if (ret < 0)
1503 return TRACEFS_ERROR;
1504
1505 switch (state) {
1506 case STATE_ENABLED:
1507 return TRACEFS_ALL_ENABLED;
1508 case STATE_DISABLED:
1509 return TRACEFS_ALL_DISABLED;
1510 case STATE_MIXED:
1511 return TRACEFS_SOME_ENABLED;
1512 default:
1513 return TRACEFS_ERROR;
1514 }
1515 }
1516