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 "bpfilter/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/cgen/program.h"
17 : #include "core/btf.h"
18 : #include "core/dump.h"
19 : #include "core/helper.h"
20 : #include "core/logger.h"
21 :
22 : #include "external/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 0 : 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 : }
|