• 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 <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