bpf: move verifier state printing code to kernel/bpf/log.c
authorAndrii Nakryiko <andrii@kernel.org>
Sat, 18 Nov 2023 03:46:17 +0000 (19:46 -0800)
committerAlexei Starovoitov <ast@kernel.org>
Sat, 18 Nov 2023 19:39:59 +0000 (11:39 -0800)
Move a good chunk of code from verifier.c to log.c: verifier state
verbose printing logic. This is an important and very much
logging/debugging oriented code. It fits the overlall log.c's focus on
verifier logging, and moving it allows to keep growing it without
unnecessarily adding to verifier.c code that otherwise contains a core
verification logic.

There are not many shared dependencies between this code and the rest of
verifier.c code, except a few single-line helpers for various register
type checks and a bit of state "scratching" helpers. We move all such
trivial helpers into include/bpf/bpf_verifier.h as static inlines.

No functional changes in this patch.

Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Acked-by: Stanislav Fomichev <sdf@google.com>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/r/20231118034623.3320920-3-andrii@kernel.org
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
include/linux/bpf_verifier.h
kernel/bpf/log.c
kernel/bpf/verifier.c

index d896f3db6a223a4a296a2fec26a9e5c6f3de29f7..39edc76f436e2bdc965e6115cd91456b61e5c62f 100644 (file)
@@ -783,4 +783,76 @@ static inline bool bpf_type_has_unsafe_modifiers(u32 type)
        return type_flag(type) & ~BPF_REG_TRUSTED_MODIFIERS;
 }
 
+static inline bool type_is_ptr_alloc_obj(u32 type)
+{
+       return base_type(type) == PTR_TO_BTF_ID && type_flag(type) & MEM_ALLOC;
+}
+
+static inline bool type_is_non_owning_ref(u32 type)
+{
+       return type_is_ptr_alloc_obj(type) && type_flag(type) & NON_OWN_REF;
+}
+
+static inline bool type_is_pkt_pointer(enum bpf_reg_type type)
+{
+       type = base_type(type);
+       return type == PTR_TO_PACKET ||
+              type == PTR_TO_PACKET_META;
+}
+
+static inline bool type_is_sk_pointer(enum bpf_reg_type type)
+{
+       return type == PTR_TO_SOCKET ||
+               type == PTR_TO_SOCK_COMMON ||
+               type == PTR_TO_TCP_SOCK ||
+               type == PTR_TO_XDP_SOCK;
+}
+
+static inline void mark_reg_scratched(struct bpf_verifier_env *env, u32 regno)
+{
+       env->scratched_regs |= 1U << regno;
+}
+
+static inline void mark_stack_slot_scratched(struct bpf_verifier_env *env, u32 spi)
+{
+       env->scratched_stack_slots |= 1ULL << spi;
+}
+
+static inline bool reg_scratched(const struct bpf_verifier_env *env, u32 regno)
+{
+       return (env->scratched_regs >> regno) & 1;
+}
+
+static inline bool stack_slot_scratched(const struct bpf_verifier_env *env, u64 regno)
+{
+       return (env->scratched_stack_slots >> regno) & 1;
+}
+
+static inline bool verifier_state_scratched(const struct bpf_verifier_env *env)
+{
+       return env->scratched_regs || env->scratched_stack_slots;
+}
+
+static inline void mark_verifier_state_clean(struct bpf_verifier_env *env)
+{
+       env->scratched_regs = 0U;
+       env->scratched_stack_slots = 0ULL;
+}
+
+/* Used for printing the entire verifier state. */
+static inline void mark_verifier_state_scratched(struct bpf_verifier_env *env)
+{
+       env->scratched_regs = ~0U;
+       env->scratched_stack_slots = ~0ULL;
+}
+
+const char *reg_type_str(struct bpf_verifier_env *env, enum bpf_reg_type type);
+const char *dynptr_type_str(enum bpf_dynptr_type type);
+const char *iter_type_str(const struct btf *btf, u32 btf_id);
+const char *iter_state_str(enum bpf_iter_state state);
+
+void print_verifier_state(struct bpf_verifier_env *env,
+                         const struct bpf_func_state *state, bool print_all);
+void print_insn_state(struct bpf_verifier_env *env, const struct bpf_func_state *state);
+
 #endif /* _LINUX_BPF_VERIFIER_H */
index f20e1449c882b3a625f07e5695bd7f0d7dbbe2c5..c1b257eac21b76042008b41f825403b17a8b4d8e 100644 (file)
@@ -384,3 +384,345 @@ __printf(3, 4) void verbose_linfo(struct bpf_verifier_env *env,
 
        env->prev_linfo = linfo;
 }
