xref: /openbmc/linux/tools/tracing/rtla/src/trace.c (revision 5487b6ce267bbafd399f3642062d974832d3eddc)
1b1696371SDaniel Bristot de Oliveira // SPDX-License-Identifier: GPL-2.0
2b1696371SDaniel Bristot de Oliveira #define _GNU_SOURCE
3b1696371SDaniel Bristot de Oliveira #include <sys/sendfile.h>
4b1696371SDaniel Bristot de Oliveira #include <tracefs.h>
5b1696371SDaniel Bristot de Oliveira #include <signal.h>
6b1696371SDaniel Bristot de Oliveira #include <stdlib.h>
7b1696371SDaniel Bristot de Oliveira #include <unistd.h>
8b1696371SDaniel Bristot de Oliveira #include <errno.h>
9b1696371SDaniel Bristot de Oliveira 
10b1696371SDaniel Bristot de Oliveira #include "trace.h"
11b1696371SDaniel Bristot de Oliveira #include "utils.h"
12b1696371SDaniel Bristot de Oliveira 
13b1696371SDaniel Bristot de Oliveira /*
14b1696371SDaniel Bristot de Oliveira  * enable_tracer_by_name - enable a tracer on the given instance
15b1696371SDaniel Bristot de Oliveira  */
16b1696371SDaniel Bristot de Oliveira int enable_tracer_by_name(struct tracefs_instance *inst, const char *tracer_name)
17b1696371SDaniel Bristot de Oliveira {
18b1696371SDaniel Bristot de Oliveira 	enum tracefs_tracers tracer;
19b1696371SDaniel Bristot de Oliveira 	int retval;
20b1696371SDaniel Bristot de Oliveira 
21b1696371SDaniel Bristot de Oliveira 	tracer = TRACEFS_TRACER_CUSTOM;
22b1696371SDaniel Bristot de Oliveira 
231a622909SDaniel Bristot de Oliveira 	debug_msg("Enabling %s tracer\n", tracer_name);
24b1696371SDaniel Bristot de Oliveira 
25b1696371SDaniel Bristot de Oliveira 	retval = tracefs_tracer_set(inst, tracer, tracer_name);
26b1696371SDaniel Bristot de Oliveira 	if (retval < 0) {
27b1696371SDaniel Bristot de Oliveira 		if (errno == ENODEV)
281a622909SDaniel Bristot de Oliveira 			err_msg("Tracer %s not found!\n", tracer_name);
29b1696371SDaniel Bristot de Oliveira 
301a622909SDaniel Bristot de Oliveira 		err_msg("Failed to enable the %s tracer\n", tracer_name);
31b1696371SDaniel Bristot de Oliveira 		return -1;
32b1696371SDaniel Bristot de Oliveira 	}
33b1696371SDaniel Bristot de Oliveira 
34b1696371SDaniel Bristot de Oliveira 	return 0;
35b1696371SDaniel Bristot de Oliveira }
36b1696371SDaniel Bristot de Oliveira 
37b1696371SDaniel Bristot de Oliveira /*
38b1696371SDaniel Bristot de Oliveira  * disable_tracer - set nop tracer to the insta
39b1696371SDaniel Bristot de Oliveira  */
40b1696371SDaniel Bristot de Oliveira void disable_tracer(struct tracefs_instance *inst)
41b1696371SDaniel Bristot de Oliveira {
42b1696371SDaniel Bristot de Oliveira 	enum tracefs_tracers t = TRACEFS_TRACER_NOP;
43b1696371SDaniel Bristot de Oliveira 	int retval;
44b1696371SDaniel Bristot de Oliveira 
45b1696371SDaniel Bristot de Oliveira 	retval = tracefs_tracer_set(inst, t);
46b1696371SDaniel Bristot de Oliveira 	if (retval < 0)
471a622909SDaniel Bristot de Oliveira 		err_msg("Oops, error disabling tracer\n");
48b1696371SDaniel Bristot de Oliveira }
49b1696371SDaniel Bristot de Oliveira 
50b1696371SDaniel Bristot de Oliveira /*
51b1696371SDaniel Bristot de Oliveira  * create_instance - create a trace instance with *instance_name
52b1696371SDaniel Bristot de Oliveira  */
53b1696371SDaniel Bristot de Oliveira struct tracefs_instance *create_instance(char *instance_name)
54b1696371SDaniel Bristot de Oliveira {
55b1696371SDaniel Bristot de Oliveira 	return tracefs_instance_create(instance_name);
56b1696371SDaniel Bristot de Oliveira }
57b1696371SDaniel Bristot de Oliveira 
58b1696371SDaniel Bristot de Oliveira /*
59b1696371SDaniel Bristot de Oliveira  * destroy_instance - remove a trace instance and free the data
60b1696371SDaniel Bristot de Oliveira  */
61b1696371SDaniel Bristot de Oliveira void destroy_instance(struct tracefs_instance *inst)
62b1696371SDaniel Bristot de Oliveira {
63b1696371SDaniel Bristot de Oliveira 	tracefs_instance_destroy(inst);
64b1696371SDaniel Bristot de Oliveira 	tracefs_instance_free(inst);
65b1696371SDaniel Bristot de Oliveira }
66b1696371SDaniel Bristot de Oliveira 
67b1696371SDaniel Bristot de Oliveira /*
68b1696371SDaniel Bristot de Oliveira  * save_trace_to_file - save the trace output of the instance to the file
69b1696371SDaniel Bristot de Oliveira  */
70b1696371SDaniel Bristot de Oliveira int save_trace_to_file(struct tracefs_instance *inst, const char *filename)
71b1696371SDaniel Bristot de Oliveira {
72b1696371SDaniel Bristot de Oliveira 	const char *file = "trace";
73b1696371SDaniel Bristot de Oliveira 	mode_t mode = 0644;
74b1696371SDaniel Bristot de Oliveira 	char buffer[4096];
75b1696371SDaniel Bristot de Oliveira 	int out_fd, in_fd;
76b1696371SDaniel Bristot de Oliveira 	int retval = -1;
77b1696371SDaniel Bristot de Oliveira 
78b1696371SDaniel Bristot de Oliveira 	in_fd = tracefs_instance_file_open(inst, file, O_RDONLY);
79b1696371SDaniel Bristot de Oliveira 	if (in_fd < 0) {
80b1696371SDaniel Bristot de Oliveira 		err_msg("Failed to open trace file\n");
81b1696371SDaniel Bristot de Oliveira 		return -1;
82b1696371SDaniel Bristot de Oliveira 	}
83b1696371SDaniel Bristot de Oliveira 
84b1696371SDaniel Bristot de Oliveira 	out_fd = creat(filename, mode);
85b1696371SDaniel Bristot de Oliveira 	if (out_fd < 0) {
86b1696371SDaniel Bristot de Oliveira 		err_msg("Failed to create output file %s\n", filename);
87b1696371SDaniel Bristot de Oliveira 		goto out_close_in;
88b1696371SDaniel Bristot de Oliveira 	}
89b1696371SDaniel Bristot de Oliveira 
90b1696371SDaniel Bristot de Oliveira 	do {
91b1696371SDaniel Bristot de Oliveira 		retval = read(in_fd, buffer, sizeof(buffer));
92b1696371SDaniel Bristot de Oliveira 		if (retval <= 0)
93b1696371SDaniel Bristot de Oliveira 			goto out_close;
94b1696371SDaniel Bristot de Oliveira 
95b1696371SDaniel Bristot de Oliveira 		retval = write(out_fd, buffer, retval);
96b1696371SDaniel Bristot de Oliveira 		if (retval < 0)
97b1696371SDaniel Bristot de Oliveira 			goto out_close;
98b1696371SDaniel Bristot de Oliveira 	} while (retval > 0);
99b1696371SDaniel Bristot de Oliveira 
100b1696371SDaniel Bristot de Oliveira 	retval = 0;
101b1696371SDaniel Bristot de Oliveira out_close:
102b1696371SDaniel Bristot de Oliveira 	close(out_fd);
103b1696371SDaniel Bristot de Oliveira out_close_in:
104b1696371SDaniel Bristot de Oliveira 	close(in_fd);
105b1696371SDaniel Bristot de Oliveira 	return retval;
106b1696371SDaniel Bristot de Oliveira }
107b1696371SDaniel Bristot de Oliveira 
108b1696371SDaniel Bristot de Oliveira /*
109b1696371SDaniel Bristot de Oliveira  * collect_registered_events - call the existing callback function for the event
110b1696371SDaniel Bristot de Oliveira  *
111b1696371SDaniel Bristot de Oliveira  * If an event has a registered callback function, call it.
112b1696371SDaniel Bristot de Oliveira  * Otherwise, ignore the event.
113b1696371SDaniel Bristot de Oliveira  */
114b1696371SDaniel Bristot de Oliveira int
115b1696371SDaniel Bristot de Oliveira collect_registered_events(struct tep_event *event, struct tep_record *record,
116b1696371SDaniel Bristot de Oliveira 			  int cpu, void *context)
117b1696371SDaniel Bristot de Oliveira {
118b1696371SDaniel Bristot de Oliveira 	struct trace_instance *trace = context;
119b1696371SDaniel Bristot de Oliveira 	struct trace_seq *s = trace->seq;
120b1696371SDaniel Bristot de Oliveira 
121b1696371SDaniel Bristot de Oliveira 	if (!event->handler)
122b1696371SDaniel Bristot de Oliveira 		return 0;
123b1696371SDaniel Bristot de Oliveira 
124b1696371SDaniel Bristot de Oliveira 	event->handler(s, record, event, context);
125b1696371SDaniel Bristot de Oliveira 
126b1696371SDaniel Bristot de Oliveira 	return 0;
127b1696371SDaniel Bristot de Oliveira }
128b1696371SDaniel Bristot de Oliveira 
129b1696371SDaniel Bristot de Oliveira /*
130b1696371SDaniel Bristot de Oliveira  * trace_instance_destroy - destroy and free a rtla trace instance
131b1696371SDaniel Bristot de Oliveira  */
132b1696371SDaniel Bristot de Oliveira void trace_instance_destroy(struct trace_instance *trace)
133b1696371SDaniel Bristot de Oliveira {
134b1696371SDaniel Bristot de Oliveira 	if (trace->inst) {
135b1696371SDaniel Bristot de Oliveira 		disable_tracer(trace->inst);
136b1696371SDaniel Bristot de Oliveira 		destroy_instance(trace->inst);
137b1696371SDaniel Bristot de Oliveira 	}
138b1696371SDaniel Bristot de Oliveira 
139b1696371SDaniel Bristot de Oliveira 	if (trace->seq)
140b1696371SDaniel Bristot de Oliveira 		free(trace->seq);
141b1696371SDaniel Bristot de Oliveira 
142b1696371SDaniel Bristot de Oliveira 	if (trace->tep)
143b1696371SDaniel Bristot de Oliveira 		tep_free(trace->tep);
144b1696371SDaniel Bristot de Oliveira }
145b1696371SDaniel Bristot de Oliveira 
146b1696371SDaniel Bristot de Oliveira /*
147b1696371SDaniel Bristot de Oliveira  * trace_instance_init - create an rtla trace instance
148b1696371SDaniel Bristot de Oliveira  *
149b1696371SDaniel Bristot de Oliveira  * It is more than the tracefs instance, as it contains other
150b1696371SDaniel Bristot de Oliveira  * things required for the tracing, such as the local events and
151b1696371SDaniel Bristot de Oliveira  * a seq file.
152b1696371SDaniel Bristot de Oliveira  *
153b1696371SDaniel Bristot de Oliveira  * Note that the trace instance is returned disabled. This allows
154b1696371SDaniel Bristot de Oliveira  * the tool to apply some other configs, like setting priority
155b1696371SDaniel Bristot de Oliveira  * to the kernel threads, before starting generating trace entries.
156b1696371SDaniel Bristot de Oliveira  */
157b1696371SDaniel Bristot de Oliveira int trace_instance_init(struct trace_instance *trace, char *tool_name)
158b1696371SDaniel Bristot de Oliveira {
159b1696371SDaniel Bristot de Oliveira 	trace->seq = calloc(1, sizeof(*trace->seq));
160b1696371SDaniel Bristot de Oliveira 	if (!trace->seq)
161b1696371SDaniel Bristot de Oliveira 		goto out_err;
162b1696371SDaniel Bristot de Oliveira 
163b1696371SDaniel Bristot de Oliveira 	trace_seq_init(trace->seq);
164b1696371SDaniel Bristot de Oliveira 
165b1696371SDaniel Bristot de Oliveira 	trace->inst = create_instance(tool_name);
166b1696371SDaniel Bristot de Oliveira 	if (!trace->inst)
167b1696371SDaniel Bristot de Oliveira 		goto out_err;
168b1696371SDaniel Bristot de Oliveira 
169b1696371SDaniel Bristot de Oliveira 	trace->tep = tracefs_local_events(NULL);
170b1696371SDaniel Bristot de Oliveira 	if (!trace->tep)
171b1696371SDaniel Bristot de Oliveira 		goto out_err;
172b1696371SDaniel Bristot de Oliveira 
173b1696371SDaniel Bristot de Oliveira 	/*
174b1696371SDaniel Bristot de Oliveira 	 * Let the main enable the record after setting some other
175b1696371SDaniel Bristot de Oliveira 	 * things such as the priority of the tracer's threads.
176b1696371SDaniel Bristot de Oliveira 	 */
177b1696371SDaniel Bristot de Oliveira 	tracefs_trace_off(trace->inst);
178b1696371SDaniel Bristot de Oliveira 
179b1696371SDaniel Bristot de Oliveira 	return 0;
180b1696371SDaniel Bristot de Oliveira 
181b1696371SDaniel Bristot de Oliveira out_err:
182b1696371SDaniel Bristot de Oliveira 	trace_instance_destroy(trace);
183b1696371SDaniel Bristot de Oliveira 	return 1;
184b1696371SDaniel Bristot de Oliveira }
185b1696371SDaniel Bristot de Oliveira 
186b1696371SDaniel Bristot de Oliveira /*
187b1696371SDaniel Bristot de Oliveira  * trace_instance_start - start tracing a given rtla instance
188b1696371SDaniel Bristot de Oliveira  */
189b1696371SDaniel Bristot de Oliveira int trace_instance_start(struct trace_instance *trace)
190b1696371SDaniel Bristot de Oliveira {
191b1696371SDaniel Bristot de Oliveira 	return tracefs_trace_on(trace->inst);
192b1696371SDaniel Bristot de Oliveira }
193b5aa0be2SDaniel Bristot de Oliveira 
194b5aa0be2SDaniel Bristot de Oliveira /*
195b5aa0be2SDaniel Bristot de Oliveira  * trace_events_free - free a list of trace events
196b5aa0be2SDaniel Bristot de Oliveira  */
197b5aa0be2SDaniel Bristot de Oliveira static void trace_events_free(struct trace_events *events)
198b5aa0be2SDaniel Bristot de Oliveira {
199b5aa0be2SDaniel Bristot de Oliveira 	struct trace_events *tevent = events;
200b5aa0be2SDaniel Bristot de Oliveira 	struct trace_events *free_event;
201b5aa0be2SDaniel Bristot de Oliveira 
202b5aa0be2SDaniel Bristot de Oliveira 	while (tevent) {
203b5aa0be2SDaniel Bristot de Oliveira 		free_event = tevent;
204b5aa0be2SDaniel Bristot de Oliveira 
205b5aa0be2SDaniel Bristot de Oliveira 		tevent = tevent->next;
206b5aa0be2SDaniel Bristot de Oliveira 
207*5487b6ceSDaniel Bristot de Oliveira 		if (free_event->filter)
208*5487b6ceSDaniel Bristot de Oliveira 			free(free_event->filter);
209336c92b2SDaniel Bristot de Oliveira 		if (free_event->trigger)
210336c92b2SDaniel Bristot de Oliveira 			free(free_event->trigger);
211b5aa0be2SDaniel Bristot de Oliveira 		free(free_event->system);
212b5aa0be2SDaniel Bristot de Oliveira 		free(free_event);
213b5aa0be2SDaniel Bristot de Oliveira 	}
214b5aa0be2SDaniel Bristot de Oliveira }
215b5aa0be2SDaniel Bristot de Oliveira 
216b5aa0be2SDaniel Bristot de Oliveira /*
217b5aa0be2SDaniel Bristot de Oliveira  * trace_event_alloc - alloc and parse a single trace event
218b5aa0be2SDaniel Bristot de Oliveira  */
219b5aa0be2SDaniel Bristot de Oliveira struct trace_events *trace_event_alloc(const char *event_string)
220b5aa0be2SDaniel Bristot de Oliveira {
221b5aa0be2SDaniel Bristot de Oliveira 	struct trace_events *tevent;
222b5aa0be2SDaniel Bristot de Oliveira 
223b5aa0be2SDaniel Bristot de Oliveira 	tevent = calloc(1, sizeof(*tevent));
224b5aa0be2SDaniel Bristot de Oliveira 	if (!tevent)
225b5aa0be2SDaniel Bristot de Oliveira 		return NULL;
226b5aa0be2SDaniel Bristot de Oliveira 
227b5aa0be2SDaniel Bristot de Oliveira 	tevent->system = strdup(event_string);
228b5aa0be2SDaniel Bristot de Oliveira 	if (!tevent->system) {
229b5aa0be2SDaniel Bristot de Oliveira 		free(tevent);
230b5aa0be2SDaniel Bristot de Oliveira 		return NULL;
231b5aa0be2SDaniel Bristot de Oliveira 	}
232b5aa0be2SDaniel Bristot de Oliveira 
233b5aa0be2SDaniel Bristot de Oliveira 	tevent->event = strstr(tevent->system, ":");
234b5aa0be2SDaniel Bristot de Oliveira 	if (tevent->event) {
235b5aa0be2SDaniel Bristot de Oliveira 		*tevent->event = '\0';
236b5aa0be2SDaniel Bristot de Oliveira 		tevent->event = &tevent->event[1];
237b5aa0be2SDaniel Bristot de Oliveira 	}
238b5aa0be2SDaniel Bristot de Oliveira 
239b5aa0be2SDaniel Bristot de Oliveira 	return tevent;
240b5aa0be2SDaniel Bristot de Oliveira }
241b5aa0be2SDaniel Bristot de Oliveira 
242b5aa0be2SDaniel Bristot de Oliveira /*
243*5487b6ceSDaniel Bristot de Oliveira  * trace_event_add_filter - record an event filter
244*5487b6ceSDaniel Bristot de Oliveira  */
245*5487b6ceSDaniel Bristot de Oliveira int trace_event_add_filter(struct trace_events *event, char *filter)
246*5487b6ceSDaniel Bristot de Oliveira {
247*5487b6ceSDaniel Bristot de Oliveira 	if (event->filter)
248*5487b6ceSDaniel Bristot de Oliveira 		free(event->filter);
249*5487b6ceSDaniel Bristot de Oliveira 
250*5487b6ceSDaniel Bristot de Oliveira 	event->filter = strdup(filter);
251*5487b6ceSDaniel Bristot de Oliveira 	if (!event->filter)
252*5487b6ceSDaniel Bristot de Oliveira 		return 1;
253*5487b6ceSDaniel Bristot de Oliveira 
254*5487b6ceSDaniel Bristot de Oliveira 	return 0;
255*5487b6ceSDaniel Bristot de Oliveira }
256*5487b6ceSDaniel Bristot de Oliveira 
257*5487b6ceSDaniel Bristot de Oliveira /*
258336c92b2SDaniel Bristot de Oliveira  * trace_event_add_trigger - record an event trigger action
259336c92b2SDaniel Bristot de Oliveira  */
260336c92b2SDaniel Bristot de Oliveira int trace_event_add_trigger(struct trace_events *event, char *trigger)
261336c92b2SDaniel Bristot de Oliveira {
262336c92b2SDaniel Bristot de Oliveira 	if (event->trigger)
263336c92b2SDaniel Bristot de Oliveira 		free(event->trigger);
264336c92b2SDaniel Bristot de Oliveira 
265336c92b2SDaniel Bristot de Oliveira 	event->trigger = strdup(trigger);
266336c92b2SDaniel Bristot de Oliveira 	if (!event->trigger)
267336c92b2SDaniel Bristot de Oliveira 		return 1;
268336c92b2SDaniel Bristot de Oliveira 
269336c92b2SDaniel Bristot de Oliveira 	return 0;
270336c92b2SDaniel Bristot de Oliveira }
271336c92b2SDaniel Bristot de Oliveira 
272336c92b2SDaniel Bristot de Oliveira /*
273*5487b6ceSDaniel Bristot de Oliveira  * trace_event_disable_filter - disable an event filter
274*5487b6ceSDaniel Bristot de Oliveira  */
275*5487b6ceSDaniel Bristot de Oliveira static void trace_event_disable_filter(struct trace_instance *instance,
276*5487b6ceSDaniel Bristot de Oliveira 				       struct trace_events *tevent)
277*5487b6ceSDaniel Bristot de Oliveira {
278*5487b6ceSDaniel Bristot de Oliveira 	char filter[1024];
279*5487b6ceSDaniel Bristot de Oliveira 	int retval;
280*5487b6ceSDaniel Bristot de Oliveira 
281*5487b6ceSDaniel Bristot de Oliveira 	if (!tevent->filter)
282*5487b6ceSDaniel Bristot de Oliveira 		return;
283*5487b6ceSDaniel Bristot de Oliveira 
284*5487b6ceSDaniel Bristot de Oliveira 	if (!tevent->filter_enabled)
285*5487b6ceSDaniel Bristot de Oliveira 		return;
286*5487b6ceSDaniel Bristot de Oliveira 
287*5487b6ceSDaniel Bristot de Oliveira 	debug_msg("Disabling %s:%s filter %s\n", tevent->system,
288*5487b6ceSDaniel Bristot de Oliveira 		  tevent->event ? : "*", tevent->filter);
289*5487b6ceSDaniel Bristot de Oliveira 
290*5487b6ceSDaniel Bristot de Oliveira 	snprintf(filter, 1024, "!%s\n", tevent->filter);
291*5487b6ceSDaniel Bristot de Oliveira 
292*5487b6ceSDaniel Bristot de Oliveira 	retval = tracefs_event_file_write(instance->inst, tevent->system,
293*5487b6ceSDaniel Bristot de Oliveira 					  tevent->event, "filter", filter);
294*5487b6ceSDaniel Bristot de Oliveira 	if (retval < 0)
295*5487b6ceSDaniel Bristot de Oliveira 		err_msg("Error disabling %s:%s filter %s\n", tevent->system,
296*5487b6ceSDaniel Bristot de Oliveira 			tevent->event ? : "*", tevent->filter);
297*5487b6ceSDaniel Bristot de Oliveira }
298*5487b6ceSDaniel Bristot de Oliveira 
299*5487b6ceSDaniel Bristot de Oliveira /*
300336c92b2SDaniel Bristot de Oliveira  * trace_event_disable_trigger - disable an event trigger
301336c92b2SDaniel Bristot de Oliveira  */
302336c92b2SDaniel Bristot de Oliveira static void trace_event_disable_trigger(struct trace_instance *instance,
303336c92b2SDaniel Bristot de Oliveira 					struct trace_events *tevent)
304336c92b2SDaniel Bristot de Oliveira {
305336c92b2SDaniel Bristot de Oliveira 	char trigger[1024];
306336c92b2SDaniel Bristot de Oliveira 	int retval;
307336c92b2SDaniel Bristot de Oliveira 
308336c92b2SDaniel Bristot de Oliveira 	if (!tevent->trigger)
309336c92b2SDaniel Bristot de Oliveira 		return;
310336c92b2SDaniel Bristot de Oliveira 
311336c92b2SDaniel Bristot de Oliveira 	if (!tevent->trigger_enabled)
312336c92b2SDaniel Bristot de Oliveira 		return;
313336c92b2SDaniel Bristot de Oliveira 
314336c92b2SDaniel Bristot de Oliveira 	debug_msg("Disabling %s:%s trigger %s\n", tevent->system,
315336c92b2SDaniel Bristot de Oliveira 		  tevent->event ? : "*", tevent->trigger);
316336c92b2SDaniel Bristot de Oliveira 
317336c92b2SDaniel Bristot de Oliveira 	snprintf(trigger, 1024, "!%s\n", tevent->trigger);
318336c92b2SDaniel Bristot de Oliveira 
319336c92b2SDaniel Bristot de Oliveira 	retval = tracefs_event_file_write(instance->inst, tevent->system,
320336c92b2SDaniel Bristot de Oliveira 					  tevent->event, "trigger", trigger);
321336c92b2SDaniel Bristot de Oliveira 	if (retval < 0)
322336c92b2SDaniel Bristot de Oliveira 		err_msg("Error disabling %s:%s trigger %s\n", tevent->system,
323336c92b2SDaniel Bristot de Oliveira 			tevent->event ? : "*", tevent->trigger);
324336c92b2SDaniel Bristot de Oliveira }
325336c92b2SDaniel Bristot de Oliveira 
326336c92b2SDaniel Bristot de Oliveira /*
327b5aa0be2SDaniel Bristot de Oliveira  * trace_events_disable - disable all trace events
328b5aa0be2SDaniel Bristot de Oliveira  */
329b5aa0be2SDaniel Bristot de Oliveira void trace_events_disable(struct trace_instance *instance,
330b5aa0be2SDaniel Bristot de Oliveira 			  struct trace_events *events)
331b5aa0be2SDaniel Bristot de Oliveira {
332b5aa0be2SDaniel Bristot de Oliveira 	struct trace_events *tevent = events;
333b5aa0be2SDaniel Bristot de Oliveira 
334b5aa0be2SDaniel Bristot de Oliveira 	if (!events)
335b5aa0be2SDaniel Bristot de Oliveira 		return;
336b5aa0be2SDaniel Bristot de Oliveira 
337b5aa0be2SDaniel Bristot de Oliveira 	while (tevent) {
338b5aa0be2SDaniel Bristot de Oliveira 		debug_msg("Disabling event %s:%s\n", tevent->system, tevent->event ? : "*");
339336c92b2SDaniel Bristot de Oliveira 		if (tevent->enabled) {
340*5487b6ceSDaniel Bristot de Oliveira 			trace_event_disable_filter(instance, tevent);
341336c92b2SDaniel Bristot de Oliveira 			trace_event_disable_trigger(instance, tevent);
342b5aa0be2SDaniel Bristot de Oliveira 			tracefs_event_disable(instance->inst, tevent->system, tevent->event);
343336c92b2SDaniel Bristot de Oliveira 		}
344b5aa0be2SDaniel Bristot de Oliveira 
345b5aa0be2SDaniel Bristot de Oliveira 		tevent->enabled = 0;
346b5aa0be2SDaniel Bristot de Oliveira 		tevent = tevent->next;
347b5aa0be2SDaniel Bristot de Oliveira 	}
348b5aa0be2SDaniel Bristot de Oliveira }
349b5aa0be2SDaniel Bristot de Oliveira 
350b5aa0be2SDaniel Bristot de Oliveira /*
351*5487b6ceSDaniel Bristot de Oliveira  * trace_event_enable_filter - enable an event filter associated with an event
352*5487b6ceSDaniel Bristot de Oliveira  */
353*5487b6ceSDaniel Bristot de Oliveira static int trace_event_enable_filter(struct trace_instance *instance,
354*5487b6ceSDaniel Bristot de Oliveira 				     struct trace_events *tevent)
355*5487b6ceSDaniel Bristot de Oliveira {
356*5487b6ceSDaniel Bristot de Oliveira 	char filter[1024];
357*5487b6ceSDaniel Bristot de Oliveira 	int retval;
358*5487b6ceSDaniel Bristot de Oliveira 
359*5487b6ceSDaniel Bristot de Oliveira 	if (!tevent->filter)
360*5487b6ceSDaniel Bristot de Oliveira 		return 0;
361*5487b6ceSDaniel Bristot de Oliveira 
362*5487b6ceSDaniel Bristot de Oliveira 	if (!tevent->event) {
363*5487b6ceSDaniel Bristot de Oliveira 		err_msg("Filter %s applies only for single events, not for all %s:* events\n",
364*5487b6ceSDaniel Bristot de Oliveira 			tevent->filter, tevent->system);
365*5487b6ceSDaniel Bristot de Oliveira 		return 1;
366*5487b6ceSDaniel Bristot de Oliveira 	}
367*5487b6ceSDaniel Bristot de Oliveira 
368*5487b6ceSDaniel Bristot de Oliveira 	snprintf(filter, 1024, "%s\n", tevent->filter);
369*5487b6ceSDaniel Bristot de Oliveira 
370*5487b6ceSDaniel Bristot de Oliveira 	debug_msg("Enabling %s:%s filter %s\n", tevent->system,
371*5487b6ceSDaniel Bristot de Oliveira 		  tevent->event ? : "*", tevent->filter);
372*5487b6ceSDaniel Bristot de Oliveira 
373*5487b6ceSDaniel Bristot de Oliveira 	retval = tracefs_event_file_write(instance->inst, tevent->system,
374*5487b6ceSDaniel Bristot de Oliveira 					  tevent->event, "filter", filter);
375*5487b6ceSDaniel Bristot de Oliveira 	if (retval < 0) {
376*5487b6ceSDaniel Bristot de Oliveira 		err_msg("Error enabling %s:%s filter %s\n", tevent->system,
377*5487b6ceSDaniel Bristot de Oliveira 			tevent->event ? : "*", tevent->filter);
378*5487b6ceSDaniel Bristot de Oliveira 		return 1;
379*5487b6ceSDaniel Bristot de Oliveira 	}
380*5487b6ceSDaniel Bristot de Oliveira 
381*5487b6ceSDaniel Bristot de Oliveira 	tevent->filter_enabled = 1;
382*5487b6ceSDaniel Bristot de Oliveira 	return 0;
383*5487b6ceSDaniel Bristot de Oliveira }
384*5487b6ceSDaniel Bristot de Oliveira 
385*5487b6ceSDaniel Bristot de Oliveira /*
386336c92b2SDaniel Bristot de Oliveira  * trace_event_enable_trigger - enable an event trigger associated with an event
387336c92b2SDaniel Bristot de Oliveira  */
388336c92b2SDaniel Bristot de Oliveira static int trace_event_enable_trigger(struct trace_instance *instance,
389336c92b2SDaniel Bristot de Oliveira 				      struct trace_events *tevent)
390336c92b2SDaniel Bristot de Oliveira {
391336c92b2SDaniel Bristot de Oliveira 	char trigger[1024];
392336c92b2SDaniel Bristot de Oliveira 	int retval;
393336c92b2SDaniel Bristot de Oliveira 
394336c92b2SDaniel Bristot de Oliveira 	if (!tevent->trigger)
395336c92b2SDaniel Bristot de Oliveira 		return 0;
396336c92b2SDaniel Bristot de Oliveira 
397336c92b2SDaniel Bristot de Oliveira 	if (!tevent->event) {
398336c92b2SDaniel Bristot de Oliveira 		err_msg("Trigger %s applies only for single events, not for all %s:* events\n",
399336c92b2SDaniel Bristot de Oliveira 			tevent->trigger, tevent->system);
400336c92b2SDaniel Bristot de Oliveira 		return 1;
401336c92b2SDaniel Bristot de Oliveira 	}
402336c92b2SDaniel Bristot de Oliveira 
403336c92b2SDaniel Bristot de Oliveira 	snprintf(trigger, 1024, "%s\n", tevent->trigger);
404336c92b2SDaniel Bristot de Oliveira 
405336c92b2SDaniel Bristot de Oliveira 	debug_msg("Enabling %s:%s trigger %s\n", tevent->system,
406336c92b2SDaniel Bristot de Oliveira 		  tevent->event ? : "*", tevent->trigger);
407336c92b2SDaniel Bristot de Oliveira 
408336c92b2SDaniel Bristot de Oliveira 	retval = tracefs_event_file_write(instance->inst, tevent->system,
409336c92b2SDaniel Bristot de Oliveira 					  tevent->event, "trigger", trigger);
410336c92b2SDaniel Bristot de Oliveira 	if (retval < 0) {
411336c92b2SDaniel Bristot de Oliveira 		err_msg("Error enabling %s:%s trigger %s\n", tevent->system,
412336c92b2SDaniel Bristot de Oliveira 			tevent->event ? : "*", tevent->trigger);
413336c92b2SDaniel Bristot de Oliveira 		return 1;
414336c92b2SDaniel Bristot de Oliveira 	}
415336c92b2SDaniel Bristot de Oliveira 
416336c92b2SDaniel Bristot de Oliveira 	tevent->trigger_enabled = 1;
417336c92b2SDaniel Bristot de Oliveira 
418336c92b2SDaniel Bristot de Oliveira 	return 0;
419336c92b2SDaniel Bristot de Oliveira }
420336c92b2SDaniel Bristot de Oliveira 
421336c92b2SDaniel Bristot de Oliveira /*
422b5aa0be2SDaniel Bristot de Oliveira  * trace_events_enable - enable all events
423b5aa0be2SDaniel Bristot de Oliveira  */
424b5aa0be2SDaniel Bristot de Oliveira int trace_events_enable(struct trace_instance *instance,
425b5aa0be2SDaniel Bristot de Oliveira 			struct trace_events *events)
426b5aa0be2SDaniel Bristot de Oliveira {
427b5aa0be2SDaniel Bristot de Oliveira 	struct trace_events *tevent = events;
428b5aa0be2SDaniel Bristot de Oliveira 	int retval;
429b5aa0be2SDaniel Bristot de Oliveira 
430b5aa0be2SDaniel Bristot de Oliveira 	while (tevent) {
431b5aa0be2SDaniel Bristot de Oliveira 		debug_msg("Enabling event %s:%s\n", tevent->system, tevent->event ? : "*");
432b5aa0be2SDaniel Bristot de Oliveira 		retval = tracefs_event_enable(instance->inst, tevent->system, tevent->event);
433b5aa0be2SDaniel Bristot de Oliveira 		if (retval < 0) {
434b5aa0be2SDaniel Bristot de Oliveira 			err_msg("Error enabling event %s:%s\n", tevent->system,
435b5aa0be2SDaniel Bristot de Oliveira 				tevent->event ? : "*");
436b5aa0be2SDaniel Bristot de Oliveira 			return 1;
437b5aa0be2SDaniel Bristot de Oliveira 		}
438b5aa0be2SDaniel Bristot de Oliveira 
439*5487b6ceSDaniel Bristot de Oliveira 		retval = trace_event_enable_filter(instance, tevent);
440*5487b6ceSDaniel Bristot de Oliveira 		if (retval)
441*5487b6ceSDaniel Bristot de Oliveira 			return 1;
442b5aa0be2SDaniel Bristot de Oliveira 
443336c92b2SDaniel Bristot de Oliveira 		retval = trace_event_enable_trigger(instance, tevent);
444336c92b2SDaniel Bristot de Oliveira 		if (retval)
445336c92b2SDaniel Bristot de Oliveira 			return 1;
446336c92b2SDaniel Bristot de Oliveira 
447b5aa0be2SDaniel Bristot de Oliveira 		tevent->enabled = 1;
448b5aa0be2SDaniel Bristot de Oliveira 		tevent = tevent->next;
449b5aa0be2SDaniel Bristot de Oliveira 	}
450b5aa0be2SDaniel Bristot de Oliveira 
451b5aa0be2SDaniel Bristot de Oliveira 	return 0;
452b5aa0be2SDaniel Bristot de Oliveira }
453b5aa0be2SDaniel Bristot de Oliveira 
454b5aa0be2SDaniel Bristot de Oliveira /*
455b5aa0be2SDaniel Bristot de Oliveira  * trace_events_destroy - disable and free all trace events
456b5aa0be2SDaniel Bristot de Oliveira  */
457b5aa0be2SDaniel Bristot de Oliveira void trace_events_destroy(struct trace_instance *instance,
458b5aa0be2SDaniel Bristot de Oliveira 			  struct trace_events *events)
459b5aa0be2SDaniel Bristot de Oliveira {
460b5aa0be2SDaniel Bristot de Oliveira 	if (!events)
461b5aa0be2SDaniel Bristot de Oliveira 		return;
462b5aa0be2SDaniel Bristot de Oliveira 
463b5aa0be2SDaniel Bristot de Oliveira 	trace_events_disable(instance, events);
464b5aa0be2SDaniel Bristot de Oliveira 	trace_events_free(events);
465b5aa0be2SDaniel Bristot de Oliveira }
466