Commit 03e01f56 authored by Wang Nan's avatar Wang Nan Committed by Arnaldo Carvalho de Melo

perf bpf: Allow BPF program config probing options

By extending the syntax of BPF object section names, this patch allows users to
config probing options like what they can do in 'perf probe'.

The error message in 'perf probe' is also updated.

Test result:

For following BPF file test_probe_glob.c:

  # cat test_probe_glob.c
  __attribute__((section("inlines=no;func=SyS_dup?"), used))

  int func(void *ctx)
  {
	  return 1;
  }

  char _license[] __attribute__((section("license"), used)) = "GPL";
  int _version __attribute__((section("version"), used)) = 0x40300;
  #
  # ./perf record  -e ./test_probe_glob.c ls /
  ...
  [ perf record: Woken up 1 times to write data ]
  [ perf record: Captured and wrote 0.013 MB perf.data ]
  # ./perf evlist
  perf_bpf_probe:func_1
  perf_bpf_probe:func

After changing "inlines=no" to "inlines=yes":

  # ./perf record  -e ./test_probe_glob.c ls /
  ...
  [ perf record: Woken up 2 times to write data ]
  [ perf record: Captured and wrote 0.013 MB perf.data ]
  # ./perf evlist
  perf_bpf_probe:func_3
  perf_bpf_probe:func_2
  perf_bpf_probe:func_1
  perf_bpf_probe:func

Then test 'force':

Use following program:

  # cat test_probe_force.c
  __attribute__((section("func=sys_write"), used))

  int funca(void *ctx)
  {
	  return 1;
  }

  __attribute__((section("force=yes;func=sys_write"), used))

  int funcb(void *ctx)
  {
  	return 1;
  }

  char _license[] __attribute__((section("license"), used)) = "GPL";
  int _version __attribute__((section("version"), used)) = 0x40300;
  #

  # perf record -e ./test_probe_force.c usleep 1
  Error: event "func" already exists.
   Hint: Remove existing event by 'perf probe -d'
       or force duplicates by 'perf probe -f'
       or set 'force=yes' in BPF source.
  event syntax error: './test_probe_force.c'
                       \___ Probe point exist. Try 'perf probe -d "*"' and set 'force=yes'

  (add -v to see detail)
  ...

Then replace 'force=no' to 'force=yes':

  # vim test_probe_force.c
  # perf record -e ./test_probe_force.c usleep 1
  [ perf record: Woken up 1 times to write data ]
  [ perf record: Captured and wrote 0.017 MB perf.data ]
  # perf evlist
  perf_bpf_probe:func_1
  perf_bpf_probe:func
  #
Signed-off-by: default avatarWang Nan <wangnan0@huawei.com>
Tested-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Zefan Li <lizefan@huawei.com>
Cc: pi3orama@163.com
Link: http://lkml.kernel.org/r/1447675815-166222-7-git-send-email-wangnan0@huawei.comSigned-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 5dbd16c0
......@@ -7,6 +7,7 @@
#include <bpf/libbpf.h>
#include <linux/err.h>
#include <linux/string.h>
#include "perf.h"
#include "debug.h"
#include "bpf-loader.h"
......@@ -129,6 +130,38 @@ config__module(const char *value, struct perf_probe_event *pev)
return 0;
}
static int
config__bool(const char *value,
bool *pbool, bool invert)
{
int err;
bool bool_value;
if (!pbool)
return -EINVAL;
err = strtobool(value, &bool_value);
if (err)
return err;
*pbool = invert ? !bool_value : bool_value;
return 0;
}
static int
config__inlines(const char *value,
struct perf_probe_event *pev __maybe_unused)
{
return config__bool(value, &probe_conf.no_inlines, true);
}
static int
config__force(const char *value,
struct perf_probe_event *pev __maybe_unused)
{
return config__bool(value, &probe_conf.force_add, false);
}
static struct {
const char *key;
const char *usage;
......@@ -146,7 +179,19 @@ static struct {
.usage = "module=<module name> ",
.desc = "Set kprobe module",
.func = config__module,
}
},
{
.key = "inlines",
.usage = "inlines=[yes|no] ",
.desc = "Probe at inline symbol",
.func = config__inlines,
},
{
.key = "force",
.usage = "force=[yes|no] ",
.desc = "Forcibly add events with existing name",
.func = config__force,
},
};
static int
......@@ -240,6 +285,10 @@ config_bpf_program(struct bpf_program *prog)
const char *config_str;
int err;
/* Initialize per-program probing setting */
probe_conf.no_inlines = false;
probe_conf.force_add = false;
config_str = bpf_program__title(prog, false);
if (IS_ERR(config_str)) {
pr_debug("bpf: unable to get title for program\n");
......@@ -544,7 +593,7 @@ int bpf__strerror_probe(struct bpf_object *obj __maybe_unused,
scnprintf(buf, size, "%s (add -v to see detail)", emsg);
break;
}
bpf__strerror_entry(EEXIST, "Probe point exist. Try use 'perf probe -d \"*\"'");
bpf__strerror_entry(EEXIST, "Probe point exist. Try 'perf probe -d \"*\"' and set 'force=yes'");
bpf__strerror_entry(EACCES, "You need to be root");
bpf__strerror_entry(EPERM, "You need to be root, and /proc/sys/kernel/kptr_restrict should be 0");
bpf__strerror_entry(ENOENT, "You need to check probing points in BPF file");
......
......@@ -2326,8 +2326,11 @@ static int get_new_event_name(char *buf, size_t len, const char *base,
goto out;
if (!allow_suffix) {
pr_warning("Error: event \"%s\" already exists. "
"(Use -f to force duplicates.)\n", buf);
pr_warning("Error: event \"%s\" already exists.\n"
" Hint: Remove existing event by 'perf probe -d'\n"
" or force duplicates by 'perf probe -f'\n"
" or set 'force=yes' in BPF source.\n",
buf);
ret = -EEXIST;
goto out;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment