xref: /freebsd/usr.bin/dtc/checking.hh (revision 7fdf597e96a02165cfe22ff357b857d5fa15ed8a)
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 	 */
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 *, 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 	 */
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 	 */
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 	 */
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 	 */
150 	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 {
161 	property_type_checker(const char* name, const std::string &property_name) :
162 		property_checker(name, property_name) {}
163 	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 {
176 	property_type_checker(const char* name, const std::string &property_name) :
177 		property_checker(name, property_name) {}
178 	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 {
191 	property_type_checker(const char* name, const std::string &property_name) :
192 		property_checker(name, property_name) {}
193 	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 {
214 	property_type_checker(const char* name, const std::string &property_name) :
215 		property_checker(name, property_name) {}
216 	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 	 */
237 	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