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