aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2016-11-25 12:12:41 -0500
committerIngo Molnar <mingo@kernel.org>2016-11-25 12:12:41 -0500
commit2471cece40d61b0035360338569d338f9dea6099 (patch)
tree809f1d14defbc82fc6a957597b8b0bcb6600faed /tools
parent47414424c53a70eceb0fc6e0a35a31a2b763d5b2 (diff)
parent4708bbda5cb2f6cdc331744597527143f46394d5 (diff)
Merge tag 'perf-core-for-mingo-20161125' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core
Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo: New features: - Improve ARM support in the annotation code, affecting 'perf annotate', 'perf report' and live annotation in 'perf top' (Kim Phillips) - Initial support for PowerPC in the annotation code (Ravi Bangoria) - Skip repetitive scheduler function on the top of the stack in 'perf sched timehist' (Namhyung Kim) Fixes: - Fix maps resolution in libbpf (Eric Leblond) - Get the kernel signature via /proc/version_signature, available on Ubuntu systems, to make sure BPF proggies works, as the one provided via 'uname -r' doesn't (Wang Nan) - Fix segfault in 'perf record' when running with suid and kptr_restrict is 1 (Wang Nan) Infrastructure changes: - Support per-arch instruction tables, kept via a static or dynamic table (Arnaldo Carvalho de Melo) Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'tools')
-rw-r--r--tools/lib/bpf/libbpf.c142
-rw-r--r--tools/perf/arch/arm/annotate/instructions.c147
-rw-r--r--tools/perf/arch/powerpc/annotate/instructions.c58
-rw-r--r--tools/perf/builtin-sched.c26
-rw-r--r--tools/perf/ui/browsers/annotate.c18
-rw-r--r--tools/perf/util/annotate.c157
-rw-r--r--tools/perf/util/annotate.h17
-rw-r--r--tools/perf/util/evsel.h1
-rw-r--r--tools/perf/util/evsel_fprintf.c7
-rw-r--r--tools/perf/util/probe-event.h2
-rw-r--r--tools/perf/util/symbol.c2
-rw-r--r--tools/perf/util/symbol.h1
-rw-r--r--tools/perf/util/util.c55
13 files changed, 431 insertions, 202 deletions
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index b699aea9a025..96a2b2ff1212 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -185,6 +185,7 @@ struct bpf_program {
185struct bpf_map { 185struct bpf_map {
186 int fd; 186 int fd;
187 char *name; 187 char *name;
188 size_t offset;
188 struct bpf_map_def def; 189 struct bpf_map_def def;
189 void *priv; 190 void *priv;
190 bpf_map_clear_priv_t clear_priv; 191 bpf_map_clear_priv_t clear_priv;
@@ -513,57 +514,106 @@ bpf_object__init_kversion(struct bpf_object *obj,
513} 514}
514 515
515static int 516static int
516bpf_object__init_maps(struct bpf_object *obj, void *data, 517bpf_object__validate_maps(struct bpf_object *obj)
517 size_t size)
518{ 518{
519 size_t nr_maps;
520 int i; 519 int i;
521 520
522 nr_maps = size / sizeof(struct bpf_map_def); 521 /*
523 if (!data || !nr_maps) { 522 * If there's only 1 map, the only error case should have been
524 pr_debug("%s doesn't need map definition\n", 523 * catched in bpf_object__init_maps().
525 obj->path); 524 */
525 if (!obj->maps || !obj->nr_maps || (obj->nr_maps == 1))
526 return 0; 526 return 0;
527 }
528 527
529 pr_debug("maps in %s: %zd bytes\n", obj->path, size); 528 for (i = 1; i < obj->nr_maps; i++) {
529 const struct bpf_map *a = &obj->maps[i - 1];
530 const struct bpf_map *b = &obj->maps[i];
530 531
531 obj->maps = calloc(nr_maps, sizeof(obj->maps[0])); 532 if (b->offset - a->offset < sizeof(struct bpf_map_def)) {
532 if (!obj->maps) { 533 pr_warning("corrupted map section in %s: map \"%s\" too small\n",
533 pr_warning("alloc maps for object failed\n"); 534 obj->path, a->name);
534 return -ENOMEM; 535 return -EINVAL;
536 }
535 } 537 }
536 obj->nr_maps = nr_maps; 538 return 0;
537 539}
538 for (i = 0; i < nr_maps; i++) {
539 struct bpf_map_def *def = &obj->maps[i].def;
540 540
541 /* 541static int compare_bpf_map(const void *_a, const void *_b)
542 * fill all fd with -1 so won't close incorrect 542{
543 * fd (fd=0 is stdin) when failure (zclose won't close 543 const struct bpf_map *a = _a;
544 * negative fd)). 544 const struct bpf_map *b = _b;
545 */
546 obj->maps[i].fd = -1;
547 545
548 /* Save map definition into obj->maps */ 546 return a->offset - b->offset;
549 *def = ((struct bpf_map_def *)data)[i];
550 }
551 return 0;
552} 547}
553 548
554static int 549static int
555bpf_object__init_maps_name(struct bpf_object *obj) 550bpf_object__init_maps(struct bpf_object *obj)
556{ 551{
557 int i; 552 int i, map_idx, nr_maps = 0;
553 Elf_Scn *scn;
554 Elf_Data *data;
558 Elf_Data *symbols = obj->efile.symbols; 555 Elf_Data *symbols = obj->efile.symbols;
559 556
560 if (!symbols || obj->efile.maps_shndx < 0) 557 if (obj->efile.maps_shndx < 0)
558 return -EINVAL;
559 if (!symbols)
560 return -EINVAL;
561
562 scn = elf_getscn(obj->efile.elf, obj->efile.maps_shndx);
563 if (scn)
564 data = elf_getdata(scn, NULL);
565 if (!scn || !data) {
566 pr_warning("failed to get Elf_Data from map section %d\n",
567 obj->efile.maps_shndx);
561 return -EINVAL; 568 return -EINVAL;
569 }
562 570
571 /*
572 * Count number of maps. Each map has a name.
573 * Array of maps is not supported: only the first element is
574 * considered.
575 *
576 * TODO: Detect array of map and report error.
577 */
563 for (i = 0; i < symbols->d_size / sizeof(GElf_Sym); i++) { 578 for (i = 0; i < symbols->d_size / sizeof(GElf_Sym); i++) {
564 GElf_Sym sym; 579 GElf_Sym sym;
565 size_t map_idx; 580
581 if (!gelf_getsym(symbols, i, &sym))
582 continue;
583 if (sym.st_shndx != obj->efile.maps_shndx)
584 continue;
585 nr_maps++;
586 }
587
588 /* Alloc obj->maps and fill nr_maps. */
589 pr_debug("maps in %s: %d maps in %zd bytes\n", obj->path,
590 nr_maps, data->d_size);
591
592 if (!nr_maps)
593 return 0;
594
595 obj->maps = calloc(nr_maps, sizeof(obj->maps[0]));
596 if (!obj->maps) {
597 pr_warning("alloc maps for object failed\n");
598 return -ENOMEM;
599 }
600 obj->nr_maps = nr_maps;
601
602 /*
603 * fill all fd with -1 so won't close incorrect
604 * fd (fd=0 is stdin) when failure (zclose won't close
605 * negative fd)).
606 */
607 for (i = 0; i < nr_maps; i++)
608 obj->maps[i].fd = -1;
609
610 /*
611 * Fill obj->maps using data in "maps" section.
612 */
613 for (i = 0, map_idx = 0; i < symbols->d_size / sizeof(GElf_Sym); i++) {
614 GElf_Sym sym;
566 const char *map_name; 615 const char *map_name;
616 struct bpf_map_def *def;
567 617
568 if (!gelf_getsym(symbols, i, &sym)) 618 if (!gelf_getsym(symbols, i, &sym))
569 continue; 619 continue;
@@ -573,21 +623,27 @@ bpf_object__init_maps_name(struct bpf_object *obj)
573 map_name = elf_strptr(obj->efile.elf, 623 map_name = elf_strptr(obj->efile.elf,
574 obj->efile.strtabidx, 624 obj->efile.strtabidx,
575 sym.st_name); 625 sym.st_name);
576 map_idx = sym.st_value / sizeof(struct bpf_map_def); 626 obj->maps[map_idx].offset = sym.st_value;
577 if (map_idx >= obj->nr_maps) { 627 if (sym.st_value + sizeof(struct bpf_map_def) > data->d_size) {
578 pr_warning("index of map \"%s\" is buggy: %zu > %zu\n", 628 pr_warning("corrupted maps section in %s: last map \"%s\" too small\n",
579 map_name, map_idx, obj->nr_maps); 629 obj->path, map_name);
580 continue; 630 return -EINVAL;
581 } 631 }
632
582 obj->maps[map_idx].name = strdup(map_name); 633 obj->maps[map_idx].name = strdup(map_name);
583 if (!obj->maps[map_idx].name) { 634 if (!obj->maps[map_idx].name) {
584 pr_warning("failed to alloc map name\n"); 635 pr_warning("failed to alloc map name\n");
585 return -ENOMEM; 636 return -ENOMEM;
586 } 637 }
587 pr_debug("map %zu is \"%s\"\n", map_idx, 638 pr_debug("map %d is \"%s\"\n", map_idx,
588 obj->maps[map_idx].name); 639 obj->maps[map_idx].name);
640 def = (struct bpf_map_def *)(data->d_buf + sym.st_value);
641 obj->maps[map_idx].def = *def;
642 map_idx++;
589 } 643 }
590 return 0; 644
645 qsort(obj->maps, obj->nr_maps, sizeof(obj->maps[0]), compare_bpf_map);
646 return bpf_object__validate_maps(obj);
591} 647}
592 648
593static int bpf_object__elf_collect(struct bpf_object *obj) 649static int bpf_object__elf_collect(struct bpf_object *obj)
@@ -645,11 +701,9 @@ static int bpf_object__elf_collect(struct bpf_object *obj)
645 err = bpf_object__init_kversion(obj, 701 err = bpf_object__init_kversion(obj,
646 data->d_buf, 702 data->d_buf,
647 data->d_size); 703 data->d_size);
648 else if (strcmp(name, "maps") == 0) { 704 else if (strcmp(name, "maps") == 0)
649 err = bpf_object__init_maps(obj, data->d_buf,
650 data->d_size);
651 obj->efile.maps_shndx = idx; 705 obj->efile.maps_shndx = idx;
652 } else if (sh.sh_type == SHT_SYMTAB) { 706 else if (sh.sh_type == SHT_SYMTAB) {
653 if (obj->efile.symbols) { 707 if (obj->efile.symbols) {
654 pr_warning("bpf: multiple SYMTAB in %s\n", 708 pr_warning("bpf: multiple SYMTAB in %s\n",
655 obj->path); 709 obj->path);
@@ -698,7 +752,7 @@ static int bpf_object__elf_collect(struct bpf_object *obj)
698 return LIBBPF_ERRNO__FORMAT; 752 return LIBBPF_ERRNO__FORMAT;
699 } 753 }
700 if (obj->efile.maps_shndx >= 0) 754 if (obj->efile.maps_shndx >= 0)
701 err = bpf_object__init_maps_name(obj); 755 err = bpf_object__init_maps(obj);
702out: 756out:
703 return err; 757 return err;
704} 758}
@@ -807,7 +861,7 @@ bpf_object__create_maps(struct bpf_object *obj)
807 zclose(obj->maps[j].fd); 861 zclose(obj->maps[j].fd);
808 return err; 862 return err;
809 } 863 }
810 pr_debug("create map: fd=%d\n", *pfd); 864 pr_debug("create map %s: fd=%d\n", obj->maps[i].name, *pfd);
811 } 865 }
812 866
813 return 0; 867 return 0;
diff --git a/tools/perf/arch/arm/annotate/instructions.c b/tools/perf/arch/arm/annotate/instructions.c
index d67b8aa26274..1ce0872b1726 100644
--- a/tools/perf/arch/arm/annotate/instructions.c
+++ b/tools/perf/arch/arm/annotate/instructions.c
@@ -1,90 +1,59 @@
1static struct ins arm__instructions[] = { 1#include <sys/types.h>
2 { .name = "add", .ops = &mov_ops, }, 2#include <regex.h>
3 { .name = "addl", .ops = &mov_ops, }, 3
4 { .name = "addq", .ops = &mov_ops, }, 4struct arm_annotate {
5 { .name = "addw", .ops = &mov_ops, }, 5 regex_t call_insn,
6 { .name = "and", .ops = &mov_ops, }, 6 jump_insn;
7 { .name = "b", .ops = &jump_ops, }, // might also be a call
8 { .name = "bcc", .ops = &jump_ops, },
9 { .name = "bcs", .ops = &jump_ops, },
10 { .name = "beq", .ops = &jump_ops, },
11 { .name = "bge", .ops = &jump_ops, },
12 { .name = "bgt", .ops = &jump_ops, },
13 { .name = "bhi", .ops = &jump_ops, },
14 { .name = "bl", .ops = &call_ops, },
15 { .name = "bls", .ops = &jump_ops, },
16 { .name = "blt", .ops = &jump_ops, },
17 { .name = "blx", .ops = &call_ops, },
18 { .name = "bne", .ops = &jump_ops, },
19 { .name = "bts", .ops = &mov_ops, },
20 { .name = "call", .ops = &call_ops, },
21 { .name = "callq", .ops = &call_ops, },
22 { .name = "cmp", .ops = &mov_ops, },
23 { .name = "cmpb", .ops = &mov_ops, },
24 { .name = "cmpl", .ops = &mov_ops, },
25 { .name = "cmpq", .ops = &mov_ops, },
26 { .name = "cmpw", .ops = &mov_ops, },
27 { .name = "cmpxch", .ops = &mov_ops, },
28 { .name = "dec", .ops = &dec_ops, },
29 { .name = "decl", .ops = &dec_ops, },
30 { .name = "imul", .ops = &mov_ops, },
31 { .name = "inc", .ops = &dec_ops, },
32 { .name = "incl", .ops = &dec_ops, },
33 { .name = "ja", .ops = &jump_ops, },
34 { .name = "jae", .ops = &jump_ops, },
35 { .name = "jb", .ops = &jump_ops, },
36 { .name = "jbe", .ops = &jump_ops, },
37 { .name = "jc", .ops = &jump_ops, },
38 { .name = "jcxz", .ops = &jump_ops, },
39 { .name = "je", .ops = &jump_ops, },
40 { .name = "jecxz", .ops = &jump_ops, },
41 { .name = "jg", .ops = &jump_ops, },
42 { .name = "jge", .ops = &jump_ops, },
43 { .name = "jl", .ops = &jump_ops, },
44 { .name = "jle", .ops = &jump_ops, },
45 { .name = "jmp", .ops = &jump_ops, },
46 { .name = "jmpq", .ops = &jump_ops, },
47 { .name = "jna", .ops = &jump_ops, },
48 { .name = "jnae", .ops = &jump_ops, },
49 { .name = "jnb", .ops = &jump_ops, },
50 { .name = "jnbe", .ops = &jump_ops, },
51 { .name = "jnc", .ops = &jump_ops, },
52 { .name = "jne", .ops = &jump_ops, },
53 { .name = "jng", .ops = &jump_ops, },
54 { .name = "jnge", .ops = &jump_ops, },
55 { .name = "jnl", .ops = &jump_ops, },
56 { .name = "jnle", .ops = &jump_ops, },
57 { .name = "jno", .ops = &jump_ops, },
58 { .name = "jnp", .ops = &jump_ops, },
59 { .name = "jns", .ops = &jump_ops, },
60 { .name = "jnz", .ops = &jump_ops, },
61 { .name = "jo", .ops = &jump_ops, },
62 { .name = "jp", .ops = &jump_ops, },
63 { .name = "jpe", .ops = &jump_ops, },
64 { .name = "jpo", .ops = &jump_ops, },
65 { .name = "jrcxz", .ops = &jump_ops, },
66 { .name = "js", .ops = &jump_ops, },
67 { .name = "jz", .ops = &jump_ops, },
68 { .name = "lea", .ops = &mov_ops, },
69 { .name = "lock", .ops = &lock_ops, },
70 { .name = "mov", .ops = &mov_ops, },
71 { .name = "movb", .ops = &mov_ops, },
72 { .name = "movdqa", .ops = &mov_ops, },
73 { .name = "movl", .ops = &mov_ops, },
74 { .name = "movq", .ops = &mov_ops, },
75 { .name = "movslq", .ops = &mov_ops, },
76 { .name = "movzbl", .ops = &mov_ops, },
77 { .name = "movzwl", .ops = &mov_ops, },
78 { .name = "nop", .ops = &nop_ops, },
79 { .name = "nopl", .ops = &nop_ops, },
80 { .name = "nopw", .ops = &nop_ops, },
81 { .name = "or", .ops = &mov_ops, },
82 { .name = "orl", .ops = &mov_ops, },
83 { .name = "test", .ops = &mov_ops, },
84 { .name = "testb", .ops = &mov_ops, },
85 { .name = "testl", .ops = &mov_ops, },
86 { .name = "xadd", .ops = &mov_ops, },
87 { .name = "xbeginl", .ops = &jump_ops, },
88 { .name = "xbeginq", .ops = &jump_ops, },
89 { .name = "retq", .ops = &ret_ops, },
90}; 7};
8
9static struct ins_ops *arm__associate_instruction_ops(struct arch *arch, const char *name)
10{
11 struct arm_annotate *arm = arch->priv;
12 struct ins_ops *ops;
13 regmatch_t match[2];
14
15 if (!regexec(&arm->call_insn, name, 2, match, 0))
16 ops = &call_ops;
17 else if (!regexec(&arm->jump_insn, name, 2, match, 0))
18 ops = &jump_ops;
19 else
20 return NULL;
21
22 arch__associate_ins_ops(arch, name, ops);
23 return ops;
24}
25
26static int arm__annotate_init(struct arch *arch)
27{
28 struct arm_annotate *arm;
29 int err;
30
31 if (arch->initialized)
32 return 0;
33
34 arm = zalloc(sizeof(*arm));
35 if (!arm)
36 return -1;
37
38#define ARM_CONDS "(cc|cs|eq|ge|gt|hi|le|ls|lt|mi|ne|pl|vc|vs)"
39 err = regcomp(&arm->call_insn, "^blx?" ARM_CONDS "?$", REG_EXTENDED);
40 if (err)
41 goto out_free_arm;
42 err = regcomp(&arm->jump_insn, "^bx?" ARM_CONDS "?$", REG_EXTENDED);
43 if (err)
44 goto out_free_call;
45#undef ARM_CONDS
46
47 arch->initialized = true;
48 arch->priv = arm;
49 arch->associate_instruction_ops = arm__associate_instruction_ops;
50 arch->objdump.comment_char = ';';
51 arch->objdump.skip_functions_char = '+';
52 return 0;
53
54out_free_call:
55 regfree(&arm->call_insn);
56out_free_arm:
57 free(arm);
58 return -1;
59}
diff --git a/tools/perf/arch/powerpc/annotate/instructions.c b/tools/perf/arch/powerpc/annotate/instructions.c
new file mode 100644
index 000000000000..3c4004db81b9
--- /dev/null
+++ b/tools/perf/arch/powerpc/annotate/instructions.c
@@ -0,0 +1,58 @@
1static struct ins_ops *powerpc__associate_instruction_ops(struct arch *arch, const char *name)
2{
3 int i;
4 struct ins_ops *ops;
5
6 /*
7 * - Interested only if instruction starts with 'b'.
8 * - Few start with 'b', but aren't branch instructions.
9 */
10 if (name[0] != 'b' ||
11 !strncmp(name, "bcd", 3) ||
12 !strncmp(name, "brinc", 5) ||
13 !strncmp(name, "bper", 4))
14 return NULL;
15
16 ops = &jump_ops;
17
18 i = strlen(name) - 1;
19 if (i < 0)
20 return NULL;
21
22 /* ignore optional hints at the end of the instructions */
23 if (name[i] == '+' || name[i] == '-')
24 i--;
25
26 if (name[i] == 'l' || (name[i] == 'a' && name[i-1] == 'l')) {
27 /*
28 * if the instruction ends up with 'l' or 'la', then
29 * those are considered 'calls' since they update LR.
30 * ... except for 'bnl' which is branch if not less than
31 * and the absolute form of the same.
32 */
33 if (strcmp(name, "bnl") && strcmp(name, "bnl+") &&
34 strcmp(name, "bnl-") && strcmp(name, "bnla") &&
35 strcmp(name, "bnla+") && strcmp(name, "bnla-"))
36 ops = &call_ops;
37 }
38 if (name[i] == 'r' && name[i-1] == 'l')
39 /*
40 * instructions ending with 'lr' are considered to be
41 * return instructions
42 */
43 ops = &ret_ops;
44
45 arch__associate_ins_ops(arch, name, ops);
46 return ops;
47}
48
49static int powerpc__annotate_init(struct arch *arch)
50{
51 if (!arch->initialized) {
52 arch->initialized = true;
53 arch->associate_instruction_ops = powerpc__associate_instruction_ops;
54 arch->objdump.comment_char = '#';
55 }
56
57 return 0;
58}
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index 829468defa07..a49a032f5b15 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -1876,7 +1876,8 @@ static void timehist_print_sample(struct perf_sched *sched,
1876 1876
1877 sample__fprintf_sym(sample, al, 0, 1877 sample__fprintf_sym(sample, al, 0,
1878 EVSEL__PRINT_SYM | EVSEL__PRINT_ONELINE | 1878 EVSEL__PRINT_SYM | EVSEL__PRINT_ONELINE |
1879 EVSEL__PRINT_CALLCHAIN_ARROW, 1879 EVSEL__PRINT_CALLCHAIN_ARROW |
1880 EVSEL__PRINT_SKIP_IGNORED,
1880 &callchain_cursor, stdout); 1881 &callchain_cursor, stdout);
1881 1882
1882out: 1883out:
@@ -1959,13 +1960,34 @@ static bool is_idle_sample(struct perf_sched *sched,
1959 return false; 1960 return false;
1960 1961
1961 if (thread__resolve_callchain(thread, cursor, evsel, sample, 1962 if (thread__resolve_callchain(thread, cursor, evsel, sample,
1962 NULL, NULL, sched->max_stack) != 0) { 1963 NULL, NULL, sched->max_stack + 2) != 0) {
1963 if (verbose) 1964 if (verbose)
1964 error("Failed to resolve callchain. Skipping\n"); 1965 error("Failed to resolve callchain. Skipping\n");
1965 1966
1966 return false; 1967 return false;
1967 } 1968 }
1969
1968 callchain_cursor_commit(cursor); 1970 callchain_cursor_commit(cursor);
1971
1972 while (true) {
1973 struct callchain_cursor_node *node;
1974 struct symbol *sym;
1975
1976 node = callchain_cursor_current(cursor);
1977 if (node == NULL)
1978 break;
1979
1980 sym = node->sym;
1981 if (sym && sym->name) {
1982 if (!strcmp(sym->name, "schedule") ||
1983 !strcmp(sym->name, "__schedule") ||
1984 !strcmp(sym->name, "preempt_schedule"))
1985 sym->ignore = 1;
1986 }
1987
1988 callchain_cursor_advance(cursor);
1989 }
1990
1969 return false; 1991 return false;
1970} 1992}
1971 1993
diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c
index e6e9f7d80dbd..cee0eee31ce6 100644
--- a/tools/perf/ui/browsers/annotate.c
+++ b/tools/perf/ui/browsers/annotate.c
@@ -213,17 +213,17 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int
213 ui_browser__write_nstring(browser, bf, printed); 213 ui_browser__write_nstring(browser, bf, printed);
214 if (change_color) 214 if (change_color)
215 ui_browser__set_color(browser, color); 215 ui_browser__set_color(browser, color);
216 if (dl->ins && dl->ins->ops->scnprintf) { 216 if (dl->ins.ops && dl->ins.ops->scnprintf) {
217 if (ins__is_jump(dl->ins)) { 217 if (ins__is_jump(&dl->ins)) {
218 bool fwd = dl->ops.target.offset > (u64)dl->offset; 218 bool fwd = dl->ops.target.offset > (u64)dl->offset;
219 219
220 ui_browser__write_graph(browser, fwd ? SLSMG_DARROW_CHAR : 220 ui_browser__write_graph(browser, fwd ? SLSMG_DARROW_CHAR :
221 SLSMG_UARROW_CHAR); 221 SLSMG_UARROW_CHAR);
222 SLsmg_write_char(' '); 222 SLsmg_write_char(' ');
223 } else if (ins__is_call(dl->ins)) { 223 } else if (ins__is_call(&dl->ins)) {
224 ui_browser__write_graph(browser, SLSMG_RARROW_CHAR); 224 ui_browser__write_graph(browser, SLSMG_RARROW_CHAR);
225 SLsmg_write_char(' '); 225 SLsmg_write_char(' ');
226 } else if (ins__is_ret(dl->ins)) { 226 } else if (ins__is_ret(&dl->ins)) {
227 ui_browser__write_graph(browser, SLSMG_LARROW_CHAR); 227 ui_browser__write_graph(browser, SLSMG_LARROW_CHAR);
228 SLsmg_write_char(' '); 228 SLsmg_write_char(' ');
229 } else { 229 } else {
@@ -243,7 +243,7 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int
243 243
244static bool disasm_line__is_valid_jump(struct disasm_line *dl, struct symbol *sym) 244static bool disasm_line__is_valid_jump(struct disasm_line *dl, struct symbol *sym)
245{ 245{
246 if (!dl || !dl->ins || !ins__is_jump(dl->ins) 246 if (!dl || !dl->ins.ops || !ins__is_jump(&dl->ins)
247 || !disasm_line__has_offset(dl) 247 || !disasm_line__has_offset(dl)
248 || dl->ops.target.offset >= symbol__size(sym)) 248 || dl->ops.target.offset >= symbol__size(sym))
249 return false; 249 return false;
@@ -492,7 +492,7 @@ static bool annotate_browser__callq(struct annotate_browser *browser,
492 }; 492 };
493 char title[SYM_TITLE_MAX_SIZE]; 493 char title[SYM_TITLE_MAX_SIZE];
494 494
495 if (!ins__is_call(dl->ins)) 495 if (!ins__is_call(&dl->ins))
496 return false; 496 return false;
497 497
498 if (map_groups__find_ams(&target) || 498 if (map_groups__find_ams(&target) ||
@@ -545,7 +545,7 @@ static bool annotate_browser__jump(struct annotate_browser *browser)
545 struct disasm_line *dl = browser->selection; 545 struct disasm_line *dl = browser->selection;
546 s64 idx; 546 s64 idx;
547 547
548 if (!ins__is_jump(dl->ins)) 548 if (!ins__is_jump(&dl->ins))
549 return false; 549 return false;
550 550
551 dl = annotate_browser__find_offset(browser, dl->ops.target.offset, &idx); 551 dl = annotate_browser__find_offset(browser, dl->ops.target.offset, &idx);
@@ -841,9 +841,9 @@ show_help:
841 ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org"); 841 ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
842 else if (browser->selection->offset == -1) 842 else if (browser->selection->offset == -1)
843 ui_helpline__puts("Actions are only available for assembly lines."); 843 ui_helpline__puts("Actions are only available for assembly lines.");
844 else if (!browser->selection->ins) 844 else if (!browser->selection->ins.ops)
845 goto show_sup_ins; 845 goto show_sup_ins;
846 else if (ins__is_ret(browser->selection->ins)) 846 else if (ins__is_ret(&browser->selection->ins))
847 goto out; 847 goto out;
848 else if (!(annotate_browser__jump(browser) || 848 else if (!(annotate_browser__jump(browser) ||
849 annotate_browser__callq(browser, evsel, hbt))) { 849 annotate_browser__callq(browser, evsel, hbt))) {
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index 095d90a9077f..3e34ee0fde28 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -28,14 +28,20 @@ const char *disassembler_style;
28const char *objdump_path; 28const char *objdump_path;
29static regex_t file_lineno; 29static regex_t file_lineno;
30 30
31static struct ins *ins__find(struct arch *arch, const char *name); 31static struct ins_ops *ins__find(struct arch *arch, const char *name);
32static int disasm_line__parse(char *line, char **namep, char **rawp); 32static void ins__sort(struct arch *arch);
33static int disasm_line__parse(char *line, const char **namep, char **rawp);
33 34
34struct arch { 35struct arch {
35 const char *name; 36 const char *name;
36 struct ins *instructions; 37 struct ins *instructions;
37 size_t nr_instructions; 38 size_t nr_instructions;
39 size_t nr_instructions_allocated;
40 struct ins_ops *(*associate_instruction_ops)(struct arch *arch, const char *name);
38 bool sorted_instructions; 41 bool sorted_instructions;
42 bool initialized;
43 void *priv;
44 int (*init)(struct arch *arch);
39 struct { 45 struct {
40 char comment_char; 46 char comment_char;
41 char skip_functions_char; 47 char skip_functions_char;
@@ -50,18 +56,62 @@ static struct ins_ops nop_ops;
50static struct ins_ops lock_ops; 56static struct ins_ops lock_ops;
51static struct ins_ops ret_ops; 57static struct ins_ops ret_ops;
52 58
59static int arch__grow_instructions(struct arch *arch)
60{
61 struct ins *new_instructions;
62 size_t new_nr_allocated;
63
64 if (arch->nr_instructions_allocated == 0 && arch->instructions)
65 goto grow_from_non_allocated_table;
66
67 new_nr_allocated = arch->nr_instructions_allocated + 128;
68 new_instructions = realloc(arch->instructions, new_nr_allocated * sizeof(struct ins));
69 if (new_instructions == NULL)
70 return -1;
71
72out_update_instructions:
73 arch->instructions = new_instructions;
74 arch->nr_instructions_allocated = new_nr_allocated;
75 return 0;
76
77grow_from_non_allocated_table:
78 new_nr_allocated = arch->nr_instructions + 128;
79 new_instructions = calloc(new_nr_allocated, sizeof(struct ins));
80 if (new_instructions == NULL)
81 return -1;
82
83 memcpy(new_instructions, arch->instructions, arch->nr_instructions);
84 goto out_update_instructions;
85}
86
87static int arch__associate_ins_ops(struct arch* arch, const char *name, struct ins_ops *ops)
88{
89 struct ins *ins;
90
91 if (arch->nr_instructions == arch->nr_instructions_allocated &&
92 arch__grow_instructions(arch))
93 return -1;
94
95 ins = &arch->instructions[arch->nr_instructions];
96 ins->name = strdup(name);
97 if (!ins->name)
98 return -1;
99
100 ins->ops = ops;
101 arch->nr_instructions++;
102
103 ins__sort(arch);
104 return 0;
105}
106
53#include "arch/arm/annotate/instructions.c" 107#include "arch/arm/annotate/instructions.c"
54#include "arch/x86/annotate/instructions.c" 108#include "arch/x86/annotate/instructions.c"
109#include "arch/powerpc/annotate/instructions.c"
55 110
56static struct arch architectures[] = { 111static struct arch architectures[] = {
57 { 112 {
58 .name = "arm", 113 .name = "arm",
59 .instructions = arm__instructions, 114 .init = arm__annotate_init,
60 .nr_instructions = ARRAY_SIZE(arm__instructions),
61 .objdump = {
62 .comment_char = ';',
63 .skip_functions_char = '+',
64 },
65 }, 115 },
66 { 116 {
67 .name = "x86", 117 .name = "x86",
@@ -71,6 +121,10 @@ static struct arch architectures[] = {
71 .comment_char = '#', 121 .comment_char = '#',
72 }, 122 },
73 }, 123 },
124 {
125 .name = "powerpc",
126 .init = powerpc__annotate_init,
127 },
74}; 128};
75 129
76static void ins__delete(struct ins_operands *ops) 130static void ins__delete(struct ins_operands *ops)
@@ -218,26 +272,20 @@ static int comment__symbol(char *raw, char *comment, u64 *addrp, char **namep)
218 272
219static int lock__parse(struct arch *arch, struct ins_operands *ops, struct map *map) 273static int lock__parse(struct arch *arch, struct ins_operands *ops, struct map *map)
220{ 274{
221 char *name;
222
223 ops->locked.ops = zalloc(sizeof(*ops->locked.ops)); 275 ops->locked.ops = zalloc(sizeof(*ops->locked.ops));
224 if (ops->locked.ops == NULL) 276 if (ops->locked.ops == NULL)
225 return 0; 277 return 0;
226 278
227 if (disasm_line__parse(ops->raw, &name, &ops->locked.ops->raw) < 0) 279 if (disasm_line__parse(ops->raw, &ops->locked.ins.name, &ops->locked.ops->raw) < 0)
228 goto out_free_ops; 280 goto out_free_ops;
229 281
230 ops->locked.ins = ins__find(arch, name); 282 ops->locked.ins.ops = ins__find(arch, ops->locked.ins.name);
231 free(name);
232 283
233 if (ops->locked.ins == NULL) 284 if (ops->locked.ins.ops == NULL)
234 goto out_free_ops; 285 goto out_free_ops;
235 286
236 if (!ops->locked.ins->ops) 287 if (ops->locked.ins.ops->parse &&
237 return 0; 288 ops->locked.ins.ops->parse(arch, ops->locked.ops, map) < 0)
238
239 if (ops->locked.ins->ops->parse &&
240 ops->locked.ins->ops->parse(arch, ops->locked.ops, map) < 0)
241 goto out_free_ops; 289 goto out_free_ops;
242 290
243 return 0; 291 return 0;
@@ -252,19 +300,19 @@ static int lock__scnprintf(struct ins *ins, char *bf, size_t size,
252{ 300{
253 int printed; 301 int printed;
254 302
255 if (ops->locked.ins == NULL) 303 if (ops->locked.ins.ops == NULL)
256 return ins__raw_scnprintf(ins, bf, size, ops); 304 return ins__raw_scnprintf(ins, bf, size, ops);
257 305
258 printed = scnprintf(bf, size, "%-6.6s ", ins->name); 306 printed = scnprintf(bf, size, "%-6.6s ", ins->name);
259 return printed + ins__scnprintf(ops->locked.ins, bf + printed, 307 return printed + ins__scnprintf(&ops->locked.ins, bf + printed,
260 size - printed, ops->locked.ops); 308 size - printed, ops->locked.ops);
261} 309}
262 310
263static void lock__delete(struct ins_operands *ops) 311static void lock__delete(struct ins_operands *ops)
264{ 312{
265 struct ins *ins = ops->locked.ins; 313 struct ins *ins = &ops->locked.ins;
266 314
267 if (ins && ins->ops->free) 315 if (ins->ops && ins->ops->free)
268 ins->ops->free(ops->locked.ops); 316 ins->ops->free(ops->locked.ops);
269 else 317 else
270 ins__delete(ops->locked.ops); 318 ins__delete(ops->locked.ops);
@@ -425,8 +473,9 @@ static void ins__sort(struct arch *arch)
425 qsort(arch->instructions, nmemb, sizeof(struct ins), ins__cmp); 473 qsort(arch->instructions, nmemb, sizeof(struct ins), ins__cmp);
426} 474}
427 475
428static struct ins *ins__find(struct arch *arch, const char *name) 476static struct ins_ops *__ins__find(struct arch *arch, const char *name)
429{ 477{
478 struct ins *ins;
430 const int nmemb = arch->nr_instructions; 479 const int nmemb = arch->nr_instructions;
431 480
432 if (!arch->sorted_instructions) { 481 if (!arch->sorted_instructions) {
@@ -434,7 +483,18 @@ static struct ins *ins__find(struct arch *arch, const char *name)
434 arch->sorted_instructions = true; 483 arch->sorted_instructions = true;
435 } 484 }
436 485
437 return bsearch(name, arch->instructions, nmemb, sizeof(struct ins), ins__key_cmp); 486 ins = bsearch(name, arch->instructions, nmemb, sizeof(struct ins), ins__key_cmp);
487 return ins ? ins->ops : NULL;
488}
489
490static struct ins_ops *ins__find(struct arch *arch, const char *name)
491{
492 struct ins_ops *ops = __ins__find(arch, name);
493
494 if (!ops && arch->associate_instruction_ops)
495 ops = arch->associate_instruction_ops(arch, name);
496
497 return ops;
438} 498}
439 499
440static int arch__key_cmp(const void *name, const void *archp) 500static int arch__key_cmp(const void *name, const void *archp)
@@ -691,19 +751,16 @@ int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 ip)
691 751
692static void disasm_line__init_ins(struct disasm_line *dl, struct arch *arch, struct map *map) 752static void disasm_line__init_ins(struct disasm_line *dl, struct arch *arch, struct map *map)
693{ 753{
694 dl->ins = ins__find(arch, dl->name); 754 dl->ins.ops = ins__find(arch, dl->ins.name);
695 755
696 if (dl->ins == NULL) 756 if (!dl->ins.ops)
697 return; 757 return;
698 758
699 if (!dl->ins->ops) 759 if (dl->ins.ops->parse && dl->ins.ops->parse(arch, &dl->ops, map) < 0)
700 return; 760 dl->ins.ops = NULL;
701
702 if (dl->ins->ops->parse && dl->ins->ops->parse(arch, &dl->ops, map) < 0)
703 dl->ins = NULL;
704} 761}
705 762
706static int disasm_line__parse(char *line, char **namep, char **rawp) 763static int disasm_line__parse(char *line, const char **namep, char **rawp)
707{ 764{
708 char *name = line, tmp; 765 char *name = line, tmp;
709 766
@@ -736,7 +793,8 @@ static int disasm_line__parse(char *line, char **namep, char **rawp)
736 return 0; 793 return 0;
737 794
738out_free_name: 795out_free_name:
739 zfree(namep); 796 free((void *)namep);
797 *namep = NULL;
740 return -1; 798 return -1;
741} 799}
742 800
@@ -755,7 +813,7 @@ static struct disasm_line *disasm_line__new(s64 offset, char *line,
755 goto out_delete; 813 goto out_delete;
756 814
757 if (offset != -1) { 815 if (offset != -1) {
758 if (disasm_line__parse(dl->line, &dl->name, &dl->ops.raw) < 0) 816 if (disasm_line__parse(dl->line, &dl->ins.name, &dl->ops.raw) < 0)
759 goto out_free_line; 817 goto out_free_line;
760 818
761 disasm_line__init_ins(dl, arch, map); 819 disasm_line__init_ins(dl, arch, map);
@@ -774,20 +832,21 @@ out_delete:
774void disasm_line__free(struct disasm_line *dl) 832void disasm_line__free(struct disasm_line *dl)
775{ 833{
776 zfree(&dl->line); 834 zfree(&dl->line);
777 zfree(&dl->name); 835 if (dl->ins.ops && dl->ins.ops->free)
778 if (dl->ins && dl->ins->ops->free) 836 dl->ins.ops->free(&dl->ops);
779 dl->ins->ops->free(&dl->ops);
780 else 837 else
781 ins__delete(&dl->ops); 838 ins__delete(&dl->ops);
839 free((void *)dl->ins.name);
840 dl->ins.name = NULL;
782 free(dl); 841 free(dl);
783} 842}
784 843
785int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw) 844int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw)
786{ 845{
787 if (raw || !dl->ins) 846 if (raw || !dl->ins.ops)
788 return scnprintf(bf, size, "%-6.6s %s", dl->name, dl->ops.raw); 847 return scnprintf(bf, size, "%-6.6s %s", dl->ins.name, dl->ops.raw);
789 848
790 return ins__scnprintf(dl->ins, bf, size, &dl->ops); 849 return ins__scnprintf(&dl->ins, bf, size, &dl->ops);
791} 850}
792 851
793static void disasm__add(struct list_head *head, struct disasm_line *line) 852static void disasm__add(struct list_head *head, struct disasm_line *line)
@@ -1143,7 +1202,7 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
1143 map__rip_2objdump(map, sym->start); 1202 map__rip_2objdump(map, sym->start);
1144 1203
1145 /* kcore has no symbols, so add the call target name */ 1204 /* kcore has no symbols, so add the call target name */
1146 if (dl->ins && ins__is_call(dl->ins) && !dl->ops.target.name) { 1205 if (dl->ins.ops && ins__is_call(&dl->ins) && !dl->ops.target.name) {
1147 struct addr_map_symbol target = { 1206 struct addr_map_symbol target = {
1148 .map = map, 1207 .map = map,
1149 .addr = dl->ops.target.addr, 1208 .addr = dl->ops.target.addr,
@@ -1173,8 +1232,8 @@ static void delete_last_nop(struct symbol *sym)
1173 while (!list_empty(list)) { 1232 while (!list_empty(list)) {
1174 dl = list_entry(list->prev, struct disasm_line, node); 1233 dl = list_entry(list->prev, struct disasm_line, node);
1175 1234
1176 if (dl->ins && dl->ins->ops) { 1235 if (dl->ins.ops) {
1177 if (dl->ins->ops != &nop_ops) 1236 if (dl->ins.ops != &nop_ops)
1178 return; 1237 return;
1179 } else { 1238 } else {
1180 if (!strstr(dl->line, " nop ") && 1239 if (!strstr(dl->line, " nop ") &&
@@ -1300,6 +1359,14 @@ int symbol__disassemble(struct symbol *sym, struct map *map, const char *arch_na
1300 if (arch == NULL) 1359 if (arch == NULL)
1301 return -ENOTSUP; 1360 return -ENOTSUP;
1302 1361
1362 if (arch->init) {
1363 err = arch->init(arch);
1364 if (err) {
1365 pr_err("%s: failed to initialize %s arch priv area\n", __func__, arch->name);
1366 return err;
1367 }
1368 }
1369
1303 pr_debug("%s: filename=%s, sym=%s, start=%#" PRIx64 ", end=%#" PRIx64 "\n", __func__, 1370 pr_debug("%s: filename=%s, sym=%s, start=%#" PRIx64 ", end=%#" PRIx64 "\n", __func__,
1304 symfs_filename, sym->name, map->unmap_ip(map, sym->start), 1371 symfs_filename, sym->name, map->unmap_ip(map, sym->start),
1305 map->unmap_ip(map, sym->end)); 1372 map->unmap_ip(map, sym->end));
@@ -1767,7 +1834,7 @@ static size_t disasm_line__fprintf(struct disasm_line *dl, FILE *fp)
1767 if (dl->offset == -1) 1834 if (dl->offset == -1)
1768 return fprintf(fp, "%s\n", dl->line); 1835 return fprintf(fp, "%s\n", dl->line);
1769 1836
1770 printed = fprintf(fp, "%#" PRIx64 " %s", dl->offset, dl->name); 1837 printed = fprintf(fp, "%#" PRIx64 " %s", dl->offset, dl->ins.name);
1771 1838
1772 if (dl->ops.raw[0] != '\0') { 1839 if (dl->ops.raw[0] != '\0') {
1773 printed += fprintf(fp, "%.*s %s\n", 6 - (int)printed, " ", 1840 printed += fprintf(fp, "%.*s %s\n", 6 - (int)printed, " ",
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h
index 8e490b5c91bc..87e4cadc5d27 100644
--- a/tools/perf/util/annotate.h
+++ b/tools/perf/util/annotate.h
@@ -11,7 +11,12 @@
11#include <linux/rbtree.h> 11#include <linux/rbtree.h>
12#include <pthread.h> 12#include <pthread.h>
13 13
14struct ins; 14struct ins_ops;
15
16struct ins {
17 const char *name;
18 struct ins_ops *ops;
19};
15 20
16struct ins_operands { 21struct ins_operands {
17 char *raw; 22 char *raw;
@@ -28,7 +33,7 @@ struct ins_operands {
28 u64 addr; 33 u64 addr;
29 } source; 34 } source;
30 struct { 35 struct {
31 struct ins *ins; 36 struct ins ins;
32 struct ins_operands *ops; 37 struct ins_operands *ops;
33 } locked; 38 } locked;
34 }; 39 };
@@ -43,11 +48,6 @@ struct ins_ops {
43 struct ins_operands *ops); 48 struct ins_operands *ops);
44}; 49};
45 50
46struct ins {
47 const char *name;
48 struct ins_ops *ops;
49};
50
51bool ins__is_jump(const struct ins *ins); 51bool ins__is_jump(const struct ins *ins);
52bool ins__is_call(const struct ins *ins); 52bool ins__is_call(const struct ins *ins);
53bool ins__is_ret(const struct ins *ins); 53bool ins__is_ret(const struct ins *ins);
@@ -59,8 +59,7 @@ struct disasm_line {
59 struct list_head node; 59 struct list_head node;
60 s64 offset; 60 s64 offset;
61 char *line; 61 char *line;
62 char *name; 62 struct ins ins;
63 struct ins *ins;
64 int line_nr; 63 int line_nr;
65 float ipc; 64 float ipc;
66 u64 cycles; 65 u64 cycles;
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 27fa3a343577..6abb89cd27f9 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -392,6 +392,7 @@ int perf_evsel__fprintf(struct perf_evsel *evsel,
392#define EVSEL__PRINT_SRCLINE (1<<5) 392#define EVSEL__PRINT_SRCLINE (1<<5)
393#define EVSEL__PRINT_UNKNOWN_AS_ADDR (1<<6) 393#define EVSEL__PRINT_UNKNOWN_AS_ADDR (1<<6)
394#define EVSEL__PRINT_CALLCHAIN_ARROW (1<<7) 394#define EVSEL__PRINT_CALLCHAIN_ARROW (1<<7)
395#define EVSEL__PRINT_SKIP_IGNORED (1<<8)
395 396
396struct callchain_cursor; 397struct callchain_cursor;
397 398
diff --git a/tools/perf/util/evsel_fprintf.c b/tools/perf/util/evsel_fprintf.c
index 53bb614feafb..5a6f52284452 100644
--- a/tools/perf/util/evsel_fprintf.c
+++ b/tools/perf/util/evsel_fprintf.c
@@ -109,6 +109,7 @@ int sample__fprintf_callchain(struct perf_sample *sample, int left_alignment,
109 int print_srcline = print_opts & EVSEL__PRINT_SRCLINE; 109 int print_srcline = print_opts & EVSEL__PRINT_SRCLINE;
110 int print_unknown_as_addr = print_opts & EVSEL__PRINT_UNKNOWN_AS_ADDR; 110 int print_unknown_as_addr = print_opts & EVSEL__PRINT_UNKNOWN_AS_ADDR;
111 int print_arrow = print_opts & EVSEL__PRINT_CALLCHAIN_ARROW; 111 int print_arrow = print_opts & EVSEL__PRINT_CALLCHAIN_ARROW;
112 int print_skip_ignored = print_opts & EVSEL__PRINT_SKIP_IGNORED;
112 char s = print_oneline ? ' ' : '\t'; 113 char s = print_oneline ? ' ' : '\t';
113 bool first = true; 114 bool first = true;
114 115
@@ -124,6 +125,9 @@ int sample__fprintf_callchain(struct perf_sample *sample, int left_alignment,
124 if (!node) 125 if (!node)
125 break; 126 break;
126 127
128 if (node->sym && node->sym->ignore && print_skip_ignored)
129 goto next;
130
127 printed += fprintf(fp, "%-*.*s", left_alignment, left_alignment, " "); 131 printed += fprintf(fp, "%-*.*s", left_alignment, left_alignment, " ");
128 132
129 if (print_arrow && !first) 133 if (print_arrow && !first)
@@ -162,8 +166,9 @@ int sample__fprintf_callchain(struct perf_sample *sample, int left_alignment,
162 if (!print_oneline) 166 if (!print_oneline)
163 printed += fprintf(fp, "\n"); 167 printed += fprintf(fp, "\n");
164 168
165 callchain_cursor_advance(cursor);
166 first = false; 169 first = false;
170next:
171 callchain_cursor_advance(cursor);
167 } 172 }
168 } 173 }
169 174
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index 8091d15113f7..5d4e94061402 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -18,6 +18,8 @@ struct probe_conf {
18extern struct probe_conf probe_conf; 18extern struct probe_conf probe_conf;
19extern bool probe_event_dry_run; 19extern bool probe_event_dry_run;
20 20
21struct symbol;
22
21/* kprobe-tracer and uprobe-tracer tracing point */ 23/* kprobe-tracer and uprobe-tracer tracing point */
22struct probe_trace_point { 24struct probe_trace_point {
23 char *realname; /* function real name (if needed) */ 25 char *realname; /* function real name (if needed) */
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index aecff69a510d..420ada9de22f 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -1962,7 +1962,7 @@ static bool symbol__read_kptr_restrict(void)
1962 char line[8]; 1962 char line[8];
1963 1963
1964 if (fgets(line, sizeof(line), fp) != NULL) 1964 if (fgets(line, sizeof(line), fp) != NULL)
1965 value = (geteuid() != 0) ? 1965 value = ((geteuid() != 0) || (getuid() != 0)) ?
1966 (atoi(line) != 0) : 1966 (atoi(line) != 0) :
1967 (atoi(line) == 2); 1967 (atoi(line) == 2);
1968 1968
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index dec7e2d44885..1bcbefc0c325 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -58,6 +58,7 @@ struct symbol {
58 u16 namelen; 58 u16 namelen;
59 u8 binding; 59 u8 binding;
60 u8 idle:1; 60 u8 idle:1;
61 u8 ignore:1;
61 u8 arch_sym; 62 u8 arch_sym;
62 char name[0]; 63 char name[0];
63}; 64};
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index 5bbd1f609f1f..67ac765da27a 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -637,12 +637,63 @@ bool find_process(const char *name)
637 return ret ? false : true; 637 return ret ? false : true;
638} 638}
639 639
640static int
641fetch_ubuntu_kernel_version(unsigned int *puint)
642{
643 ssize_t len;
644 size_t line_len = 0;
645 char *ptr, *line = NULL;
646 int version, patchlevel, sublevel, err;
647 FILE *vsig = fopen("/proc/version_signature", "r");
648
649 if (!vsig) {
650 pr_debug("Open /proc/version_signature failed: %s\n",
651 strerror(errno));
652 return -1;
653 }
654
655 len = getline(&line, &line_len, vsig);
656 fclose(vsig);
657 err = -1;
658 if (len <= 0) {
659 pr_debug("Reading from /proc/version_signature failed: %s\n",
660 strerror(errno));
661 goto errout;
662 }
663
664 ptr = strrchr(line, ' ');
665 if (!ptr) {
666 pr_debug("Parsing /proc/version_signature failed: %s\n", line);
667 goto errout;
668 }
669
670 err = sscanf(ptr + 1, "%d.%d.%d",
671 &version, &patchlevel, &sublevel);
672 if (err != 3) {
673 pr_debug("Unable to get kernel version from /proc/version_signature '%s'\n",
674 line);
675 goto errout;
676 }
677
678 if (puint)
679 *puint = (version << 16) + (patchlevel << 8) + sublevel;
680 err = 0;
681errout:
682 free(line);
683 return err;
684}
685
640int 686int
641fetch_kernel_version(unsigned int *puint, char *str, 687fetch_kernel_version(unsigned int *puint, char *str,
642 size_t str_size) 688 size_t str_size)
643{ 689{
644 struct utsname utsname; 690 struct utsname utsname;
645 int version, patchlevel, sublevel, err; 691 int version, patchlevel, sublevel, err;
692 bool int_ver_ready = false;
693
694 if (access("/proc/version_signature", R_OK) == 0)
695 if (!fetch_ubuntu_kernel_version(puint))
696 int_ver_ready = true;
646 697
647 if (uname(&utsname)) 698 if (uname(&utsname))
648 return -1; 699 return -1;
@@ -656,12 +707,12 @@ fetch_kernel_version(unsigned int *puint, char *str,
656 &version, &patchlevel, &sublevel); 707 &version, &patchlevel, &sublevel);
657 708
658 if (err != 3) { 709 if (err != 3) {
659 pr_debug("Unablt to get kernel version from uname '%s'\n", 710 pr_debug("Unable to get kernel version from uname '%s'\n",
660 utsname.release); 711 utsname.release);
661 return -1; 712 return -1;
662 } 713 }
663 714
664 if (puint) 715 if (puint && !int_ver_ready)
665 *puint = (version << 16) + (patchlevel << 8) + sublevel; 716 *puint = (version << 16) + (patchlevel << 8) + sublevel;
666 return 0; 717 return 0;
667} 718}