Commit 3140cf12 authored by Jiri Olsa's avatar Jiri Olsa Committed by Alexei Starovoitov
Browse files

libbpf: Add bpf_program__attach_uprobe_multi function



Adding bpf_program__attach_uprobe_multi function that
allows to attach multiple uprobes with uprobe_multi link.

The user can specify uprobes with direct arguments:

  binary_path/func_pattern/pid

or with struct bpf_uprobe_multi_opts opts argument fields:

  const char **syms;
  const unsigned long *offsets;
  const unsigned long *ref_ctr_offsets;
  const __u64 *cookies;

User can specify 2 mutually exclusive set of inputs:

 1) use only path/func_pattern/pid arguments

 2) use path/pid with allowed combinations of:
    syms/offsets/ref_ctr_offsets/cookies/cnt

    - syms and offsets are mutually exclusive
    - ref_ctr_offsets and cookies are optional

Any other usage results in error.

Signed-off-by: default avatarJiri Olsa <jolsa@kernel.org>
Link: https://lore.kernel.org/r/20230809083440.3209381-15-jolsa@kernel.org


Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parent 5054a303
Loading
Loading
Loading
Loading
+114 −0
Original line number Diff line number Diff line
@@ -11146,6 +11146,120 @@ static int resolve_full_path(const char *file, char *result, size_t result_sz)
	return -ENOENT;
}

struct bpf_link *
bpf_program__attach_uprobe_multi(const struct bpf_program *prog,
				 pid_t pid,
				 const char *path,
				 const char *func_pattern,
				 const struct bpf_uprobe_multi_opts *opts)
{
	const unsigned long *ref_ctr_offsets = NULL, *offsets = NULL;
	LIBBPF_OPTS(bpf_link_create_opts, lopts);
	unsigned long *resolved_offsets = NULL;
	int err = 0, link_fd, prog_fd;
	struct bpf_link *link = NULL;
	char errmsg[STRERR_BUFSIZE];
	char full_path[PATH_MAX];
	const __u64 *cookies;
	const char **syms;
	size_t cnt;

	if (!OPTS_VALID(opts, bpf_uprobe_multi_opts))
		return libbpf_err_ptr(-EINVAL);

	syms = OPTS_GET(opts, syms, NULL);
	offsets = OPTS_GET(opts, offsets, NULL);
	ref_ctr_offsets = OPTS_GET(opts, ref_ctr_offsets, NULL);
	cookies = OPTS_GET(opts, cookies, NULL);
	cnt = OPTS_GET(opts, cnt, 0);

	/*
	 * User can specify 2 mutually exclusive set of inputs:
	 *
	 * 1) use only path/func_pattern/pid arguments
	 *
	 * 2) use path/pid with allowed combinations of:
	 *    syms/offsets/ref_ctr_offsets/cookies/cnt
	 *
	 *    - syms and offsets are mutually exclusive
	 *    - ref_ctr_offsets and cookies are optional
	 *
	 * Any other usage results in error.
	 */

	if (!path)
		return libbpf_err_ptr(-EINVAL);
	if (!func_pattern && cnt == 0)
		return libbpf_err_ptr(-EINVAL);

	if (func_pattern) {
		if (syms || offsets || ref_ctr_offsets || cookies || cnt)
			return libbpf_err_ptr(-EINVAL);
	} else {
		if (!!syms == !!offsets)
			return libbpf_err_ptr(-EINVAL);
	}

	if (func_pattern) {
		if (!strchr(path, '/')) {
			err = resolve_full_path(path, full_path, sizeof(full_path));
			if (err) {
				pr_warn("prog '%s': failed to resolve full path for '%s': %d\n",
					prog->name, path, err);
				return libbpf_err_ptr(err);
			}
			path = full_path;
		}

		err = elf_resolve_pattern_offsets(path, func_pattern,
						  &resolved_offsets, &cnt);
		if (err < 0)
			return libbpf_err_ptr(err);
		offsets = resolved_offsets;
	} else if (syms) {
		err = elf_resolve_syms_offsets(path, cnt, syms, &resolved_offsets);
		if (err < 0)
			return libbpf_err_ptr(err);
		offsets = resolved_offsets;
	}

	lopts.uprobe_multi.path = path;
	lopts.uprobe_multi.offsets = offsets;
	lopts.uprobe_multi.ref_ctr_offsets = ref_ctr_offsets;
	lopts.uprobe_multi.cookies = cookies;
	lopts.uprobe_multi.cnt = cnt;
	lopts.uprobe_multi.flags = OPTS_GET(opts, retprobe, false) ? BPF_F_UPROBE_MULTI_RETURN : 0;

	if (pid == 0)
		pid = getpid();
	if (pid > 0)
		lopts.uprobe_multi.pid = pid;

	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_UPROBE_MULTI, &lopts);
	if (link_fd < 0) {
		err = -errno;
		pr_warn("prog '%s': failed to attach multi-uprobe: %s\n",
			prog->name, libbpf_strerror_r(err, errmsg, sizeof(errmsg)));
		goto error;
	}
	link->fd = link_fd;
	free(resolved_offsets);
	return link;

