checking.hh revision 259065
1207753Smm/*-
2207753Smm * Copyright (c) 2013 David Chisnall
3207753Smm * All rights reserved.
4207753Smm *
5207753Smm * This software was developed by SRI International and the University of
6207753Smm * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
7207753Smm * ("CTSRD"), as part of the DARPA CRASH research programme.
8207753Smm *
9263285Sdelphij * Redistribution and use in source and binary forms, with or without
10207753Smm * modification, are permitted provided that the following conditions
11207753Smm * are met:
12207753Smm * 1. Redistributions of source code must retain the above copyright
13207753Smm *    notice, this list of conditions and the following disclaimer.
14223935Smm * 2. Redistributions in binary form must reproduce the above copyright
15223935Smm *    notice, this list of conditions and the following disclaimer in the
16223935Smm *    documentation and/or other materials provided with the distribution.
17207753Smm *
18244601Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19207753Smm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20213700Smm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21213700Smm * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22207753Smm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23274261Sdelphij * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24292588Sdelphij * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25244601Smm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26207753Smm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27207753Smm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28207753Smm * SUCH DAMAGE.
29207753Smm *
30207753Smm * $FreeBSD: releng/10.0/usr.bin/dtc/checking.hh 245803 2013-01-22 17:49:51Z theraven $
31213700Smm */
32244601Smm
33292588Sdelphij#ifndef _CHECKING_HH_
34207753Smm#define _CHECKING_HH_
35292588Sdelphij#include "string.hh"
36292588Sdelphij#include "fdt.hh"
37223935Smm
38219001Smmnamespace dtc
39292588Sdelphij{
40207753Smmnamespace fdt
41292588Sdelphij{
42292588Sdelphijnamespace checking
43207753Smm{
44207753Smm/**
45292588Sdelphij * Base class for all checkers.  This will visit the entire tree and perform
46207753Smm * semantic checks defined in subclasses.  Note that device trees are generally
47207753Smm * small (a few dozen nodes at most) and so we optimise for flexibility and
48207753Smm * extensibility here, not for performance.  Each checker will visit the entire
49207753Smm * tree.
50292588Sdelphij */
51292588Sdelphijclass checker
52207753Smm{
53207753Smm	/**
54292588Sdelphij	 * The path to the current node being checked.  This is used for
55207753Smm	 * printing error messages.
56207753Smm	 */
57244601Smm	device_tree::node_path path;
58223935Smm	/**
59213700Smm	 * The name of the checker.  This is used for printing error messages
60244601Smm	 * and for enabling / disabling specific checkers from the command
61223935Smm	 * line.
62207753Smm	 */
63292588Sdelphij	const char *checker_name;
64263285Sdelphij	/**
65207753Smm	 * Visits each node, calling the checker functions on properties and
66207753Smm	 * nodes.
67312518Sdelphij	 */
68207753Smm	bool visit_node(device_tree *tree, node *n);
69207753Smm	protected:
70213700Smm	/**
71213700Smm	 * Prints the error message, along with the path to the node that
72244601Smm	 * caused the error and the name of the checker.
73292588Sdelphij	 */
74207753Smm	void report_error(const char *errmsg);
75223935Smm	public:
76207753Smm	/**
77207753Smm	 * Constructor.  Takes the name of this checker, which is which is used
78312518Sdelphij	 * when reporting errors.
79292588Sdelphij	 */
80263285Sdelphij	checker(const char *name) : checker_name(name) {}
81292588Sdelphij	/**
82207753Smm	 * Virtual destructor in case any subclasses need to do cleanup.
83207753Smm	 */
84263285Sdelphij	virtual ~checker() {}
85219001Smm	/**
86207753Smm	 * Method for checking that a node is valid.  The root class version
87292588Sdelphij	 * does nothing, subclasses should override this.
88207753Smm	 */
89207753Smm	virtual bool check_node(device_tree *tree, node *n)
90244601Smm	{
91207753Smm		return true;
92207753Smm	}
93207753Smm	/**
94312518Sdelphij	 * Method for checking that a property is valid.  The root class
95292588Sdelphij	 * version does nothing, subclasses should override this.
96207753Smm	 */
97223935Smm	virtual bool check_property(device_tree *tree, node *n, property *p)
98292588Sdelphij	{
99207753Smm		return true;
100207753Smm	}
101207753Smm	/**
102207753Smm	 * Runs the checker on the specified device tree.
103223935Smm	 */
104292588Sdelphij	bool check_tree(fdt::device_tree *tree)
105207753Smm	{
106207753Smm		return visit_node(tree, tree->get_root());
107292588Sdelphij	}
108312518Sdelphij};
109207753Smm
110207753Smm/**
111207753Smm * Abstract base class for simple property checks.  This class defines a check
112207753Smm * method for subclasses, which is invoked only when it finds a property with
113207753Smm * the matching name.  To define simple property checkers, just subclass this
114207753Smm * and override the check() method.
115207753Smm */
116207753Smmclass property_checker : public checker
117207753Smm{
118207753Smm	/**
119207753Smm	 * The name of the property that this checker is looking for.
120207753Smm	 */
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 */
143template<property_value::value_type T>
144struct 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 */
158template<>
159struct 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 */
173template<>
174struct 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 */
187template<>
188struct 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 */
211template<>
212struct 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 */
226struct 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 */
250class 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