bpf: Move the live-register and SCC printout to a standalone function

Tests for multiple analyses performed by the verifier need the
verifier log to contain analysis results alongside the program
disassembly. This patch moves the log-level-2 program dump from
bpf_compute_live_registers() to a standalone function called from
bpf_check(), in order to provide a common logging function for such
analyses (and thus avoid printing program disassembly multiple times).

Rename the dump header from "Live regs before insn:" to
"Program dump (scc? insn#: live_regs_before):" and print available
source-line information before the corresponding instructions.

Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Reviewed-by: Emil Tsalapatis <emil@etsalapatis.com>
Link: https://patch.msgid.link/20261009-scev-minimal-rebase-v3-22-bcba9bc53ac9@gmail.com
This commit is contained in:
Eduard Zingerman 2026-10-09 03:47:40 -07:00 committed by Alexei Starovoitov
parent f414d20879
commit ceea9085f2
No known key found for this signature in database
3 changed files with 39 additions and 28 deletions

View File

@ -2664,8 +2664,7 @@ int bpf_compute_live_registers(struct bpf_verifier_env *env)
struct bpf_insn *insns = env->prog->insnsi;
struct insn_live_regs *state;
int insn_cnt = env->prog->len;
u64 pos, insn_pos;
int err = 0, i, j, subprog, start, end;
int err = 0, i, subprog, start, end;
bool changed, ret_reg_pair;
/* Use the following algorithm:
@ -2754,31 +2753,6 @@ int bpf_compute_live_registers(struct bpf_verifier_env *env)
insn_aux[i].zext_dst = def32 >= 0 && (mask_hi(out) & BIT(def32));
}
if (env->log.level & BPF_LOG_LEVEL2) {
verbose(env, "Live regs before insn:\n");
for (i = 0; i < insn_cnt; ++i) {
if (env->insn_aux_data[i].scc)
verbose(env, "%3d ", env->insn_aux_data[i].scc);
else
verbose(env, " ");
verbose(env, "%3d: ", i);
for (j = BPF_REG_0; j < BPF_REG_10; ++j)
if (insn_aux[i].live_regs_before & BIT(j))
verbose(env, "%d", j);
else
verbose(env, ".");
verbose(env, " ");
pos = env->log.end_pos;
bpf_verbose_insn(env, &insns[i]);
insn_pos = env->log.end_pos;
if (insn_aux[i].zext_dst)
verbose(env, "%*c; zext", bpf_vlog_alignment(insn_pos - pos), ' ');
verbose(env, "\n");
if (bpf_is_ldimm64(&insns[i]))
i++;
}
}
out:
kvfree(state);
return err;

View File

@ -22863,6 +22863,40 @@ static bool bpf_prog_reenters_datapath(const struct bpf_prog *prog)
return false;
}
/* Various log level 2 information about the program */
static void log_program(struct bpf_verifier_env *env)
{
struct bpf_insn_aux_data *insn_aux = env->insn_aux_data;
struct bpf_insn *insns = env->prog->insnsi;
u32 insn_cnt = env->prog->len;
u64 pos, insn_pos;
u32 i, j;
verbose(env, "Program dump (scc? insn#: live_regs_before):\n");
for (i = 0; i < insn_cnt; ++i) {
verbose_linfo(env, i, " ; ");
if (env->insn_aux_data[i].scc)
verbose(env, "%3d ", env->insn_aux_data[i].scc);
else
verbose(env, " ");
verbose(env, "%3d: ", i);
for (j = BPF_REG_0; j < BPF_REG_10; ++j)
if (insn_aux[i].live_regs_before & BIT(j))
verbose(env, "%d", j);
else
verbose(env, ".");
verbose(env, " ");
pos = env->log.end_pos;
bpf_verbose_insn(env, &insns[i]);
insn_pos = env->log.end_pos;
if (insn_aux[i].zext_dst)
verbose(env, "%*c; zext", bpf_vlog_alignment(insn_pos - pos), ' ');
verbose(env, "\n");
if (bpf_is_ldimm64(&insns[i]))
i++;
}
}
int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, bpfptr_t uattr,
struct bpf_log_attr *attr_log)
{
@ -23073,6 +23107,9 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, bpfptr_t uattr,
if (ret < 0)
goto skip_full_check;
if (env->log.level & BPF_LOG_LEVEL2)
log_program(env);
ret = mark_fastcall_patterns(env);
if (ret < 0)
goto skip_full_check;

View File

@ -66,7 +66,7 @@ __msg("stack use/def subprog#0 must_write_not_same_slot (d0,cs0):")
* but the write conservatively marks the whole frame as may_def.
*/
__msg("6: (7b) *(u64 *)(r2 +0) = r0 ; may_def: fp0-8..-{{(512|2048)}}")
__msg("Live regs before insn:")
__msg("Program dump")
__naked void must_write_not_same_slot(void)
{
asm volatile (