Avoid to re-generate string table from ufdt to fdt

String table contains the strings of all property name in a fdt.

The ufdt_apply_overlay() converts two dtbs from fdt to ufdt,
overlays, and converts merged ufdt to fdt. These operations
shouldn't create new peroperty names, so we can just re-use the
string tables in original dtbs, and just copy them into merged
fdt. This solution can enhance a lot of performance for device
tree overlaying.

To avoid the error that some users could use string offset in
string table, the solution also give a same string offset for
the name properties by ufdt_prop_dict;

Futher, the patch also removed unused header files after
changing algorithm.

Bug: 35255584
Test: ./tests/run_tests.sh
Change-Id: Id422730115531bd20d21117285291bdd860915ff
diff --git a/Android.mk b/Android.mk
index 4b4830f..6a1b3a7 100644
--- a/Android.mk
+++ b/Android.mk
@@ -6,7 +6,7 @@
     ufdt_overlay.c \
     ufdt_convert.c \
     ufdt_node.c \
-    ufdt_node_dict.c
+    ufdt_prop_dict.c
 
 ###################################################
 
diff --git a/fdt_internal.h b/fdt_internal.h
deleted file mode 100644
index 4d7ca47..0000000
--- a/fdt_internal.h
+++ /dev/null
@@ -1,160 +0,0 @@
-#ifndef FDT_INTERNAL_H
-#define FDT_INTERNAL_H
-
-/*
- * libfdt - Flat Device Tree manipulation
- * Copyright (C) 2006 David Gibson, IBM Corporation.
- *
- * libfdt is dual licensed: you can use it either under the terms of
- * the GPL, or the BSD license, at your option.
- *
- *  a) This library is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License as
- *     published by the Free Software Foundation; either version 2 of the
- *     License, or (at your option) any later version.
- *
- *     This library is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- *     You should have received a copy of the GNU General Public
- *     License along with this library; if not, write to the Free
- *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
- *     MA 02110-1301 USA
- *
- * Alternatively,
- *
- *  b) 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
- */
-
-#include "libfdt.h"
-#include "libufdt_sysdeps.h"
-
-
-/*
- * Most of the codes below are copied from external/dtc/libfdt/libfdt_internal.h
- * and external/dtc/libfdt/fdt_sw.c .
- */
-
-#define FDT_ALIGN(x, a) (((x) + (a)-1) & ~((a)-1))
-#define FDT_TAGALIGN(x) (FDT_ALIGN((x), FDT_TAGSIZE))
-
-static inline const void *_fdt_offset_ptr(const void *fdt, int offset) {
-  return (const char *)fdt + fdt_off_dt_struct(fdt) + offset;
-}
-
-static inline void *_fdt_offset_ptr_w(void *fdt, int offset) {
-  return (void *)(uintptr_t)_fdt_offset_ptr(fdt, offset);
-}
-
-#define FDT_SW_MAGIC (~FDT_MAGIC)
-
-static int _fdt_sw_check_header(void *fdt) {
-  if (fdt_magic(fdt) != FDT_SW_MAGIC) return -FDT_ERR_BADMAGIC;
-  /* FIXME: should check more details about the header state */
-  return 0;
-}
-
-#define FDT_SW_CHECK_HEADER(fdt)                            \
-  {                                                         \
-    int err;                                                \
-    if ((err = _fdt_sw_check_header(fdt)) != 0) return err; \
-  }
-
-static void *_fdt_grab_space(void *fdt, size_t len) {
-  int offset = fdt_size_dt_struct(fdt);
-  int spaceleft;
-
-  spaceleft =
-      fdt_totalsize(fdt) - fdt_off_dt_struct(fdt) - fdt_size_dt_strings(fdt);
-
-  if ((offset + (int)len < offset) || (offset + (int)len > spaceleft))
-    return NULL;
-
-  fdt_set_size_dt_struct(fdt, offset + len);
-  return _fdt_offset_ptr_w(fdt, offset);
-}
-
-static const char *_fdt_find_string(const char *strtab, int tabsize,
-                                    const char *s) {
-  int len = dto_strlen(s) + 1;
-  const char *last = strtab + tabsize - len;
-  const char *p;
-
-  for (p = strtab; p <= last; p++)
-    if (dto_memcmp(p, s, len) == 0) return p;
-  return NULL;
-}
-
-static int _fdt_find_add_string(void *fdt, const char *s) {
-  char *strtab = (char *)fdt + fdt_totalsize(fdt);
-  const char *p;
-  int strtabsize = fdt_size_dt_strings(fdt);
-  int len = dto_strlen(s) + 1;
-  int struct_top, offset;
-
-  p = _fdt_find_string(strtab - strtabsize, strtabsize, s);
-  if (p) return p - strtab;
-
-  /* Add it */
-  offset = -strtabsize - len;
-  struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
-  if (fdt_totalsize(fdt) + offset < (size_t)struct_top)
-    return 0; /* no more room :( */
-
-  dto_memcpy(strtab + offset, s, len);
-  fdt_set_size_dt_strings(fdt, strtabsize + len);
-  return offset;
-}
-
-/*
- * From Google, speed up fdt_property() by passing nameoff to the function.
- * Adds new string to fdt if *pnameoff is 0.
- * Otherwise, use the nameoff provided.
- */
-static int fast_fdt_sw_property(void *fdt, const char *name, const void *val,
-                                int len, int *pnameoff,
-                                struct fdt_property **prop_ptr) {
-  FDT_SW_CHECK_HEADER(fdt);
-
-  if (*pnameoff == 0) {
-    *pnameoff = _fdt_find_add_string(fdt, name);
-    if (*pnameoff == 0) return -FDT_ERR_NOSPACE;
-  }
-
-  *prop_ptr = _fdt_grab_space(fdt, sizeof(**prop_ptr) + FDT_TAGALIGN(len));
-  if (*prop_ptr == NULL) return -FDT_ERR_NOSPACE;
-
-  (*prop_ptr)->tag = cpu_to_fdt32(FDT_PROP);
-  (*prop_ptr)->nameoff = cpu_to_fdt32(*pnameoff);
-  (*prop_ptr)->len = cpu_to_fdt32(len);
-  dto_memcpy((*prop_ptr)->data, val, len);
-  return 0;
-}
-
-#endif /* FDT_INTERNAL_H */
diff --git a/include/libufdt.h b/include/libufdt.h
index 4fc6965..c8e879a 100644
--- a/include/libufdt.h
+++ b/include/libufdt.h
@@ -6,79 +6,6 @@
 #include "ufdt_types.h"
 
 /*
- * BEGIN of ufdt_node_dict methods
- * Since in the current implementation, it's actually a hash table.
- * So most of operation's time complexity are O(1) with high probability
- * (w.h.p.).
- */
-
-/*
- * Allocates some new spaces and creates a new ufdt_node_dict.
- *
- * @return: a pointer to the newly created ufdt_node_dict or
- *          NULL if dto_malloc failed
- */
-struct ufdt_node_dict ufdt_node_dict_construct();
-
-/*
- * Frees all space dto_malloced, not including ufdt_nodes in the table.
- */
-void ufdt_node_dict_destruct(struct ufdt_node_dict *dict);
-
-/*
- * Adds a ufdt_node (as pointer) to the ufdt_node_dict.
- * @return: 0 if success
- *          < 0 otherwise
- *
- * @Time: O(length of node->name) w.h.p.
- */
-int ufdt_node_dict_add(struct ufdt_node_dict *dict, struct ufdt_node *node);
-
-/*
- * Returns the pointer to the entry in ufdt_node_dict with node->name =
- * name[0..len-1], for direct modification of the entry.
- * e.g., Delete an entry from the ufdt_node_dict.
- *
- * @return: a pointer to the entry in ufdt_node_dict or
- *          NULL if no such entry.
- *
- * @Time: O(len = |name|) w.h.p.
- */
-struct ufdt_node **ufdt_node_dict_find_len(struct ufdt_node_dict *dict,
-                                           const char *name, int len);
-struct ufdt_node **ufdt_node_dict_find(struct ufdt_node_dict *dict,
-                                       const char *name);
-
-/*
- * Returns the pointer to the ufdt_node with node->name =
- * name[0..len-1], for direct modification of the node.
- *
- * @return: a pointer to the node or
- *          NULL if no such node in ufdt_node_dict with same name.
- *
- * @Time: O(len = |name|) w.h.p.
- */
-struct ufdt_node *ufdt_node_dict_find_node_len(struct ufdt_node_dict *dict,
-                                               const char *name, int len);
-struct ufdt_node *ufdt_node_dict_find_node(struct ufdt_node_dict *dict,
-                                           const char *name);
-
-/*
- * Prints the each (index, node->name) pair in the dict to stdout in the
- * following format:
- * ```
- * [idx0] [name0]
- * [idx1] [name1]
- * ...
- * ```
- */
-void ufdt_node_dict_print(struct ufdt_node_dict *dict);
-
-/*
- * END of ufdt_node_dict methods
- */
-
-/*
  * BEGIN of ufdt_node methods
  */
 
