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,
45 : : args); // NOLINT(clang-analyzer-valist.Uninitialized)
46 : 0 : va_end(args);
47 : 0 : }
48 : :
49 : 0 : static const char *_bf_print_call(void *private_data,
50 : : const struct bpf_insn *insn)
51 : : {
52 : : struct bf_dump_data *bfdd = private_data;
53 : :
54 [ # # ]: 0 : if (insn->src_reg == BPF_PSEUDO_CALL) {
55 : 0 : (void)snprintf(bfdd->scratch_buff, sizeof(bfdd->scratch_buff), "%+d",
56 : 0 : insn->imm);
57 : : } else {
58 : 0 : (void)snprintf(bfdd->scratch_buff, sizeof(bfdd->scratch_buff), "%s",
59 : 0 : bf_btf_get_name(insn->imm));
60 : : }
61 : :
62 : 0 : return bfdd->scratch_buff;
63 : : }
64 : :
65 : 0 : static const char *_bf_print_imm(void *private_data,
66 : : const struct bpf_insn *insn, uint64_t full_imm)
67 : : {
68 : : struct bf_dump_data *bfdd = private_data;
69 : :
70 [ # # ]: 0 : if (insn->src_reg == BPF_PSEUDO_MAP_FD) {
71 : 0 : (void)snprintf(bfdd->scratch_buff, sizeof(bfdd->scratch_buff),
72 : 0 : "map[id:%u]", insn->imm);
73 [ # # ]: 0 : } else if (insn->src_reg == BPF_PSEUDO_MAP_VALUE) {
74 : 0 : (void)snprintf(bfdd->scratch_buff, sizeof(bfdd->scratch_buff),
75 : 0 : "map[id:%u][0]+%u", insn->imm, (insn + 1)->imm);
76 [ # # ]: 0 : } else if (insn->src_reg == BPF_PSEUDO_MAP_IDX_VALUE) {
77 : 0 : (void)snprintf(bfdd->scratch_buff, sizeof(bfdd->scratch_buff),
78 : 0 : "map[idx:%u]+%u", insn->imm, (insn + 1)->imm);
79 [ # # ]: 0 : } else if (insn->src_reg == BPF_PSEUDO_FUNC) {
80 : 0 : (void)snprintf(bfdd->scratch_buff, sizeof(bfdd->scratch_buff),
81 : 0 : "subprog[%+d]", insn->imm);
82 : : } else {
83 : 0 : (void)snprintf(bfdd->scratch_buff, sizeof(bfdd->scratch_buff), "0x%llx",
84 : : (unsigned long long)full_imm);
85 : : }
86 : :
87 : 0 : return bfdd->scratch_buff;
88 : : }
89 : :
90 : 0 : void bf_program_dump_bytecode(const struct bf_program *program)
91 : : {
92 : 0 : prefix_t prefix = {};
93 : 0 : struct bf_dump_data bfdd = {
94 : : .prefix = &prefix,
95 : : };
96 : 0 : struct bpf_insn_cbs callbacks = {
97 : : .cb_print = _bf_print_insn,
98 : : .cb_call = _bf_print_call,
99 : : .cb_imm = _bf_print_imm,
100 : : .private_data = &bfdd,
101 : : };
102 : : bool double_insn = false;
103 : :
104 : : assert(program);
105 : :
106 : 0 : bf_dump_prefix_push(&prefix);
107 : :
108 [ # # ]: 0 : bf_dbg("Bytecode for program at %p, %lu insn:", program, program->img.size);
109 : :
110 [ # # ]: 0 : for (size_t i = 0; i < program->img.size; ++i) {
111 : 0 : struct bpf_insn *insn = bf_vector_get(&program->img, i);
112 [ # # ]: 0 : if (!insn)
113 [ # # ]: 0 : bf_abort("bytecode dump: invalid instruction index %lu", i);
114 : :
115 [ # # ]: 0 : if (i == program->img.size - 1)
116 : 0 : bf_dump_prefix_last(&prefix);
117 : :
118 [ # # ]: 0 : if (double_insn) {
119 : : double_insn = false;
120 : 0 : ++bfdd.idx;
121 : 0 : continue;
122 : : }
123 : :
124 : 0 : print_bpf_insn(&callbacks, insn, true);
125 : 0 : ++bfdd.idx;
126 : :
127 : 0 : double_insn = insn->code == (BPF_LD | BPF_IMM | BPF_DW);
128 : : }
129 : :
130 : : // Force flush, otherwise output on stderr might appear.
131 : 0 : (void)fflush(stdout);
132 : 0 : }
|