• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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