@@ -95,7 +22,6 @@
 
 /*
  * Frees all nodes in the subtree rooted at *node.
- * Also dto_frees those ufdt_node_dicts in each node.
  */
 void ufdt_node_destruct(struct ufdt_node *node);
 
@@ -214,13 +140,31 @@
 struct ufdt *ufdt_construct(void *fdtp);
 
 /*
- * Frees the space occupied by the ufdt, including all ufdt_nodes and
- * ufdt_node_dicts along
+ * Frees the space occupied by the ufdt, including all ufdt_nodes
  * with static_phandle_table.
  */
 void ufdt_destruct(struct ufdt *tree);
 
 /*
+ * Add a fdt into this ufdt.
+ * Note that this function just add the given fdtp into this ufdt,
+ * and doesn't create any node.
+ *
+ * @return: 0 if success.
+ */
+int ufdt_add_fdt(struct ufdt *tree, void *fdtp);
+
+/*
+ * Calculate the offset in the string tables of the given string.
+ * All string tables will be concatenated in reversed order.
+ *
+ * @return: The offset is a negative number, base on the end position of
+ *          all concatenated string tables
+ *          Return 0 if not in any string table.
+ */
+int ufdt_get_string_off(const struct ufdt *tree, const char *s);
+
+/*
  * Gets the pointer to the ufdt_node in tree with phandle = phandle.
  * The function do a binary search in tree->phandle_table.
  *
@@ -327,9 +271,6 @@
 
 /*
  * Builds the ufdt for FDT pointed by fdtp.
- * This including build all ufdt_nodes and ufdt_node_dicts, and builds the
- * phandle table as
- * well.
  *
  * @return: the ufdt T representing fdtp or
  *          T with T.fdtp == NULL if fdtp is unvalid.
@@ -339,41 +280,17 @@
 struct ufdt *fdt_to_ufdt(void *fdtp, size_t fdt_size);
 
 /*
- * Sequentially dumps the tree rooted at *node to FDT buffer fdtp.
- * Basically it calls functions provided by libfdt/fdt_sw.c.
- *
- * All those functions works fast.
- * But when it comes to dump property node to fdt, the function they
- * provide(fdt_property()) is really slow. Since it runs through all strings
- * stored in fdt to find the right `nameoff` for the property node.
- *
- * So we implement our own fdt_property() called `output_property_to_fdt()`, the
- * basic
- * idea is that we keep a hash table that we can search for the nameoff of the
- * string in constant time instead of O(total length of strings) search.
- *
- * @return: 0 if successfully dump or
- *          < 0 otherwise
- *
- * @Time: O(total length of all names + # of nodes in subtree rooted at *root)
- */
-int output_ufdt_node_to_fdt(struct ufdt_node *node, void *fdtp,
-                            struct ufdt_node_dict *all_props);
-
-/*
  * Sequentially dumps the whole ufdt to FDT buffer fdtp with buffer size
  * buf_size.
- * Basically it calls functions provided by libfdt/fdt_sw.c.
- * The main overhead here is to dump the tree to fdtp by calling
- * output_ufdt_node_to_fdt().
  *
+ * Basically using functions provided by libfdt/fdt_sw.c.
  *
  * @return: 0 if successfully dump or
  *          < 0 otherwise
  *
  * @Time: O(total length of all names + # of nodes in tree)
  */
