1 /*- 2 * Copyright (c) 2013 David Chisnall 3 * All rights reserved. 4 * 5 * This software was developed by SRI International and the University of 6 * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237) 7 * ("CTSRD"), as part of the DARPA CRASH research programme. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 * 30 * $FreeBSD$ 31 */ 32 33 #ifndef _CHECKING_HH_ 34 #define _CHECKING_HH_ 35 #include "string.hh" 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, node *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 */ 80 checker(const char *name) : checker_name(name) {} 81 /** 82 * Virtual destructor in case any subclasses need to do cleanup. 83 */ 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 */ 89 virtual bool check_node(device_tree *tree, node *n) 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 */ 97 virtual bool check_property(device_tree *tree, node *n, property *p) 98 { 99 return true; 100 } 101 /** 102 * Runs the checker on the specified device tree. 103 */ 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 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, node *n, property *p); 128 /** 129 * Constructor. Takes the name of the checker and the name of the 130 * property to check. 131 */ 132 property_checker(const char* name, 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, node *n, property *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 */ 150 property_type_checker(const char* name, string property_name) : 151 property_checker(name, property_name) {} 152 virtual bool check(device_tree *tree, node *n, property *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 { 161 property_type_checker(const char* name, string property_name) : 162 property_checker(name, property_name) {} 163 virtual bool check(device_tree *tree, node *n, property *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 { 176 property_type_checker(const char* name, string property_name) : 177 property_checker(name, property_name) {} 178 virtual bool check(device_tree *tree, node *n, property *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 { 191 property_type_checker(const char* name, string property_name) : 192 property_checker(name, property_name) {} 193 virtual bool check(device_tree *tree, node *n, property *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 { 214 property_type_checker(const char* name, string property_name) : 215 property_checker(name, property_name) {} 216 virtual bool check(device_tree *tree, node *n, property *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 */ 237 property_size_checker(const char* name, string property_name, uint32_t bytes) 238 : property_checker(name, property_name), size(bytes) {} 239 /** 240 * Check, validates that the property has the correct size. 241 */ 242 virtual bool check(device_tree *tree, node *n, property *p); 243 }; 244 245 246 /** 247 * The check manager is the interface to running the checks. This allows 248 * default checks to be enabled, non-default checks to be enabled, and so on. 249 */ 250 class check_manager 251 { 252 /** 253 * The enabled checkers, indexed by their names. The name is used when 254 * disabling checkers from the command line. When this manager runs, 255 * it will only run the checkers from this map. 256 */ 257 std::map<string, checker*> checkers; 258 /** 259 * The disabled checkers. Moving checkers to this list disables them, 260 * but allows them to be easily moved back. 261 */ 262 std::map<string, checker*> disabled_checkers; 263 /** 264 * Helper function for adding a property value checker. 265 */ 266 template<property_value::value_type T> 267 void add_property_type_checker(const char *name, string prop); 268 /** 269 * Helper function for adding a simple type checker. 270 */ 271 void add_property_type_checker(const char *name, string prop); 272 /** 273 * Helper function for adding a property value checker. 274 */ 275 void add_property_size_checker(const char *name, 276 string prop, 277 uint32_t size); 278 public: 279 /** 280 * Delete all of the checkers that are part of this checker manager. 281 */ 282 ~check_manager(); 283 /** 284 * Default constructor, creates check manager containing all of the 285 * default checks. 286 */ 287 check_manager(); 288 /** 289 * Run all of the checks on the specified tree. 290 */ 291 bool run_checks(device_tree *tree, bool keep_going); 292 /** 293 * Disables the named checker. 294 */ 295 bool disable_checker(string name); 296 /** 297 * Enables the named checker. 298 */ 299 bool enable_checker(string name); 300 }; 301 302 } // namespace checking 303 304 } // namespace fdt 305 306 } // namespace dtc 307 308 #endif // !_CHECKING_HH_ 309