diff options
Diffstat (limited to 'tools/perf')
-rw-r--r-- | tools/perf/arch/powerpc/util/book3s_hv_exits.h | 1 | ||||
-rw-r--r-- | tools/perf/util/probe-event.c | 39 | ||||
-rw-r--r-- | tools/perf/util/probe-event.h | 1 | ||||
-rw-r--r-- | tools/perf/util/probe-file.c | 34 | ||||
-rw-r--r-- | tools/perf/util/probe-file.h | 1 | ||||
-rw-r--r-- | tools/perf/util/symbol-elf.c | 46 | ||||
-rw-r--r-- | tools/perf/util/symbol.h | 7 |
7 files changed, 106 insertions, 23 deletions
diff --git a/tools/perf/arch/powerpc/util/book3s_hv_exits.h b/tools/perf/arch/powerpc/util/book3s_hv_exits.h index 853b95d1e139..2011376c7ab5 100644 --- a/tools/perf/arch/powerpc/util/book3s_hv_exits.h +++ b/tools/perf/arch/powerpc/util/book3s_hv_exits.h | |||
@@ -15,7 +15,6 @@ | |||
15 | {0x400, "INST_STORAGE"}, \ | 15 | {0x400, "INST_STORAGE"}, \ |
16 | {0x480, "INST_SEGMENT"}, \ | 16 | {0x480, "INST_SEGMENT"}, \ |
17 | {0x500, "EXTERNAL"}, \ | 17 | {0x500, "EXTERNAL"}, \ |
18 | {0x501, "EXTERNAL_LEVEL"}, \ | ||
19 | {0x502, "EXTERNAL_HV"}, \ | 18 | {0x502, "EXTERNAL_HV"}, \ |
20 | {0x600, "ALIGNMENT"}, \ | 19 | {0x600, "ALIGNMENT"}, \ |
21 | {0x700, "PROGRAM"}, \ | 20 | {0x700, "PROGRAM"}, \ |
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index f119eb628dbb..e86f8be89157 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c | |||
@@ -1819,6 +1819,12 @@ int parse_probe_trace_command(const char *cmd, struct probe_trace_event *tev) | |||
1819 | tp->offset = strtoul(fmt2_str, NULL, 10); | 1819 | tp->offset = strtoul(fmt2_str, NULL, 10); |
1820 | } | 1820 | } |
1821 | 1821 | ||
1822 | if (tev->uprobes) { | ||
1823 | fmt2_str = strchr(p, '('); | ||
1824 | if (fmt2_str) | ||
1825 | tp->ref_ctr_offset = strtoul(fmt2_str + 1, NULL, 0); | ||
1826 | } | ||
1827 | |||
1822 | tev->nargs = argc - 2; | 1828 | tev->nargs = argc - 2; |
1823 | tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs); | 1829 | tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs); |
1824 | if (tev->args == NULL) { | 1830 | if (tev->args == NULL) { |
@@ -2012,6 +2018,22 @@ static int synthesize_probe_trace_arg(struct probe_trace_arg *arg, | |||
2012 | return err; | 2018 | return err; |
2013 | } | 2019 | } |
2014 | 2020 | ||
2021 | static int | ||
2022 | synthesize_uprobe_trace_def(struct probe_trace_event *tev, struct strbuf *buf) | ||
2023 | { | ||
2024 | struct probe_trace_point *tp = &tev->point; | ||
2025 | int err; | ||
2026 | |||
2027 | err = strbuf_addf(buf, "%s:0x%lx", tp->module, tp->address); | ||
2028 | |||
2029 | if (err >= 0 && tp->ref_ctr_offset) { | ||
2030 | if (!uprobe_ref_ctr_is_supported()) | ||
2031 | return -1; | ||
2032 | err = strbuf_addf(buf, "(0x%lx)", tp->ref_ctr_offset); | ||
2033 | } | ||
2034 | return err >= 0 ? 0 : -1; | ||
2035 | } | ||
2036 | |||
2015 | char *synthesize_probe_trace_command(struct probe_trace_event *tev) | 2037 | char *synthesize_probe_trace_command(struct probe_trace_event *tev) |
2016 | { | 2038 | { |
2017 | struct probe_trace_point *tp = &tev->point; | 2039 | struct probe_trace_point *tp = &tev->point; |
@@ -2041,15 +2063,17 @@ char *synthesize_probe_trace_command(struct probe_trace_event *tev) | |||
2041 | } | 2063 | } |
2042 | 2064 | ||
2043 | /* Use the tp->address for uprobes */ | 2065 | /* Use the tp->address for uprobes */ |
2044 | if (tev->uprobes) | 2066 | if (tev->uprobes) { |
2045 | err = strbuf_addf(&buf, "%s:0x%lx", tp->module, tp->address); | 2067 | err = synthesize_uprobe_trace_def(tev, &buf); |
2046 | else if (!strncmp(tp->symbol, "0x", 2)) | 2068 | } else if (!strncmp(tp->symbol, "0x", 2)) { |
2047 | /* Absolute address. See try_to_find_absolute_address() */ | 2069 | /* Absolute address. See try_to_find_absolute_address() */ |
2048 | err = strbuf_addf(&buf, "%s%s0x%lx", tp->module ?: "", | 2070 | err = strbuf_addf(&buf, "%s%s0x%lx", tp->module ?: "", |
2049 | tp->module ? ":" : "", tp->address); | 2071 | tp->module ? ":" : "", tp->address); |
2050 | else | 2072 | } else { |
2051 | err = strbuf_addf(&buf, "%s%s%s+%lu", tp->module ?: "", | 2073 | err = strbuf_addf(&buf, "%s%s%s+%lu", tp->module ?: "", |
2052 | tp->module ? ":" : "", tp->symbol, tp->offset); | 2074 | tp->module ? ":" : "", tp->symbol, tp->offset); |
2075 | } | ||
2076 | |||
2053 | if (err) | 2077 | if (err) |
2054 | goto error; | 2078 | goto error; |
2055 | 2079 | ||
@@ -2633,6 +2657,13 @@ static void warn_uprobe_event_compat(struct probe_trace_event *tev) | |||
2633 | { | 2657 | { |
2634 | int i; | 2658 | int i; |
2635 | char *buf = synthesize_probe_trace_command(tev); | 2659 | char *buf = synthesize_probe_trace_command(tev); |
2660 | struct probe_trace_point *tp = &tev->point; | ||
2661 | |||
2662 | if (tp->ref_ctr_offset && !uprobe_ref_ctr_is_supported()) { | ||
2663 | pr_warning("A semaphore is associated with %s:%s and " | ||
2664 | "seems your kernel doesn't support it.\n", | ||
2665 | tev->group, tev->event); | ||
2666 | } | ||
2636 | 2667 | ||
2637 | /* Old uprobe event doesn't support memory dereference */ | 2668 | /* Old uprobe event doesn't support memory dereference */ |
2638 | if (!tev->uprobes || tev->nargs == 0 || !buf) | 2669 | if (!tev->uprobes || tev->nargs == 0 || !buf) |
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h index 45b14f020558..15a98c3a2a2f 100644 --- a/tools/perf/util/probe-event.h +++ b/tools/perf/util/probe-event.h | |||
@@ -27,6 +27,7 @@ struct probe_trace_point { | |||
27 | char *symbol; /* Base symbol */ | 27 | char *symbol; /* Base symbol */ |
28 | char *module; /* Module name */ | 28 | char *module; /* Module name */ |
29 | unsigned long offset; /* Offset from symbol */ | 29 | unsigned long offset; /* Offset from symbol */ |
30 | unsigned long ref_ctr_offset; /* SDT reference counter offset */ | ||
30 | unsigned long address; /* Actual address of the trace point */ | 31 | unsigned long address; /* Actual address of the trace point */ |
31 | bool retprobe; /* Return probe flag */ | 32 | bool retprobe; /* Return probe flag */ |
32 | }; | 33 | }; |
diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c index b76088fadf3d..aac7817d9e14 100644 --- a/tools/perf/util/probe-file.c +++ b/tools/perf/util/probe-file.c | |||
@@ -696,8 +696,16 @@ out_err: | |||
696 | #ifdef HAVE_GELF_GETNOTE_SUPPORT | 696 | #ifdef HAVE_GELF_GETNOTE_SUPPORT |
697 | static unsigned long long sdt_note__get_addr(struct sdt_note *note) | 697 | static unsigned long long sdt_note__get_addr(struct sdt_note *note) |
698 | { | 698 | { |
699 | return note->bit32 ? (unsigned long long)note->addr.a32[0] | 699 | return note->bit32 ? |
700 | : (unsigned long long)note->addr.a64[0]; | 700 | (unsigned long long)note->addr.a32[SDT_NOTE_IDX_LOC] : |
701 | (unsigned long long)note->addr.a64[SDT_NOTE_IDX_LOC]; | ||
702 | } | ||
703 | |||
704 | static unsigned long long sdt_note__get_ref_ctr_offset(struct sdt_note *note) | ||
705 | { | ||
706 | return note->bit32 ? | ||
707 | (unsigned long long)note->addr.a32[SDT_NOTE_IDX_REFCTR] : | ||
708 | (unsigned long long)note->addr.a64[SDT_NOTE_IDX_REFCTR]; | ||
701 | } | 709 | } |
702 | 710 | ||
703 | static const char * const type_to_suffix[] = { | 711 | static const char * const type_to_suffix[] = { |
@@ -775,14 +783,21 @@ static char *synthesize_sdt_probe_command(struct sdt_note *note, | |||
775 | { | 783 | { |
776 | struct strbuf buf; | 784 | struct strbuf buf; |
777 | char *ret = NULL, **args; | 785 | char *ret = NULL, **args; |
778 | int i, args_count; | 786 | int i, args_count, err; |
787 | unsigned long long ref_ctr_offset; | ||
779 | 788 | ||
780 | if (strbuf_init(&buf, 32) < 0) | 789 | if (strbuf_init(&buf, 32) < 0) |
781 | return NULL; | 790 | return NULL; |
782 | 791 | ||
783 | if (strbuf_addf(&buf, "p:%s/%s %s:0x%llx", | 792 | err = strbuf_addf(&buf, "p:%s/%s %s:0x%llx", |
784 | sdtgrp, note->name, pathname, | 793 | sdtgrp, note->name, pathname, |
785 | sdt_note__get_addr(note)) < 0) | 794 | sdt_note__get_addr(note)); |
795 | |||
796 | ref_ctr_offset = sdt_note__get_ref_ctr_offset(note); | ||
797 | if (ref_ctr_offset && err >= 0) | ||
798 | err = strbuf_addf(&buf, "(0x%llx)", ref_ctr_offset); | ||
799 | |||
800 | if (err < 0) | ||
786 | goto error; | 801 | goto error; |
787 | 802 | ||
788 | if (!note->args) | 803 | if (!note->args) |
@@ -998,6 +1013,7 @@ int probe_cache__show_all_caches(struct strfilter *filter) | |||
998 | enum ftrace_readme { | 1013 | enum ftrace_readme { |
999 | FTRACE_README_PROBE_TYPE_X = 0, | 1014 | FTRACE_README_PROBE_TYPE_X = 0, |
1000 | FTRACE_README_KRETPROBE_OFFSET, | 1015 | FTRACE_README_KRETPROBE_OFFSET, |
1016 | FTRACE_README_UPROBE_REF_CTR, | ||
1001 | FTRACE_README_END, | 1017 | FTRACE_README_END, |
1002 | }; | 1018 | }; |
1003 | 1019 | ||
@@ -1009,6 +1025,7 @@ static struct { | |||
1009 | [idx] = {.pattern = pat, .avail = false} | 1025 | [idx] = {.pattern = pat, .avail = false} |
1010 | DEFINE_TYPE(FTRACE_README_PROBE_TYPE_X, "*type: * x8/16/32/64,*"), | 1026 | DEFINE_TYPE(FTRACE_README_PROBE_TYPE_X, "*type: * x8/16/32/64,*"), |
1011 | DEFINE_TYPE(FTRACE_README_KRETPROBE_OFFSET, "*place (kretprobe): *"), | 1027 | DEFINE_TYPE(FTRACE_README_KRETPROBE_OFFSET, "*place (kretprobe): *"), |
1028 | DEFINE_TYPE(FTRACE_README_UPROBE_REF_CTR, "*ref_ctr_offset*"), | ||
1012 | }; | 1029 | }; |
1013 | 1030 | ||
1014 | static bool scan_ftrace_readme(enum ftrace_readme type) | 1031 | static bool scan_ftrace_readme(enum ftrace_readme type) |
@@ -1064,3 +1081,8 @@ bool kretprobe_offset_is_supported(void) | |||
1064 | { | 1081 | { |
1065 | return scan_ftrace_readme(FTRACE_README_KRETPROBE_OFFSET); | 1082 | return scan_ftrace_readme(FTRACE_README_KRETPROBE_OFFSET); |
1066 | } | 1083 | } |
1084 | |||
1085 | bool uprobe_ref_ctr_is_supported(void) | ||
1086 | { | ||
1087 | return scan_ftrace_readme(FTRACE_README_UPROBE_REF_CTR); | ||
1088 | } | ||
diff --git a/tools/perf/util/probe-file.h b/tools/perf/util/probe-file.h index 63f29b1d22c1..2a249182f2a6 100644 --- a/tools/perf/util/probe-file.h +++ b/tools/perf/util/probe-file.h | |||
@@ -69,6 +69,7 @@ struct probe_cache_entry *probe_cache__find_by_name(struct probe_cache *pcache, | |||
69 | int probe_cache__show_all_caches(struct strfilter *filter); | 69 | int probe_cache__show_all_caches(struct strfilter *filter); |
70 | bool probe_type_is_available(enum probe_type type); | 70 | bool probe_type_is_available(enum probe_type type); |
71 | bool kretprobe_offset_is_supported(void); | 71 | bool kretprobe_offset_is_supported(void); |
72 | bool uprobe_ref_ctr_is_supported(void); | ||
72 | #else /* ! HAVE_LIBELF_SUPPORT */ | 73 | #else /* ! HAVE_LIBELF_SUPPORT */ |
73 | static inline struct probe_cache *probe_cache__new(const char *tgt __maybe_unused, struct nsinfo *nsi __maybe_unused) | 74 | static inline struct probe_cache *probe_cache__new(const char *tgt __maybe_unused, struct nsinfo *nsi __maybe_unused) |
74 | { | 75 | { |
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index 29770ea61768..0281d5e2cd67 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c | |||
@@ -1947,6 +1947,34 @@ void kcore_extract__delete(struct kcore_extract *kce) | |||
1947 | } | 1947 | } |
1948 | 1948 | ||
1949 | #ifdef HAVE_GELF_GETNOTE_SUPPORT | 1949 | #ifdef HAVE_GELF_GETNOTE_SUPPORT |
1950 | |||
1951 | static void sdt_adjust_loc(struct sdt_note *tmp, GElf_Addr base_off) | ||
1952 | { | ||
1953 | if (!base_off) | ||
1954 | return; | ||
1955 | |||
1956 | if (tmp->bit32) | ||
1957 | tmp->addr.a32[SDT_NOTE_IDX_LOC] = | ||
1958 | tmp->addr.a32[SDT_NOTE_IDX_LOC] + base_off - | ||
1959 | tmp->addr.a32[SDT_NOTE_IDX_BASE]; | ||
1960 | else | ||
1961 | tmp->addr.a64[SDT_NOTE_IDX_LOC] = | ||
1962 | tmp->addr.a64[SDT_NOTE_IDX_LOC] + base_off - | ||
1963 | tmp->addr.a64[SDT_NOTE_IDX_BASE]; | ||
1964 | } | ||
1965 | |||
1966 | static void sdt_adjust_refctr(struct sdt_note *tmp, GElf_Addr base_addr, | ||
1967 | GElf_Addr base_off) | ||
1968 | { | ||
1969 | if (!base_off) | ||
1970 | return; | ||
1971 | |||
1972 | if (tmp->bit32 && tmp->addr.a32[SDT_NOTE_IDX_REFCTR]) | ||
1973 | tmp->addr.a32[SDT_NOTE_IDX_REFCTR] -= (base_addr - base_off); | ||
1974 | else if (tmp->addr.a64[SDT_NOTE_IDX_REFCTR]) | ||
1975 | tmp->addr.a64[SDT_NOTE_IDX_REFCTR] -= (base_addr - base_off); | ||
1976 | } | ||
1977 | |||
1950 | /** | 1978 | /** |
1951 | * populate_sdt_note : Parse raw data and identify SDT note | 1979 | * populate_sdt_note : Parse raw data and identify SDT note |
1952 | * @elf: elf of the opened file | 1980 | * @elf: elf of the opened file |
@@ -1964,7 +1992,6 @@ static int populate_sdt_note(Elf **elf, const char *data, size_t len, | |||
1964 | const char *provider, *name, *args; | 1992 | const char *provider, *name, *args; |
1965 | struct sdt_note *tmp = NULL; | 1993 | struct sdt_note *tmp = NULL; |
1966 | GElf_Ehdr ehdr; | 1994 | GElf_Ehdr ehdr; |
1967 | GElf_Addr base_off = 0; | ||
1968 | GElf_Shdr shdr; | 1995 | GElf_Shdr shdr; |
1969 | int ret = -EINVAL; | 1996 | int ret = -EINVAL; |
1970 | 1997 | ||
@@ -2060,17 +2087,12 @@ static int populate_sdt_note(Elf **elf, const char *data, size_t len, | |||
2060 | * base address in the description of the SDT note. If its different, | 2087 | * base address in the description of the SDT note. If its different, |
2061 | * then accordingly, adjust the note location. | 2088 | * then accordingly, adjust the note location. |
2062 | */ | 2089 | */ |
2063 | if (elf_section_by_name(*elf, &ehdr, &shdr, SDT_BASE_SCN, NULL)) { | 2090 | if (elf_section_by_name(*elf, &ehdr, &shdr, SDT_BASE_SCN, NULL)) |
2064 | base_off = shdr.sh_offset; | 2091 | sdt_adjust_loc(tmp, shdr.sh_offset); |
2065 | if (base_off) { | 2092 | |
2066 | if (tmp->bit32) | 2093 | /* Adjust reference counter offset */ |
2067 | tmp->addr.a32[0] = tmp->addr.a32[0] + base_off - | 2094 | if (elf_section_by_name(*elf, &ehdr, &shdr, SDT_PROBES_SCN, NULL)) |
2068 | tmp->addr.a32[1]; | 2095 | sdt_adjust_refctr(tmp, shdr.sh_addr, shdr.sh_offset); |
2069 | else | ||
2070 | tmp->addr.a64[0] = tmp->addr.a64[0] + base_off - | ||
2071 | tmp->addr.a64[1]; | ||
2072 | } | ||
2073 | } | ||
2074 | 2096 | ||
2075 | list_add_tail(&tmp->note_list, sdt_notes); | 2097 | list_add_tail(&tmp->note_list, sdt_notes); |
2076 | return 0; | 2098 | return 0; |
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index f25fae4b5743..20f49779116b 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h | |||
@@ -379,12 +379,19 @@ int get_sdt_note_list(struct list_head *head, const char *target); | |||
379 | int cleanup_sdt_note_list(struct list_head *sdt_notes); | 379 | int cleanup_sdt_note_list(struct list_head *sdt_notes); |
380 | int sdt_notes__get_count(struct list_head *start); | 380 | int sdt_notes__get_count(struct list_head *start); |
381 | 381 | ||
382 | #define SDT_PROBES_SCN ".probes" | ||
382 | #define SDT_BASE_SCN ".stapsdt.base" | 383 | #define SDT_BASE_SCN ".stapsdt.base" |
383 | #define SDT_NOTE_SCN ".note.stapsdt" | 384 | #define SDT_NOTE_SCN ".note.stapsdt" |
384 | #define SDT_NOTE_TYPE 3 | 385 | #define SDT_NOTE_TYPE 3 |
385 | #define SDT_NOTE_NAME "stapsdt" | 386 | #define SDT_NOTE_NAME "stapsdt" |
386 | #define NR_ADDR 3 | 387 | #define NR_ADDR 3 |
387 | 388 | ||
389 | enum { | ||
390 | SDT_NOTE_IDX_LOC = 0, | ||
391 | SDT_NOTE_IDX_BASE, | ||
392 | SDT_NOTE_IDX_REFCTR, | ||
393 | }; | ||
394 | |||
388 | struct mem_info *mem_info__new(void); | 395 | struct mem_info *mem_info__new(void); |
389 | struct mem_info *mem_info__get(struct mem_info *mi); | 396 | struct mem_info *mem_info__get(struct mem_info *mi); |
390 | void mem_info__put(struct mem_info *mi); | 397 | void mem_info__put(struct mem_info *mi); |