Merge tag 'perf-core-for-mingo-20160901' of git://git.kernel.org/pub/scm/linux/kernel...
authorIngo Molnar <mingo@kernel.org>
Mon, 5 Sep 2016 13:15:49 +0000 (15:15 +0200)
committerIngo Molnar <mingo@kernel.org>
Mon, 5 Sep 2016 13:15:49 +0000 (15:15 +0200)
Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo:

User visible changes:

- Support generating cross arch probes, i.e. if you specify a vmlinux
  file for different arch than the one in the host machine,

 $ perf probe --definition function_name args

  will generate the probe definition string needed to append to the
  target machine /sys/kernel/debug/tracing/kprobes_events file, using
  scripting (Masami Hiramatsu).

- Make 'perf probe' skip the function prologue in uprobes if program
  compiled without optimization, using the same strategy as gdb and
  systemtap uses, fixing a bug where:

$ perf probe -x ./test 'foo i'

  When 'foo(42)' was used on the "./test" executable would produce i=0
  instead of the expected i=42 (Ravi Bangoria)

- Demangle symbols for synthesized @plt entries too (Millian Wolff)

Documentation changes:

- Show default report configuration in 'perf config' example
  and docs (Millian Wolff)

Infrastructure changes:

- Make 'perf test vmlinux' tolerate the symbol aliasing pruning done when
  loading kallsyms and vmlinux (Arnaldo Carvalho de Melo)

- Improve output of 'perf test vmlinux' test, to help identify on the verbose
  output which lines are warning and which are errors (Arnaldo Carvalho de Melo)

- Prep work to stop having to pass symbol_filter_t to lots of functions,
  simplifying symtab loading routines (Arnaldo Carvalho de Melo)

- Honor symbol_conf.allow_aliases when loading kallsyms as well, it was using
  it only when loading vmlinux files (Arnaldo Carvalho de Melo)

- Fixup symbol->end before doing alias pruning when loading symbol tables
  (Arnaldo Carvalho de Melo)

- Fix error handling of lzma kernel module decompression (Shawn Lin)

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
33 files changed:
tools/perf/Documentation/perf-config.txt
tools/perf/Documentation/perf-probe.txt
tools/perf/Documentation/perfconfig.example
tools/perf/arch/arm/include/dwarf-regs-table.h [new file with mode: 0644]
tools/perf/arch/arm64/include/dwarf-regs-table.h [new file with mode: 0644]
tools/perf/arch/powerpc/include/dwarf-regs-table.h [new file with mode: 0644]
tools/perf/arch/s390/include/dwarf-regs-table.h [new file with mode: 0644]
tools/perf/arch/sh/include/dwarf-regs-table.h [new file with mode: 0644]
tools/perf/arch/sparc/include/dwarf-regs-table.h [new file with mode: 0644]
tools/perf/arch/x86/include/dwarf-regs-table.h [new file with mode: 0644]
tools/perf/arch/xtensa/include/dwarf-regs-table.h [new file with mode: 0644]
tools/perf/builtin-annotate.c
tools/perf/builtin-probe.c
tools/perf/builtin-report.c
tools/perf/builtin-top.c
tools/perf/tests/vmlinux-kallsyms.c
tools/perf/util/Build
tools/perf/util/annotate.c
tools/perf/util/annotate.h
tools/perf/util/dwarf-aux.c
tools/perf/util/dwarf-aux.h
tools/perf/util/dwarf-regs.c [new file with mode: 0644]
tools/perf/util/evsel_fprintf.c
tools/perf/util/include/dwarf-regs.h
tools/perf/util/lzma.c
tools/perf/util/probe-event.c
tools/perf/util/probe-event.h
tools/perf/util/probe-file.c
tools/perf/util/probe-finder.c
tools/perf/util/probe-finder.h
tools/perf/util/symbol-elf.c
tools/perf/util/symbol.c
tools/perf/util/symbol.h

index 68c8919..cb081ac 100644 (file)
@@ -110,6 +110,14 @@ Given a $HOME/.perfconfig like this:
                order = caller
                sort-key = function
 
+       [report]
+               # Defaults
+               sort-order = comm,dso,symbol
+               percent-limit = 0
+               queue-size = 0
+               children = true
+               group = true
+
 Variables
 ~~~~~~~~~
 
index f37d123..e6c9902 100644 (file)
@@ -21,6 +21,8 @@ or
 'perf probe' [options] --vars='PROBEPOINT'
 or
 'perf probe' [options] --funcs
+or
+'perf probe' [options] --definition='PROBE' [...]
 
 DESCRIPTION
 -----------
@@ -34,6 +36,8 @@ OPTIONS
 -k::
 --vmlinux=PATH::
        Specify vmlinux path which has debuginfo (Dwarf binary).
+       Only when using this with --definition, you can give an offline
+       vmlinux file.
 
 -m::
 --module=MODNAME|PATH::
@@ -96,6 +100,11 @@ OPTIONS
        can also list functions in a user space executable / shared library.
        This also can accept a FILTER rule argument.
 
+-D::
+--definition=::
+       Show trace-event definition converted from given probe-event instead
+       of write it into tracing/[k,u]probe_events.
+
 --filter=FILTER::
        (Only for --vars and --funcs) Set filter. FILTER is a combination of glob
        pattern, see FILTER PATTERN for detail.
index 1d8d5bc..2b477c1 100644 (file)
        use_offset = true
        jump_arrows = true
        show_nr_jumps = false