+
+static const char *btf_type_name(const struct btf *btf, u32 id)
+{
+       return btf_name_by_offset(btf, btf_type_by_id(btf, id)->name_off);
+}
+
+/* string representation of 'enum bpf_reg_type'
+ *
+ * Note that reg_type_str() can not appear more than once in a single verbose()
+ * statement.
+ */
+const char *reg_type_str(struct bpf_verifier_env *env, enum bpf_reg_type type)
+{
+       char postfix[16] = {0}, prefix[64] = {0};
+       static const char * const str[] = {
+               [NOT_INIT]              = "?",
+               [SCALAR_VALUE]          = "scalar",
+               [PTR_TO_CTX]            = "ctx",
+               [CONST_PTR_TO_MAP]      = "map_ptr",
+               [PTR_TO_MAP_VALUE]      = "map_value",
+               [PTR_TO_STACK]          = "fp",
+               [PTR_TO_PACKET]         = "pkt",
+               [PTR_TO_PACKET_META]    = "pkt_meta",
+               [PTR_TO_PACKET_END]     = "pkt_end",
+               [PTR_TO_FLOW_KEYS]      = "flow_keys",
+               [PTR_TO_SOCKET]         = "sock",
+               [PTR_TO_SOCK_COMMON]    = "sock_common",
+               [PTR_TO_TCP_SOCK]       = "tcp_sock",
+               [PTR_TO_TP_BUFFER]      = "tp_buffer",
+               [PTR_TO_XDP_SOCK]       = "xdp_sock",
+               [PTR_TO_BTF_ID]         = "ptr_",
+               [PTR_TO_MEM]            = "mem",
+               [PTR_TO_BUF]            = "buf",
+               [PTR_TO_FUNC]           = "func",
+               [PTR_TO_MAP_KEY]        = "map_key",
+               [CONST_PTR_TO_DYNPTR]   = "dynptr_ptr",
+       };
+
+       if (type & PTR_MAYBE_NULL) {
+               if (base_type(type) == PTR_TO_BTF_ID)
+                       strncpy(postfix, "or_null_", 16);
+               else
+                       strncpy(postfix, "_or_null", 16);
+       }
+
+       snprintf(prefix, sizeof(prefix), "%s%s%s%s%s%s%s",
+                type & MEM_RDONLY ? "rdonly_" : "",
+                type & MEM_RINGBUF ? "ringbuf_" : "",
+                type & MEM_USER ? "user_" : "",
+                type & MEM_PERCPU ? "percpu_" : "",
+                type & MEM_RCU ? "rcu_" : "",
+                type & PTR_UNTRUSTED ? "untrusted_" : "",
+                type & PTR_TRUSTED ? "trusted_" : ""
+       );
+
+       snprintf(env->tmp_str_buf, TMP_STR_BUF_LEN, "%s%s%s",
+                prefix, str[base_type(type)], postfix);
+       return env->tmp_str_buf;
+}
+
+const char *dynptr_type_str(enum bpf_dynptr_type type)
+{
+       switch (type) {
+       case BPF_DYNPTR_TYPE_LOCAL:
+               return "local";
+       case BPF_DYNPTR_TYPE_RINGBUF:
+               return "ringbuf";
+       case BPF_DYNPTR_TYPE_SKB:
+               return "skb";
+       case BPF_DYNPTR_TYPE_XDP:
+               return "xdp";
+       case BPF_DYNPTR_TYPE_INVALID:
+               return "<invalid>";
+       default:
+               WARN_ONCE(1, "unknown dynptr type %d\n", type);
+               return "<unknown>";
+       }
+}
+
+const char *iter_type_str(const struct btf *btf, u32 btf_id)
+{
+       if (!btf || btf_id == 0)
+               return "<invalid>";
+
+       /* we already validated that type is valid and has conforming name */
+       return btf_type_name(btf, btf_id) + sizeof(ITER_PREFIX) - 1;
+}
+
+const char *iter_state_str(enum bpf_iter_state state)
+{
+       switch (state) {
+       case BPF_ITER_STATE_ACTIVE:
+               return "active";
+       case BPF_ITER_STATE_DRAINED:
+               return "drained";
+       case BPF_ITER_STATE_INVALID:
+               return "<invalid>";
+       default:
+               WARN_ONCE(1, "unknown iter state %d\n", state);
+               return "<unknown>";
+       }
+}
+
+static char slot_type_char[] = {
+       [STACK_INVALID] = '?',
+       [STACK_SPILL]   = 'r',
+       [STACK_MISC]    = 'm',
+       [STACK_ZERO]    = '0',
+       [STACK_DYNPTR]  = 'd',
+       [STACK_ITER]    = 'i',
+};
+
+static void print_liveness(struct bpf_verifier_env *env,
+                          enum bpf_reg_liveness live)
+{
+       if (live & (REG_LIVE_READ | REG_LIVE_WRITTEN | REG_LIVE_DONE))
+           verbose(env, "_");
+       if (live & REG_LIVE_READ)
+               verbose(env, "r");
+       if (live & REG_LIVE_WRITTEN)
+               verbose(env, "w");
+       if (live & REG_LIVE_DONE)
+               verbose(env, "D");
+}
+
+static void print_scalar_ranges(struct bpf_verifier_env *env,
+                               const struct bpf_reg_state *reg,
+                               const char **sep)
+{
+       struct {
+               const char *name;
+               u64 val;
+               bool omit;
+       } minmaxs[] = {
+               {"smin",   reg->smin_value,         reg->smin_value == S64_MIN},
+               {"smax",   reg->smax_value,         reg->smax_value == S64_MAX},
+               {"umin",   reg->umin_value,         reg->umin_value == 0},
+               {"umax",   reg->umax_value,         reg->umax_value == U64_MAX},
+               {"smin32", (s64)reg->s32_min_value, reg->s32_min_value == S32_MIN},
+               {"smax32", (s64)reg->s32_max_value, reg->s32_max_value == S32_MAX},
+               {"umin32", reg->u32_min_value,      reg->u32_min_value == 0},
+               {"umax32", reg->u32_max_value,      reg->u32_max_value == U32_MAX},
+       }, *m1, *m2, *mend = &minmaxs[ARRAY_SIZE(minmaxs)];
+       bool neg1, neg2;
+
+       for (m1 = &minmaxs[0]; m1 < mend; m1++) {
+               if (m1->omit)
+                       continue;
+
+               neg1 = m1->name[0] == 's' && (s64)m1->val < 0;
+
+               verbose(env, "%s%s=", *sep, m1->name);
+               *sep = ",";
+
+               for (m2 = m1 + 2; m2 < mend; m2 += 2) {
+                       if (m2->omit || m2->val != m1->val)
+                               continue;
+                       /* don't mix negatives with positives */
+                       neg2 = m2->name[0] == 's' && (s64)m2->val < 0;
+                       if (neg2 != neg1)
+                               continue;
+                       m2->omit = true;
+                       verbose(env, "%s=", m2->name);
+               }
+
+               verbose(env, m1->name[0] == 's' ? "%lld" : "%llu", m1->val);
+       }
+}
+
+void print_verifier_state(struct bpf_verifier_env *env, const struct bpf_func_state *state,
+                         bool print_all)
+{
+       const struct bpf_reg_state *reg;
+       enum bpf_reg_type t;
+       int i;
+
+       if (state->frameno)
+               verbose(env, " frame%d:", state->frameno);
+       for (i = 0; i < MAX_BPF_REG; i++) {
+               reg = &state->regs[i];
+               t = reg->type;
+               if (t == NOT_INIT)
+                       continue;
+               if (!print_all && !reg_scratched(env, i))
+                       continue;
+               verbose(env, " R%d", i);
+               print_liveness(env, reg->live);
+               verbose(env, "=");
+               if (t == SCALAR_VALUE && reg->precise)
+                       verbose(env, "P");
+               if ((t == SCALAR_VALUE || t == PTR_TO_STACK) &&
+                   tnum_is_const(reg->var_off)) {
+                       /* reg->off should be 0 for SCALAR_VALUE */
+                       verbose(env, "%s", t == SCALAR_VALUE ? "" : reg_type_str(env, t));
+                       verbose(env, "%lld", reg->var_off.value + reg->off);
+               } else {
+                       const char *sep = "";
+
+                       verbose(env, "%s", reg_type_str(env, t));
+                       if (base_type(t) == PTR_TO_BTF_ID)
+                               verbose(env, "%s", btf_type_name(reg->btf, reg->btf_id));
+                       verbose(env, "(");
+/*
+ * _a stands for append, was shortened to avoid multiline statements below.
+ * This macro is used to output a comma separated list of attributes.
+ */
+#define verbose_a(fmt, ...) ({ verbose(env, "%s" fmt, sep, __VA_ARGS__); sep = ","; })
+
+                       if (reg->id)
+                               verbose_a("id=%d", reg->id);
+                       if (reg->ref_obj_id)
+                               verbose_a("ref_obj_id=%d", reg->ref_obj_id);
+                       if (type_is_non_owning_ref(reg->type))
+                               verbose_a("%s", "non_own_ref");
+                       if (t != SCALAR_VALUE)
+                               verbose_a("off=%d", reg->off);
+                       if (type_is_pkt_pointer(t))
+                               verbose_a("r=%d", reg->range);
+                       else if (base_type(t) == CONST_PTR_TO_MAP ||
+                                base_type(t) == PTR_TO_MAP_KEY ||
+                                base_type(t) == PTR_TO_MAP_VALUE)
+                               verbose_a("ks=%d,vs=%d",
+                                         reg->map_ptr->key_size,
+                                         reg->map_ptr->value_size);
+                       if (tnum_is_const(reg->var_off)) {
+                               /* Typically an immediate SCALAR_VALUE, but
+                                * could be a pointer whose offset is too big
+                                * for reg->off
+                                */
+                               verbose_a("imm=%llx", reg->var_off.value);
+                       } else {
+                               print_scalar_ranges(env, reg, &sep);
+                               if (!tnum_is_unknown(reg->var_off)) {
+                                       char tn_buf[48];
+
+                                       tnum_strn(tn_buf, sizeof(tn_buf), reg->var_off);
+                                       verbose_a("var_off=%s", tn_buf);
+                               }
+                       }
+#undef verbose_a
+
+                       verbose(env, ")");
+               }
+       }
+       for (i = 0; i < state->allocated_stack / BPF_REG_SIZE; i++) {
+               char types_buf[BPF_REG_SIZE + 1];
+               bool valid = false;
+               int j;
+
+               for (j = 0; j < BPF_REG_SIZE; j++) {
+                       if (state->stack[i].slot_type[j] != STACK_INVALID)
+                               valid = true;
+                       types_buf[j] = slot_type_char[state->stack[i].slot_type[j]];
+               }
+               types_buf[BPF_REG_SIZE] = 0;
+               if (!valid)
+                       continue;
+               if (!print_all && !stack_slot_scratched(env, i))
+                       continue;
+               switch (state->stack[i].slot_type[BPF_REG_SIZE - 1]) {
+               case STACK_SPILL:
+                       reg = &state->stack[i].spilled_ptr;
+                       t = reg->type;
+
+                       verbose(env, " fp%d", (-i - 1) * BPF_REG_SIZE);
+                       print_liveness(env, reg->live);
+                       verbose(env, "=%s", t == SCALAR_VALUE ? "" : reg_type_str(env, t));
+                       if (t == SCALAR_VALUE && reg->precise)
+                               verbose(env, "P");
+                       if (t == SCALAR_VALUE && tnum_is_const(reg->var_off))
+                               verbose(env, "%lld", reg->var_off.value + reg->off);
+                       break;
+               case STACK_DYNPTR:
+                       i += BPF_DYNPTR_NR_SLOTS - 1;
+                       reg = &state->stack[i].spilled_ptr;
+
+                       verbose(env, " fp%d", (-i - 1) * BPF_REG_SIZE);
+                       print_liveness(env, reg->live);
+                       verbose(env, "=dynptr_%s", dynptr_type_str(reg->dynptr.type));
+                       if (reg->ref_obj_id)
+                               verbose(env, "(ref_id=%d)", reg->ref_obj_id);
+                       break;
+               case STACK_ITER:
+                       /* only main slot has ref_obj_id set; skip others */
+                       reg = &state->stack[i].spilled_ptr;
+                       if (!reg->ref_obj_id)
+                               continue;
+
+                       verbose(env, " fp%d", (-i - 1) * BPF_REG_SIZE);
+                       print_liveness(env, reg->live);
+                       verbose(env, "=iter_%s(ref_id=%d,state=%s,depth=%u)",
+                               iter_type_str(reg->iter.btf, reg->iter.btf_id),
+                               reg->ref_obj_id, iter_state_str(reg->iter.state),
+                               reg->iter.depth);
+                       break;
+               case STACK_MISC:
+               case STACK_ZERO:
+               default:
+                       reg = &state->stack[i].spilled_ptr;
+
+                       for (j = 0; j < BPF_REG_SIZE; j++)
+                               types_buf[j] = slot_type_char[state->stack[i].slot_type[j]];
+                       types_buf[BPF_REG_SIZE] = 0;
+
+                       verbose(env, " fp%d", (-i - 1) * BPF_REG_SIZE);
+                       print_liveness(env, reg->live);
+                       verbose(env, "=%s", types_buf);
+                       break;
+               }
+       }
+       if (state->acquired_refs && state->refs[0].id) {
+               verbose(env, " refs=%d", state->refs[0].id);
+               for (i = 1; i < state->acquired_refs; i++)
+                       if (state->refs[i].id)
+                               verbose(env, ",%d", state->refs[i].id);
+       }
+       if (state->in_callback_fn)
+               verbose(env, " cb");
+       if (state->in_async_callback_fn)
+               verbose(env, " async_cb");
+       verbose(env, "\n");
+       if (!print_all)
+               mark_verifier_state_clean(env);
+}
+
+static inline u32 vlog_alignment(u32 pos)
+{
+       return round_up(max(pos + BPF_LOG_MIN_ALIGNMENT / 2, BPF_LOG_ALIGNMENT),
+                       BPF_LOG_MIN_ALIGNMENT) - pos - 1;
+}
+
+void print_insn_state(struct bpf_verifier_env *env, const struct bpf_func_state *state)
+{
+       if (env->prev_log_pos && env->prev_log_pos == env->log.end_pos) {
+               /* remove new line character */
+               bpf_vlog_reset(&env->log, env->prev_log_pos - 1);
+               verbose(env, "%*c;", vlog_alignment(env->prev_insn_print_pos), ' ');
+       } else {
+               verbose(env, "%d:", env->insn_idx);
+       }
+       print_verifier_state(env, state, false);
+}
index 683fdda25c135992d3d5f7a066d91fc3a630c081..8c2d31aa3d31ab19bf774a3134cc0f3b2a93fe46 100644 (file)
@@ -368,21 +368,6 @@ static void verbose_invalid_scalar(struct bpf_verifier_env *env,
        verbose(env, " should have been in %s\n", tn_buf);
 }
 
