From b4ee6d415e731b9d8a51451da0ebe33450c355d2 Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Wed, 13 Jul 2016 10:44:05 +0000 Subject: [PATCH] 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 #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 Tested-by: Arnaldo Carvalho de Melo Cc: Alexei Starovoitov Cc: Jiri Olsa Cc: Zefan Li 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 --- tools/perf/util/bpf-loader.c | 65 +++++++++++++++++++++++++++++++++--- 1 file 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) DEFINE_PRINT_FN(debug, 1) struct bpf_prog_priv { + bool is_tp; + char *sys_name; + char *evt_name; struct perf_probe_event pev; bool need_prologue; struct bpf_insn *insns_buf; @@ -118,6 +121,8 @@ clear_prog_priv(struct bpf_program *prog __maybe_unused, cleanup_perf_probe_events(&priv->pev, 1); zfree(&priv->insns_buf); zfree(&priv->type_mapping); + zfree(&priv->sys_name); + zfree(&priv->evt_name); free(priv); } @@ -269,7 +274,8 @@ nextline: } static int -parse_prog_config(const char *config_str, struct perf_probe_event *pev) +parse_prog_config(const char *config_str, const char **p_main_str, + bool *is_tp, struct perf_probe_event *pev) { int err; 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) if (IS_ERR(main_str)) return PTR_ERR(main_str); + *p_main_str = main_str; + if (!strchr(main_str, '=')) { + /* Is a tracepoint event? */ + const char *s = strchr(main_str, ':'); + + if (!s) { + pr_debug("bpf: '%s' is not a valid tracepoint\n", + config_str); + return -BPF_LOADER_ERRNO__CONFIG; + } + + *is_tp = true; + return 0; + } + + *is_tp = false; err = parse_perf_probe_command(main_str, pev); if (err < 0) { pr_debug("bpf: '%s' is not a valid config string\n", @@ -292,7 +314,8 @@ config_bpf_program(struct bpf_program *prog) { struct perf_probe_event *pev = NULL; struct bpf_prog_priv *priv = NULL; - const char *config_str; + const char *config_str, *main_str; + bool is_tp = false; int err; /* Initialize per-program probing setting */ @@ -313,10 +336,19 @@ config_bpf_program(struct bpf_program *prog) pev = &priv->pev; pr_debug("bpf: config program '%s'\n", config_str); - err = parse_prog_config(config_str, pev); + err = parse_prog_config(config_str, &main_str, &is_tp, pev); if (err) goto errout; + if (is_tp) { + char *s = strchr(main_str, ':'); + + priv->is_tp = true; + priv->sys_name = strndup(main_str, s - main_str); + priv->evt_name = strdup(s + 1); + goto set_priv; + } + if (pev->group && strcmp(pev->group, PERF_BPF_PROBE_GROUP)) { pr_debug("bpf: '%s': group for event is set and not '%s'.\n", config_str, PERF_BPF_PROBE_GROUP); @@ -339,6 +371,7 @@ config_bpf_program(struct bpf_program *prog) } pr_debug("bpf: config '%s' is ok\n", config_str); +set_priv: err = bpf_program__set_priv(prog, priv, clear_prog_priv); if (err) { 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, size_t prologue_cnt = 0; int i, err; - if (IS_ERR(priv) || !priv) + if (IS_ERR(priv) || !priv || priv->is_tp) goto errout; pev = &priv->pev; @@ -544,6 +577,11 @@ static int hook_load_preprocessor(struct bpf_program *prog) return -BPF_LOADER_ERRNO__INTERNAL; } + if (priv->is_tp) { + priv->need_prologue = false; + return 0; + } + pev = &priv->pev; for (i = 0; i < pev->ntevs; i++) { struct probe_trace_event *tev = &pev->tevs[i]; @@ -610,6 +648,13 @@ int bpf__probe(struct bpf_object *obj) err = PTR_ERR(priv); goto out; } + + if (priv->is_tp) { + bpf_program__set_tracepoint(prog); + continue; + } + + bpf_program__set_kprobe(prog); pev = &priv->pev; err = convert_perf_probe_events(pev, 1); @@ -650,7 +695,7 @@ int bpf__unprobe(struct bpf_object *obj) struct bpf_prog_priv *priv = bpf_program__priv(prog); int i; - if (IS_ERR(priv) || !priv) + if (IS_ERR(priv) || !priv || priv->is_tp) continue; for (i = 0; i < priv->pev.ntevs; i++) { @@ -711,6 +756,16 @@ int bpf__foreach_event(struct bpf_object *obj, return -BPF_LOADER_ERRNO__INTERNAL; } + if (priv->is_tp) { + fd = bpf_program__fd(prog); + err = (*func)(priv->sys_name, priv->evt_name, fd, arg); + if (err) { + pr_debug("bpf: tracepoint call back failed, stop iterate\n"); + return err; + } + continue; + } + pev = &priv->pev; for (i = 0; i < pev->ntevs; i++) { tev = &pev->tevs[i]; -- 2.20.1