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