Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Wang Nan and committed by
Arnaldo Carvalho de Melo
b4ee6d41 cd102d70

+60 -5
+60 -5
tools/perf/util/bpf-loader.c
··· 37 37 DEFINE_PRINT_FN(debug, 1) 38 38 39 39 struct bpf_prog_priv { 40 + bool is_tp; 41 + char *sys_name; 42 + char *evt_name; 40 43 struct perf_probe_event pev; 41 44 bool need_prologue; 42 45 struct bpf_insn *insns_buf; ··· 121 118 cleanup_perf_probe_events(&priv->pev, 1); 122 119 zfree(&priv->insns_buf); 123 120 zfree(&priv->type_mapping); 121 + zfree(&priv->sys_name); 122 + zfree(&priv->evt_name); 124 123 free(priv); 125 124 } 126 125 ··· 274 269 } 275 270 276 271 static int 277 - parse_prog_config(const char *config_str, struct perf_probe_event *pev) 272 + parse_prog_config(const char *config_str, const char **p_main_str, 273 + bool *is_tp, struct perf_probe_event *pev) 278 274 { 279 275 int err; 280 276 const char *main_str = parse_prog_config_kvpair(config_str, pev); ··· 283 277 if (IS_ERR(main_str)) 284 278 return PTR_ERR(main_str); 285 279 280 + *p_main_str = main_str; 281 + if (!strchr(main_str, '=')) { 282 + /* Is a tracepoint event? */ 283 + const char *s = strchr(main_str, ':'); 284 + 285 + if (!s) { 286 + pr_debug("bpf: '%s' is not a valid tracepoint\n", 287 + config_str); 288 + return -BPF_LOADER_ERRNO__CONFIG; 289 + } 290 + 291 + *is_tp = true; 292 + return 0; 293 + } 294 + 295 + *is_tp = false; 286 296 err = parse_perf_probe_command(main_str, pev); 287 297 if (err < 0) { 288 298 pr_debug("bpf: '%s' is not a valid config string\n", ··· 314 292 { 315 293 struct perf_probe_event *pev = NULL; 316 294 struct bpf_prog_priv *priv = NULL; 317 - const char *config_str; 295 + const char *config_str, *main_str; 296 + bool is_tp = false; 318 297 int err; 319 298 320 299 /* Initialize per-program probing setting */ ··· 336 313 pev = &priv->pev; 337 314 338 315 pr_debug("bpf: config program '%s'\n", config_str); 339 - err = parse_prog_config(config_str, pev); 316 + err = parse_prog_config(config_str, &main_str, &is_tp, pev); 340 317 if (err) 341 318 goto errout; 319 + 320 + if (is_tp) { 321 + char *s = strchr(main_str, ':'); 322 + 323 + priv->is_tp = true; 324 + priv->sys_name = strndup(main_str, s - main_str); 325 + priv->evt_name = strdup(s + 1); 326 + goto set_priv; 327 + } 342 328 343 329 if (pev->group && strcmp(pev->group, PERF_BPF_PROBE_GROUP)) { 344 330 pr_debug("bpf: '%s': group for event is set and not '%s'.\n", ··· 371 339 } 372 340 pr_debug("bpf: config '%s' is ok\n", config_str); 373 341 342 + set_priv: 374 343 err = bpf_program__set_priv(prog, priv, clear_prog_priv); 375 344 if (err) { 376 345 pr_debug("Failed to set priv for program '%s'\n", config_str); ··· 420 387 size_t prologue_cnt = 0; 421 388 int i, err; 422 389 423 - if (IS_ERR(priv) || !priv) 390 + if (IS_ERR(priv) || !priv || priv->is_tp) 424 391 goto errout; 425 392 426 393 pev = &priv->pev; ··· 577 544 return -BPF_LOADER_ERRNO__INTERNAL; 578 545 } 579 546 547 + if (priv->is_tp) { 548 + priv->need_prologue = false; 549 + return 0; 550 + } 551 + 580 552 pev = &priv->pev; 581 553 for (i = 0; i < pev->ntevs; i++) { 582 554 struct probe_trace_event *tev = &pev->tevs[i]; ··· 648 610 err = PTR_ERR(priv); 649 611 goto out; 650 612 } 613 + 614 + if (priv->is_tp) { 615 + bpf_program__set_tracepoint(prog); 616 + continue; 617 + } 618 + 619 + bpf_program__set_kprobe(prog); 651 620 pev = &priv->pev; 652 621 653 622 err = convert_perf_probe_events(pev, 1); ··· 695 650 struct bpf_prog_priv *priv = bpf_program__priv(prog); 696 651 int i; 697 652 698 - if (IS_ERR(priv) || !priv) 653 + if (IS_ERR(priv) || !priv || priv->is_tp) 699 654 continue; 700 655 701 656 for (i = 0; i < priv->pev.ntevs; i++) { ··· 754 709 if (IS_ERR(priv) || !priv) { 755 710 pr_debug("bpf: failed to get private field\n"); 756 711 return -BPF_LOADER_ERRNO__INTERNAL; 712 + } 713 + 714 + if (priv->is_tp) { 715 + fd = bpf_program__fd(prog); 716 + err = (*func)(priv->sys_name, priv->evt_name, fd, arg); 717 + if (err) { 718 + pr_debug("bpf: tracepoint call back failed, stop iterate\n"); 719 + return err; 720 + } 721 + continue; 757 722 } 758 723 759 724 pev = &priv->pev;