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