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
  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
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.