Python FDT Bindings
pylibfdt is a Python binding for the C library `libfdt`, providing functionality to parse, manipulate, and generate Device Tree Blobs (DTBs). It offers a Pythonic interface to access nodes, properties, and iterate through the device tree structure. Currently at version 1.7.2.post1, the library maintains a stable API with infrequent but significant updates, primarily tracking upstream `libfdt` changes.
Common errors
-
ImportError: cannot import name 'Fdt' from 'pylibfdt'
cause `pylibfdt` is not installed, or the current Python environment does not have it installed.fixEnsure `pylibfdt` is installed in your active environment: `pip install pylibfdt`. -
pylibfdt.FdtException: Fdt file magic missing
cause The file or bytes provided to `Fdt()` is not a valid Device Tree Blob (DTB) and does not start with the expected magic number (`0xd00dfeed`).fixVerify that the input file path is correct and points to a properly formatted `.dtb` file, usually generated by the Device Tree Compiler (`dtc`). If providing bytes, ensure they represent a valid DTB. -
AttributeError: 'NoneType' object has no attribute 'value'
cause You attempted to access `.value` on a property object that was `None`. This typically happens when `node.get_property('some_name')` returned `None` because the property does not exist for that node.fixAlways check if the property object is not `None` before attempting to access its attributes. Example: `prop = node.get_property('some_name'); if prop: print(prop.value)`.
Warnings
- gotcha Property values accessed via `prop.value` can be of type `bytes`, `int`, or `str` depending on the property definition in the DTB. You often need to explicitly `decode('utf-8')` byte values if expecting a string, and handle `strip('\x00')` for null-terminated strings.
- gotcha Methods like `fdt.get_node()` and `node.get_property()` return `None` if the requested node or property does not exist. Failing to check for `None` before attempting to access attributes (e.g., `node.name`, `prop.value`) will result in an `AttributeError`.
- gotcha When installing `pylibfdt` from source (e.g., if no wheel is available for your platform/Python version), you will need the `libfdt` C library development headers installed on your system. This is a common requirement for Python bindings to C libraries.
Install
-
pip install pylibfdt
Imports
- Fdt
from pylibfdt import Fdt
Quickstart
from pylibfdt import Fdt
import os
# For demonstration, create a dummy DTB file if it doesn't exist
# In a real scenario, you'd load an existing .dtb file
dummy_dtb_path = "example.dtb"
if not os.path.exists(dummy_dtb_path):
# This is a very minimal valid DTB structure (version 16, no nodes)
# Actual DTBs are much more complex. This only serves to avoid FdtException on a non-existent file.
# A true example would require external tools to generate a valid DTB.
# For real use, ensure 'example.dtb' is a valid DTB created by dtc.
try:
# Attempt to create a placeholder or indicate requirement for a real DTB
# Cannot easily generate a valid DTB from scratch within Python for quickstart.
# Assume a valid 'test.dtb' exists for proper execution.
print(f"Please ensure a valid DTB file named '{dummy_dtb_path}' exists for a meaningful quickstart.")
# For strict runnable, we will use a byte literal that is a minimal valid FDT header.
# This will load, but won't have any actual nodes or properties.
minimal_fdt_bytes = b'\xd0\x0d\xfe\xed\x00\x00\x00\x01\x00\x00\x00\x28\x00\x00\x00\x30\x00\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
fdt = Fdt(dtb=minimal_fdt_bytes)
print("Loaded minimal FDT from bytes.")
except Exception as e:
print(f"Could not create dummy DTB or load minimal FDT bytes: {e}")
print("Skipping quickstart example as no valid DTB could be loaded.")
exit()
else:
try:
fdt = Fdt(filename=dummy_dtb_path)
print(f"Loaded FDT from file: {dummy_dtb_path}")
except Exception as e:
print(f"Error loading {dummy_dtb_path}: {e}")
print("Skipping quickstart example due to DTB loading error.")
exit()
# Get the root node
root_node = fdt.get_node('/')
if root_node:
print(f"Root node name: {root_node.name}")
# Walk the tree (if there are any nodes in the loaded FDT)
print("\nWalking FDT nodes:")
found_nodes = False
for node in fdt.walk():
print(f" Node: {node.name} (path: {node.path})")
for prop in node.properties:
# Property values can be bytes, strings, or integers
value = prop.value
if isinstance(value, bytes):
try:
value = value.decode('utf-8').strip('\x00') # Try decoding if it's a string
except UnicodeDecodeError:
pass # Keep as bytes if not a valid utf-8 string
print(f" Property: {prop.name} = {value}")
found_nodes = True
if not found_nodes:
print(" No nodes found in the FDT (might be a minimal FDT header).")
else:
print("Could not get root node.")
# Example of getting a specific node and property (if they exist)
# This assumes a more complex DTB than the minimal header.
# For a real DTB, you might look for '/chosen' or '/aliases'
chosen_node = fdt.get_node('/chosen')
if chosen_node:
print(f"\nFound node: {chosen_node.path}")
bootargs_prop = chosen_node.get_property('bootargs')
if bootargs_prop:
print(f" Bootargs: {bootargs_prop.value.decode('utf-8')}")
else:
print(" 'bootargs' property not found in /chosen.")
else:
print("Node '/chosen' not found (this is common for minimal DTBs).")