+
+[report]
+
+       # Defaults
+       sort-order = comm,dso,symbol
+       percent-limit = 0
+       queue-size = 0
+       children = true
+       group = true
diff --git a/tools/perf/arch/arm/include/dwarf-regs-table.h b/tools/perf/arch/arm/include/dwarf-regs-table.h
new file mode 100644 (file)
index 0000000..f298d03
--- /dev/null
@@ -0,0 +1,9 @@
+#ifdef DEFINE_DWARF_REGSTR_TABLE
+/* This is included in perf/util/dwarf-regs.c */
+
+static const char * const arm_regstr_tbl[] = {
+       "%r0", "%r1", "%r2", "%r3", "%r4",
+       "%r5", "%r6", "%r7", "%r8", "%r9", "%r10",
+       "%fp", "%ip", "%sp", "%lr", "%pc",
+};
+#endif
diff --git a/tools/perf/arch/arm64/include/dwarf-regs-table.h b/tools/perf/arch/arm64/include/dwarf-regs-table.h
new file mode 100644 (file)
index 0000000..2675936
--- /dev/null
@@ -0,0 +1,13 @@
+#ifdef DEFINE_DWARF_REGSTR_TABLE
+/* This is included in perf/util/dwarf-regs.c */
+
+static const char * const aarch64_regstr_tbl[] = {
+       "%r0", "%r1", "%r2", "%r3", "%r4",
+       "%r5", "%r6", "%r7", "%r8", "%r9",
+       "%r10", "%r11", "%r12", "%r13", "%r14",
+       "%r15", "%r16", "%r17", "%r18", "%r19",
+       "%r20", "%r21", "%r22", "%r23", "%r24",
+       "%r25", "%r26", "%r27", "%r28", "%r29",
+       "%lr", "%sp",
+};
+#endif
diff --git a/tools/perf/arch/powerpc/include/dwarf-regs-table.h b/tools/perf/arch/powerpc/include/dwarf-regs-table.h
new file mode 100644 (file)
index 0000000..db4730f
--- /dev/null
@@ -0,0 +1,27 @@
+#ifdef DEFINE_DWARF_REGSTR_TABLE
+/* This is included in perf/util/dwarf-regs.c */
+
+/*
+ * Reference:
+ * http://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi-1.9.html
+ * http://refspecs.linux-foundation.org/elf/elfspec_ppc.pdf
+ */
+#define REG_DWARFNUM_NAME(reg, idx)    [idx] = "%" #reg
+
+static const char * const powerpc_regstr_tbl[] = {
+       "%gpr0", "%gpr1", "%gpr2", "%gpr3", "%gpr4",
+       "%gpr5", "%gpr6", "%gpr7", "%gpr8", "%gpr9",
+       "%gpr10", "%gpr11", "%gpr12", "%gpr13", "%gpr14",
+       "%gpr15", "%gpr16", "%gpr17", "%gpr18", "%gpr19",
+       "%gpr20", "%gpr21", "%gpr22", "%gpr23", "%gpr24",
+       "%gpr25", "%gpr26", "%gpr27", "%gpr28", "%gpr29",
+       "%gpr30", "%gpr31",
+       REG_DWARFNUM_NAME(msr,   66),
+       REG_DWARFNUM_NAME(ctr,   109),
+       REG_DWARFNUM_NAME(link,  108),
+       REG_DWARFNUM_NAME(xer,   101),
+       REG_DWARFNUM_NAME(dar,   119),
+       REG_DWARFNUM_NAME(dsisr, 118),
+};
+
+#endif
diff --git a/tools/perf/arch/s390/include/dwarf-regs-table.h b/tools/perf/arch/s390/include/dwarf-regs-table.h
new file mode 100644 (file)
index 0000000..9da74a9
--- /dev/null
@@ -0,0 +1,8 @@
+#ifdef DEFINE_DWARF_REGSTR_TABLE
+/* This is included in perf/util/dwarf-regs.c */
+
+static const char * const s390_regstr_tbl[] = {
+       "%r0", "%r1",  "%r2",  "%r3",  "%r4",  "%r5",  "%r6",  "%r7",
+       "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15",
+};
+#endif
diff --git a/tools/perf/arch/sh/include/dwarf-regs-table.h b/tools/perf/arch/sh/include/dwarf-regs-table.h
new file mode 100644 (file)
index 0000000..3a2deaf
--- /dev/null
@@ -0,0 +1,25 @@
+#ifdef DEFINE_DWARF_REGSTR_TABLE
+/* This is included in perf/util/dwarf-regs.c */
+
+const char * const sh_regstr_tbl[] = {
+       "r0",
+       "r1",
+       "r2",
+       "r3",
+       "r4",
+       "r5",
+       "r6",
+       "r7",
+       "r8",
+       "r9",
+       "r10",
+       "r11",
+       "r12",
+       "r13",
+       "r14",
+       "r15",
+       "pc",
+       "pr",
+};
+
+#endif
diff --git a/tools/perf/arch/sparc/include/dwarf-regs-table.h b/tools/perf/arch/sparc/include/dwarf-regs-table.h
new file mode 100644 (file)
index 0000000..12c0761
--- /dev/null
@@ -0,0 +1,18 @@
+#ifdef DEFINE_DWARF_REGSTR_TABLE
+/* This is included in perf/util/dwarf-regs.c */
+
+static const char * const sparc_regstr_tbl[] = {
+       "%g0", "%g1", "%g2", "%g3", "%g4", "%g5", "%g6", "%g7",
+       "%o0", "%o1", "%o2", "%o3", "%o4", "%o5", "%sp", "%o7",
+       "%l0", "%l1", "%l2", "%l3", "%l4", "%l5", "%l6", "%l7",
+       "%i0", "%i1", "%i2", "%i3", "%i4", "%i5", "%fp", "%i7",
+       "%f0", "%f1", "%f2", "%f3", "%f4", "%f5", "%f6", "%f7",
+       "%f8", "%f9", "%f10", "%f11", "%f12", "%f13", "%f14", "%f15",
+       "%f16", "%f17", "%f18", "%f19", "%f20", "%f21", "%f22", "%f23",
+       "%f24", "%f25", "%f26", "%f27", "%f28", "%f29", "%f30", "%f31",
+       "%f32", "%f33", "%f34", "%f35", "%f36", "%f37", "%f38", "%f39",
+       "%f40", "%f41", "%f42", "%f43", "%f44", "%f45", "%f46", "%f47",
+       "%f48", "%f49", "%f50", "%f51", "%f52", "%f53", "%f54", "%f55",
+       "%f56", "%f57", "%f58", "%f59", "%f60", "%f61", "%f62", "%f63",
+};
+#endif
diff --git a/tools/perf/arch/x86/include/dwarf-regs-table.h b/tools/perf/arch/x86/include/dwarf-regs-table.h
new file mode 100644 (file)
index 0000000..39ac7cb
--- /dev/null
@@ -0,0 +1,14 @@
+#ifdef DEFINE_DWARF_REGSTR_TABLE
+/* This is included in perf/util/dwarf-regs.c */
+
+static const char * const x86_32_regstr_tbl[] = {
+       "%ax", "%cx", "%dx", "%bx", "$stack",/* Stack address instead of %sp */
+       "%bp", "%si", "%di",
+};
+
+static const char * const x86_64_regstr_tbl[] = {
+       "%ax", "dx", "%cx", "%bx", "%si", "%di",
+       "%bp", "%sp", "%r8", "%r9", "%r10", "%r11",
+       "%r12", "%r13", "%r14", "%r15",
+};
+#endif
diff --git a/tools/perf/arch/xtensa/include/dwarf-regs-table.h b/tools/perf/arch/xtensa/include/dwarf-regs-table.h
new file mode 100644 (file)
index 0000000..aa0444a
--- /dev/null
@@ -0,0 +1,8 @@
+#ifdef DEFINE_DWARF_REGSTR_TABLE
+/* This is included in perf/util/dwarf-regs.c */
+
+static const char * const xtensa_regstr_tbl[] = {
+       "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7",
+       "a8", "a9", "a10", "a11", "a12", "a13", "a14", "a15",
+};
+#endif
index 9c1034d..f07b230 100644 (file)
@@ -204,8 +204,6 @@ static int __cmd_annotate(struct perf_annotate *ann)
        struct perf_evsel *pos;
        u64 total_nr_samples;
 
-       machines__set_symbol_filter(&session->machines, symbol__annotate_init);
-
        if (ann->cpu_list) {
                ret = perf_session__cpu_bitmap(session, ann->cpu_list,
                                               ann->cpu_bitmap);
@@ -367,7 +365,10 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
        if (annotate.session == NULL)
                return -1;
 
-       symbol_conf.priv_size = sizeof(struct annotation);
+       ret = symbol__annotation_init();
+       if (ret < 0)
+               goto out_delete;
+
        symbol_conf.try_vmlinux_path = true;
 
        ret = symbol__init(&annotate.session->header.env);
index ee5b421..f87996b 100644 (file)
@@ -326,6 +326,11 @@ static int perf_add_probe_events(struct perf_probe_event *pevs, int npevs)
        if (ret < 0)
                goto out_cleanup;
 
+       if (params.command == 'D') {    /* it shows definition */
+               ret = show_probe_trace_events(pevs, npevs);
+               goto out_cleanup;
+       }
+
        ret = apply_perf_probe_events(pevs, npevs);
        if (ret < 0)
                goto out_cleanup;
@@ -454,6 +459,14 @@ out:
        return ret;
 }
 
