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