perf tools: Pass build_id object to dso__build_id_equal()
[linux-2.6-microblaze.git] / tools / perf / builtin-inject.c
index 6d2f410..452a75f 100644 (file)
@@ -10,6 +10,7 @@
 
 #include "util/color.h"
 #include "util/dso.h"
+#include "util/vdso.h"
 #include "util/evlist.h"
 #include "util/evsel.h"
 #include "util/map.h"
 #include "util/symbol.h"
 #include "util/synthetic-events.h"
 #include "util/thread.h"
-#include <linux/err.h>
+#include "util/namespaces.h"
 
+#include <linux/err.h>
 #include <subcmd/parse-options.h>
+#include <uapi/linux/mman.h> /* To get things like MAP_HUGETLB even on older libc headers */
 
 #include <linux/list.h>
 #include <errno.h>
@@ -35,6 +38,7 @@ struct perf_inject {
        struct perf_tool        tool;
        struct perf_session     *session;
        bool                    build_ids;
+       bool                    build_id_all;
        bool                    sched_stat;
        bool                    have_auxtrace;
        bool                    strip;
@@ -54,6 +58,9 @@ struct event_entry {
        union perf_event event[];
 };
 
+static int dso__inject_build_id(struct dso *dso, struct perf_tool *tool,
+                               struct machine *machine, u8 cpumode, u32 flags);
+
 static int output_bytes(struct perf_inject *inject, void *buf, size_t sz)
 {
        ssize_t size;
@@ -97,6 +104,13 @@ static int perf_event__repipe_op2_synth(struct perf_session *session,
        return perf_event__repipe_synth(session->tool, event);
 }
 
+static int perf_event__repipe_op4_synth(struct perf_session *session,
+                                       union perf_event *event,
+                                       u64 data __maybe_unused)
+{
+       return perf_event__repipe_synth(session->tool, event);
+}
+
 static int perf_event__repipe_attr(struct perf_tool *tool,
                                   union perf_event *event,
                                   struct evlist **pevlist)
@@ -115,6 +129,13 @@ static int perf_event__repipe_attr(struct perf_tool *tool,
        return perf_event__repipe_synth(tool, event);
 }
 
+static int perf_event__repipe_event_update(struct perf_tool *tool,
+                                          union perf_event *event,
+                                          struct evlist **pevlist __maybe_unused)
+{
+       return perf_event__repipe_synth(tool, event);
+}
+
 #ifdef HAVE_AUXTRACE_SUPPORT
 
 static int copy_bytes(struct perf_inject *inject, int fd, off_t size)
@@ -303,6 +324,68 @@ static int perf_event__jit_repipe_mmap(struct perf_tool *tool,
 }
 #endif
 
+static struct dso *findnew_dso(int pid, int tid, const char *filename,
+                              struct dso_id *id, struct machine *machine)
+{
+       struct thread *thread;
+       struct nsinfo *nsi = NULL;
+       struct nsinfo *nnsi;
+       struct dso *dso;
+       bool vdso;
+
+       thread = machine__findnew_thread(machine, pid, tid);
+       if (thread == NULL) {
+               pr_err("cannot find or create a task %d/%d.\n", tid, pid);
+               return NULL;
+       }
+
+       vdso = is_vdso_map(filename);
+       nsi = nsinfo__get(thread->nsinfo);
+
+       if (vdso) {
+               /* The vdso maps are always on the host and not the
+                * container.  Ensure that we don't use setns to look
+                * them up.
+                */
+               nnsi = nsinfo__copy(nsi);
+               if (nnsi) {
+                       nsinfo__put(nsi);
+                       nnsi->need_setns = false;
+                       nsi = nnsi;
+               }
+               dso = machine__findnew_vdso(machine, thread);
+       } else {
+               dso = machine__findnew_dso_id(machine, filename, id);
+       }
+
+       if (dso)
+               dso->nsinfo = nsi;
+       else
+               nsinfo__put(nsi);
+
+       thread__put(thread);
+       return dso;
+}
+
+static int perf_event__repipe_buildid_mmap(struct perf_tool *tool,
+                                          union perf_event *event,
+                                          struct perf_sample *sample,
+                                          struct machine *machine)
+{
+       struct dso *dso;
+
+       dso = findnew_dso(event->mmap.pid, event->mmap.tid,
+                         event->mmap.filename, NULL, machine);
+
+       if (dso && !dso->hit) {
+               dso->hit = 1;
+               dso__inject_build_id(dso, tool, machine, sample->cpumode, 0);
+               dso__put(dso);
+       }
+
+       return perf_event__repipe(tool, event, sample, machine);
+}
+
 static int perf_event__repipe_mmap2(struct perf_tool *tool,
                                   union perf_event *event,
                                   struct perf_sample *sample,
@@ -341,6 +424,34 @@ static int perf_event__jit_repipe_mmap2(struct perf_tool *tool,
 }
 #endif
 
+static int perf_event__repipe_buildid_mmap2(struct perf_tool *tool,
+                                           union perf_event *event,
+                                           struct perf_sample *sample,
+                                           struct machine *machine)
+{
+       struct dso_id dso_id = {
+               .maj = event->mmap2.maj,
+               .min = event->mmap2.min,
+               .ino = event->mmap2.ino,
+               .ino_generation = event->mmap2.ino_generation,
+       };
+       struct dso *dso;
+
+       dso = findnew_dso(event->mmap2.pid, event->mmap2.tid,
+                         event->mmap2.filename, &dso_id, machine);
+
+       if (dso && !dso->hit) {
+               dso->hit = 1;
+               dso__inject_build_id(dso, tool, machine, sample->cpumode,
+                                    event->mmap2.flags);
+               dso__put(dso);
+       }
+
+       perf_event__repipe(tool, event, sample, machine);
+
+       return 0;
+}
+
 static int perf_event__repipe_fork(struct perf_tool *tool,
                                   union perf_event *event,
                                   struct perf_sample *sample,
@@ -405,34 +516,36 @@ static int perf_event__repipe_tracing_data(struct perf_session *session,
 
 static int dso__read_build_id(struct dso *dso)
 {
+       struct nscookie nsc;
+
        if (dso->has_build_id)
                return 0;
 
-       if (filename__read_build_id(dso->long_name, dso->build_id,
-                                   sizeof(dso->build_id)) > 0) {
+       nsinfo__mountns_enter(dso->nsinfo, &nsc);
+       if (filename__read_build_id(dso->long_name, &dso->bid) > 0)
                dso->has_build_id = true;
-               return 0;
-       }
+       nsinfo__mountns_exit(&nsc);
 
-       return -1;
+       return dso->has_build_id ? 0 : -1;
 }
 
 static int dso__inject_build_id(struct dso *dso, struct perf_tool *tool,
-                               struct machine *machine)
+                               struct machine *machine, u8 cpumode, u32 flags)
 {
-       u16 misc = PERF_RECORD_MISC_USER;
        int err;
 
+       if (is_anon_memory(dso->long_name) || flags & MAP_HUGETLB)
+               return 0;
+       if (is_no_dso_memory(dso->long_name))
+               return 0;
+
        if (dso__read_build_id(dso) < 0) {
                pr_debug("no build_id found for %s\n", dso->long_name);
                return -1;
        }
 
-       if (dso->kernel)
-               misc = PERF_RECORD_MISC_KERNEL;
-
-       err = perf_event__synthesize_build_id(tool, dso, misc, perf_event__repipe,
-                                             machine);
+       err = perf_event__synthesize_build_id(tool, dso, cpumode,
+                                             perf_event__repipe, machine);
        if (err) {
                pr_err("Can't synthesize build_id event for %s\n", dso->long_name);
                return -1;
@@ -441,11 +554,10 @@ static int dso__inject_build_id(struct dso *dso, struct perf_tool *tool,
        return 0;
 }
 
-static int perf_event__inject_buildid(struct perf_tool *tool,
-                                     union perf_event *event,
-                                     struct perf_sample *sample,
-                                     struct evsel *evsel __maybe_unused,
-                                     struct machine *machine)
+int perf_event__inject_buildid(struct perf_tool *tool, union perf_event *event,
+                              struct perf_sample *sample,
+                              struct evsel *evsel __maybe_unused,
+                              struct machine *machine)
 {
        struct addr_location al;
        struct thread *thread;
@@ -460,19 +572,8 @@ static int perf_event__inject_buildid(struct perf_tool *tool,
        if (thread__find_map(thread, sample->cpumode, sample->ip, &al)) {
                if (!al.map->dso->hit) {
                        al.map->dso->hit = 1;
-                       if (map__load(al.map) >= 0) {
-                               dso__inject_build_id(al.map->dso, tool, machine);
-                               /*
-                                * If this fails, too bad, let the other side
-                                * account this as unresolved.
-                                */
-                       } else {
-#ifdef HAVE_LIBELF_SUPPORT
-                               pr_warning("no symbols found in %s, maybe "
-                                          "install a debug package?\n",
-                                          al.map->dso->long_name);
-#endif
-                       }
+                       dso__inject_build_id(al.map->dso, tool, machine,
+                                            sample->cpumode, al.map->flags);
                }
        }
 
@@ -606,7 +707,7 @@ static int __cmd_inject(struct perf_inject *inject)
        signal(SIGINT, sig_handler);
 
        if (inject->build_ids || inject->sched_stat ||
-           inject->itrace_synth_opts.set) {
+           inject->itrace_synth_opts.set || inject->build_id_all) {
                inject->tool.mmap         = perf_event__repipe_mmap;
                inject->tool.mmap2        = perf_event__repipe_mmap2;
                inject->tool.fork         = perf_event__repipe_fork;
@@ -615,7 +716,10 @@ static int __cmd_inject(struct perf_inject *inject)
 
        output_data_offset = session->header.data_offset;
 
-       if (inject->build_ids) {
+       if (inject->build_id_all) {
+               inject->tool.mmap         = perf_event__repipe_buildid_mmap;
+               inject->tool.mmap2        = perf_event__repipe_buildid_mmap2;
+       } else if (inject->build_ids) {
                inject->tool.sample = perf_event__inject_buildid;
        } else if (inject->sched_stat) {
                struct evsel *evsel;
@@ -708,9 +812,12 @@ int cmd_inject(int argc, const char **argv)
        struct perf_inject inject = {
                .tool = {
                        .sample         = perf_event__repipe_sample,
+                       .read           = perf_event__repipe_sample,
                        .mmap           = perf_event__repipe,
                        .mmap2          = perf_event__repipe,
                        .comm           = perf_event__repipe,
+                       .namespaces     = perf_event__repipe,
+                       .cgroup         = perf_event__repipe,
                        .fork           = perf_event__repipe,
                        .exit           = perf_event__repipe,
                        .lost           = perf_event__repipe,
@@ -718,19 +825,28 @@ int cmd_inject(int argc, const char **argv)
                        .aux            = perf_event__repipe,
                        .itrace_start   = perf_event__repipe,
                        .context_switch = perf_event__repipe,
-                       .read           = perf_event__repipe_sample,
                        .throttle       = perf_event__repipe,
                        .unthrottle     = perf_event__repipe,
+                       .ksymbol        = perf_event__repipe,
+                       .bpf            = perf_event__repipe,
+                       .text_poke      = perf_event__repipe,
                        .attr           = perf_event__repipe_attr,
+                       .event_update   = perf_event__repipe_event_update,
                        .tracing_data   = perf_event__repipe_op2_synth,
-                       .auxtrace_info  = perf_event__repipe_op2_synth,
-                       .auxtrace       = perf_event__repipe_auxtrace,
-                       .auxtrace_error = perf_event__repipe_op2_synth,
-                       .time_conv      = perf_event__repipe_op2_synth,
                        .finished_round = perf_event__repipe_oe_synth,
                        .build_id       = perf_event__repipe_op2_synth,
                        .id_index       = perf_event__repipe_op2_synth,
+                       .auxtrace_info  = perf_event__repipe_op2_synth,
+                       .auxtrace_error = perf_event__repipe_op2_synth,
+                       .time_conv      = perf_event__repipe_op2_synth,
+                       .thread_map     = perf_event__repipe_op2_synth,
+                       .cpu_map        = perf_event__repipe_op2_synth,
+                       .stat_config    = perf_event__repipe_op2_synth,
+                       .stat           = perf_event__repipe_op2_synth,
+                       .stat_round     = perf_event__repipe_op2_synth,
                        .feature        = perf_event__repipe_op2_synth,
+                       .compressed     = perf_event__repipe_op4_synth,
+                       .auxtrace       = perf_event__repipe_auxtrace,
                },
                .input_name  = "-",
                .samples = LIST_HEAD_INIT(inject.samples),
@@ -747,6 +863,8 @@ int cmd_inject(int argc, const char **argv)
        struct option options[] = {
                OPT_BOOLEAN('b', "build-ids", &inject.build_ids,
                            "Inject build-ids into the output stream"),
+               OPT_BOOLEAN(0, "buildid-all", &inject.build_id_all,
+                           "Inject build-ids of all DSOs into the output stream"),
                OPT_STRING('i', "input", &inject.input_name, "file",
                           "input file name"),
                OPT_STRING('o', "output", &inject.output.path, "file",
@@ -795,8 +913,6 @@ int cmd_inject(int argc, const char **argv)
                return -1;
        }
 
-       inject.tool.ordered_events = inject.sched_stat;
-
        data.path = inject.input_name;
        inject.session = perf_session__new(&data, true, &inject.tool);
        if (IS_ERR(inject.session))
@@ -805,7 +921,7 @@ int cmd_inject(int argc, const char **argv)
        if (zstd_init(&(inject.session->zstd_data), 0) < 0)
                pr_warning("Decompression initialization failed.\n");
 
-       if (inject.build_ids) {
+       if (inject.build_ids && !inject.build_id_all) {
                /*
                 * to make sure the mmap records are ordered correctly
                 * and so that the correct especially due to jitted code
@@ -815,6 +931,11 @@ int cmd_inject(int argc, const char **argv)
                inject.tool.ordered_events = true;
                inject.tool.ordering_requires_timestamps = true;
        }
+
+       if (inject.sched_stat) {
+               inject.tool.ordered_events = true;
+       }
+
 #ifdef HAVE_JITDUMP
        if (inject.jit_mode) {
                inject.tool.mmap2          = perf_event__jit_repipe_mmap2;