Merge git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next
[linux-2.6-microblaze.git] / tools / lib / bpf / libbpf.c
index 6f5e275..4ccfae3 100644 (file)
@@ -3894,6 +3894,42 @@ static int bpf_map_find_btf_info(struct bpf_object *obj, struct bpf_map *map)
        return 0;
 }
 
+static int bpf_get_map_info_from_fdinfo(int fd, struct bpf_map_info *info)
+{
+       char file[PATH_MAX], buff[4096];
+       FILE *fp;
+       __u32 val;
+       int err;
+
+       snprintf(file, sizeof(file), "/proc/%d/fdinfo/%d", getpid(), fd);
+       memset(info, 0, sizeof(*info));
+
+       fp = fopen(file, "r");
+       if (!fp) {
+               err = -errno;
+               pr_warn("failed to open %s: %d. No procfs support?\n", file,
+                       err);
+               return err;
+       }
+
+       while (fgets(buff, sizeof(buff), fp)) {
+               if (sscanf(buff, "map_type:\t%u", &val) == 1)
+                       info->type = val;
+               else if (sscanf(buff, "key_size:\t%u", &val) == 1)
+                       info->key_size = val;
+               else if (sscanf(buff, "value_size:\t%u", &val) == 1)
+                       info->value_size = val;
+               else if (sscanf(buff, "max_entries:\t%u", &val) == 1)
+                       info->max_entries = val;
+               else if (sscanf(buff, "map_flags:\t%i", &val) == 1)
+                       info->map_flags = val;
+       }
+
+       fclose(fp);
+
+       return 0;
+}
+
 int bpf_map__reuse_fd(struct bpf_map *map, int fd)
 {
        struct bpf_map_info info = {};
@@ -3902,6 +3938,8 @@ int bpf_map__reuse_fd(struct bpf_map *map, int fd)
        char *new_name;
 
        err = bpf_obj_get_info_by_fd(fd, &info, &len);
+       if (err && errno == EINVAL)
+               err = bpf_get_map_info_from_fdinfo(fd, &info);
        if (err)
                return libbpf_err(err);
 
@@ -4381,12 +4419,16 @@ static bool map_is_reuse_compat(const struct bpf_map *map, int map_fd)
        struct bpf_map_info map_info = {};
        char msg[STRERR_BUFSIZE];
        __u32 map_info_len;
+       int err;
 
        map_info_len = sizeof(map_info);
 
-       if (bpf_obj_get_info_by_fd(map_fd, &map_info, &map_info_len)) {
-               pr_warn("failed to get map info for map FD %d: %s\n",
-                       map_fd, libbpf_strerror_r(errno, msg, sizeof(msg)));
+       err = bpf_obj_get_info_by_fd(map_fd, &map_info, &map_info_len);
+       if (err && errno == EINVAL)
+               err = bpf_get_map_info_from_fdinfo(map_fd, &map_info);
+       if (err) {
+               pr_warn("failed to get map info for map FD %d: %s\n", map_fd,
+                       libbpf_strerror_r(errno, msg, sizeof(msg)));
                return false;
        }
 
@@ -10304,19 +10346,25 @@ static int perf_event_open_probe(bool uprobe, bool retprobe, const char *name,
        return pfd;
 }
 
-struct bpf_link *bpf_program__attach_kprobe(struct bpf_program *prog,
-                                           bool retprobe,
-                                           const char *func_name)
+struct bpf_program_attach_kprobe_opts {
+       bool retprobe;
+       unsigned long offset;
+};
+
+static struct bpf_link*
+bpf_program__attach_kprobe_opts(struct bpf_program *prog,
+                               const char *func_name,
+                               struct bpf_program_attach_kprobe_opts *opts)
 {
        char errmsg[STRERR_BUFSIZE];
        struct bpf_link *link;
        int pfd, err;
 
-       pfd = perf_event_open_probe(false /* uprobe */, retprobe, func_name,
-                                   0 /* offset */, -1 /* pid */);
+       pfd = perf_event_open_probe(false /* uprobe */, opts->retprobe, func_name,
+                                   opts->offset, -1 /* pid */);
        if (pfd < 0) {
                pr_warn("prog '%s': failed to create %s '%s' perf event: %s\n",
-                       prog->name, retprobe ? "kretprobe" : "kprobe", func_name,
+                       prog->name, opts->retprobe ? "kretprobe" : "kprobe", func_name,
                        libbpf_strerror_r(pfd, errmsg, sizeof(errmsg)));
                return libbpf_err_ptr(pfd);
        }
@@ -10325,23 +10373,53 @@ struct bpf_link *bpf_program__attach_kprobe(struct bpf_program *prog,
        if (err) {
                close(pfd);
                pr_warn("prog '%s': failed to attach to %s '%s': %s\n",
-                       prog->name, retprobe ? "kretprobe" : "kprobe", func_name,
+                       prog->name, opts->retprobe ? "kretprobe" : "kprobe", func_name,
                        libbpf_strerror_r(err, errmsg, sizeof(errmsg)));
                return libbpf_err_ptr(err);
        }
        return link;
 }
 
+struct bpf_link *bpf_program__attach_kprobe(struct bpf_program *prog,
+                                           bool retprobe,
+                                           const char *func_name)
+{
+       struct bpf_program_attach_kprobe_opts opts = {
+               .retprobe = retprobe,
+       };
+
+       return bpf_program__attach_kprobe_opts(prog, func_name, &opts);
+}
+
 static struct bpf_link *attach_kprobe(const struct bpf_sec_def *sec,
                                      struct bpf_program *prog)
 {
+       struct bpf_program_attach_kprobe_opts opts;
+       unsigned long offset = 0;
+       struct bpf_link *link;
        const char *func_name;
-       bool retprobe;
+       char *func;
+       int n, err;
 
        func_name = prog->sec_name + sec->len;
-       retprobe = strcmp(sec->sec, "kretprobe/") == 0;
+       opts.retprobe = strcmp(sec->sec, "kretprobe/") == 0;
+
+       n = sscanf(func_name, "%m[a-zA-Z0-9_.]+%lx", &func, &offset);
+       if (n < 1) {
+               err = -EINVAL;
+               pr_warn("kprobe name is invalid: %s\n", func_name);
+               return libbpf_err_ptr(err);
+       }
+       if (opts.retprobe && offset != 0) {
+               err = -EINVAL;
+               pr_warn("kretprobes do not support offset specification\n");
+               return libbpf_err_ptr(err);
+       }
 
-       return bpf_program__attach_kprobe(prog, retprobe, func_name);
+       opts.offset = offset;
+       link = bpf_program__attach_kprobe_opts(prog, func, &opts);
+       free(func);
+       return link;
 }
 
 struct bpf_link *bpf_program__attach_uprobe(struct bpf_program *prog,