summaryrefslogtreecommitdiffstats
path: root/usr.bin/dtc/checking.hh
blob: e3b3d451789fc22a53fa135e5dbe854752b7f88e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
/*-
 * Copyright (c) 2013 David Chisnall
 * All rights reserved.
 *
 * This software was developed by SRI International and the University of
 * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
 * ("CTSRD"), as part of the DARPA CRASH research programme.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * $FreeBSD$
 */

#ifndef _CHECKING_HH_
#define _CHECKING_HH_
#include "string.hh"
#include "fdt.hh"

namespace dtc
{
namespace fdt
{
namespace checking
{
/**
 * Base class for all checkers.  This will visit the entire tree and perform
 * semantic checks defined in subclasses.  Note that device trees are generally
 * small (a few dozen nodes at most) and so we optimise for flexibility and
 * extensibility here, not for performance.  Each checker will visit the entire
 * tree.
 */
class checker
{
	/**
	 * The path to the current node being checked.  This is used for
	 * printing error messages.
	 */
	device_tree::node_path path;
	/**
	 * The name of the checker.  This is used for printing error messages
	 * and for enabling / disabling specific checkers from the command
	 * line. 
	 */
	const char *checker_name;
	/**
	 * Visits each node, calling the checker functions on properties and
	 * nodes.
	 */
	bool visit_node(device_tree *tree, const node_ptr &n);
	protected:
	/**
	 * Prints the error message, along with the path to the node that
	 * caused the error and the name of the checker.
	 */
	void report_error(const char *errmsg);
	public:
	/**
	 * Constructor.  Takes the name of this checker, which is which is used
	 * when reporting errors.
	 */
	checker(const char *name) : checker_name(name) {}
	/**
	 * Virtual destructor in case any subclasses need to do cleanup.
	 */
	virtual ~checker() {}
	/**
	 * Method for checking that a node is valid.  The root class version
	 * does nothing, subclasses should override this.
	 */
	virtual bool check_node(device_tree *, const node_ptr &)
	{
		return true;
	}
	/**
	 * Method for checking that a property is valid.  The root class
	 * version does nothing, subclasses should override this.
	 */
	virtual bool check_property(device_tree *, const node_ptr &, property_ptr )
	{
		return true;
	}
	/**
	 * Runs the checker on the specified device tree.
	 */
	bool check_tree(fdt::device_tree *tree)
	{
		return visit_node(tree, tree->get_root());
	}
};

/**
 * Abstract base class for simple property checks.  This class defines a check
 * method for subclasses, which is invoked only when it finds a property with
 * the matching name.  To define simple property checkers, just subclass this
 * and override the check() method.
 */
class property_checker : public checker
{
	/**
	 * The name of the property that this checker is looking for.
	 */
	string key;
	public:
	/**
	 * Implementation of the generic property-checking method that checks
	 * for a property with the name specified in the constructor 
	 */
	virtual bool check_property(device_tree *tree, const node_ptr &n, property_ptr p);
	/**
	 * Constructor.  Takes the name of the checker and the name of the
	 * property to check.
	 */
	property_checker(const char* name, string property_name)
		: checker(name), key(property_name) {}
	/**
	 * The check method, which subclasses should implement.
	 */
	virtual bool check(device_tree *tree, const node_ptr &n, property_ptr p) = 0;
};

/**
 * Property type checker.
 */
template<property_value::value_type T>
struct property_type_checker : public property_checker
{
	/**
	 * Constructor, takes the name of the checker and the name of the
	 * property to check as arguments.
	 */
	property_type_checker(const char* name, string property_name) : 
		property_checker(name, property_name) {}
	virtual bool check(device_tree *tree, const node_ptr &n, property_ptr p) = 0;
};

/**
 * Empty property checker.  This checks that the property has no value.
 */
template<>
struct property_type_checker <property_value::EMPTY> : public property_checker
{
	property_type_checker(const char* name, string property_name) : 
		property_checker(name, property_name) {}
	virtual bool check(device_tree *, const node_ptr &, property_ptr p)
	{
		return p->begin() == p->end();
	}
};

/**
 * String property checker.  This checks that the property has exactly one
 * value, which is a string.
 */
template<>
struct property_type_checker <property_value::STRING> : public property_checker
{
	property_type_checker(const char* name, string property_name) : 
		property_checker(name, property_name) {}
	virtual bool check(device_tree *, const node_ptr &, property_ptr p)
	{
		return (p->begin() + 1 == p->end()) && p->begin()->is_string();
	}
};
/**
 * String list property checker.  This checks that the property has at least
 * one value, all of which are strings.
 */
template<>
struct property_type_checker <property_value::STRING_LIST> :
	public property_checker
{
	property_type_checker(const char* name, string property_name) : 
		property_checker(name, property_name) {}
	virtual bool check(device_tree *, const node_ptr &, property_ptr p)
	{
		for (property::value_iterator i=p->begin(),e=p->end() ; i!=e ;
		     ++i)
		{
			if (!(i->is_string() || i->is_string_list()))
			{
				return false;
			}
		}
		return p->begin() != p->end();
	}
};

/**
 * Phandle property checker.  This checks that the property has exactly one
 * value, which is a valid phandle.
 */
template<>
struct property_type_checker <property_value::PHANDLE> : public property_checker
{
	property_type_checker(const char* name, string property_name) : 
		property_checker(name, property_name) {}
	virtual bool check(device_tree *tree, const node_ptr &, property_ptr p)
	{
		return (p->begin() + 1 == p->end()) && 
			(tree->referenced_node(*p->begin()) != 0);
	}
};

/**
 * Check that a property has the correct size.
 */
struct property_size_checker : public property_checker
{
	/**
	 * The expected size of the property.
	 */
	uint32_t size;
	public:
	/**
	 * Constructor, takes the name of the checker, the name of the property
	 * to check, and its expected size as arguments.
	 */
	property_size_checker(const char* name, string property_name, uint32_t bytes)
		: property_checker(name, property_name), size(bytes) {}
	/**
	 * Check, validates that the property has the correct size.
	 */
	virtual bool check(device_tree *tree, const node_ptr &n, property_ptr p);
};


/**
 * The check manager is the interface to running the checks.  This allows
 * default checks to be enabled, non-default checks to be enabled, and so on.
 */
class check_manager
{
	/**
	 * The enabled checkers, indexed by their names.  The name is used when
	 * disabling checkers from the command line.  When this manager runs,
	 * it will only run the checkers from this map.
	 */
	std::unordered_map<string, checker*> checkers;
	/**
	 * The disabled checkers.  Moving checkers to this list disables them,
	 * but allows them to be easily moved back.
	 */
	std::unordered_map<string, checker*> disabled_checkers;
	/**
	 * Helper function for adding a property value checker.
	 */
	template<property_value::value_type T>
	void add_property_type_checker(const char *name, string prop);
	/**
	 * Helper function for adding a simple type checker.
	 */
	void add_property_type_checker(const char *name, string prop);
	/**
	 * Helper function for adding a property value checker.
	 */
	void add_property_size_checker(const char *name,
	                               string prop,
	                               uint32_t size);
	public:
	/**
	 * Delete all of the checkers that are part of this checker manager.
	 */
	~check_manager();
	/**
	 * Default constructor, creates check manager containing all of the
	 * default checks.
	 */
	check_manager();
	/**
	 * Run all of the checks on the specified tree.
	 */
	bool run_checks(device_tree *tree, bool keep_going);
	/**
	 * Disables the named checker.
	 */
	bool disable_checker(string name);
	/**
	 * Enables the named checker.  
	 */
	bool enable_checker(string name);
};

} // namespace checking

} // namespace fdt

} // namespace dtc

#endif // !_CHECKING_HH_
OpenPOWER on IntegriCloud