~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/tracing/rtla/src/trace.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 #define _GNU_SOURCE
  3 #include <sys/sendfile.h>
  4 #include <tracefs.h>
  5 #include <signal.h>
  6 #include <stdlib.h>
  7 #include <unistd.h>
  8 #include <errno.h>
  9 
 10 #include "trace.h"
 11 #include "utils.h"
 12 
 13 /*
 14  * enable_tracer_by_name - enable a tracer on the given instance
 15  */
 16 int enable_tracer_by_name(struct tracefs_instance *inst, const char *tracer_name)
 17 {
 18         enum tracefs_tracers tracer;
 19         int retval;
 20 
 21         tracer = TRACEFS_TRACER_CUSTOM;
 22 
 23         debug_msg("Enabling %s tracer\n", tracer_name);
 24 
 25         retval = tracefs_tracer_set(inst, tracer, tracer_name);
 26         if (retval < 0) {
 27                 if (errno == ENODEV)
 28                         err_msg("Tracer %s not found!\n", tracer_name);
 29 
 30                 err_msg("Failed to enable the %s tracer\n", tracer_name);
 31                 return -1;
 32         }
 33 
 34         return 0;
 35 }
 36 
 37 /*
 38  * disable_tracer - set nop tracer to the insta
 39  */
 40 void disable_tracer(struct tracefs_instance *inst)
 41 {
 42         enum tracefs_tracers t = TRACEFS_TRACER_NOP;
 43         int retval;
 44 
 45         retval = tracefs_tracer_set(inst, t);
 46         if (retval < 0)
 47                 err_msg("Oops, error disabling tracer\n");
 48 }
 49 
 50 /*
 51  * create_instance - create a trace instance with *instance_name
 52  */
 53 struct tracefs_instance *create_instance(char *instance_name)
 54 {
 55         return tracefs_instance_create(instance_name);
 56 }
 57 
 58 /*
 59  * destroy_instance - remove a trace instance and free the data
 60  */
 61 void destroy_instance(struct tracefs_instance *inst)
 62 {
 63         tracefs_instance_destroy(inst);
 64         tracefs_instance_free(inst);
 65 }
 66 
 67 /*
 68  * save_trace_to_file - save the trace output of the instance to the file
 69  */
 70 int save_trace_to_file(struct tracefs_instance *inst, const char *filename)
 71 {
 72         const char *file = "trace";
 73         mode_t mode = 0644;
 74         char buffer[4096];
 75         int out_fd, in_fd;
 76         int retval = -1;
 77 
 78         in_fd = tracefs_instance_file_open(inst, file, O_RDONLY);
 79         if (in_fd < 0) {
 80                 err_msg("Failed to open trace file\n");
 81                 return -1;
 82         }
 83 
 84         out_fd = creat(filename, mode);
 85         if (out_fd < 0) {
 86                 err_msg("Failed to create output file %s\n", filename);
 87                 goto out_close_in;
 88         }
 89 
 90         do {
 91                 retval = read(in_fd, buffer, sizeof(buffer));
 92                 if (retval <= 0)
 93                         goto out_close;
 94 
 95                 retval = write(out_fd, buffer, retval);
 96                 if (retval < 0)
 97                         goto out_close;
 98         } while (retval > 0);
 99 
100         retval = 0;
101 out_close:
102         close(out_fd);
103 out_close_in:
104         close(in_fd);
105         return retval;
106 }
107 
108 /*
109  * collect_registered_events - call the existing callback function for the event
110  *
111  * If an event has a registered callback function, call it.
112  * Otherwise, ignore the event.
113  */
114 int
115 collect_registered_events(struct tep_event *event, struct tep_record *record,
116                           int cpu, void *context)
117 {
118         struct trace_instance *trace = context;
119         struct trace_seq *s = trace->seq;
120 
121         if (!event->handler)
122                 return 0;
123 
124         event->handler(s, record, event, context);
125 
126         return 0;
127 }
128 
129 /*
130  * trace_instance_destroy - destroy and free a rtla trace instance
131  */
132 void trace_instance_destroy(struct trace_instance *trace)
133 {
134         if (trace->inst) {
135                 disable_tracer(trace->inst);
136                 destroy_instance(trace->inst);
137                 trace->inst = NULL;
138         }
139 
140         if (trace->seq) {
141                 free(trace->seq);
142                 trace->seq = NULL;
143         }
144 
145         if (trace->tep) {
146                 tep_free(trace->tep);
147                 trace->tep = NULL;
148         }
149 }
150 
151 /*
152  * trace_instance_init - create an rtla trace instance
153  *
154  * It is more than the tracefs instance, as it contains other
155  * things required for the tracing, such as the local events and
156  * a seq file.
157  *
158  * Note that the trace instance is returned disabled. This allows
159  * the tool to apply some other configs, like setting priority
160  * to the kernel threads, before starting generating trace entries.
161  */
162 int trace_instance_init(struct trace_instance *trace, char *tool_name)
163 {
164         trace->seq = calloc(1, sizeof(*trace->seq));
165         if (!trace->seq)
166                 goto out_err;
167 
168         trace_seq_init(trace->seq);
169 
170         trace->inst = create_instance(tool_name);
171         if (!trace->inst)
172                 goto out_err;
173 
174         trace->tep = tracefs_local_events(NULL);
175         if (!trace->tep)
176                 goto out_err;
177 
178         /*
179          * Let the main enable the record after setting some other
180          * things such as the priority of the tracer's threads.
181          */
182         tracefs_trace_off(trace->inst);
183 
184         return 0;
185 
186 out_err:
187         trace_instance_destroy(trace);
188         return 1;
189 }
190 
191 /*
192  * trace_instance_start - start tracing a given rtla instance
193  */
194 int trace_instance_start(struct trace_instance *trace)
195 {
196         return tracefs_trace_on(trace->inst);
197 }
198 
199 /*
200  * trace_events_free - free a list of trace events
201  */
202 static void trace_events_free(struct trace_events *events)
203 {
204         struct trace_events *tevent = events;
205         struct trace_events *free_event;
206 
207         while (tevent) {
208                 free_event = tevent;
209 
210                 tevent = tevent->next;
211 
212                 if (free_event->filter)
213                         free(free_event->filter);
214                 if (free_event->trigger)
215                         free(free_event->trigger);
216                 free(free_event->system);
217                 free(free_event);
218         }
219 }
220 
221 /*
222  * trace_event_alloc - alloc and parse a single trace event
223  */
224 struct trace_events *trace_event_alloc(const char *event_string)
225 {
226         struct trace_events *tevent;
227 
228         tevent = calloc(1, sizeof(*tevent));
229         if (!tevent)
230                 return NULL;
231 
232         tevent->system = strdup(event_string);
233         if (!tevent->system) {
234                 free(tevent);
235                 return NULL;
236         }
237 
238         tevent->event = strstr(tevent->system, ":");
239         if (tevent->event) {
240                 *tevent->event = '\0';
241                 tevent->event = &tevent->event[1];
242         }
243 
244         return tevent;
245 }
246 
247 /*
248  * trace_event_add_filter - record an event filter
249  */
250 int trace_event_add_filter(struct trace_events *event, char *filter)
251 {
252         if (event->filter)
253                 free(event->filter);
254 
255         event->filter = strdup(filter);
256         if (!event->filter)
257                 return 1;
258 
259         return 0;
260 }
261 
262 /*
263  * trace_event_add_trigger - record an event trigger action
264  */
265 int trace_event_add_trigger(struct trace_events *event, char *trigger)
266 {
267         if (event->trigger)
268                 free(event->trigger);
269 
270         event->trigger = strdup(trigger);
271         if (!event->trigger)
272                 return 1;
273 
274         return 0;
275 }
276 
277 /*
278  * trace_event_disable_filter - disable an event filter
279  */
280 static void trace_event_disable_filter(struct trace_instance *instance,
281                                        struct trace_events *tevent)
282 {
283         char filter[1024];
284         int retval;
285 
286         if (!tevent->filter)
287                 return;
288 
289         if (!tevent->filter_enabled)
290                 return;
291 
292         debug_msg("Disabling %s:%s filter %s\n", tevent->system,
293                   tevent->event ? : "*", tevent->filter);
294 
295         snprintf(filter, 1024, "!%s\n", tevent->filter);
296 
297         retval = tracefs_event_file_write(instance->inst, tevent->system,
298                                           tevent->event, "filter", filter);
299         if (retval < 0)
300                 err_msg("Error disabling %s:%s filter %s\n", tevent->system,
301                         tevent->event ? : "*", tevent->filter);
302 }
303 
304 /*
305  * trace_event_save_hist - save the content of an event hist
306  *
307  * If the trigger is a hist: one, save the content of the hist file.
308  */
309 static void trace_event_save_hist(struct trace_instance *instance,
310                                   struct trace_events *tevent)
311 {
312         int retval, index, out_fd;
313         mode_t mode = 0644;
314         char path[1024];
315         char *hist;
316 
317         if (!tevent)
318                 return;
319 
320         /* trigger enables hist */
321         if (!tevent->trigger)
322                 return;
323 
324         /* is this a hist: trigger? */
325         retval = strncmp(tevent->trigger, "hist:", strlen("hist:"));
326         if (retval)
327                 return;
328 
329         snprintf(path, 1024, "%s_%s_hist.txt", tevent->system, tevent->event);
330 
331         printf("  Saving event %s:%s hist to %s\n", tevent->system, tevent->event, path);
332 
333         out_fd = creat(path, mode);
334         if (out_fd < 0) {
335                 err_msg("  Failed to create %s output file\n", path);
336                 return;
337         }
338 
339         hist = tracefs_event_file_read(instance->inst, tevent->system, tevent->event, "hist", 0);
340         if (!hist) {
341                 err_msg("  Failed to read %s:%s hist file\n", tevent->system, tevent->event);
342                 goto out_close;
343         }
344 
345         index = 0;
346         do {
347                 index += write(out_fd, &hist[index], strlen(hist) - index);
348         } while (index < strlen(hist));
349 
350         free(hist);
351 out_close:
352         close(out_fd);
353 }
354 
355 /*
356  * trace_event_disable_trigger - disable an event trigger
357  */
358 static void trace_event_disable_trigger(struct trace_instance *instance,
359                                         struct trace_events *tevent)
360 {
361         char trigger[1024];
362         int retval;
363 
364         if (!tevent->trigger)
365                 return;
366 
367         if (!tevent->trigger_enabled)
368                 return;
369 
370         debug_msg("Disabling %s:%s trigger %s\n", tevent->system,
371                   tevent->event ? : "*", tevent->trigger);
372 
373         trace_event_save_hist(instance, tevent);
374 
375         snprintf(trigger, 1024, "!%s\n", tevent->trigger);
376 
377         retval = tracefs_event_file_write(instance->inst, tevent->system,
378                                           tevent->event, "trigger", trigger);
379         if (retval < 0)
380                 err_msg("Error disabling %s:%s trigger %s\n", tevent->system,
381                         tevent->event ? : "*", tevent->trigger);
382 }
383 
384 /*
385  * trace_events_disable - disable all trace events
386  */
387 void trace_events_disable(struct trace_instance *instance,
388                           struct trace_events *events)
389 {
390         struct trace_events *tevent = events;
391 
392         if (!events)
393                 return;
394 
395         while (tevent) {
396                 debug_msg("Disabling event %s:%s\n", tevent->system, tevent->event ? : "*");
397                 if (tevent->enabled) {
398                         trace_event_disable_filter(instance, tevent);
399                         trace_event_disable_trigger(instance, tevent);
400                         tracefs_event_disable(instance->inst, tevent->system, tevent->event);
401                 }
402 
403                 tevent->enabled = 0;
404                 tevent = tevent->next;
405         }
406 }
407 
408 /*
409  * trace_event_enable_filter - enable an event filter associated with an event
410  */
411 static int trace_event_enable_filter(struct trace_instance *instance,
412                                      struct trace_events *tevent)
413 {
414         char filter[1024];
415         int retval;
416 
417         if (!tevent->filter)
418                 return 0;
419 
420         if (!tevent->event) {
421                 err_msg("Filter %s applies only for single events, not for all %s:* events\n",
422                         tevent->filter, tevent->system);
423                 return 1;
424         }
425 
426         snprintf(filter, 1024, "%s\n", tevent->filter);
427 
428         debug_msg("Enabling %s:%s filter %s\n", tevent->system,
429                   tevent->event ? : "*", tevent->filter);
430 
431         retval = tracefs_event_file_write(instance->inst, tevent->system,
432                                           tevent->event, "filter", filter);
433         if (retval < 0) {
434                 err_msg("Error enabling %s:%s filter %s\n", tevent->system,
435                         tevent->event ? : "*", tevent->filter);
436                 return 1;
437         }
438 
439         tevent->filter_enabled = 1;
440         return 0;
441 }
442 
443 /*
444  * trace_event_enable_trigger - enable an event trigger associated with an event
445  */
446 static int trace_event_enable_trigger(struct trace_instance *instance,
447                                       struct trace_events *tevent)
448 {
449         char trigger[1024];
450         int retval;
451 
452         if (!tevent->trigger)
453                 return 0;
454 
455         if (!tevent->event) {
456                 err_msg("Trigger %s applies only for single events, not for all %s:* events\n",
457                         tevent->trigger, tevent->system);
458                 return 1;
459         }
460 
461         snprintf(trigger, 1024, "%s\n", tevent->trigger);
462 
463         debug_msg("Enabling %s:%s trigger %s\n", tevent->system,
464                   tevent->event ? : "*", tevent->trigger);
465 
466         retval = tracefs_event_file_write(instance->inst, tevent->system,
467                                           tevent->event, "trigger", trigger);
468         if (retval < 0) {
469                 err_msg("Error enabling %s:%s trigger %s\n", tevent->system,
470                         tevent->event ? : "*", tevent->trigger);
471                 return 1;
472         }
473 
474         tevent->trigger_enabled = 1;
475 
476         return 0;
477 }
478 
479 /*
480  * trace_events_enable - enable all events
481  */
482 int trace_events_enable(struct trace_instance *instance,
483                         struct trace_events *events)
484 {
485         struct trace_events *tevent = events;
486         int retval;
487 
488         while (tevent) {
489                 debug_msg("Enabling event %s:%s\n", tevent->system, tevent->event ? : "*");
490                 retval = tracefs_event_enable(instance->inst, tevent->system, tevent->event);
491                 if (retval < 0) {
492                         err_msg("Error enabling event %s:%s\n", tevent->system,
493                                 tevent->event ? : "*");
494                         return 1;
495                 }
496 
497                 retval = trace_event_enable_filter(instance, tevent);
498                 if (retval)
499                         return 1;
500 
501                 retval = trace_event_enable_trigger(instance, tevent);
502                 if (retval)
503                         return 1;
504 
505                 tevent->enabled = 1;
506                 tevent = tevent->next;
507         }
508 
509         return 0;
510 }
511 
512 /*
513  * trace_events_destroy - disable and free all trace events
514  */
515 void trace_events_destroy(struct trace_instance *instance,
516                           struct trace_events *events)
517 {
518         if (!events)
519                 return;
520 
521         trace_events_disable(instance, events);
522         trace_events_free(events);
523 }
524 
525 int trace_is_off(struct trace_instance *tool, struct trace_instance *trace)
526 {
527         /*
528          * The tool instance is always present, it is the one used to collect
529          * data.
530          */
531         if (!tracefs_trace_is_on(tool->inst))
532                 return 1;
533 
534         /*
535          * The trace instance is only enabled when -t is set. IOW, when the system
536          * is tracing.
537          */
538         if (trace && !tracefs_trace_is_on(trace->inst))
539                 return 1;
540 
541         return 0;
542 }
543 
544 /*
545  * trace_set_buffer_size - set the per-cpu tracing buffer size.
546  */
547 int trace_set_buffer_size(struct trace_instance *trace, int size)
548 {
549         int retval;
550 
551         debug_msg("Setting trace buffer size to %d Kb\n", size);
552         retval = tracefs_instance_set_buffer_size(trace->inst, size, -1);
553         if (retval)
554                 err_msg("Error setting trace buffer size\n");
555 
556         return retval;
557 }
558 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php