From: Jackie Liu <liuyun01@xxxxxxxxxx> Now multi kprobe uses glob_match for function matching, it's not enough, and sometimes we need more powerful regular expressions to support fuzzy matching, and now provides a use_regex in bpf_kprobe_multi_opts to support POSIX regular expressions. This is useful, similar to `funccount.py -r '^vfs.*'` in BCC, and can also be implemented with libbpf. Signed-off-by: Jackie Liu <liuyun01@xxxxxxxxxx> --- tools/lib/bpf/libbpf.c | 52 ++++++++++++++++++++++++++++++++++++++---- tools/lib/bpf/libbpf.h | 4 +++- 2 files changed, 51 insertions(+), 5 deletions(-) diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 81aa52fa6807..fd217e9a232d 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -25,6 +25,7 @@ #include <fcntl.h> #include <errno.h> #include <ctype.h> +#include <regex.h> #include <asm/unistd.h> #include <linux/err.h> #include <linux/kernel.h> @@ -10549,6 +10550,7 @@ struct kprobe_multi_resolve { unsigned long *addrs; size_t cap; size_t cnt; + bool use_regex; }; struct avail_kallsyms_data { @@ -10589,6 +10591,7 @@ static int libbpf_available_kallsyms_parse(struct kprobe_multi_resolve *res) int err = 0, ret, i; char **syms = NULL; size_t cap = 0, cnt = 0; + regex_t regex; f = fopen(available_functions_file, "re"); if (!f) { @@ -10597,6 +10600,18 @@ static int libbpf_available_kallsyms_parse(struct kprobe_multi_resolve *res) return err; } + if (res->use_regex) { + ret = regcomp(®ex, res->pattern, REG_EXTENDED | REG_NOSUB); + if (ret) { + char errbuf[128]; + + regerror(ret, ®ex, errbuf, sizeof(errbuf)); + pr_warn("Failed to compile regex: %s\n", errbuf); + fclose(f); + return -EINVAL; + } + } + while (true) { char *name; @@ -10610,8 +10625,13 @@ static int libbpf_available_kallsyms_parse(struct kprobe_multi_resolve *res) goto cleanup; } - if (!glob_match(sym_name, res->pattern)) - continue; + if (res->use_regex) { + if (regexec(®ex, sym_name, 0, NULL, 0)) + continue; + } else { + if (!glob_match(sym_name, res->pattern)) + continue; + } err = libbpf_ensure_mem((void **)&syms, &cap, sizeof(*syms), cnt + 1); if (err) @@ -10644,6 +10664,8 @@ static int libbpf_available_kallsyms_parse(struct kprobe_multi_resolve *res) err = -ENOENT; cleanup: + if (res->use_regex) + regfree(®ex); for (i = 0; i < cnt; i++) free((char *)syms[i]); free(syms); @@ -10664,6 +10686,7 @@ static int libbpf_available_kprobes_parse(struct kprobe_multi_resolve *res) FILE *f; int ret, err = 0; unsigned long long sym_addr; + regex_t regex; f = fopen(available_path, "re"); if (!f) { @@ -10672,6 +10695,18 @@ static int libbpf_available_kprobes_parse(struct kprobe_multi_resolve *res) return err; } + if (res->use_regex) { + ret = regcomp(®ex, res->pattern, REG_EXTENDED | REG_NOSUB); + if (ret) { + char errbuf[128]; + + regerror(ret, ®ex, errbuf, sizeof(errbuf)); + pr_warn("Failed to compile regex: %s\n", errbuf); + fclose(f); + return -EINVAL; + } + } + while (true) { ret = fscanf(f, "%llx %499s%*[^\n]\n", &sym_addr, sym_name); if (ret == EOF && feof(f)) @@ -10684,8 +10719,13 @@ static int libbpf_available_kprobes_parse(struct kprobe_multi_resolve *res) goto cleanup; } - if (!glob_match(sym_name, res->pattern)) - continue; + if (res->use_regex) { + if (regexec(®ex, sym_name, 0, NULL, 0)) + continue; + } else { + if (!glob_match(sym_name, res->pattern)) + continue; + } err = libbpf_ensure_mem((void **)&res->addrs, &res->cap, sizeof(*res->addrs), res->cnt + 1); @@ -10699,6 +10739,8 @@ static int libbpf_available_kprobes_parse(struct kprobe_multi_resolve *res) err = -ENOENT; cleanup: + if (res->use_regex) + regfree(®ex); fclose(f); return err; } @@ -10739,6 +10781,8 @@ bpf_program__attach_kprobe_multi_opts(const struct bpf_program *prog, return libbpf_err_ptr(-EINVAL); if (pattern) { + res.use_regex = OPTS_GET(opts, use_regex, false); + if (has_available_filter_functions_addrs()) err = libbpf_available_kprobes_parse(&res); else diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index 754da73c643b..34031c722213 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h @@ -519,10 +519,12 @@ struct bpf_kprobe_multi_opts { size_t cnt; /* create return kprobes */ bool retprobe; + /* use regular expression */ + bool use_regex; size_t :0; }; -#define bpf_kprobe_multi_opts__last_field retprobe +#define bpf_kprobe_multi_opts__last_field use_regex LIBBPF_API struct bpf_link * bpf_program__attach_kprobe_multi_opts(const struct bpf_program *prog, -- 2.25.1