aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tools/perf/Documentation/perf-config.txt8
-rw-r--r--tools/perf/Documentation/perf-probe.txt9
-rw-r--r--tools/perf/Documentation/perfconfig.example9
-rw-r--r--tools/perf/arch/arm/include/dwarf-regs-table.h9
-rw-r--r--tools/perf/arch/arm64/include/dwarf-regs-table.h13
-rw-r--r--tools/perf/arch/powerpc/include/dwarf-regs-table.h27
-rw-r--r--tools/perf/arch/s390/include/dwarf-regs-table.h8
-rw-r--r--tools/perf/arch/sh/include/dwarf-regs-table.h25
-rw-r--r--tools/perf/arch/sparc/include/dwarf-regs-table.h18
-rw-r--r--tools/perf/arch/x86/include/dwarf-regs-table.h14
-rw-r--r--tools/perf/arch/xtensa/include/dwarf-regs-table.h8
-rw-r--r--tools/perf/builtin-annotate.c7
-rw-r--r--tools/perf/builtin-probe.c35
-rw-r--r--tools/perf/builtin-report.c6
-rw-r--r--tools/perf/builtin-top.c8
-rw-r--r--tools/perf/tests/vmlinux-kallsyms.c44
-rw-r--r--tools/perf/util/Build1
-rw-r--r--tools/perf/util/annotate.c7
-rw-r--r--tools/perf/util/annotate.h1
-rw-r--r--tools/perf/util/dwarf-aux.c179
-rw-r--r--tools/perf/util/dwarf-aux.h8
-rw-r--r--tools/perf/util/dwarf-regs.c59
-rw-r--r--tools/perf/util/evsel_fprintf.c4
-rw-r--r--tools/perf/util/include/dwarf-regs.h6
-rw-r--r--tools/perf/util/lzma.c15
-rw-r--r--tools/perf/util/probe-event.c101
-rw-r--r--tools/perf/util/probe-event.h3
-rw-r--r--tools/perf/util/probe-file.c5
-rw-r--r--tools/perf/util/probe-finder.c60
-rw-r--r--tools/perf/util/probe-finder.h1
-rw-r--r--tools/perf/util/symbol-elf.c86
-rw-r--r--tools/perf/util/symbol.c30
-rw-r--r--tools/perf/util/symbol.h5
33 files changed, 698 insertions, 121 deletions
diff --git a/tools/perf/Documentation/perf-config.txt b/tools/perf/Documentation/perf-config.txt
index 68c89190e79c..cb081ac59fd1 100644
--- a/tools/perf/Documentation/perf-config.txt
+++ b/tools/perf/Documentation/perf-config.txt
@@ -110,6 +110,14 @@ Given a $HOME/.perfconfig like this:
110 order = caller 110 order = caller
111 sort-key = function 111 sort-key = function
112 112
113 [report]
114 # Defaults
115 sort-order = comm,dso,symbol
116 percent-limit = 0
117 queue-size = 0
118 children = true
119 group = true
120
113Variables 121Variables
114~~~~~~~~~ 122~~~~~~~~~
115 123
diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
index f37d123d5dac..e6c9902c6d82 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -21,6 +21,8 @@ or
21'perf probe' [options] --vars='PROBEPOINT' 21'perf probe' [options] --vars='PROBEPOINT'
22or 22or
23'perf probe' [options] --funcs 23'perf probe' [options] --funcs
24or
25'perf probe' [options] --definition='PROBE' [...]
24 26
25DESCRIPTION 27DESCRIPTION
26----------- 28-----------
@@ -34,6 +36,8 @@ OPTIONS
34-k:: 36-k::
35--vmlinux=PATH:: 37--vmlinux=PATH::
36 Specify vmlinux path which has debuginfo (Dwarf binary). 38 Specify vmlinux path which has debuginfo (Dwarf binary).
39 Only when using this with --definition, you can give an offline
40 vmlinux file.
37 41
38-m:: 42-m::
39--module=MODNAME|PATH:: 43--module=MODNAME|PATH::
@@ -96,6 +100,11 @@ OPTIONS
96 can also list functions in a user space executable / shared library. 100 can also list functions in a user space executable / shared library.
97 This also can accept a FILTER rule argument. 101 This also can accept a FILTER rule argument.
98 102
103-D::
104--definition=::
105 Show trace-event definition converted from given probe-event instead
106 of write it into tracing/[k,u]probe_events.
107
99--filter=FILTER:: 108--filter=FILTER::
100 (Only for --vars and --funcs) Set filter. FILTER is a combination of glob 109 (Only for --vars and --funcs) Set filter. FILTER is a combination of glob
101 pattern, see FILTER PATTERN for detail. 110 pattern, see FILTER PATTERN for detail.
diff --git a/tools/perf/Documentation/perfconfig.example b/tools/perf/Documentation/perfconfig.example
index 1d8d5bc4cd2d..2b477c1d1efe 100644
--- a/tools/perf/Documentation/perfconfig.example
+++ b/tools/perf/Documentation/perfconfig.example
@@ -27,3 +27,12 @@
27 use_offset = true 27 use_offset = true
28 jump_arrows = true 28 jump_arrows = true
29 show_nr_jumps = false 29 show_nr_jumps = false
30
31[report]
32
33 # Defaults
34 sort-order = comm,dso,symbol
35 percent-limit = 0
36 queue-size = 0
37 children = true
38 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
index 000000000000..f298d034c37b
--- /dev/null
+++ b/tools/perf/arch/arm/include/dwarf-regs-table.h
@@ -0,0 +1,9 @@
1#ifdef DEFINE_DWARF_REGSTR_TABLE
2/* This is included in perf/util/dwarf-regs.c */
3
4static const char * const arm_regstr_tbl[] = {
5 "%r0", "%r1", "%r2", "%r3", "%r4",
6 "%r5", "%r6", "%r7", "%r8", "%r9", "%r10",
7 "%fp", "%ip", "%sp", "%lr", "%pc",
8};
9#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
index 000000000000..26759363f921
--- /dev/null
+++ b/tools/perf/arch/arm64/include/dwarf-regs-table.h
@@ -0,0 +1,13 @@
1#ifdef DEFINE_DWARF_REGSTR_TABLE
2/* This is included in perf/util/dwarf-regs.c */
3
4static const char * const aarch64_regstr_tbl[] = {
5 "%r0", "%r1", "%r2", "%r3", "%r4",
6 "%r5", "%r6", "%r7", "%r8", "%r9",
7 "%r10", "%r11", "%r12", "%r13", "%r14",
8 "%r15", "%r16", "%r17", "%r18", "%r19",
9 "%r20", "%r21", "%r22", "%r23", "%r24",
10 "%r25", "%r26", "%r27", "%r28", "%r29",
11 "%lr", "%sp",
12};
13#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
index 000000000000..db4730f5585c
--- /dev/null
+++ b/tools/perf/arch/powerpc/include/dwarf-regs-table.h
@@ -0,0 +1,27 @@
1#ifdef DEFINE_DWARF_REGSTR_TABLE
2/* This is included in perf/util/dwarf-regs.c */
3
4/*
5 * Reference:
6 * http://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi-1.9.html
7 * http://refspecs.linux-foundation.org/elf/elfspec_ppc.pdf
8 */
9#define REG_DWARFNUM_NAME(reg, idx) [idx] = "%" #reg
10
11static const char * const powerpc_regstr_tbl[] = {
12 "%gpr0", "%gpr1", "%gpr2", "%gpr3", "%gpr4",
13 "%gpr5", "%gpr6", "%gpr7", "%gpr8", "%gpr9",
14 "%gpr10", "%gpr11", "%gpr12", "%gpr13", "%gpr14",
15 "%gpr15", "%gpr16", "%gpr17", "%gpr18", "%gpr19",
16 "%gpr20", "%gpr21", "%gpr22", "%gpr23", "%gpr24",
17 "%gpr25", "%gpr26", "%gpr27", "%gpr28", "%gpr29",
18 "%gpr30", "%gpr31",
19 REG_DWARFNUM_NAME(msr, 66),
20 REG_DWARFNUM_NAME(ctr, 109),
21 REG_DWARFNUM_NAME(link, 108),
22 REG_DWARFNUM_NAME(xer, 101),
23 REG_DWARFNUM_NAME(dar, 119),
24 REG_DWARFNUM_NAME(dsisr, 118),
25};
26
27#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
index 000000000000..9da74a933bd6
--- /dev/null
+++ b/tools/perf/arch/s390/include/dwarf-regs-table.h
@@ -0,0 +1,8 @@
1#ifdef DEFINE_DWARF_REGSTR_TABLE
2/* This is included in perf/util/dwarf-regs.c */
3
4static const char * const s390_regstr_tbl[] = {
5 "%r0", "%r1", "%r2", "%r3", "%r4", "%r5", "%r6", "%r7",
6 "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15",
7};
8#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
index 000000000000..3a2deaf3dab4
--- /dev/null
+++ b/tools/perf/arch/sh/include/dwarf-regs-table.h
@@ -0,0 +1,25 @@
1#ifdef DEFINE_DWARF_REGSTR_TABLE
2/* This is included in perf/util/dwarf-regs.c */
3
4const char * const sh_regstr_tbl[] = {
5 "r0",
6 "r1",
7 "r2",
8 "r3",
9 "r4",
10 "r5",
11 "r6",
12 "r7",
13 "r8",
14 "r9",
15 "r10",
16 "r11",
17 "r12",
18 "r13",
19 "r14",
20 "r15",
21 "pc",
22 "pr",
23};
24
25#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
index 000000000000..12c07619002c
--- /dev/null
+++ b/tools/perf/arch/sparc/include/dwarf-regs-table.h
@@ -0,0 +1,18 @@
1#ifdef DEFINE_DWARF_REGSTR_TABLE
2/* This is included in perf/util/dwarf-regs.c */
3
4static const char * const sparc_regstr_tbl[] = {
5 "%g0", "%g1", "%g2", "%g3", "%g4", "%g5", "%g6", "%g7",
6 "%o0", "%o1", "%o2", "%o3", "%o4", "%o5", "%sp", "%o7",
7 "%l0", "%l1", "%l2", "%l3", "%l4", "%l5", "%l6", "%l7",
8 "%i0", "%i1", "%i2", "%i3", "%i4", "%i5", "%fp", "%i7",
9 "%f0", "%f1", "%f2", "%f3", "%f4", "%f5", "%f6", "%f7",
10 "%f8", "%f9", "%f10", "%f11", "%f12", "%f13", "%f14", "%f15",
11 "%f16", "%f17", "%f18", "%f19", "%f20", "%f21", "%f22", "%f23",
12 "%f24", "%f25", "%f26", "%f27", "%f28", "%f29", "%f30", "%f31",
13 "%f32", "%f33", "%f34", "%f35", "%f36", "%f37", "%f38", "%f39",
14 "%f40", "%f41", "%f42", "%f43", "%f44", "%f45", "%f46", "%f47",
15 "%f48", "%f49", "%f50", "%f51", "%f52", "%f53", "%f54", "%f55",
16 "%f56", "%f57", "%f58", "%f59", "%f60", "%f61", "%f62", "%f63",
17};
18#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
index 000000000000..39ac7cbb525b
--- /dev/null
+++ b/tools/perf/arch/x86/include/dwarf-regs-table.h
@@ -0,0 +1,14 @@
1#ifdef DEFINE_DWARF_REGSTR_TABLE
2/* This is included in perf/util/dwarf-regs.c */
3
4static const char * const x86_32_regstr_tbl[] = {
5 "%ax", "%cx", "%dx", "%bx", "$stack",/* Stack address instead of %sp */
6 "%bp", "%si", "%di",
7};
8
9static const char * const x86_64_regstr_tbl[] = {
10 "%ax", "dx", "%cx", "%bx", "%si", "%di",
11 "%bp", "%sp", "%r8", "%r9", "%r10", "%r11",
12 "%r12", "%r13", "%r14", "%r15",
13};
14#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
index 000000000000..aa0444a33fe6
--- /dev/null
+++ b/tools/perf/arch/xtensa/include/dwarf-regs-table.h
@@ -0,0 +1,8 @@
1#ifdef DEFINE_DWARF_REGSTR_TABLE
2/* This is included in perf/util/dwarf-regs.c */
3
4static const char * const xtensa_regstr_tbl[] = {
5 "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7",
6 "a8", "a9", "a10", "a11", "a12", "a13", "a14", "a15",
7};
8#endif
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 9c1034d81b4f..f07b23011b22 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -204,8 +204,6 @@ static int __cmd_annotate(struct perf_annotate *ann)
204 struct perf_evsel *pos; 204 struct perf_evsel *pos;
205 u64 total_nr_samples; 205 u64 total_nr_samples;
206 206
207 machines__set_symbol_filter(&session->machines, symbol__annotate_init);
208
209 if (ann->cpu_list) { 207 if (ann->cpu_list) {
210 ret = perf_session__cpu_bitmap(session, ann->cpu_list, 208 ret = perf_session__cpu_bitmap(session, ann->cpu_list,
211 ann->cpu_bitmap); 209 ann->cpu_bitmap);
@@ -367,7 +365,10 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
367 if (annotate.session == NULL) 365 if (annotate.session == NULL)
368 return -1; 366 return -1;
369 367
370 symbol_conf.priv_size = sizeof(struct annotation); 368 ret = symbol__annotation_init();
369 if (ret < 0)
370 goto out_delete;
371
371 symbol_conf.try_vmlinux_path = true; 372 symbol_conf.try_vmlinux_path = true;
372 373
373 ret = symbol__init(&annotate.session->header.env); 374 ret = symbol__init(&annotate.session->header.env);
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index ee5b42173ba3..f87996b0cb29 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -326,6 +326,11 @@ static int perf_add_probe_events(struct perf_probe_event *pevs, int npevs)
326 if (ret < 0) 326 if (ret < 0)
327 goto out_cleanup; 327 goto out_cleanup;
328 328
329 if (params.command == 'D') { /* it shows definition */
330 ret = show_probe_trace_events(pevs, npevs);
331 goto out_cleanup;
332 }
333
329 ret = apply_perf_probe_events(pevs, npevs); 334 ret = apply_perf_probe_events(pevs, npevs);
330 if (ret < 0) 335 if (ret < 0)
331 goto out_cleanup; 336 goto out_cleanup;
@@ -454,6 +459,14 @@ out:
454 return ret; 459 return ret;
455} 460}
456 461
462#ifdef HAVE_DWARF_SUPPORT
463#define PROBEDEF_STR \
464 "[EVENT=]FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT [[NAME=]ARG ...]"
465#else
466#define PROBEDEF_STR "[EVENT=]FUNC[+OFF|%return] [[NAME=]ARG ...]"
467#endif
468
469
457static int 470static int
458__cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) 471__cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
459{ 472{
@@ -479,13 +492,7 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
479 opt_set_filter_with_command, DEFAULT_LIST_FILTER), 492 opt_set_filter_with_command, DEFAULT_LIST_FILTER),
480 OPT_CALLBACK('d', "del", NULL, "[GROUP:]EVENT", "delete a probe event.", 493 OPT_CALLBACK('d', "del", NULL, "[GROUP:]EVENT", "delete a probe event.",
481 opt_set_filter_with_command), 494 opt_set_filter_with_command),
482 OPT_CALLBACK('a', "add", NULL, 495 OPT_CALLBACK('a', "add", NULL, PROBEDEF_STR,
483#ifdef HAVE_DWARF_SUPPORT
484 "[EVENT=]FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT"
485 " [[NAME=]ARG ...]",
486#else
487 "[EVENT=]FUNC[+OFF|%return] [[NAME=]ARG ...]",
488#endif
489 "probe point definition, where\n" 496 "probe point definition, where\n"
490 "\t\tGROUP:\tGroup name (optional)\n" 497 "\t\tGROUP:\tGroup name (optional)\n"
491 "\t\tEVENT:\tEvent name\n" 498 "\t\tEVENT:\tEvent name\n"
@@ -503,6 +510,9 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
503 "\t\tARG:\tProbe argument (kprobe-tracer argument format.)\n", 510 "\t\tARG:\tProbe argument (kprobe-tracer argument format.)\n",
504#endif 511#endif
505 opt_add_probe_event), 512 opt_add_probe_event),
513 OPT_CALLBACK('D', "definition", NULL, PROBEDEF_STR,
514 "Show trace event definition of given traceevent for k/uprobe_events.",
515 opt_add_probe_event),
506 OPT_BOOLEAN('f', "force", &probe_conf.force_add, "forcibly add events" 516 OPT_BOOLEAN('f', "force", &probe_conf.force_add, "forcibly add events"
507 " with existing name"), 517 " with existing name"),
508 OPT_CALLBACK('L', "line", NULL, 518 OPT_CALLBACK('L', "line", NULL,
@@ -548,6 +558,7 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
548 558
549 set_option_flag(options, 'a', "add", PARSE_OPT_EXCLUSIVE); 559 set_option_flag(options, 'a', "add", PARSE_OPT_EXCLUSIVE);
550 set_option_flag(options, 'd', "del", PARSE_OPT_EXCLUSIVE); 560 set_option_flag(options, 'd', "del", PARSE_OPT_EXCLUSIVE);
561 set_option_flag(options, 'D', "definition", PARSE_OPT_EXCLUSIVE);
551 set_option_flag(options, 'l', "list", PARSE_OPT_EXCLUSIVE); 562 set_option_flag(options, 'l', "list", PARSE_OPT_EXCLUSIVE);
552#ifdef HAVE_DWARF_SUPPORT 563#ifdef HAVE_DWARF_SUPPORT
553 set_option_flag(options, 'L', "line", PARSE_OPT_EXCLUSIVE); 564 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)
600 */ 611 */
601 symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); 612 symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
602 613
614 /*
615 * Except for --list, --del and --add, other command doesn't depend
616 * nor change running kernel. So if user gives offline vmlinux,
617 * ignore its buildid.
618 */
619 if (!strchr("lda", params.command) && symbol_conf.vmlinux_name)
620 symbol_conf.ignore_vmlinux_buildid = true;
621
603 switch (params.command) { 622 switch (params.command) {
604 case 'l': 623 case 'l':
605 if (params.uprobes) { 624 if (params.uprobes) {
@@ -643,7 +662,9 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
643 return ret; 662 return ret;
644 } 663 }
645 break; 664 break;
665 case 'D':
646 case 'a': 666 case 'a':
667
647 /* Ensure the last given target is used */ 668 /* Ensure the last given target is used */
648 if (params.target && !params.target_used) { 669 if (params.target && !params.target_used) {
649 pr_err(" Error: -x/-m must follow the probe definitions.\n"); 670 pr_err(" Error: -x/-m must follow the probe definitions.\n");
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index b9e046baa5fc..1a07c4cdf6ed 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -984,9 +984,9 @@ repeat:
984 * implementation. 984 * implementation.
985 */ 985 */
986 if (ui__has_annotation()) { 986 if (ui__has_annotation()) {
987 symbol_conf.priv_size = sizeof(struct annotation); 987 ret = symbol__annotation_init();
988 machines__set_symbol_filter(&session->machines, 988 if (ret < 0)
989 symbol__annotate_init); 989 goto error;
990 /* 990 /*
991 * For searching by name on the "Browse map details". 991 * For searching by name on the "Browse map details".
992 * providing it only in verbose mode not to bloat too 992 * providing it only in verbose mode not to bloat too
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index a3223aa22213..e0919006fcba 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -680,7 +680,7 @@ static int symbol_filter(struct map *map, struct symbol *sym)
680 return 1; 680 return 1;
681 681
682 if (symbol__is_idle(sym)) 682 if (symbol__is_idle(sym))
683 sym->ignore = true; 683 sym->idle = 1;
684 684
685 return 0; 685 return 0;
686} 686}
@@ -783,7 +783,7 @@ static void perf_event__process_sample(struct perf_tool *tool,
783 } 783 }
784 } 784 }
785 785
786 if (al.sym == NULL || !al.sym->ignore) { 786 if (al.sym == NULL || !al.sym->idle) {
787 struct hists *hists = evsel__hists(evsel); 787 struct hists *hists = evsel__hists(evsel);
788 struct hist_entry_iter iter = { 788 struct hist_entry_iter iter = {
789 .evsel = evsel, 789 .evsel = evsel,
@@ -1324,7 +1324,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
1324 if (symbol_conf.cumulate_callchain && !callchain_param.order_set) 1324 if (symbol_conf.cumulate_callchain && !callchain_param.order_set)
1325 callchain_param.order = ORDER_CALLER; 1325 callchain_param.order = ORDER_CALLER;
1326 1326
1327 symbol_conf.priv_size = sizeof(struct annotation); 1327 status = symbol__annotation_init();
1328 if (status < 0)
1329 goto out_delete_evlist;
1328 1330
1329 symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); 1331 symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
1330 if (symbol__init(NULL) < 0) 1332 if (symbol__init(NULL) < 0)
diff --git a/tools/perf/tests/vmlinux-kallsyms.c b/tools/perf/tests/vmlinux-kallsyms.c
index e63abab7d5a1..77513bf99d1b 100644
--- a/tools/perf/tests/vmlinux-kallsyms.c
+++ b/tools/perf/tests/vmlinux-kallsyms.c
@@ -28,6 +28,7 @@ int test__vmlinux_matches_kallsyms(int subtest __maybe_unused)
28 enum map_type type = MAP__FUNCTION; 28 enum map_type type = MAP__FUNCTION;
29 struct maps *maps = &vmlinux.kmaps.maps[type]; 29 struct maps *maps = &vmlinux.kmaps.maps[type];
30 u64 mem_start, mem_end; 30 u64 mem_start, mem_end;
31 bool header_printed;
31 32
32 /* 33 /*
33 * Step 1: 34 * Step 1:
@@ -143,7 +144,7 @@ next_pair:
143 */ 144 */
144 s64 skew = mem_end - UM(pair->end); 145 s64 skew = mem_end - UM(pair->end);
145 if (llabs(skew) >= page_size) 146 if (llabs(skew) >= page_size)
146 pr_debug("%#" PRIx64 ": diff end addr for %s v: %#" PRIx64 " k: %#" PRIx64 "\n", 147 pr_debug("WARN: %#" PRIx64 ": diff end addr for %s v: %#" PRIx64 " k: %#" PRIx64 "\n",
147 mem_start, sym->name, mem_end, 148 mem_start, sym->name, mem_end,
148 UM(pair->end)); 149 UM(pair->end));
149 150
@@ -154,22 +155,23 @@ next_pair:
154 * kallsyms. 155 * kallsyms.
155 */ 156 */
156 continue; 157 continue;
157
158 } else { 158 } else {
159 pair = machine__find_kernel_symbol_by_name(&kallsyms, type, sym->name, NULL, NULL); 159 pair = machine__find_kernel_symbol_by_name(&kallsyms, type, sym->name, NULL, NULL);
160 if (pair) { 160 if (pair) {
161 if (UM(pair->start) == mem_start) 161 if (UM(pair->start) == mem_start)
162 goto next_pair; 162 goto next_pair;
163 163
164 pr_debug("%#" PRIx64 ": diff name v: %s k: %s\n", 164 pr_debug("WARN: %#" PRIx64 ": diff name v: %s k: %s\n",
165 mem_start, sym->name, pair->name); 165 mem_start, sym->name, pair->name);
166 } else { 166 } else {
167 pr_debug("%#" PRIx64 ": diff name v: %s k: %s\n", 167 pr_debug("WARN: %#" PRIx64 ": diff name v: %s k: %s\n",
168 mem_start, sym->name, first_pair->name); 168 mem_start, sym->name, first_pair->name);
169 } 169 }
170
171 continue;
170 } 172 }
171 } else 173 } else
172 pr_debug("%#" PRIx64 ": %s not on kallsyms\n", 174 pr_debug("ERR : %#" PRIx64 ": %s not on kallsyms\n",
173 mem_start, sym->name); 175 mem_start, sym->name);
174 176
175 err = -1; 177 err = -1;
@@ -178,7 +180,7 @@ next_pair:
178 if (!verbose) 180 if (!verbose)
179 goto out; 181 goto out;
180 182
181 pr_info("Maps only in vmlinux:\n"); 183 header_printed = false;
182 184
183 for (map = maps__first(maps); map; map = map__next(map)) { 185 for (map = maps__first(maps); map; map = map__next(map)) {
184 struct map * 186 struct map *
@@ -192,13 +194,18 @@ next_pair:
192 (map->dso->kernel ? 194 (map->dso->kernel ?
193 map->dso->short_name : 195 map->dso->short_name :
194 map->dso->name)); 196 map->dso->name));
195 if (pair) 197 if (pair) {
196 pair->priv = 1; 198 pair->priv = 1;
197 else 199 } else {
200 if (!header_printed) {
201 pr_info("WARN: Maps only in vmlinux:\n");
202 header_printed = true;
203 }
198 map__fprintf(map, stderr); 204 map__fprintf(map, stderr);
205 }
199 } 206 }
200 207
201 pr_info("Maps in vmlinux with a different name in kallsyms:\n"); 208 header_printed = false;
202 209
203 for (map = maps__first(maps); map; map = map__next(map)) { 210 for (map = maps__first(maps); map; map = map__next(map)) {
204 struct map *pair; 211 struct map *pair;
@@ -211,24 +218,33 @@ next_pair:
211 continue; 218 continue;
212 219
213 if (pair->start == mem_start) { 220 if (pair->start == mem_start) {
214 pair->priv = 1; 221 if (!header_printed) {
215 pr_info(" %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s in kallsyms as", 222 pr_info("WARN: Maps in vmlinux with a different name in kallsyms:\n");
223 header_printed = true;
224 }
225
226 pr_info("WARN: %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s in kallsyms as",
216 map->start, map->end, map->pgoff, map->dso->name); 227 map->start, map->end, map->pgoff, map->dso->name);
217 if (mem_end != pair->end) 228 if (mem_end != pair->end)
218 pr_info(":\n*%" PRIx64 "-%" PRIx64 " %" PRIx64, 229 pr_info(":\nWARN: *%" PRIx64 "-%" PRIx64 " %" PRIx64,
219 pair->start, pair->end, pair->pgoff); 230 pair->start, pair->end, pair->pgoff);
220 pr_info(" %s\n", pair->dso->name); 231 pr_info(" %s\n", pair->dso->name);
221 pair->priv = 1; 232 pair->priv = 1;
222 } 233 }
223 } 234 }
224 235
225 pr_info("Maps only in kallsyms:\n"); 236 header_printed = false;
226 237
227 maps = &kallsyms.kmaps.maps[type]; 238 maps = &kallsyms.kmaps.maps[type];
228 239
229 for (map = maps__first(maps); map; map = map__next(map)) { 240 for (map = maps__first(maps); map; map = map__next(map)) {
230 if (!map->priv) 241 if (!map->priv) {
242 if (!header_printed) {
243 pr_info("WARN: Maps only in kallsyms:\n");
244 header_printed = true;
245 }
231 map__fprintf(map, stderr); 246 map__fprintf(map, stderr);
247 }
232 } 248 }
233out: 249out:
234 machine__exit(&kallsyms); 250 machine__exit(&kallsyms);
diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index 91c5f6e1af59..f1a6d17c5a37 100644
--- a/tools/perf/util/Build
+++ b/tools/perf/util/Build
@@ -98,6 +98,7 @@ endif
98 98
99libperf-$(CONFIG_DWARF) += probe-finder.o 99libperf-$(CONFIG_DWARF) += probe-finder.o
100libperf-$(CONFIG_DWARF) += dwarf-aux.o 100libperf-$(CONFIG_DWARF) += dwarf-aux.o
101libperf-$(CONFIG_DWARF) += dwarf-regs.o
101 102
102libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o 103libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
103libperf-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind-local.o 104libperf-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind-local.o
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index 25a9259a6a6e..1b59e3129216 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -491,13 +491,6 @@ static struct ins *ins__find(const char *name)
491 return bsearch(name, instructions, nmemb, sizeof(struct ins), ins__key_cmp); 491 return bsearch(name, instructions, nmemb, sizeof(struct ins), ins__key_cmp);
492} 492}
493 493
494int symbol__annotate_init(struct map *map __maybe_unused, struct symbol *sym)
495{
496 struct annotation *notes = symbol__annotation(sym);
497 pthread_mutex_init(&notes->lock, NULL);
498 return 0;
499}
500
501int symbol__alloc_hist(struct symbol *sym) 494int symbol__alloc_hist(struct symbol *sym)
502{ 495{
503 struct annotation *notes = symbol__annotation(sym); 496 struct annotation *notes = symbol__annotation(sym);
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h
index f67ccb027561..e96f4daed9b9 100644
--- a/tools/perf/util/annotate.h
+++ b/tools/perf/util/annotate.h
@@ -177,7 +177,6 @@ enum symbol_disassemble_errno {
177int symbol__strerror_disassemble(struct symbol *sym, struct map *map, 177int symbol__strerror_disassemble(struct symbol *sym, struct map *map,
178 int errnum, char *buf, size_t buflen); 178 int errnum, char *buf, size_t buflen);
179 179
180int symbol__annotate_init(struct map *map, struct symbol *sym);
181int symbol__annotate_printf(struct symbol *sym, struct map *map, 180int symbol__annotate_printf(struct symbol *sym, struct map *map,
182 struct perf_evsel *evsel, bool full_paths, 181 struct perf_evsel *evsel, bool full_paths,
183 int min_pcnt, int max_lines, int context); 182 int min_pcnt, int max_lines, int context);
diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c
index a347b19c961a..faec899435f2 100644
--- a/tools/perf/util/dwarf-aux.c
+++ b/tools/perf/util/dwarf-aux.c
@@ -1085,3 +1085,182 @@ int die_get_var_range(Dwarf_Die *sp_die __maybe_unused,
1085 return -ENOTSUP; 1085 return -ENOTSUP;
1086} 1086}
1087#endif 1087#endif
1088
1089/*
1090 * die_has_loclist - Check if DW_AT_location of @vr_die is a location list
1091 * @vr_die: a variable DIE
1092 */
1093static bool die_has_loclist(Dwarf_Die *vr_die)
1094{
1095 Dwarf_Attribute loc;
1096 int tag = dwarf_tag(vr_die);
1097
1098 if (tag != DW_TAG_formal_parameter &&
1099 tag != DW_TAG_variable)
1100 return false;
1101
1102 return (dwarf_attr_integrate(vr_die, DW_AT_location, &loc) &&
1103 dwarf_whatform(&loc) == DW_FORM_sec_offset);
1104}
1105
1106/*
1107 * die_is_optimized_target - Check if target program is compiled with
1108 * optimization
1109 * @cu_die: a CU DIE
1110 *
1111 * For any object in given CU whose DW_AT_location is a location list,
1112 * target program is compiled with optimization. This is applicable to
1113 * clang as well.
1114 */
1115bool die_is_optimized_target(Dwarf_Die *cu_die)
1116{
1117 Dwarf_Die tmp_die;
1118
1119 if (die_has_loclist(cu_die))
1120 return true;
1121
1122 if (!dwarf_child(cu_die, &tmp_die) &&
1123 die_is_optimized_target(&tmp_die))
1124 return true;
1125
1126 if (!dwarf_siblingof(cu_die, &tmp_die) &&
1127 die_is_optimized_target(&tmp_die))
1128 return true;
1129
1130 return false;
1131}
1132
1133/*
1134 * die_search_idx - Search index of given line address
1135 * @lines: Line records of single CU
1136 * @nr_lines: Number of @lines
1137 * @addr: address we are looking for
1138 * @idx: index to be set by this function (return value)
1139 *
1140 * Search for @addr by looping over every lines of CU. If address
1141 * matches, set index of that line in @idx. Note that single source
1142 * line can have multiple line records. i.e. single source line can
1143 * have multiple index.
1144 */
1145static bool die_search_idx(Dwarf_Lines *lines, unsigned long nr_lines,
1146 Dwarf_Addr addr, unsigned long *idx)
1147{
1148 unsigned long i;
1149 Dwarf_Addr tmp;
1150
1151 for (i = 0; i < nr_lines; i++) {
1152 if (dwarf_lineaddr(dwarf_onesrcline(lines, i), &tmp))
1153 return false;
1154
1155 if (tmp == addr) {
1156 *idx = i;
1157 return true;
1158 }
1159 }
1160 return false;
1161}
1162
1163/*
1164 * die_get_postprologue_addr - Search next address after function prologue
1165 * @entrypc_idx: entrypc index
1166 * @lines: Line records of single CU
1167 * @nr_lines: Number of @lines
1168 * @hignpc: high PC address of function
1169 * @postprologue_addr: Next address after function prologue (return value)
1170 *
1171 * Look for prologue-end marker. If there is no explicit marker, return
1172 * address of next line record or next source line.
1173 */
1174static bool die_get_postprologue_addr(unsigned long entrypc_idx,
1175 Dwarf_Lines *lines,
1176 unsigned long nr_lines,
1177 Dwarf_Addr highpc,
1178 Dwarf_Addr *postprologue_addr)
1179{
1180 unsigned long i;
1181 int entrypc_lno, lno;
1182 Dwarf_Line *line;
1183 Dwarf_Addr addr;
1184 bool p_end;
1185
1186 /* entrypc_lno is actual source line number */
1187 line = dwarf_onesrcline(lines, entrypc_idx);
1188 if (dwarf_lineno(line, &entrypc_lno))
1189 return false;
1190
1191 for (i = entrypc_idx; i < nr_lines; i++) {
1192 line = dwarf_onesrcline(lines, i);
1193
1194 if (dwarf_lineaddr(line, &addr) ||
1195 dwarf_lineno(line, &lno) ||
1196 dwarf_lineprologueend(line, &p_end))
1197 return false;
1198
1199 /* highpc is exclusive. [entrypc,highpc) */
1200 if (addr >= highpc)
1201 break;
1202
1203 /* clang supports prologue-end marker */
1204 if (p_end)
1205 break;
1206
1207 /* Actual next line in source */
1208 if (lno != entrypc_lno)
1209 break;
1210
1211 /*
1212 * Single source line can have multiple line records.
1213 * For Example,
1214 * void foo() { printf("hello\n"); }
1215 * contains two line records. One points to declaration and
1216 * other points to printf() line. Variable 'lno' won't get
1217 * incremented in this case but 'i' will.
1218 */
1219 if (i != entrypc_idx)
1220 break;
1221 }
1222
1223 dwarf_lineaddr(line, postprologue_addr);
1224 if (*postprologue_addr >= highpc)
1225 dwarf_lineaddr(dwarf_onesrcline(lines, i - 1),
1226 postprologue_addr);
1227
1228 return true;
1229}
1230
1231/*
1232 * die_skip_prologue - Use next address after prologue as probe location
1233 * @sp_die: a subprogram DIE
1234 * @cu_die: a CU DIE
1235 * @entrypc: entrypc of the function
1236 *
1237 * Function prologue prepares stack and registers before executing function
1238 * logic. When target program is compiled without optimization, function
1239 * parameter information is only valid after prologue. When we probe entrypc
1240 * of the function, and try to record function parameter, it contains
1241 * garbage value.
1242 */
1243void die_skip_prologue(Dwarf_Die *sp_die, Dwarf_Die *cu_die,
1244 Dwarf_Addr *entrypc)
1245{
1246 size_t nr_lines = 0;
1247 unsigned long entrypc_idx = 0;
1248 Dwarf_Lines *lines = NULL;
1249 Dwarf_Addr postprologue_addr;
1250 Dwarf_Addr highpc;
1251
1252 if (dwarf_highpc(sp_die, &highpc))
1253 return;
1254
1255 if (dwarf_getsrclines(cu_die, &lines, &nr_lines))
1256 return;
1257
1258 if (!die_search_idx(lines, nr_lines, *entrypc, &entrypc_idx))
1259 return;
1260
1261 if (!die_get_postprologue_addr(entrypc_idx, lines, nr_lines,
1262 highpc, &postprologue_addr))
1263 return;
1264
1265 *entrypc = postprologue_addr;
1266}
diff --git a/tools/perf/util/dwarf-aux.h b/tools/perf/util/dwarf-aux.h
index dc0ce1adb075..8b6d2f83af02 100644
--- a/tools/perf/util/dwarf-aux.h
+++ b/tools/perf/util/dwarf-aux.h
@@ -125,4 +125,12 @@ int die_get_typename(Dwarf_Die *vr_die, struct strbuf *buf);
125/* Get the name and type of given variable DIE, stored as "type\tname" */ 125/* Get the name and type of given variable DIE, stored as "type\tname" */
126int die_get_varname(Dwarf_Die *vr_die, struct strbuf *buf); 126int die_get_varname(Dwarf_Die *vr_die, struct strbuf *buf);
127int die_get_var_range(Dwarf_Die *sp_die, Dwarf_Die *vr_die, struct strbuf *buf); 127int die_get_var_range(Dwarf_Die *sp_die, Dwarf_Die *vr_die, struct strbuf *buf);
128
129/* Check if target program is compiled with optimization */
130bool die_is_optimized_target(Dwarf_Die *cu_die);
131
132/* Use next address after prologue as probe location */
133void die_skip_prologue(Dwarf_Die *sp_die, Dwarf_Die *cu_die,
134 Dwarf_Addr *entrypc);
135
128#endif 136#endif
diff --git a/tools/perf/util/dwarf-regs.c b/tools/perf/util/dwarf-regs.c
new file mode 100644
index 000000000000..62bc4a86a970
--- /dev/null
+++ b/tools/perf/util/dwarf-regs.c
@@ -0,0 +1,59 @@
1/*
2 * dwarf-regs.c : Mapping of DWARF debug register numbers into register names.
3 *
4 * Written by: Masami Hiramatsu <mhiramat@kernel.org>
5 */
6
7#include <util.h>
8#include <debug.h>
9#include <dwarf-regs.h>
10#include <elf.h>
11
12#ifndef EM_AARCH64
13#define EM_AARCH64 183 /* ARM 64 bit */
14#endif
15
16/* Define const char * {arch}_register_tbl[] */
17#define DEFINE_DWARF_REGSTR_TABLE
18#include "../arch/x86/include/dwarf-regs-table.h"
19#include "../arch/arm/include/dwarf-regs-table.h"
20#include "../arch/arm64/include/dwarf-regs-table.h"
21#include "../arch/sh/include/dwarf-regs-table.h"
22#include "../arch/powerpc/include/dwarf-regs-table.h"
23#include "../arch/s390/include/dwarf-regs-table.h"
24#include "../arch/sparc/include/dwarf-regs-table.h"
25#include "../arch/xtensa/include/dwarf-regs-table.h"
26
27#define __get_dwarf_regstr(tbl, n) (((n) < ARRAY_SIZE(tbl)) ? (tbl)[(n)] : NULL)
28
29/* Return architecture dependent register string (for kprobe-tracer) */
30const char *get_dwarf_regstr(unsigned int n, unsigned int machine)
31{
32 switch (machine) {
33 case EM_NONE: /* Generic arch - use host arch */
34 return get_arch_regstr(n);
35 case EM_386:
36 return __get_dwarf_regstr(x86_32_regstr_tbl, n);
37 case EM_X86_64:
38 return __get_dwarf_regstr(x86_64_regstr_tbl, n);
39 case EM_ARM:
40 return __get_dwarf_regstr(arm_regstr_tbl, n);
41 case EM_AARCH64:
42 return __get_dwarf_regstr(aarch64_regstr_tbl, n);
43 case EM_SH:
44 return __get_dwarf_regstr(sh_regstr_tbl, n);
45 case EM_S390:
46 return __get_dwarf_regstr(s390_regstr_tbl, n);
47 case EM_PPC:
48 case EM_PPC64:
49 return __get_dwarf_regstr(powerpc_regstr_tbl, n);
50 case EM_SPARC:
51 case EM_SPARCV9:
52 return __get_dwarf_regstr(sparc_regstr_tbl, n);
53 case EM_XTENSA:
54 return __get_dwarf_regstr(xtensa_regstr_tbl, n);
55 default:
56 pr_err("ELF MACHINE %x is not supported.\n", machine);
57 }
58 return NULL;
59}
diff --git a/tools/perf/util/evsel_fprintf.c b/tools/perf/util/evsel_fprintf.c
index 3674e77ad640..9111e0666950 100644
--- a/tools/perf/util/evsel_fprintf.c
+++ b/tools/perf/util/evsel_fprintf.c
@@ -122,7 +122,7 @@ int sample__fprintf_callchain(struct perf_sample *sample, int left_alignment,
122 if (!node) 122 if (!node)
123 break; 123 break;
124 124
125 if (node->sym && node->sym->ignore) 125 if (node->sym && node->sym->idle)
126 goto next; 126 goto next;
127 127
128 printed += fprintf(fp, "%-*.*s", left_alignment, left_alignment, " "); 128 printed += fprintf(fp, "%-*.*s", left_alignment, left_alignment, " ");
@@ -181,7 +181,7 @@ int sample__fprintf_sym(struct perf_sample *sample, struct addr_location *al,
181 if (cursor != NULL) { 181 if (cursor != NULL) {
182 printed += sample__fprintf_callchain(sample, left_alignment, 182 printed += sample__fprintf_callchain(sample, left_alignment,
183 print_opts, cursor, fp); 183 print_opts, cursor, fp);
184 } else if (!(al->sym && al->sym->ignore)) { 184 } else if (!(al->sym && al->sym->idle)) {
185 printed += fprintf(fp, "%-*.*s", left_alignment, left_alignment, " "); 185 printed += fprintf(fp, "%-*.*s", left_alignment, left_alignment, " ");
186 186
187 if (print_ip) 187 if (print_ip)
diff --git a/tools/perf/util/include/dwarf-regs.h b/tools/perf/util/include/dwarf-regs.h
index 07c644ed64c4..43bfd8da7919 100644
--- a/tools/perf/util/include/dwarf-regs.h
+++ b/tools/perf/util/include/dwarf-regs.h
@@ -3,6 +3,12 @@
3 3
4#ifdef HAVE_DWARF_SUPPORT 4#ifdef HAVE_DWARF_SUPPORT
5const char *get_arch_regstr(unsigned int n); 5const char *get_arch_regstr(unsigned int n);
6/*
7 * get_dwarf_regstr - Returns ftrace register string from DWARF regnum
8 * n: DWARF register number
9 * machine: ELF machine signature (EM_*)
10 */
11const char *get_dwarf_regstr(unsigned int n, unsigned int machine);
6#endif 12#endif
7 13
8#ifdef HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET 14#ifdef HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET
diff --git a/tools/perf/util/lzma.c b/tools/perf/util/lzma.c
index 95a1acb61245..9ddea5cecd94 100644
--- a/tools/perf/util/lzma.c
+++ b/tools/perf/util/lzma.c
@@ -29,6 +29,7 @@ int lzma_decompress_to_file(const char *input, int output_fd)
29 lzma_action action = LZMA_RUN; 29 lzma_action action = LZMA_RUN;
30 lzma_stream strm = LZMA_STREAM_INIT; 30 lzma_stream strm = LZMA_STREAM_INIT;
31 lzma_ret ret; 31 lzma_ret ret;
32 int err = -1;
32 33
33 u8 buf_in[BUFSIZE]; 34 u8 buf_in[BUFSIZE];
34 u8 buf_out[BUFSIZE]; 35 u8 buf_out[BUFSIZE];
@@ -45,7 +46,7 @@ int lzma_decompress_to_file(const char *input, int output_fd)
45 if (ret != LZMA_OK) { 46 if (ret != LZMA_OK) {
46 pr_err("lzma: lzma_stream_decoder failed %s (%d)\n", 47 pr_err("lzma: lzma_stream_decoder failed %s (%d)\n",
47 lzma_strerror(ret), ret); 48 lzma_strerror(ret), ret);
48 return -1; 49 goto err_fclose;
49 } 50 }
50 51
51 strm.next_in = NULL; 52 strm.next_in = NULL;
@@ -60,7 +61,7 @@ int lzma_decompress_to_file(const char *input, int output_fd)
60 61
61 if (ferror(infile)) { 62 if (ferror(infile)) {
62 pr_err("lzma: read error: %s\n", strerror(errno)); 63 pr_err("lzma: read error: %s\n", strerror(errno));
63 return -1; 64 goto err_fclose;
64 } 65 }
65 66
66 if (feof(infile)) 67 if (feof(infile))
@@ -74,7 +75,7 @@ int lzma_decompress_to_file(const char *input, int output_fd)
74 75
75 if (writen(output_fd, buf_out, write_size) != write_size) { 76 if (writen(output_fd, buf_out, write_size) != write_size) {
76 pr_err("lzma: write error: %s\n", strerror(errno)); 77 pr_err("lzma: write error: %s\n", strerror(errno));
77 return -1; 78 goto err_fclose;
78 } 79 }
79 80
80 strm.next_out = buf_out; 81 strm.next_out = buf_out;
@@ -83,13 +84,15 @@ int lzma_decompress_to_file(const char *input, int output_fd)
83 84
84 if (ret != LZMA_OK) { 85 if (ret != LZMA_OK) {
85 if (ret == LZMA_STREAM_END) 86 if (ret == LZMA_STREAM_END)
86 return 0; 87 break;
87 88
88 pr_err("lzma: failed %s\n", lzma_strerror(ret)); 89 pr_err("lzma: failed %s\n", lzma_strerror(ret));
89 return -1; 90 goto err_fclose;
90 } 91 }
91 } 92 }
92 93
94 err = 0;
95err_fclose:
93 fclose(infile); 96 fclose(infile);
94 return 0; 97 return err;
95} 98}
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 28733962cd80..a543e9ca581c 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -674,6 +674,10 @@ post_process_kernel_probe_trace_events(struct probe_trace_event *tevs,
674 char *tmp; 674 char *tmp;
675 int i, skipped = 0; 675 int i, skipped = 0;
676 676
677 /* Skip post process if the target is an offline kernel */
678 if (symbol_conf.ignore_vmlinux_buildid)
679 return 0;
680
677 reloc_sym = kernel_get_ref_reloc_sym(); 681 reloc_sym = kernel_get_ref_reloc_sym();
678 if (!reloc_sym) { 682 if (!reloc_sym) {
679 pr_warning("Relocated base symbol is not found!\n"); 683 pr_warning("Relocated base symbol is not found!\n");
@@ -1614,19 +1618,27 @@ out:
1614 return ret; 1618 return ret;
1615} 1619}
1616 1620
1621/* Returns true if *any* ARG is either C variable, $params or $vars. */
1622bool perf_probe_with_var(struct perf_probe_event *pev)
1623{
1624 int i = 0;
1625
1626 for (i = 0; i < pev->nargs; i++)
1627 if (is_c_varname(pev->args[i].var) ||
1628 !strcmp(pev->args[i].var, PROBE_ARG_PARAMS) ||
1629 !strcmp(pev->args[i].var, PROBE_ARG_VARS))
1630 return true;
1631 return false;
1632}
1633
1617/* Return true if this perf_probe_event requires debuginfo */ 1634/* Return true if this perf_probe_event requires debuginfo */
1618bool perf_probe_event_need_dwarf(struct perf_probe_event *pev) 1635bool perf_probe_event_need_dwarf(struct perf_probe_event *pev)
1619{ 1636{
1620 int i;
1621
1622 if (pev->point.file || pev->point.line || pev->point.lazy_line) 1637 if (pev->point.file || pev->point.line || pev->point.lazy_line)
1623 return true; 1638 return true;
1624 1639
1625 for (i = 0; i < pev->nargs; i++) 1640 if (perf_probe_with_var(pev))
1626 if (is_c_varname(pev->args[i].var) || 1641 return true;
1627 !strcmp(pev->args[i].var, "$params") ||
1628 !strcmp(pev->args[i].var, "$vars"))
1629 return true;
1630 1642
1631 return false; 1643 return false;
1632} 1644}
@@ -3207,6 +3219,52 @@ int convert_perf_probe_events(struct perf_probe_event *pevs, int npevs)
3207 return 0; 3219 return 0;
3208} 3220}
3209 3221
3222static int show_probe_trace_event(struct probe_trace_event *tev)
3223{
3224 char *buf = synthesize_probe_trace_command(tev);
3225
3226 if (!buf) {
3227 pr_debug("Failed to synthesize probe trace event.\n");
3228 return -EINVAL;
3229 }
3230
3231 /* Showing definition always go stdout */
3232 printf("%s\n", buf);
3233 free(buf);
3234
3235 return 0;
3236}
3237
3238int show_probe_trace_events(struct perf_probe_event *pevs, int npevs)
3239{
3240 struct strlist *namelist = strlist__new(NULL, NULL);
3241 struct probe_trace_event *tev;
3242 struct perf_probe_event *pev;
3243 int i, j, ret = 0;
3244
3245 if (!namelist)
3246 return -ENOMEM;
3247
3248 for (j = 0; j < npevs && !ret; j++) {
3249 pev = &pevs[j];
3250 for (i = 0; i < pev->ntevs && !ret; i++) {
3251 tev = &pev->tevs[i];
3252 /* Skip if the symbol is out of .text or blacklisted */
3253 if (!tev->point.symbol && !pev->uprobes)
3254 continue;
3255
3256 /* Set new name for tev (and update namelist) */
3257 ret = probe_trace_event__set_name(tev, pev,
3258 namelist, true);
3259 if (!ret)
3260 ret = show_probe_trace_event(tev);
3261 }
3262 }
3263 strlist__delete(namelist);
3264
3265 return ret;
3266}
3267
3210int apply_perf_probe_events(struct perf_probe_event *pevs, int npevs) 3268int apply_perf_probe_events(struct perf_probe_event *pevs, int npevs)
3211{ 3269{
3212 int i, ret = 0; 3270 int i, ret = 0;
@@ -3289,24 +3347,10 @@ out:
3289 return ret; 3347 return ret;
3290} 3348}
3291 3349
3292/* TODO: don't use a global variable for filter ... */
3293static struct strfilter *available_func_filter;
3294
3295/*
3296 * If a symbol corresponds to a function with global binding and
3297 * matches filter return 0. For all others return 1.
3298 */
3299static int filter_available_functions(struct map *map __maybe_unused,
3300 struct symbol *sym)
3301{
3302 if (strfilter__compare(available_func_filter, sym->name))
3303 return 0;
3304 return 1;
3305}
3306
3307int show_available_funcs(const char *target, struct strfilter *_filter, 3350int show_available_funcs(const char *target, struct strfilter *_filter,
3308 bool user) 3351 bool user)
3309{ 3352{
3353 struct rb_node *nd;
3310 struct map *map; 3354 struct map *map;
3311 int ret; 3355 int ret;
3312 3356
@@ -3324,9 +3368,7 @@ int show_available_funcs(const char *target, struct strfilter *_filter,
3324 return -EINVAL; 3368 return -EINVAL;
3325 } 3369 }
3326 3370
3327 /* Load symbols with given filter */ 3371 ret = map__load(map, NULL);
3328 available_func_filter = _filter;
3329 ret = map__load(map, filter_available_functions);
3330 if (ret) { 3372 if (ret) {
3331 if (ret == -2) { 3373 if (ret == -2) {
3332 char *str = strfilter__string(_filter); 3374 char *str = strfilter__string(_filter);
@@ -3343,7 +3385,14 @@ int show_available_funcs(const char *target, struct strfilter *_filter,
3343 3385
3344 /* Show all (filtered) symbols */ 3386 /* Show all (filtered) symbols */
3345 setup_pager(); 3387 setup_pager();
3346 dso__fprintf_symbols_by_name(map->dso, map->type, stdout); 3388
3389 for (nd = rb_first(&map->dso->symbol_names[map->type]); nd; nd = rb_next(nd)) {
3390 struct symbol_name_rb_node *pos = rb_entry(nd, struct symbol_name_rb_node, rb_node);
3391
3392 if (strfilter__compare(_filter, pos->sym.name))
3393 printf("%s\n", pos->sym.name);
3394 }
3395
3347end: 3396end:
3348 if (user) { 3397 if (user) {
3349 map__put(map); 3398 map__put(map);
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index f4f45db77c1c..8091d15113f7 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -128,6 +128,8 @@ char *synthesize_perf_probe_point(struct perf_probe_point *pp);
128int perf_probe_event__copy(struct perf_probe_event *dst, 128int perf_probe_event__copy(struct perf_probe_event *dst,
129 struct perf_probe_event *src); 129 struct perf_probe_event *src);
130 130
131bool perf_probe_with_var(struct perf_probe_event *pev);
132
131/* Check the perf_probe_event needs debuginfo */ 133/* Check the perf_probe_event needs debuginfo */
132bool perf_probe_event_need_dwarf(struct perf_probe_event *pev); 134bool perf_probe_event_need_dwarf(struct perf_probe_event *pev);
133 135
@@ -147,6 +149,7 @@ int line_range__init(struct line_range *lr);
147int add_perf_probe_events(struct perf_probe_event *pevs, int npevs); 149int add_perf_probe_events(struct perf_probe_event *pevs, int npevs);
148int convert_perf_probe_events(struct perf_probe_event *pevs, int npevs); 150int convert_perf_probe_events(struct perf_probe_event *pevs, int npevs);
149int apply_perf_probe_events(struct perf_probe_event *pevs, int npevs); 151int apply_perf_probe_events(struct perf_probe_event *pevs, int npevs);
152int show_probe_trace_events(struct perf_probe_event *pevs, int npevs);
150void cleanup_perf_probe_events(struct perf_probe_event *pevs, int npevs); 153void cleanup_perf_probe_events(struct perf_probe_event *pevs, int npevs);
151int del_perf_probe_events(struct strfilter *filter); 154int del_perf_probe_events(struct strfilter *filter);
152 155
diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c
index 697ef66bff91..6f931e442f14 100644
--- a/tools/perf/util/probe-file.c
+++ b/tools/perf/util/probe-file.c
@@ -73,11 +73,10 @@ static void print_both_open_warning(int kerr, int uerr)
73static int open_probe_events(const char *trace_file, bool readwrite) 73static int open_probe_events(const char *trace_file, bool readwrite)
74{ 74{
75 char buf[PATH_MAX]; 75 char buf[PATH_MAX];
76 const char *tracing_dir = "";
77 int ret; 76 int ret;
78 77
79 ret = e_snprintf(buf, PATH_MAX, "%s/%s%s", 78 ret = e_snprintf(buf, PATH_MAX, "%s/%s",
80 tracing_path, tracing_dir, trace_file); 79 tracing_path, trace_file);
81 if (ret >= 0) { 80 if (ret >= 0) {
82 pr_debug("Opening %s write=%d\n", buf, readwrite); 81 pr_debug("Opening %s write=%d\n", buf, readwrite);
83 if (readwrite && !probe_event_dry_run) 82 if (readwrite && !probe_event_dry_run)
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index ac4740f8ee3a..8daca4fc1f8d 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -171,6 +171,7 @@ static struct probe_trace_arg_ref *alloc_trace_arg_ref(long offs)
171 */ 171 */
172static int convert_variable_location(Dwarf_Die *vr_die, Dwarf_Addr addr, 172static int convert_variable_location(Dwarf_Die *vr_die, Dwarf_Addr addr,
173 Dwarf_Op *fb_ops, Dwarf_Die *sp_die, 173 Dwarf_Op *fb_ops, Dwarf_Die *sp_die,
174 unsigned int machine,
174 struct probe_trace_arg *tvar) 175 struct probe_trace_arg *tvar)
175{ 176{
176 Dwarf_Attribute attr; 177 Dwarf_Attribute attr;
@@ -266,7 +267,7 @@ static_var:
266 if (!tvar) 267 if (!tvar)
267 return ret2; 268 return ret2;
268 269
269 regs = get_arch_regstr(regn); 270 regs = get_dwarf_regstr(regn, machine);
270 if (!regs) { 271 if (!regs) {
271 /* This should be a bug in DWARF or this tool */ 272 /* This should be a bug in DWARF or this tool */
272 pr_warning("Mapping for the register number %u " 273 pr_warning("Mapping for the register number %u "
@@ -543,7 +544,7 @@ static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
543 dwarf_diename(vr_die)); 544 dwarf_diename(vr_die));
544 545
545 ret = convert_variable_location(vr_die, pf->addr, pf->fb_ops, 546 ret = convert_variable_location(vr_die, pf->addr, pf->fb_ops,
546 &pf->sp_die, pf->tvar); 547 &pf->sp_die, pf->machine, pf->tvar);
547 if (ret == -ENOENT || ret == -EINVAL) { 548 if (ret == -ENOENT || ret == -EINVAL) {
548 pr_err("Failed to find the location of the '%s' variable at this address.\n" 549 pr_err("Failed to find the location of the '%s' variable at this address.\n"
549 " Perhaps it has been optimized out.\n" 550 " 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)
906 return die_walk_lines(sp_die, probe_point_lazy_walker, pf); 907 return die_walk_lines(sp_die, probe_point_lazy_walker, pf);
907} 908}
908 909
910static void skip_prologue(Dwarf_Die *sp_die, struct probe_finder *pf)
911{
912 struct perf_probe_point *pp = &pf->pev->point;
913
914 /* Not uprobe? */
915 if (!pf->pev->uprobes)
916 return;
917
918 /* Compiled with optimization? */
919 if (die_is_optimized_target(&pf->cu_die))
920 return;
921
922 /* Don't know entrypc? */
923 if (!pf->addr)
924 return;
925
926 /* Only FUNC and FUNC@SRC are eligible. */
927 if (!pp->function || pp->line || pp->retprobe || pp->lazy_line ||
928 pp->offset || pp->abs_address)
929 return;
930
931 /* Not interested in func parameter? */
932 if (!perf_probe_with_var(pf->pev))
933 return;
934
935 pr_info("Target program is compiled without optimization. Skipping prologue.\n"
936 "Probe on address 0x%" PRIx64 " to force probing at the function entry.\n\n",
937 pf->addr);
938
939 die_skip_prologue(sp_die, &pf->cu_die, &pf->addr);
940}
941
909static int probe_point_inline_cb(Dwarf_Die *in_die, void *data) 942static int probe_point_inline_cb(Dwarf_Die *in_die, void *data)
910{ 943{
911 struct probe_finder *pf = data; 944 struct probe_finder *pf = data;
@@ -968,6 +1001,7 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
968 if (pp->lazy_line) 1001 if (pp->lazy_line)
969 param->retval = find_probe_point_lazy(sp_die, pf); 1002 param->retval = find_probe_point_lazy(sp_die, pf);
970 else { 1003 else {
1004 skip_prologue(sp_die, pf);
971 pf->addr += pp->offset; 1005 pf->addr += pp->offset;
972 /* TODO: Check the address in this function */ 1006 /* TODO: Check the address in this function */
973 param->retval = call_probe_finder(sp_die, pf); 1007 param->retval = call_probe_finder(sp_die, pf);
@@ -1106,11 +1140,8 @@ static int debuginfo__find_probes(struct debuginfo *dbg,
1106 struct probe_finder *pf) 1140 struct probe_finder *pf)
1107{ 1141{
1108 int ret = 0; 1142 int ret = 0;
1109
1110#if _ELFUTILS_PREREQ(0, 142)
1111 Elf *elf; 1143 Elf *elf;
1112 GElf_Ehdr ehdr; 1144 GElf_Ehdr ehdr;
1113 GElf_Shdr shdr;
1114 1145
1115 if (pf->cfi_eh || pf->cfi_dbg) 1146 if (pf->cfi_eh || pf->cfi_dbg)
1116 return debuginfo__find_probe_location(dbg, pf); 1147 return debuginfo__find_probe_location(dbg, pf);
@@ -1123,11 +1154,18 @@ static int debuginfo__find_probes(struct debuginfo *dbg,
1123 if (gelf_getehdr(elf, &ehdr) == NULL) 1154 if (gelf_getehdr(elf, &ehdr) == NULL)
1124 return -EINVAL; 1155 return -EINVAL;
1125 1156
1126 if (elf_section_by_name(elf, &ehdr, &shdr, ".eh_frame", NULL) && 1157 pf->machine = ehdr.e_machine;
1127 shdr.sh_type == SHT_PROGBITS) 1158
1128 pf->cfi_eh = dwarf_getcfi_elf(elf); 1159#if _ELFUTILS_PREREQ(0, 142)
1160 do {
1161 GElf_Shdr shdr;
1162
1163 if (elf_section_by_name(elf, &ehdr, &shdr, ".eh_frame", NULL) &&
1164 shdr.sh_type == SHT_PROGBITS)
1165 pf->cfi_eh = dwarf_getcfi_elf(elf);
1129 1166
1130 pf->cfi_dbg = dwarf_getcfi(dbg->dbg); 1167 pf->cfi_dbg = dwarf_getcfi(dbg->dbg);
1168 } while (0);
1131#endif 1169#endif
1132 1170
1133 ret = debuginfo__find_probe_location(dbg, pf); 1171 ret = debuginfo__find_probe_location(dbg, pf);
@@ -1155,7 +1193,7 @@ static int copy_variables_cb(Dwarf_Die *die_mem, void *data)
1155 (tag == DW_TAG_variable && vf->vars)) { 1193 (tag == DW_TAG_variable && vf->vars)) {
1156 if (convert_variable_location(die_mem, vf->pf->addr, 1194 if (convert_variable_location(die_mem, vf->pf->addr,
1157 vf->pf->fb_ops, &pf->sp_die, 1195 vf->pf->fb_ops, &pf->sp_die,
1158 NULL) == 0) { 1196 pf->machine, NULL) == 0) {
1159 vf->args[vf->nargs].var = (char *)dwarf_diename(die_mem); 1197 vf->args[vf->nargs].var = (char *)dwarf_diename(die_mem);
1160 if (vf->args[vf->nargs].var == NULL) { 1198 if (vf->args[vf->nargs].var == NULL) {
1161 vf->ret = -ENOMEM; 1199 vf->ret = -ENOMEM;
@@ -1318,7 +1356,7 @@ static int collect_variables_cb(Dwarf_Die *die_mem, void *data)
1318 tag == DW_TAG_variable) { 1356 tag == DW_TAG_variable) {
1319 ret = convert_variable_location(die_mem, af->pf.addr, 1357 ret = convert_variable_location(die_mem, af->pf.addr,
1320 af->pf.fb_ops, &af->pf.sp_die, 1358 af->pf.fb_ops, &af->pf.sp_die,
1321 NULL); 1359 af->pf.machine, NULL);
1322 if (ret == 0 || ret == -ERANGE) { 1360 if (ret == 0 || ret == -ERANGE) {
1323 int ret2; 1361 int ret2;
1324 bool externs = !af->child; 1362 bool externs = !af->child;
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
index 51137fccb9c8..f1d8558f498e 100644
--- a/tools/perf/util/probe-finder.h
+++ b/tools/perf/util/probe-finder.h
@@ -80,6 +80,7 @@ struct probe_finder {
80 Dwarf_CFI *cfi_dbg; 80 Dwarf_CFI *cfi_dbg;
81#endif 81#endif
82 Dwarf_Op *fb_ops; /* Frame base attribute */ 82 Dwarf_Op *fb_ops; /* Frame base attribute */
83 unsigned int machine; /* Target machine arch */
83 struct perf_probe_arg *pvar; /* Current target variable */ 84 struct perf_probe_arg *pvar; /* Current target variable */
84 struct probe_trace_arg *tvar; /* Current result variable */ 85 struct probe_trace_arg *tvar; /* Current result variable */
85}; 86};
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index a811c13a74d6..295d3147a803 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -206,6 +206,37 @@ Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
206 return NULL; 206 return NULL;
207} 207}
208 208
209static bool want_demangle(bool is_kernel_sym)
210{
211 return is_kernel_sym ? symbol_conf.demangle_kernel : symbol_conf.demangle;
212}
213
214static char *demangle_sym(struct dso *dso, int kmodule, const char *elf_name)
215{
216 int demangle_flags = verbose ? (DMGL_PARAMS | DMGL_ANSI) : DMGL_NO_OPTS;
217 char *demangled = NULL;
218
219 /*
220 * We need to figure out if the object was created from C++ sources
221 * DWARF DW_compile_unit has this, but we don't always have access
222 * to it...
223 */
224 if (!want_demangle(dso->kernel || kmodule))
225 return demangled;
226
227 demangled = bfd_demangle(NULL, elf_name, demangle_flags);
228 if (demangled == NULL)
229 demangled = java_demangle_sym(elf_name, JAVA_DEMANGLE_NORET);
230 else if (rust_is_mangled(demangled))
231 /*
232 * Input to Rust demangling is the BFD-demangled
233 * name which it Rust-demangles in place.
234 */
235 rust_demangle_sym(demangled);
236
237 return demangled;
238}
239
209#define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \ 240#define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \
210 for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \ 241 for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \
211 idx < nr_entries; \ 242 idx < nr_entries; \
@@ -301,11 +332,19 @@ int dso__synthesize_plt_symbols(struct dso *dso, struct symsrc *ss, struct map *
301 332
302 elf_section__for_each_rela(reldata, pos, pos_mem, idx, 333 elf_section__for_each_rela(reldata, pos, pos_mem, idx,
303 nr_rel_entries) { 334 nr_rel_entries) {
335 const char *elf_name = NULL;
336 char *demangled = NULL;
304 symidx = GELF_R_SYM(pos->r_info); 337 symidx = GELF_R_SYM(pos->r_info);
305 plt_offset += shdr_plt.sh_entsize; 338 plt_offset += shdr_plt.sh_entsize;
306 gelf_getsym(syms, symidx, &sym); 339 gelf_getsym(syms, symidx, &sym);
340
341 elf_name = elf_sym__name(&sym, symstrs);
342 demangled = demangle_sym(dso, 0, elf_name);
343 if (demangled != NULL)
344 elf_name = demangled;
307 snprintf(sympltname, sizeof(sympltname), 345 snprintf(sympltname, sizeof(sympltname),
308 "%s@plt", elf_sym__name(&sym, symstrs)); 346 "%s@plt", elf_name);
347 free(demangled);
309 348
310 f = symbol__new(plt_offset, shdr_plt.sh_entsize, 349 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
311 STB_GLOBAL, sympltname); 350 STB_GLOBAL, sympltname);
@@ -323,11 +362,19 @@ int dso__synthesize_plt_symbols(struct dso *dso, struct symsrc *ss, struct map *
323 GElf_Rel pos_mem, *pos; 362 GElf_Rel pos_mem, *pos;
324 elf_section__for_each_rel(reldata, pos, pos_mem, idx, 363 elf_section__for_each_rel(reldata, pos, pos_mem, idx,
325 nr_rel_entries) { 364 nr_rel_entries) {
365 const char *elf_name = NULL;
366 char *demangled = NULL;
326 symidx = GELF_R_SYM(pos->r_info); 367 symidx = GELF_R_SYM(pos->r_info);
327 plt_offset += shdr_plt.sh_entsize; 368 plt_offset += shdr_plt.sh_entsize;
328 gelf_getsym(syms, symidx, &sym); 369 gelf_getsym(syms, symidx, &sym);
370
371 elf_name = elf_sym__name(&sym, symstrs);
372 demangled = demangle_sym(dso, 0, elf_name);
373 if (demangled != NULL)
374 elf_name = demangled;
329 snprintf(sympltname, sizeof(sympltname), 375 snprintf(sympltname, sizeof(sympltname),
330 "%s@plt", elf_sym__name(&sym, symstrs)); 376 "%s@plt", elf_name);
377 free(demangled);
331 378
332 f = symbol__new(plt_offset, shdr_plt.sh_entsize, 379 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
333 STB_GLOBAL, sympltname); 380 STB_GLOBAL, sympltname);
@@ -685,7 +732,7 @@ int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name,
685 } 732 }
686 733
687 /* Always reject images with a mismatched build-id: */ 734 /* Always reject images with a mismatched build-id: */
688 if (dso->has_build_id) { 735 if (dso->has_build_id && !symbol_conf.ignore_vmlinux_buildid) {
689 u8 build_id[BUILD_ID_SIZE]; 736 u8 build_id[BUILD_ID_SIZE];
690 737
691 if (elf_read_build_id(elf, build_id, BUILD_ID_SIZE) < 0) { 738 if (elf_read_build_id(elf, build_id, BUILD_ID_SIZE) < 0) {
@@ -775,11 +822,6 @@ static u64 ref_reloc(struct kmap *kmap)
775 return 0; 822 return 0;
776} 823}
777 824
778static bool want_demangle(bool is_kernel_sym)
779{
780 return is_kernel_sym ? symbol_conf.demangle_kernel : symbol_conf.demangle;
781}
782
783void __weak arch__sym_update(struct symbol *s __maybe_unused, 825void __weak arch__sym_update(struct symbol *s __maybe_unused,
784 GElf_Sym *sym __maybe_unused) { } 826 GElf_Sym *sym __maybe_unused) { }
785 827
@@ -1070,29 +1112,10 @@ int dso__load_sym(struct dso *dso, struct map *map,
1070 sym.st_value -= shdr.sh_addr - shdr.sh_offset; 1112 sym.st_value -= shdr.sh_addr - shdr.sh_offset;
1071 } 1113 }
1072new_symbol: 1114new_symbol:
1073 /* 1115 demangled = demangle_sym(dso, kmodule, elf_name);
1074 * We need to figure out if the object was created from C++ sources 1116 if (demangled != NULL)
1075 * DWARF DW_compile_unit has this, but we don't always have access 1117 elf_name = demangled;
1076 * to it...
1077 */
1078 if (want_demangle(dso->kernel || kmodule)) {
1079 int demangle_flags = DMGL_NO_OPTS;
1080 if (verbose)
1081 demangle_flags = DMGL_PARAMS | DMGL_ANSI;
1082
1083 demangled = bfd_demangle(NULL, elf_name, demangle_flags);
1084 if (demangled == NULL)
1085 demangled = java_demangle_sym(elf_name, JAVA_DEMANGLE_NORET);
1086 else if (rust_is_mangled(demangled))
1087 /*
1088 * Input to Rust demangling is the BFD-demangled
1089 * name which it Rust-demangles in place.
1090 */
1091 rust_demangle_sym(demangled);
1092 1118
1093 if (demangled != NULL)
1094 elf_name = demangled;
1095 }
1096 f = symbol__new(sym.st_value, sym.st_size, 1119 f = symbol__new(sym.st_value, sym.st_size,
1097 GELF_ST_BIND(sym.st_info), elf_name); 1120 GELF_ST_BIND(sym.st_info), elf_name);
1098 free(demangled); 1121 free(demangled);
@@ -1113,9 +1136,8 @@ new_symbol:
1113 * For misannotated, zeroed, ASM function sizes. 1136 * For misannotated, zeroed, ASM function sizes.
1114 */ 1137 */
1115 if (nr > 0) { 1138 if (nr > 0) {
1116 if (!symbol_conf.allow_aliases)
1117 symbols__fixup_duplicate(&dso->symbols[map->type]);
1118 symbols__fixup_end(&dso->symbols[map->type]); 1139 symbols__fixup_end(&dso->symbols[map->type]);
1140 symbols__fixup_duplicate(&dso->symbols[map->type]);
1119 if (kmap) { 1141 if (kmap) {
1120 /* 1142 /*
1121 * We need to fixup this here too because we create new 1143 * We need to fixup this here too because we create new
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 37e8d20ae03e..98cd50384c32 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -9,6 +9,7 @@
9#include <fcntl.h> 9#include <fcntl.h>
10#include <unistd.h> 10#include <unistd.h>
11#include <inttypes.h> 11#include <inttypes.h>
12#include "annotate.h"
12#include "build-id.h" 13#include "build-id.h"
13#include "util.h" 14#include "util.h"
14#include "debug.h" 15#include "debug.h"
@@ -152,6 +153,9 @@ void symbols__fixup_duplicate(struct rb_root *symbols)
152 struct rb_node *nd; 153 struct rb_node *nd;
153 struct symbol *curr, *next; 154 struct symbol *curr, *next;
154 155
156 if (symbol_conf.allow_aliases)
157 return;
158
155 nd = rb_first(symbols); 159 nd = rb_first(symbols);
156 160
157 while (nd) { 161 while (nd) {
@@ -235,8 +239,13 @@ struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name)
235 if (sym == NULL) 239 if (sym == NULL)
236 return NULL; 240 return NULL;
237 241
238 if (symbol_conf.priv_size) 242 if (symbol_conf.priv_size) {
243 if (symbol_conf.init_annotation) {
244 struct annotation *notes = (void *)sym;
245 pthread_mutex_init(&notes->lock, NULL);
246 }
239 sym = ((void *)sym) + symbol_conf.priv_size; 247 sym = ((void *)sym) + symbol_conf.priv_size;
248 }
240 249
241 sym->start = start; 250 sym->start = start;
242 sym->end = len ? start + len : start; 251 sym->end = len ? start + len : start;
@@ -1234,8 +1243,8 @@ int __dso__load_kallsyms(struct dso *dso, const char *filename,
1234 if (kallsyms__delta(map, filename, &delta)) 1243 if (kallsyms__delta(map, filename, &delta))
1235 return -1; 1244 return -1;
1236 1245
1237 symbols__fixup_duplicate(&dso->symbols[map->type]);
1238 symbols__fixup_end(&dso->symbols[map->type]); 1246 symbols__fixup_end(&dso->symbols[map->type]);
1247 symbols__fixup_duplicate(&dso->symbols[map->type]);
1239 1248
1240 if (dso->kernel == DSO_TYPE_GUEST_KERNEL) 1249 if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
1241 dso->symtab_type = DSO_BINARY_TYPE__GUEST_KALLSYMS; 1250 dso->symtab_type = DSO_BINARY_TYPE__GUEST_KALLSYMS;
@@ -1948,6 +1957,23 @@ static bool symbol__read_kptr_restrict(void)
1948 return value; 1957 return value;
1949} 1958}
1950 1959
1960int symbol__annotation_init(void)
1961{
1962 if (symbol_conf.initialized) {
1963 pr_err("Annotation needs to be init before symbol__init()\n");
1964 return -1;
1965 }
1966
1967 if (symbol_conf.init_annotation) {
1968 pr_warning("Annotation being initialized multiple times\n");
1969 return 0;
1970 }
1971
1972 symbol_conf.priv_size += sizeof(struct annotation);
1973 symbol_conf.init_annotation = true;
1974 return 0;
1975}
1976
1951int symbol__init(struct perf_env *env) 1977int symbol__init(struct perf_env *env)
1952{ 1978{
1953 const char *symfs; 1979 const char *symfs;
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 699f7cbcfe72..e54ee7c78ca3 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -57,7 +57,7 @@ struct symbol {
57 u64 end; 57 u64 end;
58 u16 namelen; 58 u16 namelen;
59 u8 binding; 59 u8 binding;
60 bool ignore; 60 u8 idle:1;
61 u8 arch_sym; 61 u8 arch_sym;
62 char name[0]; 62 char name[0];
63}; 63};
@@ -88,6 +88,7 @@ struct symbol_conf {
88 unsigned short priv_size; 88 unsigned short priv_size;
89 unsigned short nr_events; 89 unsigned short nr_events;
90 bool try_vmlinux_path, 90 bool try_vmlinux_path,
91 init_annotation,
91 force, 92 force,
92 ignore_vmlinux, 93 ignore_vmlinux,
93 ignore_vmlinux_buildid, 94 ignore_vmlinux_buildid,
@@ -277,6 +278,8 @@ struct perf_env;
277int symbol__init(struct perf_env *env); 278int symbol__init(struct perf_env *env);
278void symbol__exit(void); 279void symbol__exit(void);
279void symbol__elf_init(void); 280void symbol__elf_init(void);
281int symbol__annotation_init(void);
282
280struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name); 283struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name);
281size_t __symbol__fprintf_symname_offs(const struct symbol *sym, 284size_t __symbol__fprintf_symname_offs(const struct symbol *sym,
282 const struct addr_location *al, 285 const struct addr_location *al,