perf tools: Pass tool context in the the perf_event_ops functions
[firefly-linux-kernel-4.4.55.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/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(struct perf_event_ops *ops __used,
20                                     union perf_event *event,
21                                     struct perf_session *session __used)
22 {
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
40 static 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
46 static int perf_event__repipe_attr(union perf_event *event,
47                                    struct perf_evlist **pevlist __used)
48 {
49         return perf_event__repipe_synth(NULL, event, NULL);
50 }
51
52 static int perf_event__repipe(struct perf_event_ops *ops,
53                               union perf_event *event,
54                               struct perf_sample *sample __used,
55                               struct perf_session *session)
56 {
57         return perf_event__repipe_synth(ops, event, session);
58 }
59
60 static int perf_event__repipe_sample(struct perf_event_ops *ops,
61                                      union perf_event *event,
62                               struct perf_sample *sample __used,
63                               struct perf_evsel *evsel __used,
64                               struct perf_session *session)
65 {
66         return perf_event__repipe_synth(ops, event, session);
67 }
68
69 static int perf_event__repipe_mmap(struct perf_event_ops *ops,
70                                    union perf_event *event,
71                                    struct perf_sample *sample,
72                                    struct perf_session *session)
73 {
74         int err;
75
76         err = perf_event__process_mmap(ops, event, sample, session);
77         perf_event__repipe(ops, event, sample, session);
78
79         return err;
80 }
81
82 static int perf_event__repipe_task(struct perf_event_ops *ops,
83                                    union perf_event *event,
84                                    struct perf_sample *sample,
85                                    struct perf_session *session)
86 {
87         int err;
88
89         err = perf_event__process_task(ops, event, sample, session);
90         perf_event__repipe(ops, event, sample, session);
91
92         return err;
93 }
94
95 static int perf_event__repipe_tracing_data(union perf_event *event,
96                                            struct perf_session *session)
97 {
98         int err;
99
100         perf_event__repipe_synth(NULL, event, session);
101         err = perf_event__process_tracing_data(event, session);
102
103         return err;
104 }
105
106 static int dso__read_build_id(struct dso *self)
107 {
108         if (self->has_build_id)
109                 return 0;
110
111         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;
115         }
116
117         return -1;
118 }
119
120 static int dso__inject_build_id(struct dso *self, struct perf_event_ops *ops,
121                                 struct perf_session *session)
122 {
123         u16 misc = PERF_RECORD_MISC_USER;
124         struct machine *machine;
125         int err;
126
127         if (dso__read_build_id(self) < 0) {
128                 pr_debug("no build_id found for %s\n", self->long_name);
129                 return -1;
130         }
131
132         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
141         err = perf_event__synthesize_build_id(ops, self, misc, perf_event__repipe,
142                                               machine, session);
143         if (err) {
144                 pr_err("Can't synthesize build_id event for %s\n", self->long_name);
145                 return -1;
146         }
147
148         return 0;
149 }
150
151 static int perf_event__inject_buildid(struct perf_event_ops *ops,
152                                       union perf_event *event,
153                                       struct perf_sample *sample,
154                                       struct perf_evsel *evsel __used,
155                                       struct perf_session *session)
156 {
157         struct addr_location al;
158         struct thread *thread;
159         u8 cpumode;
160
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);
167                 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;
176                         if (map__load(al.map, NULL) >= 0) {
177                                 dso__inject_build_id(al.map->dso, ops, session);
178                                 /*
179                                  * If this fails, too bad, let the other side
180                                  * account this as unresolved.
181                                  */
182                         } else
183                                 pr_warning("no symbols found in %s, maybe "
184                                            "install a debug package?\n",
185                                            al.map->dso->long_name);
186                 }
187         }
188
189 repipe:
190         perf_event__repipe(ops, event, sample, session);
191         return 0;
192 }
193
194 struct perf_event_ops inject_ops = {
195         .sample         = perf_event__repipe_sample,
196         .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,
204         .attr           = perf_event__repipe_attr,
205         .event_type     = perf_event__repipe_synth,
206         .tracing_data   = perf_event__repipe_tracing_data_synth,
207         .build_id       = perf_event__repipe_synth,
208 };
209
210 extern volatile int session_done;
211
212 static void sig_handler(int sig __attribute__((__unused__)))
213 {
214         session_done = 1;
215 }
216
217 static 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) {
225                 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;
229         }
230
231         session = perf_session__new(input_name, O_RDONLY, false, true, &inject_ops);
232         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
242 static const char * const report_usage[] = {
243         "perf inject [<options>]",
244         NULL
245 };
246
247 static const struct option options[] = {
248         OPT_BOOLEAN('b', "build-ids", &inject_build_ids,
249                     "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
255 int 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 }