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 } 138 139 if (trace->seq) 140 free(trace->seq); 141 142 if (trace->tep) 143 tep_free(trace->tep); 144 } 145 146 /* 147 * trace_instance_init - create an rtla trace instance 148 * 149 * It is more than the tracefs instance, as it contains other 150 * things required for the tracing, such as the local events and 151 * a seq file. 152 * 153 * Note that the trace instance is returned disabled. This allows 154 * the tool to apply some other configs, like setting priority 155 * to the kernel threads, before starting generating trace entries. 156 */ 157 int trace_instance_init(struct trace_instance *trace, char *tool_name) 158 { 159 trace->seq = calloc(1, sizeof(*trace->seq)); 160 if (!trace->seq) 161 goto out_err; 162 163 trace_seq_init(trace->seq); 164 165 trace->inst = create_instance(tool_name); 166 if (!trace->inst) 167 goto out_err; 168 169 trace->tep = tracefs_local_events(NULL); 170 if (!trace->tep) 171 goto out_err; 172 173 /* 174 * Let the main enable the record after setting some other 175 * things such as the priority of the tracer's threads. 176 */ 177 tracefs_trace_off(trace->inst); 178 179 return 0; 180 181 out_err: 182 trace_instance_destroy(trace); 183 return 1; 184 } 185 186 /* 187 * trace_instance_start - start tracing a given rtla instance 188 */ 189 int trace_instance_start(struct trace_instance *trace) 190 { 191 return tracefs_trace_on(trace->inst); 192 } 193