bind/interpreter/
instruction_decoder.rs

1// Copyright 2022 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::bytecode_constants::*;
6use crate::compiler::Symbol;
7use crate::interpreter::common::*;
8use crate::parser::bind_library;
9use num_traits::FromPrimitive;
10use serde::{Deserialize, Serialize};
11use std::collections::HashMap;
12
13#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
14pub struct DecodedCondition {
15    pub is_equal: bool,
16    pub lhs: Symbol,
17    pub rhs: Symbol,
18}
19
20// Verifies and converts instruction bytecode into a set of DecodedInstructions.
21// TODO(https://fxbug.dev/42175142): Add IDs to the Label and Jump statements.
22#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
23pub enum DecodedInstruction {
24    UnconditionalAbort,
25    Condition(DecodedCondition),
26    Jump(Option<DecodedCondition>),
27    Label,
28}
29
30#[derive(Debug, Clone)]
31pub struct InstructionDecoder<'a> {
32    symbol_table: &'a HashMap<u32, String>,
33    inst_iter: BytecodeIter<'a>,
34}
35
36impl<'a> InstructionDecoder<'a> {
37    pub fn new(
38        symbol_table: &'a HashMap<u32, String>,
39        instructions: &'a Vec<u8>,
40    ) -> InstructionDecoder<'a> {
41        InstructionDecoder { symbol_table: symbol_table, inst_iter: instructions.iter() }
42    }
43
44    pub fn decode(&mut self) -> Result<Vec<DecodedInstruction>, BytecodeError> {
45        let mut decoded_instructions: Vec<DecodedInstruction> = vec![];
46        while let Some(byte) = self.inst_iter.next() {
47            let op_byte = FromPrimitive::from_u8(*byte).ok_or(BytecodeError::InvalidOp(*byte))?;
48            let instruction = match op_byte {
49                RawOp::UnconditionalJump | RawOp::JumpIfEqual | RawOp::JumpIfNotEqual => {
50                    self.decode_control_flow_statement(op_byte)?
51                }
52                RawOp::EqualCondition | RawOp::InequalCondition => DecodedInstruction::Condition(
53                    self.decode_conditional_statement(op_byte == RawOp::EqualCondition)?,
54                ),
55                RawOp::Abort => DecodedInstruction::UnconditionalAbort,
56                RawOp::JumpLandPad => DecodedInstruction::Label,
57            };
58            decoded_instructions.push(instruction);
59        }
60
61        Ok(decoded_instructions)
62    }
63
64    fn decode_control_flow_statement(
65        &mut self,
66        op_byte: RawOp,
67    ) -> Result<DecodedInstruction, BytecodeError> {
68        // TODO(https://fxbug.dev/42175045): verify offset amount takes you to a jump landing pad.
69        let offset_amount = next_u32(&mut self.inst_iter)?;
70
71        let condition = match op_byte {
72            RawOp::JumpIfEqual => Some(self.decode_conditional_statement(true)?),
73            RawOp::JumpIfNotEqual => Some(self.decode_conditional_statement(false)?),
74            RawOp::UnconditionalJump => None,
75            _ => {
76                return Err(BytecodeError::InvalidOp(op_byte as u8));
77            }
78        };
79
80        if self.inst_iter.len() as u32 <= offset_amount {
81            return Err(BytecodeError::InvalidJumpLocation);
82        }
83
84        Ok(DecodedInstruction::Jump(condition))
85    }
86
87    fn decode_conditional_statement(
88        &mut self,
89        is_equal: bool,
90    ) -> Result<DecodedCondition, BytecodeError> {
91        // Read in the LHS value first, followed by the RHS value.
92        let lhs = self.decode_value()?;
93        let rhs = self.decode_value()?;
94        Ok(DecodedCondition { is_equal: is_equal, lhs: lhs, rhs: rhs })
95    }
96
97    fn decode_value(&mut self) -> Result<Symbol, BytecodeError> {
98        let val_primitive = *next_u8(&mut self.inst_iter)?;
99        let val_type = FromPrimitive::from_u8(val_primitive)
100            .ok_or(BytecodeError::InvalidValueType(val_primitive))?;
101        let val = next_u32(&mut self.inst_iter)?;
102
103        match val_type {
104            RawValueType::NumberValue => Ok(Symbol::NumberValue(val as u64)),
105            RawValueType::BoolValue => match val {
106                FALSE_VAL => Ok(Symbol::BoolValue(false)),
107                TRUE_VAL => Ok(Symbol::BoolValue(true)),
108                _ => Err(BytecodeError::InvalidBoolValue(val)),
109            },
110            RawValueType::Key => {
111                Ok(Symbol::Key(self.lookup_symbol_table(val)?, bind_library::ValueType::Str))
112            }
113            RawValueType::StringValue => Ok(Symbol::StringValue(self.lookup_symbol_table(val)?)),
114            RawValueType::EnumValue => Ok(Symbol::EnumValue(self.lookup_symbol_table(val)?)),
115        }
116    }
117
118    fn lookup_symbol_table(&self, key: u32) -> Result<String, BytecodeError> {
119        self.symbol_table
120            .get(&key)
121            .ok_or(BytecodeError::MissingEntryInSymbolTable(key))
122            .map(|val| val.to_string())
123    }
124}
125
126#[cfg(test)]
127mod test {
128    use super::*;
129    use crate::interpreter::decode_bind_rules::{DecodedRules, NODE_TYPE_HEADER_SZ};
130    use crate::interpreter::test_common::*;
131
132    fn append_section_header(bytecode: &mut Vec<u8>, magic_num: u32, sz: u32) {
133        bytecode.extend_from_slice(&magic_num.to_be_bytes());
134        bytecode.extend_from_slice(&sz.to_le_bytes());
135    }
136
137    fn append_node_header(bytecode: &mut Vec<u8>, node_type: RawNodeType, node_id: u32, sz: u32) {
138        bytecode.push(node_type as u8);
139        bytecode.extend_from_slice(&node_id.to_le_bytes());
140        bytecode.extend_from_slice(&sz.to_le_bytes());
141    }
142
143    #[test]
144    fn test_invalid_value_type() {
145        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
146        bytecode.push(BYTECODE_DISABLE_DEBUG);
147        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 0);
148
149        let instructions = [0x01, 0x01, 0, 0, 0, 0x05, 0x10, 0, 0, 0, 0];
150        append_section_header(&mut bytecode, INSTRUCTION_MAGIC_NUM, instructions.len() as u32);
151        bytecode.extend_from_slice(&instructions);
152
153        assert_eq!(Err(BytecodeError::InvalidValueType(0x10)), DecodedRules::new(bytecode));
154    }
155
156    #[test]
157    fn test_value_string_missing_in_symbols() {
158        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
159        bytecode.push(BYTECODE_DISABLE_DEBUG);
160        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 0);
161
162        let instructions = [0x01, 0x02, 0, 0, 0, 0x05, 0x10, 0, 0, 0, 0];
163        append_section_header(&mut bytecode, INSTRUCTION_MAGIC_NUM, instructions.len() as u32);
164        bytecode.extend_from_slice(&instructions);
165
166        assert_eq!(
167            Err(BytecodeError::MissingEntryInSymbolTable(0x05000000)),
168            DecodedRules::new(bytecode)
169        );
170    }
171
172    #[test]
173    fn test_value_enum_missing_in_symbols() {
174        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
175        bytecode.push(BYTECODE_DISABLE_DEBUG);
176        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 0);
177
178        let instructions = [0x01, 0x04, 0, 0, 0, 0x05, 0x10, 0, 0, 0, 0];
179        append_section_header(&mut bytecode, INSTRUCTION_MAGIC_NUM, instructions.len() as u32);
180        bytecode.extend_from_slice(&instructions);
181
182        assert_eq!(
183            Err(BytecodeError::MissingEntryInSymbolTable(0x05000000)),
184            DecodedRules::new(bytecode)
185        );
186    }
187
188    #[test]
189    fn test_value_invalid_bool() {
190        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
191        bytecode.push(BYTECODE_DISABLE_DEBUG);
192        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 0);
193
194        let instructions = [0x01, 0x01, 0, 0, 0, 0x05, 0x03, 0, 0, 0, 0x01];
195        append_section_header(&mut bytecode, INSTRUCTION_MAGIC_NUM, instructions.len() as u32);
196        bytecode.extend_from_slice(&instructions);
197
198        assert_eq!(Err(BytecodeError::InvalidBoolValue(0x01000000)), DecodedRules::new(bytecode));
199    }
200
201    #[test]
202    fn test_invalid_outofbounds_jump_offset() {
203        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
204        bytecode.push(BYTECODE_DISABLE_DEBUG);
205        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 0);
206
207        let instructions = [
208            0x11, 0x01, 0, 0, 0, 0x01, 0, 0, 0, 0x05, 0x01, 0x10, 0, 0,
209            0, // jump 1 if 0x05000000 == 0x10
210            0x30, 0x20, // abort, jump pad
211            0x10, 0x02, 0, 0,
212            0, // jump 2 (this is the invalid jump as there is only 2 bytes left)
213            0x30, 0x20, // abort, jump pad
214        ];
215        append_section_header(&mut bytecode, INSTRUCTION_MAGIC_NUM, instructions.len() as u32);
216        bytecode.extend_from_slice(&instructions);
217
218        // The last jump would put your instruction pointer past the last element.
219        assert_eq!(Err(BytecodeError::InvalidJumpLocation), DecodedRules::new(bytecode));
220    }
221
222    #[test]
223    fn test_invalid_outofbounds_jump_offset_composite_primary() {
224        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
225        bytecode.push(BYTECODE_DISABLE_DEBUG);
226        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 27);
227
228        let device_name: [u8; 5] = [0x49, 0x42, 0x49, 0x53, 0]; // "IBIS"
229        bytecode.extend_from_slice(&[1, 0, 0, 0]);
230        bytecode.extend_from_slice(&device_name);
231
232        let primary_node_name: [u8; 5] = [0x52, 0x41, 0x49, 0x4C, 0]; // "RAIL"
233        bytecode.extend_from_slice(&[2, 0, 0, 0]);
234        bytecode.extend_from_slice(&primary_node_name);
235
236        let node_name_1: [u8; 5] = [0x43, 0x4F, 0x4F, 0x54, 0]; // "COOT"
237        bytecode.extend_from_slice(&[3, 0, 0, 0]);
238        bytecode.extend_from_slice(&node_name_1);
239
240        // There is a jump 4 that would go out of bounds for the primary node instructions.
241        let primary_node_inst =
242            [0x01, 0x01, 0, 0, 0, 0x05, 0x01, 0x10, 0, 0x20, 0, 0x10, 0x04, 0, 0, 0];
243
244        let additional_node_inst = [0x02, 0x01, 0, 0, 0, 0x02, 0x02, 0, 0, 0x10];
245
246        let composite_insts_sz = COMPOSITE_NAME_ID_BYTES
247            + ((NODE_TYPE_HEADER_SZ * 2) + primary_node_inst.len() + additional_node_inst.len())
248                as u32;
249        append_section_header(&mut bytecode, COMPOSITE_MAGIC_NUM, composite_insts_sz);
250
251        // Add device name ID.
252        bytecode.extend_from_slice(&[1, 0, 0, 0]);
253
254        append_node_header(&mut bytecode, RawNodeType::Primary, 2, primary_node_inst.len() as u32);
255        bytecode.extend_from_slice(&primary_node_inst);
256
257        // Add the additional node.
258        append_node_header(
259            &mut bytecode,
260            RawNodeType::Additional,
261            3,
262            additional_node_inst.len() as u32,
263        );
264        bytecode.extend_from_slice(&additional_node_inst);
265
266        assert_eq!(Err(BytecodeError::InvalidJumpLocation), DecodedRules::new(bytecode));
267    }
268
269    #[test]
270    fn test_invalid_outofbounds_jump_offset_composite_additional() {
271        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
272        bytecode.push(BYTECODE_DISABLE_DEBUG);
273        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 27);
274
275        let device_name: [u8; 5] = [0x49, 0x42, 0x49, 0x53, 0]; // "IBIS"
276        bytecode.extend_from_slice(&[1, 0, 0, 0]);
277        bytecode.extend_from_slice(&device_name);
278
279        let primary_node_name: [u8; 5] = [0x52, 0x41, 0x49, 0x4C, 0]; // "RAIL"
280        bytecode.extend_from_slice(&[2, 0, 0, 0]);
281        bytecode.extend_from_slice(&primary_node_name);
282
283        let node_name_1: [u8; 5] = [0x43, 0x4F, 0x4F, 0x54, 0]; // "COOT"
284        bytecode.extend_from_slice(&[3, 0, 0, 0]);
285        bytecode.extend_from_slice(&node_name_1);
286
287        let primary_node_inst = [0x02, 0x01, 0, 0, 0, 0x02, 0x01, 0, 0, 0, 0x10];
288
289        // There is a jump 4 that would go out of bounds for the additional node instructions.
290        let additional_node_inst =
291            [0x01, 0x01, 0, 0, 0, 0x05, 0x01, 0x10, 0, 0x20, 0, 0x10, 0x04, 0, 0, 0];
292
293        let composite_insts_sz = COMPOSITE_NAME_ID_BYTES
294            + ((NODE_TYPE_HEADER_SZ * 2) + primary_node_inst.len() + additional_node_inst.len())
295                as u32;
296        append_section_header(&mut bytecode, COMPOSITE_MAGIC_NUM, composite_insts_sz);
297
298        // Add device name ID.
299        bytecode.extend_from_slice(&[1, 0, 0, 0]);
300
301        append_node_header(&mut bytecode, RawNodeType::Primary, 2, primary_node_inst.len() as u32);
302        bytecode.extend_from_slice(&primary_node_inst);
303
304        // Add the additional node.
305        append_node_header(
306            &mut bytecode,
307            RawNodeType::Additional,
308            3,
309            additional_node_inst.len() as u32,
310        );
311        bytecode.extend_from_slice(&additional_node_inst);
312
313        assert_eq!(Err(BytecodeError::InvalidJumpLocation), DecodedRules::new(bytecode));
314    }
315
316    #[test]
317    fn test_invalid_value_type_composite_primary() {
318        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
319        bytecode.push(BYTECODE_DISABLE_DEBUG);
320        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 27);
321
322        let device_name: [u8; 5] = [0x49, 0x42, 0x49, 0x53, 0]; // "IBIS"
323        bytecode.extend_from_slice(&[1, 0, 0, 0]);
324        bytecode.extend_from_slice(&device_name);
325
326        let primary_node_name: [u8; 5] = [0x52, 0x41, 0x49, 0x4C, 0]; // "RAIL"
327        bytecode.extend_from_slice(&[2, 0, 0, 0]);
328        bytecode.extend_from_slice(&primary_node_name);
329
330        let node_name_1: [u8; 5] = [0x43, 0x4F, 0x4F, 0x54, 0]; // "COOT"
331        bytecode.extend_from_slice(&[3, 0, 0, 0]);
332        bytecode.extend_from_slice(&node_name_1);
333
334        // There is no value type enum for 0x05.
335        let primary_node_inst = [0x02, 0x01, 0, 0, 0, 0x02, 0x05, 0, 0, 0, 0x10];
336
337        let additional_node_inst = [0x01, 0x01, 0, 0, 0, 0x05, 0x01, 0x10, 0, 0x20, 0];
338
339        let composite_insts_sz = COMPOSITE_NAME_ID_BYTES
340            + ((NODE_TYPE_HEADER_SZ * 2) + primary_node_inst.len() + additional_node_inst.len())
341                as u32;
342        append_section_header(&mut bytecode, COMPOSITE_MAGIC_NUM, composite_insts_sz);
343
344        // Add device name ID.
345        bytecode.extend_from_slice(&[1, 0, 0, 0]);
346
347        append_node_header(&mut bytecode, RawNodeType::Primary, 2, primary_node_inst.len() as u32);
348        bytecode.extend_from_slice(&primary_node_inst);
349
350        // Add the additional node.
351        append_node_header(
352            &mut bytecode,
353            RawNodeType::Additional,
354            3,
355            additional_node_inst.len() as u32,
356        );
357        bytecode.extend_from_slice(&additional_node_inst);
358
359        assert_eq!(Err(BytecodeError::InvalidValueType(0x05)), DecodedRules::new(bytecode));
360    }
361
362    #[test]
363    fn test_invalid_value_type_composite_additional() {
364        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
365        bytecode.push(BYTECODE_DISABLE_DEBUG);
366        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 27);
367
368        let device_name: [u8; 5] = [0x49, 0x42, 0x49, 0x53, 0]; // "IBIS"
369        bytecode.extend_from_slice(&[1, 0, 0, 0]);
370        bytecode.extend_from_slice(&device_name);
371
372        let primary_node_name: [u8; 5] = [0x52, 0x41, 0x49, 0x4C, 0]; // "RAIL"
373        bytecode.extend_from_slice(&[2, 0, 0, 0]);
374        bytecode.extend_from_slice(&primary_node_name);
375
376        let node_name_1: [u8; 5] = [0x43, 0x4F, 0x4F, 0x54, 0]; // "COOT"
377        bytecode.extend_from_slice(&[3, 0, 0, 0]);
378        bytecode.extend_from_slice(&node_name_1);
379
380        let primary_node_inst = [0x01, 0x01, 0, 0, 0, 0x05, 0x01, 0x10, 0, 0x20, 0];
381
382        // There is no value type enum for 0x05.
383        let additional_node_inst = [0x02, 0x01, 0, 0, 0, 0x02, 0x05, 0, 0, 0, 0x10];
384
385        let composite_insts_sz = COMPOSITE_NAME_ID_BYTES
386            + ((NODE_TYPE_HEADER_SZ * 2) + primary_node_inst.len() + additional_node_inst.len())
387                as u32;
388        append_section_header(&mut bytecode, COMPOSITE_MAGIC_NUM, composite_insts_sz);
389
390        // Add device name ID.
391        bytecode.extend_from_slice(&[1, 0, 0, 0]);
392
393        append_node_header(&mut bytecode, RawNodeType::Primary, 2, primary_node_inst.len() as u32);
394        bytecode.extend_from_slice(&primary_node_inst);
395
396        // Add the additional node.
397        append_node_header(
398            &mut bytecode,
399            RawNodeType::Additional,
400            3,
401            additional_node_inst.len() as u32,
402        );
403        bytecode.extend_from_slice(&additional_node_inst);
404
405        assert_eq!(Err(BytecodeError::InvalidValueType(0x05)), DecodedRules::new(bytecode));
406    }
407
408    #[test]
409    fn test_value_key_missing_in_symbols_composite_primary() {
410        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
411        bytecode.push(BYTECODE_DISABLE_DEBUG);
412        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 27);
413
414        let device_name: [u8; 5] = [0x49, 0x42, 0x49, 0x53, 0]; // "IBIS"
415        bytecode.extend_from_slice(&[1, 0, 0, 0]);
416        bytecode.extend_from_slice(&device_name);
417
418        let primary_node_name: [u8; 5] = [0x52, 0x41, 0x49, 0x4C, 0]; // "RAIL"
419        bytecode.extend_from_slice(&[2, 0, 0, 0]);
420        bytecode.extend_from_slice(&primary_node_name);
421
422        let node_name_1: [u8; 5] = [0x43, 0x4F, 0x4F, 0x54, 0]; // "COOT"
423        bytecode.extend_from_slice(&[3, 0, 0, 0]);
424        bytecode.extend_from_slice(&node_name_1);
425
426        // There is no key type (type 0x00) with key 0x10000000.
427        let primary_node_inst = [0x02, 0x01, 0, 0, 0, 0x02, 0x00, 0, 0, 0, 0x10];
428
429        let additional_node_inst = [0x01, 0x01, 0, 0, 0, 0x05, 0x01, 0x10, 0, 0x20, 0];
430
431        let composite_insts_sz = COMPOSITE_NAME_ID_BYTES
432            + ((NODE_TYPE_HEADER_SZ * 2) + primary_node_inst.len() + additional_node_inst.len())
433                as u32;
434        append_section_header(&mut bytecode, COMPOSITE_MAGIC_NUM, composite_insts_sz);
435
436        // Add device name ID.
437        bytecode.extend_from_slice(&[1, 0, 0, 0]);
438
439        append_node_header(&mut bytecode, RawNodeType::Primary, 2, primary_node_inst.len() as u32);
440        bytecode.extend_from_slice(&primary_node_inst);
441
442        // Add the additional node.
443        append_node_header(
444            &mut bytecode,
445            RawNodeType::Additional,
446            3,
447            additional_node_inst.len() as u32,
448        );
449        bytecode.extend_from_slice(&additional_node_inst);
450
451        assert_eq!(
452            Err(BytecodeError::MissingEntryInSymbolTable(0x10000000)),
453            DecodedRules::new(bytecode)
454        );
455    }
456
457    #[test]
458    fn test_value_key_missing_in_symbols_composite_additional() {
459        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
460        bytecode.push(BYTECODE_DISABLE_DEBUG);
461        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 27);
462
463        let device_name: [u8; 5] = [0x49, 0x42, 0x49, 0x53, 0]; // "IBIS"
464        bytecode.extend_from_slice(&[1, 0, 0, 0]);
465        bytecode.extend_from_slice(&device_name);
466
467        let primary_node_name: [u8; 5] = [0x52, 0x41, 0x49, 0x4C, 0]; // "RAIL"
468        bytecode.extend_from_slice(&[2, 0, 0, 0]);
469        bytecode.extend_from_slice(&primary_node_name);
470
471        let node_name_1: [u8; 5] = [0x43, 0x4F, 0x4F, 0x54, 0]; // "COOT"
472        bytecode.extend_from_slice(&[3, 0, 0, 0]);
473        bytecode.extend_from_slice(&node_name_1);
474
475        let primary_node_inst = [0x01, 0x01, 0, 0, 0, 0x05, 0x01, 0x10, 0, 0x20, 0];
476
477        // There is no key type (type 0x00) with key 0x10000000.
478        let additional_node_inst = [0x02, 0x01, 0, 0, 0, 0x02, 0x00, 0, 0, 0, 0x10];
479
480        let composite_insts_sz = COMPOSITE_NAME_ID_BYTES
481            + ((NODE_TYPE_HEADER_SZ * 2) + primary_node_inst.len() + additional_node_inst.len())
482                as u32;
483        append_section_header(&mut bytecode, COMPOSITE_MAGIC_NUM, composite_insts_sz);
484
485        // Add device name ID.
486        bytecode.extend_from_slice(&[1, 0, 0, 0]);
487
488        append_node_header(&mut bytecode, RawNodeType::Primary, 2, primary_node_inst.len() as u32);
489        bytecode.extend_from_slice(&primary_node_inst);
490
491        // Add the additional node.
492        append_node_header(
493            &mut bytecode,
494            RawNodeType::Additional,
495            3,
496            additional_node_inst.len() as u32,
497        );
498        bytecode.extend_from_slice(&additional_node_inst);
499
500        assert_eq!(
501            Err(BytecodeError::MissingEntryInSymbolTable(0x10000000)),
502            DecodedRules::new(bytecode)
503        );
504    }
505
506    #[test]
507    fn test_value_string_missing_in_symbols_composite_primary() {
508        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
509        bytecode.push(BYTECODE_DISABLE_DEBUG);
510        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 27);
511
512        let device_name: [u8; 5] = [0x49, 0x42, 0x49, 0x53, 0]; // "IBIS"
513        bytecode.extend_from_slice(&[1, 0, 0, 0]);
514        bytecode.extend_from_slice(&device_name);
515
516        let primary_node_name: [u8; 5] = [0x52, 0x41, 0x49, 0x4C, 0]; // "RAIL"
517        bytecode.extend_from_slice(&[2, 0, 0, 0]);
518        bytecode.extend_from_slice(&primary_node_name);
519
520        let node_name_1: [u8; 5] = [0x43, 0x4F, 0x4F, 0x54, 0]; // "COOT"
521        bytecode.extend_from_slice(&[3, 0, 0, 0]);
522        bytecode.extend_from_slice(&node_name_1);
523
524        // There is no string literal (type 0x02) with key 0x10000000.
525        let primary_node_inst = [0x02, 0x01, 0, 0, 0, 0x02, 0x02, 0, 0, 0, 0x10];
526
527        let additional_node_inst = [0x01, 0x01, 0, 0, 0, 0x05, 0x01, 0x10, 0, 0x20, 0];
528
529        let composite_insts_sz = COMPOSITE_NAME_ID_BYTES
530            + ((NODE_TYPE_HEADER_SZ * 2) + primary_node_inst.len() + additional_node_inst.len())
531                as u32;
532        append_section_header(&mut bytecode, COMPOSITE_MAGIC_NUM, composite_insts_sz);
533
534        // Add device name ID.
535        bytecode.extend_from_slice(&[1, 0, 0, 0]);
536
537        append_node_header(&mut bytecode, RawNodeType::Primary, 2, primary_node_inst.len() as u32);
538        bytecode.extend_from_slice(&primary_node_inst);
539
540        // Add the additional node.
541        append_node_header(
542            &mut bytecode,
543            RawNodeType::Additional,
544            3,
545            additional_node_inst.len() as u32,
546        );
547        bytecode.extend_from_slice(&additional_node_inst);
548
549        assert_eq!(
550            Err(BytecodeError::MissingEntryInSymbolTable(0x10000000)),
551            DecodedRules::new(bytecode)
552        );
553    }
554
555    #[test]
556    fn test_value_string_missing_in_symbols_composite_additional() {
557        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
558        bytecode.push(BYTECODE_DISABLE_DEBUG);
559        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 27);
560
561        let device_name: [u8; 5] = [0x49, 0x42, 0x49, 0x53, 0]; // "IBIS"
562        bytecode.extend_from_slice(&[1, 0, 0, 0]);
563        bytecode.extend_from_slice(&device_name);
564
565        let primary_node_name: [u8; 5] = [0x52, 0x41, 0x49, 0x4C, 0]; // "RAIL"
566        bytecode.extend_from_slice(&[2, 0, 0, 0]);
567        bytecode.extend_from_slice(&primary_node_name);
568
569        let node_name_1: [u8; 5] = [0x43, 0x4F, 0x4F, 0x54, 0]; // "COOT"
570        bytecode.extend_from_slice(&[3, 0, 0, 0]);
571        bytecode.extend_from_slice(&node_name_1);
572
573        let primary_node_inst = [0x01, 0x01, 0, 0, 0, 0x05, 0x01, 0x10, 0, 0x20, 0];
574
575        // There is no string literal (type 0x02) with key 0x10000000.
576        let additional_node_inst = [0x02, 0x01, 0, 0, 0, 0x02, 0x02, 0, 0, 0, 0x10];
577
578        let composite_insts_sz = COMPOSITE_NAME_ID_BYTES
579            + ((NODE_TYPE_HEADER_SZ * 2) + primary_node_inst.len() + additional_node_inst.len())
580                as u32;
581        append_section_header(&mut bytecode, COMPOSITE_MAGIC_NUM, composite_insts_sz);
582
583        // Add device name ID.
584        bytecode.extend_from_slice(&[1, 0, 0, 0]);
585
586        append_node_header(&mut bytecode, RawNodeType::Primary, 2, primary_node_inst.len() as u32);
587        bytecode.extend_from_slice(&primary_node_inst);
588
589        // Add the additional node.
590        append_node_header(
591            &mut bytecode,
592            RawNodeType::Additional,
593            3,
594            additional_node_inst.len() as u32,
595        );
596        bytecode.extend_from_slice(&additional_node_inst);
597
598        assert_eq!(
599            Err(BytecodeError::MissingEntryInSymbolTable(0x10000000)),
600            DecodedRules::new(bytecode)
601        );
602    }
603
604    #[test]
605    fn test_value_enum_missing_in_symbols_composite_primary() {
606        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
607        bytecode.push(BYTECODE_DISABLE_DEBUG);
608        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 27);
609
610        let device_name: [u8; 5] = [0x49, 0x42, 0x49, 0x53, 0]; // "IBIS"
611        bytecode.extend_from_slice(&[1, 0, 0, 0]);
612        bytecode.extend_from_slice(&device_name);
613
614        let primary_node_name: [u8; 5] = [0x52, 0x41, 0x49, 0x4C, 0]; // "RAIL"
615        bytecode.extend_from_slice(&[2, 0, 0, 0]);
616        bytecode.extend_from_slice(&primary_node_name);
617
618        let node_name_1: [u8; 5] = [0x43, 0x4F, 0x4F, 0x54, 0]; // "COOT"
619        bytecode.extend_from_slice(&[3, 0, 0, 0]);
620        bytecode.extend_from_slice(&node_name_1);
621
622        // There is no enum value (type 0x04) with key 0x10000000.
623        let primary_node_inst = [0x02, 0x01, 0, 0, 0, 0x02, 0x04, 0, 0, 0, 0x10];
624
625        let additional_node_inst = [0x01, 0x01, 0, 0, 0, 0x05, 0x01, 0x10, 0, 0x20, 0];
626
627        let composite_insts_sz = COMPOSITE_NAME_ID_BYTES
628            + ((NODE_TYPE_HEADER_SZ * 2) + primary_node_inst.len() + additional_node_inst.len())
629                as u32;
630        append_section_header(&mut bytecode, COMPOSITE_MAGIC_NUM, composite_insts_sz);
631
632        // Add device name ID.
633        bytecode.extend_from_slice(&[1, 0, 0, 0]);
634
635        append_node_header(&mut bytecode, RawNodeType::Primary, 2, primary_node_inst.len() as u32);
636        bytecode.extend_from_slice(&primary_node_inst);
637
638        // Add the additional node.
639        append_node_header(
640            &mut bytecode,
641            RawNodeType::Additional,
642            3,
643            additional_node_inst.len() as u32,
644        );
645        bytecode.extend_from_slice(&additional_node_inst);
646
647        assert_eq!(
648            Err(BytecodeError::MissingEntryInSymbolTable(0x10000000)),
649            DecodedRules::new(bytecode)
650        );
651    }
652
653    #[test]
654    fn test_value_enum_missing_in_symbols_composite_additional() {
655        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
656        bytecode.push(BYTECODE_DISABLE_DEBUG);
657        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 27);
658
659        let device_name: [u8; 5] = [0x49, 0x42, 0x49, 0x53, 0]; // "IBIS"
660        bytecode.extend_from_slice(&[1, 0, 0, 0]);
661        bytecode.extend_from_slice(&device_name);
662
663        let primary_node_name: [u8; 5] = [0x52, 0x41, 0x49, 0x4C, 0]; // "RAIL"
664        bytecode.extend_from_slice(&[2, 0, 0, 0]);
665        bytecode.extend_from_slice(&primary_node_name);
666
667        let node_name_1: [u8; 5] = [0x43, 0x4F, 0x4F, 0x54, 0]; // "COOT"
668        bytecode.extend_from_slice(&[3, 0, 0, 0]);
669        bytecode.extend_from_slice(&node_name_1);
670
671        let primary_node_inst = [0x01, 0x01, 0, 0, 0, 0x05, 0x01, 0x10, 0, 0x20, 0];
672
673        // There is no enum value (type 0x04) with key 0x10000000.
674        let additional_node_inst = [0x02, 0x01, 0, 0, 0, 0x02, 0x04, 0, 0, 0, 0x10];
675
676        let composite_insts_sz = COMPOSITE_NAME_ID_BYTES
677            + ((NODE_TYPE_HEADER_SZ * 2) + primary_node_inst.len() + additional_node_inst.len())
678                as u32;
679        append_section_header(&mut bytecode, COMPOSITE_MAGIC_NUM, composite_insts_sz);
680
681        // Add device name ID.
682        bytecode.extend_from_slice(&[1, 0, 0, 0]);
683
684        append_node_header(&mut bytecode, RawNodeType::Primary, 2, primary_node_inst.len() as u32);
685        bytecode.extend_from_slice(&primary_node_inst);
686
687        // Add the additional node.
688        append_node_header(
689            &mut bytecode,
690            RawNodeType::Additional,
691            3,
692            additional_node_inst.len() as u32,
693        );
694        bytecode.extend_from_slice(&additional_node_inst);
695
696        assert_eq!(
697            Err(BytecodeError::MissingEntryInSymbolTable(0x10000000)),
698            DecodedRules::new(bytecode)
699        );
700    }
701
702    #[test]
703    fn test_value_invalid_bool_composite_primary() {
704        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
705        bytecode.push(BYTECODE_DISABLE_DEBUG);
706        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 27);
707
708        let device_name: [u8; 5] = [0x49, 0x42, 0x49, 0x53, 0]; // "IBIS"
709        bytecode.extend_from_slice(&[1, 0, 0, 0]);
710        bytecode.extend_from_slice(&device_name);
711
712        let primary_node_name: [u8; 5] = [0x52, 0x41, 0x49, 0x4C, 0]; // "RAIL"
713        bytecode.extend_from_slice(&[2, 0, 0, 0]);
714        bytecode.extend_from_slice(&primary_node_name);
715
716        let node_name_1: [u8; 5] = [0x43, 0x4F, 0x4F, 0x54, 0]; // "COOT"
717        bytecode.extend_from_slice(&[3, 0, 0, 0]);
718        bytecode.extend_from_slice(&node_name_1);
719
720        // 0x10000000 is not a valid bool value.
721        let primary_node_inst = [0x02, 0x01, 0, 0, 0, 0x02, 0x03, 0, 0, 0, 0x10];
722
723        let additional_node_inst = [0x01, 0x01, 0, 0, 0, 0x05, 0x01, 0x10, 0, 0x20, 0];
724
725        let composite_insts_sz = COMPOSITE_NAME_ID_BYTES
726            + ((NODE_TYPE_HEADER_SZ * 2) + primary_node_inst.len() + additional_node_inst.len())
727                as u32;
728        append_section_header(&mut bytecode, COMPOSITE_MAGIC_NUM, composite_insts_sz);
729
730        // Add device name ID.
731        bytecode.extend_from_slice(&[1, 0, 0, 0]);
732
733        append_node_header(&mut bytecode, RawNodeType::Primary, 2, primary_node_inst.len() as u32);
734        bytecode.extend_from_slice(&primary_node_inst);
735
736        // Add the additional node.
737        append_node_header(
738            &mut bytecode,
739            RawNodeType::Additional,
740            3,
741            additional_node_inst.len() as u32,
742        );
743        bytecode.extend_from_slice(&additional_node_inst);
744
745        assert_eq!(Err(BytecodeError::InvalidBoolValue(0x10000000)), DecodedRules::new(bytecode));
746    }
747
748    #[test]
749    fn test_value_invalid_bool_composite_additional() {
750        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
751        bytecode.push(BYTECODE_DISABLE_DEBUG);
752        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 27);
753
754        let device_name: [u8; 5] = [0x49, 0x42, 0x49, 0x53, 0]; // "IBIS"
755        bytecode.extend_from_slice(&[1, 0, 0, 0]);
756        bytecode.extend_from_slice(&device_name);
757
758        let primary_node_name: [u8; 5] = [0x52, 0x41, 0x49, 0x4C, 0]; // "RAIL"
759        bytecode.extend_from_slice(&[2, 0, 0, 0]);
760        bytecode.extend_from_slice(&primary_node_name);
761
762        let node_name_1: [u8; 5] = [0x43, 0x4F, 0x4F, 0x54, 0]; // "COOT"
763        bytecode.extend_from_slice(&[3, 0, 0, 0]);
764        bytecode.extend_from_slice(&node_name_1);
765
766        let primary_node_inst = [0x01, 0x01, 0, 0, 0, 0x05, 0x01, 0x10, 0, 0x20, 0];
767
768        // 0x10000000 is not a valid bool value.
769        let additional_node_inst = [0x02, 0x01, 0, 0, 0, 0x02, 0x03, 0, 0, 0, 0x10];
770
771        let composite_insts_sz = COMPOSITE_NAME_ID_BYTES
772            + ((NODE_TYPE_HEADER_SZ * 2) + primary_node_inst.len() + additional_node_inst.len())
773                as u32;
774        append_section_header(&mut bytecode, COMPOSITE_MAGIC_NUM, composite_insts_sz);
775
776        // Add device name ID.
777        bytecode.extend_from_slice(&[1, 0, 0, 0]);
778
779        append_node_header(&mut bytecode, RawNodeType::Primary, 2, primary_node_inst.len() as u32);
780        bytecode.extend_from_slice(&primary_node_inst);
781
782        // Add the additional node.
783        append_node_header(
784            &mut bytecode,
785            RawNodeType::Additional,
786            3,
787            additional_node_inst.len() as u32,
788        );
789        bytecode.extend_from_slice(&additional_node_inst);
790
791        assert_eq!(Err(BytecodeError::InvalidBoolValue(0x10000000)), DecodedRules::new(bytecode));
792    }
793}