Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0-only
2 : : /*
3 : : * Copyright (c) 2023 Meta Platforms, Inc. and affiliates.
4 : : */
5 : :
6 : : #include "cgen/dump.h"
7 : :
8 : : #include <linux/bpf.h>
9 : : #include <linux/bpf_common.h>
10 : :
11 : : #include <stdarg.h>
12 : : #include <stdbool.h>
13 : : #include <stdint.h>
14 : : #include <stdio.h>
15 : :
16 : : #include <bpfilter/btf.h>
17 : : #include <bpfilter/dump.h>
18 : : #include <bpfilter/helper.h>
19 : : #include <bpfilter/logger.h>
20 : :
21 : : #include "cgen/program.h"
22 : : #include "disasm.h"
23 : :
24 : : #define SYM_MAX_NAME 256
25 : :
26 : : struct bf_dump_data
27 : : {
28 : : prefix_t *prefix;
29 : : char scratch_buff[SYM_MAX_NAME + 8];
30 : : unsigned long address_call_base;
31 : : size_t idx;
32 : : };
33 : :
34 : 0 : static void _bf_print_insn(void *private_data, const char *fmt, ...)
35 : : {
36 : : va_list args;
37 : : struct bf_dump_data *bfdd = private_data;
38 : :
39 : 0 : va_start(args, fmt);
40 : 0 : (void)fprintf(stderr, "%s%-7s%s: %s %4ld: ",
41 : : bf_logger_get_color(BF_COLOR_BLUE, BF_STYLE_BOLD), "debug",
42 : : bf_logger_get_color(BF_COLOR_RESET, BF_STYLE_RESET),
43 : 0 : *(bfdd->prefix), bfdd->idx);
44 : 0 : (void)vfprintf(stderr, fmt, args);
45 : 0 : va_end(args);
46 : 0 : }
47 : :
48 : 0 : static const char *_bf_print_call(void *private_data,
49 : : const struct bpf_insn *insn)
50 : : {
51 : : struct bf_dump_data *bfdd = private_data;
52 : :
53 [ # # ]: 0 : if (insn->src_reg == BPF_PSEUDO_CALL) {
54 : 0 : (void)snprintf(bfdd->scratch_buff, sizeof(bfdd->scratch_buff), "%+d",
55 : 0 : insn->imm);
56 : : } else {
57 : 0 : (void)snprintf(bfdd->scratch_buff, sizeof(bfdd->scratch_buff), "%s",
58 : 0 : bf_btf_get_name(insn->imm));
59 : : }
60 : :
61 : 0 : return bfdd->scratch_buff;
62 : : }
63 : :
64 : 0 : static const char *_bf_print_imm(void *private_data,
65 : : const struct bpf_insn *insn, uint64_t full_imm)
66 : : {
67 : : struct bf_dump_data *bfdd = private_data;
68 : :
69 [ # # ]: 0 : if (insn->src_reg == BPF_PSEUDO_MAP_FD) {
70 : 0 : (void)snprintf(bfdd->scratch_buff, sizeof(bfdd->scratch_buff),
71 : 0 : "map[id:%u]", insn->imm);
72 [ # # ]: 0 : } else if (insn->src_reg == BPF_PSEUDO_MAP_VALUE) {
73 : 0 : (void)snprintf(bfdd->scratch_buff, sizeof(bfdd->scratch_buff),
74 : 0 : "map[id:%u][0]+%u", insn->imm, (insn + 1)->imm);
75 [ # # ]: 0 : } else if (insn->src_reg == BPF_PSEUDO_MAP_IDX_VALUE) {
76 : 0 : (void)snprintf(bfdd->scratch_buff, sizeof(bfdd->scratch_buff),
77 : 0 : "map[idx:%u]+%u", insn->imm, (insn + 1)->imm);
78 [ # # ]: 0 : } else if (insn->src_reg == BPF_PSEUDO_FUNC) {
79 : 0 : (void)snprintf(bfdd->scratch_buff, sizeof(bfdd->scratch_buff),
80 : 0 : "subprog[%+d]", insn->imm);
81 : : } else {
82 : 0 : (void)snprintf(bfdd->scratch_buff, sizeof(bfdd->scratch_buff), "0x%llx",
83 : : (unsigned long long)full_imm);
84 : : }
85 : :
86 : 0 : return bfdd->scratch_buff;
87 : : }
88 : :
89 : 0 : void bf_program_dump_bytecode(const struct bf_program *program)
90 : : {
91 : 0 : prefix_t prefix = {};
92 : 0 : struct bf_dump_data bfdd = {
93 : : .prefix = &prefix,
94 : : };
95 : 0 : struct bpf_insn_cbs callbacks = {
96 : : .cb_print = _bf_print_insn,
97 : : .cb_call = _bf_print_call,
98 : : .cb_imm = _bf_print_imm,
99 : : .private_data = &bfdd,
100 : : };
101 : : bool double_insn = false;
102 : :
103 : : bf_assert(program);
104 : :
105 : 0 : bf_dump_prefix_push(&prefix);
106 : :
107 [ # # ]: 0 : bf_dbg("Bytecode for program at %p, %lu insn:", program, program->img_size);
108 : :
109 [ # # ]: 0 : for (size_t i = 0; i < program->img_size; ++i) {
110 [ # # ]: 0 : if (i == program->img_size - 1)
111 : 0 : bf_dump_prefix_last(&prefix);
112 : :
113 [ # # ]: 0 : if (double_insn) {
114 : : double_insn = false;
115 : 0 : ++bfdd.idx;
116 : 0 : continue;
117 : : }
118 : :
119 : 0 : print_bpf_insn(&callbacks, &program->img[i], true);
120 : 0 : ++bfdd.idx;
121 : :
122 : 0 : double_insn = program->img[i].code == (BPF_LD | BPF_IMM | BPF_DW);
123 : : }
124 : :
125 : : // Force flush, otherwise output on stderr might appear.
126 : 0 : (void)fflush(stdout);
127 : 0 : }
|