git: 38fe4bc08264 - stable/14 - dtc: Sync with upstream commit 26a0fe5

From: Ed Maste <emaste_at_FreeBSD.org>
Date: Wed, 10 Jan 2024 18:51:53 UTC
The branch stable/14 has been updated by emaste:

URL: https://cgit.FreeBSD.org/src/commit/?id=38fe4bc08264652cd33964ba6042bd4c0faf6b76

commit 38fe4bc08264652cd33964ba6042bd4c0faf6b76
Author:     Jose Luis Duran <jlduran@gmail.com>
AuthorDate: 2023-09-26 16:37:52 +0000
Commit:     Ed Maste <emaste@FreeBSD.org>
CommitDate: 2024-01-10 18:50:53 +0000

    dtc: Sync with upstream commit 26a0fe5
    
    - 0206c0f ("Handle top-level /delete-node/ directives.")
    - d612a9e ("Remove C++11 standard constrain")
    - Remove extra white lines after the $FreeBSD$ tag removal
    
    Reviewed by:    kevans (earlier), theraven, emaste
    Differential Revision: https://reviews.freebsd.org/D41482
    
    (cherry picked from commit 29a55fd09b0a3cc4c888f7a630fde41694699343)
    (cherry picked from commit f147cf0ee2b2642c0a133a71c8a5dc018518d923)
---
 usr.bin/dtc/HACKING  |   1 -
 usr.bin/dtc/Makefile |   3 +-
 usr.bin/dtc/fdt.cc   | 134 ++++++++++++++++++++++++++++++++++++++++-----------
 usr.bin/dtc/fdt.hh   |  24 ++++++---
 4 files changed, 122 insertions(+), 40 deletions(-)

diff --git a/usr.bin/dtc/HACKING b/usr.bin/dtc/HACKING
index 9447c4f6ebf9..ef858c8885c0 100644
--- a/usr.bin/dtc/HACKING
+++ b/usr.bin/dtc/HACKING
@@ -1,4 +1,3 @@
-
 Notes for people hacking on dtc
 ===============================
 
diff --git a/usr.bin/dtc/Makefile b/usr.bin/dtc/Makefile
index d242ed80e8b1..9b1aff13511f 100644
--- a/usr.bin/dtc/Makefile
+++ b/usr.bin/dtc/Makefile
@@ -1,4 +1,3 @@
-
 PROG_CXX=dtc
 SRCS=	dtc.cc input_buffer.cc string.cc dtb.cc fdt.cc checking.cc
 MAN=	dtc.1
@@ -7,7 +6,7 @@ WARNS?=	3
 
 CXXFLAGS+=	-fno-rtti -fno-exceptions
 
-CXXSTD=	c++11
+CXXSTD=	c++17
 
 NO_SHARED?=NO
 
