1 /* 2 * builtin-inject.c 3 * 4 * Builtin inject command: Examine the live mode (stdin) event stream 5 * and repipe it to stdout while optionally injecting additional 6 * events into it. 7 */ 8 #include "builtin.h" 9 10 #include "perf.h" 11 #include "util/session.h" 12 #include "util/tool.h" 13 #include "util/debug.h" 14 15 #include "util/parse-options.h" 16 17 static char const *input_name = "-"; 18 static bool inject_build_ids; 19 20 static int perf_event__repipe_synth(struct perf_tool *tool __used, 21 union perf_event *event, 22 struct machine *machine __used) 23 { 24 uint32_t size; 25 void *buf = event; 26 27 size = event->header.size; 28 29 while (size) { 30 int ret = write(STDOUT_FILENO, buf, size); 31 if (ret < 0) 32 return -errno; 33 34 size -= ret; 35 buf += ret; 36 } 37 38 return 0; 39 } 40 41 static int perf_event__repipe_op2_synth(struct perf_tool *tool, 42 union perf_event *event, 43 struct perf_session *session __used) 44 { 45 return perf_event__repipe_synth(tool, event, NULL); 46 } 47 48 static int perf_event__repipe_event_type_synth(struct perf_tool *tool, 49 union perf_event *event) 50 { 51 return perf_event__repipe_synth(tool, event, NULL); 52 } 53 54 static int perf_event__repipe_tracing_data_synth(union perf_event *event, 55 struct perf_session *session __used) 56 { 57 return perf_event__repipe_synth(NULL, event, NULL); 58 } 59 60 static int perf_event__repipe_attr(union perf_event *event, 61 struct perf_evlist **pevlist __used) 62 { 63 return perf_event__repipe_synth(NULL, event, NULL); 64 } 65 66 static int perf_event__repipe(struct perf_tool *tool, 67 union perf_event *event, 68 struct perf_sample *sample __used, 69 struct machine *machine) 70 { 71 return perf_event__repipe_synth(tool, event, machine); 72 } 73 74 static int perf_event__repipe_sample(struct perf_tool *tool, 75 union perf_event *event, 76 struct perf_sample *sample __used, 77 struct perf_evsel *evsel __used, 78 struct machine *machine) 79 { 80 return perf_event__repipe_synth(tool, event, machine); 81 } 82 83 static int perf_event__repipe_mmap(struct perf_tool *tool, 84 union perf_event *event, 85 struct perf_sample *sample, 86 struct machine *machine) 87 { 88 int err; 89 90 err = perf_event__process_mmap(tool, event, sample, machine); 91 perf_event__repipe(tool, event, sample, machine); 92 93 return err; 94 } 95 96 static int perf_event__repipe_task(struct perf_tool *tool, 97 union perf_event *event, 98 struct perf_sample *sample, 99 struct machine *machine) 100 { 101 int err; 102 103 err = perf_event__process_task(tool, event, sample, machine); 104 perf_event__repipe(tool, event, sample, machine); 105 106 return err; 107 } 108 109 static int perf_event__repipe_tracing_data(union perf_event *event, 110 struct perf_session *session) 111 { 112 int err; 113 114 perf_event__repipe_synth(NULL, event, NULL); 115 err = perf_event__process_tracing_data(event, session); 116 117 return err; 118 } 119 120 static int dso__read_build_id(struct dso *self) 121 { 122 if (self->has_build_id) 123 return 0; 124 125 if (filename__read_build_id(self->long_name, self->build_id, 126 sizeof(self->build_id)) > 0) { 127 self->has_build_id = true; 128 return 0; 129 } 130 131 return -1; 132 } 133 134 static int dso__inject_build_id(struct dso *self, struct perf_tool *tool, 135 struct machine *machine) 136 { 137 u16 misc = PERF_RECORD_MISC_USER; 138 int err; 139 140 if (dso__read_build_id(self) < 0) { 141 pr_debug("no build_id found for %s\n", self->long_name); 142 return -1; 143 } 144 145 if (self->kernel) 146 misc = PERF_RECORD_MISC_KERNEL; 147 148 err = perf_event__synthesize_build_id(tool, self, misc, perf_event__repipe, 149 machine); 150 if (err) { 151 pr_err("Can't synthesize build_id event for %s\n", self->long_name); 152 return -1; 153 } 154 155 return 0; 156 } 157 158 static int perf_event__inject_buildid(struct perf_tool *tool, 159 union perf_event *event, 160 struct perf_sample *sample, 161 struct perf_evsel *evsel __used, 162 struct machine *machine) 163 { 164 struct addr_location al; 165 struct thread *thread; 166 u8 cpumode; 167 168 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 169 170 thread = machine__findnew_thread(machine, event->ip.pid); 171 if (thread == NULL) { 172 pr_err("problem processing %d event, skipping it.\n", 173 event->header.type); 174 goto repipe; 175 } 176 177 thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION, 178 event->ip.ip, &al); 179 180 if (al.map != NULL) { 181 if (!al.map->dso->hit) { 182 al.map->dso->hit = 1; 183 if (map__load(al.map, NULL) >= 0) { 184 dso__inject_build_id(al.map->dso, tool, machine); 185 /* 186 * If this fails, too bad, let the other side 187 * account this as unresolved. 188 */ 189 } else 190 pr_warning("no symbols found in %s, maybe " 191 "install a debug package?\n", 192 al.map->dso->long_name); 193 } 194 } 195 196 repipe: 197 perf_event__repipe(tool, event, sample, machine); 198 return 0; 199 } 200 201 struct perf_tool perf_inject = { 202 .sample = perf_event__repipe_sample, 203 .mmap = perf_event__repipe, 204 .comm = perf_event__repipe, 205 .fork = perf_event__repipe, 206 .exit = perf_event__repipe, 207 .lost = perf_event__repipe, 208 .read = perf_event__repipe_sample, 209 .throttle = perf_event__repipe, 210 .unthrottle = perf_event__repipe, 211 .attr = perf_event__repipe_attr, 212 .event_type = perf_event__repipe_event_type_synth, 213 .tracing_data = perf_event__repipe_tracing_data_synth, 214 .build_id = perf_event__repipe_op2_synth, 215 }; 216 217 extern volatile int session_done; 218 219 static void sig_handler(int sig __attribute__((__unused__))) 220 { 221 session_done = 1; 222 } 223 224 static int __cmd_inject(void) 225 { 226 struct perf_session *session; 227 int ret = -EINVAL; 228 229 signal(SIGINT, sig_handler); 230 231 if (inject_build_ids) { 232 perf_inject.sample = perf_event__inject_buildid; 233 perf_inject.mmap = perf_event__repipe_mmap; 234 perf_inject.fork = perf_event__repipe_task; 235 perf_inject.tracing_data = perf_event__repipe_tracing_data; 236 } 237 238 session = perf_session__new(input_name, O_RDONLY, false, true, &perf_inject); 239 if (session == NULL) 240 return -ENOMEM; 241 242 ret = perf_session__process_events(session, &perf_inject); 243 244 perf_session__delete(session); 245 246 return ret; 247 } 248 249 static const char * const report_usage[] = { 250 "perf inject [<options>]", 251 NULL 252 }; 253 254 static const struct option options[] = { 255 OPT_BOOLEAN('b', "build-ids", &inject_build_ids, 256 "Inject build-ids into the output stream"), 257 OPT_INCR('v', "verbose", &verbose, 258 "be more verbose (show build ids, etc)"), 259 OPT_END() 260 }; 261 262 int cmd_inject(int argc, const char **argv, const char *prefix __used) 263 { 264 argc = parse_options(argc, argv, options, report_usage, 0); 265 266 /* 267 * Any (unrecognized) arguments left? 268 */ 269 if (argc) 270 usage_with_options(report_usage, options); 271 272 if (symbol__init() < 0) 273 return -1; 274 275 return __cmd_inject(); 276 } 277