bpf.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Jiri Olsa <jolsa@kernel.org>
To: Alexei Starovoitov <ast@kernel.org>,
	Daniel Borkmann <daniel@iogearbox.net>,
	Andrii Nakryiko <andrii@kernel.org>,
	Masami Hiramatsu <mhiramat@kernel.org>
Cc: Masami Hiramatsu <mhiramat@redhat.com>,
	Yucong Sun <fallentree@fb.com>,
	netdev@vger.kernel.org, bpf@vger.kernel.org,
	lkml <linux-kernel@vger.kernel.org>,
	Martin KaFai Lau <kafai@fb.com>, Song Liu <songliubraving@fb.com>,
	Yonghong Song <yhs@fb.com>,
	John Fastabend <john.fastabend@gmail.com>,
	KP Singh <kpsingh@chromium.org>,
	Steven Rostedt <rostedt@goodmis.org>
Subject: [PATCH 08/10] libbpf: Add bpf_program__attach_kprobe_opts support for multi kprobes
Date: Tue, 22 Feb 2022 18:05:58 +0100	[thread overview]
Message-ID: <20220222170600.611515-9-jolsa@kernel.org> (raw)
In-Reply-To: <20220222170600.611515-1-jolsa@kernel.org>

Adding support to bpf_program__attach_kprobe_opts to attach kprobes
to multiple functions.

If the kprobe program has BPF_TRACE_KPROBE_MULTI as expected_attach_type
it will use the new kprobe_multi link to attach the program. In this case
it will use 'func_name' as pattern for functions to attach.

Adding also new section types 'kprobe.multi' and kretprobe.multi'
that allows to specify wildcards (*?) for functions, like:

  SEC("kprobe.multi/bpf_fentry_test*")
  SEC("kretprobe.multi/bpf_fentry_test?")

This will set kprobe's expected_attach_type to BPF_TRACE_KPROBE_MULTI,
and attach it to functions provided by the function pattern.

Using glob_match from selftests/bpf/test_progs.c and adding support to
match '?' based on original perf code.

Cc: Masami Hiramatsu <mhiramat@redhat.com>
Cc: Yucong Sun <fallentree@fb.com>
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 tools/lib/bpf/libbpf.c | 130 +++++++++++++++++++++++++++++++++++++++--
 1 file changed, 125 insertions(+), 5 deletions(-)

diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index fb530b004a0d..9bee2d70b99d 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -8622,6 +8622,8 @@ static const struct bpf_sec_def section_defs[] = {
 	SEC_DEF("uprobe/",		KPROBE,	0, SEC_NONE),
 	SEC_DEF("kretprobe/",		KPROBE, 0, SEC_NONE, attach_kprobe),
 	SEC_DEF("uretprobe/",		KPROBE, 0, SEC_NONE),
+	SEC_DEF("kprobe.multi/",	KPROBE,	BPF_TRACE_KPROBE_MULTI, SEC_NONE, attach_kprobe),
+	SEC_DEF("kretprobe.multi/",	KPROBE,	BPF_TRACE_KPROBE_MULTI, SEC_NONE, attach_kprobe),
 	SEC_DEF("tc",			SCHED_CLS, 0, SEC_NONE),
 	SEC_DEF("classifier",		SCHED_CLS, 0, SEC_NONE | SEC_SLOPPY_PFX | SEC_DEPRECATED),
 	SEC_DEF("action",		SCHED_ACT, 0, SEC_NONE | SEC_SLOPPY_PFX),
@@ -10038,6 +10040,113 @@ static int perf_event_kprobe_open_legacy(const char *probe_name, bool retprobe,
 	return pfd;
 }
 
+/* Adapted from perf/util/string.c */
+static bool glob_match(const char *str, const char *pat)
+{
+	while (*str && *pat && *pat != '*') {
+		if (*pat == '?') {      /* Matches any single character */
+			str++;
+			pat++;
+			continue;
+		}
+		if (*str != *pat)
+			return false;
+		str++;
+		pat++;
+	}
+	/* Check wild card */
+	if (*pat == '*') {
+		while (*pat == '*')
+			pat++;
+		if (!*pat) /* Tail wild card matches all */
+			return true;
+		while (*str)
+			if (glob_match(str++, pat))
+				return true;
+	}
+	return !*str && !*pat;
+}
+
+struct kprobe_multi_resolve {
+	const char *name;
+	__u64 *addrs;
+	size_t cap;
+	size_t cnt;
+};
+
+static int
+resolve_kprobe_multi_cb(unsigned long long sym_addr, char sym_type,
+			const char *sym_name, void *ctx)
+{
+	struct kprobe_multi_resolve *res = ctx;
+	int err;
+
+	if (!glob_match(sym_name, res->name))
+		return 0;
+
+	err = libbpf_ensure_mem((void **)&res->addrs, &res->cap, sizeof(__u64),
+				res->cnt + 1);
+	if (err)
+		return err;
+
+	res->addrs[res->cnt++] = sym_addr;
+	return 0;
+}
+
+static struct bpf_link *
+attach_kprobe_multi_opts(const struct bpf_program *prog,
+		   const char *func_pattern,
+		   const struct bpf_kprobe_opts *kopts)
+{
+	DECLARE_LIBBPF_OPTS(bpf_link_create_opts, opts);
+	struct kprobe_multi_resolve res = {
+		.name = func_pattern,
+	};
+	struct bpf_link *link = NULL;
+	char errmsg[STRERR_BUFSIZE];
+	int err, link_fd, prog_fd;
+	bool retprobe;
+
+	err = libbpf_kallsyms_parse(resolve_kprobe_multi_cb, &res);
+	if (err)
+		goto error;
+	if (!res.cnt) {
+		err = -ENOENT;
+		goto error;
+	}
+
+	retprobe = OPTS_GET(kopts, retprobe, false);
+
+	opts.kprobe_multi.addrs = ptr_to_u64(res.addrs);
+	opts.kprobe_multi.cnt = res.cnt;
+	opts.flags = retprobe ? BPF_F_KPROBE_MULTI_RETURN : 0;
+
+	link = calloc(1, sizeof(*link));
+	if (!link) {
+		err = -ENOMEM;
+		goto error;
+	}
+	link->detach = &bpf_link__detach_fd;
+
+	prog_fd = bpf_program__fd(prog);
+	link_fd = bpf_link_create(prog_fd, 0, BPF_TRACE_KPROBE_MULTI, &opts);
+	if (link_fd < 0) {
+		err = -errno;
+		pr_warn("prog '%s': failed to attach to %s: %s\n",
+			prog->name, res.name,
+			libbpf_strerror_r(err, errmsg, sizeof(errmsg)));
+		goto error;
+	}
+	link->fd = link_fd;
+	free(res.addrs);
+	return link;
+
+error:
+	free(link);
+	free(res.addrs);
+	return libbpf_err_ptr(err);
+}
+
 struct bpf_link *
 bpf_program__attach_kprobe_opts(const struct bpf_program *prog,
 				const char *func_name,
@@ -10054,6 +10163,9 @@ bpf_program__attach_kprobe_opts(const struct bpf_program *prog,
 	if (!OPTS_VALID(opts, bpf_kprobe_opts))
 		return libbpf_err_ptr(-EINVAL);
 
+	if (prog->expected_attach_type == BPF_TRACE_KPROBE_MULTI)
+		return attach_kprobe_multi_opts(prog, func_name, opts);
+
 	retprobe = OPTS_GET(opts, retprobe, false);
 	offset = OPTS_GET(opts, offset, 0);
 	pe_opts.bpf_cookie = OPTS_GET(opts, bpf_cookie, 0);
@@ -10122,19 +10234,27 @@ struct bpf_link *bpf_program__attach_kprobe(const struct bpf_program *prog,
 static struct bpf_link *attach_kprobe(const struct bpf_program *prog, long cookie)
 {
 	DECLARE_LIBBPF_OPTS(bpf_kprobe_opts, opts);
+	const char *func_name = NULL;
 	unsigned long offset = 0;
 	struct bpf_link *link;
-	const char *func_name;
 	char *func;
 	int n, err;
 
-	opts.retprobe = str_has_pfx(prog->sec_name, "kretprobe/");
-	if (opts.retprobe)
+	opts.retprobe = str_has_pfx(prog->sec_name, "kretprobe");
+
+	if (str_has_pfx(prog->sec_name, "kretprobe/"))
 		func_name = prog->sec_name + sizeof("kretprobe/") - 1;
-	else
+	else if (str_has_pfx(prog->sec_name, "kprobe/"))
 		func_name = prog->sec_name + sizeof("kprobe/") - 1;
+	else if (str_has_pfx(prog->sec_name, "kretprobe.multi/"))
+		func_name = prog->sec_name + sizeof("kretprobe.multi/") - 1;
+	else if (str_has_pfx(prog->sec_name, "kprobe.multi/"))
+		func_name = prog->sec_name + sizeof("kprobe.multi/") - 1;
+
+	if (!func_name)
+		return libbpf_err_ptr(-EINVAL);
 
-	n = sscanf(func_name, "%m[a-zA-Z0-9_.]+%li", &func, &offset);
+	n = sscanf(func_name, "%m[a-zA-Z0-9_.*?]+%li", &func, &offset);
 	if (n < 1) {
 		err = -EINVAL;
 		pr_warn("kprobe name is invalid: %s\n", func_name);
-- 
2.35.1


  parent reply	other threads:[~2022-02-22 17:08 UTC|newest]

Thread overview: 39+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-02-22 17:05 [PATCHv2 bpf-next 0/8] bpf: Add kprobe multi link Jiri Olsa
2022-02-22 17:05 ` [PATCH 01/10] lib/sort: Add priv pointer to swap function Jiri Olsa
2022-02-23  3:22   ` Masami Hiramatsu
2022-02-22 17:05 ` [PATCH 02/10] bpf: Add multi kprobe link Jiri Olsa
2022-02-23  5:58   ` Masami Hiramatsu
2022-02-23 17:44     ` Jiri Olsa
2022-02-24  4:02       ` Masami Hiramatsu
2022-03-04 23:11   ` Andrii Nakryiko
2022-03-06 17:28     ` Jiri Olsa
2022-03-08  1:23       ` Andrii Nakryiko
2022-03-08 14:21         ` Jiri Olsa
2022-02-22 17:05 ` [PATCH 03/10] bpf: Add bpf_get_func_ip kprobe helper for " Jiri Olsa
2022-03-04 23:11   ` Andrii Nakryiko
2022-02-22 17:05 ` [PATCH 04/10] bpf: Add support to inline bpf_get_func_ip helper on x86 Jiri Olsa
2022-02-22 17:05 ` [PATCH 05/10] bpf: Add cookie support to programs attached with kprobe multi link Jiri Olsa
2022-03-04 23:11   ` Andrii Nakryiko
2022-03-06 17:29     ` Jiri Olsa
2022-03-08  1:23       ` Andrii Nakryiko
2022-03-08 14:27         ` Jiri Olsa
2022-02-22 17:05 ` [PATCH 06/10] libbpf: Add libbpf_kallsyms_parse function Jiri Olsa
2022-03-04 23:11   ` Andrii Nakryiko
2022-02-22 17:05 ` [PATCH 07/10] libbpf: Add bpf_link_create support for multi kprobes Jiri Olsa
2022-03-04 23:11   ` Andrii Nakryiko
2022-03-06 17:29     ` Jiri Olsa
2022-02-22 17:05 ` Jiri Olsa [this message]
2022-03-04 23:11   ` [PATCH 08/10] libbpf: Add bpf_program__attach_kprobe_opts " Andrii Nakryiko
2022-03-06 17:29     ` Jiri Olsa
2022-03-08  1:28       ` Andrii Nakryiko
2022-03-08 14:23         ` Jiri Olsa
2022-02-22 17:05 ` [PATCH 09/10] selftest/bpf: Add kprobe_multi attach test Jiri Olsa
2022-03-04 23:11   ` Andrii Nakryiko
2022-03-06 17:29     ` Jiri Olsa
2022-02-22 17:06 ` [PATCH 10/10] selftest/bpf: Add kprobe_multi test for bpf_cookie values Jiri Olsa
2022-03-04 23:11   ` Andrii Nakryiko
2022-03-06 17:29     ` Jiri Olsa
2022-03-04 23:10 ` [PATCHv2 bpf-next 0/8] bpf: Add kprobe multi link Andrii Nakryiko
2022-03-06  1:09   ` Steven Rostedt
2022-03-06  1:32     ` Masami Hiramatsu
2022-03-08  1:45       ` Andrii Nakryiko

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220222170600.611515-9-jolsa@kernel.org \
    --to=jolsa@kernel.org \
    --cc=andrii@kernel.org \
    --cc=ast@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=fallentree@fb.com \
    --cc=john.fastabend@gmail.com \
    --cc=kafai@fb.com \
    --cc=kpsingh@chromium.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mhiramat@kernel.org \
    --cc=mhiramat@redhat.com \
    --cc=netdev@vger.kernel.org \
    --cc=rostedt@goodmis.org \
    --cc=songliubraving@fb.com \
    --cc=yhs@fb.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).