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