]>
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" | |
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 event__repipe(event_t *event __used, | |
20 | struct perf_session *session __used) | |
21 | { | |
22 | uint32_t size; | |
23 | void *buf = event; | |
24 | ||
25 | size = event->header.size; | |
26 | ||
27 | while (size) { | |
28 | int ret = write(STDOUT_FILENO, buf, size); | |
29 | if (ret < 0) | |
30 | return -errno; | |
31 | ||
32 | size -= ret; | |
33 | buf += ret; | |
34 | } | |
35 | ||
36 | return 0; | |
37 | } | |
38 | ||
39 | static int event__repipe_mmap(event_t *self, struct perf_session *session) | |
40 | { | |
41 | int err; | |
42 | ||
43 | err = event__process_mmap(self, session); | |
44 | event__repipe(self, session); | |
45 | ||
46 | return err; | |
47 | } | |
48 | ||
49 | static int event__repipe_task(event_t *self, struct perf_session *session) | |
50 | { | |
51 | int err; | |
52 | ||
53 | err = event__process_task(self, session); | |
54 | event__repipe(self, session); | |
55 | ||
56 | return err; | |
57 | } | |
58 | ||
59 | static int event__repipe_tracing_data(event_t *self, | |
60 | struct perf_session *session) | |
61 | { | |
62 | int err; | |
63 | ||
64 | event__repipe(self, session); | |
65 | err = event__process_tracing_data(self, session); | |
66 | ||
67 | return err; | |
68 | } | |
69 | ||
090f7204 | 70 | static int dso__read_build_id(struct dso *self) |
454c407e | 71 | { |
090f7204 ACM |
72 | if (self->has_build_id) |
73 | return 0; | |
454c407e | 74 | |
090f7204 ACM |
75 | if (filename__read_build_id(self->long_name, self->build_id, |
76 | sizeof(self->build_id)) > 0) { | |
77 | self->has_build_id = true; | |
78 | return 0; | |
79 | } | |
454c407e | 80 | |
090f7204 ACM |
81 | return -1; |
82 | } | |
454c407e | 83 | |
090f7204 ACM |
84 | static int dso__inject_build_id(struct dso *self, struct perf_session *session) |
85 | { | |
86 | u16 misc = PERF_RECORD_MISC_USER; | |
87 | struct machine *machine; | |
88 | int err; | |
454c407e | 89 | |
090f7204 ACM |
90 | if (dso__read_build_id(self) < 0) { |
91 | pr_debug("no build_id found for %s\n", self->long_name); | |
92 | return -1; | |
93 | } | |
454c407e | 94 | |
090f7204 ACM |
95 | machine = perf_session__find_host_machine(session); |
96 | if (machine == NULL) { | |
97 | pr_err("Can't find machine for session\n"); | |
98 | return -1; | |
99 | } | |
454c407e | 100 | |
090f7204 ACM |
101 | if (self->kernel) |
102 | misc = PERF_RECORD_MISC_KERNEL; | |
454c407e | 103 | |
090f7204 ACM |
104 | err = event__synthesize_build_id(self, misc, event__repipe, |
105 | machine, session); | |
106 | if (err) { | |
107 | pr_err("Can't synthesize build_id event for %s\n", self->long_name); | |
454c407e TZ |
108 | return -1; |
109 | } | |
110 | ||
111 | return 0; | |
112 | } | |
113 | ||
114 | static int event__inject_buildid(event_t *event, struct perf_session *session) | |
115 | { | |
116 | struct addr_location al; | |
117 | struct thread *thread; | |
118 | u8 cpumode; | |
454c407e TZ |
119 | |
120 | cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; | |
121 | ||
122 | thread = perf_session__findnew(session, event->ip.pid); | |
123 | if (thread == NULL) { | |
124 | pr_err("problem processing %d event, skipping it.\n", | |
125 | event->header.type); | |
454c407e TZ |
126 | goto repipe; |
127 | } | |
128 | ||
129 | thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION, | |
130 | event->ip.pid, event->ip.ip, &al); | |
131 | ||
132 | if (al.map != NULL) { | |
133 | if (!al.map->dso->hit) { | |
134 | al.map->dso->hit = 1; | |
090f7204 ACM |
135 | if (map__load(al.map, NULL) >= 0) { |
136 | dso__inject_build_id(al.map->dso, session); | |
137 | /* | |
138 | * If this fails, too bad, let the other side | |
139 | * account this as unresolved. | |
140 | */ | |
141 | } else | |
454c407e TZ |
142 | pr_warning("no symbols found in %s, maybe " |
143 | "install a debug package?\n", | |
144 | al.map->dso->long_name); | |
145 | } | |
146 | } | |
147 | ||
148 | repipe: | |
149 | event__repipe(event, session); | |
090f7204 | 150 | return 0; |
454c407e TZ |
151 | } |
152 | ||
153 | struct perf_event_ops inject_ops = { | |
154 | .sample = event__repipe, | |
155 | .mmap = event__repipe, | |
156 | .comm = event__repipe, | |
157 | .fork = event__repipe, | |
158 | .exit = event__repipe, | |
159 | .lost = event__repipe, | |
160 | .read = event__repipe, | |
161 | .throttle = event__repipe, | |
162 | .unthrottle = event__repipe, | |
163 | .attr = event__repipe, | |
164 | .event_type = event__repipe, | |
165 | .tracing_data = event__repipe, | |
166 | .build_id = event__repipe, | |
167 | }; | |
168 | ||
169 | extern volatile int session_done; | |
170 | ||
171 | static void sig_handler(int sig __attribute__((__unused__))) | |
172 | { | |
173 | session_done = 1; | |
174 | } | |
175 | ||
176 | static int __cmd_inject(void) | |
177 | { | |
178 | struct perf_session *session; | |
179 | int ret = -EINVAL; | |
180 | ||
181 | signal(SIGINT, sig_handler); | |
182 | ||
183 | if (inject_build_ids) { | |
184 | inject_ops.sample = event__inject_buildid; | |
185 | inject_ops.mmap = event__repipe_mmap; | |
186 | inject_ops.fork = event__repipe_task; | |
187 | inject_ops.tracing_data = event__repipe_tracing_data; | |
188 | } | |
189 | ||
190 | session = perf_session__new(input_name, O_RDONLY, false, true); | |
191 | if (session == NULL) | |
192 | return -ENOMEM; | |
193 | ||
194 | ret = perf_session__process_events(session, &inject_ops); | |
195 | ||
196 | perf_session__delete(session); | |
197 | ||
198 | return ret; | |
199 | } | |
200 | ||
201 | static const char * const report_usage[] = { | |
202 | "perf inject [<options>]", | |
203 | NULL | |
204 | }; | |
205 | ||
206 | static const struct option options[] = { | |
11d232ec | 207 | OPT_BOOLEAN('b', "build-ids", &inject_build_ids, |
454c407e TZ |
208 | "Inject build-ids into the output stream"), |
209 | OPT_INCR('v', "verbose", &verbose, | |
210 | "be more verbose (show build ids, etc)"), | |
211 | OPT_END() | |
212 | }; | |
213 | ||
214 | int cmd_inject(int argc, const char **argv, const char *prefix __used) | |
215 | { | |
216 | argc = parse_options(argc, argv, options, report_usage, 0); | |
217 | ||
218 | /* | |
219 | * Any (unrecognized) arguments left? | |
220 | */ | |
221 | if (argc) | |
222 | usage_with_options(report_usage, options); | |
223 | ||
224 | if (symbol__init() < 0) | |
225 | return -1; | |
226 | ||
227 | return __cmd_inject(); | |
228 | } |