xref: /freebsd/usr.bin/dtc/checking.cc (revision 009f7b425d0046197035b97e71153908303619c2)
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 #include <stdio.h>
35 
36 namespace dtc
37 {
38 namespace fdt
39 {
40 namespace checking
41 {
42 
43 bool
44 checker::visit_node(device_tree *tree, node *n)
45 {
46 	path.push_back(std::make_pair(n->name, n->unit_address));
47 	// Check this node
48 	if (!check_node(tree, n))
49 	{
50 		return false;
51 	}
52 	// Now check its properties
53 	for (node::property_iterator i=n->property_begin(), e=n->property_end()
54 	     ; i!=e ; ++i)
55 	{
56 		if (!check_property(tree, n, *i))
57 		{
58 			return false;
59 		}
60 	}
61 	// And then recursively check the children
62 	for (node::child_iterator i=n->child_begin(), e=n->child_end() ; i!=e ;
63 	     ++i)
64 	{
65 		if (!visit_node(tree, *i))
66 		{
67 			return false;
68 		}
69 	}
70 	path.pop_back();
71 	return true;
72 }
73 
74 void
75 checker::report_error(const char *errmsg)
76 {
77 	fprintf(stderr, "Error: %s, while checking node: ", errmsg);
78 	for (device_tree::node_path::iterator p=path.begin()+1, pe=path.end() ;
79 	     p!=pe ; ++p)
80 	{
81 		putc('/', stderr);
82 		p->first.dump();
83 		if (!(p->second.empty()))
84 		{
85 			putc('@', stderr);
86 			p->second.dump();
87 		}
88 	}
89 	fprintf(stderr, " [-W%s]\n", checker_name);
90 }
91 
92 bool
93 property_checker::check_property(device_tree *tree, node *n, property *p)
94 {
95 	if (p->get_key() == key)
96 	{
97 		if (!check(tree, n, p))
98 		{
99 			report_error("property check failed");
100 			return false;
101 		}
102 	}
103 	return true;
104 }
105 
106 bool
107 property_size_checker::check(device_tree *tree, node *n, property *p)
108 {
109 	uint32_t psize = 0;
110 	for (property::value_iterator i=p->begin(),e=p->end() ; i!=e ; ++i)
111 	{
112 		if (!i->is_binary())
113 		{
114 			return false;
115 		}
116 		psize += i->byte_data.size();
117 	}
118 	return psize == size;
119 }
120 
121 template<property_value::value_type T>
122 void
123 check_manager::add_property_type_checker(const char *name, string prop)
124 {
125 	checkers.insert(std::make_pair(string(name),
126 		new property_type_checker<T>(name, prop)));
127 }
128 
129 void
130 check_manager::add_property_size_checker(const char *name,
131                                          string prop,
132                                          uint32_t size)
133 {
134 	checkers.insert(std::make_pair(string(name),
135 		new property_size_checker(name, prop, size)));
136 }
137 
138 check_manager::~check_manager()
139 {
140 	while (checkers.begin() != checkers.end())
141 	{
142 		delete checkers.begin()->second;
143 		checkers.erase(checkers.begin());
144 	}
145 	while (disabled_checkers.begin() != disabled_checkers.end())
146 	{
147 		delete disabled_checkers.begin()->second;
148 	}
149 }
150 
151 check_manager::check_manager()
152 {
153 	// NOTE: All checks listed here MUST have a corresponding line
154 	// in the man page!
155 	add_property_type_checker<property_value::STRING_LIST>(
156 			"type-compatible", string("compatible"));
157 	add_property_type_checker<property_value::STRING>(
158 			"type-model", string("model"));
159 	add_property_size_checker("type-phandle", string("phandle"), 4);
160 }
161 
162 bool
163 check_manager::run_checks(device_tree *tree, bool keep_going)
164 {
165 	bool success = true;
166 	for (std::map<string, checker*>::iterator i=checkers.begin(),
167 	     e=checkers.end() ; i!=e ; ++i)
168 	{
169 		success &= i->second->check_tree(tree);
170 		if (!(success || keep_going))
171 		{
172 			break;
173 		}
174 	}
175 	return success;
176 }
177 
178 bool
179 check_manager::disable_checker(string name)
180 {
181 	std::map<string, checker*>::iterator checker = checkers.find(name);
182 	if (checker != checkers.end())
183 	{
184 		disabled_checkers.insert(std::make_pair(name,
185 		                                        checker->second));
186 		checkers.erase(checker);
187 		return true;
188 	}
189 	return false;
190 }
191 
192 bool
193 check_manager::enable_checker(string name)
194 {
195 	std::map<string, checker*>::iterator checker =
196 		disabled_checkers.find(name);
197 	if (checker != disabled_checkers.end())
198 	{
199 		checkers.insert(std::make_pair(name, checker->second));
200 		disabled_checkers.erase(checker);
201 		return true;
202 	}
203 	return false;
204 }
205 
206 } // namespace checking
207 
208 } // namespace fdt
209 
210 } // namespace dtc
211 
212