1245803Stheraven/*-
2245803Stheraven * Copyright (c) 2013 David Chisnall
3245803Stheraven * All rights reserved.
4245803Stheraven *
5245803Stheraven * This software was developed by SRI International and the University of
6245803Stheraven * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
7245803Stheraven * ("CTSRD"), as part of the DARPA CRASH research programme.
8245803Stheraven *
9245803Stheraven * Redistribution and use in source and binary forms, with or without
10245803Stheraven * modification, are permitted provided that the following conditions
11245803Stheraven * are met:
12245803Stheraven * 1. Redistributions of source code must retain the above copyright
13245803Stheraven *    notice, this list of conditions and the following disclaimer.
14245803Stheraven * 2. Redistributions in binary form must reproduce the above copyright
15245803Stheraven *    notice, this list of conditions and the following disclaimer in the
16245803Stheraven *    documentation and/or other materials provided with the distribution.
17245803Stheraven *
18245803Stheraven * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19245803Stheraven * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20245803Stheraven * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21245803Stheraven * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22245803Stheraven * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23245803Stheraven * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24245803Stheraven * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25245803Stheraven * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26245803Stheraven * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27245803Stheraven * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28245803Stheraven * SUCH DAMAGE.
29245803Stheraven *
30245803Stheraven * $FreeBSD$
31245803Stheraven */
32245803Stheraven
33245803Stheraven#ifndef _CHECKING_HH_
34245803Stheraven#define _CHECKING_HH_
35245803Stheraven#include "string.hh"
36245803Stheraven#include "fdt.hh"
37245803Stheraven
38245803Stheravennamespace dtc
39245803Stheraven{
40245803Stheravennamespace fdt
41245803Stheraven{
42245803Stheravennamespace checking
43245803Stheraven{
44245803Stheraven/**
45245803Stheraven * Base class for all checkers.  This will visit the entire tree and perform
46245803Stheraven * semantic checks defined in subclasses.  Note that device trees are generally
47245803Stheraven * small (a few dozen nodes at most) and so we optimise for flexibility and
48245803Stheraven * extensibility here, not for performance.  Each checker will visit the entire
49245803Stheraven * tree.
50245803Stheraven */
51245803Stheravenclass checker
52245803Stheraven{
53245803Stheraven	/**
54245803Stheraven	 * The path to the current node being checked.  This is used for
55245803Stheraven	 * printing error messages.
56245803Stheraven	 */
57245803Stheraven	device_tree::node_path path;
58245803Stheraven	/**
59245803Stheraven	 * The name of the checker.  This is used for printing error messages
60245803Stheraven	 * and for enabling / disabling specific checkers from the command
61245803Stheraven	 * line.
62245803Stheraven	 */
63245803Stheraven	const char *checker_name;
64245803Stheraven	/**
65245803Stheraven	 * Visits each node, calling the checker functions on properties and
66245803Stheraven	 * nodes.
67245803Stheraven	 */
68245803Stheraven	bool visit_node(device_tree *tree, node *n);
69245803Stheraven	protected:
70245803Stheraven	/**
71245803Stheraven	 * Prints the error message, along with the path to the node that
72245803Stheraven	 * caused the error and the name of the checker.
73245803Stheraven	 */
74245803Stheraven	void report_error(const char *errmsg);
75245803Stheraven	public:
76245803Stheraven	/**
77245803Stheraven	 * Constructor.  Takes the name of this checker, which is which is used
78245803Stheraven	 * when reporting errors.
79245803Stheraven	 */
80245803Stheraven	checker(const char *name) : checker_name(name) {}
81245803Stheraven	/**
82245803Stheraven	 * Virtual destructor in case any subclasses need to do cleanup.
83245803Stheraven	 */
84245803Stheraven	virtual ~checker() {}
85245803Stheraven	/**
86245803Stheraven	 * Method for checking that a node is valid.  The root class version
87245803Stheraven	 * does nothing, subclasses should override this.
88245803Stheraven	 */
89245803Stheraven	virtual bool check_node(device_tree *tree, node *n)
90245803Stheraven	{
91245803Stheraven		return true;
92245803Stheraven	}
93245803Stheraven	/**
94245803Stheraven	 * Method for checking that a property is valid.  The root class
95245803Stheraven	 * version does nothing, subclasses should override this.
96245803Stheraven	 */
97245803Stheraven	virtual bool check_property(device_tree *tree, node *n, property *p)
98245803Stheraven	{
99245803Stheraven		return true;
100245803Stheraven	}
101245803Stheraven	/**
102245803Stheraven	 * Runs the checker on the specified device tree.
103245803Stheraven	 */
104245803Stheraven	bool check_tree(fdt::device_tree *tree)
105245803Stheraven	{
106245803Stheraven		return visit_node(tree, tree->get_root());
107245803Stheraven	}
108245803Stheraven};
109245803Stheraven
110245803Stheraven/**
111245803Stheraven * Abstract base class for simple property checks.  This class defines a check
112245803Stheraven * method for subclasses, which is invoked only when it finds a property with
113245803Stheraven * the matching name.  To define simple property checkers, just subclass this
114245803Stheraven * and override the check() method.
115245803Stheraven */
116245803Stheravenclass property_checker : public checker
117245803Stheraven{
118245803Stheraven	/**
119245803Stheraven	 * The name of the property that this checker is looking for.
120245803Stheraven	 */
121245803Stheraven	string key;
122245803Stheraven	public:
123245803Stheraven	/**
124245803Stheraven	 * Implementation of the generic property-checking method that checks
125245803Stheraven	 * for a property with the name specified in the constructor
126245803Stheraven	 */
127245803Stheraven	virtual bool check_property(device_tree *tree, node *n, property *p);
128245803Stheraven	/**
129245803Stheraven	 * Constructor.  Takes the name of the checker and the name of the
130245803Stheraven	 * property to check.
131245803Stheraven	 */
132245803Stheraven	property_checker(const char* name, string property_name)
133245803Stheraven		: checker(name), key(property_name) {}
134245803Stheraven	/**
135245803Stheraven	 * The check method, which subclasses should implement.
136245803Stheraven	 */
137245803Stheraven	virtual bool check(device_tree *tree, node *n, property *p) = 0;
138245803Stheraven};
139245803Stheraven
140245803Stheraven/**
141245803Stheraven * Property type checker.
142245803Stheraven */
143245803Stheraventemplate<property_value::value_type T>
144245803Stheravenstruct property_type_checker : public property_checker
145245803Stheraven{
146245803Stheraven	/**
147245803Stheraven	 * Constructor, takes the name of the checker and the name of the
148245803Stheraven	 * property to check as arguments.
149245803Stheraven	 */
150245803Stheraven	property_type_checker(const char* name, string property_name) :
151245803Stheraven		property_checker(name, property_name) {}
152245803Stheraven	virtual bool check(device_tree *tree, node *n, property *p) = 0;
153245803Stheraven};
154245803Stheraven
155245803Stheraven/**
156245803Stheraven * Empty property checker.  This checks that the property has no value.
157245803Stheraven */
158245803Stheraventemplate<>
159245803Stheravenstruct property_type_checker <property_value::EMPTY> : public property_checker
160245803Stheraven{
161245803Stheraven	property_type_checker(const char* name, string property_name) :
162245803Stheraven		property_checker(name, property_name) {}
163245803Stheraven	virtual bool check(device_tree *tree, node *n, property *p)
164245803Stheraven	{
165245803Stheraven		return p->begin() == p->end();
166245803Stheraven	}
167245803Stheraven};
168245803Stheraven
169245803Stheraven/**
170245803Stheraven * String property checker.  This checks that the property has exactly one
171245803Stheraven * value, which is a string.
172245803Stheraven */
173245803Stheraventemplate<>
174245803Stheravenstruct property_type_checker <property_value::STRING> : public property_checker
175245803Stheraven{
176245803Stheraven	property_type_checker(const char* name, string property_name) :
177245803Stheraven		property_checker(name, property_name) {}
178245803Stheraven	virtual bool check(device_tree *tree, node *n, property *p)
179245803Stheraven	{
180245803Stheraven		return (p->begin() + 1 == p->end()) && p->begin()->is_string();
181245803Stheraven	}
182245803Stheraven};
183245803Stheraven/**
184245803Stheraven * String list property checker.  This checks that the property has at least
185245803Stheraven * one value, all of which are strings.
186245803Stheraven */
187245803Stheraventemplate<>
188245803Stheravenstruct property_type_checker <property_value::STRING_LIST> :
189245803Stheraven	public property_checker
190245803Stheraven{
191245803Stheraven	property_type_checker(const char* name, string property_name) :
192245803Stheraven		property_checker(name, property_name) {}
193245803Stheraven	virtual bool check(device_tree *tree, node *n, property *p)
194245803Stheraven	{
195245803Stheraven		for (property::value_iterator i=p->begin(),e=p->end() ; i!=e ;
196245803Stheraven		     ++i)
197245803Stheraven		{
198245803Stheraven			if (!(i->is_string() || i->is_string_list()))
199245803Stheraven			{
200245803Stheraven				return false;
201245803Stheraven			}
202245803Stheraven		}
203245803Stheraven		return p->begin() != p->end();
204245803Stheraven	}
205245803Stheraven};
206245803Stheraven
207245803Stheraven/**
208245803Stheraven * Phandle property checker.  This checks that the property has exactly one
209245803Stheraven * value, which is a valid phandle.
210245803Stheraven */
211245803Stheraventemplate<>
212245803Stheravenstruct property_type_checker <property_value::PHANDLE> : public property_checker
213245803Stheraven{
214245803Stheraven	property_type_checker(const char* name, string property_name) :
215245803Stheraven		property_checker(name, property_name) {}
216245803Stheraven	virtual bool check(device_tree *tree, node *n, property *p)
217245803Stheraven	{
218245803Stheraven		return (p->begin() + 1 == p->end()) &&
219245803Stheraven			(tree->referenced_node(*p->begin()) != 0);
220245803Stheraven	}
221245803Stheraven};
222245803Stheraven
223245803Stheraven/**
224245803Stheraven * Check that a property has the correct size.
225245803Stheraven */
226245803Stheravenstruct property_size_checker : public property_checker
227245803Stheraven{
228245803Stheraven	/**
229245803Stheraven	 * The expected size of the property.
230245803Stheraven	 */
231245803Stheraven	uint32_t size;
232245803Stheraven	public:
233245803Stheraven	/**
234245803Stheraven	 * Constructor, takes the name of the checker, the name of the property
235245803Stheraven	 * to check, and its expected size as arguments.
236245803Stheraven	 */
237245803Stheraven	property_size_checker(const char* name, string property_name, uint32_t bytes)
238245803Stheraven		: property_checker(name, property_name), size(bytes) {}
239245803Stheraven	/**
240245803Stheraven	 * Check, validates that the property has the correct size.
241245803Stheraven	 */
242245803Stheraven	virtual bool check(device_tree *tree, node *n, property *p);
243245803Stheraven};
244245803Stheraven
245245803Stheraven
246245803Stheraven/**
247245803Stheraven * The check manager is the interface to running the checks.  This allows
248245803Stheraven * default checks to be enabled, non-default checks to be enabled, and so on.
249245803Stheraven */
250245803Stheravenclass check_manager
251245803Stheraven{
252245803Stheraven	/**
253245803Stheraven	 * The enabled checkers, indexed by their names.  The name is used when
254245803Stheraven	 * disabling checkers from the command line.  When this manager runs,
255245803Stheraven	 * it will only run the checkers from this map.
256245803Stheraven	 */
257245803Stheraven	std::map<string, checker*> checkers;
258245803Stheraven	/**
259245803Stheraven	 * The disabled checkers.  Moving checkers to this list disables them,
260245803Stheraven	 * but allows them to be easily moved back.
261245803Stheraven	 */
262245803Stheraven	std::map<string, checker*> disabled_checkers;
263245803Stheraven	/**
264245803Stheraven	 * Helper function for adding a property value checker.
265245803Stheraven	 */
266245803Stheraven	template<property_value::value_type T>
267245803Stheraven	void add_property_type_checker(const char *name, string prop);
268245803Stheraven	/**
269245803Stheraven	 * Helper function for adding a simple type checker.
270245803Stheraven	 */
271245803Stheraven	void add_property_type_checker(const char *name, string prop);
272245803Stheraven	/**
273245803Stheraven	 * Helper function for adding a property value checker.
274245803Stheraven	 */
275245803Stheraven	void add_property_size_checker(const char *name,
276245803Stheraven	                               string prop,
277245803Stheraven	                               uint32_t size);
278245803Stheraven	public:
279245803Stheraven	/**
280245803Stheraven	 * Delete all of the checkers that are part of this checker manager.
281245803Stheraven	 */
282245803Stheraven	~check_manager();
283245803Stheraven	/**
284245803Stheraven	 * Default constructor, creates check manager containing all of the
285245803Stheraven	 * default checks.
286245803Stheraven	 */
287245803Stheraven	check_manager();
288245803Stheraven	/**
289245803Stheraven	 * Run all of the checks on the specified tree.
290245803Stheraven	 */
291245803Stheraven	bool run_checks(device_tree *tree, bool keep_going);
292245803Stheraven	/**
293245803Stheraven	 * Disables the named checker.
294245803Stheraven	 */
295245803Stheraven	bool disable_checker(string name);
296245803Stheraven	/**
297245803Stheraven	 * Enables the named checker.
298245803Stheraven	 */
299245803Stheraven	bool enable_checker(string name);
300245803Stheraven};
301245803Stheraven
302245803Stheraven} // namespace checking
303245803Stheraven
304245803Stheraven} // namespace fdt
305245803Stheraven
306245803Stheraven} // namespace dtc
307245803Stheraven
308245803Stheraven#endif // !_CHECKING_HH_
309