aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWang Nan <wangnan0@huawei.com>2016-07-13 06:44:05 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2016-07-13 22:09:04 -0400
commitb4ee6d415e731b9d8a51451da0ebe33450c355d2 (patch)
tree533e82570803fae1deedf84c62d433d5f74613ef
parentcd102d70fe957b060b9df6bc4f54684de3fe00cd (diff)
perf bpf: Support BPF program attach to tracepoints
To support 98b5c2c65c29 ("perf, bpf: allow bpf programs attach to tracepoints"), this patch allows BPF scripts to select tracepoints in their section name. Example: # cat test_tracepoint.c /*********************************************/ #include <uapi/linux/bpf.h> #define SEC(NAME) __attribute__((section(NAME), used)) SEC("raw_syscalls:sys_enter") int func(void *ctx) { /* * /sys/kernel/debug/tracing/events/raw_syscalls/sys_enter/format: * ... * field:long id; offset:8; size:8; signed:1; * ... * ctx + 8 select 'id' */ u64 id = *((u64 *)(ctx + 8)); if (id == 1) return 1; return 0; } SEC("_write=sys_write") int _write(void *ctx) { return 1; } char _license[] SEC("license") = "GPL"; int _version SEC("version") = LINUX_VERSION_CODE; /*********************************************/ # perf record -e ./test_tracepoint.c dd if=/dev/zero of=/dev/null count=5 5+0 records in 5+0 records out 2560 bytes (2.6 kB) copied, 6.2281e-05 s, 41.1 MB/s [ perf record: Woken up 1 times to write data ] # perf script dd 13436 [005] 1596.490869: raw_syscalls:sys_enter: NR 1 (1, 178d000, 200, 7ffe82470d60, ffffffffffffe020, fffff dd 13436 [005] 1596.490871: perf_bpf_probe:_write: (ffffffff812351e0) dd 13436 [005] 1596.490873: raw_syscalls:sys_enter: NR 1 (1, 178d000, 200, ffffffffffffe000, ffffffffffffe020, f dd 13436 [005] 1596.490874: perf_bpf_probe:_write: (ffffffff812351e0) dd 13436 [005] 1596.490876: raw_syscalls:sys_enter: NR 1 (1, 178d000, 200, ffffffffffffe000, ffffffffffffe020, f dd 13436 [005] 1596.490876: perf_bpf_probe:_write: (ffffffff812351e0) dd 13436 [005] 1596.490878: raw_syscalls:sys_enter: NR 1 (1, 178d000, 200, ffffffffffffe000, ffffffffffffe020, f dd 13436 [005] 1596.490879: perf_bpf_probe:_write: (ffffffff812351e0) dd 13436 [005] 1596.490881: raw_syscalls:sys_enter: NR 1 (1, 178d000, 200, ffffffffffffe000, ffffffffffffe020, f dd 13436 [005] 1596.490882: perf_bpf_probe:_write: (ffffffff812351e0) dd 13436 [005] 1596.490900: raw_syscalls:sys_enter: NR 1 (2, 7ffe8246e640, 1f, 40acb8, 7f44bac74700, 7f44baa4fba dd 13436 [005] 1596.490901: perf_bpf_probe:_write: (ffffffff812351e0) dd 13436 [005] 1596.490917: raw_syscalls:sys_enter: NR 1 (2, 7ffe8246e640, 1a, fffffffa, 7f44bac74700, 7f44baa4f dd 13436 [005] 1596.490918: perf_bpf_probe:_write: (ffffffff812351e0) dd 13436 [005] 1596.490932: raw_syscalls:sys_enter: NR 1 (2, 7ffe8246e640, 1a, fffffff9, 7f44bac74700, 7f44baa4f dd 13436 [005] 1596.490933: perf_bpf_probe:_write: (ffffffff812351e0) Committer note: Further testing: # trace --no-sys --event /home/acme/bpf/tracepoint.c cat /etc/passwd > /dev/null 0.000 raw_syscalls:sys_enter:NR 1 (1, 7f0490504000, c48, 7f0490503010, ffffffffffffffff, 0)) 0.006 perf_bpf_probe:_write:(ffffffff81241bc0)) # Signed-off-by: Wang Nan <wangnan0@huawei.com> Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Alexei Starovoitov <ast@kernel.org> Cc: Jiri Olsa <jolsa@kernel.org> Cc: Zefan Li <lizefan@huawei.com> Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1468406646-21642-6-git-send-email-wangnan0@huawei.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-rw-r--r--tools/perf/util/bpf-loader.c65
1 files changed, 60 insertions, 5 deletions
diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c
index f22701497112..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)
37DEFINE_PRINT_FN(debug, 1) 37DEFINE_PRINT_FN(debug, 1)
38 38
39struct bpf_prog_priv { 39struct 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
271static int 276static int
272parse_prog_config(const char *config_str, struct perf_probe_event *pev) 277parse_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
374set_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++) {
@@ -711,6 +756,16 @@ int bpf__foreach_event(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];