mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00

Adjust disasm_helpers.c:disasm_insn() to account for the following part of the verifier.c:jit_subprogs: for (i = 0, insn = prog->insnsi; i < prog->len; i++, insn++) { /* ... */ if (!bpf_pseudo_call(insn)) continue; insn->off = env->insn_aux_data[i].call_imm; subprog = find_subprog(env, i + insn->off + 1); insn->imm = subprog; } Where verifier moves offset of the subprogram to the insn->off field. Signed-off-by: Eduard Zingerman <eddyz87@gmail.com> Link: https://lore.kernel.org/r/20240722233844.1406874-6-eddyz87@gmail.com Signed-off-by: Alexei Starovoitov <ast@kernel.org> Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
69 lines
1.8 KiB
C
69 lines
1.8 KiB
C
// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
|
|
|
|
#include <bpf/bpf.h>
|
|
#include "disasm.h"
|
|
|
|
struct print_insn_context {
|
|
char scratch[16];
|
|
char *buf;
|
|
size_t sz;
|
|
};
|
|
|
|
static void print_insn_cb(void *private_data, const char *fmt, ...)
|
|
{
|
|
struct print_insn_context *ctx = private_data;
|
|
va_list args;
|
|
|
|
va_start(args, fmt);
|
|
vsnprintf(ctx->buf, ctx->sz, fmt, args);
|
|
va_end(args);
|
|
}
|
|
|
|
static const char *print_call_cb(void *private_data, const struct bpf_insn *insn)
|
|
{
|
|
struct print_insn_context *ctx = private_data;
|
|
|
|
/* For pseudo calls verifier.c:jit_subprogs() hides original
|
|
* imm to insn->off and changes insn->imm to be an index of
|
|
* the subprog instead.
|
|
*/
|
|
if (insn->src_reg == BPF_PSEUDO_CALL) {
|
|
snprintf(ctx->scratch, sizeof(ctx->scratch), "%+d", insn->off);
|
|
return ctx->scratch;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
struct bpf_insn *disasm_insn(struct bpf_insn *insn, char *buf, size_t buf_sz)
|
|
{
|
|
struct print_insn_context ctx = {
|
|
.buf = buf,
|
|
.sz = buf_sz,
|
|
};
|
|
struct bpf_insn_cbs cbs = {
|
|
.cb_print = print_insn_cb,
|
|
.cb_call = print_call_cb,
|
|
.private_data = &ctx,
|
|
};
|
|
char *tmp, *pfx_end, *sfx_start;
|
|
bool double_insn;
|
|
int len;
|
|
|
|
print_bpf_insn(&cbs, insn, true);
|
|
/* We share code with kernel BPF disassembler, it adds '(FF) ' prefix
|
|
* for each instruction (FF stands for instruction `code` byte).
|
|
* Remove the prefix inplace, and also simplify call instructions.
|
|
* E.g.: "(85) call foo#10" -> "call foo".
|
|
* Also remove newline in the end (the 'max(strlen(buf) - 1, 0)' thing).
|
|
*/
|
|
pfx_end = buf + 5;
|
|
sfx_start = buf + max((int)strlen(buf) - 1, 0);
|
|
if (strncmp(pfx_end, "call ", 5) == 0 && (tmp = strrchr(buf, '#')))
|
|
sfx_start = tmp;
|
|
len = sfx_start - pfx_end;
|
|
memmove(buf, pfx_end, len);
|
|
buf[len] = 0;
|
|
double_insn = insn->code == (BPF_LD | BPF_IMM | BPF_DW);
|
|
return insn + (double_insn ? 2 : 1);
|
|
}
|