/*- * 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 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 : 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 : 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 : 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 : 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 checkers; /** * The disabled checkers. Moving checkers to this list disables them, * but allows them to be easily moved back. */ std::map disabled_checkers; /** * Helper function for adding a property value checker. */ template 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_