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/tool.h"
  13#include "util/debug.h"
  14
  15#include "util/parse-options.h"
  16
  17struct perf_inject {
  18        struct perf_tool tool;
  19        bool             build_ids;
  20};
  21
  22static int perf_event__repipe_synth(struct perf_tool *tool __maybe_unused,
  23                                    union perf_event *event,
  24                                    struct machine *machine __maybe_unused)
  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
  43static int perf_event__repipe_op2_synth(struct perf_tool *tool,
  44                                        union perf_event *event,
  45                                        struct perf_session *session
  46                                        __maybe_unused)
  47{
  48        return perf_event__repipe_synth(tool, event, NULL);
  49}
  50
  51static int perf_event__repipe_event_type_synth(struct perf_tool *tool,
  52                                               union perf_event *event)
  53{
  54        return perf_event__repipe_synth(tool, event, NULL);
  55}
  56
  57static int perf_event__repipe_tracing_data_synth(union perf_event *event,
  58                                                 struct perf_session *session
  59                                                 __maybe_unused)
  60{
  61        return perf_event__repipe_synth(NULL, event, NULL);
  62}
  63
  64static int perf_event__repipe_attr(union perf_event *event,
  65                                   struct perf_evlist **pevlist __maybe_unused)
  66{
  67        int ret;
  68        ret = perf_event__process_attr(event, pevlist);
  69        if (ret)
  70                return ret;
  71
  72        return perf_event__repipe_synth(NULL, event, NULL);
  73}
  74
  75static int perf_event__repipe(struct perf_tool *tool,
  76                              union perf_event *event,
  77                              struct perf_sample *sample __maybe_unused,
  78                              struct machine *machine)
  79{
  80        return perf_event__repipe_synth(tool, event, machine);
  81}
  82
  83static int perf_event__repipe_sample(struct perf_tool *tool,
  84                                     union perf_event *event,
  85                              struct perf_sample *sample __maybe_unused,
  86                              struct perf_evsel *evsel __maybe_unused,
  87                              struct machine *machine)
  88{
  89        return perf_event__repipe_synth(tool, event, machine);
  90}
  91
  92static int perf_event__repipe_mmap(struct perf_tool *tool,
  93                                   union perf_event *event,
  94                                   struct perf_sample *sample,
  95                                   struct machine *machine)
  96{
  97        int err;
  98
  99        err = perf_event__process_mmap(tool, event, sample, machine);
 100        perf_event__repipe(tool, event, sample, machine);
 101
 102        return err;
 103}
 104
 105static int perf_event__repipe_task(struct perf_tool *tool,
 106                                   union perf_event *event,
 107                                   struct perf_sample *sample,
 108                                   struct machine *machine)
 109{
 110        int err;
 111
 112        err = perf_event__process_task(tool, event, sample, machine);
 113        perf_event__repipe(tool, event, sample, machine);
 114
 115        return err;
 116}
 117
 118static int perf_event__repipe_tracing_data(union perf_event *event,
 119                                           struct perf_session *session)
 120{
 121        int err;
 122
 123        perf_event__repipe_synth(NULL, event, NULL);
 124        err = perf_event__process_tracing_data(event, session);
 125
 126        return err;
 127}
 128
 129static int dso__read_build_id(struct dso *self)
 130{
 131        if (self->has_build_id)
 132                return 0;
 133
 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        }
 139
 140        return -1;
 141}
 142
 143static int dso__inject_build_id(struct dso *self, struct perf_tool *tool,
 144                                struct machine *machine)
 145{
 146        u16 misc = PERF_RECORD_MISC_USER;
 147        int err;
 148
 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        }
 153
 154        if (self->kernel)
 155                misc = PERF_RECORD_MISC_KERNEL;
 156
 157        err = perf_event__synthesize_build_id(tool, self, misc, perf_event__repipe,
 158                                              machine);
 159        if (err) {
 160                pr_err("Can't synthesize build_id event for %s\n", self->long_name);
 161                return -1;
 162        }
 163
 164        return 0;
 165}
 166
 167static int perf_event__inject_buildid(struct perf_tool *tool,
 168                                      union perf_event *event,
 169                                      struct perf_sample *sample,
 170                                      struct perf_evsel *evsel __maybe_unused,
 171                                      struct machine *machine)
 172{
 173        struct addr_location al;
 174        struct thread *thread;
 175        u8 cpumode;
 176
 177        cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
 178
 179        thread = machine__findnew_thread(machine, event->ip.pid);
 180        if (thread == NULL) {
 181                pr_err("problem processing %d event, skipping it.\n",
 182                       event->header.type);
 183                goto repipe;
 184        }
 185
 186        thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION,
 187                              event->ip.ip, &al);
 188
 189        if (al.map != NULL) {
 190                if (!al.map->dso->hit) {
 191                        al.map->dso->hit = 1;
 192                        if (map__load(al.map, NULL) >= 0) {
 193                                dso__inject_build_id(al.map->dso, tool, machine);
 194                                /*
 195                                 * If this fails, too bad, let the other side
 196                                 * account this as unresolved.
 197                                 */
 198                        } else {
 199#ifdef LIBELF_SUPPORT
 200                                pr_warning("no symbols found in %s, maybe "
 201                                           "install a debug package?\n",
 202                                           al.map->dso->long_name);
 203#endif
 204                        }
 205                }
 206        }
 207
 208repipe:
 209        perf_event__repipe(tool, event, sample, machine);
 210        return 0;
 211}
 212
 213extern volatile int session_done;
 214
 215static void sig_handler(int sig __maybe_unused)
 216{
 217        session_done = 1;
 218}
 219
 220static int __cmd_inject(struct perf_inject *inject)
 221{
 222        struct perf_session *session;
 223        int ret = -EINVAL;
 224
 225        signal(SIGINT, sig_handler);
 226
 227        if (inject->build_ids) {
 228                inject->tool.sample       = perf_event__inject_buildid;
 229                inject->tool.mmap         = perf_event__repipe_mmap;
 230                inject->tool.fork         = perf_event__repipe_task;
 231                inject->tool.tracing_data = perf_event__repipe_tracing_data;
 232        }
 233
 234        session = perf_session__new("-", O_RDONLY, false, true, &inject->tool);
 235        if (session == NULL)
 236                return -ENOMEM;
 237
 238        ret = perf_session__process_events(session, &inject->tool);
 239
 240        perf_session__delete(session);
 241
 242        return ret;
 243}
 244
 245int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
 246{
 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        };
 271        const char * const inject_usage[] = {
 272                "perf inject [<options>]",
 273                NULL
 274        };
 275
 276        argc = parse_options(argc, argv, options, inject_usage, 0);
 277
 278        /*
 279         * Any (unrecognized) arguments left?
 280         */
 281        if (argc)
 282                usage_with_options(inject_usage, options);
 283
 284        if (symbol__init() < 0)
 285                return -1;
 286
 287        return __cmd_inject(&inject);
 288}
 289
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.