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 if (!inst || !filename) 79 return 0; 80 81 in_fd = tracefs_instance_file_open(inst, file, O_RDONLY); 82 if (in_fd < 0) { 83 err_msg("Failed to open trace file\n"); 84 return -1; 85 } 86 87 printf(" Saving trace to %s\n", filename); 88 out_fd = creat(filename, mode); 89 if (out_fd < 0) { 90 err_msg("Failed to create output file %s\n", filename); 91 goto out_close_in; 92 } 93 94 do { 95 retval = read(in_fd, buffer, sizeof(buffer)); 96 if (retval <= 0) 97 goto out_close; 98 99 retval = write(out_fd, buffer, retval); 100 if (retval < 0) 101 goto out_close; 102 } while (retval > 0); 103 104 retval = 0; 105 out_close: 106 close(out_fd); 107 out_close_in: 108 close(in_fd); 109 return retval; 110 } 111 112 /* 113 * collect_registered_events - call the existing callback function for the event 114 * 115 * If an event has a registered callback function, call it. 116 * Otherwise, ignore the event. 117 */ 118 int 119 collect_registered_events(struct tep_event *event, struct tep_record *record, 120 int cpu, void *context) 121 { 122 struct trace_instance *trace = context; 123 struct trace_seq *s = trace->seq; 124 125 trace->processed_events++; 126 127 if (!event->handler) 128 return 0; 129 130 event->handler(s, record, event, context); 131 132 return 0; 133 } 134 135 /* 136 * collect_missed_events - record number of missed events 137 * 138 * If rtla cannot keep up with events generated by tracer, events are going 139 * to fall out of the ring buffer. 140 * Collect how many events were missed so it can be reported to the user. 141 */ 142 static int 143 collect_missed_events(struct tep_event *event, struct tep_record *record, 144 int cpu, void *context) 145 { 146 struct trace_instance *trace = context; 147 148 if (trace->missed_events == UINT64_MAX) 149 return 0; 150 151 if (record->missed_events > 0) 152 trace->missed_events += record->missed_events; 153 else 154 /* Events missed but no data on how many */ 155 trace->missed_events = UINT64_MAX; 156 157 return 0; 158 } 159 160 /* 161 * trace_instance_destroy - destroy and free a rtla trace instance 162 */ 163 void trace_instance_destroy(struct trace_instance *trace) 164 { 165 if (trace->inst) { 166 disable_tracer(trace->inst); 167 destroy_instance(trace->inst); 168 trace->inst = NULL; 169 } 170 171 if (trace->seq) { 172 free(trace->seq); 173 trace->seq = NULL; 174 } 175 176 if (trace->tep) { 177 tep_free(trace->tep); 178 trace->tep = NULL; 179 } 180 } 181 182 /* 183 * trace_instance_init - create an rtla trace instance 184 * 185 * It is more than the tracefs instance, as it contains other 186 * things required for the tracing, such as the local events and 187 * a seq file. 188 * 189 * Note that the trace instance is returned disabled. This allows 190 * the tool to apply some other configs, like setting priority 191 * to the kernel threads, before starting generating trace entries. 192 */ 193 int trace_instance_init(struct trace_instance *trace, char *tool_name) 194 { 195 trace->seq = calloc(1, sizeof(*trace->seq)); 196 if (!trace->seq) 197 goto out_err; 198 199 trace_seq_init(trace->seq); 200 201 trace->inst = create_instance(tool_name); 202 if (!trace->inst) 203 goto out_err; 204 205 trace->tep = tracefs_local_events(NULL); 206 if (!trace->tep) 207 goto out_err; 208 209 /* 210 * Let the main enable the record after setting some other 211 * things such as the priority of the tracer's threads. 212 */ 213 tracefs_trace_off(trace->inst); 214 215 /* 216 * Collect the number of events missed due to tracefs buffer 217 * overflow. 218 */ 219 trace->missed_events = 0; 220 tracefs_follow_missed_events(trace->inst, 221 collect_missed_events, 222 trace); 223 224 trace->processed_events = 0; 225 226 return 0; 227 228 out_err: 229 trace_instance_destroy(trace); 230 return 1; 231 } 232 233 /* 234 * trace_instance_start - start tracing a given rtla instance 235 */ 236 int trace_instance_start(struct trace_instance *trace) 237 { 238 return tracefs_trace_on(trace->inst); 239 } 240 241 /* 242 * trace_instance_stop - stop tracing a given rtla instance 243 */ 244 int trace_instance_stop(struct trace_instance *trace) 245 { 246 return tracefs_trace_off(trace->inst); 247 } 248 249 /* 250 * trace_events_free - free a list of trace events 251 */ 252 static void trace_events_free(struct trace_events *events) 253 { 254 struct trace_events *tevent = events; 255 struct trace_events *free_event; 256 257 while (tevent) { 258 free_event = tevent; 259 260 tevent = tevent->next; 261 262 if (free_event->filter) 263 free(free_event->filter); 264 if (free_event->trigger) 265 free(free_event->trigger); 266 free(free_event->system); 267 free(free_event); 268 } 269 } 270 271 /* 272 * trace_event_alloc - alloc and parse a single trace event 273 */ 274 struct trace_events *trace_event_alloc(const char *event_string) 275 { 276 struct trace_events *tevent; 277 278 tevent = calloc(1, sizeof(*tevent)); 279 if (!tevent) 280 return NULL; 281 282 tevent->system = strdup(event_string); 283 if (!tevent->system) { 284 free(tevent); 285 return NULL; 286 } 287 288 tevent->event = strstr(tevent->system, ":"); 289 if (tevent->event) { 290 *tevent->event = '\0'; 291 tevent->event = &tevent->event[1]; 292 } 293 294 return tevent; 295 } 296 297 /* 298 * trace_event_add_filter - record an event filter 299 */ 300 int trace_event_add_filter(struct trace_events *event, char *filter) 301 { 302 if (event->filter) 303 free(event->filter); 304 305 event->filter = strdup(filter); 306 if (!event->filter) 307 return 1; 308 309 return 0; 310 } 311 312 /* 313 * trace_event_add_trigger - record an event trigger action 314 */ 315 int trace_event_add_trigger(struct trace_events *event, char *trigger) 316 { 317 if (event->trigger) 318 free(event->trigger); 319 320 event->trigger = strdup(trigger); 321 if (!event->trigger) 322 return 1; 323 324 return 0; 325 } 326 327 /* 328 * trace_event_disable_filter - disable an event filter 329 */ 330 static void trace_event_disable_filter(struct trace_instance *instance, 331 struct trace_events *tevent) 332 { 333 char filter[1024]; 334 int retval; 335 336 if (!tevent->filter) 337 return; 338 339 if (!tevent->filter_enabled) 340 return; 341 342 debug_msg("Disabling %s:%s filter %s\n", tevent->system, 343 tevent->event ? : "*", tevent->filter); 344 345 snprintf(filter, 1024, "!%s\n", tevent->filter); 346 347 retval = tracefs_event_file_write(instance->inst, tevent->system, 348 tevent->event, "filter", filter); 349 if (retval < 0) 350 err_msg("Error disabling %s:%s filter %s\n", tevent->system, 351 tevent->event ? : "*", tevent->filter); 352 } 353 354 /* 355 * trace_event_save_hist - save the content of an event hist 356 * 357 * If the trigger is a hist: one, save the content of the hist file. 358 */ 359 static void trace_event_save_hist(struct trace_instance *instance, 360 struct trace_events *tevent) 361 { 362 int retval, index, out_fd; 363 mode_t mode = 0644; 364 char path[1024]; 365 char *hist; 366 367 if (!tevent) 368 return; 369 370 /* trigger enables hist */ 371 if (!tevent->trigger) 372 return; 373 374 /* is this a hist: trigger? */ 375 retval = strncmp(tevent->trigger, "hist:", strlen("hist:")); 376 if (retval) 377 return; 378 379 snprintf(path, 1024, "%s_%s_hist.txt", tevent->system, tevent->event); 380 381 printf(" Saving event %s:%s hist to %s\n", tevent->system, tevent->event, path); 382 383 out_fd = creat(path, mode); 384 if (out_fd < 0) { 385 err_msg(" Failed to create %s output file\n", path); 386 return; 387 } 388 389 hist = tracefs_event_file_read(instance->inst, tevent->system, tevent->event, "hist", 0); 390 if (!hist) { 391 err_msg(" Failed to read %s:%s hist file\n", tevent->system, tevent->event); 392 goto out_close; 393 } 394 395 index = 0; 396 do { 397 index += write(out_fd, &hist[index], strlen(hist) - index); 398 } while (index < strlen(hist)); 399 400 free(hist); 401 out_close: 402 close(out_fd); 403 } 404 405 /* 406 * trace_event_disable_trigger - disable an event trigger 407 */ 408 static void trace_event_disable_trigger(struct trace_instance *instance, 409 struct trace_events *tevent) 410 { 411 char trigger[1024]; 412 int retval; 413 414 if (!tevent->trigger) 415 return; 416 417 if (!tevent->trigger_enabled) 418 return; 419 420 debug_msg("Disabling %s:%s trigger %s\n", tevent->system, 421 tevent->event ? : "*", tevent->trigger); 422 423 trace_event_save_hist(instance, tevent); 424 425 snprintf(trigger, 1024, "!%s\n", tevent->trigger); 426 427 retval = tracefs_event_file_write(instance->inst, tevent->system, 428 tevent->event, "trigger", trigger); 429 if (retval < 0) 430 err_msg("Error disabling %s:%s trigger %s\n", tevent->system, 431 tevent->event ? : "*", tevent->trigger); 432 } 433 434 /* 435 * trace_events_disable - disable all trace events 436 */ 437 void trace_events_disable(struct trace_instance *instance, 438 struct trace_events *events) 439 { 440 struct trace_events *tevent = events; 441 442 if (!events) 443 return; 444 445 while (tevent) { 446 debug_msg("Disabling event %s:%s\n", tevent->system, tevent->event ? : "*"); 447 if (tevent->enabled) { 448 trace_event_disable_filter(instance, tevent); 449 trace_event_disable_trigger(instance, tevent); 450 tracefs_event_disable(instance->inst, tevent->system, tevent->event); 451 } 452 453 tevent->enabled = 0; 454 tevent = tevent->next; 455 } 456 } 457 458 /* 459 * trace_event_enable_filter - enable an event filter associated with an event 460 */ 461 static int trace_event_enable_filter(struct trace_instance *instance, 462 struct trace_events *tevent) 463 { 464 char filter[1024]; 465 int retval; 466 467 if (!tevent->filter) 468 return 0; 469 470 if (!tevent->event) { 471 err_msg("Filter %s applies only for single events, not for all %s:* events\n", 472 tevent->filter, tevent->system); 473 return 1; 474 } 475 476 snprintf(filter, 1024, "%s\n", tevent->filter); 477 478 debug_msg("Enabling %s:%s filter %s\n", tevent->system, 479 tevent->event ? : "*", tevent->filter); 480 481 retval = tracefs_event_file_write(instance->inst, tevent->system, 482 tevent->event, "filter", filter); 483 if (retval < 0) { 484 err_msg("Error enabling %s:%s filter %s\n", tevent->system, 485 tevent->event ? : "*", tevent->filter); 486 return 1; 487 } 488 489 tevent->filter_enabled = 1; 490 return 0; 491 } 492 493 /* 494 * trace_event_enable_trigger - enable an event trigger associated with an event 495 */ 496 static int trace_event_enable_trigger(struct trace_instance *instance, 497 struct trace_events *tevent) 498 { 499 char trigger[1024]; 500 int retval; 501 502 if (!tevent->trigger) 503 return 0; 504 505 if (!tevent->event) { 506 err_msg("Trigger %s applies only for single events, not for all %s:* events\n", 507 tevent->trigger, tevent->system); 508 return 1; 509 } 510 511 snprintf(trigger, 1024, "%s\n", tevent->trigger); 512 513 debug_msg("Enabling %s:%s trigger %s\n", tevent->system, 514 tevent->event ? : "*", tevent->trigger); 515 516 retval = tracefs_event_file_write(instance->inst, tevent->system, 517 tevent->event, "trigger", trigger); 518 if (retval < 0) { 519 err_msg("Error enabling %s:%s trigger %s\n", tevent->system, 520 tevent->event ? : "*", tevent->trigger); 521 return 1; 522 } 523 524 tevent->trigger_enabled = 1; 525 526 return 0; 527 } 528 529 /* 530 * trace_events_enable - enable all events 531 */ 532 int trace_events_enable(struct trace_instance *instance, 533 struct trace_events *events) 534 { 535 struct trace_events *tevent = events; 536 int retval; 537 538 while (tevent) { 539 debug_msg("Enabling event %s:%s\n", tevent->system, tevent->event ? : "*"); 540 retval = tracefs_event_enable(instance->inst, tevent->system, tevent->event); 541 if (retval < 0) { 542 err_msg("Error enabling event %s:%s\n", tevent->system, 543 tevent->event ? : "*"); 544 return 1; 545 } 546 547 retval = trace_event_enable_filter(instance, tevent); 548 if (retval) 549 return 1; 550 551 retval = trace_event_enable_trigger(instance, tevent); 552 if (retval) 553 return 1; 554 555 tevent->enabled = 1; 556 tevent = tevent->next; 557 } 558 559 return 0; 560 } 561 562 /* 563 * trace_events_destroy - disable and free all trace events 564 */ 565 void trace_events_destroy(struct trace_instance *instance, 566 struct trace_events *events) 567 { 568 if (!events) 569 return; 570 571 trace_events_disable(instance, events); 572 trace_events_free(events); 573 } 574 575 /* 576 * trace_set_buffer_size - set the per-cpu tracing buffer size. 577 */ 578 int trace_set_buffer_size(struct trace_instance *trace, int size) 579 { 580 int retval; 581 582 debug_msg("Setting trace buffer size to %d Kb\n", size); 583 retval = tracefs_instance_set_buffer_size(trace->inst, size, -1); 584 if (retval) 585 err_msg("Error setting trace buffer size\n"); 586 587 return retval; 588 } 589