-int ufdt_to_fdt(struct ufdt *tree, void *buf, int buf_size);
+int ufdt_to_fdt(const struct ufdt *tree, void *buf, int buf_size);
 
 /*
  * prints the entire subtree rooted at *node in form:
diff --git a/include/ufdt_types.h b/include/ufdt_types.h
index a1d8118..01c45b9 100644
--- a/include/ufdt_types.h
+++ b/include/ufdt_types.h
@@ -3,23 +3,10 @@
 
 #include <libfdt.h>
 
-#define ASCII_PRINT_S (32)
-#define ASCII_PRINT_E (128)
-#define ASCII_PRINT_SZ (ASCII_PRINT_E - ASCII_PRINT_S)
-
-#define FDT_PROP_DELI ':'
-#define FDT_NODE_DELI '/'
-
-#define DTNL_INIT_SZ 4
-
-/* Empirical values for hash functions. */
-#define HASH_BASE 13131
-
 /* it has type : struct ufdt_node** */
-#define for_each(it, node_dict)                                  \
-  if ((node_dict) != NULL)                                       \
-    for (it = (node_dict)->nodes;                                \
-         it != (node_dict)->nodes + (node_dict)->mem_size; ++it) \
+#define for_each(it, node)                                                 \
+  if ((node) != NULL)                                                      \
+    for (it = (node)->nodes; it != (node)->nodes + (node)->mem_size; ++it) \
       if (*it)
 
 #define for_each_child(it, node)                                    \
@@ -49,12 +36,6 @@
   struct ufdt_node *sibling;
 };
 
-struct ufdt_node_dict {
-  int mem_size;
-  int num_used;
-  struct ufdt_node **nodes;
-};
-
 struct fdt_prop_ufdt_node {
   struct ufdt_node parent;
   const char *name;
@@ -77,7 +58,10 @@
 };
 
 struct ufdt {
-  void *fdtp;
+  void **fdtps;
+  int mem_size_fdtps;
+  int num_used_fdtps;
+
   struct ufdt_node *root;
   struct static_phandle_table phandle_table;
 };
diff --git a/ufdt_convert.c b/ufdt_convert.c
index b990c20..07c489e 100644
--- a/ufdt_convert.c
+++ b/ufdt_convert.c
@@ -1,23 +1,94 @@
 #include "libufdt.h"
 
-#include "fdt_internal.h"
-#include "ufdt_util.h"
-
+#include "ufdt_prop_dict.h"
 
 struct ufdt *ufdt_construct(void *fdtp) {
-  struct ufdt *res_ufdt = dto_malloc(sizeof(struct ufdt));
-  res_ufdt->fdtp = fdtp;
+  /* Inital size is 2, will be exponentially increased when it needed later.
+     (2 -> 4 -> 8 -> ...) */
+  const int DEFAULT_MEM_SIZE_FDTPS = 2;
+
+  void **fdtps = NULL;
+  struct ufdt *res_ufdt = NULL;
+
+  fdtps = (void **)dto_malloc(sizeof(void *) * DEFAULT_MEM_SIZE_FDTPS);
+  if (fdtps == NULL) goto error;
+  fdtps[0] = fdtp;
+
+  res_ufdt = dto_malloc(sizeof(struct ufdt));
+  if (res_ufdt == NULL) goto error;
+
+  res_ufdt->fdtps = fdtps;
+  res_ufdt->mem_size_fdtps = DEFAULT_MEM_SIZE_FDTPS;
+  res_ufdt->num_used_fdtps = (fdtp != NULL ? 1 : 0);
   res_ufdt->root = NULL;
 
   return res_ufdt;
+
+error:
+  if (res_ufdt) dto_free(res_ufdt);
+  if (fdtps) dto_free(fdtps);
+
+  return NULL;
 }
 
 void ufdt_destruct(struct ufdt *tree) {
+  if (tree == NULL) return;
+
   ufdt_node_destruct(tree->root);
+
+  dto_free(tree->fdtps);
   dto_free(tree->phandle_table.data);
   dto_free(tree);
 }
 
