1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 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 * $FreeBSD$ 33 */ 34 35 #ifndef _CHECKING_HH_ 36 #define _CHECKING_HH_ 37 #include <string> 38 #include "fdt.hh" 39 40 namespace dtc 41 { 42 namespace fdt 43 { 44 namespace checking 45 { 46 /** 47 * Base class for all checkers. This will visit the entire tree and perform 48 * semantic checks defined in subclasses. Note that device trees are generally 49 * small (a few dozen nodes at most) and so we optimise for flexibility and 50 * extensibility here, not for performance. Each checker will visit the entire 51 * tree. 52 */ 53 class checker 54 { 55 /** 56 * The path to the current node being checked. This is used for 57 * printing error messages. 58 */ 59 device_tree::node_path path; 60 /** 61 * The name of the checker. This is used for printing error messages 62 * and for enabling / disabling specific checkers from the command 63 * line. 64 */ 65 const char *checker_name; 66 /** 67 * Visits each node, calling the checker functions on properties and 68 * nodes. 69 */ 70 bool visit_node(device_tree *tree, const node_ptr &n); 71 protected: 72 /** 73 * Prints the error message, along with the path to the node that 74 * caused the error and the name of the checker. 75 */ 76 void report_error(const char *errmsg); 77 public: 78 /** 79 * Constructor. Takes the name of this checker, which is which is used 80 * when reporting errors. 81 */ 82 checker(const char *name) : checker_name(name) {} 83 /** 84 * Virtual destructor in case any subclasses need to do cleanup. 85 */ 86 virtual ~checker() {} 87 /** 88 * Method for checking that a node is valid. The root class version 89 * does nothing, subclasses should override this. 90 */ 91 virtual bool check_node(device_tree *, const node_ptr &) 92 { 93 return true; 94 } 95 /** 96 * Method for checking that a property is valid. The root class 97 * version does nothing, subclasses should override this. 98 */ 99 virtual bool check_property(device_tree *, const node_ptr &, property_ptr ) 100 { 101 return true; 102 } 103 /** 104 * Runs the checker on the specified device tree. 105 */ 106 bool check_tree(fdt::device_tree *tree) 107 { 108 return visit_node(tree, tree->get_root()); 109 } 110 }; 111 112 /** 113 * Abstract base class for simple property checks. This class defines a check 114 * method for subclasses, which is invoked only when it finds a property with 115 * the matching name. To define simple property checkers, just subclass this 116 * and override the check() method. 117 */ 118 class property_checker : public checker 119 { 120 /** 121 * The name of the property that this checker is looking for. 122 */ 123 std::string key; 124 public: 125 /** 126 * Implementation of the generic property-checking method that checks 127 * for a property with the name specified in the constructor. 128 */ 129 virtual bool check_property(device_tree *tree, const node_ptr &n, property_ptr p); 130 /** 131 * Constructor. Takes the name of the checker and the name of the 132 * property to check. 133 */ 134 property_checker(const char* name, const std::string &property_name) 135 : checker(name), key(property_name) {} 136 /** 137 * The check method, which subclasses should implement. 138 */ 139 virtual bool check(device_tree *tree, const node_ptr &n, property_ptr p) = 0; 140 }; 141 142 /** 143 * Property type checker. 144 */ 145 template<property_value::value_type T> 146 struct property_type_checker : public property_checker 147 { 148 /** 149 * Constructor, takes the name of the checker and the name of the 150 * property to check as arguments. 151 */ 152 property_type_checker(const char* name, const std::string &property_name) : 153 property_checker(name, property_name) {} 154 virtual bool check(device_tree *tree, const node_ptr &n, property_ptr p) = 0; 155 }; 156 157 /** 158 * Empty property checker. This checks that the property has no value. 159 */ 160 template<> 161 struct property_type_checker <property_value::EMPTY> : public property_checker 162 { 163 property_type_checker(const char* name, const std::string &property_name) : 164 property_checker(name, property_name) {} 165 virtual bool check(device_tree *, const node_ptr &, property_ptr p) 166 { 167 return p->begin() == p->end(); 168 } 169 }; 170 171 /** 172 * String property checker. This checks that the property has exactly one 173 * value, which is a string. 174 */ 175 template<> 176 struct property_type_checker <property_value::STRING> : public property_checker 177 { 178 property_type_checker(const char* name, const std::string &property_name) : 179 property_checker(name, property_name) {} 180 virtual bool check(device_tree *, const node_ptr &, property_ptr p) 181 { 182 return (p->begin() + 1 == p->end()) && p->begin()->is_string(); 183 } 184 }; 185 /** 186 * String list property checker. This checks that the property has at least 187 * one value, all of which are strings. 188 */ 189 template<> 190 struct property_type_checker <property_value::STRING_LIST> : 191 public property_checker 192 { 193 property_type_checker(const char* name, const std::string &property_name) : 194 property_checker(name, property_name) {} 195 virtual bool check(device_tree *, const node_ptr &, property_ptr p) 196 { 197 for (property::value_iterator i=p->begin(),e=p->end() ; i!=e ; 198 ++i) 199 { 200 if (!(i->is_string() || i->is_string_list())) 201 { 202 return false; 203 } 204 } 205 return p->begin() != p->end(); 206 } 207 }; 208 209 /** 210 * Phandle property checker. This checks that the property has exactly one 211 * value, which is a valid phandle. 212 */ 213 template<> 214 struct property_type_checker <property_value::PHANDLE> : public property_checker 215 { 216 property_type_checker(const char* name, const std::string &property_name) : 217 property_checker(name, property_name) {} 218 virtual bool check(device_tree *tree, const node_ptr &, property_ptr p) 219 { 220 return (p->begin() + 1 == p->end()) && 221 (tree->referenced_node(*p->begin()) != 0); 222 } 223 }; 224 225 /** 226 * Check that a property has the correct size. 227 */ 228 struct property_size_checker : public property_checker 229 { 230 /** 231 * The expected size of the property. 232 */ 233 uint32_t size; 234 public: 235 /** 236 * Constructor, takes the name of the checker, the name of the property 237 * to check, and its expected size as arguments. 238 */ 239 property_size_checker(const char* name, 240 const std::string &property_name, 241 uint32_t bytes) 242 : property_checker(name, property_name), size(bytes) {} 243 /** 244 * Check, validates that the property has the correct size. 245 */ 246 virtual bool check(device_tree *tree, const node_ptr &n, property_ptr p); 247 }; 248 249 250 /** 251 * The check manager is the interface to running the checks. This allows 252 * default checks to be enabled, non-default checks to be enabled, and so on. 253 */ 254 class check_manager 255 { 256 /** 257 * The enabled checkers, indexed by their names. The name is used when 258 * disabling checkers from the command line. When this manager runs, 259 * it will only run the checkers from this map. 260 */ 261 std::unordered_map<std::string, checker*> checkers; 262 /** 263 * The disabled checkers. Moving checkers to this list disables them, 264 * but allows them to be easily moved back. 265 */ 266 std::unordered_map<std::string, checker*> disabled_checkers; 267 /** 268 * Helper function for adding a property value checker. 269 */ 270 template<property_value::value_type T> 271 void add_property_type_checker(const char *name, const std::string &prop); 272 /** 273 * Helper function for adding a simple type checker. 274 */ 275 void add_property_type_checker(const char *name, const std::string &prop); 276 /** 277 * Helper function for adding a property value checker. 278 */ 279 void add_property_size_checker(const char *name, 280 const std::string &prop, 281 uint32_t size); 282 public: 283 /** 284 * Delete all of the checkers that are part of this checker manager. 285 */ 286 ~check_manager(); 287 /** 288 * Default constructor, creates check manager containing all of the 289 * default checks. 290 */ 291 check_manager(); 292 /** 293 * Run all of the checks on the specified tree. 294 */ 295 bool run_checks(device_tree *tree, bool keep_going); 296 /** 297 * Disables the named checker. 298 */ 299 bool disable_checker(const std::string &name); 300 /** 301 * Enables the named checker. 302 */ 303 bool enable_checker(const std::string &name); 304 }; 305 306 } // namespace checking 307 308 } // namespace fdt 309 310 } // namespace dtc 311 312 #endif // !_CHECKING_HH_ 313