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