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