1use core::fmt;
5
6#[cfg(all(test, not(miri)))]
7mod tests;
8
9pub use super::common::*;
10pub type Instruction = super::Instruction<Cbpf>;
11pub type Program<'a> = super::Program<'a, Cbpf>;
12
13#[derive(Clone, Copy, Debug, Default)]
14pub struct Cbpf;
15
16impl super::instruction::Dialect for Cbpf {
17 const MAX_INSTRUCTIONS: usize = 4096;
19 const SOCKOPT: libc::c_int = libc::SO_ATTACH_REUSEPORT_CBPF as _;
20
21 fn debug(i: &Instruction, f: &mut fmt::Formatter) -> fmt::Result {
22 let code = i.code;
23 let k = i.k;
24 let jt = i.jt;
25 let jf = i.jf;
26 let alt = f.alternate();
27
28 let mut f = f.debug_struct("Instruction");
29 let class = Class::decode(code);
30
31 if alt {
32 f.field("code", &code).field("jt", &jt).field("jf", &jf);
33 }
34
35 f.field("class", &class);
36
37 match class {
38 Class::ALU => {
39 f.field("op", &Alu::decode(code));
40 }
41 Class::JMP => {
42 f.field("op", &Jump::decode(code));
43 }
44 Class::LD | Class::LDX | Class::RET => {
45 f.field("size", &Size::decode(code))
46 .field("mode", &Mode::decode(code));
47 }
48 _ => {}
49 }
50
51 if jt > 0 {
52 f.field("jt", &jt);
53 }
54
55 if jf > 0 {
56 f.field("jf", &jf);
57 }
58
59 let prefix = if k == 0 { "" } else { "0x" };
60 f.field("k", &format_args!("{prefix}{k:x}")).finish()
61 }
62
63 fn display(i: &Instruction, f: &mut fmt::Formatter, line: Option<usize>) -> fmt::Result {
64 let code = i.code;
65 let k = i.k;
66 let jt = i.jt;
67 let jf = i.jf;
68
69 if let Some(line) = line {
70 write!(f, "l{line:<4}: ")?;
71 }
72
73 let class = Class::decode(code);
74
75 match class {
76 Class::LD | Class::LDX => {
77 let size = Size::decode(code).suffix();
78 let mode = Mode::decode(code);
79
80 match mode {
81 Mode::IMM => return write!(f, "{class}{size} #{k}"),
82 Mode::ABS => {
83 let prefix = if k == 0 { "" } else { "0x" };
84 return if let Some(info) = super::ancillary::lookup(k) {
85 write!(
86 f,
87 "{class}{size} {} ; [{prefix}{k:x}] // {}",
88 info.extension, info.capi
89 )
90 } else {
91 write!(f, "{class}{size} [{prefix}{k:x}]")
92 };
93 }
94 Mode::LEN => return write!(f, "{class}{size} len"),
95 Mode::IND => return write!(f, "{class}{size} [x + {k}]"),
96 _ => {}
97 }
98 }
99 Class::ALU => {
100 let op = Alu::decode(code);
101 let source = Source::decode(code);
102
103 return match source {
104 Source::K => write!(f, "{op} #{k}"),
105 Source::X => write!(f, "{op} x"),
106 };
107 }
108 Class::JMP => {
109 let op = Jump::decode(code);
110 let source = Source::decode(code);
111
112 match source {
113 Source::K => write!(f, "{op} #{k}")?,
114 Source::X => write!(f, "{op} x")?,
115 }
116
117 if let Some(line) = line {
118 let line = line + 1;
119 let jt = line + jt as usize;
120 let jf = line + jf as usize;
121 write!(f, ",l{jt},l{jf}")?
122 } else {
123 write!(f, ",{jt},{jf}")?
124 }
125
126 return Ok(());
127 }
128 Class::RET => {
129 let source = Source::decode(code);
130 let size = Size::decode(code);
131
132 return match (source, size) {
133 (Source::K, Size::B) if k == 0 => write!(f, "{class} %a"),
134 (Source::K, _) => write!(f, "{class} #{k}"),
135 (Source::X, _) => write!(f, "{class} %x"),
136 };
137 }
138 Class::MISC => {
139 let misc = Misc::decode(code);
140 return match misc {
141 Misc::TAX => write!(f, "tax"),
142 Misc::TXA => write!(f, "txa"),
143 };
144 }
145 _ => {}
146 }
147
148 write!(f, "<unknown instruction {i:?}>")
149 }
150}
151
152define!(
154 #[mask(0x07)]
155 pub enum Class {
156 LD = 0x00,
157 LDX = 0x01,
158 ST = 0x02,
159 STX = 0x03,
160 ALU = 0x04,
161 JMP = 0x05,
162 RET = 0x06,
163 MISC = 0x07,
164 }
165);
166
167define!(
169 #[mask(0x18)]
170 pub enum Size {
171 W = 0x00,
173 H = 0x08,
175 B = 0x10,
177 }
178);
179
180impl Size {
181 #[inline]
182 pub const fn suffix(self) -> &'static str {
183 match self {
184 Self::W => "",
185 Self::H => "H",
186 Self::B => "B",
187 }
188 }
189}
190
191define!(
193 #[mask(0xe0)]
194 pub enum Mode {
195 IMM = 0x00,
196 ABS = 0x20,
197 IND = 0x40,
198 MEM = 0x60,
199 LEN = 0x80,
200 MSH = 0xa0,
201 }
202);
203
204define!(
206 #[mask(0xf0)]
207 pub enum Alu {
208 ADD = 0x00,
209 SUB = 0x10,
210 MUL = 0x20,
211 DIV = 0x30,
212 OR = 0x40,
213 AND = 0x50,
214 LSH = 0x60,
215 RSH = 0x70,
216 NEG = 0x80,
217 MOD = 0x90,
218 XOR = 0xa0,
219 }
220);
221
222define!(
224 #[mask(0xf0)]
225 pub enum Jump {
226 JA = 0x00,
227 JEQ = 0x10,
228 JGT = 0x20,
229 JSET = 0x40,
230 }
231);
232
233define!(
234 #[mask(0xf0)]
235 pub enum Misc {
236 TAX = 0x00,
237 TXA = 0x80,
238 }
239);
240
241impl_ops!();
242impl_ret!();
243
244pub const fn len() -> K {
245 K {
246 mode: Mode::LEN,
247 value: 0,
248 }
249}
250
251pub const fn tax() -> Instruction {
252 Instruction::raw(Class::MISC as u16 | Misc::TAX as u16, 0, 0, 0)
253}
254
255pub const fn txa() -> Instruction {
256 Instruction::raw(Class::MISC as u16 | Misc::TXA as u16, 0, 0, 0)
257}