1 // SPDX-License-Identifier: LGPL-2.1
2 /*
3 * Copyright (C) 2021 VMware Inc, Steven Rostedt <rostedt@goodmis.org>
4 *
5 * Updates:
6 * Copyright (C) 2021, 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 <fcntl.h>
15 #include <limits.h>
16 #include <sys/time.h>
17 #include <sys/types.h>
18
19 #include "tracefs.h"
20 #include "tracefs-local.h"
21
22 #define HIST_FILE "hist"
23
24 #define ASCENDING ".ascending"
25 #define DESCENDING ".descending"
26
27 #define SYNTHETIC_GROUP "synthetic"
28
29 struct tracefs_hist {
30 struct tep_handle *tep;
31 struct tep_event *event;
32 char *system;
33 char *event_name;
34 char *name;
35 char **keys;
36 char **values;
37 char **sort;
38 char *filter;
39 int size;
40 unsigned int filter_parens;
41 unsigned int filter_state;
42 };
43
44 /*
45 * tracefs_hist_get_name - get the name of the histogram
46 * @hist: The histogram to get the name for
47 *
48 * Returns name string owned by @hist on success, or NULL on error.
49 */
tracefs_hist_get_name(struct tracefs_hist * hist)50 const char *tracefs_hist_get_name(struct tracefs_hist *hist)
51 {
52 return hist ? hist->name : NULL;
53 }
54
55 /*
56 * tracefs_hist_get_event - get the event name of the histogram
57 * @hist: The histogram to get the event name for
58 *
59 * Returns event name string owned by @hist on success, or NULL on error.
60 */
tracefs_hist_get_event(struct tracefs_hist * hist)61 const char *tracefs_hist_get_event(struct tracefs_hist *hist)
62 {
63 return hist ? hist->event_name : NULL;
64 }
65
66 /*
67 * tracefs_hist_get_system - get the system name of the histogram
68 * @hist: The histogram to get the system name for
69 *
70 * Returns system name string owned by @hist on success, or NULL on error.
71 */
tracefs_hist_get_system(struct tracefs_hist * hist)72 const char *tracefs_hist_get_system(struct tracefs_hist *hist)
73 {
74 return hist ? hist->system : NULL;
75 }
76
add_list(struct trace_seq * seq,const char * start,char ** list)77 static void add_list(struct trace_seq *seq, const char *start,
78 char **list)
79 {
80 int i;
81
82 trace_seq_puts(seq, start);
83 for (i = 0; list[i]; i++) {
84 if (i)
85 trace_seq_putc(seq, ',');
86 trace_seq_puts(seq, list[i]);
87 }
88 }
89
add_hist_commands(struct trace_seq * seq,struct tracefs_hist * hist,enum tracefs_hist_command command)90 static void add_hist_commands(struct trace_seq *seq, struct tracefs_hist *hist,
91 enum tracefs_hist_command command)
92 {
93 if (command == TRACEFS_HIST_CMD_DESTROY)
94 trace_seq_putc(seq, '!');
95
96 add_list(seq, "hist:keys=", hist->keys);
97
98 if (hist->values)
99 add_list(seq, ":vals=", hist->values);
100
101 if (hist->sort)
102 add_list(seq, ":sort=", hist->sort);
103
104 if (hist->size)
105 trace_seq_printf(seq, ":size=%d", hist->size);
106
107 switch(command) {
108 case TRACEFS_HIST_CMD_START: break;
109 case TRACEFS_HIST_CMD_PAUSE: trace_seq_puts(seq, ":pause"); break;
110 case TRACEFS_HIST_CMD_CONT: trace_seq_puts(seq, ":cont"); break;
111 case TRACEFS_HIST_CMD_CLEAR: trace_seq_puts(seq, ":clear"); break;
112 default: break;
113 }
114
115 if (hist->name)
116 trace_seq_printf(seq, ":name=%s", hist->name);
117
118 if (hist->filter)
119 trace_seq_printf(seq, " if %s", hist->filter);
120
121 }
122
123 /*
124 * trace_hist_echo_cmd - show how to start the histogram
125 * @seq: A trace_seq to store the commands to create
126 * @hist: The histogram to write into the trigger file
127 * @command: If not zero, can pause, continue or clear the histogram
128 *
129 * This shows the echo commands to create the histogram for an event
130 * with the given fields.
131 *
132 * Returns 0 on succes -1 on error.
133 */
134 int
tracefs_hist_echo_cmd(struct trace_seq * seq,struct tracefs_instance * instance,struct tracefs_hist * hist,enum tracefs_hist_command command)135 tracefs_hist_echo_cmd(struct trace_seq *seq, struct tracefs_instance *instance,
136 struct tracefs_hist *hist,
137 enum tracefs_hist_command command)
138 {
139 const char *system = hist->system;
140 const char *event = hist->event_name;
141 char *path;
142
143 if (!hist->keys) {
144 errno = -EINVAL;
145 return -1;
146 }
147
148 path = tracefs_event_get_file(instance, system, event, "trigger");
149 if (!path)
150 return -1;
151
152 trace_seq_puts(seq, "echo '");
153
154 add_hist_commands(seq, hist, command);
155
156 trace_seq_printf(seq, "' > %s\n", path);
157
158 tracefs_put_tracing_file(path);
159
160 return 0;
161 }
162
163 /*
164 * tracefs_hist_command - Create, start, pause, destroy a histogram for an event
165 * @instance: The instance the histogram will be in (NULL for toplevel)
166 * @hist: The histogram to write into the trigger file
167 * @command: Command to perform on a histogram.
168 *
169 * Creates, pause, continue, clears, or destroys a histogram.
170 *
171 * Returns 0 on succes -1 on error.
172 */
tracefs_hist_command(struct tracefs_instance * instance,struct tracefs_hist * hist,enum tracefs_hist_command command)173 int tracefs_hist_command(struct tracefs_instance *instance,
174 struct tracefs_hist *hist,
175 enum tracefs_hist_command command)
176 {
177 const char *system = hist->system;
178 const char *event = hist->event_name;
179 struct trace_seq seq;
180 int ret;
181
182 if (!tracefs_event_file_exists(instance, system, event, HIST_FILE))
183 return -1;
184
185 errno = -EINVAL;
186 if (!hist->keys)
187 return -1;
188
189 trace_seq_init(&seq);
190
191 add_hist_commands(&seq, hist, command);
192
193 trace_seq_putc(&seq, '\n');
194 trace_seq_terminate(&seq);
195
196 ret = -1;
197 if (seq.state == TRACE_SEQ__GOOD)
198 ret = tracefs_event_file_append(instance, system, event,
199 "trigger", seq.buffer);
200
201 trace_seq_destroy(&seq);
202
203 return ret < 0 ? -1 : 0;
204 }
205
206 /**
207 * tracefs_hist_free - free a tracefs_hist element
208 * @hist: The histogram to free
209 */
tracefs_hist_free(struct tracefs_hist * hist)210 void tracefs_hist_free(struct tracefs_hist *hist)
211 {
212 if (!hist)
213 return;
214
215 tep_unref(hist->tep);
216 free(hist->system);
217 free(hist->event_name);
218 free(hist->name);
219 free(hist->filter);
220 tracefs_list_free(hist->keys);
221 tracefs_list_free(hist->values);
222 tracefs_list_free(hist->sort);
223 free(hist);
224 }
225
226 /**
227 * tracefs_hist_alloc - Initialize one-dimensional histogram
228 * @tep: The tep handle that has the @system and @event.
229 * @system: The system the histogram event is in.
230 * @event_name: The name of the event that the histogram will be attached to.
231 * @key: The primary key the histogram will use
232 * @type: The format type of the key.
233 *
234 * Will initialize a histogram descriptor that will be attached to
235 * the @system/@event with the given @key as the primary. This only
236 * initializes the descriptor, it does not start the histogram
237 * in the kernel.
238 *
239 * Returns an initialized histogram on success.
240 * NULL on failure.
241 */
242 struct tracefs_hist *
tracefs_hist_alloc(struct tep_handle * tep,const char * system,const char * event_name,const char * key,enum tracefs_hist_key_type type)243 tracefs_hist_alloc(struct tep_handle *tep,
244 const char *system, const char *event_name,
245 const char *key, enum tracefs_hist_key_type type)
246 {
247 struct tracefs_hist_axis axis[] = {{key, type}, {NULL, 0}};
248
249 return tracefs_hist_alloc_nd(tep, system, event_name, axis);
250 }
251
252 /**
253 * tracefs_hist_alloc_2d - Initialize two-dimensional histogram
254 * @tep: The tep handle that has the @system and @event.
255 * @system: The system the histogram event is in.
256 * @event: The event that the histogram will be attached to.
257 * @key1: The first primary key the histogram will use
258 * @type1: The format type of the first key.
259 * @key2: The second primary key the histogram will use
260 * @type2: The format type of the second key.
261 *
262 * Will initialize a histogram descriptor that will be attached to
263 * the @system/@event with the given @key1 and @key2 as the primaries.
264 * This only initializes the descriptor, it does not start the histogram
265 * in the kernel.
266 *
267 * Returns an initialized histogram on success.
268 * NULL on failure.
269 */
270 struct tracefs_hist *
tracefs_hist_alloc_2d(struct tep_handle * tep,const char * system,const char * event_name,const char * key1,enum tracefs_hist_key_type type1,const char * key2,enum tracefs_hist_key_type type2)271 tracefs_hist_alloc_2d(struct tep_handle *tep,
272 const char *system, const char *event_name,
273 const char *key1, enum tracefs_hist_key_type type1,
274 const char *key2, enum tracefs_hist_key_type type2)
275 {
276 struct tracefs_hist_axis axis[] = {{key1, type1},
277 {key2, type2},
278 {NULL, 0}};
279
280 return tracefs_hist_alloc_nd(tep, system, event_name, axis);
281 }
282
283 static struct tracefs_hist *
hist_alloc_nd(struct tep_handle * tep,const char * system,const char * event_name,struct tracefs_hist_axis * axes,struct tracefs_hist_axis_cnt * axes_cnt)284 hist_alloc_nd(struct tep_handle *tep,
285 const char *system, const char *event_name,
286 struct tracefs_hist_axis *axes,
287 struct tracefs_hist_axis_cnt *axes_cnt)
288 {
289 struct tep_event *event;
290 struct tracefs_hist *hist;
291
292 if (!system || !event_name)
293 return NULL;
294
295 event = tep_find_event_by_name(tep, system, event_name);
296 if (!event)
297 return NULL;
298
299 hist = calloc(1, sizeof(*hist));
300 if (!hist)
301 return NULL;
302
303 tep_ref(tep);
304 hist->tep = tep;
305 hist->event = event;
306 hist->system = strdup(system);
307 hist->event_name = strdup(event_name);
308 if (!hist->system || !hist->event_name)
309 goto fail;
310
311 for (; axes && axes->key; axes++)
312 if (tracefs_hist_add_key(hist, axes->key, axes->type) < 0)
313 goto fail;
314
315 for (; axes_cnt && axes_cnt->key; axes_cnt++)
316 if (tracefs_hist_add_key_cnt(hist, axes_cnt->key, axes_cnt->type, axes_cnt->cnt) < 0)
317 goto fail;
318
319 return hist;
320
321 fail:
322 tracefs_hist_free(hist);
323 return NULL;
324 }
325 /**
326 * tracefs_hist_alloc_nd - Initialize N-dimensional histogram
327 * @tep: The tep handle that has the @system and @event.
328 * @system: The system the histogram event is in
329 * @event: The event that the histogram will be attached to
330 * @axes: An array of histogram axes, terminated by a {NULL, 0} entry
331 *
332 * Will initialize a histogram descriptor that will be attached to
333 * the @system/@event. This only initializes the descriptor with the given
334 * @axes keys as primaries. This only initializes the descriptor, it does
335 * not start the histogram in the kernel.
336 *
337 * Returns an initialized histogram on success.
338 * NULL on failure.
339 */
340 struct tracefs_hist *
tracefs_hist_alloc_nd(struct tep_handle * tep,const char * system,const char * event_name,struct tracefs_hist_axis * axes)341 tracefs_hist_alloc_nd(struct tep_handle *tep,
342 const char *system, const char *event_name,
343 struct tracefs_hist_axis *axes)
344 {
345 return hist_alloc_nd(tep, system, event_name, axes, NULL);
346 }
347
348 /**
349 * tracefs_hist_alloc_nd_cnt - Initialize N-dimensional histogram
350 * @tep: The tep handle that has the @system and @event.
351 * @system: The system the histogram event is in
352 * @event: The event that the histogram will be attached to
353 * @axes: An array of histogram axes, terminated by a {NULL, 0} entry
354 *
355 * Will initialize a histogram descriptor that will be attached to
356 * the @system/@event. This only initializes the descriptor with the given
357 * @axes keys as primaries. This only initializes the descriptor, it does
358 * not start the histogram in the kernel.
359 *
360 * Returns an initialized histogram on success.
361 * NULL on failure.
362 */
363 struct tracefs_hist *
tracefs_hist_alloc_nd_cnt(struct tep_handle * tep,const char * system,const char * event_name,struct tracefs_hist_axis_cnt * axes)364 tracefs_hist_alloc_nd_cnt(struct tep_handle *tep,
365 const char *system, const char *event_name,
366 struct tracefs_hist_axis_cnt *axes)
367 {
368 return hist_alloc_nd(tep, system, event_name, NULL, axes);
369 }
370
371 /**
372 * tracefs_hist_add_key - add to a key to a histogram
373 * @hist: The histogram to add the key to.
374 * @key: The name of the key field.
375 * @type: The type of the key format.
376 * @cnt: Some types require a counter, for those, this is used
377 *
378 * This adds a secondary or tertiary key to the histogram.
379 *
380 * Returns 0 on success, -1 on error.
381 */
tracefs_hist_add_key_cnt(struct tracefs_hist * hist,const char * key,enum tracefs_hist_key_type type,int cnt)382 int tracefs_hist_add_key_cnt(struct tracefs_hist *hist, const char *key,
383 enum tracefs_hist_key_type type, int cnt)
384 {
385 bool use_key = false;
386 char *key_type = NULL;
387 char **new_list;
388 int ret = -1;
389
390 switch (type) {
391 case TRACEFS_HIST_KEY_NORMAL:
392 use_key = true;
393 ret = 0;
394 break;
395 case TRACEFS_HIST_KEY_HEX:
396 ret = asprintf(&key_type, "%s.hex", key);
397 break;
398 case TRACEFS_HIST_KEY_SYM:
399 ret = asprintf(&key_type, "%s.sym", key);
400 break;
401 case TRACEFS_HIST_KEY_SYM_OFFSET:
402 ret = asprintf(&key_type, "%s.sym-offset", key);
403 break;
404 case TRACEFS_HIST_KEY_SYSCALL:
405 ret = asprintf(&key_type, "%s.syscall", key);
406 break;
407 case TRACEFS_HIST_KEY_EXECNAME:
408 ret = asprintf(&key_type, "%s.execname", key);
409 break;
410 case TRACEFS_HIST_KEY_LOG:
411 ret = asprintf(&key_type, "%s.log2", key);
412 break;
413 case TRACEFS_HIST_KEY_USECS:
414 ret = asprintf(&key_type, "%s.usecs", key);
415 break;
416 case TRACEFS_HIST_KEY_BUCKETS:
417 ret = asprintf(&key_type, "%s.buckets=%d", key, cnt);
418 break;
419 case TRACEFS_HIST_KEY_MAX:
420 /* error */
421 break;
422 }
423
424 if (ret < 0)
425 return -1;
426
427 new_list = tracefs_list_add(hist->keys, use_key ? key : key_type);
428 free(key_type);
429 if (!new_list)
430 return -1;
431
432 hist->keys = new_list;
433
434 return 0;
435 }
436
437 /**
438 * tracefs_hist_add_key - add to a key to a histogram
439 * @hist: The histogram to add the key to.
440 * @key: The name of the key field.
441 * @type: The type of the key format.
442 *
443 * This adds a secondary or tertiary key to the histogram.
444 *
445 * Returns 0 on success, -1 on error.
446 */
tracefs_hist_add_key(struct tracefs_hist * hist,const char * key,enum tracefs_hist_key_type type)447 int tracefs_hist_add_key(struct tracefs_hist *hist, const char *key,
448 enum tracefs_hist_key_type type)
449 {
450 return tracefs_hist_add_key_cnt(hist, key, type, 0);
451 }
452
453 /**
454 * tracefs_hist_add_value - add to a value to a histogram
455 * @hist: The histogram to add the value to.
456 * @key: The name of the value field.
457 *
458 * This adds a value field to the histogram.
459 *
460 * Returns 0 on success, -1 on error.
461 */
tracefs_hist_add_value(struct tracefs_hist * hist,const char * value)462 int tracefs_hist_add_value(struct tracefs_hist *hist, const char *value)
463 {
464 char **new_list;
465
466 new_list = tracefs_list_add(hist->values, value);
467 if (!new_list)
468 return -1;
469
470 hist->values = new_list;
471
472 return 0;
473 }
474
475 /**
476 * tracefs_hist_add_name - name a histogram
477 * @hist: The histogram to name.
478 * @name: The name of the histogram.
479 *
480 * Adds a name to the histogram. Named histograms will share their
481 * data with other events that have the same name as if it was
482 * a single histogram.
483 *
484 * If the histogram already has a name, this will fail.
485 *
486 * Returns 0 on success, -1 on error.
487 */
tracefs_hist_add_name(struct tracefs_hist * hist,const char * name)488 int tracefs_hist_add_name(struct tracefs_hist *hist, const char *name)
489 {
490 if (hist->name)
491 return -1;
492
493 hist->name = strdup(name);
494
495 return hist->name ? 0 : -1;
496 }
497
498 static char **
add_sort_key(struct tracefs_hist * hist,const char * sort_key,char ** list)499 add_sort_key(struct tracefs_hist *hist, const char *sort_key, char **list)
500 {
501 char **key_list = hist->keys;
502 char **val_list = hist->values;
503 int i;
504
505 if (strcmp(sort_key, TRACEFS_HIST_HITCOUNT) == 0)
506 goto out;
507
508 for (i = 0; key_list[i]; i++) {
509 if (strcmp(key_list[i], sort_key) == 0)
510 break;
511 }
512
513 if (!key_list[i] && val_list) {
514 for (i = 0; val_list[i]; i++) {
515 if (strcmp(val_list[i], sort_key) == 0)
516 break;
517 if (!val_list[i])
518 return NULL;
519 }
520 }
521
522
523 out:
524 return tracefs_list_add(list, sort_key);
525 }
526
527 /**
528 * tracefs_hist_add_sort_key - add a key for sorting the histogram
529 * @hist: The histogram to add the sort key to
530 * @sort_key: The key to sort
531 *
532 * Call the function to add to the list of sort keys of the histohram in
533 * the order of priority that the keys would be sorted on output.
534 *
535 * Returns 0 on success, -1 on error.
536 */
tracefs_hist_add_sort_key(struct tracefs_hist * hist,const char * sort_key)537 int tracefs_hist_add_sort_key(struct tracefs_hist *hist,
538 const char *sort_key)
539 {
540 char **list = hist->sort;
541
542 if (!hist || !sort_key)
543 return -1;
544
545 list = add_sort_key(hist, sort_key, hist->sort);
546 if (!list)
547 return -1;
548
549 hist->sort = list;
550
551 return 0;
552 }
553
554 /**
555 * tracefs_hist_set_sort_key - set a key for sorting the histogram
556 * @hist: The histogram to set the sort key to
557 * @sort_key: The key to sort (and the strings after it)
558 * Last one must be NULL.
559 *
560 * Set a list of sort keys in the order of priority that the
561 * keys would be sorted on output. Keys must be added first.
562 *
563 * Returns 0 on success, -1 on error.
564 */
tracefs_hist_set_sort_key(struct tracefs_hist * hist,const char * sort_key,...)565 int tracefs_hist_set_sort_key(struct tracefs_hist *hist,
566 const char *sort_key, ...)
567 {
568 char **list = NULL;
569 char **tmp;
570 va_list ap;
571
572 if (!hist || !sort_key)
573 return -1;
574
575 tmp = add_sort_key(hist, sort_key, list);
576 if (!tmp)
577 goto fail;
578 list = tmp;
579
580 va_start(ap, sort_key);
581 for (;;) {
582 sort_key = va_arg(ap, const char *);
583 if (!sort_key)
584 break;
585 tmp = add_sort_key(hist, sort_key, list);
586 if (!tmp)
587 goto fail;
588 list = tmp;
589 }
590 va_end(ap);
591
592 tracefs_list_free(hist->sort);
593 hist->sort = list;
594
595 return 0;
596 fail:
597 tracefs_list_free(list);
598 return -1;
599 }
600
end_match(const char * sort_key,const char * ending)601 static int end_match(const char *sort_key, const char *ending)
602 {
603 int key_len = strlen(sort_key);
604 int end_len = strlen(ending);
605
606 if (key_len <= end_len)
607 return 0;
608
609 sort_key += key_len - end_len;
610
611 return strcmp(sort_key, ending) == 0 ? key_len - end_len : 0;
612 }
613
614 /**
615 * tracefs_hist_sort_key_direction - set direction of a sort key
616 * @hist: The histogram to modify.
617 * @sort_str: The sort key to set the direction for
618 * @dir: The direction to set the sort key to.
619 *
620 * Returns 0 on success, and -1 on error;
621 */
tracefs_hist_sort_key_direction(struct tracefs_hist * hist,const char * sort_str,enum tracefs_hist_sort_direction dir)622 int tracefs_hist_sort_key_direction(struct tracefs_hist *hist,
623 const char *sort_str,
624 enum tracefs_hist_sort_direction dir)
625 {
626 char **sort = hist->sort;
627 char *sort_key;
628 char *direct;
629 int match;
630 int i;
631
632 if (!sort)
633 return -1;
634
635 for (i = 0; sort[i]; i++) {
636 if (strcmp(sort[i], sort_str) == 0)
637 break;
638 }
639 if (!sort[i])
640 return -1;
641
642 sort_key = sort[i];
643
644 switch (dir) {
645 case TRACEFS_HIST_SORT_ASCENDING:
646 direct = ASCENDING;
647 break;
648 case TRACEFS_HIST_SORT_DESCENDING:
649 direct = DESCENDING;
650 break;
651 default:
652 return -1;
653 }
654
655 match = end_match(sort_key, ASCENDING);
656 if (match) {
657 /* Already match? */
658 if (dir == TRACEFS_HIST_SORT_ASCENDING)
659 return 0;
660 } else {
661 match = end_match(sort_key, DESCENDING);
662 /* Already match? */
663 if (match && dir == TRACEFS_HIST_SORT_DESCENDING)
664 return 0;
665 }
666
667 if (match)
668 /* Clear the original text */
669 sort_key[match] = '\0';
670
671 sort_key = realloc(sort_key, strlen(sort_key) + strlen(direct) + 1);
672 if (!sort_key) {
673 /* Failed to alloc, may need to put back the match */
674 sort_key = sort[i];
675 if (match)
676 sort_key[match] = '.';
677 return -1;
678 }
679
680 strcat(sort_key, direct);
681 sort[i] = sort_key;
682 return 0;
683 }
684
tracefs_hist_append_filter(struct tracefs_hist * hist,enum tracefs_filter type,const char * field,enum tracefs_compare compare,const char * val)685 int tracefs_hist_append_filter(struct tracefs_hist *hist,
686 enum tracefs_filter type,
687 const char *field,
688 enum tracefs_compare compare,
689 const char *val)
690 {
691 return trace_append_filter(&hist->filter, &hist->filter_state,
692 &hist->filter_parens,
693 hist->event,
694 type, field, compare, val);
695 }
696
697 enum action_type {
698 ACTION_NONE,
699 ACTION_TRACE,
700 ACTION_SNAPSHOT,
701 ACTION_SAVE,
702 };
703
704 struct action {
705 struct action *next;
706 enum action_type type;
707 enum tracefs_synth_handler handler;
708 char *handle_field;
709 char *save;
710 };
711
712 struct name_hash {
713 struct name_hash *next;
714 char *name;
715 char *hash;
716 };
717
718 /*
719 * @name: name of the synthetic event
720 * @start_system: system of the starting event
721 * @start_event: the starting event
722 * @end_system: system of the ending event
723 * @end_event: the ending event
724 * @actions: List of actions to take
725 * @match_names: If a match set is to be a synthetic field, it has a name
726 * @start_match: list of keys in the start event that matches end event
727 * @end_match: list of keys in the end event that matches the start event
728 * @compare_names: The synthetic field names of the compared fields
729 * @start_compare: A list of compare fields in the start to compare to end
730 * @end_compare: A list of compare fields in the end to compare to start
731 * @compare_ops: The type of operations to perform between the start and end
732 * @start_names: The fields in the start event to record
733 * @end_names: The fields in the end event to record
734 * @start_filters: The fields in the end event to record
735 * @end_filters: The fields in the end event to record
736 * @start_parens: Current parenthesis level for start event
737 * @end_parens: Current parenthesis level for end event
738 * @new_format: onmatch().trace(synth_event,..) or onmatch().synth_event(...)
739 */
740 struct tracefs_synth {
741 struct tracefs_instance *instance;
742 struct tep_handle *tep;
743 struct tep_event *start_event;
744 struct tep_event *end_event;
745 struct action *actions;
746 struct action **next_action;
747 struct tracefs_dynevent *dyn_event;
748 struct name_hash *name_hash[1 << HASH_BITS];
749 char *start_hist;
750 char *end_hist;
751 char *name;
752 char **synthetic_fields;
753 char **synthetic_args;
754 char **start_selection;
755 char **start_keys;
756 char **end_keys;
757 char **start_vars;
758 char **end_vars;
759 char *start_filter;
760 char *end_filter;
761 unsigned int start_parens;
762 unsigned int start_state;
763 unsigned int end_parens;
764 unsigned int end_state;
765 int *start_type;
766 char arg_name[16];
767 int arg_cnt;
768 bool new_format;
769 };
770
771 /*
772 * tracefs_synth_get_name - get the name of the synthetic event
773 * @synth: The synthetic event to get the name for
774 *
775 * Returns name string owned by @synth on success, or NULL on error.
776 */
tracefs_synth_get_name(struct tracefs_synth * synth)777 const char *tracefs_synth_get_name(struct tracefs_synth *synth)
778 {
779 return synth ? synth->name : NULL;
780 }
781
action_free(struct action * action)782 static void action_free(struct action *action)
783 {
784 free(action->handle_field);
785 free(action->save);
786 free(action);
787 }
788
free_name_hash(struct name_hash ** hash)789 static void free_name_hash(struct name_hash **hash)
790 {
791 struct name_hash *item;
792 int i;
793
794 for (i = 0; i < 1 << HASH_BITS; i++) {
795 while ((item = hash[i])) {
796 hash[i] = item->next;
797 free(item->name);
798 free(item->hash);
799 free(item);
800 }
801 }
802 }
803
804 /**
805 * tracefs_synth_free - free the resources alloced to a synth
806 * @synth: The tracefs_synth descriptor
807 *
808 * Frees the resources allocated for a @synth created with
809 * tracefs_synth_alloc(). It does not touch the system. That is,
810 * any synthetic event created, will not be destroyed by this
811 * function.
812 */
tracefs_synth_free(struct tracefs_synth * synth)813 void tracefs_synth_free(struct tracefs_synth *synth)
814 {
815 struct action *action;
816
817 if (!synth)
818 return;
819
820 free(synth->name);
821 free(synth->start_hist);
822 free(synth->end_hist);
823 tracefs_list_free(synth->synthetic_fields);
824 tracefs_list_free(synth->synthetic_args);
825 tracefs_list_free(synth->start_selection);
826 tracefs_list_free(synth->start_keys);
827 tracefs_list_free(synth->end_keys);
828 tracefs_list_free(synth->start_vars);
829 tracefs_list_free(synth->end_vars);
830 free_name_hash(synth->name_hash);
831 free(synth->start_filter);
832 free(synth->end_filter);
833 free(synth->start_type);
834
835 tep_unref(synth->tep);
836
837 while ((action = synth->actions)) {
838 synth->actions = action->next;
839 action_free(action);
840 }
841 tracefs_dynevent_free(synth->dyn_event);
842
843 free(synth);
844 }
845
verify_event_fields(struct tep_event * start_event,struct tep_event * end_event,const char * start_field_name,const char * end_field_name,const struct tep_format_field ** ptr_start_field)846 static bool verify_event_fields(struct tep_event *start_event,
847 struct tep_event *end_event,
848 const char *start_field_name,
849 const char *end_field_name,
850 const struct tep_format_field **ptr_start_field)
851 {
852 const struct tep_format_field *start_field;
853 const struct tep_format_field *end_field;
854 int start_flags, end_flags;
855
856 if (!trace_verify_event_field(start_event, start_field_name,
857 &start_field))
858 return false;
859
860 if (end_event) {
861 if (!trace_verify_event_field(end_event, end_field_name,
862 &end_field))
863 return false;
864
865 /* A pointer can still match a long */
866 start_flags = start_field->flags & ~TEP_FIELD_IS_POINTER;
867 end_flags = end_field->flags & ~TEP_FIELD_IS_POINTER;
868
869 if (start_flags != end_flags ||
870 start_field->size != end_field->size) {
871 errno = EBADE;
872 return false;
873 }
874 }
875
876 if (ptr_start_field)
877 *ptr_start_field = start_field;
878
879 return true;
880 }
881
append_string(char * str,const char * space,const char * add)882 __hidden char *append_string(char *str, const char *space, const char *add)
883 {
884 char *new;
885 int len;
886
887 /* String must already be allocated */
888 if (!str)
889 return NULL;
890
891 len = strlen(str) + strlen(add) + 2;
892 if (space)
893 len += strlen(space);
894
895 new = realloc(str, len);
896 if (!new) {
897 free(str);
898 return NULL;
899 }
900 str = new;
901
902 if (space)
903 strcat(str, space);
904 strcat(str, add);
905
906 return str;
907 }
908
add_synth_field(const struct tep_format_field * field,const char * name)909 static char *add_synth_field(const struct tep_format_field *field,
910 const char *name)
911 {
912 const char *type;
913 char size[64];
914 char *str;
915 bool sign;
916
917 if (field->flags & TEP_FIELD_IS_ARRAY) {
918 str = strdup("char");
919 str = append_string(str, " ", name);
920 str = append_string(str, NULL, "[");
921
922 if (!(field->flags & TEP_FIELD_IS_DYNAMIC)) {
923 snprintf(size, 64, "%d", field->size);
924 str = append_string(str, NULL, size);
925 }
926 return append_string(str, NULL, "];");
927 }
928
929 /* Synthetic events understand pid_t, gfp_t and bool */
930 if (strcmp(field->type, "pid_t") == 0 ||
931 strcmp(field->type, "gfp_t") == 0 ||
932 strcmp(field->type, "bool") == 0) {
933 str = strdup(field->type);
934 str = append_string(str, " ", name);
935 return append_string(str, NULL, ";");
936 }
937
938 sign = field->flags & TEP_FIELD_IS_SIGNED;
939
940 switch (field->size) {
941 case 1:
942 if (!sign)
943 type = "unsigned char";
944 else
945 type = "char";
946 break;
947 case 2:
948 if (sign)
949 type = "s16";
950 else
951 type = "u16";
952 break;
953 case 4:
954 if (sign)
955 type = "s32";
956 else
957 type = "u32";
958 break;
959 case 8:
960 if (sign)
961 type = "s64";
962 else
963 type = "u64";
964 break;
965 default:
966 errno = EBADF;
967 return NULL;
968 }
969
970 str = strdup(type);
971 str = append_string(str, " ", name);
972 return append_string(str, NULL, ";");
973 }
974
add_var(char *** list,const char * name,const char * var,bool is_var)975 static int add_var(char ***list, const char *name, const char *var, bool is_var)
976 {
977 char **new;
978 char *assign;
979 int ret;
980
981 if (is_var)
982 ret = asprintf(&assign, "%s=$%s", name, var);
983 else
984 ret = asprintf(&assign, "%s=%s", name, var);
985
986 if (ret < 0)
987 return -1;
988
989 new = tracefs_list_add(*list, assign);
990 free(assign);
991
992 if (!new)
993 return -1;
994 *list = new;
995 return 0;
996 }
997
998 __hidden struct tracefs_synth *
synth_init_from(struct tep_handle * tep,const char * start_system,const char * start_event_name)999 synth_init_from(struct tep_handle *tep, const char *start_system,
1000 const char *start_event_name)
1001 {
1002 struct tep_event *start_event;
1003 struct tracefs_synth *synth;
1004
1005 start_event = tep_find_event_by_name(tep, start_system,
1006 start_event_name);
1007 if (!start_event) {
1008 errno = ENODEV;
1009 return NULL;
1010 }
1011
1012 synth = calloc(1, sizeof(*synth));
1013 if (!synth)
1014 return NULL;
1015
1016 synth->start_event = start_event;
1017 synth->next_action = &synth->actions;
1018
1019 /* Hold onto a reference to this handler */
1020 tep_ref(tep);
1021 synth->tep = tep;
1022
1023 return synth;
1024 }
1025
alloc_synthetic_event(struct tracefs_synth * synth)1026 static int alloc_synthetic_event(struct tracefs_synth *synth)
1027 {
1028 char *format;
1029 const char *field;
1030 int i;
1031
1032 format = strdup("");
1033 if (!format)
1034 return -1;
1035
1036 for (i = 0; synth->synthetic_fields && synth->synthetic_fields[i]; i++) {
1037 field = synth->synthetic_fields[i];
1038 format = append_string(format, i ? " " : NULL, field);
1039 }
1040
1041 synth->dyn_event = dynevent_alloc(TRACEFS_DYNEVENT_SYNTH, SYNTHETIC_GROUP,
1042 synth->name, NULL, format);
1043 free(format);
1044
1045 return synth->dyn_event ? 0 : -1;
1046 }
1047
1048 /*
1049 * See if it is onmatch().trace(synth_event,...) or
1050 * onmatch().synth_event(...)
1051 */
has_new_format()1052 static bool has_new_format()
1053 {
1054 char *readme;
1055 char *p;
1056 int size;
1057
1058 readme = tracefs_instance_file_read(NULL, "README", &size);
1059 if (!readme)
1060 return false;
1061
1062 p = strstr(readme, "trace(<synthetic_event>,param list)");
1063 free(readme);
1064
1065 return p != NULL;
1066 }
1067
1068 /**
1069 * tracefs_synth_alloc - create a new tracefs_synth instance
1070 * @tep: The tep handle that holds the events to work on
1071 * @name: The name of the synthetic event being created
1072 * @start_system: The name of the system of the start event (can be NULL)
1073 * @start_event_name: The name of the start event
1074 * @end_system: The name of the system of the end event (can be NULL)
1075 * @end_event_name: The name of the end event
1076 * @start_match_field: The name of the field in start event to match @end_match_field
1077 * @end_match_field: The name of the field in end event to match @start_match_field
1078 * @match_name: Name to call the fields that match (can be NULL)
1079 *
1080 * Creates a tracefs_synth instance that has the minimum requirements to
1081 * create a synthetic event.
1082 *
1083 * @name is will be the name of the synthetic event that this can create.
1084 *
1085 * The start event is found with @start_system and @start_event_name. If
1086 * @start_system is NULL, then the first event with @start_event_name will
1087 * be used.
1088 *
1089 * The end event is found with @end_system and @end_event_name. If
1090 * @end_system is NULL, then the first event with @end_event_name will
1091 * be used.
1092 *
1093 * The @start_match_field is the field in the start event that will be used
1094 * to match the @end_match_field of the end event.
1095 *
1096 * If @match_name is given, then the field that matched the start and
1097 * end events will be passed an a field to the sythetic event with this
1098 * as the field name.
1099 *
1100 * Returns an allocated tracefs_synth descriptor on success and NULL
1101 * on error, with the following set in errno.
1102 *
1103 * ENOMEM - memory allocation failure.
1104 * ENIVAL - a parameter is passed as NULL that should not be
1105 * ENODEV - could not find an event or field
1106 * EBADE - The start and end fields are not compatible to match
1107 *
1108 * Note, this does not modify the system. That is, the synthetic
1109 * event on the system is not created. That needs to be done with
1110 * tracefs_synth_create().
1111 */
tracefs_synth_alloc(struct tep_handle * tep,const char * name,const char * start_system,const char * start_event_name,const char * end_system,const char * end_event_name,const char * start_match_field,const char * end_match_field,const char * match_name)1112 struct tracefs_synth *tracefs_synth_alloc(struct tep_handle *tep,
1113 const char *name,
1114 const char *start_system,
1115 const char *start_event_name,
1116 const char *end_system,
1117 const char *end_event_name,
1118 const char *start_match_field,
1119 const char *end_match_field,
1120 const char *match_name)
1121 {
1122 struct tep_event *end_event;
1123 struct tracefs_synth *synth;
1124 int ret = 0;
1125
1126 if (!tep || !name || !start_event_name || !end_event_name ||
1127 !start_match_field || !end_match_field) {
1128 errno = EINVAL;
1129 return NULL;
1130 }
1131
1132 synth = synth_init_from(tep, start_system, start_event_name);
1133 if (!synth)
1134 return NULL;
1135
1136 end_event = tep_find_event_by_name(tep, end_system,
1137 end_event_name);
1138 if (!end_event) {
1139 tep_unref(tep);
1140 errno = ENODEV;
1141 return NULL;
1142 }
1143
1144 synth->end_event = end_event;
1145
1146 synth->name = strdup(name);
1147
1148 ret = tracefs_synth_add_match_field(synth, start_match_field,
1149 end_match_field, match_name);
1150
1151 if (!synth->name || !synth->start_keys || !synth->end_keys || ret) {
1152 tracefs_synth_free(synth);
1153 synth = NULL;
1154 } else
1155 synth->new_format = has_new_format();
1156
1157 return synth;
1158 }
1159
add_synth_fields(struct tracefs_synth * synth,const struct tep_format_field * field,const char * name,const char * var)1160 static int add_synth_fields(struct tracefs_synth *synth,
1161 const struct tep_format_field *field,
1162 const char *name, const char *var)
1163 {
1164 char **list;
1165 char *str;
1166 int ret;
1167
1168 str = add_synth_field(field, name ? : field->name);
1169 if (!str)
1170 return -1;
1171
1172 if (!name)
1173 name = var;
1174
1175 list = tracefs_list_add(synth->synthetic_fields, str);
1176 free(str);
1177 if (!list)
1178 return -1;
1179 synth->synthetic_fields = list;
1180
1181 ret = asprintf(&str, "$%s", var ? : name);
1182 if (ret < 0) {
1183 trace_list_pop(synth->synthetic_fields);
1184 return -1;
1185 }
1186
1187 list = tracefs_list_add(synth->synthetic_args, str);
1188 free(str);
1189 if (!list) {
1190 trace_list_pop(synth->synthetic_fields);
1191 return -1;
1192 }
1193
1194 synth->synthetic_args = list;
1195
1196 return 0;
1197 }
1198
1199 /**
1200 * tracefs_synth_add_match_field - add another key to match events
1201 * @synth: The tracefs_synth descriptor
1202 * @start_match_field: The field of the start event to match the end event
1203 * @end_match_field: The field of the end event to match the start event
1204 * @name: The name to show in the synthetic event (NULL is allowed)
1205 *
1206 * This will add another set of keys to use for a match between
1207 * the start event and the end event.
1208 *
1209 * Returns 0 on succes and -1 on error.
1210 * On error, errno is set to:
1211 * ENOMEM - memory allocation failure.
1212 * ENIVAL - a parameter is passed as NULL that should not be
1213 * ENODEV - could not find a field
1214 * EBADE - The start and end fields are not compatible to match
1215 */
tracefs_synth_add_match_field(struct tracefs_synth * synth,const char * start_match_field,const char * end_match_field,const char * name)1216 int tracefs_synth_add_match_field(struct tracefs_synth *synth,
1217 const char *start_match_field,
1218 const char *end_match_field,
1219 const char *name)
1220 {
1221 const struct tep_format_field *key_field;
1222 char **list;
1223 int ret;
1224
1225 if (!synth || !start_match_field || !end_match_field) {
1226 errno = EINVAL;
1227 return -1;
1228 }
1229
1230 if (!verify_event_fields(synth->start_event, synth->end_event,
1231 start_match_field, end_match_field,
1232 &key_field))
1233 return -1;
1234
1235 list = tracefs_list_add(synth->start_keys, start_match_field);
1236 if (!list)
1237 return -1;
1238
1239 synth->start_keys = list;
1240
1241 list = tracefs_list_add(synth->end_keys, end_match_field);
1242 if (!list) {
1243 trace_list_pop(synth->start_keys);
1244 return -1;
1245 }
1246 synth->end_keys = list;
1247
1248 if (!name)
1249 return 0;
1250
1251 ret = add_var(&synth->end_vars, name, end_match_field, false);
1252
1253 if (ret < 0)
1254 goto pop_lists;
1255
1256 ret = add_synth_fields(synth, key_field, name, NULL);
1257 if (ret < 0)
1258 goto pop_lists;
1259
1260 return 0;
1261
1262 pop_lists:
1263 trace_list_pop(synth->start_keys);
1264 trace_list_pop(synth->end_keys);
1265 return -1;
1266 }
1267
make_rand(void)1268 static unsigned int make_rand(void)
1269 {
1270 struct timeval tv;
1271 unsigned long seed;
1272
1273 gettimeofday(&tv, NULL);
1274 seed = (tv.tv_sec + tv.tv_usec) + getpid();
1275
1276 /* taken from the rand(3) man page */
1277 seed = seed * 1103515245 + 12345;
1278 return((unsigned)(seed/65536) % 32768);
1279 }
1280
new_name(struct tracefs_synth * synth,const char * name)1281 static char *new_name(struct tracefs_synth *synth, const char *name)
1282 {
1283 int cnt = synth->arg_cnt + 1;
1284 char *arg;
1285 int ret;
1286
1287 /* Create a unique argument name */
1288 if (!synth->arg_name[0]) {
1289 /* make_rand() returns at most 32768 (total 13 bytes in use) */
1290 sprintf(synth->arg_name, "%u", make_rand());
1291 }
1292 ret = asprintf(&arg, "__%s_%s_%d", name, synth->arg_name, cnt);
1293 if (ret < 0)
1294 return NULL;
1295
1296 synth->arg_cnt = cnt;
1297 return arg;
1298 }
1299
find_name(struct tracefs_synth * synth,const char * name)1300 static struct name_hash *find_name(struct tracefs_synth *synth, const char *name)
1301 {
1302 unsigned int key = quick_hash(name);
1303 struct name_hash *hash = synth->name_hash[key];
1304
1305 for (; hash; hash = hash->next) {
1306 if (!strcmp(hash->name, name))
1307 return hash;
1308 }
1309 return NULL;
1310 }
1311
hash_name(struct tracefs_synth * synth,const char * name)1312 static const char *hash_name(struct tracefs_synth *synth, const char *name)
1313 {
1314 struct name_hash *hash;
1315 int key;
1316
1317 hash = find_name(synth, name);
1318 if (hash)
1319 return hash->hash;
1320
1321 hash = malloc(sizeof(*hash));
1322 if (!hash)
1323 return name;
1324
1325 hash->hash = new_name(synth, name);
1326 if (!hash->hash) {
1327 free(hash);
1328 return name;
1329 }
1330
1331 key = quick_hash(name);
1332 hash->next = synth->name_hash[key];
1333 synth->name_hash[key] = hash;
1334
1335 hash->name = strdup(name);
1336 if (!hash->name) {
1337 free(hash->hash);
1338 free(hash);
1339 return name;
1340 }
1341 return hash->hash;
1342 }
1343
new_arg(struct tracefs_synth * synth)1344 static char *new_arg(struct tracefs_synth *synth)
1345 {
1346 return new_name(synth, "arg");
1347 }
1348
1349 /**
1350 * tracefs_synth_add_compare_field - add a comparison between start and end
1351 * @synth: The tracefs_synth descriptor
1352 * @start_compare_field: The field of the start event to compare to the end
1353 * @end_compare_field: The field of the end event to compare to the start
1354 * @calc - How to go about the comparing the fields.
1355 * @name: The name to show in the synthetic event (must NOT be NULL)
1356 *
1357 * This will add a way to compare two different fields between the
1358 * start end end events.
1359 *
1360 * The comparing between events is decided by @calc:
1361 * TRACEFS_SYNTH_DELTA_END - name = end - start
1362 * TRACEFS_SYNTH_DELTA_START - name = start - end
1363 * TRACEFS_SYNTH_ADD - name = end + start
1364 *
1365 * Returns 0 on succes and -1 on error.
1366 * On error, errno is set to:
1367 * ENOMEM - memory allocation failure.
1368 * ENIVAL - a parameter is passed as NULL that should not be
1369 * ENODEV - could not find a field
1370 * EBADE - The start and end fields are not compatible to compare
1371 */
tracefs_synth_add_compare_field(struct tracefs_synth * synth,const char * start_compare_field,const char * end_compare_field,enum tracefs_synth_calc calc,const char * name)1372 int tracefs_synth_add_compare_field(struct tracefs_synth *synth,
1373 const char *start_compare_field,
1374 const char *end_compare_field,
1375 enum tracefs_synth_calc calc,
1376 const char *name)
1377 {
1378 const struct tep_format_field *start_field;
1379 const char *hname;
1380 char *start_arg;
1381 char *compare;
1382 int ret;
1383
1384 /* Compare fields require a name */
1385 if (!name || !start_compare_field || !end_compare_field) {
1386 errno = -EINVAL;
1387 return -1;
1388 }
1389
1390 if (!verify_event_fields(synth->start_event, synth->end_event,
1391 start_compare_field, end_compare_field,
1392 &start_field))
1393 return -1;
1394
1395 /* Calculations are not allowed on string */
1396 if (start_field->flags & (TEP_FIELD_IS_ARRAY |
1397 TEP_FIELD_IS_DYNAMIC)) {
1398 errno = -EINVAL;
1399 return -1;
1400 }
1401
1402 start_arg = new_arg(synth);
1403 if (!start_arg)
1404 return -1;
1405
1406 ret = add_var(&synth->start_vars, start_arg, start_compare_field, false);
1407 if (ret < 0) {
1408 free(start_arg);
1409 return -1;
1410 }
1411
1412 ret = -1;
1413 switch (calc) {
1414 case TRACEFS_SYNTH_DELTA_END:
1415 ret = asprintf(&compare, "%s-$%s", end_compare_field,
1416 start_arg);
1417 break;
1418 case TRACEFS_SYNTH_DELTA_START:
1419 ret = asprintf(&compare, "$%s-%s", start_arg,
1420 end_compare_field);
1421 break;
1422 case TRACEFS_SYNTH_ADD:
1423 ret = asprintf(&compare, "%s+$%s", end_compare_field,
1424 start_arg);
1425 break;
1426 }
1427 free(start_arg);
1428 if (ret < 0)
1429 return -1;
1430
1431 hname = hash_name(synth, name);
1432 ret = add_var(&synth->end_vars, hname, compare, false);
1433 if (ret < 0)
1434 goto out_free;
1435
1436 ret = add_synth_fields(synth, start_field, name, hname);
1437 if (ret < 0)
1438 goto out_free;
1439
1440 out_free:
1441 free(compare);
1442
1443 return ret ? -1 : 0;
1444 }
1445
synth_add_start_field(struct tracefs_synth * synth,const char * start_field,const char * name,enum tracefs_hist_key_type type,int count)1446 __hidden int synth_add_start_field(struct tracefs_synth *synth,
1447 const char *start_field,
1448 const char *name,
1449 enum tracefs_hist_key_type type, int count)
1450 {
1451 const struct tep_format_field *field;
1452 const char *var;
1453 char *start_arg;
1454 char **tmp;
1455 int *types;
1456 int len;
1457 int ret;
1458
1459 if (!synth || !start_field) {
1460 errno = EINVAL;
1461 return -1;
1462 }
1463
1464 if (!name)
1465 name = start_field;
1466
1467 var = hash_name(synth, name);
1468
1469 if (!trace_verify_event_field(synth->start_event, start_field, &field))
1470 return -1;
1471
1472 start_arg = new_arg(synth);
1473 if (!start_arg)
1474 return -1;
1475
1476 ret = add_var(&synth->start_vars, start_arg, start_field, false);
1477 if (ret)
1478 goto out_free;
1479
1480 ret = add_var(&synth->end_vars, var, start_arg, true);
1481 if (ret)
1482 goto out_free;
1483
1484 ret = add_synth_fields(synth, field, name, var);
1485 if (ret)
1486 goto out_free;
1487
1488 tmp = tracefs_list_add(synth->start_selection, start_field);
1489 if (!tmp) {
1490 ret = -1;
1491 goto out_free;
1492 }
1493 synth->start_selection = tmp;
1494
1495 len = tracefs_list_size(tmp);
1496 if (len <= 0) { /* ?? */
1497 ret = -1;
1498 goto out_free;
1499 }
1500
1501 types = realloc(synth->start_type, sizeof(*types) * len);
1502 if (!types) {
1503 ret = -1;
1504 goto out_free;
1505 }
1506 synth->start_type = types;
1507 synth->start_type[len - 1] = type;
1508
1509 out_free:
1510 free(start_arg);
1511 return ret;
1512 }
1513
1514 /**
1515 * tracefs_synth_add_start_field - add a start field to save
1516 * @synth: The tracefs_synth descriptor
1517 * @start_field: The field of the start event to save
1518 * @name: The name to show in the synthetic event (if NULL @start_field is used)
1519 *
1520 * This adds a field named by @start_field of the start event to
1521 * record in the synthetic event.
1522 *
1523 * Returns 0 on succes and -1 on error.
1524 * On error, errno is set to:
1525 * ENOMEM - memory allocation failure.
1526 * ENIVAL - a parameter is passed as NULL that should not be
1527 * ENODEV - could not find a field
1528 */
tracefs_synth_add_start_field(struct tracefs_synth * synth,const char * start_field,const char * name)1529 int tracefs_synth_add_start_field(struct tracefs_synth *synth,
1530 const char *start_field,
1531 const char *name)
1532 {
1533 return synth_add_start_field(synth, start_field, name, 0, 0);
1534 }
1535
1536 /**
1537 * tracefs_synth_add_end_field - add a end field to save
1538 * @synth: The tracefs_synth descriptor
1539 * @end_field: The field of the end event to save
1540 * @name: The name to show in the synthetic event (if NULL @end_field is used)
1541 *
1542 * This adds a field named by @end_field of the start event to
1543 * record in the synthetic event.
1544 *
1545 * Returns 0 on succes and -1 on error.
1546 * On error, errno is set to:
1547 * ENOMEM - memory allocation failure.
1548 * ENIVAL - a parameter is passed as NULL that should not be
1549 * ENODEV - could not find a field
1550 */
tracefs_synth_add_end_field(struct tracefs_synth * synth,const char * end_field,const char * name)1551 int tracefs_synth_add_end_field(struct tracefs_synth *synth,
1552 const char *end_field,
1553 const char *name)
1554 {
1555 const struct tep_format_field *field;
1556 const char *hname = NULL;
1557 char *tmp_var = NULL;
1558 int ret;
1559
1560 if (!synth || !end_field) {
1561 errno = EINVAL;
1562 return -1;
1563 }
1564
1565 if (name) {
1566 if (strncmp(name, "__arg", 5) != 0)
1567 hname = hash_name(synth, name);
1568 else
1569 hname = name;
1570 }
1571
1572 if (!name)
1573 tmp_var = new_arg(synth);
1574
1575 if (!trace_verify_event_field(synth->end_event, end_field, &field))
1576 return -1;
1577
1578 ret = add_var(&synth->end_vars, name ? hname : tmp_var, end_field, false);
1579 if (ret)
1580 goto out;
1581
1582 ret = add_synth_fields(synth, field, name, hname ? : tmp_var);
1583 free(tmp_var);
1584 out:
1585 return ret;
1586 }
1587
1588 /**
1589 * tracefs_synth_append_start_filter - create or append a filter
1590 * @synth: The tracefs_synth descriptor
1591 * @type: The type of element to add to the filter
1592 * @field: For @type == TRACEFS_FILTER_COMPARE, the field to compare
1593 * @compare: For @type == TRACEFS_FILTER_COMPARE, how to compare @field to @val
1594 * @val: For @type == TRACEFS_FILTER_COMPARE, what value @field is to be
1595 *
1596 * This will put together a filter string for the starting event
1597 * of @synth. It check to make sure that what is added is correct compared
1598 * to the filter that is already built.
1599 *
1600 * @type can be:
1601 * TRACEFS_FILTER_COMPARE: See below
1602 * TRACEFS_FILTER_AND: Append "&&" to the filter
1603 * TRACEFS_FILTER_OR: Append "||" to the filter
1604 * TRACEFS_FILTER_NOT: Append "!" to the filter
1605 * TRACEFS_FILTER_OPEN_PAREN: Append "(" to the filter
1606 * TRACEFS_FILTER_CLOSE_PAREN: Append ")" to the filter
1607 *
1608 * For all types except TRACEFS_FILTER_COMPARE, the @field, @compare,
1609 * and @val are ignored.
1610 *
1611 * For @type == TRACEFS_FILTER_COMPARE.
1612 *
1613 * @field is the name of the field for the start event to compare.
1614 * If it is not a field for the start event, this return an
1615 * error.
1616 *
1617 * @compare can be one of:
1618 * TRACEFS_COMPARE_EQ: Test @field == @val
1619 * TRACEFS_COMPARE_NE: Test @field != @val
1620 * TRACEFS_COMPARE_GT: Test @field > @val
1621 * TRACEFS_COMPARE_GE: Test @field >= @val
1622 * TRACEFS_COMPARE_LT: Test @field < @val
1623 * TRACEFS_COMPARE_LE: Test @field <= @val
1624 * TRACEFS_COMPARE_RE: Test @field ~ @val
1625 * TRACEFS_COMPARE_AND: Test @field & @val
1626 *
1627 * If the @field is of type string, and @compare is not
1628 * TRACEFS_COMPARE_EQ, TRACEFS_COMPARE_NE or TRACEFS_COMPARE_RE,
1629 * then this will return an error.
1630 *
1631 * Various other checks are made, for instance, if more CLOSE_PARENs
1632 * are added than existing OPEN_PARENs. Or if AND is added after an
1633 * OPEN_PAREN or another AND or an OR or a NOT.
1634 *
1635 * Returns 0 on success and -1 on failure.
1636 */
tracefs_synth_append_start_filter(struct tracefs_synth * synth,enum tracefs_filter type,const char * field,enum tracefs_compare compare,const char * val)1637 int tracefs_synth_append_start_filter(struct tracefs_synth *synth,
1638 enum tracefs_filter type,
1639 const char *field,
1640 enum tracefs_compare compare,
1641 const char *val)
1642 {
1643 return trace_append_filter(&synth->start_filter, &synth->start_state,
1644 &synth->start_parens,
1645 synth->start_event,
1646 type, field, compare, val);
1647 }
1648
1649 /**
1650 * tracefs_synth_append_end_filter - create or append a filter
1651 * @synth: The tracefs_synth descriptor
1652 * @type: The type of element to add to the filter
1653 * @field: For @type == TRACEFS_FILTER_COMPARE, the field to compare
1654 * @compare: For @type == TRACEFS_FILTER_COMPARE, how to compare @field to @val
1655 * @val: For @type == TRACEFS_FILTER_COMPARE, what value @field is to be
1656 *
1657 * Performs the same thing as tracefs_synth_append_start_filter() but
1658 * for the @synth end event.
1659 */
tracefs_synth_append_end_filter(struct tracefs_synth * synth,enum tracefs_filter type,const char * field,enum tracefs_compare compare,const char * val)1660 int tracefs_synth_append_end_filter(struct tracefs_synth *synth,
1661 enum tracefs_filter type,
1662 const char *field,
1663 enum tracefs_compare compare,
1664 const char *val)
1665 {
1666 return trace_append_filter(&synth->end_filter, &synth->end_state,
1667 &synth->end_parens,
1668 synth->end_event,
1669 type, field, compare, val);
1670 }
1671
test_max_var(struct tracefs_synth * synth,const char * var)1672 static int test_max_var(struct tracefs_synth *synth, const char *var)
1673 {
1674 char **vars = synth->end_vars;
1675 char *p;
1676 int len;
1677 int i;
1678
1679 len = strlen(var);
1680
1681 /* Make sure the var is defined for the end event */
1682 for (i = 0; vars[i]; i++) {
1683 p = strchr(vars[i], '=');
1684 if (!p)
1685 continue;
1686 if (p - vars[i] != len)
1687 continue;
1688 if (!strncmp(var, vars[i], len))
1689 return 0;
1690 }
1691 errno = ENODEV;
1692 return -1;
1693 }
1694
create_action(enum tracefs_synth_handler type,struct tracefs_synth * synth,const char * var)1695 static struct action *create_action(enum tracefs_synth_handler type,
1696 struct tracefs_synth *synth,
1697 const char *var)
1698 {
1699 struct action *action;
1700 int ret;
1701
1702 switch (type) {
1703 case TRACEFS_SYNTH_HANDLE_MAX:
1704 case TRACEFS_SYNTH_HANDLE_CHANGE:
1705 ret = test_max_var(synth, var);
1706 if (ret < 0)
1707 return NULL;
1708 break;
1709 default:
1710 break;
1711 }
1712
1713 action = calloc(1, sizeof(*action));
1714 if (!action)
1715 return NULL;
1716
1717 if (var) {
1718 ret = asprintf(&action->handle_field, "$%s", var);
1719 if (!action->handle_field) {
1720 free(action);
1721 return NULL;
1722 }
1723 }
1724 return action;
1725 }
1726
add_action(struct tracefs_synth * synth,struct action * action)1727 static void add_action(struct tracefs_synth *synth, struct action *action)
1728 {
1729 *synth->next_action = action;
1730 synth->next_action = &action->next;
1731 }
1732
1733 /**
1734 * tracefs_synth_trace - Execute the trace option
1735 * @synth: The tracefs_synth descriptor
1736 * @type: The type of handler to attach the trace action with
1737 * @field: The field for handlers onmax and onchange (ignored otherwise)
1738 *
1739 * Add the action 'trace' for handlers onmatch, onmax and onchange.
1740 *
1741 * Returns 0 on succes, -1 on error.
1742 */
tracefs_synth_trace(struct tracefs_synth * synth,enum tracefs_synth_handler type,const char * field)1743 int tracefs_synth_trace(struct tracefs_synth *synth,
1744 enum tracefs_synth_handler type, const char *field)
1745 {
1746 struct action *action;
1747
1748 if (!synth || (!field && (type != TRACEFS_SYNTH_HANDLE_MATCH))) {
1749 errno = EINVAL;
1750 return -1;
1751 }
1752
1753 action = create_action(type, synth, field);
1754 if (!action)
1755 return -1;
1756
1757 action->type = ACTION_TRACE;
1758 action->handler = type;
1759 add_action(synth, action);
1760 return 0;
1761 }
1762
1763 /**
1764 * tracefs_synth_snapshot - create a snapshot command to the histogram
1765 * @synth: The tracefs_synth descriptor
1766 * @type: The type of handler to attach the snapshot action with
1767 * @field: The field for handlers onmax and onchange
1768 *
1769 * Add the action to do a snapshot for handlers onmax and onchange.
1770 *
1771 * Returns 0 on succes, -1 on error.
1772 */
tracefs_synth_snapshot(struct tracefs_synth * synth,enum tracefs_synth_handler type,const char * field)1773 int tracefs_synth_snapshot(struct tracefs_synth *synth,
1774 enum tracefs_synth_handler type, const char *field)
1775 {
1776 struct action *action;
1777
1778 if (!synth || !field || (type == TRACEFS_SYNTH_HANDLE_MATCH)) {
1779 errno = EINVAL;
1780 return -1;
1781 }
1782
1783 action = create_action(type, synth, field);
1784 if (!action)
1785 return -1;
1786
1787 action->type = ACTION_SNAPSHOT;
1788 action->handler = type;
1789 add_action(synth, action);
1790 return 0;
1791 }
1792
1793 /**
1794 * tracefs_synth_save - create a save command to the histogram
1795 * @synth: The tracefs_synth descriptor
1796 * @type: The type of handler to attach the save action
1797 * @max_field: The field for handlers onmax and onchange
1798 * @fields: The fields to save for the end variable
1799 *
1800 * Add the action to save fields for handlers onmax and onchange.
1801 *
1802 * Returns 0 on succes, -1 on error.
1803 */
tracefs_synth_save(struct tracefs_synth * synth,enum tracefs_synth_handler type,const char * max_field,char ** fields)1804 int tracefs_synth_save(struct tracefs_synth *synth,
1805 enum tracefs_synth_handler type, const char *max_field,
1806 char **fields)
1807 {
1808 struct action *action;
1809 char *save;
1810 int i;
1811
1812 if (!synth || !max_field || (type == TRACEFS_SYNTH_HANDLE_MATCH)) {
1813 errno = EINVAL;
1814 return -1;
1815 }
1816
1817 action = create_action(type, synth, max_field);
1818 if (!action)
1819 return -1;
1820
1821 action->type = ACTION_SAVE;
1822 action->handler = type;
1823 *synth->next_action = action;
1824 synth->next_action = &action->next;
1825
1826 save = strdup(".save(");
1827 if (!save)
1828 goto error;
1829
1830 for (i = 0; fields[i]; i++) {
1831 char *delim = i ? "," : NULL;
1832
1833 if (!trace_verify_event_field(synth->end_event, fields[i], NULL))
1834 goto error;
1835 save = append_string(save, delim, fields[i]);
1836 }
1837 save = append_string(save, NULL, ")");
1838 if (!save)
1839 goto error;
1840
1841 action->save = save;
1842 add_action(synth, action);
1843 return 0;
1844 error:
1845 action_free(action);
1846 free(save);
1847 return -1;
1848 return 0;
1849 }
1850
remove_hist(struct tracefs_instance * instance,struct tep_event * event,const char * hist)1851 static int remove_hist(struct tracefs_instance *instance,
1852 struct tep_event *event, const char *hist)
1853 {
1854 char *str;
1855 int ret;
1856
1857 ret = asprintf(&str, "!%s", hist);
1858 if (ret < 0)
1859 return -1;
1860
1861 ret = tracefs_event_file_append(instance, event->system, event->name,
1862 "trigger", str);
1863 free(str);
1864 return ret < 0 ? -1 : 0;
1865 }
1866
create_hist(char ** keys,char ** vars)1867 static char *create_hist(char **keys, char **vars)
1868 {
1869 char *hist = strdup("hist:keys=");
1870 char *name;
1871 int i;
1872
1873 if (!hist)
1874 return NULL;
1875
1876 for (i = 0; keys[i]; i++) {
1877 name = keys[i];
1878 if (i)
1879 hist = append_string(hist, NULL, ",");
1880 hist = append_string(hist, NULL, name);
1881 }
1882
1883 if (!vars)
1884 return hist;
1885
1886 hist = append_string(hist, NULL, ":");
1887
1888 for (i = 0; vars[i]; i++) {
1889 name = vars[i];
1890 if (i)
1891 hist = append_string(hist, NULL, ",");
1892 hist = append_string(hist, NULL, name);
1893 }
1894
1895 return hist;
1896 }
1897
create_onmatch(char * hist,struct tracefs_synth * synth)1898 static char *create_onmatch(char *hist, struct tracefs_synth *synth)
1899 {
1900 hist = append_string(hist, NULL, ":onmatch(");
1901 hist = append_string(hist, NULL, synth->start_event->system);
1902 hist = append_string(hist, NULL, ".");
1903 hist = append_string(hist, NULL, synth->start_event->name);
1904 return append_string(hist, NULL, ")");
1905 }
1906
create_trace(char * hist,struct tracefs_synth * synth)1907 static char *create_trace(char *hist, struct tracefs_synth *synth)
1908 {
1909 char *name;
1910 int i;
1911
1912 if (synth->new_format) {
1913 hist = append_string(hist, NULL, ".trace(");
1914 hist = append_string(hist, NULL, synth->name);
1915 hist = append_string(hist, NULL, ",");
1916 } else {
1917 hist = append_string(hist, NULL, ".");
1918 hist = append_string(hist, NULL, synth->name);
1919 hist = append_string(hist, NULL, "(");
1920 }
1921
1922 for (i = 0; synth->synthetic_args && synth->synthetic_args[i]; i++) {
1923 name = synth->synthetic_args[i];
1924
1925 if (i)
1926 hist = append_string(hist, NULL, ",");
1927 hist = append_string(hist, NULL, name);
1928 }
1929
1930 return append_string(hist, NULL, ")");
1931 }
1932
create_max(char * hist,struct tracefs_synth * synth,char * field)1933 static char *create_max(char *hist, struct tracefs_synth *synth, char *field)
1934 {
1935 hist = append_string(hist, NULL, ":onmax(");
1936 hist = append_string(hist, NULL, field);
1937 return append_string(hist, NULL, ")");
1938 }
1939
create_change(char * hist,struct tracefs_synth * synth,char * field)1940 static char *create_change(char *hist, struct tracefs_synth *synth, char *field)
1941 {
1942 hist = append_string(hist, NULL, ":onchange(");
1943 hist = append_string(hist, NULL, field);
1944 return append_string(hist, NULL, ")");
1945 }
1946
create_actions(char * hist,struct tracefs_synth * synth)1947 static char *create_actions(char *hist, struct tracefs_synth *synth)
1948 {
1949 struct action *action;
1950
1951 if (!synth->actions) {
1952 /* Default is "onmatch" and "trace" */
1953 hist = create_onmatch(hist, synth);
1954 return create_trace(hist, synth);
1955 }
1956
1957 for (action = synth->actions; action; action = action->next) {
1958 switch (action->handler) {
1959 case TRACEFS_SYNTH_HANDLE_MATCH:
1960 hist = create_onmatch(hist, synth);
1961 break;
1962 case TRACEFS_SYNTH_HANDLE_MAX:
1963 hist = create_max(hist, synth, action->handle_field);
1964 break;
1965 case TRACEFS_SYNTH_HANDLE_CHANGE:
1966 hist = create_change(hist, synth, action->handle_field);
1967 break;
1968 default:
1969 continue;
1970 }
1971 switch (action->type) {
1972 case ACTION_TRACE:
1973 hist = create_trace(hist, synth);
1974 break;
1975 case ACTION_SNAPSHOT:
1976 hist = append_string(hist, NULL, ".snapshot()");
1977 break;
1978 case ACTION_SAVE:
1979 hist = append_string(hist, NULL, action->save);
1980 break;
1981 default:
1982 continue;
1983 }
1984 }
1985 return hist;
1986 }
1987
create_end_hist(struct tracefs_synth * synth)1988 static char *create_end_hist(struct tracefs_synth *synth)
1989 {
1990 char *end_hist;
1991
1992 end_hist = create_hist(synth->end_keys, synth->end_vars);
1993 return create_actions(end_hist, synth);
1994 }
1995
1996 /*
1997 * tracefs_synth_raw_fmt - show the raw format of a synthetic event
1998 * @seq: A trace_seq to store the format string
1999 * @synth: The synthetic event to read format from
2000 *
2001 * This shows the raw format that describes the synthetic event, including
2002 * the format of the dynamic event and the start / end histograms.
2003 *
2004 * Returns 0 on succes -1 on error.
2005 */
tracefs_synth_raw_fmt(struct trace_seq * seq,struct tracefs_synth * synth)2006 int tracefs_synth_raw_fmt(struct trace_seq *seq, struct tracefs_synth *synth)
2007 {
2008 if (!synth->dyn_event)
2009 return -1;
2010
2011 trace_seq_printf(seq, "%s", synth->dyn_event->format);
2012 trace_seq_printf(seq, "\n%s", synth->start_hist);
2013 trace_seq_printf(seq, "\n%s", synth->end_hist);
2014
2015 return 0;
2016 }
2017
2018 /*
2019 * tracefs_synth_show_event - show the dynamic event used by a synth event
2020 * @synth: The synthetic event to read format from
2021 *
2022 * This shows the raw format of the dynamic event used by the synthetic event.
2023 *
2024 * Returns format string owned by @synth on success, or NULL on error.
2025 */
tracefs_synth_show_event(struct tracefs_synth * synth)2026 const char *tracefs_synth_show_event(struct tracefs_synth *synth)
2027 {
2028 return synth->dyn_event ? synth->dyn_event->format : NULL;
2029 }
2030
2031 /*
2032 * tracefs_synth_show_start_hist - show the start histogram used by a synth event
2033 * @synth: The synthetic event to read format from
2034 *
2035 * This shows the raw format of the start histogram used by the synthetic event.
2036 *
2037 * Returns format string owned by @synth on success, or NULL on error.
2038 */
tracefs_synth_show_start_hist(struct tracefs_synth * synth)2039 const char *tracefs_synth_show_start_hist(struct tracefs_synth *synth)
2040 {
2041 return synth->start_hist;
2042 }
2043
2044 /*
2045 * tracefs_synth_show_end_hist - show the end histogram used by a synth event
2046 * @synth: The synthetic event to read format from
2047 *
2048 * This shows the raw format of the end histogram used by the synthetic event.
2049 *
2050 * Returns format string owned by @synth on success, or NULL on error.
2051 */
tracefs_synth_show_end_hist(struct tracefs_synth * synth)2052 const char *tracefs_synth_show_end_hist(struct tracefs_synth *synth)
2053 {
2054 return synth->end_hist;
2055 }
2056
append_filter(char * hist,char * filter,unsigned int parens)2057 static char *append_filter(char *hist, char *filter, unsigned int parens)
2058 {
2059 int i;
2060
2061 if (!filter)
2062 return hist;
2063
2064 hist = append_string(hist, NULL, " if ");
2065 hist = append_string(hist, NULL, filter);
2066 for (i = 0; i < parens; i++)
2067 hist = append_string(hist, NULL, ")");
2068 return hist;
2069 }
2070
verify_state(struct tracefs_synth * synth)2071 static int verify_state(struct tracefs_synth *synth)
2072 {
2073 if (trace_test_state(synth->start_state) < 0 ||
2074 trace_test_state(synth->end_state) < 0)
2075 return -1;
2076 return 0;
2077 }
2078
2079 /**
2080 * tracefs_synth_complete - tell if the tracefs_synth is complete or not
2081 * @synth: The synthetic event to get the start hist from.
2082 *
2083 * Retruns true if the synthetic event @synth has both a start and
2084 * end event (ie. a synthetic event, or just a histogram), and
2085 * false otherwise.
2086 */
tracefs_synth_complete(struct tracefs_synth * synth)2087 bool tracefs_synth_complete(struct tracefs_synth *synth)
2088 {
2089 return synth && synth->start_event && synth->end_event;
2090 }
2091
2092 /**
2093 * tracefs_synth_get_start_hist - Return the histogram of the start event
2094 * @synth: The synthetic event to get the start hist from.
2095 *
2096 * On success, returns a tracefs_hist descriptor that holds the
2097 * histogram information of the start_event of the synthetic event
2098 * structure. Returns NULL on failure.
2099 */
2100 struct tracefs_hist *
tracefs_synth_get_start_hist(struct tracefs_synth * synth)2101 tracefs_synth_get_start_hist(struct tracefs_synth *synth)
2102 {
2103 struct tracefs_hist *hist = NULL;
2104 struct tep_handle *tep;
2105 const char *system;
2106 const char *event;
2107 const char *key;
2108 char **keys;
2109 int *types;
2110 int ret;
2111 int i;
2112
2113 if (!synth) {
2114 errno = EINVAL;
2115 return NULL;
2116 }
2117
2118 system = synth->start_event->system;
2119 event = synth->start_event->name;
2120 types = synth->start_type;
2121 keys = synth->start_keys;
2122 tep = synth->tep;
2123
2124 if (!keys)
2125 keys = synth->start_selection;
2126
2127 if (!keys)
2128 return NULL;
2129
2130 for (i = 0; keys[i]; i++) {
2131 int type = types ? types[i] : 0;
2132
2133 if (type == HIST_COUNTER_TYPE)
2134 continue;
2135
2136 key = keys[i];
2137
2138 if (i) {
2139 ret = tracefs_hist_add_key(hist, key, type);
2140 if (ret < 0) {
2141 tracefs_hist_free(hist);
2142 return NULL;
2143 }
2144 } else {
2145 hist = tracefs_hist_alloc(tep, system, event,
2146 key, type);
2147 if (!hist)
2148 return NULL;
2149 }
2150 }
2151
2152 if (!hist)
2153 return NULL;
2154
2155 for (i = 0; keys[i]; i++) {
2156 int type = types ? types[i] : 0;
2157
2158 if (type != HIST_COUNTER_TYPE)
2159 continue;
2160
2161 key = keys[i];
2162
2163 ret = tracefs_hist_add_value(hist, key);
2164 if (ret < 0) {
2165 tracefs_hist_free(hist);
2166 return NULL;
2167 }
2168 }
2169
2170 if (synth->start_filter) {
2171 hist->filter = strdup(synth->start_filter);
2172 if (!hist->filter) {
2173 tracefs_hist_free(hist);
2174 return NULL;
2175 }
2176 }
2177
2178 return hist;
2179 }
2180
2181 /**
2182 * tracefs_synth_create - creates the synthetic event on the system
2183 * @synth: The tracefs_synth descriptor
2184 *
2185 * This creates the synthetic events.
2186 *
2187 * Returns 0 on succes and -1 on error.
2188 * On error, errno is set to:
2189 * ENOMEM - memory allocation failure.
2190 * ENIVAL - a parameter is passed as NULL that should not be or a problem
2191 * writing into the system.
2192 */
tracefs_synth_create(struct tracefs_synth * synth)2193 int tracefs_synth_create(struct tracefs_synth *synth)
2194 {
2195 int ret;
2196
2197 if (!synth) {
2198 errno = EINVAL;
2199 return -1;
2200 }
2201
2202 if (!synth->name || !synth->end_event) {
2203 errno = EUNATCH;
2204 return -1;
2205 }
2206
2207 if (verify_state(synth) < 0)
2208 return -1;
2209
2210 if (!synth->dyn_event && alloc_synthetic_event(synth))
2211 return -1;
2212 if (tracefs_dynevent_create(synth->dyn_event))
2213 return -1;
2214
2215 synth->start_hist = create_hist(synth->start_keys, synth->start_vars);
2216 synth->start_hist = append_filter(synth->start_hist, synth->start_filter,
2217 synth->start_parens);
2218 if (!synth->start_hist)
2219 goto remove_synthetic;
2220
2221 synth->end_hist = create_end_hist(synth);
2222 synth->end_hist = append_filter(synth->end_hist, synth->end_filter,
2223 synth->end_parens);
2224 if (!synth->end_hist)
2225 goto remove_synthetic;
2226
2227 ret = tracefs_event_file_append(synth->instance, synth->start_event->system,
2228 synth->start_event->name,
2229 "trigger", synth->start_hist);
2230 if (ret < 0)
2231 goto remove_synthetic;
2232
2233 ret = tracefs_event_file_append(synth->instance, synth->end_event->system,
2234 synth->end_event->name,
2235 "trigger", synth->end_hist);
2236 if (ret < 0)
2237 goto remove_start_hist;
2238
2239 return 0;
2240
2241 remove_start_hist:
2242 remove_hist(synth->instance, synth->start_event, synth->start_hist);
2243 remove_synthetic:
2244 tracefs_dynevent_destroy(synth->dyn_event, false);
2245 return -1;
2246 }
2247
2248 /**
2249 * tracefs_synth_destroy - delete the synthetic event from the system
2250 * @synth: The tracefs_synth descriptor
2251 *
2252 * This will destroy a synthetic event created by tracefs_synth_create()
2253 * with the same @synth.
2254 *
2255 * It will attempt to disable the synthetic event in its instance (top by default),
2256 * but if other instances have it active, it is likely to fail, which will likely
2257 * fail on all other parts of tearing down the synthetic event.
2258 *
2259 * Returns 0 on succes and -1 on error.
2260 * On error, errno is set to:
2261 * ENOMEM - memory allocation failure.
2262 * ENIVAL - a parameter is passed as NULL that should not be or a problem
2263 * writing into the system.
2264 */
tracefs_synth_destroy(struct tracefs_synth * synth)2265 int tracefs_synth_destroy(struct tracefs_synth *synth)
2266 {
2267 char *hist;
2268 int ret;
2269
2270 if (!synth) {
2271 errno = EINVAL;
2272 return -1;
2273 }
2274
2275 if (!synth->name || !synth->end_event) {
2276 errno = EUNATCH;
2277 return -1;
2278 }
2279
2280 /* Try to disable the event if possible */
2281 tracefs_event_disable(synth->instance, "synthetic", synth->name);
2282
2283 hist = create_end_hist(synth);
2284 hist = append_filter(hist, synth->end_filter,
2285 synth->end_parens);
2286 if (!hist)
2287 return -1;
2288 ret = remove_hist(synth->instance, synth->end_event, hist);
2289 free(hist);
2290
2291 hist = create_hist(synth->start_keys, synth->start_vars);
2292 hist = append_filter(hist, synth->start_filter,
2293 synth->start_parens);
2294 if (!hist)
2295 return -1;
2296
2297 ret = remove_hist(synth->instance, synth->start_event, hist);
2298 free(hist);
2299
2300 ret = tracefs_dynevent_destroy(synth->dyn_event, true);
2301
2302 return ret ? -1 : 0;
2303 }
2304
2305 /**
2306 * tracefs_synth_echo_cmd - show the command lines to create the synthetic event
2307 * @seq: The trace_seq to store the command lines in
2308 * @synth: The tracefs_synth descriptor
2309 *
2310 * This will list the "echo" commands that are equivalent to what would
2311 * be executed by the tracefs_synth_create() command.
2312 *
2313 * Returns 0 on succes and -1 on error.
2314 * On error, errno is set to:
2315 * ENOMEM - memory allocation failure.
2316 */
tracefs_synth_echo_cmd(struct trace_seq * seq,struct tracefs_synth * synth)2317 int tracefs_synth_echo_cmd(struct trace_seq *seq,
2318 struct tracefs_synth *synth)
2319 {
2320 bool new_event = false;
2321 char *hist = NULL;
2322 char *path;
2323 int ret = -1;
2324
2325 if (!synth) {
2326 errno = EINVAL;
2327 return -1;
2328 }
2329
2330 if (!synth->name || !synth->end_event) {
2331 errno = EUNATCH;
2332 return -1;
2333 }
2334
2335 if (!synth->dyn_event) {
2336 if (alloc_synthetic_event(synth))
2337 return -1;
2338 new_event = true;
2339 }
2340
2341 path = trace_find_tracing_dir(false);
2342 if (!path)
2343 goto out_free;
2344
2345 trace_seq_printf(seq, "echo '%s%s%s %s' >> %s/%s\n",
2346 synth->dyn_event->prefix,
2347 strlen(synth->dyn_event->prefix) ? ":" : "",
2348 synth->dyn_event->event,
2349 synth->dyn_event->format, path, synth->dyn_event->trace_file);
2350
2351 tracefs_put_tracing_file(path);
2352 path = tracefs_instance_get_dir(synth->instance);
2353
2354 hist = create_hist(synth->start_keys, synth->start_vars);
2355 hist = append_filter(hist, synth->start_filter,
2356 synth->start_parens);
2357 if (!hist)
2358 goto out_free;
2359
2360 trace_seq_printf(seq, "echo '%s' >> %s/events/%s/%s/trigger\n",
2361 hist, path, synth->start_event->system,
2362 synth->start_event->name);
2363 free(hist);
2364 hist = create_end_hist(synth);
2365 hist = append_filter(hist, synth->end_filter,
2366 synth->end_parens);
2367 if (!hist)
2368 goto out_free;
2369
2370 trace_seq_printf(seq, "echo '%s' >> %s/events/%s/%s/trigger\n",
2371 hist, path, synth->end_event->system,
2372 synth->end_event->name);
2373
2374 ret = 0;
2375 out_free:
2376 free(hist);
2377 tracefs_put_tracing_file(path);
2378 if (new_event) {
2379 tracefs_dynevent_free(synth->dyn_event);
2380 synth->dyn_event = NULL;
2381 }
2382 return ret;
2383 }
2384
2385 /**
2386 * tracefs_synth_get_event - return tep event representing the given synthetic event
2387 * @tep: a handle to the trace event parser context that holds the events
2388 * @synth: a synthetic event context, describing given synthetic event.
2389 *
2390 * Returns a pointer to a tep event describing the given synthetic event. The pointer
2391 * is managed by the @tep handle and must not be freed. In case of an error, or in case
2392 * the requested synthetic event is missing in the @tep handler - NULL is returned.
2393 */
2394 struct tep_event *
tracefs_synth_get_event(struct tep_handle * tep,struct tracefs_synth * synth)2395 tracefs_synth_get_event(struct tep_handle *tep, struct tracefs_synth *synth)
2396 {
2397 if (!tep || !synth || !synth->name)
2398 return NULL;
2399
2400 return get_tep_event(tep, SYNTHETIC_GROUP, synth->name);
2401 }
2402