1 // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2 1 // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) 2 2 3 #include <bpf/bpf.h> 3 #include <bpf/bpf.h> 4 #include "disasm.h" 4 #include "disasm.h" 5 5 6 struct print_insn_context { 6 struct print_insn_context { 7 char scratch[16]; 7 char scratch[16]; 8 char *buf; 8 char *buf; 9 size_t sz; 9 size_t sz; 10 }; 10 }; 11 11 12 static void print_insn_cb(void *private_data, 12 static void print_insn_cb(void *private_data, const char *fmt, ...) 13 { 13 { 14 struct print_insn_context *ctx = priva 14 struct print_insn_context *ctx = private_data; 15 va_list args; 15 va_list args; 16 16 17 va_start(args, fmt); 17 va_start(args, fmt); 18 vsnprintf(ctx->buf, ctx->sz, fmt, args 18 vsnprintf(ctx->buf, ctx->sz, fmt, args); 19 va_end(args); 19 va_end(args); 20 } 20 } 21 21 22 static const char *print_call_cb(void *private 22 static const char *print_call_cb(void *private_data, const struct bpf_insn *insn) 23 { 23 { 24 struct print_insn_context *ctx = priva 24 struct print_insn_context *ctx = private_data; 25 25 26 /* For pseudo calls verifier.c:jit_sub 26 /* For pseudo calls verifier.c:jit_subprogs() hides original 27 * imm to insn->off and changes insn-> 27 * imm to insn->off and changes insn->imm to be an index of 28 * the subprog instead. 28 * the subprog instead. 29 */ 29 */ 30 if (insn->src_reg == BPF_PSEUDO_CALL) 30 if (insn->src_reg == BPF_PSEUDO_CALL) { 31 snprintf(ctx->scratch, sizeof( 31 snprintf(ctx->scratch, sizeof(ctx->scratch), "%+d", insn->off); 32 return ctx->scratch; 32 return ctx->scratch; 33 } 33 } 34 34 35 return NULL; 35 return NULL; 36 } 36 } 37 37 38 struct bpf_insn *disasm_insn(struct bpf_insn * 38 struct bpf_insn *disasm_insn(struct bpf_insn *insn, char *buf, size_t buf_sz) 39 { 39 { 40 struct print_insn_context ctx = { 40 struct print_insn_context ctx = { 41 .buf = buf, 41 .buf = buf, 42 .sz = buf_sz, 42 .sz = buf_sz, 43 }; 43 }; 44 struct bpf_insn_cbs cbs = { 44 struct bpf_insn_cbs cbs = { 45 .cb_print = print_insn_c 45 .cb_print = print_insn_cb, 46 .cb_call = print_call_c 46 .cb_call = print_call_cb, 47 .private_data = &ctx, 47 .private_data = &ctx, 48 }; 48 }; 49 char *tmp, *pfx_end, *sfx_start; 49 char *tmp, *pfx_end, *sfx_start; 50 bool double_insn; 50 bool double_insn; 51 int len; 51 int len; 52 52 53 print_bpf_insn(&cbs, insn, true); 53 print_bpf_insn(&cbs, insn, true); 54 /* We share code with kernel BPF disas 54 /* We share code with kernel BPF disassembler, it adds '(FF) ' prefix 55 * for each instruction (FF stands for 55 * for each instruction (FF stands for instruction `code` byte). 56 * Remove the prefix inplace, and also 56 * Remove the prefix inplace, and also simplify call instructions. 57 * E.g.: "(85) call foo#10" -> "call f 57 * E.g.: "(85) call foo#10" -> "call foo". 58 * Also remove newline in the end (the 58 * Also remove newline in the end (the 'max(strlen(buf) - 1, 0)' thing). 59 */ 59 */ 60 pfx_end = buf + 5; 60 pfx_end = buf + 5; 61 sfx_start = buf + max((int)strlen(buf) 61 sfx_start = buf + max((int)strlen(buf) - 1, 0); 62 if (strncmp(pfx_end, "call ", 5) == 0 62 if (strncmp(pfx_end, "call ", 5) == 0 && (tmp = strrchr(buf, '#'))) 63 sfx_start = tmp; 63 sfx_start = tmp; 64 len = sfx_start - pfx_end; 64 len = sfx_start - pfx_end; 65 memmove(buf, pfx_end, len); 65 memmove(buf, pfx_end, len); 66 buf[len] = 0; 66 buf[len] = 0; 67 double_insn = insn->code == (BPF_LD | 67 double_insn = insn->code == (BPF_LD | BPF_IMM | BPF_DW); 68 return insn + (double_insn ? 2 : 1); 68 return insn + (double_insn ? 2 : 1); 69 } 69 } 70 70
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.