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