libbpf: move exception callbacks assignment logic into relocation step
authorAndrii Nakryiko <andrii@kernel.org>
Thu, 4 Jan 2024 01:38:43 +0000 (17:38 -0800)
committerAlexei Starovoitov <ast@kernel.org>
Thu, 4 Jan 2024 05:22:49 +0000 (21:22 -0800)
Move the logic of finding and assigning exception callback indices from
BTF sanitization step to program relocations step, which seems more
logical and will unblock moving BTF loading to after relocation step.

Exception callbacks discovery and assignment has no dependency on BTF
being loaded into the kernel, it only uses BTF information. It does need
to happen before subprogram relocations happen, though. Which is why the
split.

No functional changes.

Acked-by: Jiri Olsa <jolsa@kernel.org>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/r/20240104013847.3875810-6-andrii@kernel.org
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
tools/lib/bpf/libbpf.c

index a58569b7e4bfb029dec6f7ec3ce9e9a05164323f..01d45f0c40d0dfc0e8f9224e497b09b85700fe7d 100644 (file)
@@ -3192,86 +3192,6 @@ static int bpf_object__sanitize_and_load_btf(struct bpf_object *obj)
                }
        }
 
-       if (!kernel_supports(obj, FEAT_BTF_DECL_TAG))
-               goto skip_exception_cb;
-       for (i = 0; i < obj->nr_programs; i++) {
-               struct bpf_program *prog = &obj->programs[i];
-               int j, k, n;
-
-               if (prog_is_subprog(obj, prog))
-                       continue;
-               n = btf__type_cnt(obj->btf);
-               for (j = 1; j < n; j++) {
-                       const char *str = "exception_callback:", *name;
-                       size_t len = strlen(str);
-                       struct btf_type *t;
-
-                       t = btf_type_by_id(obj->btf, j);
-                       if (!btf_is_decl_tag(t) || btf_decl_tag(t)->component_idx != -1)
-                               continue;
-
-                       name = btf__str_by_offset(obj->btf, t->name_off);
-                       if (strncmp(name, str, len))
-                               continue;
-
-                       t = btf_type_by_id(obj->btf, t->type);
-                       if (!btf_is_func(t) || btf_func_linkage(t) != BTF_FUNC_GLOBAL) {
-                               pr_warn("prog '%s': exception_callback:<value> decl tag not applied to the main program\n",
-                                       prog->name);
-                               return -EINVAL;
-                       }
-                       if (strcmp(prog->name, btf__str_by_offset(obj->btf, t->name_off)))
-                               continue;
-                       /* Multiple callbacks are specified for the same prog,
-                        * the verifier will eventually return an error for this
-                        * case, hence simply skip appending a subprog.
-                        */
-                       if (prog->exception_cb_idx >= 0) {
-                               prog->exception_cb_idx = -1;
-                               break;
-                       }
-
-                       name += len;
-                       if (str_is_empty(name)) {
-                               pr_warn("prog '%s': exception_callback:<value> decl tag contains empty value\n",
-                                       prog->name);
-                               return -EINVAL;
-                       }
-
-                       for (k = 0; k < obj->nr_programs; k++) {
-                               struct bpf_program *subprog = &obj->programs[k];
-
-                               if (!prog_is_subprog(obj, subprog))
-                                       continue;
-                               if (strcmp(name, subprog->name))
-                                       continue;
-                               /* Enforce non-hidden, as from verifier point of
-                                * view it expects global functions, whereas the
-                                * mark_btf_static fixes up linkage as static.
-                                */
-                               if (!subprog->sym_global || subprog->mark_btf_static) {
-                                       pr_warn("prog '%s': exception callback %s must be a global non-hidden function\n",
-                                               prog->name, subprog->name);
-                                       return -EINVAL;
-                               }
-                               /* Let's see if we already saw a static exception callback with the same name */
-                               if (prog->exception_cb_idx >= 0) {
-                                       pr_warn("prog '%s': multiple subprogs with same name as exception callback '%s'\n",
-                                               prog->name, subprog->name);
-                                       return -EINVAL;
-                               }
-                               prog->exception_cb_idx = k;
-                               break;
-                       }
-
-                       if (prog->exception_cb_idx >= 0)
-                               continue;
-                       pr_warn("prog '%s': cannot find exception callback '%s'\n", prog->name, name);
-                       return -ENOENT;
-               }
-       }
-skip_exception_cb:
-
        sanitize = btf_needs_sanitization(obj);
        if (sanitize) {
                const void *raw_data;
@@ -6661,6 +6581,88 @@ static void bpf_object__sort_relos(struct bpf_object *obj)
        }
 }
 
