At present the Fdt class does not keep track of property offsets if they
change due to removal of properties. Update the code to handle this, and
add a test.
Signed-off-by: Simon Glass
---
Changes in v2: None
tools/dtoc/fdt.py | 20 +
tools/dtoc/test_fdt.py | 65 +-
2 files changed, 78 insertions(+), 7 deletions(-)
diff --git a/tools/dtoc/fdt.py b/tools/dtoc/fdt.py
index fd016bb8ce..274c142e7a 100644
--- a/tools/dtoc/fdt.py
+++ b/tools/dtoc/fdt.py
@@ -49,6 +49,9 @@ class Prop:
return
self.type, self.value = self.BytesToValue(bytes)
+def RefreshOffset(self, poffset):
+self._offset = poffset
+
def Widen(self, newprop):
"""Figure out which property type is more general
@@ -154,6 +157,7 @@ class Prop:
Returns:
The offset of the property (struct fdt_property) within the file
"""
+self._node._fdt.CheckCache()
return self._node._fdt.GetStructOffset(self._offset)
class Node:
@@ -233,8 +237,23 @@ class Node:
self._offset = my_offset
offset = fdt_obj.first_subnode(self._offset, QUIET_NOTFOUND)
for subnode in self.subnodes:
+if subnode.name != fdt_obj.get_name(offset):
+raise ValueError('Internal error, node name mismatch %s != %s'
%
+ (subnode.name, fdt_obj.get_name(offset)))
subnode.Refresh(offset)
offset = fdt_obj.next_subnode(offset, QUIET_NOTFOUND)
+if offset != -libfdt.FDT_ERR_NOTFOUND:
+raise ValueError('Internal error, offset == %d' % offset)
+
+poffset = fdt_obj.first_property_offset(self._offset, QUIET_NOTFOUND)
+while poffset >= 0:
+p = fdt_obj.get_property_by_offset(poffset)
+prop = self.props.get(p.name)
+if not prop:
+raise ValueError("Internal error, property '%s' missing, "
+ 'offset %d' % (p.name, poffset))
+prop.RefreshOffset(poffset)
+poffset = fdt_obj.next_property_offset(poffset, QUIET_NOTFOUND)
def DeleteProp(self, prop_name):
"""Delete a property of a node
@@ -278,6 +297,7 @@ class Fdt:
TODO(s...@chromium.org): Implement the 'root' parameter
"""
+self._cached_offsets = True
self._root = self.Node(self, None, 0, '/', '/')
self._root.Scan()
diff --git a/tools/dtoc/test_fdt.py b/tools/dtoc/test_fdt.py
index d44e4dd842..e57298dbe7 100755
--- a/tools/dtoc/test_fdt.py
+++ b/tools/dtoc/test_fdt.py
@@ -24,6 +24,30 @@ import libfdt
import test_util
import tools
+def _GetPropertyValue(dtb, node, prop_name):
+"""Low-level function to get the property value based on its offset
+
+This looks directly in the device tree at the property's offset to find
+its value. It is useful as a check that the property is in the correct
+place.
+
+Args:
+node: Node to look in
+prop_name: Property name to find
+
+Returns:
+Tuple:
+Prop object found
+Value of property as a string (found using property offset)
+"""
+prop = node.props[prop_name]
+
+# Add 12, which is sizeof(struct fdt_property), to get to start of data
+offset = prop.GetOffset() + 12
+data = dtb.GetContents()[offset:offset + len(prop.value)]
+return prop, [chr(x) for x in data]
+
+
class TestFdt(unittest.TestCase):
"""Tests for the Fdt module
@@ -124,6 +148,12 @@ class TestNode(unittest.TestCase):
with self.assertRaises(libfdt.FdtException):
self.node.DeleteProp('missing')
+def testDeleteGetOffset(self):
+"""Test that property offset update when properties are deleted"""
+self.node.DeleteProp('intval')
+prop, value = _GetPropertyValue(self.dtb, self.node, 'longbytearray')
+self.assertEqual(prop.value, value)
+
def testFindNode(self):
"""Tests that we can find a node using the _FindNode() functoin"""
node = self.dtb.GetRoot()._FindNode('i2c@0')
@@ -132,6 +162,32 @@ class TestNode(unittest.TestCase):
self.assertEqual('pmic@9', subnode.name)
self.assertEqual(None, node._FindNode('missing'))
+def testRefreshMissingNode(self):
+"""Test refreshing offsets when an extra node is present in dtb"""
+# Delete it from our tables, not the device tree
+del self.dtb._root.subnodes[-1]
+with self.assertRaises(ValueError) as e:
+self.dtb.Refresh()
+self.assertIn('Internal error, offset', str(e.exception))
+
+def testRefreshExtraNode(self):
+"""Test refreshing offsets when an expected node is missing"""
+# Delete it from the device tre, not our tables
+self.dtb.GetFdtObj().del_node(self.node.Offset())
+with self.assertRaises(ValueError) as e:
+self.dtb.Refresh()
+