+int ufdt_add_fdt(struct ufdt *tree, void *fdtp) {
+  if (fdtp == NULL) {
+    return -1;
+  }
+
+  int i = tree->num_used_fdtps;
+  if (i >= tree->mem_size_fdtps) {
+    int new_size = tree->mem_size_fdtps * 2;
+    void **new_fdtps = dto_malloc(sizeof(void *) * new_size);
+    if (new_fdtps == NULL) return -1;
+
+    dto_memcpy(new_fdtps, tree->fdtps, sizeof(void *) * tree->mem_size_fdtps);
+    dto_free(tree->fdtps);
+
+    tree->fdtps = new_fdtps;
+    tree->mem_size_fdtps = new_size;
+  }
+
+  tree->fdtps[i] = fdtp;
+  tree->num_used_fdtps = i + 1;
+
+  return 0;
+}
+
+int ufdt_get_string_off(const struct ufdt *tree, const char *s) {
+  /* fdt_create() sets the dt_string_off to the end of fdt buffer,
+     and _ufdt_output_strtab_to_fdt() copy all string tables in reversed order.
+     So, here the return offset value is base on the end of all string buffers,
+     and it should be a minus value. */
+  int res_off = 0;
+  for (int i = 0; i < tree->num_used_fdtps; i++) {
+    void *fdt = tree->fdtps[i];
+    const char *strtab_start = (const char *)fdt + fdt_off_dt_strings(fdt);
+    int strtab_size = fdt_size_dt_strings(fdt);
+    const char *strtab_end = strtab_start + strtab_size;
+
+    /* Check if the string is in the string table */
+    if (s >= strtab_start && s < strtab_end) {
+      res_off += (s - strtab_end);
+      return res_off;
+    }
+
+    res_off -= strtab_size;
+  }
+  /* Can not find the string, return 0 */
+  return 0;
+}
+
 static struct ufdt_node *ufdt_new_node(void *fdtp, int node_offset) {
   if (fdtp == NULL) {
     dto_error("Failed to get new_node because tree is NULL\n");
@@ -72,7 +143,9 @@
   return res;
 }
 
-void ufdt_print(struct ufdt *tree) { ufdt_node_print(tree->root, 0); }
+void ufdt_print(struct ufdt *tree) {
+  ufdt_node_print(tree->root, 0);
+}
 
 struct ufdt_node *ufdt_get_node_by_path_len(struct ufdt *tree, const char *path,
                                             int len) {
@@ -241,16 +314,14 @@
 }
 
 struct ufdt *fdt_to_ufdt(void *fdtp, size_t fdt_size) {
-  (void)(fdt_size); // unused parameter
-
-  struct ufdt *res_tree = ufdt_construct(fdtp);
+  (void)(fdt_size); /* unused parameter */
 
   int start_offset = fdt_path_offset(fdtp, "/");
   if (start_offset < 0) {
-    res_tree->fdtp = NULL;
-    return res_tree;
+    return ufdt_construct(NULL);
   }
 
+  struct ufdt *res_tree = ufdt_construct(fdtp);
   int end_offset;
   int start_tag = fdt_next_tag(fdtp, start_offset, &end_offset);
   res_tree->root = fdt_to_ufdt_tree(fdtp, start_offset, &end_offset, start_tag);
@@ -260,30 +331,146 @@
   return res_tree;
 }
 
-int ufdt_to_fdt(struct ufdt *tree, void *buf, int buf_size) {
+static int _ufdt_get_property_nameoff(const struct ufdt *tree, const char *name,
+                                      const struct ufdt_prop_dict *dict) {
+  int res;
+  const struct fdt_property *same_name_prop = ufdt_prop_dict_find(dict, name);
+  if (same_name_prop != NULL) {
+    /* There is a property with same name, just use its string offset */
+    res = fdt32_to_cpu(same_name_prop->nameoff);
+  } else {
+    /* Get the string offset from the string table of the current tree */
+    res = ufdt_get_string_off(tree, name);
+    if (res == 0) {
+      dto_error("Cannot find property name in string table: %s\n", name);
+      return 0;
+    }
+  }
+  return res;
+}
+
+static int _ufdt_output_property_to_fdt(
+    const struct ufdt *tree, void *fdtp,
+    const struct fdt_prop_ufdt_node *prop_node, struct ufdt_prop_dict *dict) {
+  int nameoff = _ufdt_get_property_nameoff(tree, prop_node->name, dict);
+  if (nameoff == 0) return -1;
+
+  int data_len = 0;
+  void *data = ufdt_node_get_fdt_prop_data(&prop_node->parent, &data_len);
+  int aligned_data_len = (data_len + (FDT_TAGSIZE - 1)) & ~(FDT_TAGSIZE - 1);
+
+  int new_propoff = fdt_size_dt_struct(fdtp);
+  int new_prop_size = sizeof(struct fdt_property) + aligned_data_len;
+  struct fdt_property *new_prop =
+      (struct fdt_property *)((char *)fdtp + fdt_off_dt_struct(fdtp) +
+                              new_propoff);
+  char *fdt_end = (char *)fdtp + fdt_totalsize(fdtp);
+  if ((char *)new_prop + new_prop_size > fdt_end) {
+    dto_error("Not enough space for adding property.\n");
+    return -1;
+  }
+  fdt_set_size_dt_struct(fdtp, new_propoff + new_prop_size);
+
+  new_prop->tag = cpu_to_fdt32(FDT_PROP);
+  new_prop->nameoff = cpu_to_fdt32(nameoff);
+  new_prop->len = cpu_to_fdt32(data_len);
+  dto_memcpy(new_prop->data, data, data_len);
+
+  ufdt_prop_dict_add(dict, new_prop);
+
+  return 0;
+}
+
+static int _ufdt_output_node_to_fdt(const struct ufdt *tree, void *fdtp,
+                                    const struct ufdt_node *node,
+                                    struct ufdt_prop_dict *dict) {
+  uint32_t tag = tag_of(node);
+
+  if (tag == FDT_PROP) {
+    return _ufdt_output_property_to_fdt(
+        tree, fdtp, (const struct fdt_prop_ufdt_node *)node, dict);
+  }
+
+  int err = fdt_begin_node(fdtp, name_of(node));
+  if (err < 0) return -1;
+
+  struct ufdt_node **it;
+  for_each_prop(it, node) {
+    err = _ufdt_output_node_to_fdt(tree, fdtp, *it, dict);
+    if (err < 0) return -1;
+  }
+
+  for_each_node(it, node) {
+    err = _ufdt_output_node_to_fdt(tree, fdtp, *it, dict);
+    if (err < 0) return -1;
+  }
+
+  err = fdt_end_node(fdtp);
+  if (err < 0) return -1;
+
+  return 0;
+}
+
+static int _ufdt_output_strtab_to_fdt(const struct ufdt *tree, void *fdt) {
+  /* Currently, we don't know the final dt_struct size, so we copy all
+     string tables to the end of the target fdt buffer in reversed order.
+     At last, fdt_finish() will adjust dt_string offset */
+  const char *struct_top =
+      (char *)fdt + fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
+  char *dest = (char *)fdt + fdt_totalsize(fdt);
+
+  int dest_size = 0;
+  for (int i = 0; i < tree->num_used_fdtps; i++) {
+    void *src_fdt = tree->fdtps[i];
+    const char *src_strtab = (const char *)src_fdt + fdt_off_dt_strings(src_fdt);
+    int strtab_size = fdt_size_dt_strings(src_fdt);
+
+    dest -= strtab_size;
+    if (dest < struct_top) {
+      dto_error("Not enough space for string table.\n");
+      return -1;
+    }
+
+    dto_memcpy(dest, src_strtab, strtab_size);
+
+    dest_size += strtab_size;
+  }
+
+  fdt_set_size_dt_strings(fdt, dest_size);
+
+  return 0;
+}
+
+int ufdt_to_fdt(const struct ufdt *tree, void *buf, int buf_size) {
+  if (tree->num_used_fdtps == 0) return -1;
+
   int err;
   err = fdt_create(buf, buf_size);
   if (err < 0) return -1;
 
-  int n_mem_rsv = fdt_num_mem_rsv(tree->fdtp);
+  /* Here we output the memory reserve map of the ONLY FIRST fdt,
+     to be in compliance with the DTO behavior of libfdt. */
+  int n_mem_rsv = fdt_num_mem_rsv(tree->fdtps[0]);
   for (int i = 0; i < n_mem_rsv; i++) {
     uint64_t addr, size;
-    fdt_get_mem_rsv(tree->fdtp, i, &addr, &size);
+    fdt_get_mem_rsv(tree->fdtps[0], i, &addr, &size);
     fdt_add_reservemap_entry(buf, addr, size);
   }
 
   err = fdt_finish_reservemap(buf);
   if (err < 0) return -1;
 
-  /*
-   * Obtains all props for later use because getting them from
-   * FDT requires complicated manipulation.
-  */
-  struct ufdt_node_dict all_props = ufdt_node_dict_construct();
-  err = output_ufdt_node_to_fdt(tree->root, buf, &all_props);
+  err = _ufdt_output_strtab_to_fdt(tree, buf);
   if (err < 0) return -1;
 
-  ufdt_node_dict_destruct(&all_props);
+  struct ufdt_prop_dict dict;
+  err = ufdt_prop_dict_construct(&dict, buf);
+  if (err < 0) return -1;
+
+  err = _ufdt_output_node_to_fdt(tree, buf, tree->root, &dict);
+  if (err < 0) return -1;
+
+  ufdt_prop_dict_destruct(&dict);
 
   err = fdt_finish(buf);
   if (err < 0) return -1;
diff --git a/ufdt_node.c b/ufdt_node.c
index 6ff4dc1..5a63df7 100644
--- a/ufdt_node.c
+++ b/ufdt_node.c
@@ -1,6 +1,4 @@
 #include "libufdt.h"
-#include "ufdt_util.h"
-
 
 int node_cmp(const void *a, const void *b) {
   const struct ufdt_node *na = *(struct ufdt_node **)a;
@@ -23,11 +21,12 @@
 struct ufdt_node *ufdt_node_construct(void *fdtp, fdt32_t *fdt_tag_ptr) {
   uint32_t tag = fdt32_to_cpu(*fdt_tag_ptr);
   if (tag == FDT_PROP) {
+    const struct fdt_property *prop = (const struct fdt_property *)fdt_tag_ptr;
     struct fdt_prop_ufdt_node *res = dto_malloc(sizeof(struct fdt_prop_ufdt_node));
     if (res == NULL) return NULL;
     res->parent.fdt_tag_ptr = fdt_tag_ptr;
     res->parent.sibling = NULL;
-    res->name = get_name(fdtp, (struct ufdt_node *)res);
+    res->name = fdt_string(fdtp, fdt32_to_cpu(prop->nameoff));
     return (struct ufdt_node *)res;
   } else {
     struct fdt_node_ufdt_node *res = dto_malloc(sizeof(struct fdt_node_ufdt_node));
@@ -192,66 +191,6 @@
  * END of searching-in-ufdt_node methods.
  */
 
-int output_property_to_fdt(struct ufdt_node *prop_node, void *fdtp,
-                           struct ufdt_node_dict *props_dict) {
-  int err = 0;
-  int len = 0;
-  void *data = ufdt_node_get_fdt_prop_data(prop_node, &len);
-  int nameoff = 0;
-  struct ufdt_node *same_name_prop =
-      ufdt_node_dict_find_node(props_dict, name_of(prop_node));
-
-  /*
-   * There's already a property with same name, take its nameoff instead.
-   */
-  if (same_name_prop != NULL) {
-    const struct fdt_property *prop =
-        (const struct fdt_property *)same_name_prop->fdt_tag_ptr;
-    nameoff = fdt32_to_cpu(prop->nameoff);
-  }
-  /*
-   * Modifies prop_node->fdt_tag_ptr to point to the node in new fdtp.
-   */
-  err = fast_fdt_sw_property(fdtp, name_of(prop_node), data, len, &nameoff,
-                             (struct fdt_property **)&(prop_node->fdt_tag_ptr));
-
-  if (err < 0) {
-    dto_error("Not enough space for the string space: %d\n",
-              fdt_size_dt_strings(fdtp));
-  }
-  ufdt_node_dict_add(props_dict, prop_node);
-  return err;
-}
-
-int output_ufdt_node_to_fdt(struct ufdt_node *node, void *fdtp,
-                            struct ufdt_node_dict *props_dict) {
-  uint32_t tag = tag_of(node);
-
-  if (tag == FDT_PROP) {
-    int err = output_property_to_fdt(node, fdtp, props_dict);
-    return err;
-  }
-
-  int err = fdt_begin_node(fdtp, name_of(node));
-  if (err < 0) return -1;
-
-  struct ufdt_node **it;
-  for_each_prop(it, node) {
-    err = output_ufdt_node_to_fdt(*it, fdtp, props_dict);
-    if (err < 0) return -1;
-  }
-
-  for_each_node(it, node) {
-    err = output_ufdt_node_to_fdt(*it, fdtp, props_dict);
-    if (err < 0) return -1;
-  }
-
-  err = fdt_end_node(fdtp);
-  if (err < 0) return -1;
-
-  return 0;
-}
-
 #define TAB_SIZE 2
 
 void ufdt_node_print(const struct ufdt_node *node, int depth) {
diff --git a/ufdt_node_dict.c b/ufdt_node_dict.c
deleted file mode 100644
index 448bc49..0000000
--- a/ufdt_node_dict.c
+++ /dev/null
@@ -1,178 +0,0 @@
-
-#include "libufdt.h"
-#include "ufdt_util.h"
-
-/*
- * BEGIN of Hash table internal implementations.
- */
-
-#define DICT_LIMIT_NUM 2
-#define DICT_LIMIT_DEN 3
-
-static bool _ufdt_node_dict_is_too_full(struct ufdt_node_dict *dict) {
-  /*
-   * We say a dict is too full if it's DICT_LIMIT_NUM / DICT_LIMIT_DEN full.
-   */
-  if (dict->num_used * DICT_LIMIT_DEN > dict->mem_size * DICT_LIMIT_NUM)
-    return true;
-  return false;
-}
-
-/*
- * If collision happened, use linear probing to find idx in the hash table.
- */
-static int _ufdt_node_dict_find_index_by_name_len(struct ufdt_node **hash_table,
-                                                  int size, const char *name,
-                                                  int len) {
-  if (!name || !size) return -1;
-  /*
-   * All size should be 2^k for some k
-   */
-  int hsh = get_hash_len(name, len);
-  int idx = hsh & (size - 1);
-  for (int cnt = 0; cnt < size; ++cnt) {
-    if (hash_table[idx] == NULL) return idx;
-    if (node_name_eq(hash_table[idx], name, len) == 1) return idx;
-    ++idx;
-    idx &= (size - 1);
-  }
-  return -1;
-}
-
-static int _ufdt_node_dict_find_index_by_name(struct ufdt_node **hash_table,
-                                              int size, const char *name) {
-  return _ufdt_node_dict_find_index_by_name_len(hash_table, size, name,
-                                                dto_strlen(name));
-}
-
-static int _ufdt_node_dict_find_index_in_ht(struct ufdt_node **hash_table,
-                                            int size, struct ufdt_node *x) {
-  if (x == NULL) return -1;
-  return _ufdt_node_dict_find_index_by_name(hash_table, size, name_of(x));
-}
-
-/*
- * END of Hash table internal implementations.
- */
-
-/*
- * ufdt_node_dict methods.
- */
-
-struct ufdt_node_dict ufdt_node_dict_construct() {
-  struct ufdt_node_dict res;
-  res.mem_size = DTNL_INIT_SZ;
-  res.num_used = 0;
-  res.nodes = dto_malloc(DTNL_INIT_SZ * sizeof(struct ufdt_node *));
-  if (res.nodes == NULL) {
-    res.mem_size = 0;
-    return res;
-  }
-  dto_memset(res.nodes, 0, DTNL_INIT_SZ * sizeof(struct ufdt_node *));
-  return res;
-}
-
-void ufdt_node_dict_destruct(struct ufdt_node_dict *dict) {
-  if (dict == NULL) return;
-  dto_free(dict->nodes);
-  dict->mem_size = dict->num_used = 0;
-}
-
-static int ufdt_node_dict_resize(struct ufdt_node_dict *dict) {
-  if (dict == NULL) return -1;
-
-  int new_size = dict->mem_size << 1;
-
-  struct ufdt_node **new_nodes =
-      dto_malloc(new_size * sizeof(struct ufdt_node *));
-
-  dto_memset(new_nodes, 0, new_size * sizeof(struct ufdt_node *));
-
-  for (int i = 0; i < dict->mem_size; i++) {
-    struct ufdt_node *node = dict->nodes[i];
-    if (node == NULL) continue;
-    int idx = _ufdt_node_dict_find_index_in_ht(new_nodes, new_size, node);
-    if (idx < 0) {
-      dto_error(
-          "failed to find new index in ufdt_node_dict resize for entry :%s:\n",
-          name_of(node));
-      dto_free(new_nodes);
-      return -1;
-    }
-    new_nodes[idx] = node;
-  }
-
-  dto_free(dict->nodes);
-
-  dict->mem_size = new_size;
-  dict->nodes = new_nodes;
-  return 0;
-}
-
-int ufdt_node_dict_add(struct ufdt_node_dict *dict, struct ufdt_node *node) {
-  if (node == NULL) return -1;
-  if (dict == NULL) return -1;
-
-  int idx = _ufdt_node_dict_find_index_in_ht(dict->nodes, dict->mem_size, node);
-  if (idx < 0) {
-    dto_error("failed to find new index in ufdt_node_dict add for entry :%s:\n",
-              name_of(node));
-    return -1;
-  }
-
-  if (dict->nodes[idx] == NULL) ++dict->num_used;
-  dict->nodes[idx] = node;
-
-  /*
-   * When the hash table is too full, double the size and rehashing.
-   */
-  int err = 0;
-  if (_ufdt_node_dict_is_too_full(dict)) {
-    err = ufdt_node_dict_resize(dict);
-  }
-
-  return err;
-}
-
-/*
- * BEGIN of ufdt_dict searching related methods.
- */
-
-/*
- * return a pointer to the hash table entry
- */
-struct ufdt_node **ufdt_node_dict_find_len(struct ufdt_node_dict *dict,
-                                           const char *name, int len) {
-  if (dict == NULL) return NULL;
-  int idx = _ufdt_node_dict_find_index_by_name_len(dict->nodes, dict->mem_size,
-                                                   name, len);
-  if (idx < 0) return NULL;
-  if (dict->nodes[idx] == NULL) return NULL;
-  return dict->nodes + idx;
-}
-
-struct ufdt_node **ufdt_node_dict_find(struct ufdt_node_dict *dict,
-                                       const char *name) {
-  return ufdt_node_dict_find_len(dict, name, dto_strlen(name));
-}
-
-struct ufdt_node *ufdt_node_dict_find_node_len(struct ufdt_node_dict *dict,
-                                               const char *name, int len) {
-  struct ufdt_node **res = ufdt_node_dict_find_len(dict, name, len);
-  if (res == NULL) return NULL;
-  return *res;
-}
-
-struct ufdt_node *ufdt_node_dict_find_node(struct ufdt_node_dict *dict,
-                                           const char *name) {
-  return ufdt_node_dict_find_node_len(dict, name, dto_strlen(name));
-}
-
-/*
- * END of ufdt_dict searching related methods.
- */
-
-void ufdt_node_dict_print(struct ufdt_node_dict *dict) {
-  struct ufdt_node **it;
-  for_each(it, dict) dto_print("%ld -> %s\n", it - dict->nodes, name_of(*it));
-}
diff --git a/ufdt_overlay.c b/ufdt_overlay.c
index 05f949f..d6e250e 100644
--- a/ufdt_overlay.c
+++ b/ufdt_overlay.c
@@ -540,8 +540,24 @@
 
 /* END of updating local references (phandle values) in the overlay ufdt. */
 
+static int _ufdt_overlay_fdtps(struct ufdt *main_tree,
+                               const struct ufdt *overlay_tree) {
+  for (int i = 0; i < overlay_tree->num_used_fdtps; i++) {
+    void *fdt = overlay_tree->fdtps[i];
+    if (ufdt_add_fdt(main_tree, fdt) < 0) {
+      return -1;
+    }
+  }
+  return 0;
+}
+
 static int ufdt_overlay_apply(struct ufdt *main_tree, struct ufdt *overlay_tree,
                               size_t overlay_length) {
+  if (_ufdt_overlay_fdtps(main_tree, overlay_tree) < 0) {
+    dto_error("failed to add more fdt into main ufdt tree.\n");
+    return -1;
+  }
+
   if (overlay_length < sizeof(struct fdt_header)) {
     dto_error("Overlay_length %zu smaller than header size %zu\n",
               overlay_length, sizeof(struct fdt_header));
diff --git a/ufdt_prop_dict.c b/ufdt_prop_dict.c
new file mode 100644
index 0000000..93bdfb3
--- /dev/null
+++ b/ufdt_prop_dict.c
@@ -0,0 +1,131 @@
+#include "ufdt_prop_dict.h"
+
+#include "libfdt.h"
+
+#include "libufdt_sysdeps.h"
+
+#define UFDT_PROP_DICT_INIT_SZ 4
+
+/* Empirical values for hash functions. */
+#define HASH_BASE 13131
+
+#define DICT_LIMIT_NUM 2
+#define DICT_LIMIT_DEN 3
+
+static int _ufdt_prop_dict_str_hash(const char *str) {
+  int res = 0;
+
+  for (; *str != '\0'; str++) {
+    res *= HASH_BASE;
+    res += *str;
+  }
+
+  return res;
+}
+
+static const struct fdt_property **_ufdt_prop_dict_find_index_by_name(
+    const struct ufdt_prop_dict *dict, const char *name) {
+  /* size should be 2^k for some k */
+  int hash = _ufdt_prop_dict_str_hash(name);
+  int size = dict->mem_size;
+  int idx = hash & (size - 1);
+  /* If collision, use linear probing to find idx in the hash table */
+  for (int i = 0; i < size; i++) {
+    const struct fdt_property **prop_ptr = &dict->props[idx];
+    const struct fdt_property *prop = *prop_ptr;
+    if (prop == NULL) return prop_ptr;
+
+    const char *prop_name = fdt_string(dict->fdtp, fdt32_to_cpu(prop->nameoff));
+    if (dto_strcmp(prop_name, name) == 0) return prop_ptr;
+
+    idx = (idx + 1) & (size - 1);
+  }
+  return NULL;
+}
+
+static const struct fdt_property **_ufdt_prop_dict_find_index(
+    struct ufdt_prop_dict *dict, const struct fdt_property *prop) {
+  const char *name = fdt_string(dict->fdtp, fdt32_to_cpu(prop->nameoff));
+
+  return _ufdt_prop_dict_find_index_by_name(dict, name);
+}
+
+int _ufdt_prop_dict_construct_int(struct ufdt_prop_dict *dict, void *fdtp,
+                                  int size) {
+  const size_t entry_size = sizeof(const struct fdt_property *);
+  const struct fdt_property **props =
+      (const struct fdt_property **)dto_malloc(size * entry_size);
+  if (props == NULL) return -1;
+  dto_memset(props, 0, size * entry_size);
+
+  dict->mem_size = size;
+  dict->num_used = 0;
+  dict->fdtp = fdtp;
+  dict->props = props;
+
+  return 0;
+}
+
+int ufdt_prop_dict_construct(struct ufdt_prop_dict *dict, void *fdtp) {
+  return _ufdt_prop_dict_construct_int(dict, fdtp, UFDT_PROP_DICT_INIT_SZ);
+}
+
+void ufdt_prop_dict_destruct(struct ufdt_prop_dict *dict) {
+  if (dict == NULL) return;
+
+  dto_free(dict->props);
+}
+
+static int _ufdt_prop_dict_enlarge_if_needed(struct ufdt_prop_dict *dict) {
+  if (dict == NULL) return -1;
+
+  /* Enlarge if the used number over than DICT_LIMIT_NUM / DICT_LIMIT_DEN */
+  if (dict->num_used * DICT_LIMIT_DEN <= dict->mem_size * DICT_LIMIT_NUM) {
+    return 0;
+  }
+
+  int new_size = dict->mem_size * 2;
+  struct ufdt_prop_dict temp_dict;
+  _ufdt_prop_dict_construct_int(&temp_dict, dict->fdtp, new_size);
+
+  for (int i = 0; i < dict->mem_size; i++) {
+    const struct fdt_property *prop = dict->props[i];
+    if (prop == NULL) continue;
+    const struct fdt_property **new_prop_ptr =
+        _ufdt_prop_dict_find_index(&temp_dict, prop);
+    if (new_prop_ptr == NULL) {
+      dto_error("ufdt_prop_dict: failed to find new index when enlarging.\n");
+      ufdt_prop_dict_destruct(&temp_dict);
+      return -1;
+    }
+    *new_prop_ptr = prop;
+  }
+
+  dto_free(dict->props);
+
+  dict->mem_size = new_size;
+  dict->props = temp_dict.props;
+
+  return 0;
+}
+
+int ufdt_prop_dict_add(struct ufdt_prop_dict *dict,
+                       const struct fdt_property *prop) {
+  const struct fdt_property **prop_ptr = _ufdt_prop_dict_find_index(dict, prop);
+  if (prop_ptr == NULL) {
+    dto_error("ufdt_prop_dict: failed to find new index when adding.\n");
+    return -1;
+  }
+
+  if (*prop_ptr == NULL) dict->num_used++;
+  *prop_ptr = prop;
+
+  return _ufdt_prop_dict_enlarge_if_needed(dict);
+}
+
+const struct fdt_property *ufdt_prop_dict_find(const struct ufdt_prop_dict *dict,
+                                               const char *name) {
+  const struct fdt_property **prop_ptr =
+      _ufdt_prop_dict_find_index_by_name(dict, name);
+  return prop_ptr ? *prop_ptr : NULL;
+}
diff --git a/ufdt_prop_dict.h b/ufdt_prop_dict.h
new file mode 100644
index 0000000..5f0d84f
--- /dev/null
+++ b/ufdt_prop_dict.h
@@ -0,0 +1,47 @@
+#ifndef UFDT_PROP_DICT_H
+#define UFDT_PROP_DICT_H
+
+struct fdt_property;
+
+struct ufdt_prop_dict {
+  int mem_size;
+  int num_used;
+  void *fdtp;
+  const struct fdt_property **props;
+};
+
+/*
+ * Allocates some new spaces and creates a new ufdt_prop_dict.
+ *
+ * @return: a pointer to the newly created ufdt_prop_dict or
+ *          NULL if dto_malloc failed
+ */
+int ufdt_prop_dict_construct(struct ufdt_prop_dict *dict, void *fdtp);
+
+/*
+ * Frees all space dto_malloced, not including ufdt_nodes in the table.
+ */
+void ufdt_prop_dict_destruct(struct ufdt_prop_dict *dict);
+
+/*
+ * Adds a fdt_property (as pointer) to the ufdt_prop_dict.
+ * @return: 0 if success
+ *          < 0 otherwise
+ *
+ * @Time: O(length of node->name)
+ */
+int ufdt_prop_dict_add(struct ufdt_prop_dict *dict,
+                       const struct fdt_property *prop);
+
+/*
+ * Returns the pointer to the fdt_property with name
+ *
+ * @return: a pointer to the node or
+ *          NULL if no such node in ufdt_prop_dict with same name.
+ *
+ * @Time: O(len = |name|)
+ */
+const struct fdt_property *ufdt_prop_dict_find(const struct ufdt_prop_dict *dict,
+                                               const char *name);
+
+#endif
diff --git a/ufdt_util.h b/ufdt_util.h
deleted file mode 100644
index ccd7f76..0000000
--- a/ufdt_util.h
+++ /dev/null
@@ -1,60 +0,0 @@
-
-#ifndef UFDT_UTIL_H
-#define UFDT_UTIL_H
-
-#include "fdt_internal.h"
-#include "ufdt_types.h"
-
-static const char *tag_name(uint32_t tag) {
-  switch (tag) {
-    case FDT_BEGIN_NODE:
-      return "FDT_BEGIN_NODE";
-    case FDT_END_NODE:
-      return "FDT_END_NODE";
-    case FDT_PROP:
-      return "FDT_PROP";
-    case FDT_END:
-      return "FDT_END";
-  }
-  return "";
-}
-
-static const char *get_name(void *fdtp, struct ufdt_node *node) {
-  if (!fdtp || !node) return NULL;
-
-  const struct fdt_node_header *nh;
-  const struct fdt_property *prop;
-
-  uint32_t tag = tag_of(node);
-
-  switch (tag) {
-    case FDT_BEGIN_NODE:
-      nh = (const struct fdt_node_header *)node->fdt_tag_ptr;
-      return nh->name;
-    case FDT_PROP:
-      prop = (const struct fdt_property *)node->fdt_tag_ptr;
-      return fdt_string(fdtp, fdt32_to_cpu(prop->nameoff));
-    default:
-      return "";
-  }
-}
-
-static const void *value_of(const struct ufdt_node *node) {
-  if (!node) {
-    dto_error( "Failed to get value since tree or node is NULL\n");
-    return NULL;
-  }
-  return node->fdt_tag_ptr;
-}
-
-static int get_hash_len(const char *str, int len) {
-  int res = 0;
-  for (int i = 0; i < len; i++) {
-    res = res * HASH_BASE;
-    res = res + str[i];
-  }
-  return res;
-}
-static int get_hash(const char *str) { return get_hash_len(str, dto_strlen(str)); }
-
-#endif /* UFDT_UTIL_H */