-static bool type_is_pkt_pointer(enum bpf_reg_type type)
-{
-       type = base_type(type);
-       return type == PTR_TO_PACKET ||
-              type == PTR_TO_PACKET_META;
-}
-
-static bool type_is_sk_pointer(enum bpf_reg_type type)
-{
-       return type == PTR_TO_SOCKET ||
-               type == PTR_TO_SOCK_COMMON ||
-               type == PTR_TO_TCP_SOCK ||
-               type == PTR_TO_XDP_SOCK;
-}
-
 static bool type_may_be_null(u32 type)
 {
        return type & PTR_MAYBE_NULL;
@@ -406,16 +391,6 @@ static bool reg_not_null(const struct bpf_reg_state *reg)
                type == PTR_TO_MEM;
 }
 
-static bool type_is_ptr_alloc_obj(u32 type)
-{
-       return base_type(type) == PTR_TO_BTF_ID && type_flag(type) & MEM_ALLOC;
-}
-
-static bool type_is_non_owning_ref(u32 type)
-{
-       return type_is_ptr_alloc_obj(type) && type_flag(type) & NON_OWN_REF;
-}
-
 static struct btf_record *reg_btf_record(const struct bpf_reg_state *reg)
 {
        struct btf_record *rec = NULL;
@@ -532,83 +507,6 @@ static bool is_cmpxchg_insn(const struct bpf_insn *insn)
               insn->imm == BPF_CMPXCHG;
 }
 