+static int bpf_prog_assign_exc_cb(struct bpf_object *obj, struct bpf_program *prog)
+{
+       const char *str = "exception_callback:";
+       size_t pfx_len = strlen(str);
+       int i, j, n;
+
+       if (!obj->btf || !kernel_supports(obj, FEAT_BTF_DECL_TAG))
+               return 0;
+
+       n = btf__type_cnt(obj->btf);
+       for (i = 1; i < n; i++) {
+               const char *name;
+               struct btf_type *t;
+
+               t = btf_type_by_id(obj->btf, i);
+               if (!btf_is_decl_tag(t) || btf_decl_tag(t)->component_idx != -1)
+                       continue;
+
+               name = btf__str_by_offset(obj->btf, t->name_off);
+               if (strncmp(name, str, pfx_len) != 0)
+                       continue;
+
+               t = btf_type_by_id(obj->btf, t->type);
+               if (!btf_is_func(t) || btf_func_linkage(t) != BTF_FUNC_GLOBAL) {
+                       pr_warn("prog '%s': exception_callback:<value> decl tag not applied to the main program\n",
+                               prog->name);
+                       return -EINVAL;
+               }
+               if (strcmp(prog->name, btf__str_by_offset(obj->btf, t->name_off)) != 0)
+                       continue;
+               /* Multiple callbacks are specified for the same prog,
+                * the verifier will eventually return an error for this
+                * case, hence simply skip appending a subprog.
+                */
+               if (prog->exception_cb_idx >= 0) {
+                       prog->exception_cb_idx = -1;
+                       break;
+               }
+
+               name += pfx_len;
+               if (str_is_empty(name)) {
+                       pr_warn("prog '%s': exception_callback:<value> decl tag contains empty value\n",
+                               prog->name);
+                       return -EINVAL;
+               }
+
+               for (j = 0; j < obj->nr_programs; j++) {
+                       struct bpf_program *subprog = &obj->programs[j];
+
+                       if (!prog_is_subprog(obj, subprog))
+                               continue;
+                       if (strcmp(name, subprog->name) != 0)
+                               continue;
+                       /* Enforce non-hidden, as from verifier point of
+                        * view it expects global functions, whereas the
+                        * mark_btf_static fixes up linkage as static.
+                        */
+                       if (!subprog->sym_global || subprog->mark_btf_static) {
+                               pr_warn("prog '%s': exception callback %s must be a global non-hidden function\n",
+                                       prog->name, subprog->name);
+                               return -EINVAL;
+                       }
+                       /* Let's see if we already saw a static exception callback with the same name */
+                       if (prog->exception_cb_idx >= 0) {
+                               pr_warn("prog '%s': multiple subprogs with same name as exception callback '%s'\n",
+                                       prog->name, subprog->name);
+                               return -EINVAL;
+                       }
+                       prog->exception_cb_idx = j;
+                       break;
+               }
+
+               if (prog->exception_cb_idx >= 0)
+                       continue;
+
+               pr_warn("prog '%s': cannot find exception callback '%s'\n", prog->name, name);
+               return -ENOENT;
+       }
+
+       return 0;
+}
+
 static int
 bpf_object__relocate(struct bpf_object *obj, const char *targ_btf_path)
 {
@@ -6721,6 +6723,9 @@ bpf_object__relocate(struct bpf_object *obj, const char *targ_btf_path)
                        return err;
                }
 
+               err = bpf_prog_assign_exc_cb(obj, prog);
+               if (err)
+                       return err;
                /* Now, also append exception callback if it has not been done already. */
                if (prog->exception_cb_idx >= 0) {
                        struct bpf_program *subprog = &obj->programs[prog->exception_cb_idx];