]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/dtc/checking.cc
bhyvectl(8): Normalize the man page date
[FreeBSD/FreeBSD.git] / usr.bin / dtc / checking.cc
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$
33  */
34
35 #include "checking.hh"
36 #include <stdio.h>
37
38 using std::string;
39
40 namespace dtc
41 {
42 namespace fdt
43 {
44 namespace checking
45 {
46
47 namespace
48 {
49         struct deleted_node_checker : public checker
50         {
51                 deleted_node_checker(const char *name) : checker(name) {}
52                 virtual bool check_node(device_tree *, const node_ptr &n)
53                 {
54                         auto &deleted = n->deleted_child_nodes();
55                         if (deleted.empty())
56                         {
57                                 return true;
58                         }
59                         bool plural = deleted.size() > 1;
60                         string errmsg("Attempts to delete ");
61                         errmsg += plural ? "nodes" : "node";
62                         errmsg += " that ";
63                         errmsg += plural ? "were" : "was";
64                         errmsg += " not added in merge: ";
65                         for (auto &d : deleted)
66                         {
67                                 errmsg += d;
68                         }
69                         report_error(errmsg.c_str());
70                         return false;
71                 }
72         };
73         /**
74          * Checker that verifies that every node that has children has
75          * #address-cells and #size-cells properties.
76          */
77         struct address_cells_checker : public checker
78         {
79                 address_cells_checker(const char *name) : checker(name) {}
80                 virtual bool check_node(device_tree *, const node_ptr &n)
81                 {
82                         // If this has no children, it trivially meets the
83                         // conditions.
84                         if (n->child_begin() == n->child_end())
85                         {
86                                 return true;
87                         }
88                         bool found_address = false;
89                         bool found_size = false;
90                         for (auto i=n->property_begin(), e=n->property_end() ; i!=e ; ++i)
91                         {
92                                 if (!found_address)
93                                 {
94                                         found_address = ((*i)->get_key() == "#address-cells");
95                                 }
96                                 if (!found_size)
97                                 {
98                                         found_size = ((*i)->get_key() == "#size-cells");
99                                 }
100                                 if (found_size && found_address)
101                                 {
102                                                 break;
103                                 }
104                         }
105                         if (!found_address)
106                         {
107                                         report_error("Missing #address-cells property");
108                         }
109                         if (!found_size)
110                         {
111                                         report_error("Missing #size-cells property");
112                         }
113                         return found_address && found_size;
114                 }
115         };
116 } // anonymous namespace
117
118 bool
119 checker::visit_node(device_tree *tree, const node_ptr &n)
120 {
121         path.push_back(std::make_pair(n->name, n->unit_address));
122         // Check this node
123         if (!check_node(tree, n))
124         {
125                 return false;
126         }
127         // Now check its properties
128         for (auto i=n->property_begin(), e=n->property_end() ; i!=e ; ++i)
129         {
130                 if (!check_property(tree, n, *i))
131                 {
132                         return false;
133                 }
134         }
135         // And then recursively check the children
136         for (node::child_iterator i=n->child_begin(), e=n->child_end() ; i!=e ;
137              ++i)
138         {
139                 if (!visit_node(tree, *i))
140                 {
141                         return false;
142                 }
143         }
144         path.pop_back();
145         return true;
146 }
147
148 void
149 checker::report_error(const char *errmsg)
150 {
151         fprintf(stderr, "Error: %s, while checking node: ", errmsg);
152         for (auto &p : path)
153         {
154                 putc('/', stderr);
155                 puts(p.first.c_str());
156                 if (!(p.second.empty()))
157                 {
158                         putc('@', stderr);
159                         puts(p.second.c_str());
160                 }
161         }
162         fprintf(stderr, " [-W%s]\n", checker_name);
163 }
164
165 bool
166 property_checker::check_property(device_tree *tree, const node_ptr &n, property_ptr p)
167 {
168         if (p->get_key() == key)
169         {
170                 if (!check(tree, n, p))
171                 {
172                         report_error("property check failed");
173                         return false;
174                 }
175         }
176         return true;
177 }
178
179 bool
180 property_size_checker::check(device_tree *, const node_ptr &, property_ptr p)
181 {
182         uint32_t psize = 0;
183         for (property::value_iterator i=p->begin(),e=p->end() ; i!=e ; ++i)
184         {
185                 if (!i->is_binary())
186                 {
187                         return false;
188                 }
189                 psize += i->byte_data.size();
190         }
191         return psize == size;
192 }
193
194 template<property_value::value_type T>
195 void
196 check_manager::add_property_type_checker(const char *name, const string &prop)
197 {
198         checkers.insert(std::make_pair(string(name),
199                 new property_type_checker<T>(name, prop)));
200 }
201
202 void
203 check_manager::add_property_size_checker(const char *name,
204                                          const string &prop,
205                                          uint32_t size)
206 {
207         checkers.insert(std::make_pair(string(name),
208                 new property_size_checker(name, prop, size)));
209 }
210
211 check_manager::~check_manager()
212 {
213         while (checkers.begin() != checkers.end())
214         {
215                 delete checkers.begin()->second;
216                 checkers.erase(checkers.begin());
217         }
218         while (disabled_checkers.begin() != disabled_checkers.end())
219         {
220                 delete disabled_checkers.begin()->second;
221                 disabled_checkers.erase(disabled_checkers.begin());
222         }
223 }
224
225 check_manager::check_manager()
226 {
227         // NOTE: All checks listed here MUST have a corresponding line
228         // in the man page!
229         add_property_type_checker<property_value::STRING_LIST>(
230                         "type-compatible", string("compatible"));
231         add_property_type_checker<property_value::STRING>(
232                         "type-model", string("model"));
233         add_property_size_checker("type-phandle", string("phandle"), 4);
234         disabled_checkers.insert(std::make_pair(string("cells-attributes"),
235                 new address_cells_checker("cells-attributes")));
236         checkers.insert(std::make_pair(string("deleted-nodes"),
237                 new deleted_node_checker("deleted-nodes")));
238 }
239
240 bool
241 check_manager::run_checks(device_tree *tree, bool keep_going)
242 {
243         bool success = true;
244         for (auto &i : checkers)
245         {
246                 success &= i.second->check_tree(tree);
247                 if (!(success || keep_going))
248                 {
249                         break;
250                 }
251         }
252         return success;
253 }
254
255 bool
256 check_manager::disable_checker(const string &name)
257 {
258         auto checker = checkers.find(name);
259         if (checker != checkers.end())
260         {
261                 disabled_checkers.insert(std::make_pair(name,
262                                                         checker->second));
263                 checkers.erase(checker);
264                 return true;
265         }
266         return false;
267 }
268
269 bool
270 check_manager::enable_checker(const string &name)
271 {
272         auto checker = disabled_checkers.find(name);
273         if (checker != disabled_checkers.end())
274         {
275                 checkers.insert(std::make_pair(name, checker->second));
276                 disabled_checkers.erase(checker);
277                 return true;
278         }
279         return false;
280 }
281
282 } // namespace checking
283
284 } // namespace fdt
285
286 } // namespace dtc
287