sbpf_common/
opcode.rs

1use {
2    crate::errors::SBPFError,
3    core::{fmt, str::FromStr},
4    num_derive::FromPrimitive,
5    serde::{Deserialize, Serialize},
6};
7
8#[derive(Debug, Clone, Copy, PartialEq)]
9pub enum OperationType {
10    LoadImmediate,
11    LoadMemory,
12    StoreImmediate,
13    StoreRegister,
14    BinaryImmediate,
15    BinaryRegister,
16    Unary,
17    Jump,
18    JumpImmediate,
19    JumpRegister,
20    CallImmediate,
21    CallRegister,
22    Exit,
23}
24
25pub const LOAD_IMM_OPS: &[Opcode] = &[Opcode::Lddw]; // OperationType::LoadImmediate
26
27pub const LOAD_MEMORY_OPS: &[Opcode] = &[
28    Opcode::Ldxb, // OperationType::LoadMemory
29    Opcode::Ldxh,
30    Opcode::Ldxw,
31    Opcode::Ldxdw,
32];
33
34pub const STORE_IMM_OPS: &[Opcode] = &[
35    Opcode::Stb, // OperationType::StoreImmediate
36    Opcode::Sth,
37    Opcode::Stw,
38    Opcode::Stdw,
39];
40
41pub const STORE_REG_OPS: &[Opcode] = &[
42    Opcode::Stxb, // OperationType::StoreRegister
43    Opcode::Stxh,
44    Opcode::Stxw,
45    Opcode::Stxdw,
46];
47
48pub const BIN_IMM_OPS: &[Opcode] = &[
49    Opcode::Add32Imm, // OperationType::BinaryImmediate
50    Opcode::Sub32Imm,
51    Opcode::Mul32Imm,
52    Opcode::Div32Imm,
53    Opcode::Or32Imm,
54    Opcode::And32Imm,
55    Opcode::Lsh32Imm,
56    Opcode::Rsh32Imm,
57    Opcode::Mod32Imm,
58    Opcode::Xor32Imm,
59    Opcode::Mov32Imm,
60    Opcode::Arsh32Imm,
61    Opcode::Lmul32Imm,
62    Opcode::Udiv32Imm,
63    Opcode::Urem32Imm,
64    Opcode::Sdiv32Imm,
65    Opcode::Srem32Imm,
66    Opcode::Le,
67    Opcode::Be,
68    Opcode::Add64Imm,
69    Opcode::Sub64Imm,
70    Opcode::Mul64Imm,
71    Opcode::Div64Imm,
72    Opcode::Or64Imm,
73    Opcode::And64Imm,
74    Opcode::Lsh64Imm,
75    Opcode::Rsh64Imm,
76    Opcode::Mod64Imm,
77    Opcode::Xor64Imm,
78    Opcode::Mov64Imm,
79    Opcode::Arsh64Imm,
80    Opcode::Hor64Imm,
81    Opcode::Lmul64Imm,
82    Opcode::Uhmul64Imm,
83    Opcode::Udiv64Imm,
84    Opcode::Urem64Imm,
85    Opcode::Shmul64Imm,
86    Opcode::Sdiv64Imm,
87    Opcode::Srem64Imm,
88];
89
90pub const BIN_REG_OPS: &[Opcode] = &[
91    Opcode::Add32Reg, // OperationType::BinaryRegister
92    Opcode::Sub32Reg,
93    Opcode::Mul32Reg,
94    Opcode::Div32Reg,
95    Opcode::Or32Reg,
96    Opcode::And32Reg,
97    Opcode::Lsh32Reg,
98    Opcode::Rsh32Reg,
99    Opcode::Mod32Reg,
100    Opcode::Xor32Reg,
101    Opcode::Mov32Reg,
102    Opcode::Arsh32Reg,
103    Opcode::Lmul32Reg,
104    Opcode::Udiv32Reg,
105    Opcode::Urem32Reg,
106    Opcode::Sdiv32Reg,
107    Opcode::Srem32Reg,
108    Opcode::Add64Reg,
109    Opcode::Sub64Reg,
110    Opcode::Mul64Reg,
111    Opcode::Div64Reg,
112    Opcode::Or64Reg,
113    Opcode::And64Reg,
114    Opcode::Lsh64Reg,
115    Opcode::Rsh64Reg,
116    Opcode::Mod64Reg,
117    Opcode::Xor64Reg,
118    Opcode::Mov64Reg,
119    Opcode::Arsh64Reg,
120    Opcode::Lmul64Reg,
121    Opcode::Uhmul64Reg,
122    Opcode::Udiv64Reg,
123    Opcode::Urem64Reg,
124    Opcode::Shmul64Reg,
125    Opcode::Sdiv64Reg,
126    Opcode::Srem64Reg,
127];
128
129pub const UNARY_OPS: &[Opcode] = &[
130    Opcode::Neg32, // OperationType::Unary
131    Opcode::Neg64,
132];
133
134pub const JUMP_OPS: &[Opcode] = &[Opcode::Ja]; // OperationType::Jump
135
136pub const JUMP_IMM_OPS: &[Opcode] = &[
137    Opcode::JeqImm, // OperationType::JumpImmediate
138    Opcode::JgtImm,
139    Opcode::JgeImm,
140    Opcode::JltImm,
141    Opcode::JleImm,
142    Opcode::JsetImm,
143    Opcode::JneImm,
144    Opcode::JsgtImm,
145    Opcode::JsgeImm,
146    Opcode::JsltImm,
147    Opcode::JsleImm,
148];
149
150pub const JUMP_REG_OPS: &[Opcode] = &[
151    Opcode::JeqReg, // OperationType::JumpRegister
152    Opcode::JgtReg,
153    Opcode::JgeReg,
154    Opcode::JltReg,
155    Opcode::JleReg,
156    Opcode::JsetReg,
157    Opcode::JneReg,
158    Opcode::JsgtReg,
159    Opcode::JsgeReg,
160    Opcode::JsltReg,
161    Opcode::JsleReg,
162];
163
164pub const CALL_IMM_OPS: &[Opcode] = &[Opcode::Call]; // OperationType::CallImmediate
165
166pub const CALL_REG_OPS: &[Opcode] = &[Opcode::Callx]; // OperationType::CallRegister
167
168pub const EXIT_OPS: &[Opcode] = &[Opcode::Exit]; // OperationType::Exit
169//
170#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, FromPrimitive, Serialize, Deserialize)]
171pub enum Opcode {
172    Lddw,
173    Ldxb,
174    Ldxh,
175    Ldxw,
176    Ldxdw,
177    Stb,
178    Sth,
179    Stw,
180    Stdw,
181    Stxb,
182    Stxh,
183    Stxw,
184    Stxdw,
185    Add32Imm,
186    Add32Reg,
187    Sub32Imm,
188    Sub32Reg,
189    Mul32Imm,
190    Mul32Reg,
191    Div32Imm,
192    Div32Reg,
193    Or32Imm,
194    Or32Reg,
195    And32Imm,
196    And32Reg,
197    Lsh32Imm,
198    Lsh32Reg,
199    Rsh32Imm,
200    Rsh32Reg,
201    Mod32Imm,
202    Mod32Reg,
203    Xor32Imm,
204    Xor32Reg,
205    Mov32Imm,
206    Mov32Reg,
207    Arsh32Imm,
208    Arsh32Reg,
209    Lmul32Imm,
210    Lmul32Reg,
211    Udiv32Imm,
212    Udiv32Reg,
213    Urem32Imm,
214    Urem32Reg,
215    Sdiv32Imm,
216    Sdiv32Reg,
217    Srem32Imm,
218    Srem32Reg,
219    Le,
220    Be,
221    Add64Imm,
222    Add64Reg,
223    Sub64Imm,
224    Sub64Reg,
225    Mul64Imm,
226    Mul64Reg,
227    Div64Imm,
228    Div64Reg,
229    Or64Imm,
230    Or64Reg,
231    And64Imm,
232    And64Reg,
233    Lsh64Imm,
234    Lsh64Reg,
235    Rsh64Imm,
236    Rsh64Reg,
237    Mod64Imm,
238    Mod64Reg,
239    Xor64Imm,
240    Xor64Reg,
241    Mov64Imm,
242    Mov64Reg,
243    Arsh64Imm,
244    Arsh64Reg,
245    Hor64Imm,
246    Lmul64Imm,
247    Lmul64Reg,
248    Uhmul64Imm,
249    Uhmul64Reg,
250    Udiv64Imm,
251    Udiv64Reg,
252    Urem64Imm,
253    Urem64Reg,
254    Shmul64Imm,
255    Shmul64Reg,
256    Sdiv64Imm,
257    Sdiv64Reg,
258    Srem64Imm,
259    Srem64Reg,
260    Neg32,
261    Neg64,
262    Ja,
263    JeqImm,
264    JeqReg,
265    JgtImm,
266    JgtReg,
267    JgeImm,
268    JgeReg,
269    JltImm,
270    JltReg,
271    JleImm,
272    JleReg,
273    JsetImm,
274    JsetReg,
275    JneImm,
276    JneReg,
277    JsgtImm,
278    JsgtReg,
279    JsgeImm,
280    JsgeReg,
281    JsltImm,
282    JsltReg,
283    JsleImm,
284    JsleReg,
285    Call,
286    Callx,
287    Exit,
288}
289
290impl FromStr for Opcode {
291    type Err = &'static str;
292
293    fn from_str(s: &str) -> Result<Self, Self::Err> {
294        match s.to_lowercase().as_str() {
295            "lddw" => Ok(Opcode::Lddw),
296            "ldxb" => Ok(Opcode::Ldxb),
297            "ldxh" => Ok(Opcode::Ldxh),
298            "ldxw" => Ok(Opcode::Ldxw),
299            "ldxdw" => Ok(Opcode::Ldxdw),
300            "stb" => Ok(Opcode::Stb),
301            "sth" => Ok(Opcode::Sth),
302            "stw" => Ok(Opcode::Stw),
303            "stdw" => Ok(Opcode::Stdw),
304            "stxb" => Ok(Opcode::Stxb),
305            "stxh" => Ok(Opcode::Stxh),
306            "stxw" => Ok(Opcode::Stxw),
307            "stxdw" => Ok(Opcode::Stxdw),
308            "add32" => Ok(Opcode::Add32Imm),
309            "sub32" => Ok(Opcode::Sub32Imm),
310            "mul32" => Ok(Opcode::Mul32Imm),
311            "div32" => Ok(Opcode::Div32Imm),
312            "or32" => Ok(Opcode::Or32Imm),
313            "and32" => Ok(Opcode::And32Imm),
314            "lsh32" => Ok(Opcode::Lsh32Imm),
315            "rsh32" => Ok(Opcode::Rsh32Imm),
316            "neg32" => Ok(Opcode::Neg32),
317            "mod32" => Ok(Opcode::Mod32Imm),
318            "xor32" => Ok(Opcode::Xor32Imm),
319            "mov32" => Ok(Opcode::Mov32Imm),
320            "arsh32" => Ok(Opcode::Arsh32Imm),
321            "lmul32" => Ok(Opcode::Lmul32Imm),
322            "udiv32" => Ok(Opcode::Udiv32Imm),
323            "urem32" => Ok(Opcode::Urem32Imm),
324            "sdiv32" => Ok(Opcode::Sdiv32Imm),
325            "srem32" => Ok(Opcode::Srem32Imm),
326            "le" => Ok(Opcode::Le),
327            "be" => Ok(Opcode::Be),
328            "add64" => Ok(Opcode::Add64Imm),
329            "sub64" => Ok(Opcode::Sub64Imm),
330            "mul64" => Ok(Opcode::Mul64Imm),
331            "div64" => Ok(Opcode::Div64Imm),
332            "or64" => Ok(Opcode::Or64Imm),
333            "and64" => Ok(Opcode::And64Imm),
334            "lsh64" => Ok(Opcode::Lsh64Imm),
335            "rsh64" => Ok(Opcode::Rsh64Imm),
336            "neg64" => Ok(Opcode::Neg64),
337            "mod64" => Ok(Opcode::Mod64Imm),
338            "xor64" => Ok(Opcode::Xor64Imm),
339            "mov64" => Ok(Opcode::Mov64Imm),
340            "arsh64" => Ok(Opcode::Arsh64Imm),
341            "hor64" => Ok(Opcode::Hor64Imm),
342            "lmul64" => Ok(Opcode::Lmul64Imm),
343            "uhmul64" => Ok(Opcode::Uhmul64Imm),
344            "udiv64" => Ok(Opcode::Udiv64Imm),
345            "urem64" => Ok(Opcode::Urem64Imm),
346            "shmul64" => Ok(Opcode::Shmul64Imm),
347            "sdiv64" => Ok(Opcode::Sdiv64Imm),
348            "srem64" => Ok(Opcode::Srem64Imm),
349            "ja" => Ok(Opcode::Ja),
350            "jeq" => Ok(Opcode::JeqImm),
351            "jgt" => Ok(Opcode::JgtImm),
352            "jge" => Ok(Opcode::JgeImm),
353            "jlt" => Ok(Opcode::JltImm),
354            "jle" => Ok(Opcode::JleImm),
355            "jset" => Ok(Opcode::JsetImm),
356            "jne" => Ok(Opcode::JneImm),
357            "jsgt" => Ok(Opcode::JsgtImm),
358            "jsge" => Ok(Opcode::JsgeImm),
359            "jslt" => Ok(Opcode::JsltImm),
360            "jsle" => Ok(Opcode::JsleImm),
361            "call" => Ok(Opcode::Call),
362            "callx" => Ok(Opcode::Callx),
363            "exit" => Ok(Opcode::Exit),
364            _ => Err("Invalid opcode"),
365        }
366    }
367}
368
369impl fmt::Display for Opcode {
370    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
371        write!(f, "{}", self.to_str())
372    }
373}
374
375impl TryFrom<u8> for Opcode {
376    type Error = SBPFError;
377
378    fn try_from(opcode: u8) -> Result<Self, Self::Error> {
379        match opcode {
380            0x18 => Ok(Opcode::Lddw),
381            0x71 => Ok(Opcode::Ldxb),
382            0x69 => Ok(Opcode::Ldxh),
383            0x61 => Ok(Opcode::Ldxw),
384            0x79 => Ok(Opcode::Ldxdw),
385            0x72 => Ok(Opcode::Stb),
386            0x6a => Ok(Opcode::Sth),
387            0x62 => Ok(Opcode::Stw),
388            0x7a => Ok(Opcode::Stdw),
389            0x73 => Ok(Opcode::Stxb),
390            0x6b => Ok(Opcode::Stxh),
391            0x63 => Ok(Opcode::Stxw),
392            0x7b => Ok(Opcode::Stxdw),
393            0x04 => Ok(Opcode::Add32Imm),
394            0x0c => Ok(Opcode::Add32Reg),
395            0x14 => Ok(Opcode::Sub32Imm),
396            0x1c => Ok(Opcode::Sub32Reg),
397            0x24 => Ok(Opcode::Mul32Imm),
398            0x2c => Ok(Opcode::Mul32Reg),
399            0x34 => Ok(Opcode::Div32Imm),
400            0x3c => Ok(Opcode::Div32Reg),
401            0x44 => Ok(Opcode::Or32Imm),
402            0x4c => Ok(Opcode::Or32Reg),
403            0x54 => Ok(Opcode::And32Imm),
404            0x5c => Ok(Opcode::And32Reg),
405            0x64 => Ok(Opcode::Lsh32Imm),
406            0x6c => Ok(Opcode::Lsh32Reg),
407            0x74 => Ok(Opcode::Rsh32Imm),
408            0x7c => Ok(Opcode::Rsh32Reg),
409            0x94 => Ok(Opcode::Mod32Imm),
410            0x9c => Ok(Opcode::Mod32Reg),
411            0xa4 => Ok(Opcode::Xor32Imm),
412            0xac => Ok(Opcode::Xor32Reg),
413            0xb4 => Ok(Opcode::Mov32Imm),
414            0xbc => Ok(Opcode::Mov32Reg),
415            0xc4 => Ok(Opcode::Arsh32Imm),
416            0xcc => Ok(Opcode::Arsh32Reg),
417            0x86 => Ok(Opcode::Lmul32Imm),
418            0x8e => Ok(Opcode::Lmul32Reg),
419            0x46 => Ok(Opcode::Udiv32Imm),
420            0x4e => Ok(Opcode::Udiv32Reg),
421            0x66 => Ok(Opcode::Urem32Imm),
422            0x6e => Ok(Opcode::Urem32Reg),
423            0xc6 => Ok(Opcode::Sdiv32Imm),
424            0xce => Ok(Opcode::Sdiv32Reg),
425            0xe6 => Ok(Opcode::Srem32Imm),
426            0xee => Ok(Opcode::Srem32Reg),
427            0xd4 => Ok(Opcode::Le),
428            0xdc => Ok(Opcode::Be),
429            0x07 => Ok(Opcode::Add64Imm),
430            0x0f => Ok(Opcode::Add64Reg),
431            0x17 => Ok(Opcode::Sub64Imm),
432            0x1f => Ok(Opcode::Sub64Reg),
433            0x27 => Ok(Opcode::Mul64Imm),
434            0x2f => Ok(Opcode::Mul64Reg),
435            0x37 => Ok(Opcode::Div64Imm),
436            0x3f => Ok(Opcode::Div64Reg),
437            0x47 => Ok(Opcode::Or64Imm),
438            0x4f => Ok(Opcode::Or64Reg),
439            0x57 => Ok(Opcode::And64Imm),
440            0x5f => Ok(Opcode::And64Reg),
441            0x67 => Ok(Opcode::Lsh64Imm),
442            0x6f => Ok(Opcode::Lsh64Reg),
443            0x77 => Ok(Opcode::Rsh64Imm),
444            0x7f => Ok(Opcode::Rsh64Reg),
445            0x97 => Ok(Opcode::Mod64Imm),
446            0x9f => Ok(Opcode::Mod64Reg),
447            0xa7 => Ok(Opcode::Xor64Imm),
448            0xaf => Ok(Opcode::Xor64Reg),
449            0xb7 => Ok(Opcode::Mov64Imm),
450            0xbf => Ok(Opcode::Mov64Reg),
451            0xc7 => Ok(Opcode::Arsh64Imm),
452            0xcf => Ok(Opcode::Arsh64Reg),
453            0xf7 => Ok(Opcode::Hor64Imm),
454            0x96 => Ok(Opcode::Lmul64Imm),
455            0x9e => Ok(Opcode::Lmul64Reg),
456            0x36 => Ok(Opcode::Uhmul64Imm),
457            0x3e => Ok(Opcode::Uhmul64Reg),
458            0x56 => Ok(Opcode::Udiv64Imm),
459            0x5e => Ok(Opcode::Udiv64Reg),
460            0x76 => Ok(Opcode::Urem64Imm),
461            0x7e => Ok(Opcode::Urem64Reg),
462            0xb6 => Ok(Opcode::Shmul64Imm),
463            0xbe => Ok(Opcode::Shmul64Reg),
464            0xd6 => Ok(Opcode::Sdiv64Imm),
465            0xde => Ok(Opcode::Sdiv64Reg),
466            0xf6 => Ok(Opcode::Srem64Imm),
467            0xfe => Ok(Opcode::Srem64Reg),
468            0x84 => Ok(Opcode::Neg32),
469            0x87 => Ok(Opcode::Neg64),
470            0x05 => Ok(Opcode::Ja),
471            0x15 => Ok(Opcode::JeqImm),
472            0x1d => Ok(Opcode::JeqReg),
473            0x25 => Ok(Opcode::JgtImm),
474            0x2d => Ok(Opcode::JgtReg),
475            0x35 => Ok(Opcode::JgeImm),
476            0x3d => Ok(Opcode::JgeReg),
477            0xa5 => Ok(Opcode::JltImm),
478            0xad => Ok(Opcode::JltReg),
479            0xb5 => Ok(Opcode::JleImm),
480            0xbd => Ok(Opcode::JleReg),
481            0x45 => Ok(Opcode::JsetImm),
482            0x4d => Ok(Opcode::JsetReg),
483            0x55 => Ok(Opcode::JneImm),
484            0x5d => Ok(Opcode::JneReg),
485            0x65 => Ok(Opcode::JsgtImm),
486            0x6d => Ok(Opcode::JsgtReg),
487            0x75 => Ok(Opcode::JsgeImm),
488            0x7d => Ok(Opcode::JsgeReg),
489            0xc5 => Ok(Opcode::JsltImm),
490            0xcd => Ok(Opcode::JsltReg),
491            0xd5 => Ok(Opcode::JsleImm),
492            0xdd => Ok(Opcode::JsleReg),
493            0x85 => Ok(Opcode::Call),
494            0x8d => Ok(Opcode::Callx),
495            0x95 => Ok(Opcode::Exit),
496            _ => Err(SBPFError::BytecodeError {
497                error: format!("no decode handler for opcode 0x{:02x}", opcode),
498                span: 0..1,
499                custom_label: Some("Invalid opcode".to_string()),
500            }),
501        }
502    }
503}
504
505impl From<Opcode> for u8 {
506    fn from(opcode: Opcode) -> u8 {
507        match opcode {
508            Opcode::Lddw => 0x18,
509            Opcode::Ldxb => 0x71,
510            Opcode::Ldxh => 0x69,
511            Opcode::Ldxw => 0x61,
512            Opcode::Ldxdw => 0x79,
513            Opcode::Stb => 0x72,
514            Opcode::Sth => 0x6a,
515            Opcode::Stw => 0x62,
516            Opcode::Stdw => 0x7a,
517            Opcode::Stxb => 0x73,
518            Opcode::Stxh => 0x6b,
519            Opcode::Stxw => 0x63,
520            Opcode::Stxdw => 0x7b,
521            Opcode::Add32Imm => 0x04,
522            Opcode::Add32Reg => 0x0c,
523            Opcode::Sub32Imm => 0x14,
524            Opcode::Sub32Reg => 0x1c,
525            Opcode::Mul32Imm => 0x24,
526            Opcode::Mul32Reg => 0x2c,
527            Opcode::Div32Imm => 0x34,
528            Opcode::Div32Reg => 0x3c,
529            Opcode::Or32Imm => 0x44,
530            Opcode::Or32Reg => 0x4c,
531            Opcode::And32Imm => 0x54,
532            Opcode::And32Reg => 0x5c,
533            Opcode::Lsh32Imm => 0x64,
534            Opcode::Lsh32Reg => 0x6c,
535            Opcode::Rsh32Imm => 0x74,
536            Opcode::Rsh32Reg => 0x7c,
537            Opcode::Mod32Imm => 0x94,
538            Opcode::Mod32Reg => 0x9c,
539            Opcode::Xor32Imm => 0xa4,
540            Opcode::Xor32Reg => 0xac,
541            Opcode::Mov32Imm => 0xb4,
542            Opcode::Mov32Reg => 0xbc,
543            Opcode::Arsh32Imm => 0xc4,
544            Opcode::Arsh32Reg => 0xcc,
545            Opcode::Lmul32Imm => 0x86,
546            Opcode::Lmul32Reg => 0x8e,
547            Opcode::Udiv32Imm => 0x46,
548            Opcode::Udiv32Reg => 0x4e,
549            Opcode::Urem32Imm => 0x66,
550            Opcode::Urem32Reg => 0x6e,
551            Opcode::Sdiv32Imm => 0xc6,
552            Opcode::Sdiv32Reg => 0xce,
553            Opcode::Srem32Imm => 0xe6,
554            Opcode::Srem32Reg => 0xee,
555            Opcode::Le => 0xd4,
556            Opcode::Be => 0xdc,
557            Opcode::Add64Imm => 0x07,
558            Opcode::Add64Reg => 0x0f,
559            Opcode::Sub64Imm => 0x17,
560            Opcode::Sub64Reg => 0x1f,
561            Opcode::Mul64Imm => 0x27,
562            Opcode::Mul64Reg => 0x2f,
563            Opcode::Div64Imm => 0x37,
564            Opcode::Div64Reg => 0x3f,
565            Opcode::Or64Imm => 0x47,
566            Opcode::Or64Reg => 0x4f,
567            Opcode::And64Imm => 0x57,
568            Opcode::And64Reg => 0x5f,
569            Opcode::Lsh64Imm => 0x67,
570            Opcode::Lsh64Reg => 0x6f,
571            Opcode::Rsh64Imm => 0x77,
572            Opcode::Rsh64Reg => 0x7f,
573            Opcode::Mod64Imm => 0x97,
574            Opcode::Mod64Reg => 0x9f,
575            Opcode::Xor64Imm => 0xa7,
576            Opcode::Xor64Reg => 0xaf,
577            Opcode::Mov64Imm => 0xb7,
578            Opcode::Mov64Reg => 0xbf,
579            Opcode::Arsh64Imm => 0xc7,
580            Opcode::Arsh64Reg => 0xcf,
581            Opcode::Hor64Imm => 0xf7,
582            Opcode::Lmul64Imm => 0x96,
583            Opcode::Lmul64Reg => 0x9e,
584            Opcode::Uhmul64Imm => 0x36,
585            Opcode::Uhmul64Reg => 0x3e,
586            Opcode::Udiv64Imm => 0x56,
587            Opcode::Udiv64Reg => 0x5e,
588            Opcode::Urem64Imm => 0x76,
589            Opcode::Urem64Reg => 0x7e,
590            Opcode::Shmul64Imm => 0xb6,
591            Opcode::Shmul64Reg => 0xbe,
592            Opcode::Sdiv64Imm => 0xd6,
593            Opcode::Sdiv64Reg => 0xde,
594            Opcode::Srem64Imm => 0xf6,
595            Opcode::Srem64Reg => 0xfe,
596            Opcode::Neg32 => 0x84,
597            Opcode::Neg64 => 0x87,
598            Opcode::Ja => 0x05,
599            Opcode::JeqImm => 0x15,
600            Opcode::JeqReg => 0x1d,
601            Opcode::JgtImm => 0x25,
602            Opcode::JgtReg => 0x2d,
603            Opcode::JgeImm => 0x35,
604            Opcode::JgeReg => 0x3d,
605            Opcode::JltImm => 0xa5,
606            Opcode::JltReg => 0xad,
607            Opcode::JleImm => 0xb5,
608            Opcode::JleReg => 0xbd,
609            Opcode::JsetImm => 0x45,
610            Opcode::JsetReg => 0x4d,
611            Opcode::JneImm => 0x55,
612            Opcode::JneReg => 0x5d,
613            Opcode::JsgtImm => 0x65,
614            Opcode::JsgtReg => 0x6d,
615            Opcode::JsgeImm => 0x75,
616            Opcode::JsgeReg => 0x7d,
617            Opcode::JsltImm => 0xc5,
618            Opcode::JsltReg => 0xcd,
619            Opcode::JsleImm => 0xd5,
620            Opcode::JsleReg => 0xdd,
621            Opcode::Call => 0x85,
622            Opcode::Callx => 0x8d,
623            Opcode::Exit => 0x95,
624        }
625    }
626}
627
628impl Opcode {
629    pub fn to_str(&self) -> &'static str {
630        match self {
631            Opcode::Lddw => "lddw",
632            Opcode::Ldxb => "ldxb",
633            Opcode::Ldxh => "ldxh",
634            Opcode::Ldxw => "ldxw",
635            Opcode::Ldxdw => "ldxdw",
636            Opcode::Stb => "stb",
637            Opcode::Sth => "sth",
638            Opcode::Stw => "stw",
639            Opcode::Stdw => "stdw",
640            Opcode::Stxb => "stxb",
641            Opcode::Stxh => "stxh",
642            Opcode::Stxw => "stxw",
643            Opcode::Stxdw => "stxdw",
644            Opcode::Add32Imm | Opcode::Add32Reg => "add32",
645            Opcode::Sub32Imm | Opcode::Sub32Reg => "sub32",
646            Opcode::Mul32Imm | Opcode::Mul32Reg => "mul32",
647            Opcode::Div32Imm | Opcode::Div32Reg => "div32",
648            Opcode::Or32Imm | Opcode::Or32Reg => "or32",
649            Opcode::And32Imm | Opcode::And32Reg => "and32",
650            Opcode::Lsh32Imm | Opcode::Lsh32Reg => "lsh32",
651            Opcode::Rsh32Imm | Opcode::Rsh32Reg => "rsh32",
652            Opcode::Neg32 => "neg32",
653            Opcode::Mod32Imm | Opcode::Mod32Reg => "mod32",
654            Opcode::Xor32Imm | Opcode::Xor32Reg => "xor32",
655            Opcode::Mov32Imm | Opcode::Mov32Reg => "mov32",
656            Opcode::Arsh32Imm | Opcode::Arsh32Reg => "arsh32",
657            Opcode::Lmul32Imm | Opcode::Lmul32Reg => "lmul32",
658            Opcode::Udiv32Imm | Opcode::Udiv32Reg => "udiv32",
659            Opcode::Urem32Imm | Opcode::Urem32Reg => "urem32",
660            Opcode::Sdiv32Imm | Opcode::Sdiv32Reg => "sdiv32",
661            Opcode::Srem32Imm | Opcode::Srem32Reg => "srem32",
662            Opcode::Le => "le",
663            Opcode::Be => "be",
664            Opcode::Add64Imm | Opcode::Add64Reg => "add64",
665            Opcode::Sub64Imm | Opcode::Sub64Reg => "sub64",
666            Opcode::Mul64Imm | Opcode::Mul64Reg => "mul64",
667            Opcode::Div64Imm | Opcode::Div64Reg => "div64",
668            Opcode::Or64Imm | Opcode::Or64Reg => "or64",
669            Opcode::And64Imm | Opcode::And64Reg => "and64",
670            Opcode::Lsh64Imm | Opcode::Lsh64Reg => "lsh64",
671            Opcode::Rsh64Imm | Opcode::Rsh64Reg => "rsh64",
672            Opcode::Neg64 => "neg64",
673            Opcode::Mod64Imm | Opcode::Mod64Reg => "mod64",
674            Opcode::Xor64Imm | Opcode::Xor64Reg => "xor64",
675            Opcode::Mov64Imm | Opcode::Mov64Reg => "mov64",
676            Opcode::Arsh64Imm | Opcode::Arsh64Reg => "arsh64",
677            Opcode::Hor64Imm => "hor64",
678            Opcode::Lmul64Imm | Opcode::Lmul64Reg => "lmul64",
679            Opcode::Uhmul64Imm | Opcode::Uhmul64Reg => "uhmul64",
680            Opcode::Udiv64Imm | Opcode::Udiv64Reg => "udiv64",
681            Opcode::Urem64Imm | Opcode::Urem64Reg => "urem64",
682            Opcode::Shmul64Imm | Opcode::Shmul64Reg => "shmul64",
683            Opcode::Sdiv64Imm | Opcode::Sdiv64Reg => "sdiv64",
684            Opcode::Srem64Imm | Opcode::Srem64Reg => "srem64",
685            Opcode::Ja => "ja",
686            Opcode::JeqImm | Opcode::JeqReg => "jeq",
687            Opcode::JgtImm | Opcode::JgtReg => "jgt",
688            Opcode::JgeImm | Opcode::JgeReg => "jge",
689            Opcode::JltImm | Opcode::JltReg => "jlt",
690            Opcode::JleImm | Opcode::JleReg => "jle",
691            Opcode::JsetImm | Opcode::JsetReg => "jset",
692            Opcode::JneImm | Opcode::JneReg => "jne",
693            Opcode::JsgtImm | Opcode::JsgtReg => "jsgt",
694            Opcode::JsgeImm | Opcode::JsgeReg => "jsge",
695            Opcode::JsltImm | Opcode::JsltReg => "jslt",
696            Opcode::JsleImm | Opcode::JsleReg => "jsle",
697            Opcode::Call => "call",
698            Opcode::Callx => "callx",
699            Opcode::Exit => "exit",
700        }
701    }
702}
703
704#[cfg(test)]
705mod tests {
706    use super::*;
707
708    #[test]
709    fn test_opcode_from_str_load_ops() {
710        assert_eq!(Opcode::from_str("lddw").unwrap(), Opcode::Lddw);
711        assert_eq!(Opcode::from_str("LDDW").unwrap(), Opcode::Lddw);
712        assert_eq!(Opcode::from_str("ldxb").unwrap(), Opcode::Ldxb);
713        assert_eq!(Opcode::from_str("ldxh").unwrap(), Opcode::Ldxh);
714        assert_eq!(Opcode::from_str("ldxw").unwrap(), Opcode::Ldxw);
715        assert_eq!(Opcode::from_str("ldxdw").unwrap(), Opcode::Ldxdw);
716    }
717
718    #[test]
719    fn test_opcode_from_str_store_ops() {
720        assert_eq!(Opcode::from_str("stb").unwrap(), Opcode::Stb);
721        assert_eq!(Opcode::from_str("sth").unwrap(), Opcode::Sth);
722        assert_eq!(Opcode::from_str("stw").unwrap(), Opcode::Stw);
723        assert_eq!(Opcode::from_str("stdw").unwrap(), Opcode::Stdw);
724        assert_eq!(Opcode::from_str("stxb").unwrap(), Opcode::Stxb);
725        assert_eq!(Opcode::from_str("stxh").unwrap(), Opcode::Stxh);
726        assert_eq!(Opcode::from_str("stxw").unwrap(), Opcode::Stxw);
727        assert_eq!(Opcode::from_str("stxdw").unwrap(), Opcode::Stxdw);
728    }
729
730    #[test]
731    fn test_opcode_from_str_alu32_ops() {
732        assert_eq!(Opcode::from_str("add32").unwrap(), Opcode::Add32Imm);
733        assert_eq!(Opcode::from_str("sub32").unwrap(), Opcode::Sub32Imm);
734        assert_eq!(Opcode::from_str("mul32").unwrap(), Opcode::Mul32Imm);
735        assert_eq!(Opcode::from_str("div32").unwrap(), Opcode::Div32Imm);
736        assert_eq!(Opcode::from_str("or32").unwrap(), Opcode::Or32Imm);
737        assert_eq!(Opcode::from_str("and32").unwrap(), Opcode::And32Imm);
738        assert_eq!(Opcode::from_str("lsh32").unwrap(), Opcode::Lsh32Imm);
739        assert_eq!(Opcode::from_str("rsh32").unwrap(), Opcode::Rsh32Imm);
740        assert_eq!(Opcode::from_str("neg32").unwrap(), Opcode::Neg32);
741        assert_eq!(Opcode::from_str("mod32").unwrap(), Opcode::Mod32Imm);
742        assert_eq!(Opcode::from_str("xor32").unwrap(), Opcode::Xor32Imm);
743        assert_eq!(Opcode::from_str("mov32").unwrap(), Opcode::Mov32Imm);
744        assert_eq!(Opcode::from_str("arsh32").unwrap(), Opcode::Arsh32Imm);
745        assert_eq!(Opcode::from_str("lmul32").unwrap(), Opcode::Lmul32Imm);
746        assert_eq!(Opcode::from_str("udiv32").unwrap(), Opcode::Udiv32Imm);
747        assert_eq!(Opcode::from_str("urem32").unwrap(), Opcode::Urem32Imm);
748        assert_eq!(Opcode::from_str("sdiv32").unwrap(), Opcode::Sdiv32Imm);
749        assert_eq!(Opcode::from_str("srem32").unwrap(), Opcode::Srem32Imm);
750    }
751
752    #[test]
753    fn test_opcode_from_str_alu64_ops() {
754        assert_eq!(Opcode::from_str("add64").unwrap(), Opcode::Add64Imm);
755        assert_eq!(Opcode::from_str("sub64").unwrap(), Opcode::Sub64Imm);
756        assert_eq!(Opcode::from_str("mul64").unwrap(), Opcode::Mul64Imm);
757        assert_eq!(Opcode::from_str("div64").unwrap(), Opcode::Div64Imm);
758        assert_eq!(Opcode::from_str("or64").unwrap(), Opcode::Or64Imm);
759        assert_eq!(Opcode::from_str("and64").unwrap(), Opcode::And64Imm);
760        assert_eq!(Opcode::from_str("neg64").unwrap(), Opcode::Neg64);
761        assert_eq!(Opcode::from_str("mov64").unwrap(), Opcode::Mov64Imm);
762        assert_eq!(Opcode::from_str("lsh64").unwrap(), Opcode::Lsh64Imm);
763        assert_eq!(Opcode::from_str("rsh64").unwrap(), Opcode::Rsh64Imm);
764        assert_eq!(Opcode::from_str("mod64").unwrap(), Opcode::Mod64Imm);
765        assert_eq!(Opcode::from_str("xor64").unwrap(), Opcode::Xor64Imm);
766        assert_eq!(Opcode::from_str("arsh64").unwrap(), Opcode::Arsh64Imm);
767        assert_eq!(Opcode::from_str("hor64").unwrap(), Opcode::Hor64Imm);
768        assert_eq!(Opcode::from_str("lmul64").unwrap(), Opcode::Lmul64Imm);
769        assert_eq!(Opcode::from_str("uhmul64").unwrap(), Opcode::Uhmul64Imm);
770        assert_eq!(Opcode::from_str("udiv64").unwrap(), Opcode::Udiv64Imm);
771        assert_eq!(Opcode::from_str("urem64").unwrap(), Opcode::Urem64Imm);
772        assert_eq!(Opcode::from_str("shmul64").unwrap(), Opcode::Shmul64Imm);
773        assert_eq!(Opcode::from_str("sdiv64").unwrap(), Opcode::Sdiv64Imm);
774        assert_eq!(Opcode::from_str("srem64").unwrap(), Opcode::Srem64Imm);
775    }
776
777    #[test]
778    fn test_opcode_from_str_be_le() {
779        assert_eq!(Opcode::from_str("le").unwrap(), Opcode::Le);
780        assert_eq!(Opcode::from_str("be").unwrap(), Opcode::Be);
781    }
782
783    #[test]
784    fn test_opcode_from_str_jump_ops() {
785        assert_eq!(Opcode::from_str("ja").unwrap(), Opcode::Ja);
786        assert_eq!(Opcode::from_str("jeq").unwrap(), Opcode::JeqImm);
787        assert_eq!(Opcode::from_str("jgt").unwrap(), Opcode::JgtImm);
788        assert_eq!(Opcode::from_str("jge").unwrap(), Opcode::JgeImm);
789        assert_eq!(Opcode::from_str("jlt").unwrap(), Opcode::JltImm);
790        assert_eq!(Opcode::from_str("jne").unwrap(), Opcode::JneImm);
791        assert_eq!(Opcode::from_str("jle").unwrap(), Opcode::JleImm);
792        assert_eq!(Opcode::from_str("jset").unwrap(), Opcode::JsetImm);
793        assert_eq!(Opcode::from_str("jsgt").unwrap(), Opcode::JsgtImm);
794        assert_eq!(Opcode::from_str("jsge").unwrap(), Opcode::JsgeImm);
795        assert_eq!(Opcode::from_str("jslt").unwrap(), Opcode::JsltImm);
796        assert_eq!(Opcode::from_str("jsle").unwrap(), Opcode::JsleImm);
797    }
798
799    #[test]
800    fn test_opcode_from_str_call_and_exit_ops() {
801        assert!(Opcode::from_str("invalid").is_err());
802        assert!(Opcode::from_str("").is_err());
803        assert!(Opcode::from_str("xyz").is_err());
804        assert_eq!(Opcode::from_str("call").unwrap(), Opcode::Call);
805        assert_eq!(Opcode::from_str("callx").unwrap(), Opcode::Callx);
806        assert_eq!(Opcode::from_str("exit").unwrap(), Opcode::Exit);
807    }
808
809    #[test]
810    fn test_opcode_from_str_invalid() {
811        assert!(Opcode::from_str("invalid").is_err());
812        assert!(Opcode::from_str("").is_err());
813        assert!(Opcode::from_str("xyz").is_err());
814    }
815
816    #[test]
817    fn test_all_load_memory_ops() {
818        for &op in LOAD_MEMORY_OPS {
819            let byte: u8 = op.into();
820            let roundtrip = Opcode::try_from(byte).unwrap();
821            assert_eq!(roundtrip, op);
822        }
823    }
824
825    #[test]
826    fn test_all_bin_imm_ops() {
827        for &op in BIN_IMM_OPS {
828            let byte: u8 = op.into();
829            let roundtrip = Opcode::try_from(byte).unwrap();
830            assert_eq!(roundtrip, op);
831        }
832    }
833
834    #[test]
835    fn test_all_jump_imm_ops() {
836        for &op in JUMP_IMM_OPS {
837            let byte: u8 = op.into();
838            let roundtrip = Opcode::try_from(byte).unwrap();
839            assert_eq!(roundtrip, op);
840        }
841    }
842
843    #[test]
844    fn test_all_store_imm_ops() {
845        for &op in STORE_IMM_OPS {
846            let byte: u8 = op.into();
847            let roundtrip = Opcode::try_from(byte).unwrap();
848            assert_eq!(roundtrip, op);
849        }
850    }
851
852    #[test]
853    fn test_all_store_reg_ops() {
854        for &op in STORE_REG_OPS {
855            let byte: u8 = op.into();
856            let roundtrip = Opcode::try_from(byte).unwrap();
857            assert_eq!(roundtrip, op);
858        }
859    }
860
861    #[test]
862    fn test_all_bin_reg_ops() {
863        for &op in BIN_REG_OPS {
864            let byte: u8 = op.into();
865            let roundtrip = Opcode::try_from(byte).unwrap();
866            assert_eq!(roundtrip, op);
867        }
868    }
869
870    #[test]
871    fn test_all_unary_ops() {
872        for &op in UNARY_OPS {
873            let byte: u8 = op.into();
874            let roundtrip = Opcode::try_from(byte).unwrap();
875            assert_eq!(roundtrip, op);
876        }
877    }
878
879    #[test]
880    fn test_all_jump_ops() {
881        for &op in JUMP_OPS {
882            let byte: u8 = op.into();
883            let roundtrip = Opcode::try_from(byte).unwrap();
884            assert_eq!(roundtrip, op);
885        }
886    }
887
888    #[test]
889    fn test_all_jump_reg_ops() {
890        for &op in JUMP_REG_OPS {
891            let byte: u8 = op.into();
892            let roundtrip = Opcode::try_from(byte).unwrap();
893            assert_eq!(roundtrip, op);
894        }
895    }
896
897    #[test]
898    fn test_all_call_ops() {
899        for &op in CALL_IMM_OPS {
900            let byte: u8 = op.into();
901            let roundtrip = Opcode::try_from(byte).unwrap();
902            assert_eq!(roundtrip, op);
903        }
904        for &op in CALL_REG_OPS {
905            let byte: u8 = op.into();
906            let roundtrip = Opcode::try_from(byte).unwrap();
907            assert_eq!(roundtrip, op);
908        }
909    }
910
911    #[test]
912    fn test_exit_op() {
913        for &op in EXIT_OPS {
914            let byte: u8 = op.into();
915            let roundtrip = Opcode::try_from(byte).unwrap();
916            assert_eq!(roundtrip, op);
917        }
918    }
919
920    #[test]
921    fn test_to_str_all_load_ops() {
922        assert_eq!(Opcode::Lddw.to_str(), "lddw");
923        assert_eq!(Opcode::Ldxb.to_str(), "ldxb");
924        assert_eq!(Opcode::Ldxh.to_str(), "ldxh");
925        assert_eq!(Opcode::Ldxw.to_str(), "ldxw");
926        assert_eq!(Opcode::Ldxdw.to_str(), "ldxdw");
927    }
928
929    #[test]
930    fn test_to_str_all_store_ops() {
931        assert_eq!(Opcode::Stb.to_str(), "stb");
932        assert_eq!(Opcode::Sth.to_str(), "sth");
933        assert_eq!(Opcode::Stw.to_str(), "stw");
934        assert_eq!(Opcode::Stdw.to_str(), "stdw");
935        assert_eq!(Opcode::Stxb.to_str(), "stxb");
936        assert_eq!(Opcode::Stxh.to_str(), "stxh");
937        assert_eq!(Opcode::Stxw.to_str(), "stxw");
938        assert_eq!(Opcode::Stxdw.to_str(), "stxdw");
939    }
940
941    #[test]
942    fn test_to_str_all_alu32_ops() {
943        assert_eq!(Opcode::Add32Imm.to_str(), "add32");
944        assert_eq!(Opcode::Add32Reg.to_str(), "add32");
945        assert_eq!(Opcode::Sub32Imm.to_str(), "sub32");
946        assert_eq!(Opcode::Mul32Imm.to_str(), "mul32");
947        assert_eq!(Opcode::Div32Imm.to_str(), "div32");
948        assert_eq!(Opcode::Or32Imm.to_str(), "or32");
949        assert_eq!(Opcode::And32Imm.to_str(), "and32");
950        assert_eq!(Opcode::Lsh32Imm.to_str(), "lsh32");
951        assert_eq!(Opcode::Rsh32Imm.to_str(), "rsh32");
952        assert_eq!(Opcode::Neg32.to_str(), "neg32");
953        assert_eq!(Opcode::Mod32Imm.to_str(), "mod32");
954        assert_eq!(Opcode::Xor32Imm.to_str(), "xor32");
955        assert_eq!(Opcode::Mov32Imm.to_str(), "mov32");
956        assert_eq!(Opcode::Arsh32Imm.to_str(), "arsh32");
957        assert_eq!(Opcode::Lmul32Imm.to_str(), "lmul32");
958        assert_eq!(Opcode::Lmul32Reg.to_str(), "lmul32");
959        assert_eq!(Opcode::Udiv32Imm.to_str(), "udiv32");
960        assert_eq!(Opcode::Urem32Imm.to_str(), "urem32");
961        assert_eq!(Opcode::Sdiv32Imm.to_str(), "sdiv32");
962        assert_eq!(Opcode::Srem32Imm.to_str(), "srem32");
963    }
964
965    #[test]
966    fn test_to_str_all_alu64_ops() {
967        assert_eq!(Opcode::Add64Imm.to_str(), "add64");
968        assert_eq!(Opcode::Sub64Imm.to_str(), "sub64");
969        assert_eq!(Opcode::Mul64Imm.to_str(), "mul64");
970        assert_eq!(Opcode::Div64Imm.to_str(), "div64");
971        assert_eq!(Opcode::Or64Imm.to_str(), "or64");
972        assert_eq!(Opcode::And64Imm.to_str(), "and64");
973        assert_eq!(Opcode::Lsh64Imm.to_str(), "lsh64");
974        assert_eq!(Opcode::Rsh64Imm.to_str(), "rsh64");
975        assert_eq!(Opcode::Neg64.to_str(), "neg64");
976        assert_eq!(Opcode::Mod64Imm.to_str(), "mod64");
977        assert_eq!(Opcode::Xor64Imm.to_str(), "xor64");
978        assert_eq!(Opcode::Mov64Imm.to_str(), "mov64");
979        assert_eq!(Opcode::Arsh64Imm.to_str(), "arsh64");
980        assert_eq!(Opcode::Hor64Imm.to_str(), "hor64");
981        assert_eq!(Opcode::Lmul64Imm.to_str(), "lmul64");
982        assert_eq!(Opcode::Uhmul64Imm.to_str(), "uhmul64");
983        assert_eq!(Opcode::Udiv64Imm.to_str(), "udiv64");
984        assert_eq!(Opcode::Urem64Imm.to_str(), "urem64");
985        assert_eq!(Opcode::Shmul64Imm.to_str(), "shmul64");
986        assert_eq!(Opcode::Sdiv64Imm.to_str(), "sdiv64");
987        assert_eq!(Opcode::Srem64Imm.to_str(), "srem64");
988    }
989
990    #[test]
991    fn test_to_str_be_le_ops() {
992        assert_eq!(Opcode::Be.to_str(), "be");
993        assert_eq!(Opcode::Le.to_str(), "le");
994    }
995
996    #[test]
997    fn test_to_str_all_jump_ops() {
998        assert_eq!(Opcode::Ja.to_str(), "ja");
999        assert_eq!(Opcode::JeqImm.to_str(), "jeq");
1000        assert_eq!(Opcode::JeqReg.to_str(), "jeq");
1001        assert_eq!(Opcode::JgtImm.to_str(), "jgt");
1002        assert_eq!(Opcode::JgeImm.to_str(), "jge");
1003        assert_eq!(Opcode::JltImm.to_str(), "jlt");
1004        assert_eq!(Opcode::JleImm.to_str(), "jle");
1005        assert_eq!(Opcode::JsetImm.to_str(), "jset");
1006        assert_eq!(Opcode::JneImm.to_str(), "jne");
1007        assert_eq!(Opcode::JsgtImm.to_str(), "jsgt");
1008        assert_eq!(Opcode::JsgeImm.to_str(), "jsge");
1009        assert_eq!(Opcode::JsltImm.to_str(), "jslt");
1010        assert_eq!(Opcode::JsleImm.to_str(), "jsle");
1011    }
1012
1013    #[test]
1014    fn test_to_str_call_and_exit_ops() {
1015        assert_eq!(Opcode::Call.to_str(), "call");
1016        assert_eq!(Opcode::Callx.to_str(), "callx");
1017        assert_eq!(Opcode::Exit.to_str(), "exit");
1018    }
1019}