@@ -10224,6 +10224,12 @@ static const char *tracefs_uprobe_events(void)
return use_debugfs() ? DEBUGFS"/uprobe_events" : TRACEFS"/uprobe_events";
}
+static const char *tracefs_available_filter_functions(void)
+{
+ return use_debugfs() ? DEBUGFS"/available_filter_functions" :
+ TRACEFS"/available_filter_functions";
+}
+
static void gen_kprobe_legacy_event_name(char *buf, size_t buf_sz,
const char *kfunc_name, size_t offset)
{
@@ -10539,23 +10545,113 @@ struct kprobe_multi_resolve {
size_t cnt;
};
-static int
-resolve_kprobe_multi_cb(unsigned long long sym_addr, char sym_type,
- const char *sym_name, void *ctx)
+static int qsort_compare_function(const void *a, const void *b)
{
- struct kprobe_multi_resolve *res = ctx;
- int err;
+ return strcmp(*(const char **)a, *(const char **)b);
+}
- if (!glob_match(sym_name, res->pattern))
- return 0;
+static int bsearch_compare_function(const void *a, const void *b)
+{
+ return strcmp((const char *)a, *(const char **)b);
+}
- err = libbpf_ensure_mem((void **) &res->addrs, &res->cap, sizeof(unsigned long),
- res->cnt + 1);
- if (err)
+static int libbpf_available_kallsyms_parse(struct kprobe_multi_resolve *res)
+{
+ char sym_name[500];
+ const char *available_functions_file = tracefs_available_filter_functions();
+ FILE *f;
+ int err = 0, ret, i;
+ const char **syms;
+ size_t cap = 0, cnt = 0;
+
+ f = fopen(available_functions_file, "r");
+ if (!f) {
+ err = -errno;
+ pr_warn("failed to open %s\n", available_functions_file);
return err;
+ }
- res->addrs[res->cnt++] = (unsigned long) sym_addr;
- return 0;
+ while (true) {
+ char *name;
+
+ ret = fscanf(f, "%499s%*[^\n]\n", sym_name);
+ if (ret == EOF && feof(f))
+ break;
+
+ if (ret != 1) {
+ pr_warn("failed to read available function file entry: %d\n",
+ ret);
+ err = -EINVAL;
+ goto cleanup;
+ }
+
+ if (!glob_match(sym_name, res->pattern))
+ continue;
+
+ err = libbpf_ensure_mem((void **)&syms, &cap, sizeof(void *),
+ cnt + 1);
+ if (err)
+ goto cleanup;
+
+ name = strdup(sym_name);
+ if (!name) {
+ err = -errno;
+ goto cleanup;
+ }
+
+ syms[cnt++] = name;
+ }
+ fclose(f);
+
+ /* not found entry, return direct */
+ if (!cnt)
+ return -ENOENT;
+
+ /* sort available functions */
+ qsort(syms, cnt, sizeof(void *), qsort_compare_function);
+
+ f = fopen("/proc/kallsyms", "r");
+ if (!f) {
+ err = -errno;
+ pr_warn("failed to open /proc/kallsyms\n");
+ goto free_syms;
+ }
+
+ while (true) {
+ unsigned long long sym_addr;
+
+ ret = fscanf(f, "%llx %*c %499s%*[^\n]\n", &sym_addr, sym_name);
+ if (ret == EOF && feof(f))
+ break;
+
+ if (ret != 2) {
+ pr_warn("failed to read kallsyms entry: %d\n", ret);
+ err = -EINVAL;
+ goto cleanup;
+ }
+
+ if (!bsearch(&sym_name, syms, cnt, sizeof(void *), bsearch_compare_function))
+ continue;
+
+ err = libbpf_ensure_mem((void **)&res->addrs, &res->cap,
+ sizeof(unsigned long), res->cnt + 1);
+ if (err)
+ goto cleanup;
+
+ res->addrs[res->cnt++] = (unsigned long) sym_addr;
+ }
+
+ if (!res->cnt)
+ err = -ENOENT;
+
+cleanup:
+ fclose(f);
+free_syms:
+ for (i = 0; i < cnt; i++)
+ free((char *)syms[i]);
+ free(syms);
+
+ return err;
}
struct bpf_link *
@@ -10594,13 +10690,9 @@ bpf_program__attach_kprobe_multi_opts(const struct bpf_program *prog,
return libbpf_err_ptr(-EINVAL);
if (pattern) {
- err = libbpf_kallsyms_parse(resolve_kprobe_multi_cb, &res);
+ err = libbpf_available_kallsyms_parse(&res);
if (err)
goto error;
- if (!res.cnt) {
- err = -ENOENT;
- goto error;
- }
addrs = res.addrs;
cnt = res.cnt;
}