1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2013 David Chisnall 5 * All rights reserved. 6 * 7 * This software was developed by SRI International and the University of 8 * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237) 9 * ("CTSRD"), as part of the DARPA CRASH research programme. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 #ifndef _CHECKING_HH_ 34 #define _CHECKING_HH_ 35 #include <string> 36 #include "fdt.hh" 37 38 namespace dtc 39 { 40 namespace fdt 41 { 42 namespace checking 43 { 44 /** 45 * Base class for all checkers. This will visit the entire tree and perform 46 * semantic checks defined in subclasses. Note that device trees are generally 47 * small (a few dozen nodes at most) and so we optimise for flexibility and 48 * extensibility here, not for performance. Each checker will visit the entire 49 * tree. 50 */ 51 class checker 52 { 53 /** 54 * The path to the current node being checked. This is used for 55 * printing error messages. 56 */ 57 device_tree::node_path path; 58 /** 59 * The name of the checker. This is used for printing error messages 60 * and for enabling / disabling specific checkers from the command 61 * line. 62 */ 63 const char *checker_name; 64 /** 65 * Visits each node, calling the checker functions on properties and 66 * nodes. 67 */ 68 bool visit_node(device_tree *tree, const node_ptr &n); 69 protected: 70 /** 71 * Prints the error message, along with the path to the node that 72 * caused the error and the name of the checker. 73 */ 74 void report_error(const char *errmsg); 75 public: 76 /** 77 * Constructor. Takes the name of this checker, which is which is used 78 * when reporting errors. 79 */ checker(const char * name)80 checker(const char *name) : checker_name(name) {} 81 /** 82 * Virtual destructor in case any subclasses need to do cleanup. 83 */ ~checker()84 virtual ~checker() {} 85 /** 86 * Method for checking that a node is valid. The root class version 87 * does nothing, subclasses should override this. 88 */ check_node(device_tree *,const node_ptr &)89 virtual bool check_node(device_tree *, const node_ptr &) 90 { 91 return true; 92 } 93 /** 94 * Method for checking that a property is valid. The root class 95 * version does nothing, subclasses should override this. 96 */ check_property(device_tree *,const node_ptr &,property_ptr)97 virtual bool check_property(device_tree *, const node_ptr &, property_ptr ) 98 { 99 return true; 100 } 101 /** 102 * Runs the checker on the specified device tree. 103 */ check_tree(fdt::device_tree * tree)104 bool check_tree(fdt::device_tree *tree) 105 { 106 return visit_node(tree, tree->get_root()); 107 } 108 }; 109 110 /** 111 * Abstract base class for simple property checks. This class defines a check 112 * method for subclasses, which is invoked only when it finds a property with 113 * the matching name. To define simple property checkers, just subclass this 114 * and override the check() method. 115 */ 116 class property_checker : public checker 117 { 118 /** 119 * The name of the property that this checker is looking for. 120 */ 121 std::string key; 122 public: 123 /** 124 * Implementation of the generic property-checking method that checks 125 * for a property with the name specified in the constructor. 126 */ 127 virtual bool check_property(device_tree *tree, const node_ptr &n, property_ptr p); 128 /** 129 * Constructor. Takes the name of the checker and the name of the 130 * property to check. 131 */ property_checker(const char * name,const std::string & property_name)132 property_checker(const char* name, const std::string &property_name) 133 : checker(name), key(property_name) {} 134 /** 135 * The check method, which subclasses should implement. 136 */ 137 virtual bool check(device_tree *tree, const node_ptr &n, property_ptr p) = 0; 138 }; 139 140 /** 141 * Property type checker. 142 */ 143 template<property_value::value_type T> 144 struct property_type_checker : public property_checker 145 { 146 /** 147 * Constructor, takes the name of the checker and the name of the 148 * property to check as arguments. 149 */ property_type_checkerdtc::fdt::checking::property_type_checker150 property_type_checker(const char* name, const std::string &property_name) : 151 property_checker(name, property_name) {} 152 virtual bool check(device_tree *tree, const node_ptr &n, property_ptr p) = 0; 153 }; 154 155 /** 156 * Empty property checker. This checks that the property has no value. 157 */ 158 template<> 159 struct property_type_checker <property_value::EMPTY> : public property_checker 160 { property_type_checkerdtc::fdt::checking::property_type_checker161 property_type_checker(const char* name, const std::string &property_name) : 162 property_checker(name, property_name) {} checkdtc::fdt::checking::property_type_checker163 virtual bool check(device_tree *, const node_ptr &, property_ptr p) 164 { 165 return p->begin() == p->end(); 166 } 167 }; 168 169 /** 170 * String property checker. This checks that the property has exactly one 171 * value, which is a string. 172 */ 173 template<> 174 struct property_type_checker <property_value::STRING> : public property_checker 175 { property_type_checkerdtc::fdt::checking::property_type_checker176 property_type_checker(const char* name, const std::string &property_name) : 177 property_checker(name, property_name) {} checkdtc::fdt::checking::property_type_checker178 virtual bool check(device_tree *, const node_ptr &, property_ptr p) 179 { 180 return (p->begin() + 1 == p->end()) && p->begin()->is_string(); 181 } 182 }; 183 /** 184 * String list property checker. This checks that the property has at least 185 * one value, all of which are strings. 186 */ 187 template<> 188 struct property_type_checker <property_value::STRING_LIST> : 189 public property_checker 190 { property_type_checkerdtc::fdt::checking::property_type_checker191 property_type_checker(const char* name, const std::string &property_name) : 192 property_checker(name, property_name) {} checkdtc::fdt::checking::property_type_checker193 virtual bool check(device_tree *, const node_ptr &, property_ptr p) 194 { 195 for (property::value_iterator i=p->begin(),e=p->end() ; i!=e ; 196 ++i) 197 { 198 if (!(i->is_string() || i->is_string_list())) 199 { 200 return false; 201 } 202 } 203 return p->begin() != p->end(); 204 } 205 }; 206 207 /** 208 * Phandle property checker. This checks that the property has exactly one 209 * value, which is a valid phandle. 210 */ 211 template<> 212 struct property_type_checker <property_value::PHANDLE> : public property_checker 213 { property_type_checkerdtc::fdt::checking::property_type_checker214 property_type_checker(const char* name, const std::string &property_name) : 215 property_checker(name, property_name) {} checkdtc::fdt::checking::property_type_checker216 virtual bool check(device_tree *tree, const node_ptr &, property_ptr p) 217 { 218 return (p->begin() + 1 == p->end()) && 219 (tree->referenced_node(*p->begin()) != 0); 220 } 221 }; 222 223 /** 224 * Check that a property has the correct size. 225 */ 226 struct property_size_checker : public property_checker 227 { 228 /** 229 * The expected size of the property. 230 */ 231 uint32_t size; 232 public: 233 /** 234 * Constructor, takes the name of the checker, the name of the property 235 * to check, and its expected size as arguments. 236 */ property_size_checkerdtc::fdt::checking::property_size_checker237 property_size_checker(const char* name, 238 const std::string &property_name, 239 uint32_t bytes) 240 : property_checker(name, property_name), size(bytes) {} 241 /** 242 * Check, validates that the property has the correct size. 243 */ 244 virtual bool check(device_tree *tree, const node_ptr &n, property_ptr p); 245 }; 246 247 248 /** 249 * The check manager is the interface to running the checks. This allows 250 * default checks to be enabled, non-default checks to be enabled, and so on. 251 */ 252 class check_manager 253 { 254 /** 255 * The enabled checkers, indexed by their names. The name is used when 256 * disabling checkers from the command line. When this manager runs, 257 * it will only run the checkers from this map. 258 */ 259 std::unordered_map<std::string, checker*> checkers; 260 /** 261 * The disabled checkers. Moving checkers to this list disables them, 262 * but allows them to be easily moved back. 263 */ 264 std::unordered_map<std::string, checker*> disabled_checkers; 265 /** 266 * Helper function for adding a property value checker. 267 */ 268 template<property_value::value_type T> 269 void add_property_type_checker(const char *name, const std::string &prop); 270 /** 271 * Helper function for adding a simple type checker. 272 */ 273 void add_property_type_checker(const char *name, const std::string &prop); 274 /** 275 * Helper function for adding a property value checker. 276 */ 277 void add_property_size_checker(const char *name, 278 const std::string &prop, 279 uint32_t size); 280 public: 281 /** 282 * Delete all of the checkers that are part of this checker manager. 283 */ 284 ~check_manager(); 285 /** 286 * Default constructor, creates check manager containing all of the 287 * default checks. 288 */ 289 check_manager(); 290 /** 291 * Run all of the checks on the specified tree. 292 */ 293 bool run_checks(device_tree *tree, bool keep_going); 294 /** 295 * Disables the named checker. 296 */ 297 bool disable_checker(const std::string &name); 298 /** 299 * Enables the named checker. 300 */ 301 bool enable_checker(const std::string &name); 302 }; 303 304 } // namespace checking 305 306 } // namespace fdt 307 308 } // namespace dtc 309 310 #endif // !_CHECKING_HH_ 311