bind/interpreter/
match_bind.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::compiler::symbol_table::get_deprecated_key_identifier;
7use crate::compiler::Symbol;
8use crate::interpreter::common::*;
9use crate::interpreter::decode_bind_rules::DecodedBindRules;
10use crate::parser::bind_library;
11use core::hash::Hash;
12use num_traits::FromPrimitive;
13use std::collections::HashMap;
14
15#[derive(PartialEq)]
16enum Condition {
17    Unconditional,
18    Equal,
19    Inequal,
20}
21
22// TODO(https://fxbug.dev/42151229): Currently, the driver manager only supports number-based
23// device properties. It will support string-based properties soon. We should
24// support other device property types in the future.
25#[derive(
26    Clone, Debug, Hash, Eq, Ord, PartialEq, PartialOrd, serde::Serialize, serde::Deserialize,
27)]
28pub enum PropertyKey {
29    NumberKey(u64),
30    StringKey(String),
31}
32
33pub type DeviceProperties = HashMap<PropertyKey, Symbol>;
34
35pub struct MatchBindData<'a> {
36    pub symbol_table: &'a HashMap<u32, String>,
37    pub instructions: &'a Vec<u8>,
38}
39
40struct DeviceMatcher<'a> {
41    properties: &'a DeviceProperties,
42    symbol_table: &'a HashMap<u32, String>,
43    iter: BytecodeIter<'a>,
44}
45
46impl<'a> DeviceMatcher<'a> {
47    pub fn match_bind(mut self) -> Result<bool, BytecodeError> {
48        while let Some(byte) = self.iter.next() {
49            let op_byte = FromPrimitive::from_u8(*byte).ok_or(BytecodeError::InvalidOp(*byte))?;
50            match op_byte {
51                RawOp::EqualCondition | RawOp::InequalCondition => {
52                    if !self.evaluate_condition_inst(op_byte)? {
53                        return Ok(false);
54                    }
55                }
56                RawOp::Abort => {
57                    return Ok(false);
58                }
59                RawOp::UnconditionalJump => self.evaluate_jump_inst(Condition::Unconditional)?,
60                RawOp::JumpIfEqual => self.evaluate_jump_inst(Condition::Equal)?,
61                RawOp::JumpIfNotEqual => self.evaluate_jump_inst(Condition::Inequal)?,
62                RawOp::JumpLandPad => {
63                    // No-op.
64                }
65            };
66        }
67
68        Ok(true)
69    }
70
71    // Evaluates a conditional instruction and returns false if the condition failed.
72    fn evaluate_condition_inst(&mut self, op: RawOp) -> Result<bool, BytecodeError> {
73        let condition = match op {
74            RawOp::EqualCondition => Condition::Equal,
75            RawOp::InequalCondition => Condition::Inequal,
76            _ => panic!(
77                "evaluate_condition_inst() should only be called for Equal or Inequal instructions"
78            ),
79        };
80
81        Ok(self.read_and_evaluate_values(condition)?)
82    }
83
84    fn evaluate_jump_inst(&mut self, condition: Condition) -> Result<(), BytecodeError> {
85        let offset = next_u32(&mut self.iter)?;
86        if condition != Condition::Unconditional && !self.read_and_evaluate_values(condition)? {
87            return Ok(());
88        }
89
90        // Skip through the bytes by the amount in the offset.
91        for _ in 0..offset {
92            next_u8(&mut self.iter)?;
93        }
94
95        // Verify that the next instruction is a jump pad.
96        if *next_u8(&mut self.iter)? != RawOp::JumpLandPad as u8 {
97            return Err(BytecodeError::InvalidJumpLocation);
98        }
99
100        Ok(())
101    }
102
103    // Read in two values and evaluate them based on the given condition.
104    fn read_and_evaluate_values(&mut self, condition: Condition) -> Result<bool, BytecodeError> {
105        let property_key = match self.read_next_value()? {
106            Symbol::NumberValue(key) => PropertyKey::NumberKey(key),
107            Symbol::StringValue(key) => PropertyKey::StringKey(key),
108            Symbol::Key(key, _) => PropertyKey::StringKey(key),
109            _ => {
110                return Err(BytecodeError::InvalidKeyType);
111            }
112        };
113
114        let expected_value = self.read_next_value()?;
115        let mut node_property_value = self.properties.get(&property_key);
116
117        // If the node properties doesn't contain an integer key, try to convert the
118        // integer key to a deprecated string key, and check if the node properties
119        // contain that.
120        if node_property_value.is_none() {
121            if let PropertyKey::NumberKey(int_key) = property_key {
122                if let Some(str_key) = get_deprecated_key_identifier(int_key as u32) {
123                    node_property_value = self.properties.get(&PropertyKey::StringKey(str_key));
124                }
125            }
126        }
127
128        match node_property_value {
129            None => Ok(condition == Condition::Inequal),
130            Some(value) => compare_symbols(condition, &expected_value, value),
131        }
132    }
133
134    // Read in the next u8 as the value type and the next u32 as the value. Convert the value
135    // into a Symbol.
136    fn read_next_value(&mut self) -> Result<Symbol, BytecodeError> {
137        let value_type = *next_u8(&mut self.iter)?;
138        let value_type = FromPrimitive::from_u8(value_type)
139            .ok_or(BytecodeError::InvalidValueType(value_type))?;
140
141        let value = next_u32(&mut self.iter)?;
142        match value_type {
143            RawValueType::NumberValue => Ok(Symbol::NumberValue(value as u64)),
144            RawValueType::Key => {
145                // The key's value type is a placeholder. The value type doesn't matter since
146                // the only the key will be used for looking up the device property.
147                Ok(Symbol::Key(self.lookup_symbol_table(value)?, bind_library::ValueType::Str))
148            }
149            RawValueType::StringValue => Ok(Symbol::StringValue(self.lookup_symbol_table(value)?)),
150            RawValueType::BoolValue => match value {
151                0x0 => Ok(Symbol::BoolValue(false)),
152                0x1 => Ok(Symbol::BoolValue(true)),
153                _ => Err(BytecodeError::InvalidBoolValue(value)),
154            },
155            RawValueType::EnumValue => Ok(Symbol::EnumValue(self.lookup_symbol_table(value)?)),
156        }
157    }
158
159    fn lookup_symbol_table(&self, key: u32) -> Result<String, BytecodeError> {
160        self.symbol_table
161            .get(&key)
162            .ok_or(BytecodeError::MissingEntryInSymbolTable(key))
163            .map(|val| val.to_string())
164    }
165}
166
167fn compare_symbols(
168    condition: Condition,
169    lhs: &Symbol,
170    rhs: &Symbol,
171) -> Result<bool, BytecodeError> {
172    // If either side is an EnumValue type, convert it into a StringValue type for the comparison.
173    // This is because both of these types contain a string inside of them and as long as that
174    // value is the same, then the equality is satisfied.
175    let mut lhs_for_compare = lhs.clone();
176    let mut rhs_for_compare = rhs.clone();
177    if let Symbol::EnumValue(val) = lhs {
178        lhs_for_compare = Symbol::StringValue(val.to_string());
179    };
180    if let Symbol::EnumValue(val) = rhs {
181        rhs_for_compare = Symbol::StringValue(val.to_string());
182    };
183    if std::mem::discriminant(&lhs_for_compare) != std::mem::discriminant(&rhs_for_compare) {
184        return Err(BytecodeError::MismatchValueTypes);
185    }
186
187    Ok(match condition {
188        Condition::Equal => lhs_for_compare == rhs_for_compare,
189        Condition::Inequal => lhs_for_compare != rhs_for_compare,
190        Condition::Unconditional => {
191            panic!("This function shouldn't be called for Unconditional.")
192        }
193    })
194}
195
196// Return true if the bytecode matches the device properties. The bytecode
197// is for a non-composite driver.
198pub fn match_bytecode(
199    bytecode: Vec<u8>,
200    properties: &DeviceProperties,
201) -> Result<bool, BytecodeError> {
202    let decoded_bind_rules = DecodedBindRules::from_bytecode(bytecode)?;
203    let matcher = DeviceMatcher {
204        properties: &properties,
205        symbol_table: &decoded_bind_rules.symbol_table,
206        iter: decoded_bind_rules.instructions.iter(),
207    };
208    matcher.match_bind()
209}
210
211// Return true if the bind rules matches the device properties.
212pub fn match_bind(
213    bind_data: MatchBindData,
214    properties: &DeviceProperties,
215) -> Result<bool, BytecodeError> {
216    let matcher = DeviceMatcher {
217        properties: &properties,
218        symbol_table: &bind_data.symbol_table,
219        iter: bind_data.instructions.iter(),
220    };
221    matcher.match_bind()
222}
223
224#[cfg(test)]
225mod test {
226    use super::*;
227
228    // Constants representing the number of bytes in an operand and value.
229    const OP_BYTES: u32 = 1;
230    const VALUE_BYTES: u32 = 5;
231    const OFFSET_BYTES: u32 = 4;
232
233    // Constants representing the number of bytes in each instruction.
234    const ABORT_BYTES: u32 = OP_BYTES;
235    const COND_INST_BYTES: u32 = OP_BYTES + VALUE_BYTES + VALUE_BYTES;
236    const UNCOND_JMP_BYTES: u32 = OP_BYTES + OFFSET_BYTES;
237    const COND_JMP_BYTES: u32 = OP_BYTES + OFFSET_BYTES + VALUE_BYTES + VALUE_BYTES;
238    const JMP_PAD_BYTES: u32 = OP_BYTES;
239
240    struct EncodedValue {
241        value_type: RawValueType,
242        value: u32,
243    }
244
245    fn append_encoded_value(bytecode: &mut Vec<u8>, encoded_val: EncodedValue) {
246        bytecode.push(encoded_val.value_type as u8);
247        bytecode.extend_from_slice(&encoded_val.value.to_le_bytes());
248    }
249
250    fn append_abort(bytecode: &mut Vec<u8>) {
251        bytecode.push(0x30);
252    }
253
254    fn append_equal_cond(
255        bytecode: &mut Vec<u8>,
256        property_key: EncodedValue,
257        property_value: EncodedValue,
258    ) {
259        bytecode.push(0x01);
260        append_encoded_value(bytecode, property_key);
261        append_encoded_value(bytecode, property_value);
262    }
263
264    fn append_inequal_cond(
265        bytecode: &mut Vec<u8>,
266        property_key: EncodedValue,
267        property_value: EncodedValue,
268    ) {
269        bytecode.push(0x02);
270        append_encoded_value(bytecode, property_key);
271        append_encoded_value(bytecode, property_value);
272    }
273
274    fn append_unconditional_jump(bytecode: &mut Vec<u8>, offset: u32) {
275        bytecode.push(0x10);
276        bytecode.extend_from_slice(&offset.to_le_bytes());
277    }
278
279    fn append_jump_if_equal(
280        bytecode: &mut Vec<u8>,
281        offset: u32,
282        property_key: EncodedValue,
283        property_value: EncodedValue,
284    ) {
285        bytecode.push(0x11);
286        bytecode.extend_from_slice(&offset.to_le_bytes());
287        append_encoded_value(bytecode, property_key);
288        append_encoded_value(bytecode, property_value);
289    }
290
291    fn append_jump_if_not_equal(
292        bytecode: &mut Vec<u8>,
293        offset: u32,
294        property_key: EncodedValue,
295        property_value: EncodedValue,
296    ) {
297        bytecode.push(0x12);
298        bytecode.extend_from_slice(&offset.to_le_bytes());
299        append_encoded_value(bytecode, property_key);
300        append_encoded_value(bytecode, property_value);
301    }
302
303    fn append_jump_pad(bytecode: &mut Vec<u8>) {
304        bytecode.push(0x20);
305    }
306
307    fn verify_match_result(
308        expected_result: Result<bool, BytecodeError>,
309        bind_rules: DecodedBindRules,
310        device_properties: &DeviceProperties,
311    ) {
312        let matcher = DeviceMatcher {
313            properties: device_properties,
314            symbol_table: &bind_rules.symbol_table,
315            iter: bind_rules.instructions.iter(),
316        };
317
318        assert_eq!(expected_result, matcher.match_bind());
319    }
320
321    #[test]
322    fn empty_instructions() {
323        verify_match_result(
324            Ok(true),
325            DecodedBindRules {
326                symbol_table: HashMap::new(),
327                instructions: vec![],
328                decoded_instructions: vec![],
329                debug_info: None,
330            },
331            &HashMap::new(),
332        );
333    }
334
335    #[test]
336    fn equal_condition_with_number_property_keys() {
337        let mut device_properties: DeviceProperties = HashMap::new();
338        device_properties.insert(PropertyKey::NumberKey(1), Symbol::NumberValue(2000));
339        device_properties.insert(PropertyKey::NumberKey(2), Symbol::NumberValue(500));
340
341        // The condition statement should match the device properties.
342        let mut instructions: Vec<u8> = vec![];
343        append_equal_cond(
344            &mut instructions,
345            EncodedValue { value_type: RawValueType::NumberValue, value: 1 },
346            EncodedValue { value_type: RawValueType::NumberValue, value: 2000 },
347        );
348        verify_match_result(
349            Ok(true),
350            DecodedBindRules {
351                symbol_table: HashMap::new(),
352                instructions: instructions,
353                decoded_instructions: vec![],
354                debug_info: None,
355            },
356            &device_properties,
357        );
358
359        // The condition should fail since the device property has a different value.
360        let mut instructions: Vec<u8> = vec![];
361        append_equal_cond(
362            &mut instructions,
363            EncodedValue { value_type: RawValueType::NumberValue, value: 1 },
364            EncodedValue { value_type: RawValueType::NumberValue, value: 5 },
365        );
366        verify_match_result(
367            Ok(false),
368            DecodedBindRules {
369                symbol_table: HashMap::new(),
370                instructions: instructions,
371                decoded_instructions: vec![],
372                debug_info: None,
373            },
374            &device_properties,
375        );
376
377        // The condition should fail since the property is missing from device properties.
378        let mut instructions: Vec<u8> = vec![];
379        append_equal_cond(
380            &mut instructions,
381            EncodedValue { value_type: RawValueType::NumberValue, value: 3 },
382            EncodedValue { value_type: RawValueType::NumberValue, value: 5 },
383        );
384        verify_match_result(
385            Ok(false),
386            DecodedBindRules {
387                symbol_table: HashMap::new(),
388                instructions: instructions,
389                decoded_instructions: vec![],
390                debug_info: None,
391            },
392            &device_properties,
393        );
394    }
395
396    #[test]
397    fn equal_condition_with_string_property_keys() {
398        let mut device_properties: DeviceProperties = HashMap::new();
399        device_properties.insert(
400            PropertyKey::StringKey("nightjar".to_string()),
401            Symbol::StringValue("poorwill".to_string()),
402        );
403
404        device_properties.insert(
405            PropertyKey::StringKey("poorwill".to_string()),
406            Symbol::EnumValue("nighthawk".to_string()),
407        );
408
409        let mut symbol_table: HashMap<u32, String> = HashMap::new();
410        symbol_table.insert(1, "nightjar".to_string());
411        symbol_table.insert(2, "poorwill".to_string());
412        symbol_table.insert(3, "nighthawk".to_string());
413
414        // The condition statement should match the string device properties.
415        let mut instructions: Vec<u8> = vec![];
416        append_equal_cond(
417            &mut instructions,
418            EncodedValue { value_type: RawValueType::StringValue, value: 1 },
419            EncodedValue { value_type: RawValueType::StringValue, value: 2 },
420        );
421        append_equal_cond(
422            &mut instructions,
423            EncodedValue { value_type: RawValueType::StringValue, value: 2 },
424            EncodedValue { value_type: RawValueType::EnumValue, value: 3 },
425        );
426        verify_match_result(
427            Ok(true),
428            DecodedBindRules {
429                symbol_table: symbol_table.clone(),
430                instructions: instructions,
431                decoded_instructions: vec![],
432                debug_info: None,
433            },
434            &device_properties,
435        );
436
437        // The condition should fail since the string device property has a different value.
438        let mut instructions: Vec<u8> = vec![];
439        append_equal_cond(
440            &mut instructions,
441            EncodedValue { value_type: RawValueType::StringValue, value: 1 },
442            EncodedValue { value_type: RawValueType::StringValue, value: 3 },
443        );
444        verify_match_result(
445            Ok(false),
446            DecodedBindRules {
447                symbol_table: symbol_table.clone(),
448                instructions: instructions,
449                decoded_instructions: vec![],
450                debug_info: None,
451            },
452            &device_properties,
453        );
454
455        // The condition should fail since the property is missing from string device properties.
456        let mut instructions: Vec<u8> = vec![];
457        append_equal_cond(
458            &mut instructions,
459            EncodedValue { value_type: RawValueType::StringValue, value: 3 },
460            EncodedValue { value_type: RawValueType::StringValue, value: 1 },
461        );
462        verify_match_result(
463            Ok(false),
464            DecodedBindRules {
465                symbol_table: symbol_table.clone(),
466                instructions: instructions,
467                decoded_instructions: vec![],
468                debug_info: None,
469            },
470            &device_properties,
471        );
472    }
473
474    #[test]
475    fn inequal_condition_with_number_property_keys() {
476        let mut device_properties: DeviceProperties = HashMap::new();
477        device_properties.insert(PropertyKey::NumberKey(1), Symbol::NumberValue(2000));
478        device_properties.insert(PropertyKey::NumberKey(2), Symbol::NumberValue(500));
479
480        // The condition should match since the device property has a different value.
481        let mut instructions: Vec<u8> = vec![];
482        append_inequal_cond(
483            &mut instructions,
484            EncodedValue { value_type: RawValueType::NumberValue, value: 1 },
485            EncodedValue { value_type: RawValueType::NumberValue, value: 500 },
486        );
487        verify_match_result(
488            Ok(true),
489            DecodedBindRules {
490                symbol_table: HashMap::new(),
491                instructions: instructions,
492                decoded_instructions: vec![],
493                debug_info: None,
494            },
495            &device_properties,
496        );
497
498        // The condition should match since the device properties doesn't contain the property.
499        let mut instructions: Vec<u8> = vec![];
500        append_inequal_cond(
501            &mut instructions,
502            EncodedValue { value_type: RawValueType::NumberValue, value: 10 },
503            EncodedValue { value_type: RawValueType::NumberValue, value: 5 },
504        );
505        verify_match_result(
506            Ok(true),
507            DecodedBindRules {
508                symbol_table: HashMap::new(),
509                instructions: instructions,
510                decoded_instructions: vec![],
511                debug_info: None,
512            },
513            &device_properties,
514        );
515
516        // The condition should fail since the device properties matches the value.
517        let mut instructions: Vec<u8> = vec![];
518        append_inequal_cond(
519            &mut instructions,
520            EncodedValue { value_type: RawValueType::NumberValue, value: 2 },
521            EncodedValue { value_type: RawValueType::NumberValue, value: 500 },
522        );
523        verify_match_result(
524            Ok(false),
525            DecodedBindRules {
526                symbol_table: HashMap::new(),
527                instructions: instructions,
528                decoded_instructions: vec![],
529                debug_info: None,
530            },
531            &device_properties,
532        );
533    }
534
535    #[test]
536    fn inequal_condition_with_string_property_keys() {
537        let mut device_properties: DeviceProperties = HashMap::new();
538        device_properties.insert(
539            PropertyKey::StringKey("nightjar".to_string()),
540            Symbol::StringValue("poorwill".to_string()),
541        );
542
543        let mut symbol_table: HashMap<u32, String> = HashMap::new();
544        symbol_table.insert(1, "nightjar".to_string());
545        symbol_table.insert(2, "poorwill".to_string());
546
547        // The condition should match since the string device property has a different value.
548        let mut instructions: Vec<u8> = vec![];
549        append_inequal_cond(
550            &mut instructions,
551            EncodedValue { value_type: RawValueType::StringValue, value: 1 },
552            EncodedValue { value_type: RawValueType::StringValue, value: 1 },
553        );
554        verify_match_result(
555            Ok(true),
556            DecodedBindRules {
557                symbol_table: symbol_table.clone(),
558                instructions: instructions,
559                decoded_instructions: vec![],
560                debug_info: None,
561            },
562            &device_properties,
563        );
564
565        // The condition should match since the string device properties doesn't contain the
566        // property.
567        let mut instructions: Vec<u8> = vec![];
568        append_inequal_cond(
569            &mut instructions,
570            EncodedValue { value_type: RawValueType::StringValue, value: 2 },
571            EncodedValue { value_type: RawValueType::StringValue, value: 1 },
572        );
573        verify_match_result(
574            Ok(true),
575            DecodedBindRules {
576                symbol_table: symbol_table.clone(),
577                instructions: instructions,
578                decoded_instructions: vec![],
579                debug_info: None,
580            },
581            &device_properties,
582        );
583
584        // The condition should fail since the string device properties matches the value.
585        let mut instructions: Vec<u8> = vec![];
586        append_inequal_cond(
587            &mut instructions,
588            EncodedValue { value_type: RawValueType::StringValue, value: 1 },
589            EncodedValue { value_type: RawValueType::StringValue, value: 2 },
590        );
591        verify_match_result(
592            Ok(false),
593            DecodedBindRules {
594                symbol_table: symbol_table.clone(),
595                instructions: instructions,
596                decoded_instructions: vec![],
597                debug_info: None,
598            },
599            &device_properties,
600        );
601    }
602
603    #[test]
604    fn unconditional_abort() {
605        let mut instructions: Vec<u8> = vec![];
606        append_abort(&mut instructions);
607        verify_match_result(
608            Ok(false),
609            DecodedBindRules {
610                symbol_table: HashMap::new(),
611                instructions: instructions,
612                decoded_instructions: vec![],
613                debug_info: None,
614            },
615            &HashMap::new(),
616        );
617    }
618
619    #[test]
620    fn match_with_key_values() {
621        let mut device_properties: DeviceProperties = HashMap::new();
622        device_properties
623            .insert(PropertyKey::StringKey("timberdoodle".to_string()), Symbol::NumberValue(2000));
624
625        let mut symbol_table: HashMap<u32, String> = HashMap::new();
626        symbol_table.insert(1, "timberdoodle".to_string());
627
628        let mut instructions: Vec<u8> = vec![];
629        append_equal_cond(
630            &mut instructions,
631            EncodedValue { value_type: RawValueType::Key, value: 1 },
632            EncodedValue { value_type: RawValueType::NumberValue, value: 2000 },
633        );
634        verify_match_result(
635            Ok(true),
636            DecodedBindRules {
637                symbol_table: symbol_table.clone(),
638                instructions: instructions,
639                decoded_instructions: vec![],
640                debug_info: None,
641            },
642            &device_properties,
643        );
644
645        let mut instructions: Vec<u8> = vec![];
646        append_equal_cond(
647            &mut instructions,
648            EncodedValue { value_type: RawValueType::Key, value: 1 },
649            EncodedValue { value_type: RawValueType::NumberValue, value: 500 },
650        );
651        verify_match_result(
652            Ok(false),
653            DecodedBindRules {
654                symbol_table: symbol_table,
655                instructions: instructions,
656                decoded_instructions: vec![],
657                debug_info: None,
658            },
659            &device_properties,
660        );
661    }
662
663    #[test]
664    fn match_with_bool_values() {
665        let mut device_properties: DeviceProperties = HashMap::new();
666        device_properties.insert(PropertyKey::NumberKey(1), Symbol::BoolValue(true));
667
668        let mut instructions: Vec<u8> = vec![];
669        append_equal_cond(
670            &mut instructions,
671            EncodedValue { value_type: RawValueType::NumberValue, value: 1 },
672            EncodedValue { value_type: RawValueType::BoolValue, value: 1 },
673        );
674        verify_match_result(
675            Ok(true),
676            DecodedBindRules {
677                symbol_table: HashMap::new(),
678                instructions: instructions,
679                decoded_instructions: vec![],
680                debug_info: None,
681            },
682            &device_properties,
683        );
684
685        let mut instructions: Vec<u8> = vec![];
686        append_equal_cond(
687            &mut instructions,
688            EncodedValue { value_type: RawValueType::NumberValue, value: 1 },
689            EncodedValue { value_type: RawValueType::BoolValue, value: 0 },
690        );
691        verify_match_result(
692            Ok(false),
693            DecodedBindRules {
694                symbol_table: HashMap::new(),
695                instructions: instructions,
696                decoded_instructions: vec![],
697                debug_info: None,
698            },
699            &device_properties,
700        );
701    }
702
703    #[test]
704    fn match_with_str_deprecated_keys() {
705        let mut device_properties: DeviceProperties = HashMap::new();
706        device_properties.insert(
707            PropertyKey::StringKey("fuchsia.BIND_PROTOCOL".to_string()),
708            Symbol::NumberValue(10),
709        );
710        device_properties.insert(
711            PropertyKey::StringKey("fuchsia.BIND_PWM_ID".to_string()),
712            Symbol::NumberValue(5),
713        );
714
715        let mut instructions: Vec<u8> = vec![];
716        append_equal_cond(
717            &mut instructions,
718            EncodedValue {
719                value_type: RawValueType::NumberValue,
720                value: 0x01, /* BIND_PROTOCOL */
721            },
722            EncodedValue { value_type: RawValueType::NumberValue, value: 10 },
723        );
724        append_equal_cond(
725            &mut instructions,
726            EncodedValue {
727                value_type: RawValueType::NumberValue,
728                value: 0x0A50, /* BIND_PWN_ID */
729            },
730            EncodedValue { value_type: RawValueType::NumberValue, value: 5 },
731        );
732        verify_match_result(
733            Ok(true),
734            DecodedBindRules {
735                symbol_table: HashMap::new(),
736                instructions: instructions,
737                decoded_instructions: vec![],
738                debug_info: None,
739            },
740            &device_properties,
741        );
742    }
743
744    #[test]
745    fn missing_entry_in_symbol_table() {
746        let mut symbol_table: HashMap<u32, String> = HashMap::new();
747        symbol_table.insert(1, "nightjar".to_string());
748        symbol_table.insert(2, "poorwill".to_string());
749
750        let mut instructions: Vec<u8> = vec![];
751        append_inequal_cond(
752            &mut instructions,
753            EncodedValue { value_type: RawValueType::StringValue, value: 10 },
754            EncodedValue { value_type: RawValueType::StringValue, value: 1 },
755        );
756        verify_match_result(
757            Err(BytecodeError::MissingEntryInSymbolTable(10)),
758            DecodedBindRules {
759                symbol_table: HashMap::new(),
760                instructions: instructions,
761                decoded_instructions: vec![],
762                debug_info: None,
763            },
764            &HashMap::new(),
765        );
766
767        let mut instructions: Vec<u8> = vec![];
768        append_inequal_cond(
769            &mut instructions,
770            EncodedValue { value_type: RawValueType::Key, value: 15 },
771            EncodedValue { value_type: RawValueType::StringValue, value: 1 },
772        );
773        verify_match_result(
774            Err(BytecodeError::MissingEntryInSymbolTable(15)),
775            DecodedBindRules {
776                symbol_table: HashMap::new(),
777                instructions: instructions,
778                decoded_instructions: vec![],
779                debug_info: None,
780            },
781            &HashMap::new(),
782        );
783    }
784
785    #[test]
786    fn invalid_op() {
787        let mut instructions: Vec<u8> = vec![0xFF];
788        append_inequal_cond(
789            &mut instructions,
790            EncodedValue { value_type: RawValueType::NumberValue, value: 10 },
791            EncodedValue { value_type: RawValueType::NumberValue, value: 1 },
792        );
793
794        verify_match_result(
795            Err(BytecodeError::InvalidOp(0xFF)),
796            DecodedBindRules {
797                symbol_table: HashMap::new(),
798                instructions: instructions,
799                decoded_instructions: vec![],
800                debug_info: None,
801            },
802            &HashMap::new(),
803        );
804    }
805
806    #[test]
807    fn invalid_value_type() {
808        let instructions: Vec<u8> = vec![0x01, 0x05, 0, 0, 0, 0, 0x01, 0, 0, 0, 0];
809        verify_match_result(
810            Err(BytecodeError::InvalidValueType(0x05)),
811            DecodedBindRules {
812                symbol_table: HashMap::new(),
813                instructions: instructions,
814                decoded_instructions: vec![],
815                debug_info: None,
816            },
817            &HashMap::new(),
818        );
819    }
820
821    #[test]
822    fn invalid_bool_value() {
823        let mut instructions: Vec<u8> = vec![];
824        append_inequal_cond(
825            &mut instructions,
826            EncodedValue { value_type: RawValueType::NumberValue, value: 10 },
827            EncodedValue { value_type: RawValueType::BoolValue, value: 15 },
828        );
829
830        verify_match_result(
831            Err(BytecodeError::InvalidBoolValue(15)),
832            DecodedBindRules {
833                symbol_table: HashMap::new(),
834                instructions: instructions,
835                decoded_instructions: vec![],
836                debug_info: None,
837            },
838            &HashMap::new(),
839        );
840    }
841
842    #[test]
843    fn invalid_key_type() {
844        let mut instructions: Vec<u8> = vec![];
845        append_inequal_cond(
846            &mut instructions,
847            EncodedValue { value_type: RawValueType::BoolValue, value: 1 },
848            EncodedValue { value_type: RawValueType::BoolValue, value: 15 },
849        );
850
851        verify_match_result(
852            Err(BytecodeError::InvalidKeyType),
853            DecodedBindRules {
854                symbol_table: HashMap::new(),
855                instructions: instructions,
856                decoded_instructions: vec![],
857                debug_info: None,
858            },
859            &HashMap::new(),
860        );
861    }
862
863    #[test]
864    fn mismatch_value_types() {
865        let mut device_properties: DeviceProperties = HashMap::new();
866        device_properties.insert(PropertyKey::NumberKey(1), Symbol::NumberValue(2000));
867        device_properties.insert(
868            PropertyKey::StringKey("tyrant".to_string()),
869            Symbol::StringValue("flycatcher".to_string()),
870        );
871
872        let mut symbol_table: HashMap<u32, String> = HashMap::new();
873        symbol_table.insert(1, "tyrant".to_string());
874        symbol_table.insert(2, "flycatcher".to_string());
875
876        let mut instructions: Vec<u8> = vec![];
877        append_equal_cond(
878            &mut instructions,
879            EncodedValue { value_type: RawValueType::StringValue, value: 1 },
880            EncodedValue { value_type: RawValueType::NumberValue, value: 15 },
881        );
882
883        verify_match_result(
884            Err(BytecodeError::MismatchValueTypes),
885            DecodedBindRules {
886                symbol_table: symbol_table,
887                instructions: instructions,
888                decoded_instructions: vec![],
889                debug_info: None,
890            },
891            &device_properties,
892        );
893    }
894
895    #[test]
896    fn invalid_condition_statement() {
897        let instructions: Vec<u8> = vec![0x01, 0x02, 0, 0, 0];
898        verify_match_result(
899            Err(BytecodeError::UnexpectedEnd),
900            DecodedBindRules {
901                symbol_table: HashMap::new(),
902                instructions: instructions,
903                decoded_instructions: vec![],
904                debug_info: None,
905            },
906            &HashMap::new(),
907        );
908    }
909
910    #[test]
911    fn match_with_multiple_condition_statements() {
912        let mut device_properties: DeviceProperties = HashMap::new();
913        device_properties.insert(PropertyKey::NumberKey(10), Symbol::NumberValue(2000));
914        device_properties.insert(PropertyKey::NumberKey(2), Symbol::NumberValue(500));
915        device_properties.insert(
916            PropertyKey::StringKey("rail".to_string()),
917            Symbol::StringValue("crake".to_string()),
918        );
919
920        let mut symbol_table: HashMap<u32, String> = HashMap::new();
921        symbol_table.insert(1, "crake".to_string());
922        symbol_table.insert(2, "rail".to_string());
923
924        let mut instructions: Vec<u8> = vec![];
925        append_inequal_cond(
926            &mut instructions,
927            EncodedValue { value_type: RawValueType::NumberValue, value: 10 },
928            EncodedValue { value_type: RawValueType::NumberValue, value: 200 },
929        );
930        append_inequal_cond(
931            &mut instructions,
932            EncodedValue { value_type: RawValueType::StringValue, value: 1 },
933            EncodedValue { value_type: RawValueType::StringValue, value: 2 },
934        );
935        append_equal_cond(
936            &mut instructions,
937            EncodedValue { value_type: RawValueType::NumberValue, value: 10 },
938            EncodedValue { value_type: RawValueType::NumberValue, value: 2000 },
939        );
940
941        verify_match_result(
942            Ok(true),
943            DecodedBindRules {
944                symbol_table: symbol_table,
945                instructions: instructions,
946                decoded_instructions: vec![],
947                debug_info: None,
948            },
949            &device_properties,
950        );
951    }
952
953    #[test]
954    fn no_match_with_multiple_condition_statements() {
955        let mut device_properties: DeviceProperties = HashMap::new();
956        device_properties.insert(PropertyKey::NumberKey(10), Symbol::NumberValue(2000));
957        device_properties.insert(PropertyKey::NumberKey(2), Symbol::NumberValue(500));
958        device_properties.insert(
959            PropertyKey::StringKey("rail".to_string()),
960            Symbol::StringValue("crake".to_string()),
961        );
962
963        let mut symbol_table: HashMap<u32, String> = HashMap::new();
964        symbol_table.insert(1, "crake".to_string());
965        symbol_table.insert(2, "rail".to_string());
966
967        let mut instructions: Vec<u8> = vec![];
968        append_equal_cond(
969            &mut instructions,
970            EncodedValue { value_type: RawValueType::StringValue, value: 2 },
971            EncodedValue { value_type: RawValueType::StringValue, value: 1 },
972        );
973        append_equal_cond(
974            &mut instructions,
975            EncodedValue { value_type: RawValueType::NumberValue, value: 2 },
976            EncodedValue { value_type: RawValueType::NumberValue, value: 5000 },
977        );
978        append_inequal_cond(
979            &mut instructions,
980            EncodedValue { value_type: RawValueType::NumberValue, value: 1 },
981            EncodedValue { value_type: RawValueType::NumberValue, value: 40 },
982        );
983
984        verify_match_result(
985            Ok(false),
986            DecodedBindRules {
987                symbol_table: symbol_table,
988                instructions: instructions,
989                decoded_instructions: vec![],
990                debug_info: None,
991            },
992            &device_properties,
993        );
994    }
995
996    #[test]
997    fn unconditional_jump() {
998        let mut instructions: Vec<u8> = vec![];
999        append_unconditional_jump(&mut instructions, ABORT_BYTES + COND_INST_BYTES);
1000        append_abort(&mut instructions);
1001        append_equal_cond(
1002            &mut instructions,
1003            EncodedValue { value_type: RawValueType::NumberValue, value: 1 },
1004            EncodedValue { value_type: RawValueType::NumberValue, value: 2000 },
1005        );
1006        append_jump_pad(&mut instructions);
1007
1008        verify_match_result(
1009            Ok(true),
1010            DecodedBindRules {
1011                symbol_table: HashMap::new(),
1012                instructions: instructions,
1013                decoded_instructions: vec![],
1014                debug_info: None,
1015            },
1016            &HashMap::new(),
1017        );
1018    }
1019
1020    #[test]
1021    fn jump_if_equal() {
1022        let mut symbol_table: HashMap<u32, String> = HashMap::new();
1023        symbol_table.insert(1, "whimbrel".to_string());
1024
1025        let mut instructions: Vec<u8> = vec![];
1026        append_jump_if_equal(
1027            &mut instructions,
1028            ABORT_BYTES * 2,
1029            EncodedValue { value_type: RawValueType::NumberValue, value: 10 },
1030            EncodedValue { value_type: RawValueType::StringValue, value: 1 },
1031        );
1032        append_abort(&mut instructions);
1033        append_abort(&mut instructions);
1034        append_jump_pad(&mut instructions);
1035
1036        let mut device_properties: DeviceProperties = HashMap::new();
1037        device_properties
1038            .insert(PropertyKey::NumberKey(10), Symbol::StringValue("whimbrel".to_string()));
1039        verify_match_result(
1040            Ok(true),
1041            DecodedBindRules {
1042                symbol_table: symbol_table.clone(),
1043                instructions: instructions.clone(),
1044                decoded_instructions: vec![],
1045                debug_info: None,
1046            },
1047            &device_properties,
1048        );
1049
1050        let mut device_properties: DeviceProperties = HashMap::new();
1051        device_properties
1052            .insert(PropertyKey::NumberKey(10), Symbol::StringValue("godwit".to_string()));
1053        verify_match_result(
1054            Ok(false),
1055            DecodedBindRules {
1056                symbol_table: symbol_table.clone(),
1057                instructions: instructions,
1058                decoded_instructions: vec![],
1059                debug_info: None,
1060            },
1061            &device_properties,
1062        );
1063    }
1064
1065    #[test]
1066    fn jump_if_not_equal() {
1067        let mut instructions: Vec<u8> = vec![];
1068        append_jump_if_not_equal(
1069            &mut instructions,
1070            ABORT_BYTES * 2,
1071            EncodedValue { value_type: RawValueType::NumberValue, value: 10 },
1072            EncodedValue { value_type: RawValueType::NumberValue, value: 2000 },
1073        );
1074        append_abort(&mut instructions);
1075        append_abort(&mut instructions);
1076        append_jump_pad(&mut instructions);
1077
1078        let mut device_properties: DeviceProperties = HashMap::new();
1079        device_properties.insert(PropertyKey::NumberKey(10), Symbol::NumberValue(2000));
1080        verify_match_result(
1081            Ok(false),
1082            DecodedBindRules {
1083                symbol_table: HashMap::new(),
1084                instructions: instructions.clone(),
1085                decoded_instructions: vec![],
1086                debug_info: None,
1087            },
1088            &device_properties,
1089        );
1090
1091        let mut device_properties: DeviceProperties = HashMap::new();
1092        device_properties.insert(PropertyKey::NumberKey(10), Symbol::NumberValue(20));
1093        verify_match_result(
1094            Ok(true),
1095            DecodedBindRules {
1096                symbol_table: HashMap::new(),
1097                instructions: instructions,
1098                decoded_instructions: vec![],
1099                debug_info: None,
1100            },
1101            &device_properties,
1102        );
1103    }
1104
1105    #[test]
1106    fn no_jump_pad() {
1107        let mut device_properties: DeviceProperties = HashMap::new();
1108        device_properties.insert(PropertyKey::NumberKey(10), Symbol::NumberValue(2000));
1109
1110        let mut instructions: Vec<u8> = vec![];
1111        append_jump_if_equal(
1112            &mut instructions,
1113            ABORT_BYTES,
1114            EncodedValue { value_type: RawValueType::NumberValue, value: 10 },
1115            EncodedValue { value_type: RawValueType::NumberValue, value: 2000 },
1116        );
1117        append_abort(&mut instructions);
1118        append_abort(&mut instructions);
1119        verify_match_result(
1120            Err(BytecodeError::InvalidJumpLocation),
1121            DecodedBindRules {
1122                symbol_table: HashMap::new(),
1123                instructions: instructions,
1124                decoded_instructions: vec![],
1125                debug_info: None,
1126            },
1127            &device_properties,
1128        );
1129    }
1130
1131    #[test]
1132    fn jump_out_of_bounds() {
1133        let mut device_properties: DeviceProperties = HashMap::new();
1134        device_properties.insert(PropertyKey::NumberKey(10), Symbol::NumberValue(2000));
1135
1136        let mut instructions: Vec<u8> = vec![];
1137        append_jump_if_equal(
1138            &mut instructions,
1139            ABORT_BYTES + JMP_PAD_BYTES + 1,
1140            EncodedValue { value_type: RawValueType::NumberValue, value: 10 },
1141            EncodedValue { value_type: RawValueType::NumberValue, value: 2000 },
1142        );
1143        append_abort(&mut instructions);
1144        append_jump_pad(&mut instructions);
1145        verify_match_result(
1146            Err(BytecodeError::UnexpectedEnd),
1147            DecodedBindRules {
1148                symbol_table: HashMap::new(),
1149                instructions: instructions,
1150                decoded_instructions: vec![],
1151                debug_info: None,
1152            },
1153            &device_properties,
1154        );
1155    }
1156
1157    #[test]
1158    fn nested_jump_instructions() {
1159        let mut instructions: Vec<u8> = vec![];
1160        append_jump_if_equal(
1161            &mut instructions,
1162            ABORT_BYTES * 2 + UNCOND_JMP_BYTES + JMP_PAD_BYTES,
1163            EncodedValue { value_type: RawValueType::NumberValue, value: 10 },
1164            EncodedValue { value_type: RawValueType::NumberValue, value: 2000 },
1165        );
1166        append_unconditional_jump(&mut instructions, ABORT_BYTES);
1167        append_abort(&mut instructions);
1168        append_jump_pad(&mut instructions);
1169        append_abort(&mut instructions);
1170        append_jump_pad(&mut instructions);
1171
1172        let mut device_properties: DeviceProperties = HashMap::new();
1173        device_properties.insert(PropertyKey::NumberKey(10), Symbol::NumberValue(2000));
1174        verify_match_result(
1175            Ok(true),
1176            DecodedBindRules {
1177                symbol_table: HashMap::new(),
1178                instructions: instructions.clone(),
1179                decoded_instructions: vec![],
1180                debug_info: None,
1181            },
1182            &device_properties,
1183        );
1184
1185        let mut device_properties: DeviceProperties = HashMap::new();
1186        device_properties.insert(PropertyKey::NumberKey(10), Symbol::NumberValue(200));
1187        device_properties.insert(
1188            PropertyKey::StringKey("kingfisher".to_string()),
1189            Symbol::StringValue("kookaburra".to_string()),
1190        );
1191        verify_match_result(
1192            Ok(false),
1193            DecodedBindRules {
1194                symbol_table: HashMap::new(),
1195                instructions: instructions,
1196                decoded_instructions: vec![],
1197                debug_info: None,
1198            },
1199            &device_properties,
1200        );
1201    }
1202
1203    #[test]
1204    fn complex_mix_of_bind_rules() {
1205        let mut symbol_table: HashMap<u32, String> = HashMap::new();
1206        symbol_table.insert(1, "kingfisher".to_string());
1207        symbol_table.insert(2, "kookaburra".to_string());
1208
1209        let mut instructions: Vec<u8> = vec![];
1210        append_jump_if_equal(
1211            &mut instructions,
1212            COND_INST_BYTES + ABORT_BYTES,
1213            EncodedValue { value_type: RawValueType::NumberValue, value: 5 },
1214            EncodedValue { value_type: RawValueType::BoolValue, value: 1 },
1215        );
1216        append_equal_cond(
1217            &mut instructions,
1218            EncodedValue { value_type: RawValueType::NumberValue, value: 2 },
1219            EncodedValue { value_type: RawValueType::NumberValue, value: 2000 },
1220        );
1221        append_abort(&mut instructions);
1222        append_jump_pad(&mut instructions);
1223        append_unconditional_jump(&mut instructions, COND_JMP_BYTES + ABORT_BYTES);
1224        append_jump_if_not_equal(
1225            &mut instructions,
1226            ABORT_BYTES + JMP_PAD_BYTES + COND_INST_BYTES,
1227            EncodedValue { value_type: RawValueType::StringValue, value: 1 },
1228            EncodedValue { value_type: RawValueType::StringValue, value: 2 },
1229        );
1230        append_abort(&mut instructions);
1231        append_jump_pad(&mut instructions);
1232        append_inequal_cond(
1233            &mut instructions,
1234            EncodedValue { value_type: RawValueType::NumberValue, value: 1 },
1235            EncodedValue { value_type: RawValueType::NumberValue, value: 50 },
1236        );
1237        append_jump_pad(&mut instructions);
1238        append_equal_cond(
1239            &mut instructions,
1240            EncodedValue { value_type: RawValueType::StringValue, value: 1 },
1241            EncodedValue { value_type: RawValueType::StringValue, value: 2 },
1242        );
1243
1244        let mut device_properties: DeviceProperties = HashMap::new();
1245        device_properties.insert(
1246            PropertyKey::StringKey("kingfisher".to_string()),
1247            Symbol::StringValue("kookaburra".to_string()),
1248        );
1249        device_properties.insert(PropertyKey::NumberKey(1), Symbol::NumberValue(9));
1250        device_properties.insert(PropertyKey::NumberKey(2), Symbol::NumberValue(100));
1251        device_properties.insert(PropertyKey::NumberKey(5), Symbol::BoolValue(true));
1252
1253        verify_match_result(
1254            Ok(true),
1255            DecodedBindRules {
1256                symbol_table: symbol_table,
1257                instructions: instructions,
1258                decoded_instructions: vec![],
1259                debug_info: None,
1260            },
1261            &device_properties,
1262        );
1263    }
1264}