perf inject: Work with files
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / tools / perf / builtin-inject.c
CommitLineData
454c407e
TZ
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"
45694aa7 12#include "util/tool.h"
454c407e
TZ
13#include "util/debug.h"
14
15#include "util/parse-options.h"
16
5ded57ac
ACM
17struct perf_inject {
18 struct perf_tool tool;
19 bool build_ids;
e558a5bd
AV
20 const char *input_name;
21 int pipe_output,
22 output;
23 u64 bytes_written;
5ded57ac 24};
454c407e 25
e558a5bd 26static int perf_event__repipe_synth(struct perf_tool *tool,
d20deb64 27 union perf_event *event,
1d037ca1 28 struct machine *machine __maybe_unused)
454c407e 29{
e558a5bd 30 struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
454c407e
TZ
31 uint32_t size;
32 void *buf = event;
33
34 size = event->header.size;
35
36 while (size) {
e558a5bd 37 int ret = write(inject->output, buf, size);
454c407e
TZ
38 if (ret < 0)
39 return -errno;
40
41 size -= ret;
42 buf += ret;
e558a5bd 43 inject->bytes_written += ret;
454c407e
TZ
44 }
45
46 return 0;
47}
48
45694aa7 49static int perf_event__repipe_op2_synth(struct perf_tool *tool,
743eb868 50 union perf_event *event,
1d037ca1
IT
51 struct perf_session *session
52 __maybe_unused)
743eb868 53{
45694aa7 54 return perf_event__repipe_synth(tool, event, NULL);
743eb868
ACM
55}
56
45694aa7 57static int perf_event__repipe_event_type_synth(struct perf_tool *tool,
743eb868
ACM
58 union perf_event *event)
59{
45694aa7 60 return perf_event__repipe_synth(tool, event, NULL);
743eb868
ACM
61}
62
d20deb64 63static int perf_event__repipe_tracing_data_synth(union perf_event *event,
1d037ca1
IT
64 struct perf_session *session
65 __maybe_unused)
d20deb64 66{
743eb868 67 return perf_event__repipe_synth(NULL, event, NULL);
d20deb64
ACM
68}
69
10d0f086 70static int perf_event__repipe_attr(union perf_event *event,
1d037ca1 71 struct perf_evlist **pevlist __maybe_unused)
10d0f086 72{
1a1ed1ba
SE
73 int ret;
74 ret = perf_event__process_attr(event, pevlist);
75 if (ret)
76 return ret;
77
d20deb64 78 return perf_event__repipe_synth(NULL, event, NULL);
10d0f086
ACM
79}
80
45694aa7 81static int perf_event__repipe(struct perf_tool *tool,
d20deb64 82 union perf_event *event,
1d037ca1 83 struct perf_sample *sample __maybe_unused,
743eb868 84 struct machine *machine)
640c03ce 85{
45694aa7 86 return perf_event__repipe_synth(tool, event, machine);
640c03ce
ACM
87}
88
45694aa7 89static int perf_event__repipe_sample(struct perf_tool *tool,
d20deb64 90 union perf_event *event,
1d037ca1
IT
91 struct perf_sample *sample __maybe_unused,
92 struct perf_evsel *evsel __maybe_unused,
743eb868 93 struct machine *machine)
9e69c210 94{
45694aa7 95 return perf_event__repipe_synth(tool, event, machine);
9e69c210
ACM
96}
97
45694aa7 98static int perf_event__repipe_mmap(struct perf_tool *tool,
d20deb64 99 union perf_event *event,
8115d60c 100 struct perf_sample *sample,
743eb868 101 struct machine *machine)
454c407e
TZ
102{
103 int err;
104
45694aa7
ACM
105 err = perf_event__process_mmap(tool, event, sample, machine);
106 perf_event__repipe(tool, event, sample, machine);
454c407e
TZ
107
108 return err;
109}
110
f62d3f0f 111static int perf_event__repipe_fork(struct perf_tool *tool,
d20deb64 112 union perf_event *event,
8115d60c 113 struct perf_sample *sample,
743eb868 114 struct machine *machine)
454c407e
TZ
115{
116 int err;
117
f62d3f0f 118 err = perf_event__process_fork(tool, event, sample, machine);
45694aa7 119 perf_event__repipe(tool, event, sample, machine);
454c407e
TZ
120
121 return err;
122}
123
8115d60c
ACM
124static int perf_event__repipe_tracing_data(union perf_event *event,
125 struct perf_session *session)
454c407e
TZ
126{
127 int err;
128
743eb868 129 perf_event__repipe_synth(NULL, event, NULL);
8115d60c 130 err = perf_event__process_tracing_data(event, session);
454c407e
TZ
131
132 return err;
133}
134
090f7204 135static int dso__read_build_id(struct dso *self)
454c407e 136{
090f7204
ACM
137 if (self->has_build_id)
138 return 0;
454c407e 139
090f7204
ACM
140 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;
144 }
454c407e 145
090f7204
ACM
146 return -1;
147}
454c407e 148
45694aa7 149static int dso__inject_build_id(struct dso *self, struct perf_tool *tool,
743eb868 150 struct machine *machine)
090f7204
ACM
151{
152 u16 misc = PERF_RECORD_MISC_USER;
090f7204 153 int err;
454c407e 154
090f7204
ACM
155 if (dso__read_build_id(self) < 0) {
156 pr_debug("no build_id found for %s\n", self->long_name);
157 return -1;
158 }
454c407e 159
090f7204
ACM
160 if (self->kernel)
161 misc = PERF_RECORD_MISC_KERNEL;
454c407e 162
45694aa7 163 err = perf_event__synthesize_build_id(tool, self, misc, perf_event__repipe,
743eb868 164 machine);
090f7204
ACM
165 if (err) {
166 pr_err("Can't synthesize build_id event for %s\n", self->long_name);
454c407e
TZ
167 return -1;
168 }
169
170 return 0;
171}
172
45694aa7 173static int perf_event__inject_buildid(struct perf_tool *tool,
d20deb64 174 union perf_event *event,
8115d60c 175 struct perf_sample *sample,
1d037ca1 176 struct perf_evsel *evsel __maybe_unused,
743eb868 177 struct machine *machine)
454c407e
TZ
178{
179 struct addr_location al;
180 struct thread *thread;
181 u8 cpumode;
454c407e
TZ
182
183 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
184
743eb868 185 thread = machine__findnew_thread(machine, event->ip.pid);
454c407e
TZ
186 if (thread == NULL) {
187 pr_err("problem processing %d event, skipping it.\n",
188 event->header.type);
454c407e
TZ
189 goto repipe;
190 }
191
743eb868
ACM
192 thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION,
193 event->ip.ip, &al);
454c407e
TZ
194
195 if (al.map != NULL) {
196 if (!al.map->dso->hit) {
197 al.map->dso->hit = 1;
090f7204 198 if (map__load(al.map, NULL) >= 0) {
45694aa7 199 dso__inject_build_id(al.map->dso, tool, machine);
090f7204
ACM
200 /*
201 * If this fails, too bad, let the other side
202 * account this as unresolved.
203 */
393be2e3 204 } else {
29a0fc9b 205#ifdef LIBELF_SUPPORT
454c407e
TZ
206 pr_warning("no symbols found in %s, maybe "
207 "install a debug package?\n",
208 al.map->dso->long_name);
393be2e3
NK
209#endif
210 }
454c407e
TZ
211 }
212 }
213
214repipe:
45694aa7 215 perf_event__repipe(tool, event, sample, machine);
090f7204 216 return 0;
454c407e
TZ
217}
218
454c407e
TZ
219extern volatile int session_done;
220
1d037ca1 221static void sig_handler(int sig __maybe_unused)
454c407e
TZ
222{
223 session_done = 1;
224}
225
5ded57ac 226static int __cmd_inject(struct perf_inject *inject)
454c407e
TZ
227{
228 struct perf_session *session;
229 int ret = -EINVAL;
230
231 signal(SIGINT, sig_handler);
232
5ded57ac
ACM
233 if (inject->build_ids) {
234 inject->tool.sample = perf_event__inject_buildid;
235 inject->tool.mmap = perf_event__repipe_mmap;
f62d3f0f 236 inject->tool.fork = perf_event__repipe_fork;
5ded57ac 237 inject->tool.tracing_data = perf_event__repipe_tracing_data;
454c407e
TZ
238 }
239
e558a5bd 240 session = perf_session__new(inject->input_name, O_RDONLY, false, true, &inject->tool);
454c407e
TZ
241 if (session == NULL)
242 return -ENOMEM;
243
e558a5bd
AV
244 if (!inject->pipe_output)
245 lseek(inject->output, session->header.data_offset, SEEK_SET);
246
5ded57ac 247 ret = perf_session__process_events(session, &inject->tool);
454c407e 248
e558a5bd
AV
249 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
454c407e
TZ
254 perf_session__delete(session);
255
256 return ret;
257}
258
1d037ca1 259int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
454c407e 260{
5ded57ac
ACM
261 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 },
e558a5bd 277 .input_name = "-",
5ded57ac 278 };
e558a5bd 279 const char *output_name = "-";
5ded57ac
ACM
280 const struct option options[] = {
281 OPT_BOOLEAN('b', "build-ids", &inject.build_ids,
282 "Inject build-ids into the output stream"),
e558a5bd
AV
283 OPT_STRING('i', "input", &inject.input_name, "file",
284 "input file name"),
285 OPT_STRING('o', "output", &output_name, "file",
286 "output file name"),
5ded57ac
ACM
287 OPT_INCR('v', "verbose", &verbose,
288 "be more verbose (show build ids, etc)"),
289 OPT_END()
290 };
002439e8
ACM
291 const char * const inject_usage[] = {
292 "perf inject [<options>]",
293 NULL
294 };
5ded57ac 295
002439e8 296 argc = parse_options(argc, argv, options, inject_usage, 0);
454c407e
TZ
297
298 /*
299 * Any (unrecognized) arguments left?
300 */
301 if (argc)
002439e8 302 usage_with_options(inject_usage, options);
454c407e 303
e558a5bd
AV
304 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
454c407e
TZ
316 if (symbol__init() < 0)
317 return -1;
318
5ded57ac 319 return __cmd_inject(&inject);
454c407e 320}