diff options
Diffstat (limited to 'usr.bin/dtc/checking.hh')
-rw-r--r-- | usr.bin/dtc/checking.hh | 308 |
1 files changed, 308 insertions, 0 deletions
diff --git a/usr.bin/dtc/checking.hh b/usr.bin/dtc/checking.hh new file mode 100644 index 0000000..0de1d60 --- /dev/null +++ b/usr.bin/dtc/checking.hh @@ -0,0 +1,308 @@ +/*- + * Copyright (c) 2013 David Chisnall + * All rights reserved. + * + * This software was developed by SRI International and the University of + * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237) + * ("CTSRD"), as part of the DARPA CRASH research programme. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _CHECKING_HH_ +#define _CHECKING_HH_ +#include "string.hh" +#include "fdt.hh" + +namespace dtc +{ +namespace fdt +{ +namespace checking +{ +/** + * Base class for all checkers. This will visit the entire tree and perform + * semantic checks defined in subclasses. Note that device trees are generally + * small (a few dozen nodes at most) and so we optimise for flexibility and + * extensibility here, not for performance. Each checker will visit the entire + * tree. + */ +class checker +{ + /** + * The path to the current node being checked. This is used for + * printing error messages. + */ + device_tree::node_path path; + /** + * The name of the checker. This is used for printing error messages + * and for enabling / disabling specific checkers from the command + * line. + */ + const char *checker_name; + /** + * Visits each node, calling the checker functions on properties and + * nodes. + */ + bool visit_node(device_tree *tree, node *n); + protected: + /** + * Prints the error message, along with the path to the node that + * caused the error and the name of the checker. + */ + void report_error(const char *errmsg); + public: + /** + * Constructor. Takes the name of this checker, which is which is used + * when reporting errors. + */ + checker(const char *name) : checker_name(name) {} + /** + * Virtual destructor in case any subclasses need to do cleanup. + */ + virtual ~checker() {} + /** + * Method for checking that a node is valid. The root class version + * does nothing, subclasses should override this. + */ + virtual bool check_node(device_tree *tree, node *n) + { + return true; + } + /** + * Method for checking that a property is valid. The root class + * version does nothing, subclasses should override this. + */ + virtual bool check_property(device_tree *tree, node *n, property *p) + { + return true; + } + /** + * Runs the checker on the specified device tree. + */ + bool check_tree(fdt::device_tree *tree) + { + return visit_node(tree, tree->get_root()); + } +}; + +/** + * Abstract base class for simple property checks. This class defines a check + * method for subclasses, which is invoked only when it finds a property with + * the matching name. To define simple property checkers, just subclass this + * and override the check() method. + */ +class property_checker : public checker +{ + /** + * The name of the property that this checker is looking for. + */ + string key; + public: + /** + * Implementation of the generic property-checking method that checks + * for a property with the name specified in the constructor + */ + virtual bool check_property(device_tree *tree, node *n, property *p); + /** + * Constructor. Takes the name of the checker and the name of the + * property to check. + */ + property_checker(const char* name, string property_name) + : checker(name), key(property_name) {} + /** + * The check method, which subclasses should implement. + */ + virtual bool check(device_tree *tree, node *n, property *p) = 0; +}; + +/** + * Property type checker. + */ +template<property_value::value_type T> +struct property_type_checker : public property_checker +{ + /** + * Constructor, takes the name of the checker and the name of the + * property to check as arguments. + */ + property_type_checker(const char* name, string property_name) : + property_checker(name, property_name) {} + virtual bool check(device_tree *tree, node *n, property *p) = 0; +}; + +/** + * Empty property checker. This checks that the property has no value. + */ +template<> +struct property_type_checker <property_value::EMPTY> : public property_checker +{ + property_type_checker(const char* name, string property_name) : + property_checker(name, property_name) {} + virtual bool check(device_tree *tree, node *n, property *p) + { + return p->begin() == p->end(); + } +}; + +/** + * String property checker. This checks that the property has exactly one + * value, which is a string. + */ +template<> +struct property_type_checker <property_value::STRING> : public property_checker +{ + property_type_checker(const char* name, string property_name) : + property_checker(name, property_name) {} + virtual bool check(device_tree *tree, node *n, property *p) + { + return (p->begin() + 1 == p->end()) && p->begin()->is_string(); + } +}; +/** + * String list property checker. This checks that the property has at least + * one value, all of which are strings. + */ +template<> +struct property_type_checker <property_value::STRING_LIST> : + public property_checker +{ + property_type_checker(const char* name, string property_name) : + property_checker(name, property_name) {} + virtual bool check(device_tree *tree, node *n, property *p) + { + for (property::value_iterator i=p->begin(),e=p->end() ; i!=e ; + ++i) + { + if (!(i->is_string() || i->is_string_list())) + { + return false; + } + } + return p->begin() != p->end(); + } +}; + +/** + * Phandle property checker. This checks that the property has exactly one + * value, which is a valid phandle. + */ +template<> +struct property_type_checker <property_value::PHANDLE> : public property_checker +{ + property_type_checker(const char* name, string property_name) : + property_checker(name, property_name) {} + virtual bool check(device_tree *tree, node *n, property *p) + { + return (p->begin() + 1 == p->end()) && + (tree->referenced_node(*p->begin()) != 0); + } +}; + +/** + * Check that a property has the correct size. + */ +struct property_size_checker : public property_checker +{ + /** + * The expected size of the property. + */ + uint32_t size; + public: + /** + * Constructor, takes the name of the checker, the name of the property + * to check, and its expected size as arguments. + */ + property_size_checker(const char* name, string property_name, uint32_t bytes) + : property_checker(name, property_name), size(bytes) {} + /** + * Check, validates that the property has the correct size. + */ + virtual bool check(device_tree *tree, node *n, property *p); +}; + + +/** + * The check manager is the interface to running the checks. This allows + * default checks to be enabled, non-default checks to be enabled, and so on. + */ +class check_manager +{ + /** + * The enabled checkers, indexed by their names. The name is used when + * disabling checkers from the command line. When this manager runs, + * it will only run the checkers from this map. + */ + std::map<string, checker*> checkers; + /** + * The disabled checkers. Moving checkers to this list disables them, + * but allows them to be easily moved back. + */ + std::map<string, checker*> disabled_checkers; + /** + * Helper function for adding a property value checker. + */ + template<property_value::value_type T> + void add_property_type_checker(const char *name, string prop); + /** + * Helper function for adding a simple type checker. + */ + void add_property_type_checker(const char *name, string prop); + /** + * Helper function for adding a property value checker. + */ + void add_property_size_checker(const char *name, + string prop, + uint32_t size); + public: + /** + * Delete all of the checkers that are part of this checker manager. + */ + ~check_manager(); + /** + * Default constructor, creates check manager containing all of the + * default checks. + */ + check_manager(); + /** + * Run all of the checks on the specified tree. + */ + bool run_checks(device_tree *tree, bool keep_going); + /** + * Disables the named checker. + */ + bool disable_checker(string name); + /** + * Enables the named checker. + */ + bool enable_checker(string name); +}; + +} // namespace checking + +} // namespace fdt + +} // namespace dtc + +#endif // !_CHECKING_HH_ |