Re: [PATCH bpf-next v4 02/16] bpf: Add source and instruction diagnostic context

Eduard Zingerman <[email protected]>
Newsgroups org.kernel.vger.bpf
Message-ID <[email protected]>
On Thu, 2026-08-13 at 01:33 +0200, Kumar Kartikeya Dwivedi wrote:

Acked-by: Eduard Zingerman <[email protected]>

...

> diff --git a/include/linux/bpf.h b/include/linux/bpf.h
> index b4a10c9878cf..7aad3bbed412 100644
> --- a/include/linux/bpf.h
> +++ b/include/linux/bpf.h
> @@ -4147,8 +4147,17 @@ static inline bool bpf_is_subprog(const struct bpf_prog *prog)
>  }
>  
>  const struct bpf_line_info *bpf_find_linfo(const struct bpf_prog *prog, u32 insn_off);
> -void bpf_get_linfo_file_line(struct btf *btf, const struct bpf_line_info *linfo,
> -			     const char **filep, const char **linep, int *nump);
> +#define BPF_LINFO_LINE_TRIM 1

Nit: a single callsite requires trim, might as well trim there and avoid the flag.

> +struct bpf_linfo_source {
> +	const char *file;
> +	const char *line;
> +	u32 file_name_off;
> +	int line_num;
> +	int line_col;
> +};
> +
> +void bpf_get_linfo_source(struct btf *btf, const struct bpf_line_info *linfo,
> +			  struct bpf_linfo_source *src, u32 flags);

...

