aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf
diff options
context:
space:
mode:
authorWang Nan <wangnan0@huawei.com>2015-10-14 08:41:15 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2015-10-28 11:48:13 -0400
commitaa3abf30bb28addcf593578d37447d42e3f65fc3 (patch)
treec5a0d8de1ffc58bada4bd9c7edf7da24aa34be9b /tools/perf
parent84c86ca12b2189df751eed7b2d67cb63bc8feda5 (diff)
perf tools: Create probe points for BPF programs
This patch introduces bpf__{un,}probe() functions to enable callers to create kprobe points based on section names a BPF program. It parses the section names in the program and creates corresponding 'struct perf_probe_event' structures. The parse_perf_probe_command() function is used to do the main parsing work. The resuling 'struct perf_probe_event' is stored into program private data for further using. By utilizing the new probing API, this patch creates probe points during event parsing. To ensure probe points be removed correctly, register an atexit hook so even perf quit through exit() bpf__clear() is still called, so probing points are cleared. Note that bpf_clear() should be registered before bpf__probe() is called, so failure of bpf__probe() can still trigger bpf__clear() to remove probe points which are already probed. strerror style error reporting scaffold is created by this patch. bpf__strerror_probe() is the first error reporting function in bpf-loader.c. Committer note: Trying it: To build a test eBPF object file: I am testing using a script I built from the 'perf test -v LLVM' output: $ cat ~/bin/hello-ebpf export KERNEL_INC_OPTIONS="-nostdinc -isystem /usr/lib/gcc/x86_64-redhat-linux/4.8.3/include -I/home/acme/git/linux/arch/x86/include -Iarch/x86/include/generated/uapi -Iarch/x86/include/generated -I/home/acme/git/linux/include -Iinclude -I/home/acme/git/linux/arch/x86/include/uapi -Iarch/x86/include/generated/uapi -I/home/acme/git/linux/include/uapi -Iinclude/generated/uapi -include /home/acme/git/linux/include/linux/kconfig.h" export WORKING_DIR=/lib/modules/4.2.0/build export CLANG_SOURCE=- export CLANG_OPTIONS=-xc OBJ=/tmp/foo.o rm -f $OBJ echo '__attribute__((section("fork=do_fork"), used)) int fork(void *ctx) {return 0;} char _license[] __attribute__((section("license"), used)) = "GPL";int _version __attribute__((section("version"), used)) = 0x40100;' | \ clang -D__KERNEL__ $CLANG_OPTIONS $KERNEL_INC_OPTIONS -Wno-unused-value -Wno-pointer-sign -working-directory $WORKING_DIR -c "$CLANG_SOURCE" -target bpf -O2 -o /tmp/foo.o && file $OBJ --- First asking to put a probe in a function not present in the kernel (misses the initial _): $ perf record --event /tmp/foo.o sleep 1 Probe point 'do_fork' not found. event syntax error: '/tmp/foo.o' \___ You need to check probing points in BPF file (add -v to see detail) Run 'perf list' for a list of valid events Usage: perf record [<options>] [<command>] or: perf record [<options>] -- <command> [<options>] -e, --event <event> event selector. use 'perf list' to list available events $ --- Now, with "__attribute__((section("fork=_do_fork"), used)): $ grep _do_fork /proc/kallsyms ffffffff81099ab0 T _do_fork $ perf record --event /tmp/foo.o sleep 1 Failed to open kprobe_events: Permission denied event syntax error: '/tmp/foo.o' \___ Permission denied --- Cool, we need to provide some better hints, "kprobe_events" is too low level, one doesn't strictly need to know the precise details of how these things are put in place, so something that shows the command needed to fix the permissions would be more helpful. Lets try as root instead: # perf record --event /tmp/foo.o sleep 1 Lowering default frequency rate to 1000. Please consider tweaking /proc/sys/kernel/perf_event_max_sample_rate. [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.013 MB perf.data ] # perf evlist /tmp/foo.o [root@felicio ~]# perf evlist -v /tmp/foo.o: type: 1, size: 112, config: 0x9, { sample_period, sample_freq }: 1000, sample_type: IP|TID|TIME|PERIOD, disabled: 1, inherit: 1, mmap: 1, comm: 1, freq: 1, enable_on_exec: 1, task: 1, sample_id_all: 1, exclude_guest: 1, mmap2: 1, comm_exec: 1 --- Signed-off-by: Wang Nan <wangnan0@huawei.com> Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Alexei Starovoitov <ast@plumgrid.com> Cc: Brendan Gregg <brendan.d.gregg@gmail.com> Cc: Daniel Borkmann <daniel@iogearbox.net> Cc: David Ahern <dsahern@gmail.com> Cc: He Kuang <hekuang@huawei.com> Cc: Jiri Olsa <jolsa@kernel.org> Cc: Kaixu Xia <xiakaixu@huawei.com> Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Zefan Li <lizefan@huawei.com> Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1444826502-49291-5-git-send-email-wangnan0@huawei.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf')
-rw-r--r--tools/perf/util/bpf-loader.c222
-rw-r--r--tools/perf/util/bpf-loader.h30
-rw-r--r--tools/perf/util/parse-events.c17
3 files changed, 268 insertions, 1 deletions
diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c
index ab56073c5d6e..56f6fe8cf318 100644
--- a/tools/perf/util/bpf-loader.c
+++ b/tools/perf/util/bpf-loader.c
@@ -10,6 +10,8 @@
10#include "perf.h" 10#include "perf.h"
11#include "debug.h" 11#include "debug.h"
12#include "bpf-loader.h" 12#include "bpf-loader.h"
13#include "probe-event.h"
14#include "probe-finder.h" // for MAX_PROBES
13 15
14#define DEFINE_PRINT_FN(name, level) \ 16#define DEFINE_PRINT_FN(name, level) \
15static int libbpf_##name(const char *fmt, ...) \ 17static int libbpf_##name(const char *fmt, ...) \
@@ -27,6 +29,10 @@ DEFINE_PRINT_FN(warning, 0)
27DEFINE_PRINT_FN(info, 0) 29DEFINE_PRINT_FN(info, 0)
28DEFINE_PRINT_FN(debug, 1) 30DEFINE_PRINT_FN(debug, 1)
29 31
32struct bpf_prog_priv {
33 struct perf_probe_event pev;
34};
35
30struct bpf_object *bpf__prepare_load(const char *filename) 36struct bpf_object *bpf__prepare_load(const char *filename)
31{ 37{
32 struct bpf_object *obj; 38 struct bpf_object *obj;
@@ -52,6 +58,220 @@ void bpf__clear(void)
52{ 58{
53 struct bpf_object *obj, *tmp; 59 struct bpf_object *obj, *tmp;
54 60
55 bpf_object__for_each_safe(obj, tmp) 61 bpf_object__for_each_safe(obj, tmp) {
62 bpf__unprobe(obj);
56 bpf_object__close(obj); 63 bpf_object__close(obj);
64 }
65}
66
67static void
68bpf_prog_priv__clear(struct bpf_program *prog __maybe_unused,
69 void *_priv)
70{
71 struct bpf_prog_priv *priv = _priv;
72
73 cleanup_perf_probe_events(&priv->pev, 1);
74 free(priv);
75}
76
77static int
78config_bpf_program(struct bpf_program *prog)
79{
80 struct perf_probe_event *pev = NULL;
81 struct bpf_prog_priv *priv = NULL;
82 const char *config_str;
83 int err;
84
85 config_str = bpf_program__title(prog, false);
86 if (!config_str) {
87 pr_debug("bpf: unable to get title for program\n");
88 return -EINVAL;
89 }
90
91 priv = calloc(sizeof(*priv), 1);
92 if (!priv) {
93 pr_debug("bpf: failed to alloc priv\n");
94 return -ENOMEM;
95 }
96 pev = &priv->pev;
97
98 pr_debug("bpf: config program '%s'\n", config_str);
99 err = parse_perf_probe_command(config_str, pev);
100 if (err < 0) {
101 pr_debug("bpf: '%s' is not a valid config string\n",
102 config_str);
103 err = -EINVAL;
104 goto errout;
105 }
106
107 if (pev->group && strcmp(pev->group, PERF_BPF_PROBE_GROUP)) {
108 pr_debug("bpf: '%s': group for event is set and not '%s'.\n",
109 config_str, PERF_BPF_PROBE_GROUP);
110 err = -EINVAL;
111 goto errout;
112 } else if (!pev->group)
113 pev->group = strdup(PERF_BPF_PROBE_GROUP);
114
115 if (!pev->group) {
116 pr_debug("bpf: strdup failed\n");
117 err = -ENOMEM;
118 goto errout;
119 }
120
121 if (!pev->event) {
122 pr_debug("bpf: '%s': event name is missing\n",
123 config_str);
124 err = -EINVAL;
125 goto errout;
126 }
127 pr_debug("bpf: config '%s' is ok\n", config_str);
128
129 err = bpf_program__set_private(prog, priv, bpf_prog_priv__clear);
130 if (err) {
131 pr_debug("Failed to set priv for program '%s'\n", config_str);
132 goto errout;
133 }
134
135 return 0;
136
137errout:
138 if (pev)
139 clear_perf_probe_event(pev);
140 free(priv);
141 return err;
142}
143
144static int bpf__prepare_probe(void)
145{
146 static int err = 0;
147 static bool initialized = false;
148
149 /*
150 * Make err static, so if init failed the first, bpf__prepare_probe()
151 * fails each time without calling init_probe_symbol_maps multiple
152 * times.
153 */
154 if (initialized)
155 return err;
156
157 initialized = true;
158 err = init_probe_symbol_maps(false);
159 if (err < 0)
160 pr_debug("Failed to init_probe_symbol_maps\n");
161 probe_conf.max_probes = MAX_PROBES;
162 return err;
163}
164
165int bpf__probe(struct bpf_object *obj)
166{
167 int err = 0;
168 struct bpf_program *prog;
169 struct bpf_prog_priv *priv;
170 struct perf_probe_event *pev;
171
172 err = bpf__prepare_probe();
173 if (err) {
174 pr_debug("bpf__prepare_probe failed\n");
175 return err;
176 }
177
178 bpf_object__for_each_program(prog, obj) {
179 err = config_bpf_program(prog);
180 if (err)
181 goto out;
182
183 err = bpf_program__get_private(prog, (void **)&priv);
184 if (err || !priv)
185 goto out;
186 pev = &priv->pev;
187
188 err = convert_perf_probe_events(pev, 1);
189 if (err < 0) {
190 pr_debug("bpf_probe: failed to convert perf probe events");
191 goto out;
192 }
193
194 err = apply_perf_probe_events(pev, 1);
195 if (err < 0) {
196 pr_debug("bpf_probe: failed to apply perf probe events");
197 goto out;
198 }
199 }
200out:
201 return err < 0 ? err : 0;
202}
203
204#define EVENTS_WRITE_BUFSIZE 4096
205int bpf__unprobe(struct bpf_object *obj)
206{
207 int err, ret = 0;
208 struct bpf_program *prog;
209 struct bpf_prog_priv *priv;
210
211 bpf_object__for_each_program(prog, obj) {
212 int i;
213
214 err = bpf_program__get_private(prog, (void **)&priv);
215 if (err || !priv)
216 continue;
217
218 for (i = 0; i < priv->pev.ntevs; i++) {
219 struct probe_trace_event *tev = &priv->pev.tevs[i];
220 char name_buf[EVENTS_WRITE_BUFSIZE];
221 struct strfilter *delfilter;
222
223 snprintf(name_buf, EVENTS_WRITE_BUFSIZE,
224 "%s:%s", tev->group, tev->event);
225 name_buf[EVENTS_WRITE_BUFSIZE - 1] = '\0';
226
227 delfilter = strfilter__new(name_buf, NULL);
228 if (!delfilter) {
229 pr_debug("Failed to create filter for unprobing\n");
230 ret = -ENOMEM;
231 continue;
232 }
233
234 err = del_perf_probe_events(delfilter);
235 strfilter__delete(delfilter);
236 if (err) {
237 pr_debug("Failed to delete %s\n", name_buf);
238 ret = err;
239 continue;
240 }
241 }
242 }
243 return ret;
244}
245
246#define bpf__strerror_head(err, buf, size) \
247 char sbuf[STRERR_BUFSIZE], *emsg;\
248 if (!size)\
249 return 0;\
250 if (err < 0)\
251 err = -err;\
252 emsg = strerror_r(err, sbuf, sizeof(sbuf));\
253 switch (err) {\
254 default:\
255 scnprintf(buf, size, "%s", emsg);\
256 break;
257
258#define bpf__strerror_entry(val, fmt...)\
259 case val: {\
260 scnprintf(buf, size, fmt);\
261 break;\
262 }
263
264#define bpf__strerror_end(buf, size)\
265 }\
266 buf[size - 1] = '\0';
267
268int bpf__strerror_probe(struct bpf_object *obj __maybe_unused,
269 int err, char *buf, size_t size)
270{
271 bpf__strerror_head(err, buf, size);
272 bpf__strerror_entry(EEXIST, "Probe point exist. Try use 'perf probe -d \"*\"'");
273 bpf__strerror_entry(EPERM, "You need to be root, and /proc/sys/kernel/kptr_restrict should be 0\n");
274 bpf__strerror_entry(ENOENT, "You need to check probing points in BPF file\n");
275 bpf__strerror_end(buf, size);
276 return 0;
57} 277}
diff --git a/tools/perf/util/bpf-loader.h b/tools/perf/util/bpf-loader.h
index f402d7c8c288..b819622dc7ce 100644
--- a/tools/perf/util/bpf-loader.h
+++ b/tools/perf/util/bpf-loader.h
@@ -11,11 +11,18 @@
11#include "debug.h" 11#include "debug.h"
12 12
13struct bpf_object; 13struct bpf_object;
14#define PERF_BPF_PROBE_GROUP "perf_bpf_probe"
14 15
15#ifdef HAVE_LIBBPF_SUPPORT 16#ifdef HAVE_LIBBPF_SUPPORT
16struct bpf_object *bpf__prepare_load(const char *filename); 17struct bpf_object *bpf__prepare_load(const char *filename);
17 18
18void bpf__clear(void); 19void bpf__clear(void);
20
21int bpf__probe(struct bpf_object *obj);
22int bpf__unprobe(struct bpf_object *obj);
23int bpf__strerror_probe(struct bpf_object *obj, int err,
24 char *buf, size_t size);
25
19#else 26#else
20static inline struct bpf_object * 27static inline struct bpf_object *
21bpf__prepare_load(const char *filename __maybe_unused) 28bpf__prepare_load(const char *filename __maybe_unused)
@@ -25,5 +32,28 @@ bpf__prepare_load(const char *filename __maybe_unused)
25} 32}
26 33
27static inline void bpf__clear(void) { } 34static inline void bpf__clear(void) { }
35
36static inline int bpf__probe(struct bpf_object *obj __maybe_unused) { return 0;}
37static inline int bpf__unprobe(struct bpf_object *obj __maybe_unused) { return 0;}
38
39static inline int
40__bpf_strerror(char *buf, size_t size)
41{
42 if (!size)
43 return 0;
44 strncpy(buf,
45 "ERROR: eBPF object loading is disabled during compiling.\n",
46 size);
47 buf[size - 1] = '\0';
48 return 0;
49}
50
51static inline int
52bpf__strerror_probe(struct bpf_object *obj __maybe_unused,
53 int err __maybe_unused,
54 char *buf, size_t size)
55{
56 return __bpf_strerror(buf, size);
57}
28#endif 58#endif
29#endif 59#endif
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index a9e1d79d17d7..10a946779f46 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -536,6 +536,7 @@ int parse_events_load_bpf_obj(struct parse_events_evlist *data,
536{ 536{
537 int err; 537 int err;
538 char errbuf[BUFSIZ]; 538 char errbuf[BUFSIZ];
539 static bool registered_unprobe_atexit = false;
539 540
540 if (IS_ERR(obj) || !obj) { 541 if (IS_ERR(obj) || !obj) {
541 snprintf(errbuf, sizeof(errbuf), 542 snprintf(errbuf, sizeof(errbuf),
@@ -545,6 +546,22 @@ int parse_events_load_bpf_obj(struct parse_events_evlist *data,
545 } 546 }
546 547
547 /* 548 /*
549 * Register atexit handler before calling bpf__probe() so
550 * bpf__probe() don't need to unprobe probe points its already
551 * created when failure.
552 */
553 if (!registered_unprobe_atexit) {
554 atexit(bpf__clear);
555 registered_unprobe_atexit = true;
556 }
557
558 err = bpf__probe(obj);
559 if (err) {
560 bpf__strerror_probe(obj, err, errbuf, sizeof(errbuf));
561 goto errout;
562 }
563
564 /*
548 * Temporary add a dummy event here so we can check whether 565 * Temporary add a dummy event here so we can check whether
549 * basic bpf loader works. Following patches will replace 566 * basic bpf loader works. Following patches will replace
550 * dummy event by useful evsels. 567 * dummy event by useful evsels.