diff options
author | Ingo Molnar <mingo@kernel.org> | 2016-07-14 02:54:13 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2016-07-14 02:54:13 -0400 |
commit | b29c6574699dc475da5dbff8db19297b203aacce (patch) | |
tree | 688462638604b4d4c405dbf5a9a699bad52c6d9a /tools/perf | |
parent | 7b39cafb7aa68ef8e32a9f51fbe737d96084ca74 (diff) | |
parent | 8e5dc848356ecf6ea8d27d641c4d7ad8d42fe92b (diff) |
Merge tag 'perf-core-for-mingo-20160713' 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:
User visible changes:
- Finish merging initial SDT (Statically Defined Traces) support, see
cset comments for details about how it all works (Masami Hiramatsu)
- Support attaching eBPF programs to tracepoints (Wang Nan)
Infrastructure changes:
- Fix up BITS_PER_LONG setting (Arnaldo Carvalho de Melo)
- Add fallback from ELF_C_READ_MMAP to ELF_C_READ in objtool, fixing
the build in libelf implementations lacking that elf_begin() cmd,
such as Alpine Linux's (Arnaldo Carvalho de Melo)
- Avoid checking code drift on busybox's diff in objtool (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/perf')
-rw-r--r-- | tools/perf/Documentation/perf-probe.txt | 11 | ||||
-rw-r--r-- | tools/perf/Makefile.perf | 3 | ||||
-rw-r--r-- | tools/perf/builtin-list.c | 6 | ||||
-rw-r--r-- | tools/perf/builtin-probe.c | 2 | ||||
-rw-r--r-- | tools/perf/config/Makefile | 10 | ||||
-rw-r--r-- | tools/perf/tests/Build | 1 | ||||
-rw-r--r-- | tools/perf/tests/builtin-test.c | 4 | ||||
-rw-r--r-- | tools/perf/tests/make | 3 | ||||
-rw-r--r-- | tools/perf/tests/sdt.c | 115 | ||||
-rw-r--r-- | tools/perf/tests/tests.h | 1 | ||||
-rw-r--r-- | tools/perf/util/bpf-loader.c | 73 | ||||
-rw-r--r-- | tools/perf/util/bpf-loader.h | 12 | ||||
-rw-r--r-- | tools/perf/util/build-id.c | 76 | ||||
-rw-r--r-- | tools/perf/util/build-id.h | 3 | ||||
-rw-r--r-- | tools/perf/util/parse-events.c | 110 | ||||
-rw-r--r-- | tools/perf/util/parse-events.h | 4 | ||||
-rw-r--r-- | tools/perf/util/probe-event.c | 309 | ||||
-rw-r--r-- | tools/perf/util/probe-event.h | 1 | ||||
-rw-r--r-- | tools/perf/util/probe-file.c | 57 | ||||
-rw-r--r-- | tools/perf/util/probe-file.h | 14 |
20 files changed, 725 insertions, 90 deletions
diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt index 7a258e953252..736da44596e4 100644 --- a/tools/perf/Documentation/perf-probe.txt +++ b/tools/perf/Documentation/perf-probe.txt | |||
@@ -151,6 +151,10 @@ Probe points are defined by following syntax. | |||
151 | 3) Define event based on source file with lazy pattern | 151 | 3) Define event based on source file with lazy pattern |
152 | [[GROUP:]EVENT=]SRC;PTN [ARG ...] | 152 | [[GROUP:]EVENT=]SRC;PTN [ARG ...] |
153 | 153 | ||
154 | 4) Pre-defined SDT events or cached event with name | ||
155 | %[sdt_PROVIDER:]SDTEVENT | ||
156 | or, | ||
157 | sdt_PROVIDER:SDTEVENT | ||
154 | 158 | ||
155 | 'EVENT' specifies the name of new event, if omitted, it will be set the name of the probed function. You can also specify a group name by 'GROUP', if omitted, set 'probe' is used for kprobe and 'probe_<bin>' is used for uprobe. | 159 | 'EVENT' specifies the name of new event, if omitted, it will be set the name of the probed function. You can also specify a group name by 'GROUP', if omitted, set 'probe' is used for kprobe and 'probe_<bin>' is used for uprobe. |
156 | Note that using existing group name can conflict with other events. Especially, using the group name reserved for kernel modules can hide embedded events in the | 160 | Note that using existing group name can conflict with other events. Especially, using the group name reserved for kernel modules can hide embedded events in the |
@@ -158,6 +162,11 @@ modules. | |||
158 | 'FUNC' specifies a probed function name, and it may have one of the following options; '+OFFS' is the offset from function entry address in bytes, ':RLN' is the relative-line number from function entry line, and '%return' means that it probes function return. And ';PTN' means lazy matching pattern (see LAZY MATCHING). Note that ';PTN' must be the end of the probe point definition. In addition, '@SRC' specifies a source file which has that function. | 162 | 'FUNC' specifies a probed function name, and it may have one of the following options; '+OFFS' is the offset from function entry address in bytes, ':RLN' is the relative-line number from function entry line, and '%return' means that it probes function return. And ';PTN' means lazy matching pattern (see LAZY MATCHING). Note that ';PTN' must be the end of the probe point definition. In addition, '@SRC' specifies a source file which has that function. |
159 | It is also possible to specify a probe point by the source line number or lazy matching by using 'SRC:ALN' or 'SRC;PTN' syntax, where 'SRC' is the source file path, ':ALN' is the line number and ';PTN' is the lazy matching pattern. | 163 | It is also possible to specify a probe point by the source line number or lazy matching by using 'SRC:ALN' or 'SRC;PTN' syntax, where 'SRC' is the source file path, ':ALN' is the line number and ';PTN' is the lazy matching pattern. |
160 | 'ARG' specifies the arguments of this probe point, (see PROBE ARGUMENT). | 164 | 'ARG' specifies the arguments of this probe point, (see PROBE ARGUMENT). |
165 | 'SDTEVENT' and 'PROVIDER' is the pre-defined event name which is defined by user SDT (Statically Defined Tracing) or the pre-cached probes with event name. | ||
166 | Note that before using the SDT event, the target binary (on which SDT events are defined) must be scanned by linkperf:perf-buildid-cache[1] to make SDT events as cached events. | ||
167 | |||
168 | For details of the SDT, see below. | ||
169 | https://sourceware.org/gdb/onlinedocs/gdb/Static-Probe-Points.html | ||
161 | 170 | ||
162 | PROBE ARGUMENT | 171 | PROBE ARGUMENT |
163 | -------------- | 172 | -------------- |
@@ -237,4 +246,4 @@ Add probes at malloc() function on libc | |||
237 | 246 | ||
238 | SEE ALSO | 247 | SEE ALSO |
239 | -------- | 248 | -------- |
240 | linkperf:perf-trace[1], linkperf:perf-record[1] | 249 | linkperf:perf-trace[1], linkperf:perf-record[1], linkperf:perf-buildid-cache[1] |
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index feb2c66b110b..a129fbc1ed37 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf | |||
@@ -81,6 +81,9 @@ include ../scripts/utilities.mak | |||
81 | # | 81 | # |
82 | # Define NO_LIBBPF if you do not want BPF support | 82 | # Define NO_LIBBPF if you do not want BPF support |
83 | # | 83 | # |
84 | # Define NO_SDT if you do not want to define SDT event in perf tools, | ||
85 | # note that it doesn't disable SDT scanning support. | ||
86 | # | ||
84 | # Define FEATURES_DUMP to provide features detection dump file | 87 | # Define FEATURES_DUMP to provide features detection dump file |
85 | # and bypass the feature detection | 88 | # and bypass the feature detection |
86 | 89 | ||
diff --git a/tools/perf/builtin-list.c b/tools/perf/builtin-list.c index 5e22db4684b8..88ee419e5189 100644 --- a/tools/perf/builtin-list.c +++ b/tools/perf/builtin-list.c | |||
@@ -25,7 +25,7 @@ int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused) | |||
25 | OPT_END() | 25 | OPT_END() |
26 | }; | 26 | }; |
27 | const char * const list_usage[] = { | 27 | const char * const list_usage[] = { |
28 | "perf list [hw|sw|cache|tracepoint|pmu|event_glob]", | 28 | "perf list [hw|sw|cache|tracepoint|pmu|sdt|event_glob]", |
29 | NULL | 29 | NULL |
30 | }; | 30 | }; |
31 | 31 | ||
@@ -62,6 +62,8 @@ int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused) | |||
62 | print_hwcache_events(NULL, raw_dump); | 62 | print_hwcache_events(NULL, raw_dump); |
63 | else if (strcmp(argv[i], "pmu") == 0) | 63 | else if (strcmp(argv[i], "pmu") == 0) |
64 | print_pmu_events(NULL, raw_dump); | 64 | print_pmu_events(NULL, raw_dump); |
65 | else if (strcmp(argv[i], "sdt") == 0) | ||
66 | print_sdt_events(NULL, NULL, raw_dump); | ||
65 | else if ((sep = strchr(argv[i], ':')) != NULL) { | 67 | else if ((sep = strchr(argv[i], ':')) != NULL) { |
66 | int sep_idx; | 68 | int sep_idx; |
67 | 69 | ||
@@ -76,6 +78,7 @@ int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused) | |||
76 | 78 | ||
77 | s[sep_idx] = '\0'; | 79 | s[sep_idx] = '\0'; |
78 | print_tracepoint_events(s, s + sep_idx + 1, raw_dump); | 80 | print_tracepoint_events(s, s + sep_idx + 1, raw_dump); |
81 | print_sdt_events(s, s + sep_idx + 1, raw_dump); | ||
79 | free(s); | 82 | free(s); |
80 | } else { | 83 | } else { |
81 | if (asprintf(&s, "*%s*", argv[i]) < 0) { | 84 | if (asprintf(&s, "*%s*", argv[i]) < 0) { |
@@ -89,6 +92,7 @@ int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused) | |||
89 | print_hwcache_events(s, raw_dump); | 92 | print_hwcache_events(s, raw_dump); |
90 | print_pmu_events(s, raw_dump); | 93 | print_pmu_events(s, raw_dump); |
91 | print_tracepoint_events(NULL, s, raw_dump); | 94 | print_tracepoint_events(NULL, s, raw_dump); |
95 | print_sdt_events(NULL, s, raw_dump); | ||
92 | free(s); | 96 | free(s); |
93 | } | 97 | } |
94 | } | 98 | } |
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index c6d890ad2c1a..ee5b42173ba3 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c | |||
@@ -370,7 +370,7 @@ static int del_perf_probe_caches(struct strfilter *filter) | |||
370 | struct str_node *nd; | 370 | struct str_node *nd; |
371 | int ret; | 371 | int ret; |
372 | 372 | ||
373 | bidlist = build_id_cache__list_all(); | 373 | bidlist = build_id_cache__list_all(false); |
374 | if (!bidlist) { | 374 | if (!bidlist) { |
375 | ret = -errno; | 375 | ret = -errno; |
376 | pr_debug("Failed to get buildids: %d\n", ret); | 376 | pr_debug("Failed to get buildids: %d\n", ret); |
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index 5ac428060779..24803c58049a 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile | |||
@@ -355,6 +355,16 @@ ifndef NO_LIBELF | |||
355 | endif # NO_LIBBPF | 355 | endif # NO_LIBBPF |
356 | endif # NO_LIBELF | 356 | endif # NO_LIBELF |
357 | 357 | ||
358 | ifndef NO_SDT | ||
359 | ifneq ($(feature-sdt), 1) | ||
360 | msg := $(warning No sys/sdt.h found, no SDT events are defined, please install systemtap-sdt-devel or systemtap-sdt-dev); | ||
361 | NO_SDT := 1; | ||
362 | else | ||
363 | CFLAGS += -DHAVE_SDT_EVENT | ||
364 | $(call detected,CONFIG_SDT_EVENT) | ||
365 | endif | ||
366 | endif | ||
367 | |||
358 | ifdef PERF_HAVE_JITDUMP | 368 | ifdef PERF_HAVE_JITDUMP |
359 | ifndef NO_DWARF | 369 | ifndef NO_DWARF |
360 | $(call detected,CONFIG_JITDUMP) | 370 | $(call detected,CONFIG_JITDUMP) |
diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build index 66a28982547b..4158422cc2a6 100644 --- a/tools/perf/tests/Build +++ b/tools/perf/tests/Build | |||
@@ -39,6 +39,7 @@ perf-y += stat.o | |||
39 | perf-y += event_update.o | 39 | perf-y += event_update.o |
40 | perf-y += event-times.o | 40 | perf-y += event-times.o |
41 | perf-y += backward-ring-buffer.o | 41 | perf-y += backward-ring-buffer.o |
42 | perf-y += sdt.o | ||
42 | 43 | ||
43 | $(OUTPUT)tests/llvm-src-base.c: tests/bpf-script-example.c tests/Build | 44 | $(OUTPUT)tests/llvm-src-base.c: tests/bpf-script-example.c tests/Build |
44 | $(call rule_mkdir) | 45 | $(call rule_mkdir) |
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index c23cbf733549..4dd2d050788a 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c | |||
@@ -218,6 +218,10 @@ static struct test generic_tests[] = { | |||
218 | .func = test__cpu_map_print, | 218 | .func = test__cpu_map_print, |
219 | }, | 219 | }, |
220 | { | 220 | { |
221 | .desc = "Test SDT event probing", | ||
222 | .func = test__sdt_event, | ||
223 | }, | ||
224 | { | ||
221 | .func = NULL, | 225 | .func = NULL, |
222 | }, | 226 | }, |
223 | }; | 227 | }; |
diff --git a/tools/perf/tests/make b/tools/perf/tests/make index 51966d92fc82..143f4d549769 100644 --- a/tools/perf/tests/make +++ b/tools/perf/tests/make | |||
@@ -82,6 +82,7 @@ make_no_auxtrace := NO_AUXTRACE=1 | |||
82 | make_no_libbpf := NO_LIBBPF=1 | 82 | make_no_libbpf := NO_LIBBPF=1 |
83 | make_no_libcrypto := NO_LIBCRYPTO=1 | 83 | make_no_libcrypto := NO_LIBCRYPTO=1 |
84 | make_with_babeltrace:= LIBBABELTRACE=1 | 84 | make_with_babeltrace:= LIBBABELTRACE=1 |
85 | make_no_sdt := NO_SDT=1 | ||
85 | make_tags := tags | 86 | make_tags := tags |
86 | make_cscope := cscope | 87 | make_cscope := cscope |
87 | make_help := help | 88 | make_help := help |
@@ -105,7 +106,7 @@ make_minimal := NO_LIBPERL=1 NO_LIBPYTHON=1 NO_NEWT=1 NO_GTK2=1 | |||
105 | make_minimal += NO_DEMANGLE=1 NO_LIBELF=1 NO_LIBUNWIND=1 NO_BACKTRACE=1 | 106 | make_minimal += NO_DEMANGLE=1 NO_LIBELF=1 NO_LIBUNWIND=1 NO_BACKTRACE=1 |
106 | make_minimal += NO_LIBNUMA=1 NO_LIBAUDIT=1 NO_LIBBIONIC=1 | 107 | make_minimal += NO_LIBNUMA=1 NO_LIBAUDIT=1 NO_LIBBIONIC=1 |
107 | make_minimal += NO_LIBDW_DWARF_UNWIND=1 NO_AUXTRACE=1 NO_LIBBPF=1 | 108 | make_minimal += NO_LIBDW_DWARF_UNWIND=1 NO_AUXTRACE=1 NO_LIBBPF=1 |
108 | make_minimal += NO_LIBCRYPTO=1 | 109 | make_minimal += NO_LIBCRYPTO=1 NO_SDT=1 |
109 | 110 | ||
110 | # $(run) contains all available tests | 111 | # $(run) contains all available tests |
111 | run := make_pure | 112 | run := make_pure |
diff --git a/tools/perf/tests/sdt.c b/tools/perf/tests/sdt.c new file mode 100644 index 000000000000..f59d210e1baf --- /dev/null +++ b/tools/perf/tests/sdt.c | |||
@@ -0,0 +1,115 @@ | |||
1 | #include <stdio.h> | ||
2 | #include <sys/epoll.h> | ||
3 | #include <util/util.h> | ||
4 | #include <util/evlist.h> | ||
5 | #include <linux/filter.h> | ||
6 | #include "tests.h" | ||
7 | #include "debug.h" | ||
8 | #include "probe-file.h" | ||
9 | #include "build-id.h" | ||
10 | |||
11 | /* To test SDT event, we need libelf support to scan elf binary */ | ||
12 | #if defined(HAVE_SDT_EVENT) && defined(HAVE_LIBELF_SUPPORT) | ||
13 | |||
14 | #include <sys/sdt.h> | ||
15 | |||
16 | static int target_function(void) | ||
17 | { | ||
18 | DTRACE_PROBE(perf, test_target); | ||
19 | return TEST_OK; | ||
20 | } | ||
21 | |||
22 | /* Copied from builtin-buildid-cache.c */ | ||
23 | static int build_id_cache__add_file(const char *filename) | ||
24 | { | ||
25 | char sbuild_id[SBUILD_ID_SIZE]; | ||
26 | u8 build_id[BUILD_ID_SIZE]; | ||
27 | int err; | ||
28 | |||
29 | err = filename__read_build_id(filename, &build_id, sizeof(build_id)); | ||
30 | if (err < 0) { | ||
31 | pr_debug("Failed to read build id of %s\n", filename); | ||
32 | return err; | ||
33 | } | ||
34 | |||
35 | build_id__sprintf(build_id, sizeof(build_id), sbuild_id); | ||
36 | err = build_id_cache__add_s(sbuild_id, filename, false, false); | ||
37 | if (err < 0) | ||
38 | pr_debug("Failed to add build id cache of %s\n", filename); | ||
39 | return err; | ||
40 | } | ||
41 | |||
42 | static char *get_self_path(void) | ||
43 | { | ||
44 | char *buf = calloc(PATH_MAX, sizeof(char)); | ||
45 | |||
46 | if (buf && readlink("/proc/self/exe", buf, PATH_MAX) < 0) { | ||
47 | pr_debug("Failed to get correct path of perf\n"); | ||
48 | free(buf); | ||
49 | return NULL; | ||
50 | } | ||
51 | return buf; | ||
52 | } | ||
53 | |||
54 | static int search_cached_probe(const char *target, | ||
55 | const char *group, const char *event) | ||
56 | { | ||
57 | struct probe_cache *cache = probe_cache__new(target); | ||
58 | int ret = 0; | ||
59 | |||
60 | if (!cache) { | ||
61 | pr_debug("Failed to open probe cache of %s\n", target); | ||
62 | return -EINVAL; | ||
63 | } | ||
64 | |||
65 | if (!probe_cache__find_by_name(cache, group, event)) { | ||
66 | pr_debug("Failed to find %s:%s in the cache\n", group, event); | ||
67 | ret = -ENOENT; | ||
68 | } | ||
69 | probe_cache__delete(cache); | ||
70 | |||
71 | return ret; | ||
72 | } | ||
73 | |||
74 | int test__sdt_event(int subtests __maybe_unused) | ||
75 | { | ||
76 | int ret = TEST_FAIL; | ||
77 | char __tempdir[] = "./test-buildid-XXXXXX"; | ||
78 | char *tempdir = NULL, *myself = get_self_path(); | ||
79 | |||
80 | if (myself == NULL || mkdtemp(__tempdir) == NULL) { | ||
81 | pr_debug("Failed to make a tempdir for build-id cache\n"); | ||
82 | goto error; | ||
83 | } | ||
84 | /* Note that buildid_dir must be an absolute path */ | ||
85 | tempdir = realpath(__tempdir, NULL); | ||
86 | |||
87 | /* At first, scan itself */ | ||
88 | set_buildid_dir(tempdir); | ||
89 | if (build_id_cache__add_file(myself) < 0) | ||
90 | goto error_rmdir; | ||
91 | |||
92 | /* Open a cache and make sure the SDT is stored */ | ||
93 | if (search_cached_probe(myself, "sdt_perf", "test_target") < 0) | ||
94 | goto error_rmdir; | ||
95 | |||
96 | /* TBD: probing on the SDT event and collect logs */ | ||
97 | |||
98 | /* Call the target and get an event */ | ||
99 | ret = target_function(); | ||
100 | |||
101 | error_rmdir: | ||
102 | /* Cleanup temporary buildid dir */ | ||
103 | rm_rf(tempdir); | ||
104 | error: | ||
105 | free(tempdir); | ||
106 | free(myself); | ||
107 | return ret; | ||
108 | } | ||
109 | #else | ||
110 | int test__sdt_event(int subtests __maybe_unused) | ||
111 | { | ||
112 | pr_debug("Skip SDT event test because SDT support is not compiled\n"); | ||
113 | return TEST_SKIP; | ||
114 | } | ||
115 | #endif | ||
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h index 52f969570c97..a0288f8092b2 100644 --- a/tools/perf/tests/tests.h +++ b/tools/perf/tests/tests.h | |||
@@ -88,6 +88,7 @@ int test__event_update(int subtest); | |||
88 | int test__event_times(int subtest); | 88 | int test__event_times(int subtest); |
89 | int test__backward_ring_buffer(int subtest); | 89 | int test__backward_ring_buffer(int subtest); |
90 | int test__cpu_map_print(int subtest); | 90 | int test__cpu_map_print(int subtest); |
91 | int test__sdt_event(int subtest); | ||
91 | 92 | ||
92 | #if defined(__arm__) || defined(__aarch64__) | 93 | #if defined(__arm__) || defined(__aarch64__) |
93 | #ifdef HAVE_DWARF_UNWIND_SUPPORT | 94 | #ifdef HAVE_DWARF_UNWIND_SUPPORT |
diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c index 8445e89621fe..1f12e4e40006 100644 --- a/tools/perf/util/bpf-loader.c +++ b/tools/perf/util/bpf-loader.c | |||
@@ -37,6 +37,9 @@ DEFINE_PRINT_FN(info, 1) | |||
37 | DEFINE_PRINT_FN(debug, 1) | 37 | DEFINE_PRINT_FN(debug, 1) |
38 | 38 | ||
39 | struct bpf_prog_priv { | 39 | struct bpf_prog_priv { |
40 | bool is_tp; | ||
41 | char *sys_name; | ||
42 | char *evt_name; | ||
40 | struct perf_probe_event pev; | 43 | struct perf_probe_event pev; |
41 | bool need_prologue; | 44 | bool need_prologue; |
42 | struct bpf_insn *insns_buf; | 45 | struct bpf_insn *insns_buf; |
@@ -118,6 +121,8 @@ clear_prog_priv(struct bpf_program *prog __maybe_unused, | |||
118 | cleanup_perf_probe_events(&priv->pev, 1); | 121 | cleanup_perf_probe_events(&priv->pev, 1); |
119 | zfree(&priv->insns_buf); | 122 | zfree(&priv->insns_buf); |
120 | zfree(&priv->type_mapping); | 123 | zfree(&priv->type_mapping); |
124 | zfree(&priv->sys_name); | ||
125 | zfree(&priv->evt_name); | ||
121 | free(priv); | 126 | free(priv); |
122 | } | 127 | } |
123 | 128 | ||
@@ -269,7 +274,8 @@ nextline: | |||
269 | } | 274 | } |
270 | 275 | ||
271 | static int | 276 | static int |
272 | parse_prog_config(const char *config_str, struct perf_probe_event *pev) | 277 | parse_prog_config(const char *config_str, const char **p_main_str, |
278 | bool *is_tp, struct perf_probe_event *pev) | ||
273 | { | 279 | { |
274 | int err; | 280 | int err; |
275 | const char *main_str = parse_prog_config_kvpair(config_str, pev); | 281 | const char *main_str = parse_prog_config_kvpair(config_str, pev); |
@@ -277,6 +283,22 @@ parse_prog_config(const char *config_str, struct perf_probe_event *pev) | |||
277 | if (IS_ERR(main_str)) | 283 | if (IS_ERR(main_str)) |
278 | return PTR_ERR(main_str); | 284 | return PTR_ERR(main_str); |
279 | 285 | ||
286 | *p_main_str = main_str; | ||
287 | if (!strchr(main_str, '=')) { | ||
288 | /* Is a tracepoint event? */ | ||
289 | const char *s = strchr(main_str, ':'); | ||
290 | |||
291 | if (!s) { | ||
292 | pr_debug("bpf: '%s' is not a valid tracepoint\n", | ||
293 | config_str); | ||
294 | return -BPF_LOADER_ERRNO__CONFIG; | ||
295 | } | ||
296 | |||
297 | *is_tp = true; | ||
298 | return 0; | ||
299 | } | ||
300 | |||
301 | *is_tp = false; | ||
280 | err = parse_perf_probe_command(main_str, pev); | 302 | err = parse_perf_probe_command(main_str, pev); |
281 | if (err < 0) { | 303 | if (err < 0) { |
282 | pr_debug("bpf: '%s' is not a valid config string\n", | 304 | pr_debug("bpf: '%s' is not a valid config string\n", |
@@ -292,7 +314,8 @@ config_bpf_program(struct bpf_program *prog) | |||
292 | { | 314 | { |
293 | struct perf_probe_event *pev = NULL; | 315 | struct perf_probe_event *pev = NULL; |
294 | struct bpf_prog_priv *priv = NULL; | 316 | struct bpf_prog_priv *priv = NULL; |
295 | const char *config_str; | 317 | const char *config_str, *main_str; |
318 | bool is_tp = false; | ||
296 | int err; | 319 | int err; |
297 | 320 | ||
298 | /* Initialize per-program probing setting */ | 321 | /* Initialize per-program probing setting */ |
@@ -313,10 +336,19 @@ config_bpf_program(struct bpf_program *prog) | |||
313 | pev = &priv->pev; | 336 | pev = &priv->pev; |
314 | 337 | ||
315 | pr_debug("bpf: config program '%s'\n", config_str); | 338 | pr_debug("bpf: config program '%s'\n", config_str); |
316 | err = parse_prog_config(config_str, pev); | 339 | err = parse_prog_config(config_str, &main_str, &is_tp, pev); |
317 | if (err) | 340 | if (err) |
318 | goto errout; | 341 | goto errout; |
319 | 342 | ||
343 | if (is_tp) { | ||
344 | char *s = strchr(main_str, ':'); | ||
345 | |||
346 | priv->is_tp = true; | ||
347 | priv->sys_name = strndup(main_str, s - main_str); | ||
348 | priv->evt_name = strdup(s + 1); | ||
349 | goto set_priv; | ||
350 | } | ||
351 | |||
320 | if (pev->group && strcmp(pev->group, PERF_BPF_PROBE_GROUP)) { | 352 | if (pev->group && strcmp(pev->group, PERF_BPF_PROBE_GROUP)) { |
321 | pr_debug("bpf: '%s': group for event is set and not '%s'.\n", | 353 | pr_debug("bpf: '%s': group for event is set and not '%s'.\n", |
322 | config_str, PERF_BPF_PROBE_GROUP); | 354 | config_str, PERF_BPF_PROBE_GROUP); |
@@ -339,6 +371,7 @@ config_bpf_program(struct bpf_program *prog) | |||
339 | } | 371 | } |
340 | pr_debug("bpf: config '%s' is ok\n", config_str); | 372 | pr_debug("bpf: config '%s' is ok\n", config_str); |
341 | 373 | ||
374 | set_priv: | ||
342 | err = bpf_program__set_priv(prog, priv, clear_prog_priv); | 375 | err = bpf_program__set_priv(prog, priv, clear_prog_priv); |
343 | if (err) { | 376 | if (err) { |
344 | pr_debug("Failed to set priv for program '%s'\n", config_str); | 377 | pr_debug("Failed to set priv for program '%s'\n", config_str); |
@@ -387,7 +420,7 @@ preproc_gen_prologue(struct bpf_program *prog, int n, | |||
387 | size_t prologue_cnt = 0; | 420 | size_t prologue_cnt = 0; |
388 | int i, err; | 421 | int i, err; |
389 | 422 | ||
390 | if (IS_ERR(priv) || !priv) | 423 | if (IS_ERR(priv) || !priv || priv->is_tp) |
391 | goto errout; | 424 | goto errout; |
392 | 425 | ||
393 | pev = &priv->pev; | 426 | pev = &priv->pev; |
@@ -544,6 +577,11 @@ static int hook_load_preprocessor(struct bpf_program *prog) | |||
544 | return -BPF_LOADER_ERRNO__INTERNAL; | 577 | return -BPF_LOADER_ERRNO__INTERNAL; |
545 | } | 578 | } |
546 | 579 | ||
580 | if (priv->is_tp) { | ||
581 | priv->need_prologue = false; | ||
582 | return 0; | ||
583 | } | ||
584 | |||
547 | pev = &priv->pev; | 585 | pev = &priv->pev; |
548 | for (i = 0; i < pev->ntevs; i++) { | 586 | for (i = 0; i < pev->ntevs; i++) { |
549 | struct probe_trace_event *tev = &pev->tevs[i]; | 587 | struct probe_trace_event *tev = &pev->tevs[i]; |
@@ -610,6 +648,13 @@ int bpf__probe(struct bpf_object *obj) | |||
610 | err = PTR_ERR(priv); | 648 | err = PTR_ERR(priv); |
611 | goto out; | 649 | goto out; |
612 | } | 650 | } |
651 | |||
652 | if (priv->is_tp) { | ||
653 | bpf_program__set_tracepoint(prog); | ||
654 | continue; | ||
655 | } | ||
656 | |||
657 | bpf_program__set_kprobe(prog); | ||
613 | pev = &priv->pev; | 658 | pev = &priv->pev; |
614 | 659 | ||
615 | err = convert_perf_probe_events(pev, 1); | 660 | err = convert_perf_probe_events(pev, 1); |
@@ -650,7 +695,7 @@ int bpf__unprobe(struct bpf_object *obj) | |||
650 | struct bpf_prog_priv *priv = bpf_program__priv(prog); | 695 | struct bpf_prog_priv *priv = bpf_program__priv(prog); |
651 | int i; | 696 | int i; |
652 | 697 | ||
653 | if (IS_ERR(priv) || !priv) | 698 | if (IS_ERR(priv) || !priv || priv->is_tp) |
654 | continue; | 699 | continue; |
655 | 700 | ||
656 | for (i = 0; i < priv->pev.ntevs; i++) { | 701 | for (i = 0; i < priv->pev.ntevs; i++) { |
@@ -693,9 +738,9 @@ int bpf__load(struct bpf_object *obj) | |||
693 | return 0; | 738 | return 0; |
694 | } | 739 | } |
695 | 740 | ||
696 | int bpf__foreach_tev(struct bpf_object *obj, | 741 | int bpf__foreach_event(struct bpf_object *obj, |
697 | bpf_prog_iter_callback_t func, | 742 | bpf_prog_iter_callback_t func, |
698 | void *arg) | 743 | void *arg) |
699 | { | 744 | { |
700 | struct bpf_program *prog; | 745 | struct bpf_program *prog; |
701 | int err; | 746 | int err; |
@@ -711,6 +756,16 @@ int bpf__foreach_tev(struct bpf_object *obj, | |||
711 | return -BPF_LOADER_ERRNO__INTERNAL; | 756 | return -BPF_LOADER_ERRNO__INTERNAL; |
712 | } | 757 | } |
713 | 758 | ||
759 | if (priv->is_tp) { | ||
760 | fd = bpf_program__fd(prog); | ||
761 | err = (*func)(priv->sys_name, priv->evt_name, fd, arg); | ||
762 | if (err) { | ||
763 | pr_debug("bpf: tracepoint call back failed, stop iterate\n"); | ||
764 | return err; | ||
765 | } | ||
766 | continue; | ||
767 | } | ||
768 | |||
714 | pev = &priv->pev; | 769 | pev = &priv->pev; |
715 | for (i = 0; i < pev->ntevs; i++) { | 770 | for (i = 0; i < pev->ntevs; i++) { |
716 | tev = &pev->tevs[i]; | 771 | tev = &pev->tevs[i]; |
@@ -728,7 +783,7 @@ int bpf__foreach_tev(struct bpf_object *obj, | |||
728 | return fd; | 783 | return fd; |
729 | } | 784 | } |
730 | 785 | ||
731 | err = (*func)(tev, fd, arg); | 786 | err = (*func)(tev->group, tev->event, fd, arg); |
732 | if (err) { | 787 | if (err) { |
733 | pr_debug("bpf: call back failed, stop iterate\n"); | 788 | pr_debug("bpf: call back failed, stop iterate\n"); |
734 | return err; | 789 | return err; |
diff --git a/tools/perf/util/bpf-loader.h b/tools/perf/util/bpf-loader.h index 941e17275aa7..f2b737b225f2 100644 --- a/tools/perf/util/bpf-loader.h +++ b/tools/perf/util/bpf-loader.h | |||
@@ -46,7 +46,7 @@ struct bpf_object; | |||
46 | struct parse_events_term; | 46 | struct parse_events_term; |
47 | #define PERF_BPF_PROBE_GROUP "perf_bpf_probe" | 47 | #define PERF_BPF_PROBE_GROUP "perf_bpf_probe" |
48 | 48 | ||
49 | typedef int (*bpf_prog_iter_callback_t)(struct probe_trace_event *tev, | 49 | typedef int (*bpf_prog_iter_callback_t)(const char *group, const char *event, |
50 | int fd, void *arg); | 50 | int fd, void *arg); |
51 | 51 | ||
52 | #ifdef HAVE_LIBBPF_SUPPORT | 52 | #ifdef HAVE_LIBBPF_SUPPORT |
@@ -67,8 +67,8 @@ int bpf__strerror_probe(struct bpf_object *obj, int err, | |||
67 | int bpf__load(struct bpf_object *obj); | 67 | int bpf__load(struct bpf_object *obj); |
68 | int bpf__strerror_load(struct bpf_object *obj, int err, | 68 | int bpf__strerror_load(struct bpf_object *obj, int err, |
69 | char *buf, size_t size); | 69 | char *buf, size_t size); |
70 | int bpf__foreach_tev(struct bpf_object *obj, | 70 | int bpf__foreach_event(struct bpf_object *obj, |
71 | bpf_prog_iter_callback_t func, void *arg); | 71 | bpf_prog_iter_callback_t func, void *arg); |
72 | 72 | ||
73 | int bpf__config_obj(struct bpf_object *obj, struct parse_events_term *term, | 73 | int bpf__config_obj(struct bpf_object *obj, struct parse_events_term *term, |
74 | struct perf_evlist *evlist, int *error_pos); | 74 | struct perf_evlist *evlist, int *error_pos); |
@@ -107,9 +107,9 @@ static inline int bpf__unprobe(struct bpf_object *obj __maybe_unused) { return 0 | |||
107 | static inline int bpf__load(struct bpf_object *obj __maybe_unused) { return 0; } | 107 | static inline int bpf__load(struct bpf_object *obj __maybe_unused) { return 0; } |
108 | 108 | ||
109 | static inline int | 109 | static inline int |
110 | bpf__foreach_tev(struct bpf_object *obj __maybe_unused, | 110 | bpf__foreach_event(struct bpf_object *obj __maybe_unused, |
111 | bpf_prog_iter_callback_t func __maybe_unused, | 111 | bpf_prog_iter_callback_t func __maybe_unused, |
112 | void *arg __maybe_unused) | 112 | void *arg __maybe_unused) |
113 | { | 113 | { |
114 | return 0; | 114 | return 0; |
115 | } | 115 | } |
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c index 1e504e40dac8..5651f3c12f93 100644 --- a/tools/perf/util/build-id.c +++ b/tools/perf/util/build-id.c | |||
@@ -206,6 +206,31 @@ out: | |||
206 | return ret; | 206 | return ret; |
207 | } | 207 | } |
208 | 208 | ||
209 | /* Check if the given build_id cache is valid on current running system */ | ||
210 | static bool build_id_cache__valid_id(char *sbuild_id) | ||
211 | { | ||
212 | char real_sbuild_id[SBUILD_ID_SIZE] = ""; | ||
213 | char *pathname; | ||
214 | int ret = 0; | ||
215 | bool result = false; | ||
216 | |||
217 | pathname = build_id_cache__origname(sbuild_id); | ||
218 | if (!pathname) | ||
219 | return false; | ||
220 | |||
221 | if (!strcmp(pathname, DSO__NAME_KALLSYMS)) | ||
222 | ret = sysfs__sprintf_build_id("/", real_sbuild_id); | ||
223 | else if (pathname[0] == '/') | ||
224 | ret = filename__sprintf_build_id(pathname, real_sbuild_id); | ||
225 | else | ||
226 | ret = -EINVAL; /* Should we support other special DSO cache? */ | ||
227 | if (ret >= 0) | ||
228 | result = (strcmp(sbuild_id, real_sbuild_id) == 0); | ||
229 | free(pathname); | ||
230 | |||
231 | return result; | ||
232 | } | ||
233 | |||
209 | static const char *build_id_cache__basename(bool is_kallsyms, bool is_vdso) | 234 | static const char *build_id_cache__basename(bool is_kallsyms, bool is_vdso) |
210 | { | 235 | { |
211 | return is_kallsyms ? "kallsyms" : (is_vdso ? "vdso" : "elf"); | 236 | return is_kallsyms ? "kallsyms" : (is_vdso ? "vdso" : "elf"); |
@@ -433,13 +458,17 @@ static bool lsdir_bid_tail_filter(const char *name __maybe_unused, | |||
433 | return (i == SBUILD_ID_SIZE - 3) && (d->d_name[i] == '\0'); | 458 | return (i == SBUILD_ID_SIZE - 3) && (d->d_name[i] == '\0'); |
434 | } | 459 | } |
435 | 460 | ||
436 | struct strlist *build_id_cache__list_all(void) | 461 | struct strlist *build_id_cache__list_all(bool validonly) |
437 | { | 462 | { |
438 | struct strlist *toplist, *linklist = NULL, *bidlist; | 463 | struct strlist *toplist, *linklist = NULL, *bidlist; |
439 | struct str_node *nd, *nd2; | 464 | struct str_node *nd, *nd2; |
440 | char *topdir, *linkdir = NULL; | 465 | char *topdir, *linkdir = NULL; |
441 | char sbuild_id[SBUILD_ID_SIZE]; | 466 | char sbuild_id[SBUILD_ID_SIZE]; |
442 | 467 | ||
468 | /* for filename__ functions */ | ||
469 | if (validonly) | ||
470 | symbol__init(NULL); | ||
471 | |||
443 | /* Open the top-level directory */ | 472 | /* Open the top-level directory */ |
444 | if (asprintf(&topdir, "%s/.build-id/", buildid_dir) < 0) | 473 | if (asprintf(&topdir, "%s/.build-id/", buildid_dir) < 0) |
445 | return NULL; | 474 | return NULL; |
@@ -470,6 +499,8 @@ struct strlist *build_id_cache__list_all(void) | |||
470 | if (snprintf(sbuild_id, SBUILD_ID_SIZE, "%s%s", | 499 | if (snprintf(sbuild_id, SBUILD_ID_SIZE, "%s%s", |
471 | nd->s, nd2->s) != SBUILD_ID_SIZE - 1) | 500 | nd->s, nd2->s) != SBUILD_ID_SIZE - 1) |
472 | goto err_out; | 501 | goto err_out; |
502 | if (validonly && !build_id_cache__valid_id(sbuild_id)) | ||
503 | continue; | ||
473 | if (strlist__add(bidlist, sbuild_id) < 0) | 504 | if (strlist__add(bidlist, sbuild_id) < 0) |
474 | goto err_out; | 505 | goto err_out; |
475 | } | 506 | } |
@@ -492,6 +523,49 @@ err_out: | |||
492 | goto out_free; | 523 | goto out_free; |
493 | } | 524 | } |
494 | 525 | ||
526 | static bool str_is_build_id(const char *maybe_sbuild_id, size_t len) | ||
527 | { | ||
528 | size_t i; | ||
529 | |||
530 | for (i = 0; i < len; i++) { | ||
531 | if (!isxdigit(maybe_sbuild_id[i])) | ||
532 | return false; | ||
533 | } | ||
534 | return true; | ||
535 | } | ||
536 | |||
537 | /* Return the valid complete build-id */ | ||
538 | char *build_id_cache__complement(const char *incomplete_sbuild_id) | ||
539 | { | ||
540 | struct strlist *bidlist; | ||
541 | struct str_node *nd, *cand = NULL; | ||
542 | char *sbuild_id = NULL; | ||
543 | size_t len = strlen(incomplete_sbuild_id); | ||
544 | |||
545 | if (len >= SBUILD_ID_SIZE || | ||
546 | !str_is_build_id(incomplete_sbuild_id, len)) | ||
547 | return NULL; | ||
548 | |||
549 | bidlist = build_id_cache__list_all(true); | ||
550 | if (!bidlist) | ||
551 | return NULL; | ||
552 | |||
553 | strlist__for_each_entry(nd, bidlist) { | ||
554 | if (strncmp(nd->s, incomplete_sbuild_id, len) != 0) | ||
555 | continue; | ||
556 | if (cand) { /* Error: There are more than 2 candidates. */ | ||
557 | cand = NULL; | ||
558 | break; | ||
559 | } | ||
560 | cand = nd; | ||
561 | } | ||
562 | if (cand) | ||
563 | sbuild_id = strdup(cand->s); | ||
564 | strlist__delete(bidlist); | ||
565 | |||
566 | return sbuild_id; | ||
567 | } | ||
568 | |||
495 | char *build_id_cache__cachedir(const char *sbuild_id, const char *name, | 569 | char *build_id_cache__cachedir(const char *sbuild_id, const char *name, |
496 | bool is_kallsyms, bool is_vdso) | 570 | bool is_kallsyms, bool is_vdso) |
497 | { | 571 | { |
diff --git a/tools/perf/util/build-id.h b/tools/perf/util/build-id.h index b742e271ea2c..d27990610f9f 100644 --- a/tools/perf/util/build-id.h +++ b/tools/perf/util/build-id.h | |||
@@ -34,7 +34,8 @@ char *build_id_cache__origname(const char *sbuild_id); | |||
34 | char *build_id_cache__linkname(const char *sbuild_id, char *bf, size_t size); | 34 | char *build_id_cache__linkname(const char *sbuild_id, char *bf, size_t size); |
35 | char *build_id_cache__cachedir(const char *sbuild_id, const char *name, | 35 | char *build_id_cache__cachedir(const char *sbuild_id, const char *name, |
36 | bool is_kallsyms, bool is_vdso); | 36 | bool is_kallsyms, bool is_vdso); |
37 | struct strlist *build_id_cache__list_all(void); | 37 | struct strlist *build_id_cache__list_all(bool validonly); |
38 | char *build_id_cache__complement(const char *incomplete_sbuild_id); | ||
38 | int build_id_cache__list_build_ids(const char *pathname, | 39 | int build_id_cache__list_build_ids(const char *pathname, |
39 | struct strlist **result); | 40 | struct strlist **result); |
40 | bool build_id_cache__cached(const char *sbuild_id); | 41 | bool build_id_cache__cached(const char *sbuild_id); |
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index ebd87b773f56..375af0e02831 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include "pmu.h" | 20 | #include "pmu.h" |
21 | #include "thread_map.h" | 21 | #include "thread_map.h" |
22 | #include "cpumap.h" | 22 | #include "cpumap.h" |
23 | #include "probe-file.h" | ||
23 | #include "asm/bug.h" | 24 | #include "asm/bug.h" |
24 | 25 | ||
25 | #define MAX_NAME_LEN 100 | 26 | #define MAX_NAME_LEN 100 |
@@ -436,7 +437,7 @@ int parse_events_add_cache(struct list_head *list, int *idx, | |||
436 | } | 437 | } |
437 | 438 | ||
438 | static void tracepoint_error(struct parse_events_error *e, int err, | 439 | static void tracepoint_error(struct parse_events_error *e, int err, |
439 | char *sys, char *name) | 440 | const char *sys, const char *name) |
440 | { | 441 | { |
441 | char help[BUFSIZ]; | 442 | char help[BUFSIZ]; |
442 | 443 | ||
@@ -466,7 +467,7 @@ static void tracepoint_error(struct parse_events_error *e, int err, | |||
466 | } | 467 | } |
467 | 468 | ||
468 | static int add_tracepoint(struct list_head *list, int *idx, | 469 | static int add_tracepoint(struct list_head *list, int *idx, |
469 | char *sys_name, char *evt_name, | 470 | const char *sys_name, const char *evt_name, |
470 | struct parse_events_error *err, | 471 | struct parse_events_error *err, |
471 | struct list_head *head_config) | 472 | struct list_head *head_config) |
472 | { | 473 | { |
@@ -491,7 +492,7 @@ static int add_tracepoint(struct list_head *list, int *idx, | |||
491 | } | 492 | } |
492 | 493 | ||
493 | static int add_tracepoint_multi_event(struct list_head *list, int *idx, | 494 | static int add_tracepoint_multi_event(struct list_head *list, int *idx, |
494 | char *sys_name, char *evt_name, | 495 | const char *sys_name, const char *evt_name, |
495 | struct parse_events_error *err, | 496 | struct parse_events_error *err, |
496 | struct list_head *head_config) | 497 | struct list_head *head_config) |
497 | { | 498 | { |
@@ -533,7 +534,7 @@ static int add_tracepoint_multi_event(struct list_head *list, int *idx, | |||
533 | } | 534 | } |
534 | 535 | ||
535 | static int add_tracepoint_event(struct list_head *list, int *idx, | 536 | static int add_tracepoint_event(struct list_head *list, int *idx, |
536 | char *sys_name, char *evt_name, | 537 | const char *sys_name, const char *evt_name, |
537 | struct parse_events_error *err, | 538 | struct parse_events_error *err, |
538 | struct list_head *head_config) | 539 | struct list_head *head_config) |
539 | { | 540 | { |
@@ -545,7 +546,7 @@ static int add_tracepoint_event(struct list_head *list, int *idx, | |||
545 | } | 546 | } |
546 | 547 | ||
547 | static int add_tracepoint_multi_sys(struct list_head *list, int *idx, | 548 | static int add_tracepoint_multi_sys(struct list_head *list, int *idx, |
548 | char *sys_name, char *evt_name, | 549 | const char *sys_name, const char *evt_name, |
549 | struct parse_events_error *err, | 550 | struct parse_events_error *err, |
550 | struct list_head *head_config) | 551 | struct list_head *head_config) |
551 | { | 552 | { |
@@ -584,7 +585,7 @@ struct __add_bpf_event_param { | |||
584 | struct list_head *head_config; | 585 | struct list_head *head_config; |
585 | }; | 586 | }; |
586 | 587 | ||
587 | static int add_bpf_event(struct probe_trace_event *tev, int fd, | 588 | static int add_bpf_event(const char *group, const char *event, int fd, |
588 | void *_param) | 589 | void *_param) |
589 | { | 590 | { |
590 | LIST_HEAD(new_evsels); | 591 | LIST_HEAD(new_evsels); |
@@ -595,27 +596,27 @@ static int add_bpf_event(struct probe_trace_event *tev, int fd, | |||
595 | int err; | 596 | int err; |
596 | 597 | ||
597 | pr_debug("add bpf event %s:%s and attach bpf program %d\n", | 598 | pr_debug("add bpf event %s:%s and attach bpf program %d\n", |
598 | tev->group, tev->event, fd); | 599 | group, event, fd); |
599 | 600 | ||
600 | err = parse_events_add_tracepoint(&new_evsels, &evlist->idx, tev->group, | 601 | err = parse_events_add_tracepoint(&new_evsels, &evlist->idx, group, |
601 | tev->event, evlist->error, | 602 | event, evlist->error, |
602 | param->head_config); | 603 | param->head_config); |
603 | if (err) { | 604 | if (err) { |
604 | struct perf_evsel *evsel, *tmp; | 605 | struct perf_evsel *evsel, *tmp; |
605 | 606 | ||
606 | pr_debug("Failed to add BPF event %s:%s\n", | 607 | pr_debug("Failed to add BPF event %s:%s\n", |
607 | tev->group, tev->event); | 608 | group, event); |
608 | list_for_each_entry_safe(evsel, tmp, &new_evsels, node) { | 609 | list_for_each_entry_safe(evsel, tmp, &new_evsels, node) { |
609 | list_del(&evsel->node); | 610 | list_del(&evsel->node); |
610 | perf_evsel__delete(evsel); | 611 | perf_evsel__delete(evsel); |
611 | } | 612 | } |
612 | return err; | 613 | return err; |
613 | } | 614 | } |
614 | pr_debug("adding %s:%s\n", tev->group, tev->event); | 615 | pr_debug("adding %s:%s\n", group, event); |
615 | 616 | ||
616 | list_for_each_entry(pos, &new_evsels, node) { | 617 | list_for_each_entry(pos, &new_evsels, node) { |
617 | pr_debug("adding %s:%s to %p\n", | 618 | pr_debug("adding %s:%s to %p\n", |
618 | tev->group, tev->event, pos); | 619 | group, event, pos); |
619 | pos->bpf_fd = fd; | 620 | pos->bpf_fd = fd; |
620 | } | 621 | } |
621 | list_splice(&new_evsels, list); | 622 | list_splice(&new_evsels, list); |
@@ -661,7 +662,7 @@ int parse_events_load_bpf_obj(struct parse_events_evlist *data, | |||
661 | goto errout; | 662 | goto errout; |
662 | } | 663 | } |
663 | 664 | ||
664 | err = bpf__foreach_tev(obj, add_bpf_event, ¶m); | 665 | err = bpf__foreach_event(obj, add_bpf_event, ¶m); |
665 | if (err) { | 666 | if (err) { |
666 | snprintf(errbuf, sizeof(errbuf), | 667 | snprintf(errbuf, sizeof(errbuf), |
667 | "Attach events in BPF object failed"); | 668 | "Attach events in BPF object failed"); |
@@ -1126,7 +1127,7 @@ do { \ | |||
1126 | } | 1127 | } |
1127 | 1128 | ||
1128 | int parse_events_add_tracepoint(struct list_head *list, int *idx, | 1129 | int parse_events_add_tracepoint(struct list_head *list, int *idx, |
1129 | char *sys, char *event, | 1130 | const char *sys, const char *event, |
1130 | struct parse_events_error *err, | 1131 | struct parse_events_error *err, |
1131 | struct list_head *head_config) | 1132 | struct list_head *head_config) |
1132 | { | 1133 | { |
@@ -1984,6 +1985,85 @@ static bool is_event_supported(u8 type, unsigned config) | |||
1984 | return ret; | 1985 | return ret; |
1985 | } | 1986 | } |
1986 | 1987 | ||
1988 | void print_sdt_events(const char *subsys_glob, const char *event_glob, | ||
1989 | bool name_only) | ||
1990 | { | ||
1991 | struct probe_cache *pcache; | ||
1992 | struct probe_cache_entry *ent; | ||
1993 | struct strlist *bidlist, *sdtlist; | ||
1994 | struct strlist_config cfg = {.dont_dupstr = true}; | ||
1995 | struct str_node *nd, *nd2; | ||
1996 | char *buf, *path, *ptr = NULL; | ||
1997 | bool show_detail = false; | ||
1998 | int ret; | ||
1999 | |||
2000 | sdtlist = strlist__new(NULL, &cfg); | ||
2001 | if (!sdtlist) { | ||
2002 | pr_debug("Failed to allocate new strlist for SDT\n"); | ||
2003 | return; | ||
2004 | } | ||
2005 | bidlist = build_id_cache__list_all(true); | ||
2006 | if (!bidlist) { | ||
2007 | pr_debug("Failed to get buildids: %d\n", errno); | ||
2008 | return; | ||
2009 | } | ||
2010 | strlist__for_each_entry(nd, bidlist) { | ||
2011 | pcache = probe_cache__new(nd->s); | ||
2012 | if (!pcache) | ||
2013 | continue; | ||
2014 | list_for_each_entry(ent, &pcache->entries, node) { | ||
2015 | if (!ent->sdt) | ||
2016 | continue; | ||
2017 | if (subsys_glob && | ||
2018 | !strglobmatch(ent->pev.group, subsys_glob)) | ||
2019 | continue; | ||
2020 | if (event_glob && | ||
2021 | !strglobmatch(ent->pev.event, event_glob)) | ||
2022 | continue; | ||
2023 | ret = asprintf(&buf, "%s:%s@%s", ent->pev.group, | ||
2024 | ent->pev.event, nd->s); | ||
2025 | if (ret > 0) | ||
2026 | strlist__add(sdtlist, buf); | ||
2027 | } | ||
2028 | probe_cache__delete(pcache); | ||
2029 | } | ||
2030 | strlist__delete(bidlist); | ||
2031 | |||
2032 | strlist__for_each_entry(nd, sdtlist) { | ||
2033 | buf = strchr(nd->s, '@'); | ||
2034 | if (buf) | ||
2035 | *(buf++) = '\0'; | ||
2036 | if (name_only) { | ||
2037 | printf("%s ", nd->s); | ||
2038 | continue; | ||
2039 | } | ||
2040 | nd2 = strlist__next(nd); | ||
2041 | if (nd2) { | ||
2042 | ptr = strchr(nd2->s, '@'); | ||
2043 | if (ptr) | ||
2044 | *ptr = '\0'; | ||
2045 | if (strcmp(nd->s, nd2->s) == 0) | ||
2046 | show_detail = true; | ||
2047 | } | ||
2048 | if (show_detail) { | ||
2049 | path = build_id_cache__origname(buf); | ||
2050 | ret = asprintf(&buf, "%s@%s(%.12s)", nd->s, path, buf); | ||
2051 | if (ret > 0) { | ||
2052 | printf(" %-50s [%s]\n", buf, "SDT event"); | ||
2053 | free(buf); | ||
2054 | } | ||
2055 | } else | ||
2056 | printf(" %-50s [%s]\n", nd->s, "SDT event"); | ||
2057 | if (nd2) { | ||
2058 | if (strcmp(nd->s, nd2->s) != 0) | ||
2059 | show_detail = false; | ||
2060 | if (ptr) | ||
2061 | *ptr = '@'; | ||
2062 | } | ||
2063 | } | ||
2064 | strlist__delete(sdtlist); | ||
2065 | } | ||
2066 | |||
1987 | int print_hwcache_events(const char *event_glob, bool name_only) | 2067 | int print_hwcache_events(const char *event_glob, bool name_only) |
1988 | { | 2068 | { |
1989 | unsigned int type, op, i, evt_i = 0, evt_num = 0; | 2069 | unsigned int type, op, i, evt_i = 0, evt_num = 0; |
@@ -2166,6 +2246,8 @@ void print_events(const char *event_glob, bool name_only) | |||
2166 | } | 2246 | } |
2167 | 2247 | ||
2168 | print_tracepoint_events(NULL, NULL, name_only); | 2248 | print_tracepoint_events(NULL, NULL, name_only); |
2249 | |||
2250 | print_sdt_events(NULL, NULL, name_only); | ||
2169 | } | 2251 | } |
2170 | 2252 | ||
2171 | int parse_events__is_hardcoded_term(struct parse_events_term *term) | 2253 | int parse_events__is_hardcoded_term(struct parse_events_term *term) |
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index 46c05ccd5dfe..b4aa7eb2df73 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h | |||
@@ -134,7 +134,7 @@ int parse_events__modifier_event(struct list_head *list, char *str, bool add); | |||
134 | int parse_events__modifier_group(struct list_head *list, char *event_mod); | 134 | int parse_events__modifier_group(struct list_head *list, char *event_mod); |
135 | int parse_events_name(struct list_head *list, char *name); | 135 | int parse_events_name(struct list_head *list, char *name); |
136 | int parse_events_add_tracepoint(struct list_head *list, int *idx, | 136 | int parse_events_add_tracepoint(struct list_head *list, int *idx, |
137 | char *sys, char *event, | 137 | const char *sys, const char *event, |
138 | struct parse_events_error *error, | 138 | struct parse_events_error *error, |
139 | struct list_head *head_config); | 139 | struct list_head *head_config); |
140 | int parse_events_load_bpf(struct parse_events_evlist *data, | 140 | int parse_events_load_bpf(struct parse_events_evlist *data, |
@@ -183,6 +183,8 @@ void print_symbol_events(const char *event_glob, unsigned type, | |||
183 | void print_tracepoint_events(const char *subsys_glob, const char *event_glob, | 183 | void print_tracepoint_events(const char *subsys_glob, const char *event_glob, |
184 | bool name_only); | 184 | bool name_only); |
185 | int print_hwcache_events(const char *event_glob, bool name_only); | 185 | int print_hwcache_events(const char *event_glob, bool name_only); |
186 | void print_sdt_events(const char *subsys_glob, const char *event_glob, | ||
187 | bool name_only); | ||
186 | int is_valid_tracepoint(const char *event_string); | 188 | int is_valid_tracepoint(const char *event_string); |
187 | 189 | ||
188 | int valid_event_mount(const char *eventfs); | 190 | int valid_event_mount(const char *eventfs); |
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 2b222a7955c9..d4f8835c0a27 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c | |||
@@ -1197,6 +1197,34 @@ err: | |||
1197 | return err; | 1197 | return err; |
1198 | } | 1198 | } |
1199 | 1199 | ||
1200 | static int parse_perf_probe_event_name(char **arg, struct perf_probe_event *pev) | ||
1201 | { | ||
1202 | char *ptr; | ||
1203 | |||
1204 | ptr = strchr(*arg, ':'); | ||
1205 | if (ptr) { | ||
1206 | *ptr = '\0'; | ||
1207 | if (!pev->sdt && !is_c_func_name(*arg)) | ||
1208 | goto ng_name; | ||
1209 | pev->group = strdup(*arg); | ||
1210 | if (!pev->group) | ||
1211 | return -ENOMEM; | ||
1212 | *arg = ptr + 1; | ||
1213 | } else | ||
1214 | pev->group = NULL; | ||
1215 | if (!pev->sdt && !is_c_func_name(*arg)) { | ||
1216 | ng_name: | ||
1217 | semantic_error("%s is bad for event name -it must " | ||
1218 | "follow C symbol-naming rule.\n", *arg); | ||
1219 | return -EINVAL; | ||
1220 | } | ||
1221 | pev->event = strdup(*arg); | ||
1222 | if (pev->event == NULL) | ||
1223 | return -ENOMEM; | ||
1224 | |||
1225 | return 0; | ||
1226 | } | ||
1227 | |||
1200 | /* Parse probepoint definition. */ | 1228 | /* Parse probepoint definition. */ |
1201 | static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev) | 1229 | static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev) |
1202 | { | 1230 | { |
@@ -1204,38 +1232,64 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev) | |||
1204 | char *ptr, *tmp; | 1232 | char *ptr, *tmp; |
1205 | char c, nc = 0; | 1233 | char c, nc = 0; |
1206 | bool file_spec = false; | 1234 | bool file_spec = false; |
1235 | int ret; | ||
1236 | |||
1207 | /* | 1237 | /* |
1208 | * <Syntax> | 1238 | * <Syntax> |
1209 | * perf probe [GRP:][EVENT=]SRC[:LN|;PTN] | 1239 | * perf probe [GRP:][EVENT=]SRC[:LN|;PTN] |
1210 | * perf probe [GRP:][EVENT=]FUNC[@SRC][+OFFS|%return|:LN|;PAT] | 1240 | * perf probe [GRP:][EVENT=]FUNC[@SRC][+OFFS|%return|:LN|;PAT] |
1241 | * perf probe %[GRP:]SDT_EVENT | ||
1211 | */ | 1242 | */ |
1212 | if (!arg) | 1243 | if (!arg) |
1213 | return -EINVAL; | 1244 | return -EINVAL; |
1214 | 1245 | ||
1246 | /* | ||
1247 | * If the probe point starts with '%', | ||
1248 | * or starts with "sdt_" and has a ':' but no '=', | ||
1249 | * then it should be a SDT/cached probe point. | ||
1250 | */ | ||
1251 | if (arg[0] == '%' || | ||
1252 | (!strncmp(arg, "sdt_", 4) && | ||
1253 | !!strchr(arg, ':') && !strchr(arg, '='))) { | ||
1254 | pev->sdt = true; | ||
1255 | if (arg[0] == '%') | ||
1256 | arg++; | ||
1257 | } | ||
1258 | |||
1215 | ptr = strpbrk(arg, ";=@+%"); | 1259 | ptr = strpbrk(arg, ";=@+%"); |
1216 | if (ptr && *ptr == '=') { /* Event name */ | 1260 | if (pev->sdt) { |
1217 | *ptr = '\0'; | ||
1218 | tmp = ptr + 1; | ||
1219 | ptr = strchr(arg, ':'); | ||
1220 | if (ptr) { | 1261 | if (ptr) { |
1221 | *ptr = '\0'; | 1262 | if (*ptr != '@') { |
1222 | if (!is_c_func_name(arg)) | 1263 | semantic_error("%s must be an SDT name.\n", |
1223 | goto not_fname; | 1264 | arg); |
1224 | pev->group = strdup(arg); | 1265 | return -EINVAL; |
1225 | if (!pev->group) | 1266 | } |
1267 | /* This must be a target file name or build id */ | ||
1268 | tmp = build_id_cache__complement(ptr + 1); | ||
1269 | if (tmp) { | ||
1270 | pev->target = build_id_cache__origname(tmp); | ||
1271 | free(tmp); | ||
1272 | } else | ||
1273 | pev->target = strdup(ptr + 1); | ||
1274 | if (!pev->target) | ||
1226 | return -ENOMEM; | 1275 | return -ENOMEM; |
1227 | arg = ptr + 1; | 1276 | *ptr = '\0'; |
1228 | } else | ||
1229 | pev->group = NULL; | ||
1230 | if (!is_c_func_name(arg)) { | ||
1231 | not_fname: | ||
1232 | semantic_error("%s is bad for event name -it must " | ||
1233 | "follow C symbol-naming rule.\n", arg); | ||
1234 | return -EINVAL; | ||
1235 | } | 1277 | } |
1236 | pev->event = strdup(arg); | 1278 | ret = parse_perf_probe_event_name(&arg, pev); |
1237 | if (pev->event == NULL) | 1279 | if (ret == 0) { |
1238 | return -ENOMEM; | 1280 | if (asprintf(&pev->point.function, "%%%s", pev->event) < 0) |
1281 | ret = -errno; | ||
1282 | } | ||
1283 | return ret; | ||
1284 | } | ||
1285 | |||
1286 | if (ptr && *ptr == '=') { /* Event name */ | ||
1287 | *ptr = '\0'; | ||
1288 | tmp = ptr + 1; | ||
1289 | ret = parse_perf_probe_event_name(&arg, pev); | ||
1290 | if (ret < 0) | ||
1291 | return ret; | ||
1292 | |||
1239 | arg = tmp; | 1293 | arg = tmp; |
1240 | } | 1294 | } |
1241 | 1295 | ||
@@ -1547,7 +1601,9 @@ bool perf_probe_event_need_dwarf(struct perf_probe_event *pev) | |||
1547 | return true; | 1601 | return true; |
1548 | 1602 | ||
1549 | for (i = 0; i < pev->nargs; i++) | 1603 | for (i = 0; i < pev->nargs; i++) |
1550 | if (is_c_varname(pev->args[i].var)) | 1604 | if (is_c_varname(pev->args[i].var) || |
1605 | !strcmp(pev->args[i].var, "$params") || | ||
1606 | !strcmp(pev->args[i].var, "$vars")) | ||
1551 | return true; | 1607 | return true; |
1552 | 1608 | ||
1553 | return false; | 1609 | return false; |
@@ -1609,6 +1665,7 @@ int parse_probe_trace_command(const char *cmd, struct probe_trace_event *tev) | |||
1609 | ret = -ENOMEM; | 1665 | ret = -ENOMEM; |
1610 | goto out; | 1666 | goto out; |
1611 | } | 1667 | } |
1668 | tev->uprobes = (tp->module[0] == '/'); | ||
1612 | p++; | 1669 | p++; |
1613 | } else | 1670 | } else |
1614 | p = argv[1]; | 1671 | p = argv[1]; |
@@ -2483,7 +2540,7 @@ static int probe_trace_event__set_name(struct probe_trace_event *tev, | |||
2483 | int ret; | 2540 | int ret; |
2484 | 2541 | ||
2485 | /* If probe_event or trace_event already have the name, reuse it */ | 2542 | /* If probe_event or trace_event already have the name, reuse it */ |
2486 | if (pev->event) | 2543 | if (pev->event && !pev->sdt) |
2487 | event = pev->event; | 2544 | event = pev->event; |
2488 | else if (tev->event) | 2545 | else if (tev->event) |
2489 | event = tev->event; | 2546 | event = tev->event; |
@@ -2496,7 +2553,7 @@ static int probe_trace_event__set_name(struct probe_trace_event *tev, | |||
2496 | else | 2553 | else |
2497 | event = tev->point.realname; | 2554 | event = tev->point.realname; |
2498 | } | 2555 | } |
2499 | if (pev->group) | 2556 | if (pev->group && !pev->sdt) |
2500 | group = pev->group; | 2557 | group = pev->group; |
2501 | else if (tev->group) | 2558 | else if (tev->group) |
2502 | group = tev->group; | 2559 | group = tev->group; |
@@ -2521,41 +2578,60 @@ static int probe_trace_event__set_name(struct probe_trace_event *tev, | |||
2521 | return 0; | 2578 | return 0; |
2522 | } | 2579 | } |
2523 | 2580 | ||
2524 | static int __add_probe_trace_events(struct perf_probe_event *pev, | 2581 | static int __open_probe_file_and_namelist(bool uprobe, |
2525 | struct probe_trace_event *tevs, | 2582 | struct strlist **namelist) |
2526 | int ntevs, bool allow_suffix) | ||
2527 | { | 2583 | { |
2528 | int i, fd, ret; | 2584 | int fd; |
2529 | struct probe_trace_event *tev = NULL; | ||
2530 | struct probe_cache *cache = NULL; | ||
2531 | struct strlist *namelist; | ||
2532 | 2585 | ||
2533 | fd = probe_file__open(PF_FL_RW | (pev->uprobes ? PF_FL_UPROBE : 0)); | 2586 | fd = probe_file__open(PF_FL_RW | (uprobe ? PF_FL_UPROBE : 0)); |
2534 | if (fd < 0) | 2587 | if (fd < 0) |
2535 | return fd; | 2588 | return fd; |
2536 | 2589 | ||
2537 | /* Get current event names */ | 2590 | /* Get current event names */ |
2538 | namelist = probe_file__get_namelist(fd); | 2591 | *namelist = probe_file__get_namelist(fd); |
2539 | if (!namelist) { | 2592 | if (!(*namelist)) { |
2540 | pr_debug("Failed to get current event list.\n"); | 2593 | pr_debug("Failed to get current event list.\n"); |
2541 | ret = -ENOMEM; | 2594 | close(fd); |
2542 | goto close_out; | 2595 | return -ENOMEM; |
2543 | } | 2596 | } |
2597 | return fd; | ||
2598 | } | ||
2599 | |||
2600 | static int __add_probe_trace_events(struct perf_probe_event *pev, | ||
2601 | struct probe_trace_event *tevs, | ||
2602 | int ntevs, bool allow_suffix) | ||
2603 | { | ||
2604 | int i, fd[2] = {-1, -1}, up, ret; | ||
2605 | struct probe_trace_event *tev = NULL; | ||
2606 | struct probe_cache *cache = NULL; | ||
2607 | struct strlist *namelist[2] = {NULL, NULL}; | ||
2608 | |||
2609 | up = pev->uprobes ? 1 : 0; | ||
2610 | fd[up] = __open_probe_file_and_namelist(up, &namelist[up]); | ||
2611 | if (fd[up] < 0) | ||
2612 | return fd[up]; | ||
2544 | 2613 | ||
2545 | ret = 0; | 2614 | ret = 0; |
2546 | for (i = 0; i < ntevs; i++) { | 2615 | for (i = 0; i < ntevs; i++) { |
2547 | tev = &tevs[i]; | 2616 | tev = &tevs[i]; |
2617 | up = tev->uprobes ? 1 : 0; | ||
2618 | if (fd[up] == -1) { /* Open the kprobe/uprobe_events */ | ||
2619 | fd[up] = __open_probe_file_and_namelist(up, | ||
2620 | &namelist[up]); | ||
2621 | if (fd[up] < 0) | ||
2622 | goto close_out; | ||
2623 | } | ||
2548 | /* Skip if the symbol is out of .text or blacklisted */ | 2624 | /* Skip if the symbol is out of .text or blacklisted */ |
2549 | if (!tev->point.symbol && !pev->uprobes) | 2625 | if (!tev->point.symbol && !pev->uprobes) |
2550 | continue; | 2626 | continue; |
2551 | 2627 | ||
2552 | /* Set new name for tev (and update namelist) */ | 2628 | /* Set new name for tev (and update namelist) */ |
2553 | ret = probe_trace_event__set_name(tev, pev, namelist, | 2629 | ret = probe_trace_event__set_name(tev, pev, namelist[up], |
2554 | allow_suffix); | 2630 | allow_suffix); |
2555 | if (ret < 0) | 2631 | if (ret < 0) |
2556 | break; | 2632 | break; |
2557 | 2633 | ||
2558 | ret = probe_file__add_event(fd, tev); | 2634 | ret = probe_file__add_event(fd[up], tev); |
2559 | if (ret < 0) | 2635 | if (ret < 0) |
2560 | break; | 2636 | break; |
2561 | 2637 | ||
@@ -2578,9 +2654,12 @@ static int __add_probe_trace_events(struct perf_probe_event *pev, | |||
2578 | probe_cache__delete(cache); | 2654 | probe_cache__delete(cache); |
2579 | } | 2655 | } |
2580 | 2656 | ||
2581 | strlist__delete(namelist); | ||
2582 | close_out: | 2657 | close_out: |
2583 | close(fd); | 2658 | for (up = 0; up < 2; up++) { |
2659 | strlist__delete(namelist[up]); | ||
2660 | if (fd[up] >= 0) | ||
2661 | close(fd[up]); | ||
2662 | } | ||
2584 | return ret; | 2663 | return ret; |
2585 | } | 2664 | } |
2586 | 2665 | ||
@@ -2859,6 +2938,142 @@ errout: | |||
2859 | 2938 | ||
2860 | bool __weak arch__prefers_symtab(void) { return false; } | 2939 | bool __weak arch__prefers_symtab(void) { return false; } |
2861 | 2940 | ||
2941 | /* Concatinate two arrays */ | ||
2942 | static void *memcat(void *a, size_t sz_a, void *b, size_t sz_b) | ||
2943 | { | ||
2944 | void *ret; | ||
2945 | |||
2946 | ret = malloc(sz_a + sz_b); | ||
2947 | if (ret) { | ||
2948 | memcpy(ret, a, sz_a); | ||
2949 | memcpy(ret + sz_a, b, sz_b); | ||
2950 | } | ||
2951 | return ret; | ||
2952 | } | ||
2953 | |||
2954 | static int | ||
2955 | concat_probe_trace_events(struct probe_trace_event **tevs, int *ntevs, | ||
2956 | struct probe_trace_event **tevs2, int ntevs2) | ||
2957 | { | ||
2958 | struct probe_trace_event *new_tevs; | ||
2959 | int ret = 0; | ||
2960 | |||
2961 | if (ntevs == 0) { | ||
2962 | *tevs = *tevs2; | ||
2963 | *ntevs = ntevs2; | ||
2964 | *tevs2 = NULL; | ||
2965 | return 0; | ||
2966 | } | ||
2967 | |||
2968 | if (*ntevs + ntevs2 > probe_conf.max_probes) | ||
2969 | ret = -E2BIG; | ||
2970 | else { | ||
2971 | /* Concatinate the array of probe_trace_event */ | ||
2972 | new_tevs = memcat(*tevs, (*ntevs) * sizeof(**tevs), | ||
2973 | *tevs2, ntevs2 * sizeof(**tevs2)); | ||
2974 | if (!new_tevs) | ||
2975 | ret = -ENOMEM; | ||
2976 | else { | ||
2977 | free(*tevs); | ||
2978 | *tevs = new_tevs; | ||
2979 | *ntevs += ntevs2; | ||
2980 | } | ||
2981 | } | ||
2982 | if (ret < 0) | ||
2983 | clear_probe_trace_events(*tevs2, ntevs2); | ||
2984 | zfree(tevs2); | ||
2985 | |||
2986 | return ret; | ||
2987 | } | ||
2988 | |||
2989 | /* | ||
2990 | * Try to find probe_trace_event from given probe caches. Return the number | ||
2991 | * of cached events found, if an error occurs return the error. | ||
2992 | */ | ||
2993 | static int find_cached_events(struct perf_probe_event *pev, | ||
2994 | struct probe_trace_event **tevs, | ||
2995 | const char *target) | ||
2996 | { | ||
2997 | struct probe_cache *cache; | ||
2998 | struct probe_cache_entry *entry; | ||
2999 | struct probe_trace_event *tmp_tevs = NULL; | ||
3000 | int ntevs = 0; | ||
3001 | int ret = 0; | ||
3002 | |||
3003 | cache = probe_cache__new(target); | ||
3004 | /* Return 0 ("not found") if the target has no probe cache. */ | ||
3005 | if (!cache) | ||
3006 | return 0; | ||
3007 | |||
3008 | for_each_probe_cache_entry(entry, cache) { | ||
3009 | /* Skip the cache entry which has no name */ | ||
3010 | if (!entry->pev.event || !entry->pev.group) | ||
3011 | continue; | ||
3012 | if ((!pev->group || strglobmatch(entry->pev.group, pev->group)) && | ||
3013 | strglobmatch(entry->pev.event, pev->event)) { | ||
3014 | ret = probe_cache_entry__get_event(entry, &tmp_tevs); | ||
3015 | if (ret > 0) | ||
3016 | ret = concat_probe_trace_events(tevs, &ntevs, | ||
3017 | &tmp_tevs, ret); | ||
3018 | if (ret < 0) | ||
3019 | break; | ||
3020 | } | ||
3021 | } | ||
3022 | probe_cache__delete(cache); | ||
3023 | if (ret < 0) { | ||
3024 | clear_probe_trace_events(*tevs, ntevs); | ||
3025 | zfree(tevs); | ||
3026 | } else { | ||
3027 | ret = ntevs; | ||
3028 | if (ntevs > 0 && target && target[0] == '/') | ||
3029 | pev->uprobes = true; | ||
3030 | } | ||
3031 | |||
3032 | return ret; | ||
3033 | } | ||
3034 | |||
3035 | /* Try to find probe_trace_event from all probe caches */ | ||
3036 | static int find_cached_events_all(struct perf_probe_event *pev, | ||
3037 | struct probe_trace_event **tevs) | ||
3038 | { | ||
3039 | struct probe_trace_event *tmp_tevs = NULL; | ||
3040 | struct strlist *bidlist; | ||
3041 | struct str_node *nd; | ||
3042 | char *pathname; | ||
3043 | int ntevs = 0; | ||
3044 | int ret; | ||
3045 | |||
3046 | /* Get the buildid list of all valid caches */ | ||
3047 | bidlist = build_id_cache__list_all(true); | ||
3048 | if (!bidlist) { | ||
3049 | ret = -errno; | ||
3050 | pr_debug("Failed to get buildids: %d\n", ret); | ||
3051 | return ret; | ||
3052 | } | ||
3053 | |||
3054 | ret = 0; | ||
3055 | strlist__for_each_entry(nd, bidlist) { | ||
3056 | pathname = build_id_cache__origname(nd->s); | ||
3057 | ret = find_cached_events(pev, &tmp_tevs, pathname); | ||
3058 | /* In the case of cnt == 0, we just skip it */ | ||
3059 | if (ret > 0) | ||
3060 | ret = concat_probe_trace_events(tevs, &ntevs, | ||
3061 | &tmp_tevs, ret); | ||
3062 | free(pathname); | ||
3063 | if (ret < 0) | ||
3064 | break; | ||
3065 | } | ||
3066 | strlist__delete(bidlist); | ||
3067 | |||
3068 | if (ret < 0) { | ||
3069 | clear_probe_trace_events(*tevs, ntevs); | ||
3070 | zfree(tevs); | ||
3071 | } else | ||
3072 | ret = ntevs; | ||
3073 | |||
3074 | return ret; | ||
3075 | } | ||
3076 | |||
2862 | static int find_probe_trace_events_from_cache(struct perf_probe_event *pev, | 3077 | static int find_probe_trace_events_from_cache(struct perf_probe_event *pev, |
2863 | struct probe_trace_event **tevs) | 3078 | struct probe_trace_event **tevs) |
2864 | { | 3079 | { |
@@ -2868,13 +3083,21 @@ static int find_probe_trace_events_from_cache(struct perf_probe_event *pev, | |||
2868 | struct str_node *node; | 3083 | struct str_node *node; |
2869 | int ret, i; | 3084 | int ret, i; |
2870 | 3085 | ||
3086 | if (pev->sdt) { | ||
3087 | /* For SDT/cached events, we use special search functions */ | ||
3088 | if (!pev->target) | ||
3089 | return find_cached_events_all(pev, tevs); | ||
3090 | else | ||
3091 | return find_cached_events(pev, tevs, pev->target); | ||
3092 | } | ||
2871 | cache = probe_cache__new(pev->target); | 3093 | cache = probe_cache__new(pev->target); |
2872 | if (!cache) | 3094 | if (!cache) |
2873 | return 0; | 3095 | return 0; |
2874 | 3096 | ||
2875 | entry = probe_cache__find(cache, pev); | 3097 | entry = probe_cache__find(cache, pev); |
2876 | if (!entry) { | 3098 | if (!entry) { |
2877 | ret = 0; | 3099 | /* SDT must be in the cache */ |
3100 | ret = pev->sdt ? -ENOENT : 0; | ||
2878 | goto out; | 3101 | goto out; |
2879 | } | 3102 | } |
2880 | 3103 | ||
@@ -2913,7 +3136,7 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev, | |||
2913 | { | 3136 | { |
2914 | int ret; | 3137 | int ret; |
2915 | 3138 | ||
2916 | if (!pev->group) { | 3139 | if (!pev->group && !pev->sdt) { |
2917 | /* Set group name if not given */ | 3140 | /* Set group name if not given */ |
2918 | if (!pev->uprobes) { | 3141 | if (!pev->uprobes) { |
2919 | pev->group = strdup(PERFPROBE_GROUP); | 3142 | pev->group = strdup(PERFPROBE_GROUP); |
@@ -2932,8 +3155,8 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev, | |||
2932 | 3155 | ||
2933 | /* At first, we need to lookup cache entry */ | 3156 | /* At first, we need to lookup cache entry */ |
2934 | ret = find_probe_trace_events_from_cache(pev, tevs); | 3157 | ret = find_probe_trace_events_from_cache(pev, tevs); |
2935 | if (ret > 0) | 3158 | if (ret > 0 || pev->sdt) /* SDT can be found only in the cache */ |
2936 | return ret; /* Found in probe cache */ | 3159 | return ret == 0 ? -ENOENT : ret; /* Found in probe cache */ |
2937 | 3160 | ||
2938 | if (arch__prefers_symtab() && !perf_probe_event_need_dwarf(pev)) { | 3161 | if (arch__prefers_symtab() && !perf_probe_event_need_dwarf(pev)) { |
2939 | ret = find_probe_trace_events_from_map(pev, tevs); | 3162 | ret = find_probe_trace_events_from_map(pev, tevs); |
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h index 432b690d3f17..e18ea9fe6385 100644 --- a/tools/perf/util/probe-event.h +++ b/tools/perf/util/probe-event.h | |||
@@ -85,6 +85,7 @@ struct perf_probe_event { | |||
85 | char *group; /* Group name */ | 85 | char *group; /* Group name */ |
86 | struct perf_probe_point point; /* Probe point */ | 86 | struct perf_probe_point point; /* Probe point */ |
87 | int nargs; /* Number of arguments */ | 87 | int nargs; /* Number of arguments */ |
88 | bool sdt; /* SDT/cached event flag */ | ||
88 | bool uprobes; /* Uprobe event flag */ | 89 | bool uprobes; /* Uprobe event flag */ |
89 | char *target; /* Target binary */ | 90 | char *target; /* Target binary */ |
90 | struct perf_probe_arg *args; /* Arguments */ | 91 | struct perf_probe_arg *args; /* Arguments */ |
diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c index e705a742ee1e..9aed9c332da6 100644 --- a/tools/perf/util/probe-file.c +++ b/tools/perf/util/probe-file.c | |||
@@ -362,13 +362,38 @@ probe_cache_entry__new(struct perf_probe_event *pev) | |||
362 | return entry; | 362 | return entry; |
363 | } | 363 | } |
364 | 364 | ||
365 | /* For the kernel probe caches, pass target = NULL */ | 365 | int probe_cache_entry__get_event(struct probe_cache_entry *entry, |
366 | struct probe_trace_event **tevs) | ||
367 | { | ||
368 | struct probe_trace_event *tev; | ||
369 | struct str_node *node; | ||
370 | int ret, i; | ||
371 | |||
372 | ret = strlist__nr_entries(entry->tevlist); | ||
373 | if (ret > probe_conf.max_probes) | ||
374 | return -E2BIG; | ||
375 | |||
376 | *tevs = zalloc(ret * sizeof(*tev)); | ||
377 | if (!*tevs) | ||
378 | return -ENOMEM; | ||
379 | |||
380 | i = 0; | ||
381 | strlist__for_each_entry(node, entry->tevlist) { | ||
382 | tev = &(*tevs)[i++]; | ||
383 | ret = parse_probe_trace_command(node->s, tev); | ||
384 | if (ret < 0) | ||
385 | break; | ||
386 | } | ||
387 | return i; | ||
388 | } | ||
389 | |||
390 | /* For the kernel probe caches, pass target = NULL or DSO__NAME_KALLSYMS */ | ||
366 | static int probe_cache__open(struct probe_cache *pcache, const char *target) | 391 | static int probe_cache__open(struct probe_cache *pcache, const char *target) |
367 | { | 392 | { |
368 | char cpath[PATH_MAX]; | 393 | char cpath[PATH_MAX]; |
369 | char sbuildid[SBUILD_ID_SIZE]; | 394 | char sbuildid[SBUILD_ID_SIZE]; |
370 | char *dir_name = NULL; | 395 | char *dir_name = NULL; |
371 | bool is_kallsyms = !target; | 396 | bool is_kallsyms = false; |
372 | int ret, fd; | 397 | int ret, fd; |
373 | 398 | ||
374 | if (target && build_id_cache__cached(target)) { | 399 | if (target && build_id_cache__cached(target)) { |
@@ -378,12 +403,13 @@ static int probe_cache__open(struct probe_cache *pcache, const char *target) | |||
378 | goto found; | 403 | goto found; |
379 | } | 404 | } |
380 | 405 | ||
381 | if (target) | 406 | if (!target || !strcmp(target, DSO__NAME_KALLSYMS)) { |
382 | ret = filename__sprintf_build_id(target, sbuildid); | ||
383 | else { | ||
384 | target = DSO__NAME_KALLSYMS; | 407 | target = DSO__NAME_KALLSYMS; |
408 | is_kallsyms = true; | ||
385 | ret = sysfs__sprintf_build_id("/", sbuildid); | 409 | ret = sysfs__sprintf_build_id("/", sbuildid); |
386 | } | 410 | } else |
411 | ret = filename__sprintf_build_id(target, sbuildid); | ||
412 | |||
387 | if (ret < 0) { | 413 | if (ret < 0) { |
388 | pr_debug("Failed to get build-id from %s.\n", target); | 414 | pr_debug("Failed to get build-id from %s.\n", target); |
389 | return ret; | 415 | return ret; |
@@ -546,7 +572,16 @@ probe_cache__find(struct probe_cache *pcache, struct perf_probe_event *pev) | |||
546 | if (!cmd) | 572 | if (!cmd) |
547 | return NULL; | 573 | return NULL; |
548 | 574 | ||
549 | list_for_each_entry(entry, &pcache->entries, node) { | 575 | for_each_probe_cache_entry(entry, pcache) { |
576 | if (pev->sdt) { | ||
577 | if (entry->pev.event && | ||
578 | streql(entry->pev.event, pev->event) && | ||
579 | (!pev->group || | ||
580 | streql(entry->pev.group, pev->group))) | ||
581 | goto found; | ||
582 | |||
583 | continue; | ||
584 | } | ||
550 | /* Hit if same event name or same command-string */ | 585 | /* Hit if same event name or same command-string */ |
551 | if ((pev->event && | 586 | if ((pev->event && |
552 | (streql(entry->pev.group, pev->group) && | 587 | (streql(entry->pev.group, pev->group) && |
@@ -567,7 +602,7 @@ probe_cache__find_by_name(struct probe_cache *pcache, | |||
567 | { | 602 | { |
568 | struct probe_cache_entry *entry = NULL; | 603 | struct probe_cache_entry *entry = NULL; |
569 | 604 | ||
570 | list_for_each_entry(entry, &pcache->entries, node) { | 605 | for_each_probe_cache_entry(entry, pcache) { |
571 | /* Hit if same event name or same command-string */ | 606 | /* Hit if same event name or same command-string */ |
572 | if (streql(entry->pev.group, group) && | 607 | if (streql(entry->pev.group, group) && |
573 | streql(entry->pev.event, event)) | 608 | streql(entry->pev.event, event)) |
@@ -739,7 +774,7 @@ int probe_cache__commit(struct probe_cache *pcache) | |||
739 | if (ret < 0) | 774 | if (ret < 0) |
740 | goto out; | 775 | goto out; |
741 | 776 | ||
742 | list_for_each_entry(entry, &pcache->entries, node) { | 777 | for_each_probe_cache_entry(entry, pcache) { |
743 | ret = probe_cache_entry__write(entry, pcache->fd); | 778 | ret = probe_cache_entry__write(entry, pcache->fd); |
744 | pr_debug("Cache committed: %d\n", ret); | 779 | pr_debug("Cache committed: %d\n", ret); |
745 | if (ret < 0) | 780 | if (ret < 0) |
@@ -781,7 +816,7 @@ static int probe_cache__show_entries(struct probe_cache *pcache, | |||
781 | { | 816 | { |
782 | struct probe_cache_entry *entry; | 817 | struct probe_cache_entry *entry; |
783 | 818 | ||
784 | list_for_each_entry(entry, &pcache->entries, node) { | 819 | for_each_probe_cache_entry(entry, pcache) { |
785 | if (probe_cache_entry__compare(entry, filter)) | 820 | if (probe_cache_entry__compare(entry, filter)) |
786 | printf("%s\n", entry->spev); | 821 | printf("%s\n", entry->spev); |
787 | } | 822 | } |
@@ -799,7 +834,7 @@ int probe_cache__show_all_caches(struct strfilter *filter) | |||
799 | pr_debug("list cache with filter: %s\n", buf); | 834 | pr_debug("list cache with filter: %s\n", buf); |
800 | free(buf); | 835 | free(buf); |
801 | 836 | ||
802 | bidlist = build_id_cache__list_all(); | 837 | bidlist = build_id_cache__list_all(true); |
803 | if (!bidlist) { | 838 | if (!bidlist) { |
804 | pr_debug("Failed to get buildids: %d\n", errno); | 839 | pr_debug("Failed to get buildids: %d\n", errno); |
805 | return -EINVAL; | 840 | return -EINVAL; |
diff --git a/tools/perf/util/probe-file.h b/tools/perf/util/probe-file.h index ddf5ae212c2f..9577b5c0b487 100644 --- a/tools/perf/util/probe-file.h +++ b/tools/perf/util/probe-file.h | |||
@@ -21,7 +21,11 @@ struct probe_cache { | |||
21 | 21 | ||
22 | #define PF_FL_UPROBE 1 | 22 | #define PF_FL_UPROBE 1 |
23 | #define PF_FL_RW 2 | 23 | #define PF_FL_RW 2 |
24 | #define for_each_probe_cache_entry(entry, pcache) \ | ||
25 | list_for_each_entry(entry, &pcache->entries, node) | ||
24 | 26 | ||
27 | /* probe-file.c depends on libelf */ | ||
28 | #ifdef HAVE_LIBELF_SUPPORT | ||
25 | int probe_file__open(int flag); | 29 | int probe_file__open(int flag); |
26 | int probe_file__open_both(int *kfd, int *ufd, int flag); | 30 | int probe_file__open_both(int *kfd, int *ufd, int flag); |
27 | struct strlist *probe_file__get_namelist(int fd); | 31 | struct strlist *probe_file__get_namelist(int fd); |
@@ -32,6 +36,9 @@ int probe_file__get_events(int fd, struct strfilter *filter, | |||
32 | struct strlist *plist); | 36 | struct strlist *plist); |
33 | int probe_file__del_strlist(int fd, struct strlist *namelist); | 37 | int probe_file__del_strlist(int fd, struct strlist *namelist); |
34 | 38 | ||
39 | int probe_cache_entry__get_event(struct probe_cache_entry *entry, | ||
40 | struct probe_trace_event **tevs); | ||
41 | |||
35 | struct probe_cache *probe_cache__new(const char *target); | 42 | struct probe_cache *probe_cache__new(const char *target); |
36 | int probe_cache__add_entry(struct probe_cache *pcache, | 43 | int probe_cache__add_entry(struct probe_cache *pcache, |
37 | struct perf_probe_event *pev, | 44 | struct perf_probe_event *pev, |
@@ -47,4 +54,11 @@ struct probe_cache_entry *probe_cache__find(struct probe_cache *pcache, | |||
47 | struct probe_cache_entry *probe_cache__find_by_name(struct probe_cache *pcache, | 54 | struct probe_cache_entry *probe_cache__find_by_name(struct probe_cache *pcache, |
48 | const char *group, const char *event); | 55 | const char *group, const char *event); |
49 | int probe_cache__show_all_caches(struct strfilter *filter); | 56 | int probe_cache__show_all_caches(struct strfilter *filter); |
57 | #else /* ! HAVE_LIBELF_SUPPORT */ | ||
58 | static inline struct probe_cache *probe_cache__new(const char *tgt __maybe_unused) | ||
59 | { | ||
60 | return NULL; | ||
61 | } | ||
62 | #define probe_cache__delete(pcache) do {} while (0) | ||
63 | #endif | ||
50 | #endif | 64 | #endif |