0001
0002 #define _GNU_SOURCE
0003 #include <sys/sendfile.h>
0004 #include <tracefs.h>
0005 #include <signal.h>
0006 #include <stdlib.h>
0007 #include <unistd.h>
0008 #include <errno.h>
0009
0010 #include "trace.h"
0011 #include "utils.h"
0012
0013
0014
0015
0016 int enable_tracer_by_name(struct tracefs_instance *inst, const char *tracer_name)
0017 {
0018 enum tracefs_tracers tracer;
0019 int retval;
0020
0021 tracer = TRACEFS_TRACER_CUSTOM;
0022
0023 debug_msg("Enabling %s tracer\n", tracer_name);
0024
0025 retval = tracefs_tracer_set(inst, tracer, tracer_name);
0026 if (retval < 0) {
0027 if (errno == ENODEV)
0028 err_msg("Tracer %s not found!\n", tracer_name);
0029
0030 err_msg("Failed to enable the %s tracer\n", tracer_name);
0031 return -1;
0032 }
0033
0034 return 0;
0035 }
0036
0037
0038
0039
0040 void disable_tracer(struct tracefs_instance *inst)
0041 {
0042 enum tracefs_tracers t = TRACEFS_TRACER_NOP;
0043 int retval;
0044
0045 retval = tracefs_tracer_set(inst, t);
0046 if (retval < 0)
0047 err_msg("Oops, error disabling tracer\n");
0048 }
0049
0050
0051
0052
0053 struct tracefs_instance *create_instance(char *instance_name)
0054 {
0055 return tracefs_instance_create(instance_name);
0056 }
0057
0058
0059
0060
0061 void destroy_instance(struct tracefs_instance *inst)
0062 {
0063 tracefs_instance_destroy(inst);
0064 tracefs_instance_free(inst);
0065 }
0066
0067
0068
0069
0070 int save_trace_to_file(struct tracefs_instance *inst, const char *filename)
0071 {
0072 const char *file = "trace";
0073 mode_t mode = 0644;
0074 char buffer[4096];
0075 int out_fd, in_fd;
0076 int retval = -1;
0077
0078 in_fd = tracefs_instance_file_open(inst, file, O_RDONLY);
0079 if (in_fd < 0) {
0080 err_msg("Failed to open trace file\n");
0081 return -1;
0082 }
0083
0084 out_fd = creat(filename, mode);
0085 if (out_fd < 0) {
0086 err_msg("Failed to create output file %s\n", filename);
0087 goto out_close_in;
0088 }
0089
0090 do {
0091 retval = read(in_fd, buffer, sizeof(buffer));
0092 if (retval <= 0)
0093 goto out_close;
0094
0095 retval = write(out_fd, buffer, retval);
0096 if (retval < 0)
0097 goto out_close;
0098 } while (retval > 0);
0099
0100 retval = 0;
0101 out_close:
0102 close(out_fd);
0103 out_close_in:
0104 close(in_fd);
0105 return retval;
0106 }
0107
0108
0109
0110
0111
0112
0113
0114 int
0115 collect_registered_events(struct tep_event *event, struct tep_record *record,
0116 int cpu, void *context)
0117 {
0118 struct trace_instance *trace = context;
0119 struct trace_seq *s = trace->seq;
0120
0121 if (!event->handler)
0122 return 0;
0123
0124 event->handler(s, record, event, context);
0125
0126 return 0;
0127 }
0128
0129
0130
0131
0132 void trace_instance_destroy(struct trace_instance *trace)
0133 {
0134 if (trace->inst) {
0135 disable_tracer(trace->inst);
0136 destroy_instance(trace->inst);
0137 trace->inst = NULL;
0138 }
0139
0140 if (trace->seq) {
0141 free(trace->seq);
0142 trace->seq = NULL;
0143 }
0144
0145 if (trace->tep) {
0146 tep_free(trace->tep);
0147 trace->tep = NULL;
0148 }
0149 }
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161
0162 int trace_instance_init(struct trace_instance *trace, char *tool_name)
0163 {
0164 trace->seq = calloc(1, sizeof(*trace->seq));
0165 if (!trace->seq)
0166 goto out_err;
0167
0168 trace_seq_init(trace->seq);
0169
0170 trace->inst = create_instance(tool_name);
0171 if (!trace->inst)
0172 goto out_err;
0173
0174 trace->tep = tracefs_local_events(NULL);
0175 if (!trace->tep)
0176 goto out_err;
0177
0178
0179
0180
0181
0182 tracefs_trace_off(trace->inst);
0183
0184 return 0;
0185
0186 out_err:
0187 trace_instance_destroy(trace);
0188 return 1;
0189 }
0190
0191
0192
0193
0194 int trace_instance_start(struct trace_instance *trace)
0195 {
0196 return tracefs_trace_on(trace->inst);
0197 }
0198
0199
0200
0201
0202 static void trace_events_free(struct trace_events *events)
0203 {
0204 struct trace_events *tevent = events;
0205 struct trace_events *free_event;
0206
0207 while (tevent) {
0208 free_event = tevent;
0209
0210 tevent = tevent->next;
0211
0212 if (free_event->filter)
0213 free(free_event->filter);
0214 if (free_event->trigger)
0215 free(free_event->trigger);
0216 free(free_event->system);
0217 free(free_event);
0218 }
0219 }
0220
0221
0222
0223
0224 struct trace_events *trace_event_alloc(const char *event_string)
0225 {
0226 struct trace_events *tevent;
0227
0228 tevent = calloc(1, sizeof(*tevent));
0229 if (!tevent)
0230 return NULL;
0231
0232 tevent->system = strdup(event_string);
0233 if (!tevent->system) {
0234 free(tevent);
0235 return NULL;
0236 }
0237
0238 tevent->event = strstr(tevent->system, ":");
0239 if (tevent->event) {
0240 *tevent->event = '\0';
0241 tevent->event = &tevent->event[1];
0242 }
0243
0244 return tevent;
0245 }
0246
0247
0248
0249
0250 int trace_event_add_filter(struct trace_events *event, char *filter)
0251 {
0252 if (event->filter)
0253 free(event->filter);
0254
0255 event->filter = strdup(filter);
0256 if (!event->filter)
0257 return 1;
0258
0259 return 0;
0260 }
0261
0262
0263
0264
0265 int trace_event_add_trigger(struct trace_events *event, char *trigger)
0266 {
0267 if (event->trigger)
0268 free(event->trigger);
0269
0270 event->trigger = strdup(trigger);
0271 if (!event->trigger)
0272 return 1;
0273
0274 return 0;
0275 }
0276
0277
0278
0279
0280 static void trace_event_disable_filter(struct trace_instance *instance,
0281 struct trace_events *tevent)
0282 {
0283 char filter[1024];
0284 int retval;
0285
0286 if (!tevent->filter)
0287 return;
0288
0289 if (!tevent->filter_enabled)
0290 return;
0291
0292 debug_msg("Disabling %s:%s filter %s\n", tevent->system,
0293 tevent->event ? : "*", tevent->filter);
0294
0295 snprintf(filter, 1024, "!%s\n", tevent->filter);
0296
0297 retval = tracefs_event_file_write(instance->inst, tevent->system,
0298 tevent->event, "filter", filter);
0299 if (retval < 0)
0300 err_msg("Error disabling %s:%s filter %s\n", tevent->system,
0301 tevent->event ? : "*", tevent->filter);
0302 }
0303
0304
0305
0306
0307
0308
0309 static void trace_event_save_hist(struct trace_instance *instance,
0310 struct trace_events *tevent)
0311 {
0312 int retval, index, out_fd;
0313 mode_t mode = 0644;
0314 char path[1024];
0315 char *hist;
0316
0317 if (!tevent)
0318 return;
0319
0320
0321 if (!tevent->trigger)
0322 return;
0323
0324
0325 retval = strncmp(tevent->trigger, "hist:", strlen("hist:"));
0326 if (retval)
0327 return;
0328
0329 snprintf(path, 1024, "%s_%s_hist.txt", tevent->system, tevent->event);
0330
0331 printf(" Saving event %s:%s hist to %s\n", tevent->system, tevent->event, path);
0332
0333 out_fd = creat(path, mode);
0334 if (out_fd < 0) {
0335 err_msg(" Failed to create %s output file\n", path);
0336 return;
0337 }
0338
0339 hist = tracefs_event_file_read(instance->inst, tevent->system, tevent->event, "hist", 0);
0340 if (!hist) {
0341 err_msg(" Failed to read %s:%s hist file\n", tevent->system, tevent->event);
0342 goto out_close;
0343 }
0344
0345 index = 0;
0346 do {
0347 index += write(out_fd, &hist[index], strlen(hist) - index);
0348 } while (index < strlen(hist));
0349
0350 free(hist);
0351 out_close:
0352 close(out_fd);
0353 }
0354
0355
0356
0357
0358 static void trace_event_disable_trigger(struct trace_instance *instance,
0359 struct trace_events *tevent)
0360 {
0361 char trigger[1024];
0362 int retval;
0363
0364 if (!tevent->trigger)
0365 return;
0366
0367 if (!tevent->trigger_enabled)
0368 return;
0369
0370 debug_msg("Disabling %s:%s trigger %s\n", tevent->system,
0371 tevent->event ? : "*", tevent->trigger);
0372
0373 trace_event_save_hist(instance, tevent);
0374
0375 snprintf(trigger, 1024, "!%s\n", tevent->trigger);
0376
0377 retval = tracefs_event_file_write(instance->inst, tevent->system,
0378 tevent->event, "trigger", trigger);
0379 if (retval < 0)
0380 err_msg("Error disabling %s:%s trigger %s\n", tevent->system,
0381 tevent->event ? : "*", tevent->trigger);
0382 }
0383
0384
0385
0386
0387 void trace_events_disable(struct trace_instance *instance,
0388 struct trace_events *events)
0389 {
0390 struct trace_events *tevent = events;
0391
0392 if (!events)
0393 return;
0394
0395 while (tevent) {
0396 debug_msg("Disabling event %s:%s\n", tevent->system, tevent->event ? : "*");
0397 if (tevent->enabled) {
0398 trace_event_disable_filter(instance, tevent);
0399 trace_event_disable_trigger(instance, tevent);
0400 tracefs_event_disable(instance->inst, tevent->system, tevent->event);
0401 }
0402
0403 tevent->enabled = 0;
0404 tevent = tevent->next;
0405 }
0406 }
0407
0408
0409
0410
0411 static int trace_event_enable_filter(struct trace_instance *instance,
0412 struct trace_events *tevent)
0413 {
0414 char filter[1024];
0415 int retval;
0416
0417 if (!tevent->filter)
0418 return 0;
0419
0420 if (!tevent->event) {
0421 err_msg("Filter %s applies only for single events, not for all %s:* events\n",
0422 tevent->filter, tevent->system);
0423 return 1;
0424 }
0425
0426 snprintf(filter, 1024, "%s\n", tevent->filter);
0427
0428 debug_msg("Enabling %s:%s filter %s\n", tevent->system,
0429 tevent->event ? : "*", tevent->filter);
0430
0431 retval = tracefs_event_file_write(instance->inst, tevent->system,
0432 tevent->event, "filter", filter);
0433 if (retval < 0) {
0434 err_msg("Error enabling %s:%s filter %s\n", tevent->system,
0435 tevent->event ? : "*", tevent->filter);
0436 return 1;
0437 }
0438
0439 tevent->filter_enabled = 1;
0440 return 0;
0441 }
0442
0443
0444
0445
0446 static int trace_event_enable_trigger(struct trace_instance *instance,
0447 struct trace_events *tevent)
0448 {
0449 char trigger[1024];
0450 int retval;
0451
0452 if (!tevent->trigger)
0453 return 0;
0454
0455 if (!tevent->event) {
0456 err_msg("Trigger %s applies only for single events, not for all %s:* events\n",
0457 tevent->trigger, tevent->system);
0458 return 1;
0459 }
0460
0461 snprintf(trigger, 1024, "%s\n", tevent->trigger);
0462
0463 debug_msg("Enabling %s:%s trigger %s\n", tevent->system,
0464 tevent->event ? : "*", tevent->trigger);
0465
0466 retval = tracefs_event_file_write(instance->inst, tevent->system,
0467 tevent->event, "trigger", trigger);
0468 if (retval < 0) {
0469 err_msg("Error enabling %s:%s trigger %s\n", tevent->system,
0470 tevent->event ? : "*", tevent->trigger);
0471 return 1;
0472 }
0473
0474 tevent->trigger_enabled = 1;
0475
0476 return 0;
0477 }
0478
0479
0480
0481
0482 int trace_events_enable(struct trace_instance *instance,
0483 struct trace_events *events)
0484 {
0485 struct trace_events *tevent = events;
0486 int retval;
0487
0488 while (tevent) {
0489 debug_msg("Enabling event %s:%s\n", tevent->system, tevent->event ? : "*");
0490 retval = tracefs_event_enable(instance->inst, tevent->system, tevent->event);
0491 if (retval < 0) {
0492 err_msg("Error enabling event %s:%s\n", tevent->system,
0493 tevent->event ? : "*");
0494 return 1;
0495 }
0496
0497 retval = trace_event_enable_filter(instance, tevent);
0498 if (retval)
0499 return 1;
0500
0501 retval = trace_event_enable_trigger(instance, tevent);
0502 if (retval)
0503 return 1;
0504
0505 tevent->enabled = 1;
0506 tevent = tevent->next;
0507 }
0508
0509 return 0;
0510 }
0511
0512
0513
0514
0515 void trace_events_destroy(struct trace_instance *instance,
0516 struct trace_events *events)
0517 {
0518 if (!events)
0519 return;
0520
0521 trace_events_disable(instance, events);
0522 trace_events_free(events);
0523 }
0524
0525 int trace_is_off(struct trace_instance *tool, struct trace_instance *trace)
0526 {
0527
0528
0529
0530
0531 if (!tracefs_trace_is_on(tool->inst))
0532 return 1;
0533
0534
0535
0536
0537
0538 if (trace && !tracefs_trace_is_on(trace->inst))
0539 return 1;
0540
0541 return 0;
0542 }