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