Skip to content

Commit 3140cf1

Browse files
olsajiriAlexei Starovoitov
authored andcommitted
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: Jiri Olsa <jolsa@kernel.org> Link: https://lore.kernel.org/r/20230809083440.3209381-15-jolsa@kernel.org Signed-off-by: Alexei Starovoitov <ast@kernel.org>
1 parent 5054a30 commit 3140cf1

3 files changed

Lines changed: 166 additions & 0 deletions

File tree

tools/lib/bpf/libbpf.c

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11146,6 +11146,120 @@ static int resolve_full_path(const char *file, char *result, size_t result_sz)
1114611146
return -ENOENT;
1114711147
}
1114811148

11149+
struct bpf_link *
11150+
bpf_program__attach_uprobe_multi(const struct bpf_program *prog,
11151+
pid_t pid,
11152+
const char *path,
11153+
const char *func_pattern,
11154+
const struct bpf_uprobe_multi_opts *opts)
11155+
{
11156+
const unsigned long *ref_ctr_offsets = NULL, *offsets = NULL;
11157+
LIBBPF_OPTS(bpf_link_create_opts, lopts);
11158+
unsigned long *resolved_offsets = NULL;
11159+
int err = 0, link_fd, prog_fd;
11160+
struct bpf_link *link = NULL;
11161+
char errmsg[STRERR_BUFSIZE];
11162+
char full_path[PATH_MAX];
11163+
const __u64 *cookies;
11164+
const char **syms;
11165+
size_t cnt;
11166+
11167+
if (!OPTS_VALID(opts, bpf_uprobe_multi_opts))
11168+
return libbpf_err_ptr(-EINVAL);
11169+
11170+
syms = OPTS_GET(opts, syms, NULL);
11171+
offsets = OPTS_GET(opts, offsets, NULL);
11172+
ref_ctr_offsets = OPTS_GET(opts, ref_ctr_offsets, NULL);
11173+
cookies = OPTS_GET(opts, cookies, NULL);
11174+
cnt = OPTS_GET(opts, cnt, 0);
11175+
11176+
/*
11177+
* User can specify 2 mutually exclusive set of inputs:
11178+
*
11179+
* 1) use only path/func_pattern/pid arguments
11180+
*
11181+
* 2) use path/pid with allowed combinations of:
11182+
* syms/offsets/ref_ctr_offsets/cookies/cnt
11183+
*
11184+
* - syms and offsets are mutually exclusive
11185+
* - ref_ctr_offsets and cookies are optional
11186+
*
11187+
* Any other usage results in error.
11188+
*/
11189+
11190+
if (!path)
11191+
return libbpf_err_ptr(-EINVAL);
11192+
if (!func_pattern && cnt == 0)
11193+
return libbpf_err_ptr(-EINVAL);
11194+
11195+
if (func_pattern) {
11196+
if (syms || offsets || ref_ctr_offsets || cookies || cnt)
11197+
return libbpf_err_ptr(-EINVAL);
11198+
} else {
11199+
if (!!syms == !!offsets)
11200+
return libbpf_err_ptr(-EINVAL);
11201+
}
11202+
11203+
if (func_pattern) {
11204+
if (!strchr(path, '/')) {
11205+
err = resolve_full_path(path, full_path, sizeof(full_path));
11206+
if (err) {
11207+
pr_warn("prog '%s': failed to resolve full path for '%s': %d\n",
11208+
prog->name, path, err);
11209+
return libbpf_err_ptr(err);
11210+
}
11211+
path = full_path;
11212+
}
11213+
11214+
err = elf_resolve_pattern_offsets(path, func_pattern,
11215+
&resolved_offsets, &cnt);
11216+
if (err < 0)
11217+
return libbpf_err_ptr(err);
11218+
offsets = resolved_offsets;
11219+
} else if (syms) {
11220+
err = elf_resolve_syms_offsets(path, cnt, syms, &resolved_offsets);
11221+
if (err < 0)
11222+
return libbpf_err_ptr(err);
11223+
offsets = resolved_offsets;
11224+
}
11225+
11226+
lopts.uprobe_multi.path = path;
11227+
lopts.uprobe_multi.offsets = offsets;
11228+
lopts.uprobe_multi.ref_ctr_offsets = ref_ctr_offsets;
11229+
lopts.uprobe_multi.cookies = cookies;
11230+
lopts.uprobe_multi.cnt = cnt;
11231+
lopts.uprobe_multi.flags = OPTS_GET(opts, retprobe, false) ? BPF_F_UPROBE_MULTI_RETURN : 0;
11232+
11233+
if (pid == 0)
11234+
pid = getpid();
11235+
if (pid > 0)
11236+
lopts.uprobe_multi.pid = pid;
11237+
11238+
link = calloc(1, sizeof(*link));
11239+
if (!link) {
11240+
err = -ENOMEM;
11241+
goto error;
11242+
}
11243+
link->detach = &bpf_link__detach_fd;
11244+
11245+
prog_fd = bpf_program__fd(prog);
11246+
link_fd = bpf_link_create(prog_fd, 0, BPF_TRACE_UPROBE_MULTI, &lopts);
11247+
if (link_fd < 0) {
11248+
err = -errno;
11249+
pr_warn("prog '%s': failed to attach multi-uprobe: %s\n",
11250+
prog->name, libbpf_strerror_r(err, errmsg, sizeof(errmsg)));
11251+
goto error;
11252+
}
11253+
link->fd = link_fd;
11254+
free(resolved_offsets);
11255+
return link;
11256+
11257+
error:
11258+
free(resolved_offsets);
11259+
free(link);
11260+
return libbpf_err_ptr(err);
11261+
}
11262+
1114911263
LIBBPF_API struct bpf_link *
1115011264
bpf_program__attach_uprobe_opts(const struct bpf_program *prog, pid_t pid,
1115111265
const char *binary_path, size_t func_offset,

tools/lib/bpf/libbpf.h

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -529,6 +529,57 @@ bpf_program__attach_kprobe_multi_opts(const struct bpf_program *prog,
529529
const char *pattern,
530530
const struct bpf_kprobe_multi_opts *opts);
531531

532+
struct bpf_uprobe_multi_opts {
533+
/* size of this struct, for forward/backward compatibility */
534+
size_t sz;
535+
/* array of function symbols to attach to */
536+
const char **syms;
537+
/* array of function addresses to attach to */
538+
const unsigned long *offsets;
539+
/* optional, array of associated ref counter offsets */
540+
const unsigned long *ref_ctr_offsets;
541+
/* optional, array of associated BPF cookies */
542+
const __u64 *cookies;
543+
/* number of elements in syms/addrs/cookies arrays */
544+
size_t cnt;
545+
/* create return uprobes */
546+
bool retprobe;
547+
size_t :0;
548+
};
549+
550+
#define bpf_uprobe_multi_opts__last_field retprobe
551+
552+
/**
553+
* @brief **bpf_program__attach_uprobe_multi()** attaches a BPF program
554+
* to multiple uprobes with uprobe_multi link.
555+
*
556+
* User can specify 2 mutually exclusive set of inputs:
557+
*
558+
* 1) use only path/func_pattern/pid arguments
559+
*
560+
* 2) use path/pid with allowed combinations of
561+
* syms/offsets/ref_ctr_offsets/cookies/cnt
562+
*
563+
* - syms and offsets are mutually exclusive
564+
* - ref_ctr_offsets and cookies are optional
565+
*
566+
*
567+
* @param prog BPF program to attach
568+
* @param pid Process ID to attach the uprobe to, 0 for self (own process),
569+
* -1 for all processes
570+
* @param binary_path Path to binary
571+
* @param func_pattern Regular expression to specify functions to attach
572+
* BPF program to
573+
* @param opts Additional options (see **struct bpf_uprobe_multi_opts**)
574+
* @return 0, on success; negative error code, otherwise
575+
*/
576+
LIBBPF_API struct bpf_link *
577+
bpf_program__attach_uprobe_multi(const struct bpf_program *prog,
578+
pid_t pid,
579+
const char *binary_path,
580+
const char *func_pattern,
581+
const struct bpf_uprobe_multi_opts *opts);
582+
532583
struct bpf_ksyscall_opts {
533584
/* size of this struct, for forward/backward compatibility */
534585
size_t sz;

tools/lib/bpf/libbpf.map

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,4 +398,5 @@ LIBBPF_1.3.0 {
398398
bpf_prog_detach_opts;
399399
bpf_program__attach_netfilter;
400400
bpf_program__attach_tcx;
401+
bpf_program__attach_uprobe_multi;
401402
} LIBBPF_1.2.0;

0 commit comments

Comments
 (0)