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