checking.hh revision 330449
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: stable/11/usr.bin/dtc/checking.hh 330449 2018-03-05 07:26:05Z eadler $
33 */
34
35#ifndef _CHECKING_HH_
36#define _CHECKING_HH_
37#include <string>
38#include "fdt.hh"
39
40namespace dtc
41{
42namespace fdt
43{
44namespace 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 */
53class 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 */
118class 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 */
145template<property_value::value_type T>
146struct 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 */
160template<>
161struct 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 */
175template<>
176struct 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 */
189template<>
190struct 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 */
213template<>
214struct 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 */
228struct 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 */
254class 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