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

Archive Download this file



interactive