+#ifdef HAVE_DWARF_SUPPORT
+#define PROBEDEF_STR   \
+       "[EVENT=]FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT [[NAME=]ARG ...]"
+#else
+#define PROBEDEF_STR   "[EVENT=]FUNC[+OFF|%return] [[NAME=]ARG ...]"
+#endif
+
+
 static int
 __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
 {
@@ -479,13 +492,7 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
                             opt_set_filter_with_command, DEFAULT_LIST_FILTER),
        OPT_CALLBACK('d', "del", NULL, "[GROUP:]EVENT", "delete a probe event.",
                     opt_set_filter_with_command),
-       OPT_CALLBACK('a', "add", NULL,
-#ifdef HAVE_DWARF_SUPPORT
-               "[EVENT=]FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT"
-               " [[NAME=]ARG ...]",
-#else
-               "[EVENT=]FUNC[+OFF|%return] [[NAME=]ARG ...]",
-#endif
+       OPT_CALLBACK('a', "add", NULL, PROBEDEF_STR,
                "probe point definition, where\n"
                "\t\tGROUP:\tGroup name (optional)\n"
                "\t\tEVENT:\tEvent name\n"
@@ -503,6 +510,9 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
                "\t\tARG:\tProbe argument (kprobe-tracer argument format.)\n",
 #endif
                opt_add_probe_event),
+       OPT_CALLBACK('D', "definition", NULL, PROBEDEF_STR,
+               "Show trace event definition of given traceevent for k/uprobe_events.",
+               opt_add_probe_event),
        OPT_BOOLEAN('f', "force", &probe_conf.force_add, "forcibly add events"
                    " with existing name"),
        OPT_CALLBACK('L', "line", NULL,
@@ -548,6 +558,7 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
 
        set_option_flag(options, 'a', "add", PARSE_OPT_EXCLUSIVE);
        set_option_flag(options, 'd', "del", PARSE_OPT_EXCLUSIVE);
+       set_option_flag(options, 'D', "definition", PARSE_OPT_EXCLUSIVE);
        set_option_flag(options, 'l', "list", PARSE_OPT_EXCLUSIVE);
 #ifdef HAVE_DWARF_SUPPORT
        set_option_flag(options, 'L', "line", PARSE_OPT_EXCLUSIVE);
@@ -600,6 +611,14 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
         */
        symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
 
+       /*
+        * Except for --list, --del and --add, other command doesn't depend
+        * nor change running kernel. So if user gives offline vmlinux,
+        * ignore its buildid.
+        */
+       if (!strchr("lda", params.command) && symbol_conf.vmlinux_name)
+               symbol_conf.ignore_vmlinux_buildid = true;
+
        switch (params.command) {
        case 'l':
                if (params.uprobes) {
@@ -643,7 +662,9 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
                        return ret;
                }
                break;
+       case 'D':
        case 'a':
+
                /* Ensure the last given target is used */
                if (params.target && !params.target_used) {
                        pr_err("  Error: -x/-m must follow the probe definitions.\n");
index b9e046b..1a07c4c 100644 (file)
@@ -984,9 +984,9 @@ repeat:
         * implementation.
         */
        if (ui__has_annotation()) {
-               symbol_conf.priv_size = sizeof(struct annotation);
-               machines__set_symbol_filter(&session->machines,
-                                           symbol__annotate_init);
+               ret = symbol__annotation_init();
+               if (ret < 0)
+                       goto error;
                /*
                 * For searching by name on the "Browse map details".
                 * providing it only in verbose mode not to bloat too
index a3223aa..e091900 100644 (file)
@@ -680,7 +680,7 @@ static int symbol_filter(struct map *map, struct symbol *sym)
                return 1;
 
        if (symbol__is_idle(sym))
-               sym->ignore = true;
+               sym->idle = 1;
 
        return 0;
 }
@@ -783,7 +783,7 @@ static void perf_event__process_sample(struct perf_tool *tool,
                }
        }
 
-       if (al.sym == NULL || !al.sym->ignore) {
+       if (al.sym == NULL || !al.sym->idle) {
                struct hists *hists = evsel__hists(evsel);
                struct hist_entry_iter iter = {
                        .evsel          = evsel,
@@ -1324,7 +1324,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
        if (symbol_conf.cumulate_callchain && !callchain_param.order_set)
                callchain_param.order = ORDER_CALLER;
 
-       symbol_conf.priv_size = sizeof(struct annotation);
+       status = symbol__annotation_init();
+       if (status < 0)
+               goto out_delete_evlist;
 
        symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
        if (symbol__init(NULL) < 0)
index e63abab..77513bf 100644 (file)
@@ -28,6 +28,7 @@ int test__vmlinux_matches_kallsyms(int subtest __maybe_unused)
        enum map_type type = MAP__FUNCTION;
        struct maps *maps = &vmlinux.kmaps.maps[type];
        u64 mem_start, mem_end;
+       bool header_printed;
 
        /*
         * Step 1:
@@ -143,7 +144,7 @@ next_pair:
                                 */
                                s64 skew = mem_end - UM(pair->end);
                                if (llabs(skew) >= page_size)
-                                       pr_debug("%#" PRIx64 ": diff end addr for %s v: %#" PRIx64 " k: %#" PRIx64 "\n",
+                                       pr_debug("WARN: %#" PRIx64 ": diff end addr for %s v: %#" PRIx64 " k: %#" PRIx64 "\n",
                                                 mem_start, sym->name, mem_end,
                                                 UM(pair->end));
 
@@ -154,22 +155,23 @@ next_pair:
                                 * kallsyms.
                                 */
                                continue;
-
                        } else {
                                pair = machine__find_kernel_symbol_by_name(&kallsyms, type, sym->name, NULL, NULL);
                                if (pair) {
                                        if (UM(pair->start) == mem_start)
                                                goto next_pair;
 
-                                       pr_debug("%#" PRIx64 ": diff name v: %s k: %s\n",
+                                       pr_debug("WARN: %#" PRIx64 ": diff name v: %s k: %s\n",
                                                 mem_start, sym->name, pair->name);
                                } else {
-                                       pr_debug("%#" PRIx64 ": diff name v: %s k: %s\n",
+                                       pr_debug("WARN: %#" PRIx64 ": diff name v: %s k: %s\n",
                                                 mem_start, sym->name, first_pair->name);
                                }
+
+                               continue;
                        }
                } else
-                       pr_debug("%#" PRIx64 ": %s not on kallsyms\n",
+                       pr_debug("ERR : %#" PRIx64 ": %s not on kallsyms\n",
                                 mem_start, sym->name);
 
                err = -1;
@@ -178,7 +180,7 @@ next_pair:
        if (!verbose)
                goto out;
 
-       pr_info("Maps only in vmlinux:\n");
+       header_printed = false;
 
        for (map = maps__first(maps); map; map = map__next(map)) {
                struct map *
@@ -192,13 +194,18 @@ next_pair:
                                                (map->dso->kernel ?
                                                        map->dso->short_name :
                                                        map->dso->name));
-               if (pair)
+               if (pair) {
                        pair->priv = 1;
-               else
+               } else {
+                       if (!header_printed) {
+                               pr_info("WARN: Maps only in vmlinux:\n");
+                               header_printed = true;
+                       }
                        map__fprintf(map, stderr);
+               }
        }
 
-       pr_info("Maps in vmlinux with a different name in kallsyms:\n");
+       header_printed = false;
 
        for (map = maps__first(maps); map; map = map__next(map)) {
                struct map *pair;
@@ -211,24 +218,33 @@ next_pair:
                        continue;
 
                if (pair->start == mem_start) {
-                       pair->priv = 1;
-                       pr_info(" %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s in kallsyms as",
+                       if (!header_printed) {
+                               pr_info("WARN: Maps in vmlinux with a different name in kallsyms:\n");
+                               header_printed = true;
+                       }
+
+                       pr_info("WARN: %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s in kallsyms as",
                                map->start, map->end, map->pgoff, map->dso->name);
                        if (mem_end != pair->end)
-                               pr_info(":\n*%" PRIx64 "-%" PRIx64 " %" PRIx64,
+                               pr_info(":\nWARN: *%" PRIx64 "-%" PRIx64 " %" PRIx64,
                                        pair->start, pair->end, pair->pgoff);
                        pr_info(" %s\n", pair->dso->name);
                        pair->priv = 1;
                }
        }
 
-       pr_info("Maps only in kallsyms:\n");
+       header_printed = false;
 
        maps = &kallsyms.kmaps.maps[type];
 
        for (map = maps__first(maps); map; map = map__next(map)) {
-               if (!map->priv)
+               if (!map->priv) {
+                       if (!header_printed) {
+                               pr_info("WARN: Maps only in kallsyms:\n");
+                               header_printed = true;
+                       }
                        map__fprintf(map, stderr);
+               }
        }
 out:
        machine__exit(&kallsyms);
index 91c5f6e..f1a6d17 100644 (file)
@@ -98,6 +98,7 @@ endif
 
 libperf-$(CONFIG_DWARF) += probe-finder.o
 libperf-$(CONFIG_DWARF) += dwarf-aux.o
+libperf-$(CONFIG_DWARF) += dwarf-regs.o
 
 libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
 libperf-$(CONFIG_LOCAL_LIBUNWIND)    += unwind-libunwind-local.o
index 25a9259..1b59e31 100644 (file)
@@ -491,13 +491,6 @@ static struct ins *ins__find(const char *name)
        return bsearch(name, instructions, nmemb, sizeof(struct ins), ins__key_cmp);
 }
 
-int symbol__annotate_init(struct map *map __maybe_unused, struct symbol *sym)
-{
-       struct annotation *notes = symbol__annotation(sym);
-       pthread_mutex_init(&notes->lock, NULL);
-       return 0;
-}
-
 int symbol__alloc_hist(struct symbol *sym)
 {
        struct annotation *notes = symbol__annotation(sym);
index f67ccb0..e96f4da 100644 (file)
@@ -177,7 +177,6 @@ enum symbol_disassemble_errno {
 int symbol__strerror_disassemble(struct symbol *sym, struct map *map,
                                 int errnum, char *buf, size_t buflen);
 
-int symbol__annotate_init(struct map *map, struct symbol *sym);
 int symbol__annotate_printf(struct symbol *sym, struct map *map,
                            struct perf_evsel *evsel, bool full_paths,
                            int min_pcnt, int max_lines, int context);
index a347b19..faec899 100644 (file)
@@ -1085,3 +1085,182 @@ int die_get_var_range(Dwarf_Die *sp_die __maybe_unused,
        return -ENOTSUP;
 }
 #endif
+
+/*
+ * die_has_loclist - Check if DW_AT_location of @vr_die is a location list
+ * @vr_die: a variable DIE
+ */
+static bool die_has_loclist(Dwarf_Die *vr_die)
+{
+       Dwarf_Attribute loc;
+       int tag = dwarf_tag(vr_die);
+
+       if (tag != DW_TAG_formal_parameter &&
+           tag != DW_TAG_variable)
+               return false;
+
+       return (dwarf_attr_integrate(vr_die, DW_AT_location, &loc) &&
+               dwarf_whatform(&loc) == DW_FORM_sec_offset);
+}
+
+/*
+ * die_is_optimized_target - Check if target program is compiled with
+ * optimization
+ * @cu_die: a CU DIE
+ *
+ * For any object in given CU whose DW_AT_location is a location list,
+ * target program is compiled with optimization. This is applicable to
+ * clang as well.
+ */
+bool die_is_optimized_target(Dwarf_Die *cu_die)
+{
+       Dwarf_Die tmp_die;
+
+       if (die_has_loclist(cu_die))
+               return true;
+
+       if (!dwarf_child(cu_die, &tmp_die) &&
+           die_is_optimized_target(&tmp_die))
+               return true;
+
+       if (!dwarf_siblingof(cu_die, &tmp_die) &&
+           die_is_optimized_target(&tmp_die))
+               return true;
+
+       return false;
+}
+
+/*
+ * die_search_idx - Search index of given line address
+ * @lines: Line records of single CU
+ * @nr_lines: Number of @lines
+ * @addr: address we are looking for
+ * @idx: index to be set by this function (return value)
+ *
+ * Search for @addr by looping over every lines of CU. If address
+ * matches, set index of that line in @idx. Note that single source
+ * line can have multiple line records. i.e. single source line can
+ * have multiple index.
+ */
+static bool die_search_idx(Dwarf_Lines *lines, unsigned long nr_lines,
+                          Dwarf_Addr addr, unsigned long *idx)
+{
+       unsigned long i;
+       Dwarf_Addr tmp;
+
+       for (i = 0; i < nr_lines; i++) {
+               if (dwarf_lineaddr(dwarf_onesrcline(lines, i), &tmp))
+                       return false;
+
+               if (tmp == addr) {
+                       *idx = i;
+                       return true;
+               }
+       }
+       return false;
+}
+
+/*
+ * die_get_postprologue_addr - Search next address after function prologue
+ * @entrypc_idx: entrypc index
+ * @lines: Line records of single CU
+ * @nr_lines: Number of @lines
+ * @hignpc: high PC address of function
+ * @postprologue_addr: Next address after function prologue (return value)
+ *
+ * Look for prologue-end marker. If there is no explicit marker, return
+ * address of next line record or next source line.
+ */
+static bool die_get_postprologue_addr(unsigned long entrypc_idx,
+                                     Dwarf_Lines *lines,
+                                     unsigned long nr_lines,
+                                     Dwarf_Addr highpc,
+                                     Dwarf_Addr *postprologue_addr)
+{
+       unsigned long i;
+       int entrypc_lno, lno;
+       Dwarf_Line *line;
+       Dwarf_Addr addr;
+       bool p_end;
+
+       /* entrypc_lno is actual source line number */
+       line = dwarf_onesrcline(lines, entrypc_idx);
+       if (dwarf_lineno(line, &entrypc_lno))
+               return false;
+
+       for (i = entrypc_idx; i < nr_lines; i++) {
+               line = dwarf_onesrcline(lines, i);
+
+               if (dwarf_lineaddr(line, &addr) ||
+                   dwarf_lineno(line, &lno)    ||
+                   dwarf_lineprologueend(line, &p_end))
+                       return false;
+
+               /* highpc is exclusive. [entrypc,highpc) */
+               if (addr >= highpc)
+                       break;
+
+               /* clang supports prologue-end marker */
+               if (p_end)
+                       break;
+
+               /* Actual next line in source */
+               if (lno != entrypc_lno)
+                       break;
+
+               /*
+                * Single source line can have multiple line records.
+                * For Example,
+                *     void foo() { printf("hello\n"); }
+                * contains two line records. One points to declaration and
+                * other points to printf() line. Variable 'lno' won't get
+                * incremented in this case but 'i' will.
+                */
+               if (i != entrypc_idx)
+                       break;
+       }
+
+       dwarf_lineaddr(line, postprologue_addr);
+       if (*postprologue_addr >= highpc)
+               dwarf_lineaddr(dwarf_onesrcline(lines, i - 1),
+                              postprologue_addr);
+
+       return true;
+}
+
+/*
+ * die_skip_prologue - Use next address after prologue as probe location
+ * @sp_die: a subprogram DIE
+ * @cu_die: a CU DIE
+ * @entrypc: entrypc of the function
+ *
+ * Function prologue prepares stack and registers before executing function
+ * logic. When target program is compiled without optimization, function
+ * parameter information is only valid after prologue. When we probe entrypc
+ * of the function, and try to record function parameter, it contains
+ * garbage value.
+ */
+void die_skip_prologue(Dwarf_Die *sp_die, Dwarf_Die *cu_die,
+                      Dwarf_Addr *entrypc)
+{
+       size_t nr_lines = 0;
+       unsigned long entrypc_idx = 0;
+       Dwarf_Lines *lines = NULL;
+       Dwarf_Addr postprologue_addr;
+       Dwarf_Addr highpc;
+
+       if (dwarf_highpc(sp_die, &highpc))
+               return;
+
+       if (dwarf_getsrclines(cu_die, &lines, &nr_lines))
+               return;
+
+       if (!die_search_idx(lines, nr_lines, *entrypc, &entrypc_idx))
+               return;
+
+       if (!die_get_postprologue_addr(entrypc_idx, lines, nr_lines,
+                                      highpc, &postprologue_addr))
+               return;
+
+       *entrypc = postprologue_addr;
+}
index dc0ce1a..8b6d2f8 100644 (file)
@@ -125,4 +125,12 @@ int die_get_typename(Dwarf_Die *vr_die, struct strbuf *buf);
 /* Get the name and type of given variable DIE, stored as "type\tname" */
 int die_get_varname(Dwarf_Die *vr_die, struct strbuf *buf);
 int die_get_var_range(Dwarf_Die *sp_die, Dwarf_Die *vr_die, struct strbuf *buf);
+
+/* Check if target program is compiled with optimization */
+bool die_is_optimized_target(Dwarf_Die *cu_die);
+
+/* Use next address after prologue as probe location */
+void die_skip_prologue(Dwarf_Die *sp_die, Dwarf_Die *cu_die,
+                      Dwarf_Addr *entrypc);
+
 #endif
diff --git a/tools/perf/util/dwarf-regs.c b/tools/perf/util/dwarf-regs.c
new file mode 100644 (file)
index 0000000..62bc4a8
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * dwarf-regs.c : Mapping of DWARF debug register numbers into register names.
+ *
+ * Written by: Masami Hiramatsu <mhiramat@kernel.org>
+ */
+
+#include <util.h>
+#include <debug.h>
+#include <dwarf-regs.h>
+#include <elf.h>
+
+#ifndef EM_AARCH64
+#define EM_AARCH64     183  /* ARM 64 bit */
+#endif
+
+/* Define const char * {arch}_register_tbl[] */
+#define DEFINE_DWARF_REGSTR_TABLE
+#include "../arch/x86/include/dwarf-regs-table.h"
+#include "../arch/arm/include/dwarf-regs-table.h"
+#include "../arch/arm64/include/dwarf-regs-table.h"
+#include "../arch/sh/include/dwarf-regs-table.h"
+#include "../arch/powerpc/include/dwarf-regs-table.h"
+#include "../arch/s390/include/dwarf-regs-table.h"
+#include "../arch/sparc/include/dwarf-regs-table.h"
+#include "../arch/xtensa/include/dwarf-regs-table.h"
+
+#define __get_dwarf_regstr(tbl, n) (((n) < ARRAY_SIZE(tbl)) ? (tbl)[(n)] : NULL)
+
+/* Return architecture dependent register string (for kprobe-tracer) */
+const char *get_dwarf_regstr(unsigned int n, unsigned int machine)
+{
+       switch (machine) {
+       case EM_NONE:   /* Generic arch - use host arch */
+               return get_arch_regstr(n);
+       case EM_386:
+               return __get_dwarf_regstr(x86_32_regstr_tbl, n);
+       case EM_X86_64:
+               return __get_dwarf_regstr(x86_64_regstr_tbl, n);
+       case EM_ARM:
+               return __get_dwarf_regstr(arm_regstr_tbl, n);
+       case EM_AARCH64:
+               return __get_dwarf_regstr(aarch64_regstr_tbl, n);
+       case EM_SH:
+               return __get_dwarf_regstr(sh_regstr_tbl, n);
+       case EM_S390:
+               return __get_dwarf_regstr(s390_regstr_tbl, n);
+       case EM_PPC:
+       case EM_PPC64:
+               return __get_dwarf_regstr(powerpc_regstr_tbl, n);
+       case EM_SPARC:
+       case EM_SPARCV9:
+               return __get_dwarf_regstr(sparc_regstr_tbl, n);
+       case EM_XTENSA:
+               return __get_dwarf_regstr(xtensa_regstr_tbl, n);
+       default:
+               pr_err("ELF MACHINE %x is not supported.\n", machine);
+       }
+       return NULL;
+}
index 3674e77..9111e06 100644 (file)
@@ -122,7 +122,7 @@ int sample__fprintf_callchain(struct perf_sample *sample, int left_alignment,
                        if (!node)
                                break;
 
-                       if (node->sym && node->sym->ignore)
+                       if (node->sym && node->sym->idle)
                                goto next;
 
                        printed += fprintf(fp, "%-*.*s", left_alignment, left_alignment, " ");
@@ -181,7 +181,7 @@ int sample__fprintf_sym(struct perf_sample *sample, struct addr_location *al,
        if (cursor != NULL) {
                printed += sample__fprintf_callchain(sample, left_alignment,
                                                     print_opts, cursor, fp);
-       } else if (!(al->sym && al->sym->ignore)) {
+       } else if (!(al->sym && al->sym->idle)) {
                printed += fprintf(fp, "%-*.*s", left_alignment, left_alignment, " ");
 
                if (print_ip)
index 07c644e..43bfd8d 100644 (file)
@@ -3,6 +3,12 @@
 
 #ifdef HAVE_DWARF_SUPPORT
 const char *get_arch_regstr(unsigned int n);
+/*
+ * get_dwarf_regstr - Returns ftrace register string from DWARF regnum
+ * n: DWARF register number
+ * machine: ELF machine signature (EM_*)
+ */
+const char *get_dwarf_regstr(unsigned int n, unsigned int machine);
 #endif
 
 #ifdef HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET
index 95a1acb..9ddea5c 100644 (file)
@@ -29,6 +29,7 @@ int lzma_decompress_to_file(const char *input, int output_fd)
        lzma_action action = LZMA_RUN;
        lzma_stream strm   = LZMA_STREAM_INIT;
        lzma_ret ret;
+       int err = -1;
 
        u8 buf_in[BUFSIZE];
        u8 buf_out[BUFSIZE];
@@ -45,7 +46,7 @@ int lzma_decompress_to_file(const char *input, int output_fd)
        if (ret != LZMA_OK) {
                pr_err("lzma: lzma_stream_decoder failed %s (%d)\n",
                        lzma_strerror(ret), ret);
-               return -1;
+               goto err_fclose;
        }
 
        strm.next_in   = NULL;
@@ -60,7 +61,7 @@ int lzma_decompress_to_file(const char *input, int output_fd)
 
                        if (ferror(infile)) {
                                pr_err("lzma: read error: %s\n", strerror(errno));
-                               return -1;
+                               goto err_fclose;
                        }
 
                        if (feof(infile))
@@ -74,7 +75,7 @@ int lzma_decompress_to_file(const char *input, int output_fd)
 
                        if (writen(output_fd, buf_out, write_size) != write_size) {
                                pr_err("lzma: write error: %s\n", strerror(errno));
-                               return -1;
+                               goto err_fclose;
                        }
 
                        strm.next_out  = buf_out;
@@ -83,13 +84,15 @@ int lzma_decompress_to_file(const char *input, int output_fd)
 
                if (ret != LZMA_OK) {
                        if (ret == LZMA_STREAM_END)
-                               return 0;
+                               break;
 
                        pr_err("lzma: failed %s\n", lzma_strerror(ret));
-                       return -1;
+                       goto err_fclose;
                }
        }
 
+       err = 0;
+err_fclose:
        fclose(infile);
-       return 0;
+       return err;
 }
index 2873396..a543e9c 100644 (file)
@@ -674,6 +674,10 @@ post_process_kernel_probe_trace_events(struct probe_trace_event *tevs,
        char *tmp;
        int i, skipped = 0;
 
+       /* Skip post process if the target is an offline kernel */
+       if (symbol_conf.ignore_vmlinux_buildid)
+               return 0;
+
        reloc_sym = kernel_get_ref_reloc_sym();
        if (!reloc_sym) {
                pr_warning("Relocated base symbol is not found!\n");
@@ -1614,19 +1618,27 @@ out:
        return ret;
 }
 
+/* Returns true if *any* ARG is either C variable, $params or $vars. */
+bool perf_probe_with_var(struct perf_probe_event *pev)
+{
+       int i = 0;
+
+       for (i = 0; i < pev->nargs; i++)
+               if (is_c_varname(pev->args[i].var)              ||
+                   !strcmp(pev->args[i].var, PROBE_ARG_PARAMS) ||
+                   !strcmp(pev->args[i].var, PROBE_ARG_VARS))
+                       return true;
+       return false;
+}
+
 /* Return true if this perf_probe_event requires debuginfo */
 bool perf_probe_event_need_dwarf(struct perf_probe_event *pev)
 {
-       int i;
-
        if (pev->point.file || pev->point.line || pev->point.lazy_line)
                return true;
 
-       for (i = 0; i < pev->nargs; i++)
-               if (is_c_varname(pev->args[i].var) ||
-                   !strcmp(pev->args[i].var, "$params") ||
-                   !strcmp(pev->args[i].var, "$vars"))
-                       return true;
+       if (perf_probe_with_var(pev))
+               return true;
 
        return false;
 }
@@ -3207,6 +3219,52 @@ int convert_perf_probe_events(struct perf_probe_event *pevs, int npevs)
        return 0;
 }
 
+static int show_probe_trace_event(struct probe_trace_event *tev)
+{
+       char *buf = synthesize_probe_trace_command(tev);
+
+       if (!buf) {
+               pr_debug("Failed to synthesize probe trace event.\n");
+               return -EINVAL;
+       }
+
+       /* Showing definition always go stdout */
+       printf("%s\n", buf);
+       free(buf);
+
+       return 0;
+}
+
+int show_probe_trace_events(struct perf_probe_event *pevs, int npevs)
+{
+       struct strlist *namelist = strlist__new(NULL, NULL);
+       struct probe_trace_event *tev;
+       struct perf_probe_event *pev;
+       int i, j, ret = 0;
+
+       if (!namelist)
+               return -ENOMEM;
+
+       for (j = 0; j < npevs && !ret; j++) {
+               pev = &pevs[j];
+               for (i = 0; i < pev->ntevs && !ret; i++) {
+                       tev = &pev->tevs[i];
+                       /* Skip if the symbol is out of .text or blacklisted */
+                       if (!tev->point.symbol && !pev->uprobes)
+                               continue;
+
+                       /* Set new name for tev (and update namelist) */
+                       ret = probe_trace_event__set_name(tev, pev,
+                                                         namelist, true);
+                       if (!ret)
+                               ret = show_probe_trace_event(tev);
+               }
+       }
+       strlist__delete(namelist);
+
+       return ret;
+}
+
 int apply_perf_probe_events(struct perf_probe_event *pevs, int npevs)
 {
        int i, ret = 0;
@@ -3289,24 +3347,10 @@ out:
        return ret;
 }
 
-/* TODO: don't use a global variable for filter ... */
-static struct strfilter *available_func_filter;
-
-/*
- * If a symbol corresponds to a function with global binding and
- * matches filter return 0. For all others return 1.
- */
-static int filter_available_functions(struct map *map __maybe_unused,
-                                     struct symbol *sym)
-{
-       if (strfilter__compare(available_func_filter, sym->name))
-               return 0;
-       return 1;
-}
-
 int show_available_funcs(const char *target, struct strfilter *_filter,
                                        bool user)
 {
+        struct rb_node *nd;
        struct map *map;
        int ret;
 
@@ -3324,9 +3368,7 @@ int show_available_funcs(const char *target, struct strfilter *_filter,
                return -EINVAL;
        }
 
-       /* Load symbols with given filter */
-       available_func_filter = _filter;
-       ret = map__load(map, filter_available_functions);
+       ret = map__load(map, NULL);
        if (ret) {
                if (ret == -2) {
                        char *str = strfilter__string(_filter);
@@ -3343,7 +3385,14 @@ int show_available_funcs(const char *target, struct strfilter *_filter,
 
        /* Show all (filtered) symbols */
        setup_pager();
-       dso__fprintf_symbols_by_name(map->dso, map->type, stdout);
+
+        for (nd = rb_first(&map->dso->symbol_names[map->type]); nd; nd = rb_next(nd)) {
+               struct symbol_name_rb_node *pos = rb_entry(nd, struct symbol_name_rb_node, rb_node);
+
+               if (strfilter__compare(_filter, pos->sym.name))
+                       printf("%s\n", pos->sym.name);
+        }
+
 end:
        if (user) {
                map__put(map);
index f4f45db..8091d15 100644 (file)
@@ -128,6 +128,8 @@ char *synthesize_perf_probe_point(struct perf_probe_point *pp);
 int perf_probe_event__copy(struct perf_probe_event *dst,
                           struct perf_probe_event *src);
 
+bool perf_probe_with_var(struct perf_probe_event *pev);
+
 /* Check the perf_probe_event needs debuginfo */
 bool perf_probe_event_need_dwarf(struct perf_probe_event *pev);
 
@@ -147,6 +149,7 @@ int line_range__init(struct line_range *lr);
 int add_perf_probe_events(struct perf_probe_event *pevs, int npevs);
 int convert_perf_probe_events(struct perf_probe_event *pevs, int npevs);
 int apply_perf_probe_events(struct perf_probe_event *pevs, int npevs);
+int show_probe_trace_events(struct perf_probe_event *pevs, int npevs);
 void cleanup_perf_probe_events(struct perf_probe_event *pevs, int npevs);
 int del_perf_probe_events(struct strfilter *filter);
 
index 697ef66..6f931e4 100644 (file)
@@ -73,11 +73,10 @@ static void print_both_open_warning(int kerr, int uerr)
 static int open_probe_events(const char *trace_file, bool readwrite)
 {
        char buf[PATH_MAX];
-       const char *tracing_dir = "";
        int ret;
 
-       ret = e_snprintf(buf, PATH_MAX, "%s/%s%s",
-                        tracing_path, tracing_dir, trace_file);
+       ret = e_snprintf(buf, PATH_MAX, "%s/%s",
+                        tracing_path, trace_file);
        if (ret >= 0) {
                pr_debug("Opening %s write=%d\n", buf, readwrite);
                if (readwrite && !probe_event_dry_run)
index ac4740f..8daca4f 100644 (file)
@@ -171,6 +171,7 @@ static struct probe_trace_arg_ref *alloc_trace_arg_ref(long offs)
  */
 static int convert_variable_location(Dwarf_Die *vr_die, Dwarf_Addr addr,
                                     Dwarf_Op *fb_ops, Dwarf_Die *sp_die,
+                                    unsigned int machine,
                                     struct probe_trace_arg *tvar)
 {
        Dwarf_Attribute attr;
@@ -266,7 +267,7 @@ static_var:
        if (!tvar)
                return ret2;
 
-       regs = get_arch_regstr(regn);
+       regs = get_dwarf_regstr(regn, machine);
        if (!regs) {
                /* This should be a bug in DWARF or this tool */
                pr_warning("Mapping for the register number %u "
@@ -543,7 +544,7 @@ static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
                 dwarf_diename(vr_die));
 
        ret = convert_variable_location(vr_die, pf->addr, pf->fb_ops,
-                                       &pf->sp_die, pf->tvar);
+                                       &pf->sp_die, pf->machine, pf->tvar);
        if (ret == -ENOENT || ret == -EINVAL) {
                pr_err("Failed to find the location of the '%s' variable at this address.\n"
                       " Perhaps it has been optimized out.\n"
@@ -906,6 +907,38 @@ static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
        return die_walk_lines(sp_die, probe_point_lazy_walker, pf);
 }
 
+static void skip_prologue(Dwarf_Die *sp_die, struct probe_finder *pf)
+{
+       struct perf_probe_point *pp = &pf->pev->point;
+
+       /* Not uprobe? */
+       if (!pf->pev->uprobes)
+               return;
+
+       /* Compiled with optimization? */
+       if (die_is_optimized_target(&pf->cu_die))
+               return;
+
+       /* Don't know entrypc? */
+       if (!pf->addr)
+               return;
+
+       /* Only FUNC and FUNC@SRC are eligible. */
+       if (!pp->function || pp->line || pp->retprobe || pp->lazy_line ||
+           pp->offset || pp->abs_address)
+               return;
+
+       /* Not interested in func parameter? */
+       if (!perf_probe_with_var(pf->pev))
+               return;
+
+       pr_info("Target program is compiled without optimization. Skipping prologue.\n"
+               "Probe on address 0x%" PRIx64 " to force probing at the function entry.\n\n",
+               pf->addr);
+
+       die_skip_prologue(sp_die, &pf->cu_die, &pf->addr);
+}
+
 static int probe_point_inline_cb(Dwarf_Die *in_die, void *data)
 {
        struct probe_finder *pf = data;
@@ -968,6 +1001,7 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
                if (pp->lazy_line)
                        param->retval = find_probe_point_lazy(sp_die, pf);
                else {
+                       skip_prologue(sp_die, pf);
                        pf->addr += pp->offset;
                        /* TODO: Check the address in this function */
                        param->retval = call_probe_finder(sp_die, pf);
@@ -1106,11 +1140,8 @@ static int debuginfo__find_probes(struct debuginfo *dbg,
                                  struct probe_finder *pf)
 {
        int ret = 0;
-
-#if _ELFUTILS_PREREQ(0, 142)
        Elf *elf;
        GElf_Ehdr ehdr;
-       GElf_Shdr shdr;
 
        if (pf->cfi_eh || pf->cfi_dbg)
                return debuginfo__find_probe_location(dbg, pf);
@@ -1123,11 +1154,18 @@ static int debuginfo__find_probes(struct debuginfo *dbg,
        if (gelf_getehdr(elf, &ehdr) == NULL)
                return -EINVAL;
 
-       if (elf_section_by_name(elf, &ehdr, &shdr, ".eh_frame", NULL) &&
-           shdr.sh_type == SHT_PROGBITS)
-               pf->cfi_eh = dwarf_getcfi_elf(elf);
+       pf->machine = ehdr.e_machine;
+
+#if _ELFUTILS_PREREQ(0, 142)
+       do {
+               GElf_Shdr shdr;
+
+               if (elf_section_by_name(elf, &ehdr, &shdr, ".eh_frame", NULL) &&
+                   shdr.sh_type == SHT_PROGBITS)
+                       pf->cfi_eh = dwarf_getcfi_elf(elf);
 
-       pf->cfi_dbg = dwarf_getcfi(dbg->dbg);
+               pf->cfi_dbg = dwarf_getcfi(dbg->dbg);
+       } while (0);
 #endif
 
        ret = debuginfo__find_probe_location(dbg, pf);
@@ -1155,7 +1193,7 @@ static int copy_variables_cb(Dwarf_Die *die_mem, void *data)
            (tag == DW_TAG_variable && vf->vars)) {
                if (convert_variable_location(die_mem, vf->pf->addr,
                                              vf->pf->fb_ops, &pf->sp_die,
-                                             NULL) == 0) {
+                                             pf->machine, NULL) == 0) {
                        vf->args[vf->nargs].var = (char *)dwarf_diename(die_mem);
                        if (vf->args[vf->nargs].var == NULL) {
                                vf->ret = -ENOMEM;
@@ -1318,7 +1356,7 @@ static int collect_variables_cb(Dwarf_Die *die_mem, void *data)
            tag == DW_TAG_variable) {
                ret = convert_variable_location(die_mem, af->pf.addr,
                                                af->pf.fb_ops, &af->pf.sp_die,
-                                               NULL);
+                                               af->pf.machine, NULL);
                if (ret == 0 || ret == -ERANGE) {
                        int ret2;
                        bool externs = !af->child;
index 51137fc..f1d8558 100644 (file)
@@ -80,6 +80,7 @@ struct probe_finder {
        Dwarf_CFI               *cfi_dbg;
 #endif
        Dwarf_Op                *fb_ops;        /* Frame base attribute */
+       unsigned int            machine;        /* Target machine arch */
        struct perf_probe_arg   *pvar;          /* Current target variable */
        struct probe_trace_arg  *tvar;          /* Current result variable */
 };
index a811c13..295d314 100644 (file)
@@ -206,6 +206,37 @@ Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
        return NULL;
 }
 
+static bool want_demangle(bool is_kernel_sym)
+{
+       return is_kernel_sym ? symbol_conf.demangle_kernel : symbol_conf.demangle;
+}
+
+static char *demangle_sym(struct dso *dso, int kmodule, const char *elf_name)
+{
+       int demangle_flags = verbose ? (DMGL_PARAMS | DMGL_ANSI) : DMGL_NO_OPTS;
+       char *demangled = NULL;
+
+       /*
+        * We need to figure out if the object was created from C++ sources
+        * DWARF DW_compile_unit has this, but we don't always have access
+        * to it...
+        */
+       if (!want_demangle(dso->kernel || kmodule))
+           return demangled;
+
+       demangled = bfd_demangle(NULL, elf_name, demangle_flags);
+       if (demangled == NULL)
+               demangled = java_demangle_sym(elf_name, JAVA_DEMANGLE_NORET);
+       else if (rust_is_mangled(demangled))
+               /*
+                   * Input to Rust demangling is the BFD-demangled
+                   * name which it Rust-demangles in place.
+                   */
+               rust_demangle_sym(demangled);
+
+       return demangled;
+}
+
 #define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \
        for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \
             idx < nr_entries; \
@@ -301,11 +332,19 @@ int dso__synthesize_plt_symbols(struct dso *dso, struct symsrc *ss, struct map *
 
                elf_section__for_each_rela(reldata, pos, pos_mem, idx,
                                           nr_rel_entries) {
+                       const char *elf_name = NULL;
+                       char *demangled = NULL;
                        symidx = GELF_R_SYM(pos->r_info);
                        plt_offset += shdr_plt.sh_entsize;
                        gelf_getsym(syms, symidx, &sym);
+
+                       elf_name = elf_sym__name(&sym, symstrs);
+                       demangled = demangle_sym(dso, 0, elf_name);
+                       if (demangled != NULL)
+                               elf_name = demangled;
                        snprintf(sympltname, sizeof(sympltname),
-                                "%s@plt", elf_sym__name(&sym, symstrs));
+                                "%s@plt", elf_name);
+                       free(demangled);
 
                        f = symbol__new(plt_offset, shdr_plt.sh_entsize,
                                        STB_GLOBAL, sympltname);
@@ -323,11 +362,19 @@ int dso__synthesize_plt_symbols(struct dso *dso, struct symsrc *ss, struct map *
                GElf_Rel pos_mem, *pos;
                elf_section__for_each_rel(reldata, pos, pos_mem, idx,
                                          nr_rel_entries) {
+                       const char *elf_name = NULL;
+                       char *demangled = NULL;
                        symidx = GELF_R_SYM(pos->r_info);
                        plt_offset += shdr_plt.sh_entsize;
                        gelf_getsym(syms, symidx, &sym);
+
+                       elf_name = elf_sym__name(&sym, symstrs);
+                       demangled = demangle_sym(dso, 0, elf_name);
+                       if (demangled != NULL)
+                               elf_name = demangled;
                        snprintf(sympltname, sizeof(sympltname),
-                                "%s@plt", elf_sym__name(&sym, symstrs));
+                                "%s@plt", elf_name);
+                       free(demangled);
 
                        f = symbol__new(plt_offset, shdr_plt.sh_entsize,
                                        STB_GLOBAL, sympltname);
@@ -685,7 +732,7 @@ int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name,
        }
 
        /* Always reject images with a mismatched build-id: */
-       if (dso->has_build_id) {
+       if (dso->has_build_id && !symbol_conf.ignore_vmlinux_buildid) {
                u8 build_id[BUILD_ID_SIZE];
 
                if (elf_read_build_id(elf, build_id, BUILD_ID_SIZE) < 0) {
@@ -775,11 +822,6 @@ static u64 ref_reloc(struct kmap *kmap)
        return 0;
 }
 
-static bool want_demangle(bool is_kernel_sym)
-{
-       return is_kernel_sym ? symbol_conf.demangle_kernel : symbol_conf.demangle;
-}
-
 void __weak arch__sym_update(struct symbol *s __maybe_unused,
                GElf_Sym *sym __maybe_unused) { }
 
@@ -1070,29 +1112,10 @@ int dso__load_sym(struct dso *dso, struct map *map,
                        sym.st_value -= shdr.sh_addr - shdr.sh_offset;
                }
 new_symbol:
-               /*
-                * We need to figure out if the object was created from C++ sources
-                * DWARF DW_compile_unit has this, but we don't always have access
-                * to it...
-                */
-               if (want_demangle(dso->kernel || kmodule)) {
-                       int demangle_flags = DMGL_NO_OPTS;
-                       if (verbose)
-                               demangle_flags = DMGL_PARAMS | DMGL_ANSI;
-
-                       demangled = bfd_demangle(NULL, elf_name, demangle_flags);
-                       if (demangled == NULL)
-                               demangled = java_demangle_sym(elf_name, JAVA_DEMANGLE_NORET);
-                       else if (rust_is_mangled(demangled))
-                               /*
-                                * Input to Rust demangling is the BFD-demangled
-                                * name which it Rust-demangles in place.
-                                */
-                               rust_demangle_sym(demangled);
+               demangled = demangle_sym(dso, kmodule, elf_name);
+               if (demangled != NULL)
+                       elf_name = demangled;
 
-                       if (demangled != NULL)
-                               elf_name = demangled;
-               }
                f = symbol__new(sym.st_value, sym.st_size,
                                GELF_ST_BIND(sym.st_info), elf_name);
                free(demangled);
@@ -1113,9 +1136,8 @@ new_symbol:
         * For misannotated, zeroed, ASM function sizes.
         */
        if (nr > 0) {
-               if (!symbol_conf.allow_aliases)
-                       symbols__fixup_duplicate(&dso->symbols[map->type]);
                symbols__fixup_end(&dso->symbols[map->type]);
+               symbols__fixup_duplicate(&dso->symbols[map->type]);
                if (kmap) {
                        /*
                         * We need to fixup this here too because we create new
index 37e8d20..98cd503 100644 (file)
@@ -9,6 +9,7 @@
 #include <fcntl.h>
 #include <unistd.h>
 #include <inttypes.h>
+#include "annotate.h"
 #include "build-id.h"
 #include "util.h"
 #include "debug.h"
@@ -152,6 +153,9 @@ void symbols__fixup_duplicate(struct rb_root *symbols)
        struct rb_node *nd;
        struct symbol *curr, *next;
 
+       if (symbol_conf.allow_aliases)
+               return;
+
        nd = rb_first(symbols);
 
        while (nd) {
@@ -235,8 +239,13 @@ struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name)
        if (sym == NULL)
                return NULL;
 
-       if (symbol_conf.priv_size)
+       if (symbol_conf.priv_size) {
+               if (symbol_conf.init_annotation) {
+                       struct annotation *notes = (void *)sym;
+                       pthread_mutex_init(&notes->lock, NULL);
+               }
                sym = ((void *)sym) + symbol_conf.priv_size;
+       }
 
        sym->start   = start;
        sym->end     = len ? start + len : start;
@@ -1234,8 +1243,8 @@ int __dso__load_kallsyms(struct dso *dso, const char *filename,
        if (kallsyms__delta(map, filename, &delta))
                return -1;
 
-       symbols__fixup_duplicate(&dso->symbols[map->type]);
        symbols__fixup_end(&dso->symbols[map->type]);
+       symbols__fixup_duplicate(&dso->symbols[map->type]);
 
        if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
                dso->symtab_type = DSO_BINARY_TYPE__GUEST_KALLSYMS;
@@ -1948,6 +1957,23 @@ static bool symbol__read_kptr_restrict(void)
        return value;
 }
 
+int symbol__annotation_init(void)
+{
+       if (symbol_conf.initialized) {
+               pr_err("Annotation needs to be init before symbol__init()\n");
+               return -1;
+       }
+
+       if (symbol_conf.init_annotation) {
+               pr_warning("Annotation being initialized multiple times\n");
+               return 0;
+       }
+
+       symbol_conf.priv_size += sizeof(struct annotation);
+       symbol_conf.init_annotation = true;
+       return 0;
+}
+
 int symbol__init(struct perf_env *env)
 {
        const char *symfs;
index 699f7cb..e54ee7c 100644 (file)
@@ -57,7 +57,7 @@ struct symbol {
        u64             end;
        u16             namelen;
        u8              binding;
-       bool            ignore;
+       u8              idle:1;
        u8              arch_sym;
        char            name[0];
 };
@@ -88,6 +88,7 @@ struct symbol_conf {
        unsigned short  priv_size;
        unsigned short  nr_events;
        bool            try_vmlinux_path,
+                       init_annotation,
                        force,
                        ignore_vmlinux,
                        ignore_vmlinux_buildid,
@@ -277,6 +278,8 @@ struct perf_env;
 int symbol__init(struct perf_env *env);
 void symbol__exit(void);
 void symbol__elf_init(void);
+int symbol__annotation_init(void);
+
 struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name);
 size_t __symbol__fprintf_symname_offs(const struct symbol *sym,
                                      const struct addr_location *al,