diff --git a/usr.bin/dtc/fdt.cc b/usr.bin/dtc/fdt.cc
index 5ab9ba10d2f0..f0b98cfe720c 100644
--- a/usr.bin/dtc/fdt.cc
+++ b/usr.bin/dtc/fdt.cc
@@ -861,7 +861,15 @@ node::node(const string &n,
 node_ptr node::create_special_node(const string &name,
                                    const std::vector<property_ptr> &props)
 {
-	node_ptr n(new node(name, props));
+	// Work around for the fact that we can't call make_shared on something
+	// with a private constructor.  Instead create a subclass with a public
+	// constructor that is visible only in this function and construct that
+	// instead.
+	struct constructable_node : public node
+	{
+		constructable_node(const string &n, const std::vector<property_ptr> &p) : node(n, p) {}
+	};
+	node_ptr n{std::make_shared<constructable_node>(name, props)};
 	return n;
 }
 
@@ -1035,12 +1043,31 @@ node::parse(text_input_buffer &input,
             string &&address,
             define_map *defines)
 {
-	node_ptr n(new node(input,
-	                    tree,
-	                    std::move(name),
-	                    std::move(label),
-	                    std::move(address),
-	                    defines));
+	// Work around for the fact that we can't call make_shared on something
+	// with a private constructor.  Instead create a subclass with a public
+	// constructor that is visible only in this function and construct that
+	// instead.
+	struct constructable_node : public node
+	{
+		constructable_node(text_input_buffer &input,
+	                       device_tree &tree,
+	                       std::string &&n,
+	                       std::unordered_set<std::string> &&l,
+	                       std::string &&a,
+	                       define_map*m) : node(input,
+	                                            tree,
+	                                            std::move(n),
+	                                            std::move(l),
+	                                            std::move(a),
+	                                            m)
+		{}
+	};
+	node_ptr n{std::make_shared<constructable_node>(input,
+	                                                tree,
+	                                                std::move(name),
+	                                                std::move(label),
+	                                                std::move(address),
+	                                                defines)};
 	if (!n->valid)
 	{
 		n = 0;
@@ -1208,7 +1235,7 @@ node::write_dts(FILE *file, int indent)
 }
 
 void
-device_tree::collect_names_recursive(node_ptr &n, node_path &path)
+device_tree::collect_names_recursive(node_ptr parent, node_ptr n, node_path &path)
 {
 	path.push_back(std::make_pair(n->name, n->unit_address));
 	for (const string &name : n->labels)
@@ -1218,9 +1245,13 @@ device_tree::collect_names_recursive(node_ptr &n, node_path &path)
 			auto iter = node_names.find(name);
 			if (iter == node_names.end())
 			{
-				node_names.insert(std::make_pair(name, n.get()));
+				node_names.insert(std::make_pair(name, n));
 				node_paths.insert(std::make_pair(name, path));
 				ordered_node_paths.push_back({name, path});
+				if (parent)
+				{
+					node_name_parents.insert({name, parent});
+				}
 			}
 			else
 			{
@@ -1236,7 +1267,7 @@ device_tree::collect_names_recursive(node_ptr &n, node_path &path)
 	}
 	for (auto &c : n->child_nodes())
 	{
-		collect_names_recursive(c, path);
+		collect_names_recursive(n, c, path);
 	}
 	// Now we collect the phandles and properties that reference
 	// other nodes.
@@ -1264,7 +1295,7 @@ device_tree::collect_names_recursive(node_ptr &n, node_path &path)
 			else
 			{
 				uint32_t phandle = p->begin()->get_as_uint32();
-				used_phandles.insert(std::make_pair(phandle, n.get()));
+				used_phandles.insert(std::make_pair(phandle, n));
 			}
 		}
 	}
@@ -1280,11 +1311,11 @@ device_tree::collect_names()
 	ordered_node_paths.clear();
 	cross_references.clear();
 	fixups.clear();
-	collect_names_recursive(root, p);
+	collect_names_recursive(nullptr, root, p);
 }
 
 property_ptr
-device_tree::assign_phandle(node *n, uint32_t &phandle)
+device_tree::assign_phandle(node_ptr n, uint32_t &phandle)
 {
 	// If there is an existing phandle, use it
 	property_ptr p = n->get_property("phandle");
@@ -1329,11 +1360,11 @@ device_tree::assign_phandle(node *n, uint32_t &phandle)
 }
 
 void
