xref: /freebsd/usr.bin/dtc/checking.cc (revision af0dd31fc469cac25e441ff350ccda958ea5c8df)
1 /*-
2  * Copyright (c) 2013 David Chisnall
3  * All rights reserved.
4  *
5  * This software was developed by SRI International and the University of
6  * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
7  * ("CTSRD"), as part of the DARPA CRASH research programme.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  *
30  * $FreeBSD$
31  */
32 
33 #include "checking.hh"
34 
35 namespace dtc
36 {
37 namespace fdt
38 {
39 namespace checking
40 {
41 
42 bool
43 checker::visit_node(device_tree *tree, node *n)
44 {
45 	path.push_back(std::make_pair(n->name, n->unit_address));
46 	// Check this node
47 	if (!check_node(tree, n))
48 	{
49 		return false;
50 	}
51 	// Now check its properties
52 	for (node::property_iterator i=n->property_begin(), e=n->property_end()
53 	     ; i!=e ; ++i)
54 	{
55 		if (!check_property(tree, n, *i))
56 		{
57 			return false;
58 		}
59 	}
60 	// And then recursively check the children
61 	for (node::child_iterator i=n->child_begin(), e=n->child_end() ; i!=e ;
62 	     ++i)
63 	{
64 		if (!visit_node(tree, *i))
65 		{
66 			return false;
67 		}
68 	}
69 	path.pop_back();
70 	return true;
71 }
72 
73 void
74 checker::report_error(const char *errmsg)
75 {
76 	fprintf(stderr, "Error: %s, while checking node: ", errmsg);
77 	for (device_tree::node_path::iterator p=path.begin()+1, pe=path.end() ;
78 	     p!=pe ; ++p)
79 	{
80 		putc('/', stderr);
81 		p->first.dump();
82 		if (!(p->second.empty()))
83 		{
84 			putc('@', stderr);
85 			p->second.dump();
86 		}
87 	}
88 	fprintf(stderr, " [-W%s]\n", checker_name);
89 }
90 
91 bool
92 property_checker::check_property(device_tree *tree, node *n, property *p)
93 {
94 	if (p->get_key() == key)
95 	{
96 		if (!check(tree, n, p))
97 		{
98 			report_error("property check failed");
99 			return false;
100 		}
101 	}
102 	return true;
103 }
104 
105 bool
106 property_size_checker::check(device_tree *tree, node *n, property *p)
107 {
108 	uint32_t psize = 0;
109 	for (property::value_iterator i=p->begin(),e=p->end() ; i!=e ; ++i)
110 	{
111 		if (!i->is_binary())
112 		{
113 			return false;
114 		}
115 		psize += i->byte_data.size();
116 	}
117 	return psize == size;
118 }
119 
120 template<property_value::value_type T>
121 void
122 check_manager::add_property_type_checker(const char *name, string prop)
123 {
124 	checkers.insert(std::make_pair(string(name),
125 		new property_type_checker<T>(name, prop)));
126 }
127 
128 void
129 check_manager::add_property_size_checker(const char *name,
130                                          string prop,
131                                          uint32_t size)
132 {
133 	checkers.insert(std::make_pair(string(name),
134 		new property_size_checker(name, prop, size)));
135 }
136 
137 check_manager::~check_manager()
138 {
139 	while (checkers.begin() != checkers.end())
140 	{
141 		delete checkers.begin()->second;
142 		checkers.erase(checkers.begin());
143 	}
144 	while (disabled_checkers.begin() != disabled_checkers.end())
145 	{
146 		delete disabled_checkers.begin()->second;
147 	}
148 }
149 
150 check_manager::check_manager()
151 {
152 	// NOTE: All checks listed here MUST have a corresponding line
153 	// in the man page!
154 	add_property_type_checker<property_value::STRING_LIST>(
155 			"type-compatible", string("compatible"));
156 	add_property_type_checker<property_value::STRING>(
157 			"type-model", string("model"));
158 	add_property_size_checker("type-phandle", string("phandle"), 4);
159 }
160 
161 bool
162 check_manager::run_checks(device_tree *tree, bool keep_going)
163 {
164 	bool success = true;
165 	for (std::map<string, checker*>::iterator i=checkers.begin(),
166 	     e=checkers.end() ; i!=e ; ++i)
167 	{
168 		success &= i->second->check_tree(tree);
169 		if (!(success || keep_going))
170 		{
171 			break;
172 		}
173 	}
174 	return success;
175 }
176 
177 bool
178 check_manager::disable_checker(string name)
179 {
180 	std::map<string, checker*>::iterator checker = checkers.find(name);
181 	if (checker != checkers.end())
182 	{
183 		disabled_checkers.insert(std::make_pair(name,
184 		                                        checker->second));
185 		checkers.erase(checker);
186 		return true;
187 	}
188 	return false;
189 }
190 
191 bool
192 check_manager::enable_checker(string name)
193 {
194 	std::map<string, checker*>::iterator checker =
195 		disabled_checkers.find(name);
196 	if (checker != disabled_checkers.end())
197 	{
198 		checkers.insert(std::make_pair(name, checker->second));
199 		disabled_checkers.erase(checker);
200 		return true;
201 	}
202 	return false;
203 }
204 
205 } // namespace checking
206 
207 } // namespace fdt
208 
209 } // namespace dtc
210 
211