-/* string representation of 'enum bpf_reg_type'
- *
- * Note that reg_type_str() can not appear more than once in a single verbose()
- * statement.
- */
-static const char *reg_type_str(struct bpf_verifier_env *env,
-                               enum bpf_reg_type type)
-{
-       char postfix[16] = {0}, prefix[64] = {0};
-       static const char * const str[] = {
-               [NOT_INIT]              = "?",
-               [SCALAR_VALUE]          = "scalar",
-               [PTR_TO_CTX]            = "ctx",
-               [CONST_PTR_TO_MAP]      = "map_ptr",
-               [PTR_TO_MAP_VALUE]      = "map_value",
-               [PTR_TO_STACK]          = "fp",
-               [PTR_TO_PACKET]         = "pkt",
-               [PTR_TO_PACKET_META]    = "pkt_meta",
-               [PTR_TO_PACKET_END]     = "pkt_end",
-               [PTR_TO_FLOW_KEYS]      = "flow_keys",
-               [PTR_TO_SOCKET]         = "sock",
-               [PTR_TO_SOCK_COMMON]    = "sock_common",
-               [PTR_TO_TCP_SOCK]       = "tcp_sock",
-               [PTR_TO_TP_BUFFER]      = "tp_buffer",
-               [PTR_TO_XDP_SOCK]       = "xdp_sock",
-               [PTR_TO_BTF_ID]         = "ptr_",
-               [PTR_TO_MEM]            = "mem",
-               [PTR_TO_BUF]            = "buf",
-               [PTR_TO_FUNC]           = "func",
-               [PTR_TO_MAP_KEY]        = "map_key",
-               [CONST_PTR_TO_DYNPTR]   = "dynptr_ptr",
-       };
-
-       if (type & PTR_MAYBE_NULL) {
-               if (base_type(type) == PTR_TO_BTF_ID)
-                       strncpy(postfix, "or_null_", 16);
-               else
-                       strncpy(postfix, "_or_null", 16);
-       }
-
-       snprintf(prefix, sizeof(prefix), "%s%s%s%s%s%s%s",
-                type & MEM_RDONLY ? "rdonly_" : "",
-                type & MEM_RINGBUF ? "ringbuf_" : "",
-                type & MEM_USER ? "user_" : "",
-                type & MEM_PERCPU ? "percpu_" : "",
-                type & MEM_RCU ? "rcu_" : "",
-                type & PTR_UNTRUSTED ? "untrusted_" : "",
-                type & PTR_TRUSTED ? "trusted_" : ""
-       );
-
-       snprintf(env->tmp_str_buf, TMP_STR_BUF_LEN, "%s%s%s",
-                prefix, str[base_type(type)], postfix);
-       return env->tmp_str_buf;
-}
-
-static char slot_type_char[] = {
-       [STACK_INVALID] = '?',
-       [STACK_SPILL]   = 'r',
-       [STACK_MISC]    = 'm',
-       [STACK_ZERO]    = '0',
-       [STACK_DYNPTR]  = 'd',
-       [STACK_ITER]    = 'i',
-};
-
-static void print_liveness(struct bpf_verifier_env *env,
-                          enum bpf_reg_liveness live)
-{
-       if (live & (REG_LIVE_READ | REG_LIVE_WRITTEN | REG_LIVE_DONE))
-           verbose(env, "_");
-       if (live & REG_LIVE_READ)
-               verbose(env, "r");
-       if (live & REG_LIVE_WRITTEN)
-               verbose(env, "w");
-       if (live & REG_LIVE_DONE)
-               verbose(env, "D");
-}
-
 static int __get_spi(s32 off)
 {
        return (-off - 1) / BPF_REG_SIZE;
@@ -678,87 +576,6 @@ static const char *btf_type_name(const struct btf *btf, u32 id)
        return btf_name_by_offset(btf, btf_type_by_id(btf, id)->name_off);
 }
 
