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/debug.h" 13 14 #include "util/parse-options.h" 15 16 static char const *input_name = "-"; 17 static bool inject_build_ids; 18 19 static int event__repipe_synth(event_t *event, 20 struct perf_session *session __used) 21 { 22 uint32_t size; 23 void *buf = event; 24 25 size = event->header.size; 26 27 while (size) { 28 int ret = write(STDOUT_FILENO, buf, size); 29 if (ret < 0) 30 return -errno; 31 32 size -= ret; 33 buf += ret; 34 } 35 36 return 0; 37 } 38 39 static int event__repipe(event_t *event, struct sample_data *sample __used, 40 struct perf_session *session) 41 { 42 return event__repipe_synth(event, session); 43 } 44 45 static int event__repipe_mmap(event_t *self, struct sample_data *sample, 46 struct perf_session *session) 47 { 48 int err; 49 50 err = event__process_mmap(self, sample, session); 51 event__repipe(self, sample, session); 52 53 return err; 54 } 55 56 static int event__repipe_task(event_t *self, struct sample_data *sample, 57 struct perf_session *session) 58 { 59 int err; 60 61 err = event__process_task(self, sample, session); 62 event__repipe(self, sample, session); 63 64 return err; 65 } 66 67 static int event__repipe_tracing_data(event_t *self, 68 struct perf_session *session) 69 { 70 int err; 71 72 event__repipe_synth(self, session); 73 err = event__process_tracing_data(self, session); 74 75 return err; 76 } 77 78 static int dso__read_build_id(struct dso *self) 79 { 80 if (self->has_build_id) 81 return 0; 82 83 if (filename__read_build_id(self->long_name, self->build_id, 84 sizeof(self->build_id)) > 0) { 85 self->has_build_id = true; 86 return 0; 87 } 88 89 return -1; 90 } 91 92 static int dso__inject_build_id(struct dso *self, struct perf_session *session) 93 { 94 u16 misc = PERF_RECORD_MISC_USER; 95 struct machine *machine; 96 int err; 97 98 if (dso__read_build_id(self) < 0) { 99 pr_debug("no build_id found for %s\n", self->long_name); 100 return -1; 101 } 102 103 machine = perf_session__find_host_machine(session); 104 if (machine == NULL) { 105 pr_err("Can't find machine for session\n"); 106 return -1; 107 } 108 109 if (self->kernel) 110 misc = PERF_RECORD_MISC_KERNEL; 111 112 err = event__synthesize_build_id(self, misc, event__repipe, 113 machine, session); 114 if (err) { 115 pr_err("Can't synthesize build_id event for %s\n", self->long_name); 116 return -1; 117 } 118 119 return 0; 120 } 121 122 static int event__inject_buildid(event_t *event, struct sample_data *sample, 123 struct perf_session *session) 124 { 125 struct addr_location al; 126 struct thread *thread; 127 u8 cpumode; 128 129 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 130 131 thread = perf_session__findnew(session, event->ip.pid); 132 if (thread == NULL) { 133 pr_err("problem processing %d event, skipping it.\n", 134 event->header.type); 135 goto repipe; 136 } 137 138 thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION, 139 event->ip.pid, event->ip.ip, &al); 140 141 if (al.map != NULL) { 142 if (!al.map->dso->hit) { 143 al.map->dso->hit = 1; 144 if (map__load(al.map, NULL) >= 0) { 145 dso__inject_build_id(al.map->dso, session); 146 /* 147 * If this fails, too bad, let the other side 148 * account this as unresolved. 149 */ 150 } else 151 pr_warning("no symbols found in %s, maybe " 152 "install a debug package?\n", 153 al.map->dso->long_name); 154 } 155 } 156 157 repipe: 158 event__repipe(event, sample, session); 159 return 0; 160 } 161 162 struct perf_event_ops inject_ops = { 163 .sample = event__repipe, 164 .mmap = event__repipe, 165 .comm = event__repipe, 166 .fork = event__repipe, 167 .exit = event__repipe, 168 .lost = event__repipe, 169 .read = event__repipe, 170 .throttle = event__repipe, 171 .unthrottle = event__repipe, 172 .attr = event__repipe_synth, 173 .event_type = event__repipe_synth, 174 .tracing_data = event__repipe_synth, 175 .build_id = event__repipe_synth, 176 }; 177 178 extern volatile int session_done; 179 180 static void sig_handler(int sig __attribute__((__unused__))) 181 { 182 session_done = 1; 183 } 184 185 static int __cmd_inject(void) 186 { 187 struct perf_session *session; 188 int ret = -EINVAL; 189 190 signal(SIGINT, sig_handler); 191 192 if (inject_build_ids) { 193 inject_ops.sample = event__inject_buildid; 194 inject_ops.mmap = event__repipe_mmap; 195 inject_ops.fork = event__repipe_task; 196 inject_ops.tracing_data = event__repipe_tracing_data; 197 } 198 199 session = perf_session__new(input_name, O_RDONLY, false, true, &inject_ops); 200 if (session == NULL) 201 return -ENOMEM; 202 203 ret = perf_session__process_events(session, &inject_ops); 204 205 perf_session__delete(session); 206 207 return ret; 208 } 209 210 static const char * const report_usage[] = { 211 "perf inject [<options>]", 212 NULL 213 }; 214 215 static const struct option options[] = { 216 OPT_BOOLEAN('b', "build-ids", &inject_build_ids, 217 "Inject build-ids into the output stream"), 218 OPT_INCR('v', "verbose", &verbose, 219 "be more verbose (show build ids, etc)"), 220 OPT_END() 221 }; 222 223 int cmd_inject(int argc, const char **argv, const char *prefix __used) 224 { 225 argc = parse_options(argc, argv, options, report_usage, 0); 226 227 /* 228 * Any (unrecognized) arguments left? 229 */ 230 if (argc) 231 usage_with_options(report_usage, options); 232 233 if (symbol__init() < 0) 234 return -1; 235 236 return __cmd_inject(); 237 } 238