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