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