-device_tree::assign_phandles(node_ptr &n, uint32_t &next)
+device_tree::assign_phandles(node_ptr n, uint32_t &next)
 {
 	if (!n->labels.empty())
 	{
-		assign_phandle(n.get(), next);
+		assign_phandle(n, next);
 	}
 
 	for (auto &c : n->child_nodes())
@@ -1391,14 +1422,14 @@ device_tree::resolve_cross_references(uint32_t &phandle)
 	for (auto &i : sorted_phandles)
 	{
 		string target_name = i.get().val.string_data;
-		node *target = nullptr;
+		node_ptr target;
 		string possible;
 		// If the node name is a path, then look it up by following the path,
 		// otherwise jump directly to the named node.
 		if (target_name[0] == '/')
 		{
 			string path;
-			target = root.get();
+			target = root;
 			std::istringstream ss(target_name);
 			string path_element;
 			// Read the leading /
@@ -1412,14 +1443,14 @@ device_tree::resolve_cross_references(uint32_t &phandle)
 				string node_name, node_address;
 				std::getline(nss, node_name, '@');
 				std::getline(nss, node_address, '@');
-				node *next = nullptr;
+				node_ptr next;
 				for (auto &c : target->child_nodes())
 				{
 					if (c->name == node_name)
 					{
 						if (c->unit_address == node_address)
 						{
-							next = c.get();
+							next = c;
 							break;
 						}
 						else
@@ -1478,8 +1509,8 @@ device_tree::resolve_cross_references(uint32_t &phandle)
 bool
 device_tree::garbage_collect_marked_nodes()
 {
-	std::unordered_set<node*> previously_referenced_nodes;
-	std::unordered_set<node*> newly_referenced_nodes;
+	std::unordered_set<node_ptr> previously_referenced_nodes;
+	std::unordered_set<node_ptr> newly_referenced_nodes;
 
 	auto mark_referenced_nodes_used = [&](node &n)
 	{
@@ -1489,7 +1520,7 @@ device_tree::garbage_collect_marked_nodes()
 			{
 				if (v.is_phandle())
 				{
-					node *nx = node_names[v.string_data];
+					node_ptr nx = node_names[v.string_data];
 					if (nx == nullptr)
 					{
 						// Try it again, but as a path
@@ -1534,8 +1565,9 @@ device_tree::garbage_collect_marked_nodes()
 
 	while (!newly_referenced_nodes.empty())
 	{
-			previously_referenced_nodes = std::move(newly_referenced_nodes);
-			for (auto *n : previously_referenced_nodes)
+			previously_referenced_nodes = newly_referenced_nodes;
+			newly_referenced_nodes.clear();
+			for (auto &n : previously_referenced_nodes)
 			{
 				mark_referenced_nodes_used(*n);
 			}
@@ -1617,7 +1649,38 @@ device_tree::parse_file(text_input_buffer &input,
 	while (valid && !input.finished())
 	{
 		node_ptr n;
-		if (input.consume('/'))
+		if (input.consume("/delete-node/"))
+		{
+			// Top-level /delete-node/ directives refer to references that must
+			// be deleted later.
+			input.next_token();
+			auto expect = [&](auto token, const char *msg)
+			{
+				if (!input.consume(token))
+				{
+					input.parse_error(msg);
+					valid = false;
+				}
+				input.next_token();
+				return valid;
+			};
+			if (expect('&', "Expected reference after top-level /delete-node/."))
+			{
+				string ref = input.parse_node_name();
+				if (ref == string())
+				{
+					input.parse_error("Expected label name for top-level /delete-node/.");
+					valid = false;
+				}
+				else
+				{
+					deletions.push_back(std::move(ref));
+				}
+				expect(';', "Missing semicolon.");
+			}
+			continue;
+		}
+		else if (input.consume('/'))
 		{
 			input.next_token();
 			n = node::parse(input, *this, string(), string_set(), string(), &defines);
@@ -1732,7 +1795,7 @@ device_tree::write(int fd)
 	strings_writer.write_to_file(fd);
 }
 
-node*
+node_ptr
 device_tree::referenced_node(property_value &v)
 {
 	if (v.is_phandle())
@@ -2032,6 +2095,19 @@ device_tree::parse_dts(const string &fn, FILE *depfile)
 		}
 	}
 	collect_names();
+	for (auto &ref : deletions)
+	{
+		auto parent = node_name_parents[ref];
+		auto node = node_names[ref];
+		if (!parent)
+		{
+			fprintf(stderr, "Top-level /delete-node/ directive refers to label %s, which is not found.\n", ref.c_str());
+		}
+		else
+		{
+			parent->delete_children_if([&](node_ptr &child) { return child == node; });
+		}
+	}
 	// Return value indicates whether we've dirtied the tree or not and need to
 	// recollect names
 	if (garbage_collect && garbage_collect_marked_nodes())
@@ -2127,7 +2203,7 @@ device_tree::parse_dts(const string &fn, FILE *depfile)
 			{
 				continue;
 			}
-			node *n = local_fixups.get();
+			node_ptr n = local_fixups;
 			for (auto &p : i.path)
 			{
 				// Skip the implicit root
@@ -2142,7 +2218,7 @@ device_tree::parse_dts(const string &fn, FILE *depfile)
 					{
 						if (c->unit_address == p.second)
 						{
-							n = c.get();
+							n = c;
 							found = true;
 							break;
 						}
@@ -2157,7 +2233,7 @@ device_tree::parse_dts(const string &fn, FILE *depfile)
 						path += p.second;
 					}
 					n->add_child(node::create_special_node(path, symbols));
-					n = (--n->child_end())->get();
+					n = *(--(n->child_end()));
 				}
 			}
 			assert(n);
diff --git a/usr.bin/dtc/fdt.hh b/usr.bin/dtc/fdt.hh
index 86c9ff153b80..fad9609d40bb 100644
--- a/usr.bin/dtc/fdt.hh
+++ b/usr.bin/dtc/fdt.hh
@@ -71,7 +71,7 @@ typedef std::shared_ptr<property> property_ptr;
 /**
  * Owning pointer to a node.
  */
-typedef std::unique_ptr<node> node_ptr;
+typedef std::shared_ptr<node> node_ptr;
 /**
  * Map from macros to property pointers.
  */
@@ -663,7 +663,7 @@ class node
 	/**
 	 * Deletes any children from this node.
 	 */
-	inline void delete_children_if(bool (*predicate)(node_ptr &))
+	inline void delete_children_if(std::function<bool(node_ptr &)> predicate)
 	{
 		children.erase(std::remove_if(children.begin(), children.end(), predicate), children.end());
 	}
@@ -761,7 +761,11 @@ class device_tree
 	 * Mapping from names to nodes.  Only unambiguous names are recorded,
 	 * duplicate names are stored as (node*)-1.
 	 */
-	std::unordered_map<std::string, node*> node_names;
+	std::unordered_map<std::string, node_ptr> node_names;
+	/**
+	 * Mapping from names to the nodes that contain them.
+	 */
+	std::unordered_map<std::string, node_ptr> node_name_parents;
 	/**
 	 * A map from labels to node paths.  When resolving cross references,
 	 * we look up referenced nodes in this and replace the cross reference
@@ -779,6 +783,10 @@ class device_tree
 	 * These should be expanded to the full path of their targets.
 	 */
 	std::vector<property_value*> cross_references;
+	/**
+	 * Labels collected from top-level /delete-node/ directives.
+	 */
+	std::vector<std::string> deletions;
 	/**
 	 * The location of something requiring a fixup entry.
 	 */
@@ -827,7 +835,7 @@ class device_tree
 	 * find phandles that were provided by the user explicitly when we are
 	 * doing checking.
 	 */
-	std::unordered_map<uint32_t, node*> used_phandles;
+	std::unordered_map<uint32_t, node_ptr> used_phandles;
 	/**
 	 * Paths to search for include files.  This contains a set of
 	 * nul-terminated strings, which are not owned by this class and so
@@ -864,19 +872,19 @@ class device_tree
 	 * used in resolving cross references.  Also collects phandle
 	 * properties that have been explicitly added.  
 	 */
-	void collect_names_recursive(node_ptr &n, node_path &path);
+	void collect_names_recursive(node_ptr parent, node_ptr n, node_path &path);
 	/**
 	 * Assign a phandle property to a single node.  The next parameter
 	 * holds the phandle to be assigned, and will be incremented upon
 	 * assignment.
 	 */
-	property_ptr assign_phandle(node *n, uint32_t &next);
+	property_ptr assign_phandle(node_ptr n, uint32_t &next);
 	/**
 	 * Assign phandle properties to all nodes that have been referenced and
 	 * require one.  This method will recursively visit the tree starting at
 	 * the node that it is passed.
 	 */
-	void assign_phandles(node_ptr &n, uint32_t &next);
+	void assign_phandles(node_ptr n, uint32_t &next);
 	/**
 	 * Calls the recursive version of this method on every root node.
 	 */
@@ -925,7 +933,7 @@ class device_tree
 	 * is in source form, then we have a string that we can use to index
 	 * the cross_references array and so we can just look that up.  
 	 */
-	node *referenced_node(property_value &v);
+	node_ptr referenced_node(property_value &v);
 	/**
 	 * Writes this FDT as a DTB to the specified output.
 	 */