error:
	free(resolved_offsets);
	free(link);
	return libbpf_err_ptr(err);
}

LIBBPF_API struct bpf_link *
bpf_program__attach_uprobe_opts(const struct bpf_program *prog, pid_t pid,
				const char *binary_path, size_t func_offset,
+51 −0
Original line number Diff line number Diff line
@@ -529,6 +529,57 @@ bpf_program__attach_kprobe_multi_opts(const struct bpf_program *prog,
				      const char *pattern,
				      const struct bpf_kprobe_multi_opts *opts);

struct bpf_uprobe_multi_opts {
	/* size of this struct, for forward/backward compatibility */
	size_t sz;
	/* array of function symbols to attach to */
	const char **syms;
	/* array of function addresses to attach to */
	const unsigned long *offsets;
	/* optional, array of associated ref counter offsets */
	const unsigned long *ref_ctr_offsets;
	/* optional, array of associated BPF cookies */
	const __u64 *cookies;
	/* number of elements in syms/addrs/cookies arrays */
	size_t cnt;
	/* create return uprobes */
	bool retprobe;
	size_t :0;
};

#define bpf_uprobe_multi_opts__last_field retprobe

/**
 * @brief **bpf_program__attach_uprobe_multi()** attaches a BPF program
 * to multiple uprobes with uprobe_multi link.
 *
 * User can specify 2 mutually exclusive set of inputs:
 *
 *   1) use only path/func_pattern/pid arguments
 *
 *   2) use path/pid with allowed combinations of
 *      syms/offsets/ref_ctr_offsets/cookies/cnt
 *
 *      - syms and offsets are mutually exclusive
 *      - ref_ctr_offsets and cookies are optional
 *
 *
 * @param prog BPF program to attach
 * @param pid Process ID to attach the uprobe to, 0 for self (own process),
 * -1 for all processes
 * @param binary_path Path to binary
 * @param func_pattern Regular expression to specify functions to attach
 * BPF program to
 * @param opts Additional options (see **struct bpf_uprobe_multi_opts**)
 * @return 0, on success; negative error code, otherwise
 */
LIBBPF_API struct bpf_link *
bpf_program__attach_uprobe_multi(const struct bpf_program *prog,
				 pid_t pid,
				 const char *binary_path,
				 const char *func_pattern,
				 const struct bpf_uprobe_multi_opts *opts);

struct bpf_ksyscall_opts {
	/* size of this struct, for forward/backward compatibility */
	size_t sz;
+1 −0
Original line number Diff line number Diff line
@@ -398,4 +398,5 @@ LIBBPF_1.3.0 {
		bpf_prog_detach_opts;
		bpf_program__attach_netfilter;
		bpf_program__attach_tcx;
		bpf_program__attach_uprobe_multi;
} LIBBPF_1.2.0;