xref: /freebsd/usr.bin/dtc/checking.hh (revision fed1ca4b719c56c930f2259d80663cd34be812bb)
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, 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 	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, 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, 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, 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, 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, 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, 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, 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, const node_ptr &n, property_ptr 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::unordered_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::unordered_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