xref: /freebsd/usr.bin/dtc/checking.hh (revision b3e7694832e81d7a904a10f525f8797b753bf0d3)
1af0dd31fSDavid Chisnall /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
31de7b4b8SPedro F. Giffuni  *
4af0dd31fSDavid Chisnall  * Copyright (c) 2013 David Chisnall
5af0dd31fSDavid Chisnall  * All rights reserved.
6af0dd31fSDavid Chisnall  *
7af0dd31fSDavid Chisnall  * This software was developed by SRI International and the University of
8af0dd31fSDavid Chisnall  * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
9af0dd31fSDavid Chisnall  * ("CTSRD"), as part of the DARPA CRASH research programme.
10af0dd31fSDavid Chisnall  *
11af0dd31fSDavid Chisnall  * Redistribution and use in source and binary forms, with or without
12af0dd31fSDavid Chisnall  * modification, are permitted provided that the following conditions
13af0dd31fSDavid Chisnall  * are met:
14af0dd31fSDavid Chisnall  * 1. Redistributions of source code must retain the above copyright
15af0dd31fSDavid Chisnall  *    notice, this list of conditions and the following disclaimer.
16af0dd31fSDavid Chisnall  * 2. Redistributions in binary form must reproduce the above copyright
17af0dd31fSDavid Chisnall  *    notice, this list of conditions and the following disclaimer in the
18af0dd31fSDavid Chisnall  *    documentation and/or other materials provided with the distribution.
19af0dd31fSDavid Chisnall  *
20af0dd31fSDavid Chisnall  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21af0dd31fSDavid Chisnall  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22af0dd31fSDavid Chisnall  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23af0dd31fSDavid Chisnall  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24af0dd31fSDavid Chisnall  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25af0dd31fSDavid Chisnall  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26af0dd31fSDavid Chisnall  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27af0dd31fSDavid Chisnall  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28af0dd31fSDavid Chisnall  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29af0dd31fSDavid Chisnall  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30af0dd31fSDavid Chisnall  * SUCH DAMAGE.
31af0dd31fSDavid Chisnall  */
32af0dd31fSDavid Chisnall 
33af0dd31fSDavid Chisnall #ifndef _CHECKING_HH_
34af0dd31fSDavid Chisnall #define _CHECKING_HH_
35bbe31b70SEd Maste #include <string>
36af0dd31fSDavid Chisnall #include "fdt.hh"
37af0dd31fSDavid Chisnall 
38af0dd31fSDavid Chisnall namespace dtc
39af0dd31fSDavid Chisnall {
40af0dd31fSDavid Chisnall namespace fdt
41af0dd31fSDavid Chisnall {
42af0dd31fSDavid Chisnall namespace checking
43af0dd31fSDavid Chisnall {
44af0dd31fSDavid Chisnall /**
45af0dd31fSDavid Chisnall  * Base class for all checkers.  This will visit the entire tree and perform
46af0dd31fSDavid Chisnall  * semantic checks defined in subclasses.  Note that device trees are generally
47af0dd31fSDavid Chisnall  * small (a few dozen nodes at most) and so we optimise for flexibility and
48af0dd31fSDavid Chisnall  * extensibility here, not for performance.  Each checker will visit the entire
49af0dd31fSDavid Chisnall  * tree.
50af0dd31fSDavid Chisnall  */
51af0dd31fSDavid Chisnall class checker
52af0dd31fSDavid Chisnall {
53af0dd31fSDavid Chisnall 	/**
54af0dd31fSDavid Chisnall 	 * The path to the current node being checked.  This is used for
55af0dd31fSDavid Chisnall 	 * printing error messages.
56af0dd31fSDavid Chisnall 	 */
57af0dd31fSDavid Chisnall 	device_tree::node_path path;
58af0dd31fSDavid Chisnall 	/**
59af0dd31fSDavid Chisnall 	 * The name of the checker.  This is used for printing error messages
60af0dd31fSDavid Chisnall 	 * and for enabling / disabling specific checkers from the command
61af0dd31fSDavid Chisnall 	 * line.
62af0dd31fSDavid Chisnall 	 */
63af0dd31fSDavid Chisnall 	const char *checker_name;
64af0dd31fSDavid Chisnall 	/**
65af0dd31fSDavid Chisnall 	 * Visits each node, calling the checker functions on properties and
66af0dd31fSDavid Chisnall 	 * nodes.
67af0dd31fSDavid Chisnall 	 */
68a0706eb4SDavid Chisnall 	bool visit_node(device_tree *tree, const node_ptr &n);
69af0dd31fSDavid Chisnall 	protected:
70af0dd31fSDavid Chisnall 	/**
71af0dd31fSDavid Chisnall 	 * Prints the error message, along with the path to the node that
72af0dd31fSDavid Chisnall 	 * caused the error and the name of the checker.
73af0dd31fSDavid Chisnall 	 */
74af0dd31fSDavid Chisnall 	void report_error(const char *errmsg);
75af0dd31fSDavid Chisnall 	public:
76af0dd31fSDavid Chisnall 	/**
77af0dd31fSDavid Chisnall 	 * Constructor.  Takes the name of this checker, which is which is used
78af0dd31fSDavid Chisnall 	 * when reporting errors.
79af0dd31fSDavid Chisnall 	 */
checker(const char * name)80af0dd31fSDavid Chisnall 	checker(const char *name) : checker_name(name) {}
81af0dd31fSDavid Chisnall 	/**
82af0dd31fSDavid Chisnall 	 * Virtual destructor in case any subclasses need to do cleanup.
83af0dd31fSDavid Chisnall 	 */
~checker()84af0dd31fSDavid Chisnall 	virtual ~checker() {}
85af0dd31fSDavid Chisnall 	/**
86af0dd31fSDavid Chisnall 	 * Method for checking that a node is valid.  The root class version
87af0dd31fSDavid Chisnall 	 * does nothing, subclasses should override this.
88af0dd31fSDavid Chisnall 	 */
check_node(device_tree *,const node_ptr &)89c64a3eafSDavid Chisnall 	virtual bool check_node(device_tree *, const node_ptr &)
90af0dd31fSDavid Chisnall 	{
91af0dd31fSDavid Chisnall 		return true;
92af0dd31fSDavid Chisnall 	}
93af0dd31fSDavid Chisnall 	/**
94af0dd31fSDavid Chisnall 	 * Method for checking that a property is valid.  The root class
95af0dd31fSDavid Chisnall 	 * version does nothing, subclasses should override this.
96af0dd31fSDavid Chisnall 	 */
check_property(device_tree *,const node_ptr &,property_ptr)97c64a3eafSDavid Chisnall 	virtual bool check_property(device_tree *, const node_ptr &, property_ptr )
98af0dd31fSDavid Chisnall 	{
99af0dd31fSDavid Chisnall 		return true;
100af0dd31fSDavid Chisnall 	}
101af0dd31fSDavid Chisnall 	/**
102af0dd31fSDavid Chisnall 	 * Runs the checker on the specified device tree.
103af0dd31fSDavid Chisnall 	 */
check_tree(fdt::device_tree * tree)104af0dd31fSDavid Chisnall 	bool check_tree(fdt::device_tree *tree)
105af0dd31fSDavid Chisnall 	{
106af0dd31fSDavid Chisnall 		return visit_node(tree, tree->get_root());
107af0dd31fSDavid Chisnall 	}
108af0dd31fSDavid Chisnall };
109af0dd31fSDavid Chisnall 
110af0dd31fSDavid Chisnall /**
111af0dd31fSDavid Chisnall  * Abstract base class for simple property checks.  This class defines a check
112af0dd31fSDavid Chisnall  * method for subclasses, which is invoked only when it finds a property with
113af0dd31fSDavid Chisnall  * the matching name.  To define simple property checkers, just subclass this
114af0dd31fSDavid Chisnall  * and override the check() method.
115af0dd31fSDavid Chisnall  */
116af0dd31fSDavid Chisnall class property_checker : public checker
117af0dd31fSDavid Chisnall {
118af0dd31fSDavid Chisnall 	/**
119af0dd31fSDavid Chisnall 	 * The name of the property that this checker is looking for.
120af0dd31fSDavid Chisnall 	 */
121bbe31b70SEd Maste 	std::string key;
122af0dd31fSDavid Chisnall 	public:
123af0dd31fSDavid Chisnall 	/**
124af0dd31fSDavid Chisnall 	 * Implementation of the generic property-checking method that checks
125bbe31b70SEd Maste 	 * for a property with the name specified in the constructor.
126af0dd31fSDavid Chisnall 	 */
127a0706eb4SDavid Chisnall 	virtual bool check_property(device_tree *tree, const node_ptr &n, property_ptr p);
128af0dd31fSDavid Chisnall 	/**
129af0dd31fSDavid Chisnall 	 * Constructor.  Takes the name of the checker and the name of the
130af0dd31fSDavid Chisnall 	 * property to check.
131af0dd31fSDavid Chisnall 	 */
property_checker(const char * name,const std::string & property_name)132bbe31b70SEd Maste 	property_checker(const char* name, const std::string &property_name)
133af0dd31fSDavid Chisnall 		: checker(name), key(property_name) {}
134af0dd31fSDavid Chisnall 	/**
135af0dd31fSDavid Chisnall 	 * The check method, which subclasses should implement.
136af0dd31fSDavid Chisnall 	 */
137a0706eb4SDavid Chisnall 	virtual bool check(device_tree *tree, const node_ptr &n, property_ptr p) = 0;
138af0dd31fSDavid Chisnall };
139af0dd31fSDavid Chisnall 
140af0dd31fSDavid Chisnall /**
141af0dd31fSDavid Chisnall  * Property type checker.
142af0dd31fSDavid Chisnall  */
143af0dd31fSDavid Chisnall template<property_value::value_type T>
144af0dd31fSDavid Chisnall struct property_type_checker : public property_checker
145af0dd31fSDavid Chisnall {
146af0dd31fSDavid Chisnall 	/**
147af0dd31fSDavid Chisnall 	 * Constructor, takes the name of the checker and the name of the
148af0dd31fSDavid Chisnall 	 * property to check as arguments.
149af0dd31fSDavid Chisnall 	 */
property_type_checkerdtc::fdt::checking::property_type_checker150bbe31b70SEd Maste 	property_type_checker(const char* name, const std::string &property_name) :
151af0dd31fSDavid Chisnall 		property_checker(name, property_name) {}
152a0706eb4SDavid Chisnall 	virtual bool check(device_tree *tree, const node_ptr &n, property_ptr p) = 0;
153af0dd31fSDavid Chisnall };
154af0dd31fSDavid Chisnall 
155af0dd31fSDavid Chisnall /**
156af0dd31fSDavid Chisnall  * Empty property checker.  This checks that the property has no value.
157af0dd31fSDavid Chisnall  */
158af0dd31fSDavid Chisnall template<>
159af0dd31fSDavid Chisnall struct property_type_checker <property_value::EMPTY> : public property_checker
160af0dd31fSDavid Chisnall {
property_type_checkerdtc::fdt::checking::property_type_checker161bbe31b70SEd Maste 	property_type_checker(const char* name, const std::string &property_name) :
162af0dd31fSDavid Chisnall 		property_checker(name, property_name) {}
checkdtc::fdt::checking::property_type_checker163c64a3eafSDavid Chisnall 	virtual bool check(device_tree *, const node_ptr &, property_ptr p)
164af0dd31fSDavid Chisnall 	{
165af0dd31fSDavid Chisnall 		return p->begin() == p->end();
166af0dd31fSDavid Chisnall 	}
167af0dd31fSDavid Chisnall };
168af0dd31fSDavid Chisnall 
169af0dd31fSDavid Chisnall /**
170af0dd31fSDavid Chisnall  * String property checker.  This checks that the property has exactly one
171af0dd31fSDavid Chisnall  * value, which is a string.
172af0dd31fSDavid Chisnall  */
173af0dd31fSDavid Chisnall template<>
174af0dd31fSDavid Chisnall struct property_type_checker <property_value::STRING> : public property_checker
175af0dd31fSDavid Chisnall {
property_type_checkerdtc::fdt::checking::property_type_checker176bbe31b70SEd Maste 	property_type_checker(const char* name, const std::string &property_name) :
177af0dd31fSDavid Chisnall 		property_checker(name, property_name) {}
checkdtc::fdt::checking::property_type_checker178c64a3eafSDavid Chisnall 	virtual bool check(device_tree *, const node_ptr &, property_ptr p)
179af0dd31fSDavid Chisnall 	{
180af0dd31fSDavid Chisnall 		return (p->begin() + 1 == p->end()) && p->begin()->is_string();
181af0dd31fSDavid Chisnall 	}
182af0dd31fSDavid Chisnall };
183af0dd31fSDavid Chisnall /**
184af0dd31fSDavid Chisnall  * String list property checker.  This checks that the property has at least
185af0dd31fSDavid Chisnall  * one value, all of which are strings.
186af0dd31fSDavid Chisnall  */
187af0dd31fSDavid Chisnall template<>
188af0dd31fSDavid Chisnall struct property_type_checker <property_value::STRING_LIST> :
189af0dd31fSDavid Chisnall 	public property_checker
190af0dd31fSDavid Chisnall {
property_type_checkerdtc::fdt::checking::property_type_checker191bbe31b70SEd Maste 	property_type_checker(const char* name, const std::string &property_name) :
192af0dd31fSDavid Chisnall 		property_checker(name, property_name) {}
checkdtc::fdt::checking::property_type_checker193c64a3eafSDavid Chisnall 	virtual bool check(device_tree *, const node_ptr &, property_ptr p)
194af0dd31fSDavid Chisnall 	{
195af0dd31fSDavid Chisnall 		for (property::value_iterator i=p->begin(),e=p->end() ; i!=e ;
196af0dd31fSDavid Chisnall 		     ++i)
197af0dd31fSDavid Chisnall 		{
198af0dd31fSDavid Chisnall 			if (!(i->is_string() || i->is_string_list()))
199af0dd31fSDavid Chisnall 			{
200af0dd31fSDavid Chisnall 				return false;
201af0dd31fSDavid Chisnall 			}
202af0dd31fSDavid Chisnall 		}
203af0dd31fSDavid Chisnall 		return p->begin() != p->end();
204af0dd31fSDavid Chisnall 	}
205af0dd31fSDavid Chisnall };
206af0dd31fSDavid Chisnall 
207af0dd31fSDavid Chisnall /**
208af0dd31fSDavid Chisnall  * Phandle property checker.  This checks that the property has exactly one
209af0dd31fSDavid Chisnall  * value, which is a valid phandle.
210af0dd31fSDavid Chisnall  */
211af0dd31fSDavid Chisnall template<>
212af0dd31fSDavid Chisnall struct property_type_checker <property_value::PHANDLE> : public property_checker
213af0dd31fSDavid Chisnall {
property_type_checkerdtc::fdt::checking::property_type_checker214bbe31b70SEd Maste 	property_type_checker(const char* name, const std::string &property_name) :
215af0dd31fSDavid Chisnall 		property_checker(name, property_name) {}
checkdtc::fdt::checking::property_type_checker216c64a3eafSDavid Chisnall 	virtual bool check(device_tree *tree, const node_ptr &, property_ptr p)
217af0dd31fSDavid Chisnall 	{
218af0dd31fSDavid Chisnall 		return (p->begin() + 1 == p->end()) &&
219af0dd31fSDavid Chisnall 			(tree->referenced_node(*p->begin()) != 0);
220af0dd31fSDavid Chisnall 	}
221af0dd31fSDavid Chisnall };
222af0dd31fSDavid Chisnall 
223af0dd31fSDavid Chisnall /**
224af0dd31fSDavid Chisnall  * Check that a property has the correct size.
225af0dd31fSDavid Chisnall  */
226af0dd31fSDavid Chisnall struct property_size_checker : public property_checker
227af0dd31fSDavid Chisnall {
228af0dd31fSDavid Chisnall 	/**
229af0dd31fSDavid Chisnall 	 * The expected size of the property.
230af0dd31fSDavid Chisnall 	 */
231af0dd31fSDavid Chisnall 	uint32_t size;
232af0dd31fSDavid Chisnall 	public:
233af0dd31fSDavid Chisnall 	/**
234af0dd31fSDavid Chisnall 	 * Constructor, takes the name of the checker, the name of the property
235af0dd31fSDavid Chisnall 	 * to check, and its expected size as arguments.
236af0dd31fSDavid Chisnall 	 */
property_size_checkerdtc::fdt::checking::property_size_checker237bbe31b70SEd Maste 	property_size_checker(const char* name,
238bbe31b70SEd Maste 	                      const std::string &property_name,
239bbe31b70SEd Maste 	                      uint32_t bytes)
240af0dd31fSDavid Chisnall 		: property_checker(name, property_name), size(bytes) {}
241af0dd31fSDavid Chisnall 	/**
242af0dd31fSDavid Chisnall 	 * Check, validates that the property has the correct size.
243af0dd31fSDavid Chisnall 	 */
244a0706eb4SDavid Chisnall 	virtual bool check(device_tree *tree, const node_ptr &n, property_ptr p);
245af0dd31fSDavid Chisnall };
246af0dd31fSDavid Chisnall 
247af0dd31fSDavid Chisnall 
248af0dd31fSDavid Chisnall /**
249af0dd31fSDavid Chisnall  * The check manager is the interface to running the checks.  This allows
250af0dd31fSDavid Chisnall  * default checks to be enabled, non-default checks to be enabled, and so on.
251af0dd31fSDavid Chisnall  */
252af0dd31fSDavid Chisnall class check_manager
253af0dd31fSDavid Chisnall {
254af0dd31fSDavid Chisnall 	/**
255af0dd31fSDavid Chisnall 	 * The enabled checkers, indexed by their names.  The name is used when
256af0dd31fSDavid Chisnall 	 * disabling checkers from the command line.  When this manager runs,
257af0dd31fSDavid Chisnall 	 * it will only run the checkers from this map.
258af0dd31fSDavid Chisnall 	 */
259bbe31b70SEd Maste 	std::unordered_map<std::string, checker*> checkers;
260af0dd31fSDavid Chisnall 	/**
261af0dd31fSDavid Chisnall 	 * The disabled checkers.  Moving checkers to this list disables them,
262af0dd31fSDavid Chisnall 	 * but allows them to be easily moved back.
263af0dd31fSDavid Chisnall 	 */
264bbe31b70SEd Maste 	std::unordered_map<std::string, checker*> disabled_checkers;
265af0dd31fSDavid Chisnall 	/**
266af0dd31fSDavid Chisnall 	 * Helper function for adding a property value checker.
267af0dd31fSDavid Chisnall 	 */
268af0dd31fSDavid Chisnall 	template<property_value::value_type T>
269bbe31b70SEd Maste 	void add_property_type_checker(const char *name, const std::string &prop);
270af0dd31fSDavid Chisnall 	/**
271af0dd31fSDavid Chisnall 	 * Helper function for adding a simple type checker.
272af0dd31fSDavid Chisnall 	 */
273bbe31b70SEd Maste 	void add_property_type_checker(const char *name, const std::string &prop);
274af0dd31fSDavid Chisnall 	/**
275af0dd31fSDavid Chisnall 	 * Helper function for adding a property value checker.
276af0dd31fSDavid Chisnall 	 */
277af0dd31fSDavid Chisnall 	void add_property_size_checker(const char *name,
278bbe31b70SEd Maste 	                               const std::string &prop,
279af0dd31fSDavid Chisnall 	                               uint32_t size);
280af0dd31fSDavid Chisnall 	public:
281af0dd31fSDavid Chisnall 	/**
282af0dd31fSDavid Chisnall 	 * Delete all of the checkers that are part of this checker manager.
283af0dd31fSDavid Chisnall 	 */
284af0dd31fSDavid Chisnall 	~check_manager();
285af0dd31fSDavid Chisnall 	/**
286af0dd31fSDavid Chisnall 	 * Default constructor, creates check manager containing all of the
287af0dd31fSDavid Chisnall 	 * default checks.
288af0dd31fSDavid Chisnall 	 */
289af0dd31fSDavid Chisnall 	check_manager();
290af0dd31fSDavid Chisnall 	/**
291af0dd31fSDavid Chisnall 	 * Run all of the checks on the specified tree.
292af0dd31fSDavid Chisnall 	 */
293af0dd31fSDavid Chisnall 	bool run_checks(device_tree *tree, bool keep_going);
294af0dd31fSDavid Chisnall 	/**
295af0dd31fSDavid Chisnall 	 * Disables the named checker.
296af0dd31fSDavid Chisnall 	 */
297bbe31b70SEd Maste 	bool disable_checker(const std::string &name);
298af0dd31fSDavid Chisnall 	/**
299af0dd31fSDavid Chisnall 	 * Enables the named checker.
300af0dd31fSDavid Chisnall 	 */
301bbe31b70SEd Maste 	bool enable_checker(const std::string &name);
302af0dd31fSDavid Chisnall };
303af0dd31fSDavid Chisnall 
304af0dd31fSDavid Chisnall } // namespace checking
305af0dd31fSDavid Chisnall 
306af0dd31fSDavid Chisnall } // namespace fdt
307af0dd31fSDavid Chisnall 
308af0dd31fSDavid Chisnall } // namespace dtc
309af0dd31fSDavid Chisnall 
310af0dd31fSDavid Chisnall #endif // !_CHECKING_HH_
311