6b647a7ab8
- Numerous crash and bug fixes - Improved warning and error messages - Permit multiple labels on nodes and properties - Fix node@address references - Add support for /delete-node/ - Consume whitespace after a node - Read the next token before the second /memreserve/ - Fix parsing of whitespace - Clean up /delete-node/ and add support for /delete-property/ - Handle /delete-node/ specifying a unit address Obtained from: https://github.com/davidchisnall/dtc @df5ede4
311 lines
9.3 KiB
C++
311 lines
9.3 KiB
C++
/*-
|
|
* 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>
|
|
#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.
|
|
*/
|
|
std::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, const std::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, const std::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, const std::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, const std::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, const std::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, const std::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,
|
|
const std::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<std::string, checker*> checkers;
|
|
/**
|
|
* The disabled checkers. Moving checkers to this list disables them,
|
|
* but allows them to be easily moved back.
|
|
*/
|
|
std::unordered_map<std::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, const std::string &prop);
|
|
/**
|
|
* Helper function for adding a simple type checker.
|
|
*/
|
|
void add_property_type_checker(const char *name, const std::string &prop);
|
|
/**
|
|
* Helper function for adding a property value checker.
|
|
*/
|
|
void add_property_size_checker(const char *name,
|
|
const std::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(const std::string &name);
|
|
/**
|
|
* Enables the named checker.
|
|
*/
|
|
bool enable_checker(const std::string &name);
|
|
};
|
|
|
|
} // namespace checking
|
|
|
|
} // namespace fdt
|
|
|
|
} // namespace dtc
|
|
|
|
#endif // !_CHECKING_HH_
|