blob: a706ed57f94ee438102414ed1f1dacfe7e09faf7 [file] [log] [blame]
Tom Zanussi454c4072010-05-01 01:41:20 -05001/*
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"
Arnaldo Carvalho de Melo45694aa2011-11-28 08:30:20 -020012#include "util/tool.h"
Tom Zanussi454c4072010-05-01 01:41:20 -050013#include "util/debug.h"
14
15#include "util/parse-options.h"
16
Arnaldo Carvalho de Melo5ded57a2012-09-30 19:54:10 -030017struct perf_inject {
18 struct perf_tool tool;
19 bool build_ids;
Andrew Vagine558a5b2012-08-07 16:56:02 +040020 const char *input_name;
21 int pipe_output,
22 output;
23 u64 bytes_written;
Arnaldo Carvalho de Melo5ded57a2012-09-30 19:54:10 -030024};
Tom Zanussi454c4072010-05-01 01:41:20 -050025
Andrew Vagine558a5b2012-08-07 16:56:02 +040026static int perf_event__repipe_synth(struct perf_tool *tool,
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -020027 union perf_event *event,
Irina Tirdea1d037ca2012-09-11 01:15:03 +030028 struct machine *machine __maybe_unused)
Tom Zanussi454c4072010-05-01 01:41:20 -050029{
Andrew Vagine558a5b2012-08-07 16:56:02 +040030 struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
Tom Zanussi454c4072010-05-01 01:41:20 -050031 uint32_t size;
32 void *buf = event;
33
34 size = event->header.size;
35
36 while (size) {
Andrew Vagine558a5b2012-08-07 16:56:02 +040037 int ret = write(inject->output, buf, size);
Tom Zanussi454c4072010-05-01 01:41:20 -050038 if (ret < 0)
39 return -errno;
40
41 size -= ret;
42 buf += ret;
Andrew Vagine558a5b2012-08-07 16:56:02 +040043 inject->bytes_written += ret;
Tom Zanussi454c4072010-05-01 01:41:20 -050044 }
45
46 return 0;
47}
48
Arnaldo Carvalho de Melo45694aa2011-11-28 08:30:20 -020049static int perf_event__repipe_op2_synth(struct perf_tool *tool,
Arnaldo Carvalho de Melo743eb862011-11-28 07:56:39 -020050 union perf_event *event,
Irina Tirdea1d037ca2012-09-11 01:15:03 +030051 struct perf_session *session
52 __maybe_unused)
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -020053{
Arnaldo Carvalho de Melo45694aa2011-11-28 08:30:20 -020054 return perf_event__repipe_synth(tool, event, NULL);
Arnaldo Carvalho de Melo743eb862011-11-28 07:56:39 -020055}
56
Arnaldo Carvalho de Melo45694aa2011-11-28 08:30:20 -020057static int perf_event__repipe_event_type_synth(struct perf_tool *tool,
Arnaldo Carvalho de Melo743eb862011-11-28 07:56:39 -020058 union perf_event *event)
59{
Arnaldo Carvalho de Melo45694aa2011-11-28 08:30:20 -020060 return perf_event__repipe_synth(tool, event, NULL);
Arnaldo Carvalho de Melo743eb862011-11-28 07:56:39 -020061}
62
63static int perf_event__repipe_tracing_data_synth(union perf_event *event,
Irina Tirdea1d037ca2012-09-11 01:15:03 +030064 struct perf_session *session
65 __maybe_unused)
Arnaldo Carvalho de Melo743eb862011-11-28 07:56:39 -020066{
67 return perf_event__repipe_synth(NULL, event, NULL);
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -020068}
69
Arnaldo Carvalho de Melo10d0f082011-11-11 22:45:41 -020070static int perf_event__repipe_attr(union perf_event *event,
Irina Tirdea1d037ca2012-09-11 01:15:03 +030071 struct perf_evlist **pevlist __maybe_unused)
Arnaldo Carvalho de Melo10d0f082011-11-11 22:45:41 -020072{
Stephane Eranian1a1ed1b2012-05-15 13:28:11 +020073 int ret;
74 ret = perf_event__process_attr(event, pevlist);
75 if (ret)
76 return ret;
77
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -020078 return perf_event__repipe_synth(NULL, event, NULL);
Arnaldo Carvalho de Melo10d0f082011-11-11 22:45:41 -020079}
80
Arnaldo Carvalho de Melo45694aa2011-11-28 08:30:20 -020081static int perf_event__repipe(struct perf_tool *tool,
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -020082 union perf_event *event,
Irina Tirdea1d037ca2012-09-11 01:15:03 +030083 struct perf_sample *sample __maybe_unused,
Arnaldo Carvalho de Melo743eb862011-11-28 07:56:39 -020084 struct machine *machine)
Arnaldo Carvalho de Melo640c03c2010-12-02 14:10:21 -020085{
Arnaldo Carvalho de Melo45694aa2011-11-28 08:30:20 -020086 return perf_event__repipe_synth(tool, event, machine);
Arnaldo Carvalho de Melo640c03c2010-12-02 14:10:21 -020087}
88
Arnaldo Carvalho de Melo45694aa2011-11-28 08:30:20 -020089static int perf_event__repipe_sample(struct perf_tool *tool,
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -020090 union perf_event *event,
Irina Tirdea1d037ca2012-09-11 01:15:03 +030091 struct perf_sample *sample __maybe_unused,
92 struct perf_evsel *evsel __maybe_unused,
Arnaldo Carvalho de Melo743eb862011-11-28 07:56:39 -020093 struct machine *machine)
Arnaldo Carvalho de Melo9e69c212011-03-15 15:44:01 -030094{
Arnaldo Carvalho de Melo45694aa2011-11-28 08:30:20 -020095 return perf_event__repipe_synth(tool, event, machine);
Arnaldo Carvalho de Melo9e69c212011-03-15 15:44:01 -030096}
97
Arnaldo Carvalho de Melo45694aa2011-11-28 08:30:20 -020098static int perf_event__repipe_mmap(struct perf_tool *tool,
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -020099 union perf_event *event,
Arnaldo Carvalho de Melo8115d602011-01-29 14:01:45 -0200100 struct perf_sample *sample,
Arnaldo Carvalho de Melo743eb862011-11-28 07:56:39 -0200101 struct machine *machine)
Tom Zanussi454c4072010-05-01 01:41:20 -0500102{
103 int err;
104
Arnaldo Carvalho de Melo45694aa2011-11-28 08:30:20 -0200105 err = perf_event__process_mmap(tool, event, sample, machine);
106 perf_event__repipe(tool, event, sample, machine);
Tom Zanussi454c4072010-05-01 01:41:20 -0500107
108 return err;
109}
110
Arnaldo Carvalho de Melof62d3f02012-10-06 15:44:59 -0300111static int perf_event__repipe_fork(struct perf_tool *tool,
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200112 union perf_event *event,
Arnaldo Carvalho de Melo8115d602011-01-29 14:01:45 -0200113 struct perf_sample *sample,
Arnaldo Carvalho de Melo743eb862011-11-28 07:56:39 -0200114 struct machine *machine)
Tom Zanussi454c4072010-05-01 01:41:20 -0500115{
116 int err;
117
Arnaldo Carvalho de Melof62d3f02012-10-06 15:44:59 -0300118 err = perf_event__process_fork(tool, event, sample, machine);
Arnaldo Carvalho de Melo45694aa2011-11-28 08:30:20 -0200119 perf_event__repipe(tool, event, sample, machine);
Tom Zanussi454c4072010-05-01 01:41:20 -0500120
121 return err;
122}
123
Arnaldo Carvalho de Melo8115d602011-01-29 14:01:45 -0200124static int perf_event__repipe_tracing_data(union perf_event *event,
125 struct perf_session *session)
Tom Zanussi454c4072010-05-01 01:41:20 -0500126{
127 int err;
128
Arnaldo Carvalho de Melo743eb862011-11-28 07:56:39 -0200129 perf_event__repipe_synth(NULL, event, NULL);
Arnaldo Carvalho de Melo8115d602011-01-29 14:01:45 -0200130 err = perf_event__process_tracing_data(event, session);
Tom Zanussi454c4072010-05-01 01:41:20 -0500131
132 return err;
133}
134
Arnaldo Carvalho de Melo090f7202010-05-02 19:46:36 -0300135static int dso__read_build_id(struct dso *self)
Tom Zanussi454c4072010-05-01 01:41:20 -0500136{
Arnaldo Carvalho de Melo090f7202010-05-02 19:46:36 -0300137 if (self->has_build_id)
138 return 0;
Tom Zanussi454c4072010-05-01 01:41:20 -0500139
Arnaldo Carvalho de Melo090f7202010-05-02 19:46:36 -0300140 if (filename__read_build_id(self->long_name, self->build_id,
141 sizeof(self->build_id)) > 0) {
142 self->has_build_id = true;
143 return 0;
Tom Zanussi454c4072010-05-01 01:41:20 -0500144 }
145
Arnaldo Carvalho de Melo090f7202010-05-02 19:46:36 -0300146 return -1;
147}
Tom Zanussi454c4072010-05-01 01:41:20 -0500148
Arnaldo Carvalho de Melo45694aa2011-11-28 08:30:20 -0200149static int dso__inject_build_id(struct dso *self, struct perf_tool *tool,
Arnaldo Carvalho de Melo743eb862011-11-28 07:56:39 -0200150 struct machine *machine)
Arnaldo Carvalho de Melo090f7202010-05-02 19:46:36 -0300151{
152 u16 misc = PERF_RECORD_MISC_USER;
Arnaldo Carvalho de Melo090f7202010-05-02 19:46:36 -0300153 int err;
Tom Zanussi454c4072010-05-01 01:41:20 -0500154
Arnaldo Carvalho de Melo090f7202010-05-02 19:46:36 -0300155 if (dso__read_build_id(self) < 0) {
156 pr_debug("no build_id found for %s\n", self->long_name);
157 return -1;
158 }
Tom Zanussi454c4072010-05-01 01:41:20 -0500159
Arnaldo Carvalho de Melo090f7202010-05-02 19:46:36 -0300160 if (self->kernel)
161 misc = PERF_RECORD_MISC_KERNEL;
162
Arnaldo Carvalho de Melo45694aa2011-11-28 08:30:20 -0200163 err = perf_event__synthesize_build_id(tool, self, misc, perf_event__repipe,
Arnaldo Carvalho de Melo743eb862011-11-28 07:56:39 -0200164 machine);
Arnaldo Carvalho de Melo090f7202010-05-02 19:46:36 -0300165 if (err) {
166 pr_err("Can't synthesize build_id event for %s\n", self->long_name);
Tom Zanussi454c4072010-05-01 01:41:20 -0500167 return -1;
168 }
169
170 return 0;
171}
172
Arnaldo Carvalho de Melo45694aa2011-11-28 08:30:20 -0200173static int perf_event__inject_buildid(struct perf_tool *tool,
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200174 union perf_event *event,
Arnaldo Carvalho de Melo8115d602011-01-29 14:01:45 -0200175 struct perf_sample *sample,
Irina Tirdea1d037ca2012-09-11 01:15:03 +0300176 struct perf_evsel *evsel __maybe_unused,
Arnaldo Carvalho de Melo743eb862011-11-28 07:56:39 -0200177 struct machine *machine)
Tom Zanussi454c4072010-05-01 01:41:20 -0500178{
179 struct addr_location al;
180 struct thread *thread;
181 u8 cpumode;
Tom Zanussi454c4072010-05-01 01:41:20 -0500182
183 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
184
Arnaldo Carvalho de Melo743eb862011-11-28 07:56:39 -0200185 thread = machine__findnew_thread(machine, event->ip.pid);
Tom Zanussi454c4072010-05-01 01:41:20 -0500186 if (thread == NULL) {
187 pr_err("problem processing %d event, skipping it.\n",
188 event->header.type);
Tom Zanussi454c4072010-05-01 01:41:20 -0500189 goto repipe;
190 }
191
Arnaldo Carvalho de Melo743eb862011-11-28 07:56:39 -0200192 thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION,
193 event->ip.ip, &al);
Tom Zanussi454c4072010-05-01 01:41:20 -0500194
195 if (al.map != NULL) {
196 if (!al.map->dso->hit) {
197 al.map->dso->hit = 1;
Arnaldo Carvalho de Melo090f7202010-05-02 19:46:36 -0300198 if (map__load(al.map, NULL) >= 0) {
Arnaldo Carvalho de Melo45694aa2011-11-28 08:30:20 -0200199 dso__inject_build_id(al.map->dso, tool, machine);
Arnaldo Carvalho de Melo090f7202010-05-02 19:46:36 -0300200 /*
201 * If this fails, too bad, let the other side
202 * account this as unresolved.
203 */
Namhyung Kim393be2e2012-08-06 13:41:21 +0900204 } else {
Namhyung Kim29a0fc92012-09-28 18:31:59 +0900205#ifdef LIBELF_SUPPORT
Tom Zanussi454c4072010-05-01 01:41:20 -0500206 pr_warning("no symbols found in %s, maybe "
207 "install a debug package?\n",
208 al.map->dso->long_name);
Namhyung Kim393be2e2012-08-06 13:41:21 +0900209#endif
210 }
Tom Zanussi454c4072010-05-01 01:41:20 -0500211 }
212 }
213
214repipe:
Arnaldo Carvalho de Melo45694aa2011-11-28 08:30:20 -0200215 perf_event__repipe(tool, event, sample, machine);
Arnaldo Carvalho de Melo090f7202010-05-02 19:46:36 -0300216 return 0;
Tom Zanussi454c4072010-05-01 01:41:20 -0500217}
218
Tom Zanussi454c4072010-05-01 01:41:20 -0500219extern volatile int session_done;
220
Irina Tirdea1d037ca2012-09-11 01:15:03 +0300221static void sig_handler(int sig __maybe_unused)
Tom Zanussi454c4072010-05-01 01:41:20 -0500222{
223 session_done = 1;
224}
225
Arnaldo Carvalho de Melo5ded57a2012-09-30 19:54:10 -0300226static int __cmd_inject(struct perf_inject *inject)
Tom Zanussi454c4072010-05-01 01:41:20 -0500227{
228 struct perf_session *session;
229 int ret = -EINVAL;
230
231 signal(SIGINT, sig_handler);
232
Arnaldo Carvalho de Melo5ded57a2012-09-30 19:54:10 -0300233 if (inject->build_ids) {
234 inject->tool.sample = perf_event__inject_buildid;
235 inject->tool.mmap = perf_event__repipe_mmap;
Arnaldo Carvalho de Melof62d3f02012-10-06 15:44:59 -0300236 inject->tool.fork = perf_event__repipe_fork;
Arnaldo Carvalho de Melo5ded57a2012-09-30 19:54:10 -0300237 inject->tool.tracing_data = perf_event__repipe_tracing_data;
Tom Zanussi454c4072010-05-01 01:41:20 -0500238 }
239
Andrew Vagine558a5b2012-08-07 16:56:02 +0400240 session = perf_session__new(inject->input_name, O_RDONLY, false, true, &inject->tool);
Tom Zanussi454c4072010-05-01 01:41:20 -0500241 if (session == NULL)
242 return -ENOMEM;
243
Andrew Vagine558a5b2012-08-07 16:56:02 +0400244 if (!inject->pipe_output)
245 lseek(inject->output, session->header.data_offset, SEEK_SET);
246
Arnaldo Carvalho de Melo5ded57a2012-09-30 19:54:10 -0300247 ret = perf_session__process_events(session, &inject->tool);
Tom Zanussi454c4072010-05-01 01:41:20 -0500248
Andrew Vagine558a5b2012-08-07 16:56:02 +0400249 if (!inject->pipe_output) {
250 session->header.data_size = inject->bytes_written;
251 perf_session__write_header(session, session->evlist, inject->output, true);
252 }
253
Tom Zanussi454c4072010-05-01 01:41:20 -0500254 perf_session__delete(session);
255
256 return ret;
257}
258
Irina Tirdea1d037ca2012-09-11 01:15:03 +0300259int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
Tom Zanussi454c4072010-05-01 01:41:20 -0500260{
Arnaldo Carvalho de Melo5ded57a2012-09-30 19:54:10 -0300261 struct perf_inject inject = {
262 .tool = {
263 .sample = perf_event__repipe_sample,
264 .mmap = perf_event__repipe,
265 .comm = perf_event__repipe,
266 .fork = perf_event__repipe,
267 .exit = perf_event__repipe,
268 .lost = perf_event__repipe,
269 .read = perf_event__repipe_sample,
270 .throttle = perf_event__repipe,
271 .unthrottle = perf_event__repipe,
272 .attr = perf_event__repipe_attr,
273 .event_type = perf_event__repipe_event_type_synth,
274 .tracing_data = perf_event__repipe_tracing_data_synth,
275 .build_id = perf_event__repipe_op2_synth,
276 },
Andrew Vagine558a5b2012-08-07 16:56:02 +0400277 .input_name = "-",
Arnaldo Carvalho de Melo5ded57a2012-09-30 19:54:10 -0300278 };
Andrew Vagine558a5b2012-08-07 16:56:02 +0400279 const char *output_name = "-";
Arnaldo Carvalho de Melo5ded57a2012-09-30 19:54:10 -0300280 const struct option options[] = {
281 OPT_BOOLEAN('b', "build-ids", &inject.build_ids,
282 "Inject build-ids into the output stream"),
Andrew Vagine558a5b2012-08-07 16:56:02 +0400283 OPT_STRING('i', "input", &inject.input_name, "file",
284 "input file name"),
285 OPT_STRING('o', "output", &output_name, "file",
286 "output file name"),
Arnaldo Carvalho de Melo5ded57a2012-09-30 19:54:10 -0300287 OPT_INCR('v', "verbose", &verbose,
288 "be more verbose (show build ids, etc)"),
289 OPT_END()
290 };
Arnaldo Carvalho de Melo002439e2012-10-01 15:20:58 -0300291 const char * const inject_usage[] = {
292 "perf inject [<options>]",
293 NULL
294 };
Arnaldo Carvalho de Melo5ded57a2012-09-30 19:54:10 -0300295
Arnaldo Carvalho de Melo002439e2012-10-01 15:20:58 -0300296 argc = parse_options(argc, argv, options, inject_usage, 0);
Tom Zanussi454c4072010-05-01 01:41:20 -0500297
298 /*
299 * Any (unrecognized) arguments left?
300 */
301 if (argc)
Arnaldo Carvalho de Melo002439e2012-10-01 15:20:58 -0300302 usage_with_options(inject_usage, options);
Tom Zanussi454c4072010-05-01 01:41:20 -0500303
Andrew Vagine558a5b2012-08-07 16:56:02 +0400304 if (!strcmp(output_name, "-")) {
305 inject.pipe_output = 1;
306 inject.output = STDOUT_FILENO;
307 } else {
308 inject.output = open(output_name, O_CREAT | O_WRONLY | O_TRUNC,
309 S_IRUSR | S_IWUSR);
310 if (inject.output < 0) {
311 perror("failed to create output file");
312 return -1;
313 }
314 }
315
Tom Zanussi454c4072010-05-01 01:41:20 -0500316 if (symbol__init() < 0)
317 return -1;
318
Arnaldo Carvalho de Melo5ded57a2012-09-30 19:54:10 -0300319 return __cmd_inject(&inject);
Tom Zanussi454c4072010-05-01 01:41:20 -0500320}