-static const char *dynptr_type_str(enum bpf_dynptr_type type)
-{
-       switch (type) {
-       case BPF_DYNPTR_TYPE_LOCAL:
-               return "local";
-       case BPF_DYNPTR_TYPE_RINGBUF:
-               return "ringbuf";
-       case BPF_DYNPTR_TYPE_SKB:
-               return "skb";
-       case BPF_DYNPTR_TYPE_XDP:
-               return "xdp";
-       case BPF_DYNPTR_TYPE_INVALID:
-               return "<invalid>";
-       default:
-               WARN_ONCE(1, "unknown dynptr type %d\n", type);
-               return "<unknown>";
-       }
-}
-
-static const char *iter_type_str(const struct btf *btf, u32 btf_id)
-{
-       if (!btf || btf_id == 0)
-               return "<invalid>";
-
-       /* we already validated that type is valid and has conforming name */
-       return btf_type_name(btf, btf_id) + sizeof(ITER_PREFIX) - 1;
-}
-
-static const char *iter_state_str(enum bpf_iter_state state)
-{
-       switch (state) {
-       case BPF_ITER_STATE_ACTIVE:
-               return "active";
-       case BPF_ITER_STATE_DRAINED:
-               return "drained";
-       case BPF_ITER_STATE_INVALID:
-               return "<invalid>";
-       default:
-               WARN_ONCE(1, "unknown iter state %d\n", state);
-               return "<unknown>";
-       }
-}
-
-static void mark_reg_scratched(struct bpf_verifier_env *env, u32 regno)
-{
-       env->scratched_regs |= 1U << regno;
-}
-
-static void mark_stack_slot_scratched(struct bpf_verifier_env *env, u32 spi)
-{
-       env->scratched_stack_slots |= 1ULL << spi;
-}
-
-static bool reg_scratched(const struct bpf_verifier_env *env, u32 regno)
-{
-       return (env->scratched_regs >> regno) & 1;
-}
-
-static bool stack_slot_scratched(const struct bpf_verifier_env *env, u64 regno)
-{
-       return (env->scratched_stack_slots >> regno) & 1;
-}
-
-static bool verifier_state_scratched(const struct bpf_verifier_env *env)
-{
-       return env->scratched_regs || env->scratched_stack_slots;
-}
-
-static void mark_verifier_state_clean(struct bpf_verifier_env *env)
-{
-       env->scratched_regs = 0U;
-       env->scratched_stack_slots = 0ULL;
-}
-
-/* Used for printing the entire verifier state. */
-static void mark_verifier_state_scratched(struct bpf_verifier_env *env)
-{
-       env->scratched_regs = ~0U;
-       env->scratched_stack_slots = ~0ULL;
-}
-
 static enum bpf_dynptr_type arg_to_dynptr_type(enum bpf_arg_type arg_type)
 {
        switch (arg_type & DYNPTR_TYPE_FLAG_MASK) {
@@ -1298,226 +1115,6 @@ static void scrub_spilled_slot(u8 *stype)
                *stype = STACK_MISC;
 }
 
-static void print_scalar_ranges(struct bpf_verifier_env *env,
-                               const struct bpf_reg_state *reg,
-                               const char **sep)
-{
-       struct {
-               const char *name;
-               u64 val;
-               bool omit;
-       } minmaxs[] = {
-               {"smin",   reg->smin_value,         reg->smin_value == S64_MIN},
-               {"smax",   reg->smax_value,         reg->smax_value == S64_MAX},
-               {"umin",   reg->umin_value,         reg->umin_value == 0},
-               {"umax",   reg->umax_value,         reg->umax_value == U64_MAX},
-               {"smin32", (s64)reg->s32_min_value, reg->s32_min_value == S32_MIN},
-               {"smax32", (s64)reg->s32_max_value, reg->s32_max_value == S32_MAX},
-               {"umin32", reg->u32_min_value,      reg->u32_min_value == 0},
-               {"umax32", reg->u32_max_value,      reg->u32_max_value == U32_MAX},
-       }, *m1, *m2, *mend = &minmaxs[ARRAY_SIZE(minmaxs)];
-       bool neg1, neg2;
-
-       for (m1 = &minmaxs[0]; m1 < mend; m1++) {
-               if (m1->omit)
-                       continue;
-
-               neg1 = m1->name[0] == 's' && (s64)m1->val < 0;
-
-               verbose(env, "%s%s=", *sep, m1->name);
-               *sep = ",";
-
-               for (m2 = m1 + 2; m2 < mend; m2 += 2) {
-                       if (m2->omit || m2->val != m1->val)
-                               continue;
-                       /* don't mix negatives with positives */
-                       neg2 = m2->name[0] == 's' && (s64)m2->val < 0;
-                       if (neg2 != neg1)
-                               continue;
-                       m2->omit = true;
-                       verbose(env, "%s=", m2->name);
-               }
-
-               verbose(env, m1->name[0] == 's' ? "%lld" : "%llu", m1->val);
-       }
-}
-
-static void print_verifier_state(struct bpf_verifier_env *env,
-                                const struct bpf_func_state *state,
-                                bool print_all)
-{
-       const struct bpf_reg_state *reg;
-       enum bpf_reg_type t;
-       int i;
-
-       if (state->frameno)
-               verbose(env, " frame%d:", state->frameno);
-       for (i = 0; i < MAX_BPF_REG; i++) {
-               reg = &state->regs[i];
-               t = reg->type;
-               if (t == NOT_INIT)
-                       continue;
-               if (!print_all && !reg_scratched(env, i))
-                       continue;
-               verbose(env, " R%d", i);
-               print_liveness(env, reg->live);
-               verbose(env, "=");
-               if (t == SCALAR_VALUE && reg->precise)
-                       verbose(env, "P");
-               if ((t == SCALAR_VALUE || t == PTR_TO_STACK) &&
-                   tnum_is_const(reg->var_off)) {
-                       /* reg->off should be 0 for SCALAR_VALUE */
-                       verbose(env, "%s", t == SCALAR_VALUE ? "" : reg_type_str(env, t));
-                       verbose(env, "%lld", reg->var_off.value + reg->off);
-               } else {
-                       const char *sep = "";
-
-                       verbose(env, "%s", reg_type_str(env, t));
-                       if (base_type(t) == PTR_TO_BTF_ID)
-                               verbose(env, "%s", btf_type_name(reg->btf, reg->btf_id));
-                       verbose(env, "(");
-/*
- * _a stands for append, was shortened to avoid multiline statements below.
- * This macro is used to output a comma separated list of attributes.
- */
-#define verbose_a(fmt, ...) ({ verbose(env, "%s" fmt, sep, __VA_ARGS__); sep = ","; })
-
-                       if (reg->id)
-                               verbose_a("id=%d", reg->id);
-                       if (reg->ref_obj_id)
-                               verbose_a("ref_obj_id=%d", reg->ref_obj_id);
-                       if (type_is_non_owning_ref(reg->type))
-                               verbose_a("%s", "non_own_ref");
-                       if (t != SCALAR_VALUE)
-                               verbose_a("off=%d", reg->off);
-                       if (type_is_pkt_pointer(t))
-                               verbose_a("r=%d", reg->range);
-                       else if (base_type(t) == CONST_PTR_TO_MAP ||
-                                base_type(t) == PTR_TO_MAP_KEY ||
-                                base_type(t) == PTR_TO_MAP_VALUE)
-                               verbose_a("ks=%d,vs=%d",
-                                         reg->map_ptr->key_size,
-                                         reg->map_ptr->value_size);
-                       if (tnum_is_const(reg->var_off)) {
-                               /* Typically an immediate SCALAR_VALUE, but
-                                * could be a pointer whose offset is too big
-                                * for reg->off
-                                */
-                               verbose_a("imm=%llx", reg->var_off.value);
-                       } else {
-                               print_scalar_ranges(env, reg, &sep);
-                               if (!tnum_is_unknown(reg->var_off)) {
-                                       char tn_buf[48];
-
-                                       tnum_strn(tn_buf, sizeof(tn_buf), reg->var_off);
-                                       verbose_a("var_off=%s", tn_buf);
-                               }
-                       }
-#undef verbose_a
-
-                       verbose(env, ")");
-               }
-       }
-       for (i = 0; i < state->allocated_stack / BPF_REG_SIZE; i++) {
-               char types_buf[BPF_REG_SIZE + 1];
-               bool valid = false;
-               int j;
-
-               for (j = 0; j < BPF_REG_SIZE; j++) {
-                       if (state->stack[i].slot_type[j] != STACK_INVALID)
-                               valid = true;
-                       types_buf[j] = slot_type_char[state->stack[i].slot_type[j]];
-               }
-               types_buf[BPF_REG_SIZE] = 0;
-               if (!valid)
-                       continue;
-               if (!print_all && !stack_slot_scratched(env, i))
-                       continue;
-               switch (state->stack[i].slot_type[BPF_REG_SIZE - 1]) {
-               case STACK_SPILL:
-                       reg = &state->stack[i].spilled_ptr;
-                       t = reg->type;
-
-                       verbose(env, " fp%d", (-i - 1) * BPF_REG_SIZE);
-                       print_liveness(env, reg->live);
-                       verbose(env, "=%s", t == SCALAR_VALUE ? "" : reg_type_str(env, t));
-                       if (t == SCALAR_VALUE && reg->precise)
-                               verbose(env, "P");
-                       if (t == SCALAR_VALUE && tnum_is_const(reg->var_off))
-                               verbose(env, "%lld", reg->var_off.value + reg->off);
-                       break;
-               case STACK_DYNPTR:
-                       i += BPF_DYNPTR_NR_SLOTS - 1;
-                       reg = &state->stack[i].spilled_ptr;
-
-                       verbose(env, " fp%d", (-i - 1) * BPF_REG_SIZE);
-                       print_liveness(env, reg->live);
-                       verbose(env, "=dynptr_%s", dynptr_type_str(reg->dynptr.type));
-                       if (reg->ref_obj_id)
-                               verbose(env, "(ref_id=%d)", reg->ref_obj_id);
-                       break;
-               case STACK_ITER:
-                       /* only main slot has ref_obj_id set; skip others */
-                       reg = &state->stack[i].spilled_ptr;
-                       if (!reg->ref_obj_id)
-                               continue;
-
-                       verbose(env, " fp%d", (-i - 1) * BPF_REG_SIZE);
-                       print_liveness(env, reg->live);
-                       verbose(env, "=iter_%s(ref_id=%d,state=%s,depth=%u)",
-                               iter_type_str(reg->iter.btf, reg->iter.btf_id),
-                               reg->ref_obj_id, iter_state_str(reg->iter.state),
-                               reg->iter.depth);
-                       break;
-               case STACK_MISC:
-               case STACK_ZERO:
-               default:
-                       reg = &state->stack[i].spilled_ptr;
-
-                       for (j = 0; j < BPF_REG_SIZE; j++)
-                               types_buf[j] = slot_type_char[state->stack[i].slot_type[j]];
-                       types_buf[BPF_REG_SIZE] = 0;
-
-                       verbose(env, " fp%d", (-i - 1) * BPF_REG_SIZE);
-                       print_liveness(env, reg->live);
-                       verbose(env, "=%s", types_buf);
-                       break;
-               }
-       }
-       if (state->acquired_refs && state->refs[0].id) {
-               verbose(env, " refs=%d", state->refs[0].id);
-               for (i = 1; i < state->acquired_refs; i++)
-                       if (state->refs[i].id)
-                               verbose(env, ",%d", state->refs[i].id);
-       }
-       if (state->in_callback_fn)
-               verbose(env, " cb");
-       if (state->in_async_callback_fn)
-               verbose(env, " async_cb");
-       verbose(env, "\n");
-       if (!print_all)
-               mark_verifier_state_clean(env);
-}
-
-static inline u32 vlog_alignment(u32 pos)
-{
-       return round_up(max(pos + BPF_LOG_MIN_ALIGNMENT / 2, BPF_LOG_ALIGNMENT),
-                       BPF_LOG_MIN_ALIGNMENT) - pos - 1;
-}
-
-static void print_insn_state(struct bpf_verifier_env *env,
-                            const struct bpf_func_state *state)
-{
-       if (env->prev_log_pos && env->prev_log_pos == env->log.end_pos) {
-               /* remove new line character */
-               bpf_vlog_reset(&env->log, env->prev_log_pos - 1);
-               verbose(env, "%*c;", vlog_alignment(env->prev_insn_print_pos), ' ');
-       } else {
-               verbose(env, "%d:", env->insn_idx);
-       }
-       print_verifier_state(env, state, false);
-}
-
 /* copy array src of length n * size bytes to dst. dst is reallocated if it's too
  * small to hold src. This is different from krealloc since we don't want to preserve
  * the contents of dst.