diff options
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 | |||
113 | Variables | 121 | Variables |
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' |
22 | or | 22 | or |
23 | 'perf probe' [options] --funcs | 23 | 'perf probe' [options] --funcs |
24 | or | ||
25 | 'perf probe' [options] --definition='PROBE' [...] | ||
24 | 26 | ||
25 | DESCRIPTION | 27 | DESCRIPTION |
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 | |||
4 | static 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 | |||
4 | static 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 | |||
11 | static 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 | |||
4 | static 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 | |||
4 | const 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 | |||
4 | static 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 | |||
4 | static const char * const x86_32_regstr_tbl[] = { | ||
5 | "%ax", "%cx", "%dx", "%bx", "$stack",/* Stack address instead of %sp */ | ||
6 | "%bp", "%si", "%di", | ||
7 | }; | ||
8 | |||
9 | static 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 | |||
4 | static 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 | |||
457 | static int | 470 | static 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 | } |
233 | out: | 249 | out: |
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 | ||
99 | libperf-$(CONFIG_DWARF) += probe-finder.o | 99 | libperf-$(CONFIG_DWARF) += probe-finder.o |
100 | libperf-$(CONFIG_DWARF) += dwarf-aux.o | 100 | libperf-$(CONFIG_DWARF) += dwarf-aux.o |
101 | libperf-$(CONFIG_DWARF) += dwarf-regs.o | ||
101 | 102 | ||
102 | libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o | 103 | libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o |
103 | libperf-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind-local.o | 104 | libperf-$(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 | ||
494 | int symbol__annotate_init(struct map *map __maybe_unused, struct symbol *sym) | ||
495 | { | ||
496 | struct annotation *notes = symbol__annotation(sym); | ||
497 | pthread_mutex_init(¬es->lock, NULL); | ||
498 | return 0; | ||
499 | } | ||
500 | |||
501 | int symbol__alloc_hist(struct symbol *sym) | 494 | int 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 { | |||
177 | int symbol__strerror_disassemble(struct symbol *sym, struct map *map, | 177 | int 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 | ||
180 | int symbol__annotate_init(struct map *map, struct symbol *sym); | ||
181 | int symbol__annotate_printf(struct symbol *sym, struct map *map, | 180 | int 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 | */ | ||
1093 | static 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 | */ | ||
1115 | bool 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 | */ | ||
1145 | static 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 | */ | ||
1174 | static 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 | */ | ||
1243 | void 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" */ |
126 | int die_get_varname(Dwarf_Die *vr_die, struct strbuf *buf); | 126 | int die_get_varname(Dwarf_Die *vr_die, struct strbuf *buf); |
127 | int die_get_var_range(Dwarf_Die *sp_die, Dwarf_Die *vr_die, struct strbuf *buf); | 127 | int 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 */ | ||
130 | bool die_is_optimized_target(Dwarf_Die *cu_die); | ||
131 | |||
132 | /* Use next address after prologue as probe location */ | ||
133 | void 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) */ | ||
30 | const 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 |
5 | const char *get_arch_regstr(unsigned int n); | 5 | const 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 | */ | ||
11 | const 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; | ||
95 | err_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. */ | ||
1622 | bool 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 */ |
1618 | bool perf_probe_event_need_dwarf(struct perf_probe_event *pev) | 1635 | bool 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 | ||
3222 | static 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 | |||
3238 | int 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 | |||
3210 | int apply_perf_probe_events(struct perf_probe_event *pevs, int npevs) | 3268 | int 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 ... */ | ||
3293 | static 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 | */ | ||
3299 | static 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 | |||
3307 | int show_available_funcs(const char *target, struct strfilter *_filter, | 3350 | int 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 | |||
3347 | end: | 3396 | end: |
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); | |||
128 | int perf_probe_event__copy(struct perf_probe_event *dst, | 128 | int perf_probe_event__copy(struct perf_probe_event *dst, |
129 | struct perf_probe_event *src); | 129 | struct perf_probe_event *src); |
130 | 130 | ||
131 | bool 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 */ |
132 | bool perf_probe_event_need_dwarf(struct perf_probe_event *pev); | 134 | bool perf_probe_event_need_dwarf(struct perf_probe_event *pev); |
133 | 135 | ||
@@ -147,6 +149,7 @@ int line_range__init(struct line_range *lr); | |||
147 | int add_perf_probe_events(struct perf_probe_event *pevs, int npevs); | 149 | int add_perf_probe_events(struct perf_probe_event *pevs, int npevs); |
148 | int convert_perf_probe_events(struct perf_probe_event *pevs, int npevs); | 150 | int convert_perf_probe_events(struct perf_probe_event *pevs, int npevs); |
149 | int apply_perf_probe_events(struct perf_probe_event *pevs, int npevs); | 151 | int apply_perf_probe_events(struct perf_probe_event *pevs, int npevs); |
152 | int show_probe_trace_events(struct perf_probe_event *pevs, int npevs); | ||
150 | void cleanup_perf_probe_events(struct perf_probe_event *pevs, int npevs); | 153 | void cleanup_perf_probe_events(struct perf_probe_event *pevs, int npevs); |
151 | int del_perf_probe_events(struct strfilter *filter); | 154 | int 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) | |||
73 | static int open_probe_events(const char *trace_file, bool readwrite) | 73 | static 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 | */ |
172 | static int convert_variable_location(Dwarf_Die *vr_die, Dwarf_Addr addr, | 172 | static 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 | ||
910 | static 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 | |||
909 | static int probe_point_inline_cb(Dwarf_Die *in_die, void *data) | 942 | static 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 | ||
209 | static bool want_demangle(bool is_kernel_sym) | ||
210 | { | ||
211 | return is_kernel_sym ? symbol_conf.demangle_kernel : symbol_conf.demangle; | ||
212 | } | ||
213 | |||
214 | static 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 | ||
778 | static bool want_demangle(bool is_kernel_sym) | ||
779 | { | ||
780 | return is_kernel_sym ? symbol_conf.demangle_kernel : symbol_conf.demangle; | ||
781 | } | ||
782 | |||
783 | void __weak arch__sym_update(struct symbol *s __maybe_unused, | 825 | void __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 | } |
1072 | new_symbol: | 1114 | new_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(¬es->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 | ||
1960 | int 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 | |||
1951 | int symbol__init(struct perf_env *env) | 1977 | int 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; | |||
277 | int symbol__init(struct perf_env *env); | 278 | int symbol__init(struct perf_env *env); |
278 | void symbol__exit(void); | 279 | void symbol__exit(void); |
279 | void symbol__elf_init(void); | 280 | void symbol__elf_init(void); |
281 | int symbol__annotation_init(void); | ||
282 | |||
280 | struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name); | 283 | struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name); |
281 | size_t __symbol__fprintf_symname_offs(const struct symbol *sym, | 284 | size_t __symbol__fprintf_symname_offs(const struct symbol *sym, |
282 | const struct addr_location *al, | 285 | const struct addr_location *al, |