Skip to main content

bind/interpreter/
decode_bind_rules.rs

1// Copyright 2021 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::interpreter::common::*;
7use crate::interpreter::instruction_decoder::*;
8use num_traits::FromPrimitive;
9use serde::{Deserialize, Serialize};
10use std::collections::HashMap;
11
12// Each node section header contains a u8 node type and a uint32 section
13// size.
14pub const NODE_TYPE_HEADER_SZ: usize = 9;
15
16// At minimum, the bytecode would contain the bind header, symbol table
17// header and instruction header.
18const MINIMUM_BYTECODE_SZ: usize = HEADER_SZ * 3;
19
20// Each debug flag byte contains 1 byte
21const DEBUG_FLAG_SZ: usize = 1;
22
23// Parse through the bytecode and separate out the symbol table, instructions
24// and an optional debug section. Verify the bytecode header and the symbol table
25// header.
26fn get_symbol_table_and_instruction_debug_bytecode(
27    bytecode: Vec<u8>,
28) -> Result<(HashMap<u32, String>, Vec<u8>, Option<Vec<u8>>), BytecodeError> {
29    if bytecode.len() < MINIMUM_BYTECODE_SZ {
30        return Err(BytecodeError::UnexpectedEnd);
31    }
32
33    // Remove the bytecode header and verify the bytecode version.
34    let (version, bytecode) = read_and_remove_header(bytecode, BIND_MAGIC_NUM)?;
35    if version != BYTECODE_VERSION {
36        return Err(BytecodeError::InvalidVersion(version));
37    }
38
39    // Remove the enable_debug flag byte from the bytecode
40    let (debug_flag_byte, bytecode) = read_and_remove_debug_flag(bytecode)?;
41
42    // Remove the symbol table header and verify that the size is less than
43    // the remaining bytecode.
44    let (symbol_table_sz, mut symbol_table_bytecode) =
45        read_and_remove_header(bytecode, SYMB_MAGIC_NUM)?;
46    if symbol_table_bytecode.len() < symbol_table_sz as usize + HEADER_SZ {
47        return Err(BytecodeError::IncorrectSectionSize);
48    }
49
50    // Split the instruction bytecode from the symbol table bytecode.
51    let mut inst_bytecode = symbol_table_bytecode.split_off(symbol_table_sz as usize);
52
53    // Read in the instruction section size and verify that the size is correct.
54    let inst_bytecode_size = u32::from_le_bytes(get_u32_bytes(&inst_bytecode, 4)?);
55    if inst_bytecode.len() < inst_bytecode_size as usize + HEADER_SZ {
56        return Err(BytecodeError::IncorrectSectionSize);
57    }
58
59    // Split the debug bytecode from the instruction bytecode if the debug flag
60    // byte is true.
61    let debug_bytecode = if debug_flag_byte == BYTECODE_ENABLE_DEBUG {
62        let debug_result = inst_bytecode.split_off(inst_bytecode_size as usize + HEADER_SZ);
63        let (debug_sz, debug_result_vec) = read_and_remove_header(debug_result, DEBG_MAGIC_NUM)?;
64        if debug_result_vec.len() != debug_sz as usize {
65            return Err(BytecodeError::IncorrectSectionSize);
66        }
67        Some(debug_result_vec)
68    } else {
69        None
70    };
71
72    Ok((read_symbol_table(symbol_table_bytecode)?, inst_bytecode, debug_bytecode))
73}
74
75// Remove the instructions in the first node and return it along with the
76// remaining bytecode.
77fn split_off_parent(
78    mut bytecode: Vec<u8>,
79    expect_primary: bool,
80    symbol_table: &HashMap<u32, String>,
81) -> Result<(bool, Parent, Vec<u8>), BytecodeError> {
82    // Verify the node type and retrieve the node section size.
83    let (is_optional, node_id, node_inst_sz) =
84        verify_and_read_node_header(&bytecode, expect_primary)?;
85    if bytecode.len() < NODE_TYPE_HEADER_SZ + node_inst_sz as usize {
86        return Err(BytecodeError::IncorrectParentSectionSize);
87    }
88
89    if !symbol_table.contains_key(&node_id) {
90        return Err(BytecodeError::MissingParentIdInSymbolTable);
91    }
92
93    let mut node_instructions = bytecode.split_off(NODE_TYPE_HEADER_SZ);
94    let remaining_bytecode = node_instructions.split_off(node_inst_sz as usize);
95    let decoded_instructions =
96        InstructionDecoder::new(symbol_table, &node_instructions).decode()?;
97    Ok((
98        is_optional,
99        Parent {
100            name_id: node_id,
101            instructions: node_instructions,
102            decoded_instructions: decoded_instructions,
103        },
104        remaining_bytecode,
105    ))
106}
107
108#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
109pub enum DecodedRules {
110    Normal(DecodedBindRules),
111    Composite(DecodedCompositeBindRules),
112}
113
114impl DecodedRules {
115    pub fn new(bytecode: Vec<u8>) -> Result<Self, BytecodeError> {
116        let (symbol_table, inst_bytecode, debug_bytecode) =
117            get_symbol_table_and_instruction_debug_bytecode(bytecode)?;
118        let parsed_magic_num = u32::from_be_bytes(get_u32_bytes(&inst_bytecode, 0)?);
119        if parsed_magic_num == COMPOSITE_MAGIC_NUM {
120            return Ok(DecodedRules::Composite(DecodedCompositeBindRules::new(
121                symbol_table,
122                inst_bytecode,
123                decode_debug_bytecode(debug_bytecode)?,
124            )?));
125        }
126        Ok(DecodedRules::Normal(DecodedBindRules::new(
127            symbol_table,
128            inst_bytecode,
129            decode_debug_bytecode(debug_bytecode)?,
130        )?))
131    }
132}
133
134#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
135pub struct DecodedDebugInfo {
136    pub symbol_table: HashMap<u32, String>,
137}
138
139impl DecodedDebugInfo {
140    pub fn new(debug_bytecode: Vec<u8>) -> Result<Self, BytecodeError> {
141        // Verify the debug symbol table header and size.
142        let (debug_sz, debug_sym_bytecode) =
143            read_and_remove_header(debug_bytecode, DBSY_MAGIC_NUM)?;
144        if debug_sym_bytecode.len() != debug_sz as usize {
145            return Err(BytecodeError::IncorrectSectionSize);
146        }
147        // Read in the debug symbol table.
148        let symbol_table = read_symbol_table(debug_sym_bytecode)?;
149
150        Ok(DecodedDebugInfo { symbol_table: symbol_table })
151    }
152}
153
154// Decode the debug bytecode if it's not empty.
155pub fn decode_debug_bytecode(
156    debug_bytecode: Option<Vec<u8>>,
157) -> Result<Option<DecodedDebugInfo>, BytecodeError> {
158    if debug_bytecode.is_none() {
159        return Ok(None);
160    }
161    let bytecode = debug_bytecode.unwrap();
162    if bytecode.is_empty() {
163        return Ok(None);
164    }
165    return Ok(Some(DecodedDebugInfo::new(bytecode)?));
166}
167
168// This struct decodes and unwraps the given bytecode into a symbol table
169// and list of instructions. It contains an optional debug section.
170#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
171pub struct DecodedBindRules {
172    pub symbol_table: HashMap<u32, String>,
173    pub instructions: Vec<u8>,
174    pub decoded_instructions: Vec<DecodedInstruction>,
175    pub debug_info: Option<DecodedDebugInfo>,
176}
177
178impl DecodedBindRules {
179    pub fn new(
180        symbol_table: HashMap<u32, String>,
181        inst_bytecode: Vec<u8>,
182        debug_info: Option<DecodedDebugInfo>,
183    ) -> Result<Self, BytecodeError> {
184        // Remove the INST header and check if the section size is correct.
185        let (inst_sz, inst_bytecode) =
186            read_and_remove_header(inst_bytecode, INSTRUCTION_MAGIC_NUM)?;
187
188        if inst_bytecode.len() != inst_sz as usize {
189            return Err(BytecodeError::IncorrectSectionSize);
190        }
191
192        let decoded_instructions =
193            InstructionDecoder::new(&symbol_table, &inst_bytecode).decode()?;
194
195        Ok(DecodedBindRules {
196            symbol_table: symbol_table,
197            instructions: inst_bytecode,
198            decoded_instructions: decoded_instructions,
199            debug_info: debug_info,
200        })
201    }
202
203    pub fn from_bytecode(bytecode: Vec<u8>) -> Result<Self, BytecodeError> {
204        let (symbol_table, inst_bytecode, debug_bytecode) =
205            get_symbol_table_and_instruction_debug_bytecode(bytecode)?;
206        DecodedBindRules::new(symbol_table, inst_bytecode, decode_debug_bytecode(debug_bytecode)?)
207    }
208}
209
210#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
211pub struct Parent {
212    // Symbol table ID for the node name.
213    pub name_id: u32,
214    pub instructions: Vec<u8>,
215    pub decoded_instructions: Vec<DecodedInstruction>,
216}
217
218// This struct decodes and unwraps the given bytecode into a symbol table
219// and list of instructions.
220#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
221pub struct DecodedCompositeBindRules {
222    pub symbol_table: HashMap<u32, String>,
223    pub device_name_id: u32,
224    pub primary_parent: Parent,
225    pub additional_parents: Vec<Parent>,
226    pub optional_parents: Vec<Parent>,
227    pub debug_info: Option<DecodedDebugInfo>,
228}
229
230impl DecodedCompositeBindRules {
231    pub fn new(
232        symbol_table: HashMap<u32, String>,
233        composite_inst_bytecode: Vec<u8>,
234        debug_info: Option<DecodedDebugInfo>,
235    ) -> Result<Self, BytecodeError> {
236        // Separate the instruction bytecode out of the symbol table bytecode and verify
237        // the magic number and length. Remove the composite instruction header.
238        let (composite_inst_sz, mut composite_inst_bytecode) =
239            read_and_remove_header(composite_inst_bytecode, COMPOSITE_MAGIC_NUM)?;
240        if composite_inst_bytecode.len() != composite_inst_sz as usize {
241            return Err(BytecodeError::IncorrectSectionSize);
242        }
243
244        // Retrieve the device name ID and check if it's in the symbol table.
245        let device_name_id = u32::from_le_bytes(get_u32_bytes(&composite_inst_bytecode, 0)?);
246        if !symbol_table.contains_key(&device_name_id) {
247            return Err(BytecodeError::MissingDeviceNameInSymbolTable);
248        }
249
250        // Split off the device name ID.
251        let node_bytecode = composite_inst_bytecode.split_off(4);
252
253        // Extract the primary node instructions.
254        let (_, primary_parent, mut node_bytecode) =
255            split_off_parent(node_bytecode, true, &symbol_table)?;
256
257        // Extract additional and optional nodes from the remaining bytecode until there's none left.
258        let mut additional_parents: Vec<Parent> = vec![];
259        let mut optional_parents: Vec<Parent> = vec![];
260        while !node_bytecode.is_empty() {
261            let (is_optional, parent, remaining) =
262                split_off_parent(node_bytecode, false, &symbol_table)?;
263            node_bytecode = remaining;
264            if is_optional {
265                optional_parents.push(parent);
266            } else {
267                additional_parents.push(parent);
268            }
269        }
270
271        Ok(DecodedCompositeBindRules {
272            symbol_table: symbol_table,
273            device_name_id: device_name_id,
274            primary_parent: primary_parent,
275            additional_parents: additional_parents,
276            optional_parents: optional_parents,
277            debug_info: debug_info,
278        })
279    }
280
281    pub fn from_bytecode(bytecode: Vec<u8>) -> Result<Self, BytecodeError> {
282        let (symbol_table, inst_bytecode, debug_bytecode) =
283            get_symbol_table_and_instruction_debug_bytecode(bytecode)?;
284        DecodedCompositeBindRules::new(
285            symbol_table,
286            inst_bytecode,
287            decode_debug_bytecode(debug_bytecode)?,
288        )
289    }
290}
291
292fn get_u32_bytes(bytecode: &Vec<u8>, idx: usize) -> Result<[u8; 4], BytecodeError> {
293    if idx + 4 > bytecode.len() {
294        return Err(BytecodeError::UnexpectedEnd);
295    }
296
297    let mut bytes: [u8; 4] = [0; 4];
298    bytes.copy_from_slice(&bytecode[idx..(4 + idx)]);
299    Ok(bytes)
300}
301
302// Verify the header magic number. Return the value after the magic number and the following bytes.
303fn read_and_remove_header(
304    mut bytecode: Vec<u8>,
305    magic_num: u32,
306) -> Result<(u32, Vec<u8>), BytecodeError> {
307    let parsed_magic_num = u32::from_be_bytes(get_u32_bytes(&bytecode, 0)?);
308    if parsed_magic_num != magic_num {
309        return Err(BytecodeError::InvalidHeader(magic_num, parsed_magic_num));
310    }
311
312    let val = u32::from_le_bytes(get_u32_bytes(&bytecode, 4)?);
313    Ok((val, bytecode.split_off(HEADER_SZ)))
314}
315
316// Verify the enable_debug flag byte.
317fn read_and_remove_debug_flag(mut bytecode: Vec<u8>) -> Result<(u8, Vec<u8>), BytecodeError> {
318    let debug_flag_byte = bytecode[0];
319    if debug_flag_byte != BYTECODE_DISABLE_DEBUG && debug_flag_byte != BYTECODE_ENABLE_DEBUG {
320        return Err(BytecodeError::InvalidDebugFlag(debug_flag_byte));
321    }
322    Ok((debug_flag_byte, bytecode.split_off(DEBUG_FLAG_SZ)))
323}
324
325// Verify the node type and return the node ID and the number of bytes in the node instructions.
326fn verify_and_read_node_header(
327    bytecode: &Vec<u8>,
328    expect_primary: bool,
329) -> Result<(bool, u32, u32), BytecodeError> {
330    if bytecode.len() < NODE_TYPE_HEADER_SZ {
331        return Err(BytecodeError::UnexpectedEnd);
332    }
333
334    let is_optional = match FromPrimitive::from_u8(bytecode[0]) {
335        Some(RawParentType::Primary) => {
336            if !expect_primary {
337                return Err(BytecodeError::MultiplePrimaryParents);
338            }
339
340            false
341        }
342        Some(RawParentType::Additional) => {
343            if expect_primary {
344                return Err(BytecodeError::InvalidPrimaryParent);
345            }
346
347            false
348        }
349        Some(RawParentType::Optional) => {
350            if expect_primary {
351                return Err(BytecodeError::InvalidPrimaryParent);
352            }
353
354            true
355        }
356        None => {
357            return Err(BytecodeError::InvalidParentType(bytecode[0]));
358        }
359    };
360
361    let node_id = u32::from_le_bytes(get_u32_bytes(bytecode, 1)?);
362    let inst_sz = u32::from_le_bytes(get_u32_bytes(bytecode, 5)?);
363    Ok((is_optional, node_id, inst_sz))
364}
365
366fn read_string(iter: &mut BytecodeIter) -> Result<String, BytecodeError> {
367    let mut str_bytes = vec![];
368
369    // Read in the bytes for the string until a zero terminator is reached.
370    // If the number of bytes exceed the maximum string length, return an error.
371    loop {
372        let byte = *next_u8(iter)?;
373        if byte == 0 {
374            break;
375        }
376
377        str_bytes.push(byte);
378        if str_bytes.len() > MAX_STRING_LENGTH {
379            return Err(BytecodeError::InvalidStringLength);
380        }
381    }
382
383    if str_bytes.is_empty() {
384        return Err(BytecodeError::EmptyString);
385    }
386
387    String::from_utf8(str_bytes).map_err(|_| BytecodeError::Utf8ConversionFailure)
388}
389
390fn read_symbol_table(bytecode: Vec<u8>) -> Result<HashMap<u32, String>, BytecodeError> {
391    let mut iter = bytecode.iter();
392
393    let mut symbol_table = HashMap::new();
394    let mut expected_key = SYMB_TBL_START_KEY;
395    while let Some(key) = try_next_u32(&mut iter)? {
396        if key != expected_key {
397            return Err(BytecodeError::InvalidSymbolTableKey(key));
398        }
399
400        // Read the string and increase the byte count by the string length and the
401        // zero terminator.
402        let str_val = read_string(&mut iter)?;
403        symbol_table.insert(key, str_val);
404        expected_key += 1;
405    }
406
407    Ok(symbol_table)
408}
409
410#[cfg(test)]
411mod test {
412    use super::*;
413    use crate::compiler::Symbol;
414    use crate::interpreter::test_common::*;
415    use crate::parser::bind_library;
416
417    fn append_section_header(bytecode: &mut Vec<u8>, magic_num: u32, sz: u32) {
418        bytecode.extend_from_slice(&magic_num.to_be_bytes());
419        bytecode.extend_from_slice(&sz.to_le_bytes());
420    }
421
422    fn append_node_header(bytecode: &mut Vec<u8>, node_type: RawParentType, node_id: u32, sz: u32) {
423        bytecode.push(node_type as u8);
424        bytecode.extend_from_slice(&node_id.to_le_bytes());
425        bytecode.extend_from_slice(&sz.to_le_bytes());
426    }
427
428    #[test]
429    fn test_invalid_header() {
430        // Test invalid magic number.
431        let mut bytecode: Vec<u8> = vec![0x41, 0x49, 0x4E, 0x44, 0x02, 0, 0, 0];
432        bytecode.push(BYTECODE_DISABLE_DEBUG);
433        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 0);
434        append_section_header(&mut bytecode, INSTRUCTION_MAGIC_NUM, 0);
435        assert_eq!(
436            Err(BytecodeError::InvalidHeader(BIND_MAGIC_NUM, 0x41494E44)),
437            DecodedRules::new(bytecode)
438        );
439
440        // Test invalid version.
441        let mut bytecode: Vec<u8> = vec![0x42, 0x49, 0x4E, 0x44, 0x03, 0, 0, 0];
442        bytecode.push(BYTECODE_DISABLE_DEBUG);
443        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 0);
444        append_section_header(&mut bytecode, INSTRUCTION_MAGIC_NUM, 0);
445        assert_eq!(Err(BytecodeError::InvalidVersion(3)), DecodedRules::new(bytecode));
446
447        // Test invalid symbol table header.
448        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
449        bytecode.push(BYTECODE_DISABLE_DEBUG);
450        append_section_header(&mut bytecode, 0xAAAAAAAA, 0);
451        append_section_header(&mut bytecode, INSTRUCTION_MAGIC_NUM, 0);
452        assert_eq!(
453            Err(BytecodeError::InvalidHeader(SYMB_MAGIC_NUM, 0xAAAAAAAA)),
454            DecodedRules::new(bytecode)
455        );
456
457        // Test invalid instruction header.
458        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
459        bytecode.push(BYTECODE_DISABLE_DEBUG);
460        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 0);
461        append_section_header(&mut bytecode, 0xAAAAAAAA, 0);
462        assert_eq!(
463            Err(BytecodeError::InvalidHeader(INSTRUCTION_MAGIC_NUM, 0xAAAAAAAA)),
464            DecodedRules::new(bytecode)
465        );
466
467        // Test invalid debug information section header.
468        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
469        bytecode.push(BYTECODE_ENABLE_DEBUG);
470        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 0);
471        append_section_header(&mut bytecode, INSTRUCTION_MAGIC_NUM, 0);
472        append_section_header(&mut bytecode, 0x44454241, 0);
473        assert_eq!(
474            Err(BytecodeError::InvalidHeader(DEBG_MAGIC_NUM, 0x44454241)),
475            DecodedRules::new(bytecode)
476        );
477
478        // Test invalid debug symbol section header.
479        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
480        bytecode.push(BYTECODE_ENABLE_DEBUG);
481        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 0);
482        append_section_header(&mut bytecode, INSTRUCTION_MAGIC_NUM, 0);
483        append_section_header(&mut bytecode, DEBG_MAGIC_NUM, 8);
484        append_section_header(&mut bytecode, 0x44454247, 0);
485        assert_eq!(
486            Err(BytecodeError::InvalidHeader(DBSY_MAGIC_NUM, 0x44454247)),
487            DecodedRules::new(bytecode)
488        );
489    }
490
491    #[test]
492    fn test_long_string() {
493        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
494        bytecode.push(BYTECODE_DISABLE_DEBUG);
495
496        let mut long_str: [u8; 275] = [0x41; 275];
497        long_str[274] = 0;
498
499        let symbol_section_sz = long_str.len() + 4;
500        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, symbol_section_sz as u32);
501
502        bytecode.extend_from_slice(&[1, 0, 0, 0]);
503        bytecode.extend_from_slice(&long_str);
504
505        append_section_header(&mut bytecode, INSTRUCTION_MAGIC_NUM, 0);
506        assert_eq!(Err(BytecodeError::InvalidStringLength), DecodedRules::new(bytecode));
507    }
508
509    #[test]
510    fn test_unexpected_end() {
511        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
512        bytecode.push(BYTECODE_DISABLE_DEBUG);
513        bytecode.extend_from_slice(&SYMB_MAGIC_NUM.to_be_bytes());
514        assert_eq!(Err(BytecodeError::UnexpectedEnd), DecodedRules::new(bytecode));
515    }
516
517    #[test]
518    fn test_string_with_no_zero_terminator() {
519        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
520        bytecode.push(BYTECODE_DISABLE_DEBUG);
521        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 14);
522
523        let invalid_str: [u8; 10] = [0x41; 10];
524        bytecode.extend_from_slice(&[1, 0, 0, 0]);
525        bytecode.extend_from_slice(&invalid_str);
526
527        append_section_header(&mut bytecode, INSTRUCTION_MAGIC_NUM, 0);
528
529        assert_eq!(Err(BytecodeError::UnexpectedEnd), DecodedRules::new(bytecode));
530    }
531
532    #[test]
533    fn test_duplicate_key() {
534        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
535        bytecode.push(BYTECODE_DISABLE_DEBUG);
536        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 14);
537
538        let str_1: [u8; 3] = [0x41, 0x42, 0];
539        bytecode.extend_from_slice(&[1, 0, 0, 0]);
540        bytecode.extend_from_slice(&str_1);
541
542        let str_2: [u8; 3] = [0x42, 0x43, 0];
543        bytecode.extend_from_slice(&[1, 0, 0, 0]);
544        bytecode.extend_from_slice(&str_2);
545
546        append_section_header(&mut bytecode, INSTRUCTION_MAGIC_NUM, 0);
547        assert_eq!(Err(BytecodeError::InvalidSymbolTableKey(1)), DecodedRules::new(bytecode));
548    }
549
550    #[test]
551    fn test_invalid_key() {
552        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
553        bytecode.push(BYTECODE_DISABLE_DEBUG);
554        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 15);
555
556        let str_1: [u8; 4] = [0x41, 0x45, 0x60, 0];
557        bytecode.extend_from_slice(&[1, 0, 0, 0]);
558        bytecode.extend_from_slice(&str_1);
559
560        let str_2: [u8; 3] = [0x42, 0x43, 0];
561        bytecode.extend_from_slice(&[5, 0, 0, 0]);
562        bytecode.extend_from_slice(&str_2);
563
564        append_section_header(&mut bytecode, INSTRUCTION_MAGIC_NUM, 0);
565        assert_eq!(Err(BytecodeError::InvalidSymbolTableKey(5)), DecodedRules::new(bytecode));
566    }
567
568    #[test]
569    fn test_cutoff_symbol_table_key() {
570        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
571        bytecode.push(BYTECODE_DISABLE_DEBUG);
572        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 9);
573
574        let str_1: [u8; 3] = [0x41, 0x42, 0];
575        bytecode.extend_from_slice(&[1, 0, 0, 0]);
576        bytecode.extend_from_slice(&str_1);
577
578        bytecode.extend_from_slice(&[2, 0]);
579        append_section_header(&mut bytecode, INSTRUCTION_MAGIC_NUM, 0);
580
581        assert_eq!(Err(BytecodeError::UnexpectedEnd), DecodedRules::new(bytecode));
582    }
583
584    #[test]
585    fn test_incorrect_inst_size() {
586        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
587        bytecode.push(BYTECODE_DISABLE_DEBUG);
588        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 0);
589        append_section_header(&mut bytecode, INSTRUCTION_MAGIC_NUM, 0);
590        bytecode.push(0x30);
591        assert_eq!(Err(BytecodeError::IncorrectSectionSize), DecodedRules::new(bytecode));
592    }
593
594    #[test]
595    fn test_minimum_size_bytecode() {
596        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
597        bytecode.push(BYTECODE_DISABLE_DEBUG);
598        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 0);
599        append_section_header(&mut bytecode, INSTRUCTION_MAGIC_NUM, 0);
600        assert_eq!(
601            DecodedRules::Normal(DecodedBindRules {
602                symbol_table: HashMap::new(),
603                instructions: vec![],
604                decoded_instructions: vec![],
605                debug_info: None,
606            }),
607            DecodedRules::new(bytecode).unwrap()
608        );
609    }
610
611    #[test]
612    fn test_incorrect_size_symbol_table() {
613        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
614        bytecode.push(BYTECODE_DISABLE_DEBUG);
615        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, u32::MAX);
616        append_section_header(&mut bytecode, INSTRUCTION_MAGIC_NUM, 0);
617        assert_eq!(Err(BytecodeError::IncorrectSectionSize), DecodedRules::new(bytecode));
618    }
619
620    #[test]
621    fn test_instructions() {
622        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
623        bytecode.push(BYTECODE_DISABLE_DEBUG);
624        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 0);
625
626        let instructions = [0x30, 0x01, 0x01, 0, 0, 0, 0x05, 0x01, 0x10, 0, 0, 0x10];
627        append_section_header(&mut bytecode, INSTRUCTION_MAGIC_NUM, instructions.len() as u32);
628        bytecode.extend_from_slice(&instructions);
629        let bind_rules = DecodedBindRules::from_bytecode(bytecode).unwrap();
630        assert_eq!(instructions.to_vec(), bind_rules.instructions);
631    }
632
633    #[test]
634    fn test_enable_debug_flag_empty_debug_info_section() {
635        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
636        bytecode.push(BYTECODE_ENABLE_DEBUG);
637        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 0);
638
639        let instructions = [0x30];
640        append_section_header(&mut bytecode, INSTRUCTION_MAGIC_NUM, instructions.len() as u32);
641        bytecode.extend_from_slice(&instructions);
642        append_section_header(&mut bytecode, DEBG_MAGIC_NUM, 0);
643
644        let rules = DecodedBindRules {
645            symbol_table: HashMap::new(),
646            instructions: vec![0x30],
647            decoded_instructions: vec![DecodedInstruction::UnconditionalAbort],
648            debug_info: None,
649        };
650
651        assert_eq!(DecodedRules::Normal(rules), DecodedRules::new(bytecode).unwrap());
652    }
653
654    #[test]
655    fn test_enable_debug_flag_empty_debug_symb_section() {
656        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
657        bytecode.push(BYTECODE_ENABLE_DEBUG);
658        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 0);
659
660        let instructions = [0x30];
661        append_section_header(&mut bytecode, INSTRUCTION_MAGIC_NUM, instructions.len() as u32);
662        bytecode.extend_from_slice(&instructions);
663        append_section_header(&mut bytecode, DEBG_MAGIC_NUM, 8);
664        append_section_header(&mut bytecode, DBSY_MAGIC_NUM, 0);
665
666        let rules = DecodedBindRules {
667            symbol_table: HashMap::new(),
668            instructions: vec![0x30],
669            decoded_instructions: vec![DecodedInstruction::UnconditionalAbort],
670            debug_info: Some(DecodedDebugInfo { symbol_table: HashMap::new() }),
671        };
672
673        assert_eq!(DecodedRules::Normal(rules), DecodedRules::new(bytecode).unwrap());
674    }
675
676    #[test]
677    fn test_enable_debug_flag() {
678        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
679        bytecode.push(BYTECODE_ENABLE_DEBUG);
680        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 0);
681
682        let instructions = [0x30];
683        append_section_header(&mut bytecode, INSTRUCTION_MAGIC_NUM, instructions.len() as u32);
684        bytecode.extend_from_slice(&instructions);
685
686        append_section_header(&mut bytecode, DEBG_MAGIC_NUM, 0x22);
687        append_section_header(&mut bytecode, DBSY_MAGIC_NUM, 0x1A);
688
689        let str_1: [u8; 22] = [
690            // "fuchsia.BIND_PROTOCOL"
691            0x66, 0x75, 0x63, 0x68, 0x73, 0x69, 0x61, 0x2e, 0x42, 0x49, 0x4e, 0x44, 0x5f, 0x50,
692            0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0,
693        ];
694        bytecode.extend_from_slice(&[1, 0, 0, 0]);
695        bytecode.extend_from_slice(&str_1);
696
697        let mut expected_symbol_table: HashMap<u32, String> = HashMap::new();
698        expected_symbol_table.insert(1, "fuchsia.BIND_PROTOCOL".to_string());
699
700        let rules = DecodedBindRules {
701            symbol_table: HashMap::new(),
702            instructions: vec![0x30],
703            decoded_instructions: vec![DecodedInstruction::UnconditionalAbort],
704            debug_info: Some(DecodedDebugInfo { symbol_table: expected_symbol_table }),
705        };
706
707        assert_eq!(DecodedRules::Normal(rules), DecodedRules::new(bytecode).unwrap());
708    }
709
710    #[test]
711    fn test_missing_debug_flag() {
712        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
713        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 0);
714
715        let instructions = [0x01, 0x01, 0x05, 0, 0, 0, 0x01, 0x16, 0, 0, 0];
716        append_section_header(&mut bytecode, INSTRUCTION_MAGIC_NUM, instructions.len() as u32);
717        bytecode.extend_from_slice(&instructions);
718
719        assert_eq!(Err(BytecodeError::InvalidDebugFlag(0x53)), DecodedRules::new(bytecode));
720    }
721
722    #[test]
723    fn test_invalid_debug_flag() {
724        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
725        bytecode.push(0x03);
726        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 0);
727
728        let instructions = [0x01, 0x01, 0x05, 0, 0, 0, 0x01, 0x16, 0, 0, 0];
729        append_section_header(&mut bytecode, INSTRUCTION_MAGIC_NUM, instructions.len() as u32);
730        bytecode.extend_from_slice(&instructions);
731
732        assert_eq!(Err(BytecodeError::InvalidDebugFlag(0x03)), DecodedRules::new(bytecode));
733    }
734
735    #[test]
736    fn test_value_key_missing_in_symbols() {
737        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
738        bytecode.push(BYTECODE_DISABLE_DEBUG);
739        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 0);
740
741        let instructions = [0x01, 0x00, 0, 0, 0, 0x05, 0x10, 0, 0, 0, 0];
742        append_section_header(&mut bytecode, INSTRUCTION_MAGIC_NUM, instructions.len() as u32);
743        bytecode.extend_from_slice(&instructions);
744
745        assert_eq!(
746            Err(BytecodeError::MissingEntryInSymbolTable(0x05000000)),
747            DecodedRules::new(bytecode)
748        );
749    }
750
751    #[test]
752    fn test_valid_bytecode() {
753        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
754        bytecode.push(BYTECODE_DISABLE_DEBUG);
755        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 18);
756
757        let str_1: [u8; 5] = [0x57, 0x52, 0x45, 0x4E, 0]; // "WREN"
758        bytecode.extend_from_slice(&[1, 0, 0, 0]);
759        bytecode.extend_from_slice(&str_1);
760
761        let str_2: [u8; 5] = [0x44, 0x55, 0x43, 0x4B, 0]; // "DUCK"
762        bytecode.extend_from_slice(&[2, 0, 0, 0]);
763        bytecode.extend_from_slice(&str_2);
764
765        let instructions = [
766            0x01, 0x01, 0, 0, 0, 0x05, 0x01, 0x10, 0, 0, 0x10, // 0x05000000 == 0x10000010
767            0x11, 0x01, 0, 0, 0, 0x01, 0, 0, 0, 0x05, 0x01, 0x10, 0, 0,
768            0, // jmp 1 if 0x05000000 == 0x10
769            0x30, 0x20, // abort, jump pad
770            0x11, 0x01, 0, 0, 0, 0x00, 0x01, 0, 0, 0, 0x02, 0x02, 0, 0,
771            0, // jmp 1 if key("WREN") == "DUCK"
772            0x30, 0x20, // abort, jump pad
773            0x10, 0x02, 0, 0, 0, 0x30, 0x30, 0x20, // jump 2, 2 aborts, jump pad
774        ];
775        append_section_header(&mut bytecode, INSTRUCTION_MAGIC_NUM, instructions.len() as u32);
776        bytecode.extend_from_slice(&instructions);
777
778        let mut expected_symbol_table: HashMap<u32, String> = HashMap::new();
779        expected_symbol_table.insert(1, "WREN".to_string());
780        expected_symbol_table.insert(2, "DUCK".to_string());
781
782        let expected_decoded_inst = vec![
783            DecodedInstruction::Condition(DecodedCondition {
784                is_equal: true,
785                lhs: Symbol::NumberValue(0x05000000),
786                rhs: Symbol::NumberValue(0x10000010),
787            }),
788            DecodedInstruction::Jump(Some(DecodedCondition {
789                is_equal: true,
790                lhs: Symbol::NumberValue(0x05000000),
791                rhs: Symbol::NumberValue(0x10),
792            })),
793            DecodedInstruction::UnconditionalAbort,
794            DecodedInstruction::Label,
795            DecodedInstruction::Jump(Some(DecodedCondition {
796                is_equal: true,
797                lhs: Symbol::Key("WREN".to_string(), bind_library::ValueType::Str),
798                rhs: Symbol::StringValue("DUCK".to_string()),
799            })),
800            DecodedInstruction::UnconditionalAbort,
801            DecodedInstruction::Label,
802            DecodedInstruction::Jump(None),
803            DecodedInstruction::UnconditionalAbort,
804            DecodedInstruction::UnconditionalAbort,
805            DecodedInstruction::Label,
806        ];
807
808        let rules = DecodedBindRules {
809            symbol_table: expected_symbol_table,
810            instructions: instructions.to_vec(),
811            decoded_instructions: expected_decoded_inst,
812            debug_info: None,
813        };
814        assert_eq!(DecodedRules::Normal(rules), DecodedRules::new(bytecode).unwrap());
815    }
816
817    #[test]
818    fn test_enable_debug_composite() {
819        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
820        bytecode.push(BYTECODE_ENABLE_DEBUG);
821        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 38);
822
823        let device_name: [u8; 5] = [0x49, 0x42, 0x49, 0x53, 0]; // "IBIS"
824        bytecode.extend_from_slice(&[1, 0, 0, 0]);
825        bytecode.extend_from_slice(&device_name);
826
827        let primary_node_name: [u8; 5] = [0x52, 0x41, 0x49, 0x4C, 0]; // "RAIL"
828        bytecode.extend_from_slice(&[2, 0, 0, 0]);
829        bytecode.extend_from_slice(&primary_node_name);
830
831        let node_name_1: [u8; 5] = [0x43, 0x4F, 0x4F, 0x54, 0]; // "COOT"
832        bytecode.extend_from_slice(&[3, 0, 0, 0]);
833        bytecode.extend_from_slice(&node_name_1);
834
835        let node_name_2: [u8; 7] = [0x50, 0x4C, 0x4F, 0x56, 0x45, 0x52, 0]; // "PLOVER"
836        bytecode.extend_from_slice(&[4, 0, 0, 0]);
837        bytecode.extend_from_slice(&node_name_2);
838
839        let primary_node_inst = [0x30, 0x01, 0x01, 0, 0, 0, 0x05, 0x01, 0x10, 0, 0x20, 0];
840        let additional_node_inst_1 = [0x02, 0x01, 0, 0, 0, 0x02, 0x01, 0, 0, 0, 0x10];
841        let additional_node_inst_2 = [0x30, 0x30];
842
843        let composite_insts_sz = COMPOSITE_NAME_ID_BYTES
844            + ((NODE_TYPE_HEADER_SZ * 3)
845                + primary_node_inst.len()
846                + additional_node_inst_1.len()
847                + additional_node_inst_2.len()) as u32;
848        append_section_header(&mut bytecode, COMPOSITE_MAGIC_NUM, composite_insts_sz);
849
850        // Add device name ID.
851        bytecode.extend_from_slice(&[1, 0, 0, 0]);
852
853        // Add the node instructions.
854        append_node_header(
855            &mut bytecode,
856            RawParentType::Primary,
857            2,
858            primary_node_inst.len() as u32,
859        );
860        bytecode.extend_from_slice(&primary_node_inst);
861        append_node_header(
862            &mut bytecode,
863            RawParentType::Additional,
864            3,
865            additional_node_inst_1.len() as u32,
866        );
867        bytecode.extend_from_slice(&additional_node_inst_1);
868        append_node_header(
869            &mut bytecode,
870            RawParentType::Additional,
871            4,
872            additional_node_inst_2.len() as u32,
873        );
874        bytecode.extend_from_slice(&additional_node_inst_2);
875
876        let mut expected_symbol_table: HashMap<u32, String> = HashMap::new();
877        expected_symbol_table.insert(1, "IBIS".to_string());
878        expected_symbol_table.insert(2, "RAIL".to_string());
879        expected_symbol_table.insert(3, "COOT".to_string());
880        expected_symbol_table.insert(4, "PLOVER".to_string());
881
882        append_section_header(&mut bytecode, DEBG_MAGIC_NUM, 0x22);
883        append_section_header(&mut bytecode, DBSY_MAGIC_NUM, 0x1A);
884
885        let str_1: [u8; 22] = [
886            // "fuchsia.BIND_PROTOCOL"
887            0x66, 0x75, 0x63, 0x68, 0x73, 0x69, 0x61, 0x2e, 0x42, 0x49, 0x4e, 0x44, 0x5f, 0x50,
888            0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0,
889        ];
890        bytecode.extend_from_slice(&[1, 0, 0, 0]);
891        bytecode.extend_from_slice(&str_1);
892
893        let mut debug_symbol_table: HashMap<u32, String> = HashMap::new();
894        debug_symbol_table.insert(1, "fuchsia.BIND_PROTOCOL".to_string());
895
896        let rules = DecodedCompositeBindRules {
897            symbol_table: expected_symbol_table,
898            device_name_id: 1,
899            primary_parent: Parent {
900                name_id: 2,
901                instructions: primary_node_inst.to_vec(),
902                decoded_instructions: vec![
903                    DecodedInstruction::UnconditionalAbort,
904                    DecodedInstruction::Condition(DecodedCondition {
905                        is_equal: true,
906                        lhs: Symbol::NumberValue(0x5000000),
907                        rhs: Symbol::NumberValue(0x200010),
908                    }),
909                ],
910            },
911            additional_parents: vec![
912                Parent {
913                    name_id: 3,
914                    instructions: additional_node_inst_1.to_vec(),
915                    decoded_instructions: vec![DecodedInstruction::Condition(DecodedCondition {
916                        is_equal: false,
917                        lhs: Symbol::NumberValue(0x2000000),
918                        rhs: Symbol::NumberValue(0x10000000),
919                    })],
920                },
921                Parent {
922                    name_id: 4,
923                    instructions: additional_node_inst_2.to_vec(),
924                    decoded_instructions: vec![
925                        DecodedInstruction::UnconditionalAbort,
926                        DecodedInstruction::UnconditionalAbort,
927                    ],
928                },
929            ],
930            optional_parents: vec![],
931            debug_info: Some(DecodedDebugInfo { symbol_table: debug_symbol_table }),
932        };
933        assert_eq!(DecodedRules::Composite(rules), DecodedRules::new(bytecode).unwrap());
934    }
935
936    #[test]
937    fn test_enable_debug_composite_with_optional() {
938        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
939        bytecode.push(BYTECODE_ENABLE_DEBUG);
940        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 38);
941
942        let device_name: [u8; 5] = [0x49, 0x42, 0x49, 0x53, 0]; // "IBIS"
943        bytecode.extend_from_slice(&[1, 0, 0, 0]);
944        bytecode.extend_from_slice(&device_name);
945
946        let primary_node_name: [u8; 5] = [0x52, 0x41, 0x49, 0x4C, 0]; // "RAIL"
947        bytecode.extend_from_slice(&[2, 0, 0, 0]);
948        bytecode.extend_from_slice(&primary_node_name);
949
950        let node_name_1: [u8; 5] = [0x43, 0x4F, 0x4F, 0x54, 0]; // "COOT"
951        bytecode.extend_from_slice(&[3, 0, 0, 0]);
952        bytecode.extend_from_slice(&node_name_1);
953
954        let node_name_2: [u8; 7] = [0x50, 0x4C, 0x4F, 0x56, 0x45, 0x52, 0]; // "PLOVER"
955        bytecode.extend_from_slice(&[4, 0, 0, 0]);
956        bytecode.extend_from_slice(&node_name_2);
957
958        let primary_node_inst = [0x30, 0x01, 0x01, 0, 0, 0, 0x05, 0x01, 0x10, 0, 0x20, 0];
959        let additional_node_inst_1 = [0x02, 0x01, 0, 0, 0, 0x02, 0x01, 0, 0, 0, 0x10];
960        let optional_node_inst_1 = [0x30, 0x30];
961
962        let composite_insts_sz = COMPOSITE_NAME_ID_BYTES
963            + ((NODE_TYPE_HEADER_SZ * 3)
964                + primary_node_inst.len()
965                + additional_node_inst_1.len()
966                + optional_node_inst_1.len()) as u32;
967        append_section_header(&mut bytecode, COMPOSITE_MAGIC_NUM, composite_insts_sz);
968
969        // Add device name ID.
970        bytecode.extend_from_slice(&[1, 0, 0, 0]);
971
972        // Add the node instructions.
973        append_node_header(
974            &mut bytecode,
975            RawParentType::Primary,
976            2,
977            primary_node_inst.len() as u32,
978        );
979        bytecode.extend_from_slice(&primary_node_inst);
980        append_node_header(
981            &mut bytecode,
982            RawParentType::Additional,
983            3,
984            additional_node_inst_1.len() as u32,
985        );
986        bytecode.extend_from_slice(&additional_node_inst_1);
987        append_node_header(
988            &mut bytecode,
989            RawParentType::Optional,
990            4,
991            optional_node_inst_1.len() as u32,
992        );
993        bytecode.extend_from_slice(&optional_node_inst_1);
994
995        let mut expected_symbol_table: HashMap<u32, String> = HashMap::new();
996        expected_symbol_table.insert(1, "IBIS".to_string());
997        expected_symbol_table.insert(2, "RAIL".to_string());
998        expected_symbol_table.insert(3, "COOT".to_string());
999        expected_symbol_table.insert(4, "PLOVER".to_string());
1000
1001        append_section_header(&mut bytecode, DEBG_MAGIC_NUM, 0x22);
1002        append_section_header(&mut bytecode, DBSY_MAGIC_NUM, 0x1A);
1003
1004        let str_1: [u8; 22] = [
1005            // "fuchsia.BIND_PROTOCOL"
1006            0x66, 0x75, 0x63, 0x68, 0x73, 0x69, 0x61, 0x2e, 0x42, 0x49, 0x4e, 0x44, 0x5f, 0x50,
1007            0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0,
1008        ];
1009        bytecode.extend_from_slice(&[1, 0, 0, 0]);
1010        bytecode.extend_from_slice(&str_1);
1011
1012        let mut debug_symbol_table: HashMap<u32, String> = HashMap::new();
1013        debug_symbol_table.insert(1, "fuchsia.BIND_PROTOCOL".to_string());
1014
1015        let rules = DecodedCompositeBindRules {
1016            symbol_table: expected_symbol_table,
1017            device_name_id: 1,
1018            primary_parent: Parent {
1019                name_id: 2,
1020                instructions: primary_node_inst.to_vec(),
1021                decoded_instructions: vec![
1022                    DecodedInstruction::UnconditionalAbort,
1023                    DecodedInstruction::Condition(DecodedCondition {
1024                        is_equal: true,
1025                        lhs: Symbol::NumberValue(0x5000000),
1026                        rhs: Symbol::NumberValue(0x200010),
1027                    }),
1028                ],
1029            },
1030            additional_parents: vec![Parent {
1031                name_id: 3,
1032                instructions: additional_node_inst_1.to_vec(),
1033                decoded_instructions: vec![DecodedInstruction::Condition(DecodedCondition {
1034                    is_equal: false,
1035                    lhs: Symbol::NumberValue(0x2000000),
1036                    rhs: Symbol::NumberValue(0x10000000),
1037                })],
1038            }],
1039            optional_parents: vec![Parent {
1040                name_id: 4,
1041                instructions: optional_node_inst_1.to_vec(),
1042                decoded_instructions: vec![
1043                    DecodedInstruction::UnconditionalAbort,
1044                    DecodedInstruction::UnconditionalAbort,
1045                ],
1046            }],
1047            debug_info: Some(DecodedDebugInfo { symbol_table: debug_symbol_table }),
1048        };
1049        assert_eq!(DecodedRules::Composite(rules), DecodedRules::new(bytecode).unwrap());
1050    }
1051
1052    #[test]
1053    fn test_valid_composite_bind() {
1054        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
1055        bytecode.push(BYTECODE_DISABLE_DEBUG);
1056        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 38);
1057
1058        let device_name: [u8; 5] = [0x49, 0x42, 0x49, 0x53, 0]; // "IBIS"
1059        bytecode.extend_from_slice(&[1, 0, 0, 0]);
1060        bytecode.extend_from_slice(&device_name);
1061
1062        let primary_node_name: [u8; 5] = [0x52, 0x41, 0x49, 0x4C, 0]; // "RAIL"
1063        bytecode.extend_from_slice(&[2, 0, 0, 0]);
1064        bytecode.extend_from_slice(&primary_node_name);
1065
1066        let node_name_1: [u8; 5] = [0x43, 0x4F, 0x4F, 0x54, 0]; // "COOT"
1067        bytecode.extend_from_slice(&[3, 0, 0, 0]);
1068        bytecode.extend_from_slice(&node_name_1);
1069
1070        let node_name_2: [u8; 7] = [0x50, 0x4C, 0x4F, 0x56, 0x45, 0x52, 0]; // "PLOVER"
1071        bytecode.extend_from_slice(&[4, 0, 0, 0]);
1072        bytecode.extend_from_slice(&node_name_2);
1073
1074        let primary_node_inst = [0x30, 0x01, 0x01, 0, 0, 0, 0x05, 0x01, 0x10, 0, 0x20, 0];
1075        let additional_node_inst_1 = [0x02, 0x01, 0, 0, 0, 0x02, 0x01, 0, 0, 0, 0x10];
1076        let additional_node_inst_2 = [0x30, 0x30];
1077
1078        let composite_insts_sz = COMPOSITE_NAME_ID_BYTES
1079            + ((NODE_TYPE_HEADER_SZ * 3)
1080                + primary_node_inst.len()
1081                + additional_node_inst_1.len()
1082                + additional_node_inst_2.len()) as u32;
1083        append_section_header(&mut bytecode, COMPOSITE_MAGIC_NUM, composite_insts_sz);
1084
1085        // Add device name ID.
1086        bytecode.extend_from_slice(&[1, 0, 0, 0]);
1087
1088        // Add the node instructions.
1089        append_node_header(
1090            &mut bytecode,
1091            RawParentType::Primary,
1092            2,
1093            primary_node_inst.len() as u32,
1094        );
1095        bytecode.extend_from_slice(&primary_node_inst);
1096        append_node_header(
1097            &mut bytecode,
1098            RawParentType::Additional,
1099            3,
1100            additional_node_inst_1.len() as u32,
1101        );
1102        bytecode.extend_from_slice(&additional_node_inst_1);
1103        append_node_header(
1104            &mut bytecode,
1105            RawParentType::Additional,
1106            4,
1107            additional_node_inst_2.len() as u32,
1108        );
1109        bytecode.extend_from_slice(&additional_node_inst_2);
1110
1111        let mut expected_symbol_table: HashMap<u32, String> = HashMap::new();
1112        expected_symbol_table.insert(1, "IBIS".to_string());
1113        expected_symbol_table.insert(2, "RAIL".to_string());
1114        expected_symbol_table.insert(3, "COOT".to_string());
1115        expected_symbol_table.insert(4, "PLOVER".to_string());
1116
1117        let rules = DecodedCompositeBindRules {
1118            symbol_table: expected_symbol_table,
1119            device_name_id: 1,
1120            primary_parent: Parent {
1121                name_id: 2,
1122                instructions: primary_node_inst.to_vec(),
1123                decoded_instructions: vec![
1124                    DecodedInstruction::UnconditionalAbort,
1125                    DecodedInstruction::Condition(DecodedCondition {
1126                        is_equal: true,
1127                        lhs: Symbol::NumberValue(0x5000000),
1128                        rhs: Symbol::NumberValue(0x200010),
1129                    }),
1130                ],
1131            },
1132            additional_parents: vec![
1133                Parent {
1134                    name_id: 3,
1135                    instructions: additional_node_inst_1.to_vec(),
1136                    decoded_instructions: vec![DecodedInstruction::Condition(DecodedCondition {
1137                        is_equal: false,
1138                        lhs: Symbol::NumberValue(0x2000000),
1139                        rhs: Symbol::NumberValue(0x10000000),
1140                    })],
1141                },
1142                Parent {
1143                    name_id: 4,
1144                    instructions: additional_node_inst_2.to_vec(),
1145                    decoded_instructions: vec![
1146                        DecodedInstruction::UnconditionalAbort,
1147                        DecodedInstruction::UnconditionalAbort,
1148                    ],
1149                },
1150            ],
1151            optional_parents: vec![],
1152            debug_info: None,
1153        };
1154        assert_eq!(DecodedRules::Composite(rules), DecodedRules::new(bytecode).unwrap());
1155    }
1156
1157    #[test]
1158    fn test_valid_composite_bind_with_optional() {
1159        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
1160        bytecode.push(BYTECODE_DISABLE_DEBUG);
1161        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 38);
1162
1163        let device_name: [u8; 5] = [0x49, 0x42, 0x49, 0x53, 0]; // "IBIS"
1164        bytecode.extend_from_slice(&[1, 0, 0, 0]);
1165        bytecode.extend_from_slice(&device_name);
1166
1167        let primary_node_name: [u8; 5] = [0x52, 0x41, 0x49, 0x4C, 0]; // "RAIL"
1168        bytecode.extend_from_slice(&[2, 0, 0, 0]);
1169        bytecode.extend_from_slice(&primary_node_name);
1170
1171        let node_name_1: [u8; 5] = [0x43, 0x4F, 0x4F, 0x54, 0]; // "COOT"
1172        bytecode.extend_from_slice(&[3, 0, 0, 0]);
1173        bytecode.extend_from_slice(&node_name_1);
1174
1175        let node_name_2: [u8; 7] = [0x50, 0x4C, 0x4F, 0x56, 0x45, 0x52, 0]; // "PLOVER"
1176        bytecode.extend_from_slice(&[4, 0, 0, 0]);
1177        bytecode.extend_from_slice(&node_name_2);
1178
1179        let primary_node_inst = [0x30, 0x01, 0x01, 0, 0, 0, 0x05, 0x01, 0x10, 0, 0x20, 0];
1180        let additional_node_inst_1 = [0x02, 0x01, 0, 0, 0, 0x02, 0x01, 0, 0, 0, 0x10];
1181        let optional_node_inst_1 = [0x30, 0x30];
1182
1183        let composite_insts_sz = COMPOSITE_NAME_ID_BYTES
1184            + ((NODE_TYPE_HEADER_SZ * 3)
1185                + primary_node_inst.len()
1186                + additional_node_inst_1.len()
1187                + optional_node_inst_1.len()) as u32;
1188        append_section_header(&mut bytecode, COMPOSITE_MAGIC_NUM, composite_insts_sz);
1189
1190        // Add device name ID.
1191        bytecode.extend_from_slice(&[1, 0, 0, 0]);
1192
1193        // Add the node instructions.
1194        append_node_header(
1195            &mut bytecode,
1196            RawParentType::Primary,
1197            2,
1198            primary_node_inst.len() as u32,
1199        );
1200        bytecode.extend_from_slice(&primary_node_inst);
1201        append_node_header(
1202            &mut bytecode,
1203            RawParentType::Additional,
1204            3,
1205            additional_node_inst_1.len() as u32,
1206        );
1207        bytecode.extend_from_slice(&additional_node_inst_1);
1208        append_node_header(
1209            &mut bytecode,
1210            RawParentType::Optional,
1211            4,
1212            optional_node_inst_1.len() as u32,
1213        );
1214        bytecode.extend_from_slice(&optional_node_inst_1);
1215
1216        let mut expected_symbol_table: HashMap<u32, String> = HashMap::new();
1217        expected_symbol_table.insert(1, "IBIS".to_string());
1218        expected_symbol_table.insert(2, "RAIL".to_string());
1219        expected_symbol_table.insert(3, "COOT".to_string());
1220        expected_symbol_table.insert(4, "PLOVER".to_string());
1221
1222        let rules = DecodedCompositeBindRules {
1223            symbol_table: expected_symbol_table,
1224            device_name_id: 1,
1225            primary_parent: Parent {
1226                name_id: 2,
1227                instructions: primary_node_inst.to_vec(),
1228                decoded_instructions: vec![
1229                    DecodedInstruction::UnconditionalAbort,
1230                    DecodedInstruction::Condition(DecodedCondition {
1231                        is_equal: true,
1232                        lhs: Symbol::NumberValue(0x5000000),
1233                        rhs: Symbol::NumberValue(0x200010),
1234                    }),
1235                ],
1236            },
1237            additional_parents: vec![Parent {
1238                name_id: 3,
1239                instructions: additional_node_inst_1.to_vec(),
1240                decoded_instructions: vec![DecodedInstruction::Condition(DecodedCondition {
1241                    is_equal: false,
1242                    lhs: Symbol::NumberValue(0x2000000),
1243                    rhs: Symbol::NumberValue(0x10000000),
1244                })],
1245            }],
1246            optional_parents: vec![Parent {
1247                name_id: 4,
1248                instructions: optional_node_inst_1.to_vec(),
1249                decoded_instructions: vec![
1250                    DecodedInstruction::UnconditionalAbort,
1251                    DecodedInstruction::UnconditionalAbort,
1252                ],
1253            }],
1254            debug_info: None,
1255        };
1256        assert_eq!(DecodedRules::Composite(rules), DecodedRules::new(bytecode).unwrap());
1257    }
1258
1259    #[test]
1260    fn test_primary_node_only() {
1261        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
1262        bytecode.push(BYTECODE_DISABLE_DEBUG);
1263        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 18);
1264
1265        let device_name: [u8; 5] = [0x49, 0x42, 0x49, 0x53, 0]; // "IBIS"
1266        bytecode.extend_from_slice(&[1, 0, 0, 0]);
1267        bytecode.extend_from_slice(&device_name);
1268
1269        let primary_node_name: [u8; 5] = [0x43, 0x4F, 0x4F, 0x54, 0]; // "RAIL"
1270        bytecode.extend_from_slice(&[2, 0, 0, 0]);
1271        bytecode.extend_from_slice(&primary_node_name);
1272
1273        let primary_node_inst = [0x30, 0x01, 0x01, 0, 0, 0, 0x05, 0x01, 0x10, 0, 0x20, 0];
1274
1275        let composite_insts_sz =
1276            COMPOSITE_NAME_ID_BYTES + (NODE_TYPE_HEADER_SZ + primary_node_inst.len()) as u32;
1277        append_section_header(&mut bytecode, COMPOSITE_MAGIC_NUM, composite_insts_sz);
1278
1279        // Add device name ID.
1280        bytecode.extend_from_slice(&[1, 0, 0, 0]);
1281
1282        // Add the node instructions.
1283        append_node_header(
1284            &mut bytecode,
1285            RawParentType::Primary,
1286            2,
1287            primary_node_inst.len() as u32,
1288        );
1289        bytecode.extend_from_slice(&primary_node_inst);
1290
1291        let mut expected_symbol_table: HashMap<u32, String> = HashMap::new();
1292        expected_symbol_table.insert(1, "IBIS".to_string());
1293        expected_symbol_table.insert(2, "COOT".to_string());
1294
1295        assert_eq!(
1296            DecodedRules::Composite(DecodedCompositeBindRules {
1297                symbol_table: expected_symbol_table,
1298                device_name_id: 1,
1299                primary_parent: Parent {
1300                    name_id: 2,
1301                    instructions: primary_node_inst.to_vec(),
1302                    decoded_instructions: vec![
1303                        DecodedInstruction::UnconditionalAbort,
1304                        DecodedInstruction::Condition(DecodedCondition {
1305                            is_equal: true,
1306                            lhs: Symbol::NumberValue(0x5000000),
1307                            rhs: Symbol::NumberValue(0x200010),
1308                        }),
1309                    ],
1310                },
1311                additional_parents: vec![],
1312                optional_parents: vec![],
1313                debug_info: None,
1314            }),
1315            DecodedRules::new(bytecode).unwrap()
1316        );
1317    }
1318
1319    #[test]
1320    fn test_missing_device_name() {
1321        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
1322        bytecode.push(BYTECODE_DISABLE_DEBUG);
1323        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 9);
1324
1325        let primary_node_name: [u8; 5] = [0x43, 0x4F, 0x4F, 0x54, 0]; // "RAIL"
1326        bytecode.extend_from_slice(&[1, 0, 0, 0]);
1327        bytecode.extend_from_slice(&primary_node_name);
1328
1329        let primary_node_inst = [0x30];
1330        let composite_insts_sz =
1331            COMPOSITE_NAME_ID_BYTES + (NODE_TYPE_HEADER_SZ + primary_node_inst.len()) as u32;
1332        append_section_header(&mut bytecode, COMPOSITE_MAGIC_NUM, composite_insts_sz);
1333        bytecode.extend_from_slice(&[2, 0, 0, 0]);
1334
1335        append_node_header(
1336            &mut bytecode,
1337            RawParentType::Primary,
1338            1,
1339            primary_node_inst.len() as u32,
1340        );
1341        bytecode.extend_from_slice(&primary_node_inst);
1342
1343        assert_eq!(Err(BytecodeError::MissingDeviceNameInSymbolTable), DecodedRules::new(bytecode));
1344    }
1345
1346    #[test]
1347    fn test_missing_node_name() {
1348        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
1349        bytecode.push(BYTECODE_DISABLE_DEBUG);
1350        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 9);
1351
1352        let primary_node_name: [u8; 5] = [0x43, 0x4F, 0x4F, 0x54, 0]; // "RAIL"
1353        bytecode.extend_from_slice(&[1, 0, 0, 0]);
1354        bytecode.extend_from_slice(&primary_node_name);
1355
1356        let primary_node_inst = [0x30];
1357        let composite_insts_sz =
1358            COMPOSITE_NAME_ID_BYTES + (NODE_TYPE_HEADER_SZ + primary_node_inst.len()) as u32;
1359        append_section_header(&mut bytecode, COMPOSITE_MAGIC_NUM, composite_insts_sz);
1360        bytecode.extend_from_slice(&[1, 0, 0, 0]);
1361
1362        append_node_header(
1363            &mut bytecode,
1364            RawParentType::Primary,
1365            2,
1366            primary_node_inst.len() as u32,
1367        );
1368        bytecode.extend_from_slice(&primary_node_inst);
1369
1370        assert_eq!(Err(BytecodeError::MissingParentIdInSymbolTable), DecodedRules::new(bytecode));
1371    }
1372
1373    #[test]
1374    fn test_missing_primary_node() {
1375        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
1376        bytecode.push(BYTECODE_DISABLE_DEBUG);
1377        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 29);
1378
1379        let device_name: [u8; 5] = [0x4C, 0x4F, 0x4F, 0x4E, 0]; // "LOON"
1380        bytecode.extend_from_slice(&[1, 0, 0, 0]);
1381        bytecode.extend_from_slice(&device_name);
1382
1383        let primary_node_name: [u8; 6] = [0x47, 0x52, 0x45, 0x42, 0x45, 0]; // "GREBE"
1384        bytecode.extend_from_slice(&[2, 0, 0, 0]);
1385        bytecode.extend_from_slice(&primary_node_name);
1386
1387        let additional_node_name: [u8; 6] = [0x53, 0x43, 0x41, 0x55, 0x50, 0]; // "SCAUP"
1388        bytecode.extend_from_slice(&[3, 0, 0, 0]);
1389        bytecode.extend_from_slice(&additional_node_name);
1390
1391        let additional_node_inst_1 = [0x02, 0x01, 0, 0, 0, 0x02, 0x02, 0, 0, 0x10];
1392        let additional_node_inst_2 = [0x30];
1393
1394        let composite_insts_sz = COMPOSITE_NAME_ID_BYTES
1395            + ((NODE_TYPE_HEADER_SZ * 2)
1396                + additional_node_inst_1.len()
1397                + additional_node_inst_2.len()) as u32;
1398        append_section_header(&mut bytecode, COMPOSITE_MAGIC_NUM, composite_insts_sz);
1399
1400        // Add device name ID.
1401        bytecode.extend_from_slice(&[1, 0, 0, 0]);
1402
1403        // Add the node instructions.
1404        append_node_header(
1405            &mut bytecode,
1406            RawParentType::Additional,
1407            2,
1408            additional_node_inst_1.len() as u32,
1409        );
1410        bytecode.extend_from_slice(&additional_node_inst_1);
1411        append_node_header(
1412            &mut bytecode,
1413            RawParentType::Additional,
1414            3,
1415            additional_node_inst_2.len() as u32,
1416        );
1417        bytecode.extend_from_slice(&additional_node_inst_2);
1418
1419        assert_eq!(Err(BytecodeError::InvalidPrimaryParent), DecodedRules::new(bytecode));
1420    }
1421
1422    #[test]
1423    fn test_primary_node_incorrect_order() {
1424        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
1425        bytecode.push(BYTECODE_DISABLE_DEBUG);
1426        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 29);
1427
1428        let device_name: [u8; 5] = [0x4C, 0x4F, 0x4F, 0x4E, 0]; // "LOON"
1429        bytecode.extend_from_slice(&[1, 0, 0, 0]);
1430        bytecode.extend_from_slice(&device_name);
1431
1432        let primary_node_name: [u8; 6] = [0x47, 0x52, 0x45, 0x42, 0x45, 0]; // "GREBE"
1433        bytecode.extend_from_slice(&[2, 0, 0, 0]);
1434        bytecode.extend_from_slice(&primary_node_name);
1435
1436        let additional_node_name: [u8; 6] = [0x53, 0x43, 0x41, 0x55, 0x50, 0]; // "SCAUP"
1437        bytecode.extend_from_slice(&[3, 0, 0, 0]);
1438        bytecode.extend_from_slice(&additional_node_name);
1439
1440        let primary_node_inst = [0x02, 0x01, 0, 0, 0, 0x02, 0x02, 0, 0, 0x10];
1441        let additional_node_inst = [0x30];
1442
1443        let composite_insts_sz = COMPOSITE_NAME_ID_BYTES
1444            + ((NODE_TYPE_HEADER_SZ * 2) + primary_node_inst.len() + additional_node_inst.len())
1445                as u32;
1446        append_section_header(&mut bytecode, COMPOSITE_MAGIC_NUM, composite_insts_sz);
1447
1448        // Add device name ID.
1449        bytecode.extend_from_slice(&[1, 0, 0, 0]);
1450
1451        // Add the node instructions.
1452        append_node_header(
1453            &mut bytecode,
1454            RawParentType::Additional,
1455            3,
1456            additional_node_inst.len() as u32,
1457        );
1458        bytecode.extend_from_slice(&additional_node_inst);
1459        append_node_header(
1460            &mut bytecode,
1461            RawParentType::Primary,
1462            2,
1463            primary_node_inst.len() as u32,
1464        );
1465        bytecode.extend_from_slice(&primary_node_inst);
1466
1467        assert_eq!(Err(BytecodeError::InvalidPrimaryParent), DecodedRules::new(bytecode));
1468    }
1469
1470    #[test]
1471    fn test_multiple_primary_nodes() {
1472        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
1473        bytecode.push(BYTECODE_DISABLE_DEBUG);
1474        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 29);
1475
1476        let device_name: [u8; 5] = [0x4C, 0x4F, 0x4F, 0x4E, 0]; // "LOON"
1477        bytecode.extend_from_slice(&[1, 0, 0, 0]);
1478        bytecode.extend_from_slice(&device_name);
1479
1480        let primary_node_name: [u8; 6] = [0x47, 0x52, 0x45, 0x42, 0x45, 0]; // "GREBE"
1481        bytecode.extend_from_slice(&[2, 0, 0, 0]);
1482        bytecode.extend_from_slice(&primary_node_name);
1483
1484        let primary_node_name_2: [u8; 6] = [0x53, 0x43, 0x41, 0x55, 0x50, 0]; // "SCAUP"
1485        bytecode.extend_from_slice(&[3, 0, 0, 0]);
1486        bytecode.extend_from_slice(&primary_node_name_2);
1487
1488        let primary_node_inst = [0x02, 0x01, 0, 0, 0, 0x02, 0x01, 0, 0, 0, 0x10];
1489        let primary_node_inst_2 = [0x30];
1490
1491        let composite_insts_sz = COMPOSITE_NAME_ID_BYTES
1492            + ((NODE_TYPE_HEADER_SZ * 2) + primary_node_inst.len() + primary_node_inst_2.len())
1493                as u32;
1494        append_section_header(&mut bytecode, COMPOSITE_MAGIC_NUM, composite_insts_sz);
1495
1496        // Add device name ID.
1497        bytecode.extend_from_slice(&[1, 0, 0, 0]);
1498
1499        // Add the node instructions.
1500        append_node_header(
1501            &mut bytecode,
1502            RawParentType::Primary,
1503            2,
1504            primary_node_inst.len() as u32,
1505        );
1506        bytecode.extend_from_slice(&primary_node_inst);
1507        append_node_header(
1508            &mut bytecode,
1509            RawParentType::Primary,
1510            3,
1511            primary_node_inst_2.len() as u32,
1512        );
1513        bytecode.extend_from_slice(&primary_node_inst_2);
1514
1515        assert_eq!(Err(BytecodeError::MultiplePrimaryParents), DecodedRules::new(bytecode));
1516    }
1517
1518    #[test]
1519    fn test_invalid_node_type() {
1520        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
1521        bytecode.push(BYTECODE_DISABLE_DEBUG);
1522        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 18);
1523
1524        let device_name: [u8; 5] = [0x49, 0x42, 0x49, 0x53, 0]; // "IBIS"
1525        bytecode.extend_from_slice(&[1, 0, 0, 0]);
1526        bytecode.extend_from_slice(&device_name);
1527
1528        let primary_node_name: [u8; 5] = [0x52, 0x41, 0x49, 0x4C, 0]; // "RAIL"
1529        bytecode.extend_from_slice(&[2, 0, 0, 0]);
1530        bytecode.extend_from_slice(&primary_node_name);
1531
1532        let primary_node_inst = [0x30];
1533
1534        let composite_insts_sz =
1535            COMPOSITE_NAME_ID_BYTES + (NODE_TYPE_HEADER_SZ + primary_node_inst.len()) as u32;
1536        append_section_header(&mut bytecode, COMPOSITE_MAGIC_NUM, composite_insts_sz);
1537
1538        // Add device name ID.
1539        bytecode.extend_from_slice(&[1, 0, 0, 0]);
1540
1541        // Add the node instructions with an invalid node type.
1542        bytecode.push(0x53);
1543        bytecode.extend_from_slice(&[2, 0, 0, 0]);
1544        bytecode.extend_from_slice(&(primary_node_inst.len() as u32).to_le_bytes());
1545        bytecode.extend_from_slice(&primary_node_inst);
1546
1547        assert_eq!(Err(BytecodeError::InvalidParentType(0x53)), DecodedRules::new(bytecode));
1548    }
1549
1550    #[test]
1551    fn test_incorrect_node_section_sz_overlap() {
1552        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
1553        bytecode.push(BYTECODE_DISABLE_DEBUG);
1554        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 27);
1555
1556        let device_name: [u8; 5] = [0x49, 0x42, 0x49, 0x53, 0]; // "IBIS"
1557        bytecode.extend_from_slice(&[1, 0, 0, 0]);
1558        bytecode.extend_from_slice(&device_name);
1559
1560        let primary_node_name: [u8; 5] = [0x52, 0x41, 0x49, 0x4C, 0]; // "RAIL"
1561        bytecode.extend_from_slice(&[2, 0, 0, 0]);
1562        bytecode.extend_from_slice(&primary_node_name);
1563
1564        let node_name_1: [u8; 5] = [0x43, 0x4F, 0x4F, 0x54, 0]; // "COOT"
1565        bytecode.extend_from_slice(&[3, 0, 0, 0]);
1566        bytecode.extend_from_slice(&node_name_1);
1567
1568        let primary_node_inst = [0x30];
1569        let additional_node_inst = [0x02, 0x01, 0, 0, 0, 0x02, 0x02, 0, 0, 0x10];
1570
1571        let composite_insts_sz = COMPOSITE_NAME_ID_BYTES
1572            + ((NODE_TYPE_HEADER_SZ * 2) + primary_node_inst.len() + additional_node_inst.len())
1573                as u32;
1574        append_section_header(&mut bytecode, COMPOSITE_MAGIC_NUM, composite_insts_sz);
1575
1576        // Add device name ID.
1577        bytecode.extend_from_slice(&[1, 0, 0, 0]);
1578
1579        // Add the primary node instructions with a size that overlaps to the next
1580        // node.
1581        append_node_header(&mut bytecode, RawParentType::Primary, 2, 7);
1582        bytecode.extend_from_slice(&primary_node_inst);
1583
1584        append_node_header(
1585            &mut bytecode,
1586            RawParentType::Additional,
1587            3,
1588            additional_node_inst.len() as u32,
1589        );
1590        bytecode.extend_from_slice(&additional_node_inst);
1591
1592        // Instructions for the primary node end, the next byte is the node type for the next node.
1593        assert_eq!(
1594            Err(BytecodeError::InvalidOp(RawParentType::Additional as u8)),
1595            DecodedRules::new(bytecode)
1596        );
1597    }
1598
1599    #[test]
1600    fn test_incorrect_node_section_sz_undersize() {
1601        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
1602        bytecode.push(BYTECODE_DISABLE_DEBUG);
1603        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 27);
1604
1605        let device_name: [u8; 5] = [0x49, 0x42, 0x49, 0x53, 0]; // "IBIS"
1606        bytecode.extend_from_slice(&[1, 0, 0, 0]);
1607        bytecode.extend_from_slice(&device_name);
1608
1609        let primary_node_name: [u8; 5] = [0x52, 0x41, 0x49, 0x4C, 0]; // "RAIL"
1610        bytecode.extend_from_slice(&[2, 0, 0, 0]);
1611        bytecode.extend_from_slice(&primary_node_name);
1612
1613        let node_name_1: [u8; 5] = [0x43, 0x4F, 0x4F, 0x54, 0]; // "COOT"
1614        bytecode.extend_from_slice(&[3, 0, 0, 0]);
1615        bytecode.extend_from_slice(&node_name_1);
1616
1617        let primary_node_inst = [0x30];
1618        let additional_node_inst = [0x02, 0x01, 0, 0, 0, 0x02, 0x02, 0, 0, 0x10];
1619
1620        let composite_insts_sz = COMPOSITE_NAME_ID_BYTES
1621            + ((NODE_TYPE_HEADER_SZ * 2) + primary_node_inst.len() + additional_node_inst.len())
1622                as u32;
1623        append_section_header(&mut bytecode, COMPOSITE_MAGIC_NUM, composite_insts_sz);
1624
1625        // Add device name ID.
1626        bytecode.extend_from_slice(&[1, 0, 0, 0]);
1627
1628        append_node_header(
1629            &mut bytecode,
1630            RawParentType::Primary,
1631            2,
1632            primary_node_inst.len() as u32,
1633        );
1634        bytecode.extend_from_slice(&primary_node_inst);
1635
1636        // Add the additional node with a size that's too small.
1637        append_node_header(&mut bytecode, RawParentType::Additional, 3, 1);
1638        bytecode.extend_from_slice(&additional_node_inst);
1639
1640        // Reach end when trying to read in value type after the inequality operator (0x02).
1641        assert_eq!(Err(BytecodeError::UnexpectedEnd), DecodedRules::new(bytecode));
1642    }
1643
1644    #[test]
1645    fn test_incorrect_node_section_sz_oversize() {
1646        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
1647        bytecode.push(BYTECODE_DISABLE_DEBUG);
1648        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 18);
1649
1650        let device_name: [u8; 5] = [0x49, 0x42, 0x49, 0x53, 0]; // "IBIS"
1651        bytecode.extend_from_slice(&[1, 0, 0, 0]);
1652        bytecode.extend_from_slice(&device_name);
1653
1654        let primary_node_name: [u8; 5] = [0x43, 0x4F, 0x4F, 0x54, 0]; // "RAIL"
1655        bytecode.extend_from_slice(&[2, 0, 0, 0]);
1656        bytecode.extend_from_slice(&primary_node_name);
1657
1658        let primary_node_inst = [0x30, 0x01, 0x01, 0, 0, 0, 0x05, 0x01, 0x10, 0, 0x20, 0];
1659
1660        let composite_insts_sz =
1661            COMPOSITE_NAME_ID_BYTES + (NODE_TYPE_HEADER_SZ + primary_node_inst.len()) as u32;
1662        append_section_header(&mut bytecode, COMPOSITE_MAGIC_NUM, composite_insts_sz);
1663
1664        // Add device name ID.
1665        bytecode.extend_from_slice(&[1, 0, 0, 0]);
1666
1667        // Add primary node instructions with a size that exceed the entire instruction size.
1668        append_node_header(&mut bytecode, RawParentType::Primary, 2, 50);
1669        bytecode.extend_from_slice(&primary_node_inst);
1670
1671        assert_eq!(Err(BytecodeError::IncorrectParentSectionSize), DecodedRules::new(bytecode));
1672    }
1673
1674    #[test]
1675    fn test_composite_header_in_noncomposite_bytecode() {
1676        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
1677        bytecode.push(BYTECODE_DISABLE_DEBUG);
1678        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 18);
1679
1680        let str_1: [u8; 5] = [0x49, 0x42, 0x49, 0x53, 0]; // "IBIS"
1681        bytecode.extend_from_slice(&[1, 0, 0, 0]);
1682        bytecode.extend_from_slice(&str_1);
1683
1684        let primary_node_name: [u8; 5] = [0x52, 0x41, 0x49, 0x4C, 0]; // "RAIL"
1685        bytecode.extend_from_slice(&[2, 0, 0, 0]);
1686        bytecode.extend_from_slice(&primary_node_name);
1687
1688        let primary_node_inst = [0x30, 0x01, 0x01, 0, 0, 0, 0x05, 0x01, 0x10, 0, 0x20, 0];
1689
1690        let composite_insts_sz =
1691            COMPOSITE_NAME_ID_BYTES + (NODE_TYPE_HEADER_SZ + primary_node_inst.len()) as u32;
1692        append_section_header(&mut bytecode, COMPOSITE_MAGIC_NUM, composite_insts_sz);
1693
1694        // Add device name ID.
1695        bytecode.extend_from_slice(&[1, 0, 0, 0]);
1696
1697        // Add the node instructions.
1698        append_node_header(
1699            &mut bytecode,
1700            RawParentType::Primary,
1701            2,
1702            primary_node_inst.len() as u32,
1703        );
1704        bytecode.extend_from_slice(&primary_node_inst);
1705
1706        assert_eq!(
1707            Err(BytecodeError::InvalidHeader(INSTRUCTION_MAGIC_NUM, COMPOSITE_MAGIC_NUM)),
1708            DecodedBindRules::from_bytecode(bytecode)
1709        );
1710    }
1711
1712    #[test]
1713    fn test_inst_header_in_composite_bytecode() {
1714        let mut bytecode: Vec<u8> = BIND_HEADER.to_vec();
1715        bytecode.push(BYTECODE_DISABLE_DEBUG);
1716        append_section_header(&mut bytecode, SYMB_MAGIC_NUM, 0);
1717
1718        let instructions = [0x30, 0x01, 0x01, 0, 0, 0, 0x05, 0x10, 0, 0, 0x10];
1719        append_section_header(&mut bytecode, INSTRUCTION_MAGIC_NUM, instructions.len() as u32);
1720        bytecode.extend_from_slice(&instructions);
1721
1722        assert_eq!(
1723            Err(BytecodeError::InvalidHeader(COMPOSITE_MAGIC_NUM, INSTRUCTION_MAGIC_NUM)),
1724            DecodedCompositeBindRules::from_bytecode(bytecode)
1725        );
1726    }
1727
1728    #[test]
1729    fn test_composite_with_compiler() {
1730        use crate::compiler::{
1731            CompiledBindRules, CompositeBindRules, CompositeParent, Symbol, SymbolicInstruction,
1732            SymbolicInstructionInfo,
1733        };
1734        use crate::parser::bind_library::ValueType;
1735
1736        let primary_node_inst = vec![SymbolicInstructionInfo {
1737            location: None,
1738            instruction: SymbolicInstruction::UnconditionalAbort,
1739        }];
1740
1741        let additional_node_inst = vec![
1742            SymbolicInstructionInfo {
1743                location: None,
1744                instruction: SymbolicInstruction::AbortIfEqual {
1745                    lhs: Symbol::Key("bobolink".to_string(), ValueType::Bool),
1746                    rhs: Symbol::BoolValue(false),
1747                },
1748            },
1749            SymbolicInstructionInfo {
1750                location: None,
1751                instruction: SymbolicInstruction::AbortIfNotEqual {
1752                    lhs: Symbol::Key("grackle".to_string(), ValueType::Number),
1753                    rhs: Symbol::NumberValue(1),
1754                },
1755            },
1756        ];
1757
1758        let bytecode = CompiledBindRules::CompositeBind(CompositeBindRules {
1759            device_name: "blackbird".to_string(),
1760            symbol_table: HashMap::new(),
1761            primary_parent: CompositeParent {
1762                name: "meadowlark".to_string(),
1763                instructions: primary_node_inst,
1764            },
1765            additional_parents: vec![CompositeParent {
1766                name: "cowbird".to_string(),
1767                instructions: additional_node_inst,
1768            }],
1769            optional_parents: vec![],
1770            enable_debug: false,
1771        })
1772        .encode_to_bytecode()
1773        .unwrap();
1774
1775        let mut expected_symbol_table: HashMap<u32, String> = HashMap::new();
1776        expected_symbol_table.insert(1, "blackbird".to_string());
1777        expected_symbol_table.insert(2, "meadowlark".to_string());
1778        expected_symbol_table.insert(3, "cowbird".to_string());
1779        expected_symbol_table.insert(4, "bobolink".to_string());
1780        expected_symbol_table.insert(5, "grackle".to_string());
1781
1782        let primary_node_inst = [0x30];
1783        let additional_node_inst = [
1784            0x02, 0x0, 0x04, 0x0, 0x0, 0x0, 0x03, 0x0, 0x0, 0x0, 0x0, // bobolink != false
1785            0x01, 0x0, 0x05, 0x0, 0x0, 0x0, 0x01, 0x1, 0x0, 0x0, 0x0, // grackle == 1
1786        ];
1787
1788        assert_eq!(
1789            DecodedRules::Composite(DecodedCompositeBindRules {
1790                symbol_table: expected_symbol_table,
1791                device_name_id: 1,
1792                primary_parent: Parent {
1793                    name_id: 2,
1794                    instructions: primary_node_inst.to_vec(),
1795                    decoded_instructions: vec![DecodedInstruction::UnconditionalAbort],
1796                },
1797                additional_parents: vec![Parent {
1798                    name_id: 3,
1799                    instructions: additional_node_inst.to_vec(),
1800                    decoded_instructions: vec![
1801                        DecodedInstruction::Condition(DecodedCondition {
1802                            is_equal: false,
1803                            lhs: Symbol::Key("bobolink".to_string(), ValueType::Str),
1804                            rhs: Symbol::BoolValue(false)
1805                        }),
1806                        DecodedInstruction::Condition(DecodedCondition {
1807                            is_equal: true,
1808                            lhs: Symbol::Key("grackle".to_string(), ValueType::Str),
1809                            rhs: Symbol::NumberValue(1)
1810                        })
1811                    ]
1812                }],
1813                optional_parents: vec![],
1814                debug_info: None,
1815            }),
1816            DecodedRules::new(bytecode).unwrap()
1817        );
1818    }
1819
1820    #[test]
1821    fn test_composite_optional_with_compiler() {
1822        use crate::compiler::{
1823            CompiledBindRules, CompositeBindRules, CompositeParent, Symbol, SymbolicInstruction,
1824            SymbolicInstructionInfo,
1825        };
1826        use crate::parser::bind_library::ValueType;
1827
1828        let primary_node_inst = vec![SymbolicInstructionInfo {
1829            location: None,
1830            instruction: SymbolicInstruction::UnconditionalAbort,
1831        }];
1832
1833        let additional_node_inst = vec![
1834            SymbolicInstructionInfo {
1835                location: None,
1836                instruction: SymbolicInstruction::AbortIfEqual {
1837                    lhs: Symbol::Key("bobolink".to_string(), ValueType::Bool),
1838                    rhs: Symbol::BoolValue(false),
1839                },
1840            },
1841            SymbolicInstructionInfo {
1842                location: None,
1843                instruction: SymbolicInstruction::AbortIfNotEqual {
1844                    lhs: Symbol::Key("grackle".to_string(), ValueType::Number),
1845                    rhs: Symbol::NumberValue(1),
1846                },
1847            },
1848        ];
1849
1850        let optional_node_inst = vec![SymbolicInstructionInfo {
1851            location: None,
1852            instruction: SymbolicInstruction::AbortIfEqual {
1853                lhs: Symbol::Key("mockingbird".to_string(), ValueType::Bool),
1854                rhs: Symbol::BoolValue(false),
1855            },
1856        }];
1857
1858        let bytecode = CompiledBindRules::CompositeBind(CompositeBindRules {
1859            device_name: "blackbird".to_string(),
1860            symbol_table: HashMap::new(),
1861            primary_parent: CompositeParent {
1862                name: "meadowlark".to_string(),
1863                instructions: primary_node_inst,
1864            },
1865            additional_parents: vec![CompositeParent {
1866                name: "cowbird".to_string(),
1867                instructions: additional_node_inst,
1868            }],
1869            optional_parents: vec![CompositeParent {
1870                name: "cowbird_optional".to_string(),
1871                instructions: optional_node_inst,
1872            }],
1873            enable_debug: false,
1874        })
1875        .encode_to_bytecode()
1876        .unwrap();
1877
1878        let mut expected_symbol_table: HashMap<u32, String> = HashMap::new();
1879        expected_symbol_table.insert(1, "blackbird".to_string());
1880        expected_symbol_table.insert(2, "meadowlark".to_string());
1881        expected_symbol_table.insert(3, "cowbird".to_string());
1882        expected_symbol_table.insert(4, "bobolink".to_string());
1883        expected_symbol_table.insert(5, "grackle".to_string());
1884        expected_symbol_table.insert(6, "cowbird_optional".to_string());
1885        expected_symbol_table.insert(7, "mockingbird".to_string());
1886
1887        let primary_node_inst = [0x30];
1888        let additional_node_inst = [
1889            0x02, 0x0, 0x04, 0x0, 0x0, 0x0, 0x03, 0x0, 0x0, 0x0, 0x0, // bobolink != false
1890            0x01, 0x0, 0x05, 0x0, 0x0, 0x0, 0x01, 0x1, 0x0, 0x0, 0x0, // grackle == 1
1891        ];
1892
1893        let optional_node_inst = [
1894            0x02, 0x0, 0x07, 0x0, 0x0, 0x0, 0x03, 0x0, 0x0, 0x0, 0x0, // mockingbird != false
1895        ];
1896
1897        assert_eq!(
1898            DecodedRules::Composite(DecodedCompositeBindRules {
1899                symbol_table: expected_symbol_table,
1900                device_name_id: 1,
1901                primary_parent: Parent {
1902                    name_id: 2,
1903                    instructions: primary_node_inst.to_vec(),
1904                    decoded_instructions: vec![DecodedInstruction::UnconditionalAbort],
1905                },
1906                additional_parents: vec![Parent {
1907                    name_id: 3,
1908                    instructions: additional_node_inst.to_vec(),
1909                    decoded_instructions: vec![
1910                        DecodedInstruction::Condition(DecodedCondition {
1911                            is_equal: false,
1912                            lhs: Symbol::Key("bobolink".to_string(), ValueType::Str),
1913                            rhs: Symbol::BoolValue(false)
1914                        }),
1915                        DecodedInstruction::Condition(DecodedCondition {
1916                            is_equal: true,
1917                            lhs: Symbol::Key("grackle".to_string(), ValueType::Str),
1918                            rhs: Symbol::NumberValue(1)
1919                        })
1920                    ]
1921                }],
1922                optional_parents: vec![Parent {
1923                    name_id: 6,
1924                    instructions: optional_node_inst.to_vec(),
1925                    decoded_instructions: vec![DecodedInstruction::Condition(DecodedCondition {
1926                        is_equal: false,
1927                        lhs: Symbol::Key("mockingbird".to_string(), ValueType::Str),
1928                        rhs: Symbol::BoolValue(false)
1929                    })],
1930                }],
1931                debug_info: None,
1932            }),
1933            DecodedRules::new(bytecode).unwrap()
1934        );
1935    }
1936}