blob: 6ce6d80b59db32534133b44f48f97b6af5ff22c4 [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"
12#include "util/debug.h"
13
14#include "util/parse-options.h"
15
16static char const *input_name = "-";
17static bool inject_build_ids;
18
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -020019static int perf_event__repipe_synth(struct perf_event_ops *ops __used,
20 union perf_event *event,
Arnaldo Carvalho de Melo8115d602011-01-29 14:01:45 -020021 struct perf_session *session __used)
Tom Zanussi454c4072010-05-01 01:41:20 -050022{
23 uint32_t size;
24 void *buf = event;
25
26 size = event->header.size;
27
28 while (size) {
29 int ret = write(STDOUT_FILENO, buf, size);
30 if (ret < 0)
31 return -errno;
32
33 size -= ret;
34 buf += ret;
35 }
36
37 return 0;
38}
39
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -020040static int perf_event__repipe_tracing_data_synth(union perf_event *event,
41 struct perf_session *session)
42{
43 return perf_event__repipe_synth(NULL, event, session);
44}
45
Arnaldo Carvalho de Melo10d0f082011-11-11 22:45:41 -020046static int perf_event__repipe_attr(union perf_event *event,
47 struct perf_evlist **pevlist __used)
48{
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -020049 return perf_event__repipe_synth(NULL, event, NULL);
Arnaldo Carvalho de Melo10d0f082011-11-11 22:45:41 -020050}
51
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -020052static int perf_event__repipe(struct perf_event_ops *ops,
53 union perf_event *event,
Arnaldo Carvalho de Melo8115d602011-01-29 14:01:45 -020054 struct perf_sample *sample __used,
55 struct perf_session *session)
Arnaldo Carvalho de Melo640c03c2010-12-02 14:10:21 -020056{
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -020057 return perf_event__repipe_synth(ops, event, session);
Arnaldo Carvalho de Melo640c03c2010-12-02 14:10:21 -020058}
59
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -020060static int perf_event__repipe_sample(struct perf_event_ops *ops,
61 union perf_event *event,
Arnaldo Carvalho de Melo9e69c212011-03-15 15:44:01 -030062 struct perf_sample *sample __used,
63 struct perf_evsel *evsel __used,
64 struct perf_session *session)
65{
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -020066 return perf_event__repipe_synth(ops, event, session);
Arnaldo Carvalho de Melo9e69c212011-03-15 15:44:01 -030067}
68
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -020069static int perf_event__repipe_mmap(struct perf_event_ops *ops,
70 union perf_event *event,
Arnaldo Carvalho de Melo8115d602011-01-29 14:01:45 -020071 struct perf_sample *sample,
72 struct perf_session *session)
Tom Zanussi454c4072010-05-01 01:41:20 -050073{
74 int err;
75
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -020076 err = perf_event__process_mmap(ops, event, sample, session);
77 perf_event__repipe(ops, event, sample, session);
Tom Zanussi454c4072010-05-01 01:41:20 -050078
79 return err;
80}
81
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -020082static int perf_event__repipe_task(struct perf_event_ops *ops,
83 union perf_event *event,
Arnaldo Carvalho de Melo8115d602011-01-29 14:01:45 -020084 struct perf_sample *sample,
85 struct perf_session *session)
Tom Zanussi454c4072010-05-01 01:41:20 -050086{
87 int err;
88
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -020089 err = perf_event__process_task(ops, event, sample, session);
90 perf_event__repipe(ops, event, sample, session);
Tom Zanussi454c4072010-05-01 01:41:20 -050091
92 return err;
93}
94
Arnaldo Carvalho de Melo8115d602011-01-29 14:01:45 -020095static int perf_event__repipe_tracing_data(union perf_event *event,
96 struct perf_session *session)
Tom Zanussi454c4072010-05-01 01:41:20 -050097{
98 int err;
99
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200100 perf_event__repipe_synth(NULL, event, session);
Arnaldo Carvalho de Melo8115d602011-01-29 14:01:45 -0200101 err = perf_event__process_tracing_data(event, session);
Tom Zanussi454c4072010-05-01 01:41:20 -0500102
103 return err;
104}
105
Arnaldo Carvalho de Melo090f7202010-05-02 19:46:36 -0300106static int dso__read_build_id(struct dso *self)
Tom Zanussi454c4072010-05-01 01:41:20 -0500107{
Arnaldo Carvalho de Melo090f7202010-05-02 19:46:36 -0300108 if (self->has_build_id)
109 return 0;
Tom Zanussi454c4072010-05-01 01:41:20 -0500110
Arnaldo Carvalho de Melo090f7202010-05-02 19:46:36 -0300111 if (filename__read_build_id(self->long_name, self->build_id,
112 sizeof(self->build_id)) > 0) {
113 self->has_build_id = true;
114 return 0;
Tom Zanussi454c4072010-05-01 01:41:20 -0500115 }
116
Arnaldo Carvalho de Melo090f7202010-05-02 19:46:36 -0300117 return -1;
118}
Tom Zanussi454c4072010-05-01 01:41:20 -0500119
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200120static int dso__inject_build_id(struct dso *self, struct perf_event_ops *ops,
121 struct perf_session *session)
Arnaldo Carvalho de Melo090f7202010-05-02 19:46:36 -0300122{
123 u16 misc = PERF_RECORD_MISC_USER;
124 struct machine *machine;
125 int err;
Tom Zanussi454c4072010-05-01 01:41:20 -0500126
Arnaldo Carvalho de Melo090f7202010-05-02 19:46:36 -0300127 if (dso__read_build_id(self) < 0) {
128 pr_debug("no build_id found for %s\n", self->long_name);
129 return -1;
130 }
Tom Zanussi454c4072010-05-01 01:41:20 -0500131
Arnaldo Carvalho de Melo090f7202010-05-02 19:46:36 -0300132 machine = perf_session__find_host_machine(session);
133 if (machine == NULL) {
134 pr_err("Can't find machine for session\n");
135 return -1;
136 }
137
138 if (self->kernel)
139 misc = PERF_RECORD_MISC_KERNEL;
140
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200141 err = perf_event__synthesize_build_id(ops, self, misc, perf_event__repipe,
Arnaldo Carvalho de Melo8115d602011-01-29 14:01:45 -0200142 machine, session);
Arnaldo Carvalho de Melo090f7202010-05-02 19:46:36 -0300143 if (err) {
144 pr_err("Can't synthesize build_id event for %s\n", self->long_name);
Tom Zanussi454c4072010-05-01 01:41:20 -0500145 return -1;
146 }
147
148 return 0;
149}
150
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200151static int perf_event__inject_buildid(struct perf_event_ops *ops,
152 union perf_event *event,
Arnaldo Carvalho de Melo8115d602011-01-29 14:01:45 -0200153 struct perf_sample *sample,
Arnaldo Carvalho de Melo9e69c212011-03-15 15:44:01 -0300154 struct perf_evsel *evsel __used,
Arnaldo Carvalho de Melo8115d602011-01-29 14:01:45 -0200155 struct perf_session *session)
Tom Zanussi454c4072010-05-01 01:41:20 -0500156{
157 struct addr_location al;
158 struct thread *thread;
159 u8 cpumode;
Tom Zanussi454c4072010-05-01 01:41:20 -0500160
161 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
162
163 thread = perf_session__findnew(session, event->ip.pid);
164 if (thread == NULL) {
165 pr_err("problem processing %d event, skipping it.\n",
166 event->header.type);
Tom Zanussi454c4072010-05-01 01:41:20 -0500167 goto repipe;
168 }
169
170 thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION,
171 event->ip.pid, event->ip.ip, &al);
172
173 if (al.map != NULL) {
174 if (!al.map->dso->hit) {
175 al.map->dso->hit = 1;
Arnaldo Carvalho de Melo090f7202010-05-02 19:46:36 -0300176 if (map__load(al.map, NULL) >= 0) {
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200177 dso__inject_build_id(al.map->dso, ops, session);
Arnaldo Carvalho de Melo090f7202010-05-02 19:46:36 -0300178 /*
179 * If this fails, too bad, let the other side
180 * account this as unresolved.
181 */
182 } else
Tom Zanussi454c4072010-05-01 01:41:20 -0500183 pr_warning("no symbols found in %s, maybe "
184 "install a debug package?\n",
185 al.map->dso->long_name);
186 }
187 }
188
189repipe:
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200190 perf_event__repipe(ops, event, sample, session);
Arnaldo Carvalho de Melo090f7202010-05-02 19:46:36 -0300191 return 0;
Tom Zanussi454c4072010-05-01 01:41:20 -0500192}
193
194struct perf_event_ops inject_ops = {
Arnaldo Carvalho de Melo9e69c212011-03-15 15:44:01 -0300195 .sample = perf_event__repipe_sample,
Arnaldo Carvalho de Melo8115d602011-01-29 14:01:45 -0200196 .mmap = perf_event__repipe,
197 .comm = perf_event__repipe,
198 .fork = perf_event__repipe,
199 .exit = perf_event__repipe,
200 .lost = perf_event__repipe,
201 .read = perf_event__repipe,
202 .throttle = perf_event__repipe,
203 .unthrottle = perf_event__repipe,
Arnaldo Carvalho de Melo10d0f082011-11-11 22:45:41 -0200204 .attr = perf_event__repipe_attr,
Arnaldo Carvalho de Melod20deb62011-11-25 08:19:45 -0200205 .event_type = perf_event__repipe_synth,
206 .tracing_data = perf_event__repipe_tracing_data_synth,
207 .build_id = perf_event__repipe_synth,
Tom Zanussi454c4072010-05-01 01:41:20 -0500208};
209
210extern volatile int session_done;
211
212static void sig_handler(int sig __attribute__((__unused__)))
213{
214 session_done = 1;
215}
216
217static int __cmd_inject(void)
218{
219 struct perf_session *session;
220 int ret = -EINVAL;
221
222 signal(SIGINT, sig_handler);
223
224 if (inject_build_ids) {
Arnaldo Carvalho de Melo8115d602011-01-29 14:01:45 -0200225 inject_ops.sample = perf_event__inject_buildid;
226 inject_ops.mmap = perf_event__repipe_mmap;
227 inject_ops.fork = perf_event__repipe_task;
228 inject_ops.tracing_data = perf_event__repipe_tracing_data;
Tom Zanussi454c4072010-05-01 01:41:20 -0500229 }
230
Ian Munsie21ef97f2010-12-10 14:09:16 +1100231 session = perf_session__new(input_name, O_RDONLY, false, true, &inject_ops);
Tom Zanussi454c4072010-05-01 01:41:20 -0500232 if (session == NULL)
233 return -ENOMEM;
234
235 ret = perf_session__process_events(session, &inject_ops);
236
237 perf_session__delete(session);
238
239 return ret;
240}
241
242static const char * const report_usage[] = {
243 "perf inject [<options>]",
244 NULL
245};
246
247static const struct option options[] = {
Arnaldo Carvalho de Melo11d232e2010-05-04 10:48:22 -0300248 OPT_BOOLEAN('b', "build-ids", &inject_build_ids,
Tom Zanussi454c4072010-05-01 01:41:20 -0500249 "Inject build-ids into the output stream"),
250 OPT_INCR('v', "verbose", &verbose,
251 "be more verbose (show build ids, etc)"),
252 OPT_END()
253};
254
255int cmd_inject(int argc, const char **argv, const char *prefix __used)
256{
257 argc = parse_options(argc, argv, options, report_usage, 0);
258
259 /*
260 * Any (unrecognized) arguments left?
261 */
262 if (argc)
263 usage_with_options(report_usage, options);
264
265 if (symbol__init() < 0)
266 return -1;
267
268 return __cmd_inject();
269}