xref: /freebsd/usr.bin/dtc/checking.hh (revision 4f52dfbb)
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