> --- a/include/linux/btf.h
> +++ b/include/linux/btf.h
> @@ -214,6 +214,7 @@ int btf_type_seq_show_flags(const struct btf *btf, u32 type_id, void *obj,
>   */
>  int btf_type_snprintf_show(const struct btf *btf, u32 type_id, void *obj,
>  			   char *buf, int len, u64 flags);
> +int btf_type_snprintf_show_name(const struct btf *btf, u32 type_id, char *buf, int len);

Nit: the name of the function suggests that it does a printf.

...

> diff --git a/kernel/bpf/diagnostics.c b/kernel/bpf/diagnostics.c
> index ba57aabd399f..77dcffb9adee 100644
> --- a/kernel/bpf/diagnostics.c
> +++ b/kernel/bpf/diagnostics.c

...

> @@ -16,6 +24,50 @@
>  #define POLICY "Policy"
>  #define VERIFIER_LIMIT "Verifier Limit"
>  
> +#define BPF_DIAG_MSG_LEN 512
...
> +#define BPF_DIAG_REG_DESC_LEN 512
...
> +#define BPF_DIAG_REG_TMP_LEN 192

dead constants

...

> +static struct bpf_diag *diag_env(struct bpf_verifier_env *env)
> +{
> +	return env->diag;
> +}

this wrapper is unnecessary

> +static char *diag_fmt_alloc(struct bpf_verifier_env *env, size_t size)
> +{
> +	struct bpf_diag *diag = diag_env(env);
> +	struct diag_fmt_chunk *chunk;
> +	size_t capacity, available;
> +	char *buf;
> +
> +	if (!diag || !size || size > INT_MAX)
> +		return NULL;
> +
> +	if (!list_empty(&diag->fmt_chunks)) {
> +		chunk = list_last_entry(&diag->fmt_chunks, struct diag_fmt_chunk, node);
> +		available = seq_buf_get_buf(&chunk->seq, &buf);
> +		if (available >= size)
> +			goto commit;
> +	}
> +
> +	capacity = max_t(size_t, BPF_DIAG_FMT_CHUNK_SIZE, size);
> +	chunk = kmalloc(struct_size(chunk, data, capacity), GFP_KERNEL_ACCOUNT);

Q: would it be cheaper to allocate one page per chunk?

> +	if (!chunk)
> +		return NULL;
> +
> +	seq_buf_init(&chunk->seq, chunk->data, capacity);
> +	list_add_tail(&chunk->node, &diag->fmt_chunks);
> +	available = seq_buf_get_buf(&chunk->seq, &buf);
> +	if (WARN_ON_ONCE(available < size))
> +		return NULL;
> +
> +commit:
> +	seq_buf_commit(&chunk->seq, size);
> +	return buf;
> +}

...

> +static void diag_fmt_restore(struct bpf_verifier_env *env, struct diag_fmt_mark mark)
> +{
> +	struct bpf_diag *diag = diag_env(env);
> +	struct diag_fmt_chunk *chunk;
> +
> +	if (!diag)
> +		return;
> +
> +	while (!list_empty(&diag->fmt_chunks)) {
> +		chunk = list_last_entry(&diag->fmt_chunks, struct diag_fmt_chunk, node);
> +		if (chunk == mark.chunk)
> +			break;
> +		list_del(&chunk->node);
> +		kfree(chunk);
> +	}
> +
> +	if (mark.chunk) {
> +		mark.chunk->seq.len = mark.len;
> +		seq_buf_str(&mark.chunk->seq);
> +	}
> +}
> +
> +static void diag_fmt_free(struct bpf_verifier_env *env)

Nit: single user, might as well inline. Also, can it be:

     diag_fmt_restore(env, (struct diag_fmt_mark mark){})

     ?

> +{
> +	struct bpf_diag *diag = diag_env(env);
> +	struct diag_fmt_chunk *chunk, *tmp;
> +
> +	if (!diag)
> +		return;
> +
> +	list_for_each_entry_safe(chunk, tmp, &diag->fmt_chunks, node) {
> +		list_del(&chunk->node);
> +		kfree(chunk);
> +	}
> +}
> +
> +void bpf_diag_free(struct bpf_verifier_env *env)
> +{
> +	struct bpf_diag *diag = env->diag;
> +
> +	if (!diag)
> +		return;
> +
> +	diag_fmt_free(env);
> +	kfree(diag);
> +	env->diag = NULL;
> +}
> +

...

> +static void diag_format_source_lane(char *buf, size_t size, const char *source_prefix,
> +				    int source_line_width, int line_num, const char *line)
> +{
> +	int len, text_width;
> +
> +	if (line_num <= 0) {
> +		buf[0] = '\0';
> +		return;
> +	}
> +
> +	len = scnprintf(buf, size, "%s%*d | ", source_prefix, source_line_width, line_num);
> +	if (len >= (int)size)

Can this condition ever be true? scnprintf returns a value in range [0..size].

> +		return;
> +
> +	text_width = BPF_DIAG_SOURCE_LANE_WIDTH - len;
> +	diag_format_source_text(buf + len, size - len, line, text_width);
> +}

...

> +void bpf_diag_source(struct bpf_verifier_env *env, u32 insn_idx, const char *label,
> +			    const char *fmt, ...)
> +{

...

> +	linfo = bpf_find_linfo(env->prog, insn_idx);
> +	if (!btf || !linfo) {
> +		diag_write(env, "  insn %u\n", insn_idx);
> +		diag_print_source_annotation(env, 0, 0, label, msg);
> +		goto out_restore;
> +	}
> +	bpf_get_linfo_source(btf, linfo, &src, 0);
> +	if (!src.file || !*src.file || !src.line || !*src.line) {
> +		diag_write(env, "  insn %u\n", insn_idx);
> +		diag_print_source_annotation(env, 0, 0, label, msg);

Should this case still print instruction context?
(and the one above it).

> +		goto out_restore;
> +	}
> +

...

> diff --git a/kernel/bpf/diagnostics.h b/kernel/bpf/diagnostics.h
> index e8e4c06233e2..7b391cf49ae5 100644

...

> +void bpf_diag_source(struct bpf_verifier_env *env, u32 insn_idx, const char *label,
> +			    const char *fmt, ...) __printf(4, 5);

Nit: no external users.

...
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.