diff --git a/src/main/java/devicetreeblob/DeviceTreeBlobPlugin.java b/src/main/java/devicetreeblob/DeviceTreeBlobPlugin.java index 761f4d5..262d9ff 100644 --- a/src/main/java/devicetreeblob/DeviceTreeBlobPlugin.java +++ b/src/main/java/devicetreeblob/DeviceTreeBlobPlugin.java @@ -17,9 +17,14 @@ import java.io.File; import java.io.IOException; +import java.text.ParseException; +import java.util.List; +import java.util.stream.Collectors; import javax.swing.JComponent; +import devicetreeblob.DtbParser.Block; +import devicetreeblob.DtbParser.Block.Reg; import docking.action.builder.ActionBuilder; import docking.tool.ToolConstants; import docking.widgets.filechooser.GhidraFileChooser; @@ -33,7 +38,14 @@ import ghidra.framework.plugintool.PluginTool; import ghidra.framework.plugintool.util.PluginStatus; import ghidra.framework.preferences.Preferences; +import ghidra.framework.store.LockException; +import ghidra.program.model.address.Address; +import ghidra.program.model.address.AddressOverflowException; +import ghidra.program.model.address.AddressSpace; import ghidra.program.model.listing.Program; +import ghidra.program.model.mem.Memory; +import ghidra.program.model.mem.MemoryBlock; +import ghidra.program.model.mem.MemoryConflictException; import ghidra.util.Msg; import ghidra.util.filechooser.ExtensionFileFilter; @@ -54,7 +66,7 @@ public DeviceTreeBlobPlugin(PluginTool tool) { super(tool); createActions(); } - + private void createActions() { new ActionBuilder("Load DTB File", this.getName()).withContext(ProgramActionContext.class) .validContextWhen(pac -> pac.getProgram() != null).menuPath(ToolConstants.MENU_FILE, "Load DTB File...") @@ -68,23 +80,64 @@ private void loadDtb(ProgramActionContext pac) { Msg.showWarn(getClass(), null, "Load PDB", "Unable to load PDB file while analysis is running."); return; } - + File file = getDtbFileFromDialog(pac.getComponentProvider().getComponent()); if (file == null) return; - + Msg.info(getClass(), "Loading " + file.getPath()); - Dtb dtb; + DtbParser dtb; try { - dtb = Dtb.fromFile(file.getAbsolutePath()); - } catch (IOException e) { + dtb = new DtbParser(file); + } catch (IOException | ParseException e) { Msg.error(getClass(), "Could not parse DTB file!", e); return; } - - + Msg.info(getClass(), "Filtering unwanted DTB blocks..."); + List memBlocks = dtb.mBlocks.stream().filter(x -> (!x.name().equalsIgnoreCase("cpu") && x.hasRegs())) + .collect(Collectors.toList()); + + Msg.info(getClass(), "Creating regions in memory..."); + Memory memory = program.getMemory(); + AddressSpace addrSpace = program.getAddressFactory().getDefaultAddressSpace(); + for (Block block : memBlocks) + for (Reg region : block.getRegs()) { + String reg_name = block.name() + ((region.name != null) ? ("_" + region.name) : ""); + Address addr = addrSpace.getAddress(region.addr); + int transactionId = program.startTransaction("Device Tree Blob memory block creation"); + boolean ok = createMemoryRegion(memory, reg_name, addr, region.size); + program.endTransaction(transactionId, ok); + } + } + + private boolean createMemoryRegion(Memory memory, String name, Address addr, Long size) { + try { + MemoryBlock memBlock = memory.createUninitializedBlock(name, addr, size, false); + boolean isRam = name.equals("memory"); + memBlock.setRead(true); + memBlock.setWrite(true); + memBlock.setExecute(isRam); + memBlock.setVolatile(!isRam); + memBlock.setComment("Generated by Device Tree Blob"); + return true; + } catch (MemoryConflictException e) { + Msg.error(getClass(), + "Could not create a region for " + name + "@" + String.format("0x%08x", addr.getOffset()) + "+" + + String.format("0x%08x", size) + ". It conflicts with an existing region!", + e); + } catch (LockException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IllegalArgumentException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (AddressOverflowException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return false; } private File getDtbFileFromDialog(JComponent parent) { diff --git a/src/main/java/devicetreeblob/Dtb.java b/src/main/java/devicetreeblob/Dtb.java index 54af76a..dc36cc0 100644 --- a/src/main/java/devicetreeblob/Dtb.java +++ b/src/main/java/devicetreeblob/Dtb.java @@ -12,8 +12,8 @@ import java.nio.charset.Charset; /** - * Also referred to as Devicetree Blob (DTB). It is a flat binary encoding - * of data (primarily devicetree data, although other data is possible as well). + * Also referred to as Devicetree Blob (DTB). It is a flat binary encoding of + * data (primarily devicetree data, although other data is possible as well). * The data is internally stored as a tree of named nodes and properties. Nodes * contain properties and child nodes, while properties are name-value pairs. * @@ -33,404 +33,568 @@ * Example files: * * * - * @see Source - * @see Source + * + * @see Source + * @see Source */ public class Dtb extends KaitaiStruct { - public static Dtb fromFile(String fileName) throws IOException { - return new Dtb(new ByteBufferKaitaiStream(fileName)); - } - - public enum Fdt { - BEGIN_NODE(1), - END_NODE(2), - PROP(3), - NOP(4), - END(9); - - private final long id; - Fdt(long id) { this.id = id; } - public long id() { return id; } - private static final Map byId = new HashMap(5); - static { - for (Fdt e : Fdt.values()) - byId.put(e.id(), e); - } - public static Fdt byId(long id) { return byId.get(id); } - } - - public Dtb(KaitaiStream _io) { - this(_io, null, null); - } - - public Dtb(KaitaiStream _io, KaitaiStruct _parent) { - this(_io, _parent, null); - } - - public Dtb(KaitaiStream _io, KaitaiStruct _parent, Dtb _root) { - super(_io); - this._parent = _parent; - this._root = _root == null ? this : _root; - _read(); - } - private void _read() { - this.magic = this._io.readBytes(4); - if (!(Arrays.equals(magic(), new byte[] { -48, 13, -2, -19 }))) { - throw new KaitaiStream.ValidationNotEqualError(new byte[] { -48, 13, -2, -19 }, magic(), _io(), "/seq/0"); - } - this.totalSize = this._io.readU4be(); - this.ofsStructureBlock = this._io.readU4be(); - this.ofsStringsBlock = this._io.readU4be(); - this.ofsMemoryReservationBlock = this._io.readU4be(); - this.version = this._io.readU4be(); - this.minCompatibleVersion = this._io.readU4be(); - if (!(minCompatibleVersion() <= version())) { - throw new KaitaiStream.ValidationGreaterThanError(version(), minCompatibleVersion(), _io(), "/seq/6"); - } - this.bootCpuidPhys = this._io.readU4be(); - this.lenStringsBlock = this._io.readU4be(); - this.lenStructureBlock = this._io.readU4be(); - } - public static class MemoryBlock extends KaitaiStruct { - public static MemoryBlock fromFile(String fileName) throws IOException { - return new MemoryBlock(new ByteBufferKaitaiStream(fileName)); - } - - public MemoryBlock(KaitaiStream _io) { - this(_io, null, null); - } - - public MemoryBlock(KaitaiStream _io, Dtb _parent) { - this(_io, _parent, null); - } - - public MemoryBlock(KaitaiStream _io, Dtb _parent, Dtb _root) { - super(_io); - this._parent = _parent; - this._root = _root; - _read(); - } - private void _read() { - this.entries = new ArrayList(); - { - int i = 0; - while (!this._io.isEof()) { - this.entries.add(new MemoryBlockEntry(this._io, this, _root)); - i++; - } - } - } - private ArrayList entries; - private Dtb _root; - private Dtb _parent; - public ArrayList entries() { return entries; } - public Dtb _root() { return _root; } - public Dtb _parent() { return _parent; } - } - public static class FdtBlock extends KaitaiStruct { - public static FdtBlock fromFile(String fileName) throws IOException { - return new FdtBlock(new ByteBufferKaitaiStream(fileName)); - } - - public FdtBlock(KaitaiStream _io) { - this(_io, null, null); - } - - public FdtBlock(KaitaiStream _io, Dtb _parent) { - this(_io, _parent, null); - } - - public FdtBlock(KaitaiStream _io, Dtb _parent, Dtb _root) { - super(_io); - this._parent = _parent; - this._root = _root; - _read(); - } - private void _read() { - this.nodes = new ArrayList(); - { - FdtNode _it; - int i = 0; - do { - _it = new FdtNode(this._io, this, _root); - this.nodes.add(_it); - i++; - } while (!(_it.type() == Dtb.Fdt.END)); - } - } - private ArrayList nodes; - private Dtb _root; - private Dtb _parent; - public ArrayList nodes() { return nodes; } - public Dtb _root() { return _root; } - public Dtb _parent() { return _parent; } - } - public static class MemoryBlockEntry extends KaitaiStruct { - public static MemoryBlockEntry fromFile(String fileName) throws IOException { - return new MemoryBlockEntry(new ByteBufferKaitaiStream(fileName)); - } - - public MemoryBlockEntry(KaitaiStream _io) { - this(_io, null, null); - } - - public MemoryBlockEntry(KaitaiStream _io, Dtb.MemoryBlock _parent) { - this(_io, _parent, null); - } - - public MemoryBlockEntry(KaitaiStream _io, Dtb.MemoryBlock _parent, Dtb _root) { - super(_io); - this._parent = _parent; - this._root = _root; - _read(); - } - private void _read() { - this.address = this._io.readU8be(); - this.size = this._io.readU8be(); - } - private long address; - private long size; - private Dtb _root; - private Dtb.MemoryBlock _parent; - /** - * physical address of a reserved memory region - */ - public long address() { return address; } - - /** - * size of a reserved memory region - */ - public long size() { return size; } - public Dtb _root() { return _root; } - public Dtb.MemoryBlock _parent() { return _parent; } - } - public static class Strings extends KaitaiStruct { - public static Strings fromFile(String fileName) throws IOException { - return new Strings(new ByteBufferKaitaiStream(fileName)); - } - - public Strings(KaitaiStream _io) { - this(_io, null, null); - } - - public Strings(KaitaiStream _io, Dtb _parent) { - this(_io, _parent, null); - } - - public Strings(KaitaiStream _io, Dtb _parent, Dtb _root) { - super(_io); - this._parent = _parent; - this._root = _root; - _read(); - } - private void _read() { - this.strings = new ArrayList(); - { - int i = 0; - while (!this._io.isEof()) { - this.strings.add(new String(this._io.readBytesTerm((byte) 0, false, true, true), Charset.forName("ASCII"))); - i++; - } - } - } - private ArrayList strings; - private Dtb _root; - private Dtb _parent; - public ArrayList strings() { return strings; } - public Dtb _root() { return _root; } - public Dtb _parent() { return _parent; } - } - public static class FdtProp extends KaitaiStruct { - public static FdtProp fromFile(String fileName) throws IOException { - return new FdtProp(new ByteBufferKaitaiStream(fileName)); - } - - public FdtProp(KaitaiStream _io) { - this(_io, null, null); - } - - public FdtProp(KaitaiStream _io, Dtb.FdtNode _parent) { - this(_io, _parent, null); - } - - public FdtProp(KaitaiStream _io, Dtb.FdtNode _parent, Dtb _root) { - super(_io); - this._parent = _parent; - this._root = _root; - _read(); - } - private void _read() { - this.lenProperty = this._io.readU4be(); - this.ofsName = this._io.readU4be(); - this.property = this._io.readBytes(lenProperty()); - this.padding = this._io.readBytes(KaitaiStream.mod(-(_io().pos()), 4)); - } - private String name; - public String name() { - if (this.name != null) - return this.name; - KaitaiStream io = _root().stringsBlock()._io(); - long _pos = io.pos(); - io.seek(ofsName()); - this.name = new String(io.readBytesTerm((byte) 0, false, true, true), Charset.forName("ASCII")); - io.seek(_pos); - return this.name; - } - private long lenProperty; - private long ofsName; - private byte[] property; - private byte[] padding; - private Dtb _root; - private Dtb.FdtNode _parent; - public long lenProperty() { return lenProperty; } - public long ofsName() { return ofsName; } - public byte[] property() { return property; } - public byte[] padding() { return padding; } - public Dtb _root() { return _root; } - public Dtb.FdtNode _parent() { return _parent; } - } - public static class FdtNode extends KaitaiStruct { - public static FdtNode fromFile(String fileName) throws IOException { - return new FdtNode(new ByteBufferKaitaiStream(fileName)); - } - - public FdtNode(KaitaiStream _io) { - this(_io, null, null); - } - - public FdtNode(KaitaiStream _io, Dtb.FdtBlock _parent) { - this(_io, _parent, null); - } - - public FdtNode(KaitaiStream _io, Dtb.FdtBlock _parent, Dtb _root) { - super(_io); - this._parent = _parent; - this._root = _root; - _read(); - } - private void _read() { - this.type = Dtb.Fdt.byId(this._io.readU4be()); - { - Fdt on = type(); - if (on != null) { - switch (type()) { - case BEGIN_NODE: { - this.body = new FdtBeginNode(this._io, this, _root); - break; - } - case PROP: { - this.body = new FdtProp(this._io, this, _root); - break; - } - } - } - } - } - private Fdt type; - private KaitaiStruct body; - private Dtb _root; - private Dtb.FdtBlock _parent; - public Fdt type() { return type; } - public KaitaiStruct body() { return body; } - public Dtb _root() { return _root; } - public Dtb.FdtBlock _parent() { return _parent; } - } - public static class FdtBeginNode extends KaitaiStruct { - public static FdtBeginNode fromFile(String fileName) throws IOException { - return new FdtBeginNode(new ByteBufferKaitaiStream(fileName)); - } - - public FdtBeginNode(KaitaiStream _io) { - this(_io, null, null); - } - - public FdtBeginNode(KaitaiStream _io, Dtb.FdtNode _parent) { - this(_io, _parent, null); - } - - public FdtBeginNode(KaitaiStream _io, Dtb.FdtNode _parent, Dtb _root) { - super(_io); - this._parent = _parent; - this._root = _root; - _read(); - } - private void _read() { - this.name = new String(this._io.readBytesTerm((byte) 0, false, true, true), Charset.forName("ASCII")); - this.padding = this._io.readBytes(KaitaiStream.mod(-(_io().pos()), 4)); - } - private String name; - private byte[] padding; - private Dtb _root; - private Dtb.FdtNode _parent; - public String name() { return name; } - public byte[] padding() { return padding; } - public Dtb _root() { return _root; } - public Dtb.FdtNode _parent() { return _parent; } - } - private MemoryBlock memoryReservationBlock; - public MemoryBlock memoryReservationBlock() { - if (this.memoryReservationBlock != null) - return this.memoryReservationBlock; - long _pos = this._io.pos(); - this._io.seek(ofsMemoryReservationBlock()); - this._raw_memoryReservationBlock = this._io.readBytes((ofsStructureBlock() - ofsMemoryReservationBlock())); - KaitaiStream _io__raw_memoryReservationBlock = new ByteBufferKaitaiStream(_raw_memoryReservationBlock); - this.memoryReservationBlock = new MemoryBlock(_io__raw_memoryReservationBlock, this, _root); - this._io.seek(_pos); - return this.memoryReservationBlock; - } - private FdtBlock structureBlock; - public FdtBlock structureBlock() { - if (this.structureBlock != null) - return this.structureBlock; - long _pos = this._io.pos(); - this._io.seek(ofsStructureBlock()); - this._raw_structureBlock = this._io.readBytes(lenStructureBlock()); - KaitaiStream _io__raw_structureBlock = new ByteBufferKaitaiStream(_raw_structureBlock); - this.structureBlock = new FdtBlock(_io__raw_structureBlock, this, _root); - this._io.seek(_pos); - return this.structureBlock; - } - private Strings stringsBlock; - public Strings stringsBlock() { - if (this.stringsBlock != null) - return this.stringsBlock; - long _pos = this._io.pos(); - this._io.seek(ofsStringsBlock()); - this._raw_stringsBlock = this._io.readBytes(lenStringsBlock()); - KaitaiStream _io__raw_stringsBlock = new ByteBufferKaitaiStream(_raw_stringsBlock); - this.stringsBlock = new Strings(_io__raw_stringsBlock, this, _root); - this._io.seek(_pos); - return this.stringsBlock; - } - private byte[] magic; - private long totalSize; - private long ofsStructureBlock; - private long ofsStringsBlock; - private long ofsMemoryReservationBlock; - private long version; - private long minCompatibleVersion; - private long bootCpuidPhys; - private long lenStringsBlock; - private long lenStructureBlock; - private Dtb _root; - private KaitaiStruct _parent; - private byte[] _raw_memoryReservationBlock; - private byte[] _raw_structureBlock; - private byte[] _raw_stringsBlock; - public byte[] magic() { return magic; } - public long totalSize() { return totalSize; } - public long ofsStructureBlock() { return ofsStructureBlock; } - public long ofsStringsBlock() { return ofsStringsBlock; } - public long ofsMemoryReservationBlock() { return ofsMemoryReservationBlock; } - public long version() { return version; } - public long minCompatibleVersion() { return minCompatibleVersion; } - public long bootCpuidPhys() { return bootCpuidPhys; } - public long lenStringsBlock() { return lenStringsBlock; } - public long lenStructureBlock() { return lenStructureBlock; } - public Dtb _root() { return _root; } - public KaitaiStruct _parent() { return _parent; } - public byte[] _raw_memoryReservationBlock() { return _raw_memoryReservationBlock; } - public byte[] _raw_structureBlock() { return _raw_structureBlock; } - public byte[] _raw_stringsBlock() { return _raw_stringsBlock; } + public static Dtb fromFile(String fileName) throws IOException { + return new Dtb(new ByteBufferKaitaiStream(fileName)); + } + + public enum Fdt { + BEGIN_NODE(1), END_NODE(2), PROP(3), NOP(4), END(9); + + private final long id; + + Fdt(long id) { + this.id = id; + } + + public long id() { + return id; + } + + private static final Map byId = new HashMap(5); + static { + for (Fdt e : Fdt.values()) + byId.put(e.id(), e); + } + + public static Fdt byId(long id) { + return byId.get(id); + } + } + + public Dtb(KaitaiStream _io) { + this(_io, null, null); + } + + public Dtb(KaitaiStream _io, KaitaiStruct _parent) { + this(_io, _parent, null); + } + + public Dtb(KaitaiStream _io, KaitaiStruct _parent, Dtb _root) { + super(_io); + this._parent = _parent; + this._root = _root == null ? this : _root; + _read(); + } + + private void _read() { + this.magic = this._io.readBytes(4); + if (!(Arrays.equals(magic(), new byte[] { -48, 13, -2, -19 }))) { + throw new KaitaiStream.ValidationNotEqualError(new byte[] { -48, 13, -2, -19 }, magic(), _io(), "/seq/0"); + } + this.totalSize = this._io.readU4be(); + this.ofsStructureBlock = this._io.readU4be(); + this.ofsStringsBlock = this._io.readU4be(); + this.ofsMemoryReservationBlock = this._io.readU4be(); + this.version = this._io.readU4be(); + this.minCompatibleVersion = this._io.readU4be(); + if (!(minCompatibleVersion() <= version())) { + throw new KaitaiStream.ValidationGreaterThanError(version(), minCompatibleVersion(), _io(), "/seq/6"); + } + this.bootCpuidPhys = this._io.readU4be(); + this.lenStringsBlock = this._io.readU4be(); + this.lenStructureBlock = this._io.readU4be(); + } + + public static class MemoryBlock extends KaitaiStruct { + public static MemoryBlock fromFile(String fileName) throws IOException { + return new MemoryBlock(new ByteBufferKaitaiStream(fileName)); + } + + public MemoryBlock(KaitaiStream _io) { + this(_io, null, null); + } + + public MemoryBlock(KaitaiStream _io, Dtb _parent) { + this(_io, _parent, null); + } + + public MemoryBlock(KaitaiStream _io, Dtb _parent, Dtb _root) { + super(_io); + this._parent = _parent; + this._root = _root; + _read(); + } + + private void _read() { + this.entries = new ArrayList(); + { + while (!this._io.isEof()) { + this.entries.add(new MemoryBlockEntry(this._io, this, _root)); + } + } + } + + private ArrayList entries; + private Dtb _root; + private Dtb _parent; + + public ArrayList entries() { + return entries; + } + + public Dtb _root() { + return _root; + } + + public Dtb _parent() { + return _parent; + } + } + + public static class FdtBlock extends KaitaiStruct { + public static FdtBlock fromFile(String fileName) throws IOException { + return new FdtBlock(new ByteBufferKaitaiStream(fileName)); + } + + public FdtBlock(KaitaiStream _io) { + this(_io, null, null); + } + + public FdtBlock(KaitaiStream _io, Dtb _parent) { + this(_io, _parent, null); + } + + public FdtBlock(KaitaiStream _io, Dtb _parent, Dtb _root) { + super(_io); + this._parent = _parent; + this._root = _root; + _read(); + } + + private void _read() { + this.nodes = new ArrayList(); + { + FdtNode _it; + do { + _it = new FdtNode(this._io, this, _root); + this.nodes.add(_it); + } while (!(_it.type() == Dtb.Fdt.END)); + } + } + + private ArrayList nodes; + private Dtb _root; + private Dtb _parent; + + public ArrayList nodes() { + return nodes; + } + + public Dtb _root() { + return _root; + } + + public Dtb _parent() { + return _parent; + } + } + + public static class MemoryBlockEntry extends KaitaiStruct { + public static MemoryBlockEntry fromFile(String fileName) throws IOException { + return new MemoryBlockEntry(new ByteBufferKaitaiStream(fileName)); + } + + public MemoryBlockEntry(KaitaiStream _io) { + this(_io, null, null); + } + + public MemoryBlockEntry(KaitaiStream _io, Dtb.MemoryBlock _parent) { + this(_io, _parent, null); + } + + public MemoryBlockEntry(KaitaiStream _io, Dtb.MemoryBlock _parent, Dtb _root) { + super(_io); + this._parent = _parent; + this._root = _root; + _read(); + } + + private void _read() { + this.address = this._io.readU8be(); + this.size = this._io.readU8be(); + } + + private long address; + private long size; + private Dtb _root; + private Dtb.MemoryBlock _parent; + + /** + * physical address of a reserved memory region + */ + public long address() { + return address; + } + + /** + * size of a reserved memory region + */ + public long size() { + return size; + } + + public Dtb _root() { + return _root; + } + + public Dtb.MemoryBlock _parent() { + return _parent; + } + } + + public static class Strings extends KaitaiStruct { + public static Strings fromFile(String fileName) throws IOException { + return new Strings(new ByteBufferKaitaiStream(fileName)); + } + + public Strings(KaitaiStream _io) { + this(_io, null, null); + } + + public Strings(KaitaiStream _io, Dtb _parent) { + this(_io, _parent, null); + } + + public Strings(KaitaiStream _io, Dtb _parent, Dtb _root) { + super(_io); + this._parent = _parent; + this._root = _root; + _read(); + } + + private void _read() { + this.strings = new ArrayList(); + { + while (!this._io.isEof()) { + this.strings.add( + new String(this._io.readBytesTerm((byte) 0, false, true, true), Charset.forName("ASCII"))); + } + } + } + + private ArrayList strings; + private Dtb _root; + private Dtb _parent; + + public ArrayList strings() { + return strings; + } + + public Dtb _root() { + return _root; + } + + public Dtb _parent() { + return _parent; + } + } + + public static class FdtProp extends KaitaiStruct { + public static FdtProp fromFile(String fileName) throws IOException { + return new FdtProp(new ByteBufferKaitaiStream(fileName)); + } + + public FdtProp(KaitaiStream _io) { + this(_io, null, null); + } + + public FdtProp(KaitaiStream _io, Dtb.FdtNode _parent) { + this(_io, _parent, null); + } + + public FdtProp(KaitaiStream _io, Dtb.FdtNode _parent, Dtb _root) { + super(_io); + this._parent = _parent; + this._root = _root; + _read(); + } + + private void _read() { + this.lenProperty = this._io.readU4be(); + this.ofsName = this._io.readU4be(); + this.property = this._io.readBytes(lenProperty()); + this.padding = this._io.readBytes(KaitaiStream.mod(-(_io().pos()), 4)); + } + + private String name; + + public String name() { + if (this.name != null) + return this.name; + KaitaiStream io = _root().stringsBlock()._io(); + long _pos = io.pos(); + io.seek(ofsName()); + this.name = new String(io.readBytesTerm((byte) 0, false, true, true), Charset.forName("ASCII")); + io.seek(_pos); + return this.name; + } + + private long lenProperty; + private long ofsName; + private byte[] property; + private byte[] padding; + private Dtb _root; + private Dtb.FdtNode _parent; + + public long lenProperty() { + return lenProperty; + } + + public long ofsName() { + return ofsName; + } + + public byte[] property() { + return property; + } + + public byte[] padding() { + return padding; + } + + public Dtb _root() { + return _root; + } + + public Dtb.FdtNode _parent() { + return _parent; + } + } + + public static class FdtNode extends KaitaiStruct { + public static FdtNode fromFile(String fileName) throws IOException { + return new FdtNode(new ByteBufferKaitaiStream(fileName)); + } + + public FdtNode(KaitaiStream _io) { + this(_io, null, null); + } + + public FdtNode(KaitaiStream _io, Dtb.FdtBlock _parent) { + this(_io, _parent, null); + } + + public FdtNode(KaitaiStream _io, Dtb.FdtBlock _parent, Dtb _root) { + super(_io); + this._parent = _parent; + this._root = _root; + _read(); + } + + private void _read() { + this.type = Dtb.Fdt.byId(this._io.readU4be()); + { + Fdt on = type(); + if (on != null) { + switch (type()) { + case BEGIN_NODE: { + this.body = new FdtBeginNode(this._io, this, _root); + break; + } + case PROP: { + this.body = new FdtProp(this._io, this, _root); + break; + } + case END_NODE: + case END: + case NOP: + break; + } + } + } + } + + private Fdt type; + private KaitaiStruct body; + private Dtb _root; + private Dtb.FdtBlock _parent; + + public Fdt type() { + return type; + } + + public KaitaiStruct body() { + return body; + } + + public Dtb _root() { + return _root; + } + + public Dtb.FdtBlock _parent() { + return _parent; + } + } + + public static class FdtBeginNode extends KaitaiStruct { + public static FdtBeginNode fromFile(String fileName) throws IOException { + return new FdtBeginNode(new ByteBufferKaitaiStream(fileName)); + } + + public FdtBeginNode(KaitaiStream _io) { + this(_io, null, null); + } + + public FdtBeginNode(KaitaiStream _io, Dtb.FdtNode _parent) { + this(_io, _parent, null); + } + + public FdtBeginNode(KaitaiStream _io, Dtb.FdtNode _parent, Dtb _root) { + super(_io); + this._parent = _parent; + this._root = _root; + _read(); + } + + private void _read() { + this.name = new String(this._io.readBytesTerm((byte) 0, false, true, true), Charset.forName("ASCII")); + this.padding = this._io.readBytes(KaitaiStream.mod(-(_io().pos()), 4)); + } + + private String name; + private byte[] padding; + private Dtb _root; + private Dtb.FdtNode _parent; + + public String name() { + return name; + } + + public byte[] padding() { + return padding; + } + + public Dtb _root() { + return _root; + } + + public Dtb.FdtNode _parent() { + return _parent; + } + } + + private MemoryBlock memoryReservationBlock; + + public MemoryBlock memoryReservationBlock() { + if (this.memoryReservationBlock != null) + return this.memoryReservationBlock; + long _pos = this._io.pos(); + this._io.seek(ofsMemoryReservationBlock()); + this._raw_memoryReservationBlock = this._io.readBytes((ofsStructureBlock() - ofsMemoryReservationBlock())); + KaitaiStream _io__raw_memoryReservationBlock = new ByteBufferKaitaiStream(_raw_memoryReservationBlock); + this.memoryReservationBlock = new MemoryBlock(_io__raw_memoryReservationBlock, this, _root); + this._io.seek(_pos); + return this.memoryReservationBlock; + } + + private FdtBlock structureBlock; + + public FdtBlock structureBlock() { + if (this.structureBlock != null) + return this.structureBlock; + long _pos = this._io.pos(); + this._io.seek(ofsStructureBlock()); + this._raw_structureBlock = this._io.readBytes(lenStructureBlock()); + KaitaiStream _io__raw_structureBlock = new ByteBufferKaitaiStream(_raw_structureBlock); + this.structureBlock = new FdtBlock(_io__raw_structureBlock, this, _root); + this._io.seek(_pos); + return this.structureBlock; + } + + private Strings stringsBlock; + + public Strings stringsBlock() { + if (this.stringsBlock != null) + return this.stringsBlock; + long _pos = this._io.pos(); + this._io.seek(ofsStringsBlock()); + this._raw_stringsBlock = this._io.readBytes(lenStringsBlock()); + KaitaiStream _io__raw_stringsBlock = new ByteBufferKaitaiStream(_raw_stringsBlock); + this.stringsBlock = new Strings(_io__raw_stringsBlock, this, _root); + this._io.seek(_pos); + return this.stringsBlock; + } + + private byte[] magic; + private long totalSize; + private long ofsStructureBlock; + private long ofsStringsBlock; + private long ofsMemoryReservationBlock; + private long version; + private long minCompatibleVersion; + private long bootCpuidPhys; + private long lenStringsBlock; + private long lenStructureBlock; + private Dtb _root; + private KaitaiStruct _parent; + private byte[] _raw_memoryReservationBlock; + private byte[] _raw_structureBlock; + private byte[] _raw_stringsBlock; + + public byte[] magic() { + return magic; + } + + public long totalSize() { + return totalSize; + } + + public long ofsStructureBlock() { + return ofsStructureBlock; + } + + public long ofsStringsBlock() { + return ofsStringsBlock; + } + + public long ofsMemoryReservationBlock() { + return ofsMemoryReservationBlock; + } + + public long version() { + return version; + } + + public long minCompatibleVersion() { + return minCompatibleVersion; + } + + public long bootCpuidPhys() { + return bootCpuidPhys; + } + + public long lenStringsBlock() { + return lenStringsBlock; + } + + public long lenStructureBlock() { + return lenStructureBlock; + } + + public Dtb _root() { + return _root; + } + + public KaitaiStruct _parent() { + return _parent; + } + + public byte[] _raw_memoryReservationBlock() { + return _raw_memoryReservationBlock; + } + + public byte[] _raw_structureBlock() { + return _raw_structureBlock; + } + + public byte[] _raw_stringsBlock() { + return _raw_stringsBlock; + } } diff --git a/src/main/java/devicetreeblob/DtbParser.java b/src/main/java/devicetreeblob/DtbParser.java new file mode 100644 index 0000000..d3a179b --- /dev/null +++ b/src/main/java/devicetreeblob/DtbParser.java @@ -0,0 +1,116 @@ +package devicetreeblob; + +import java.io.File; +import java.io.IOException; +import java.math.BigInteger; +import java.nio.charset.StandardCharsets; +import java.text.ParseException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import devicetreeblob.Dtb.FdtBeginNode; +import devicetreeblob.Dtb.FdtBlock; +import devicetreeblob.Dtb.FdtNode; +import devicetreeblob.Dtb.FdtProp; + +public class DtbParser { + + ArrayList mBlocks; + + public DtbParser(File file) throws IOException, ParseException { + mBlocks = new ArrayList(); + parseBlocks(Dtb.fromFile(file.getAbsolutePath())); + } + + private void parseBlocks(Dtb dtb) throws ParseException { + FdtBlock fdtBlock = dtb.structureBlock(); + ArrayList stack = new ArrayList(); + for (FdtNode node : fdtBlock.nodes()) { + switch (node.type()) { + case BEGIN_NODE: + Block b = new Block((FdtBeginNode) node.body()); + mBlocks.add(b); + stack.add(b); + break; + case END_NODE: + stack.remove(stack.size() - 1); + break; + case PROP: + stack.get(stack.size() - 1).addProperty((FdtProp) node.body()); + break; + case NOP: + case END: + break; + } + } + if (stack.size() != 0) + throw new ParseException("Wrong number of END_NODE nodes in DTB file!", 0); + } + + class Block { + private String mName; + Map mProperties; + + public Block(FdtBeginNode node) { + mName = node.name(); + mProperties = new HashMap<>(); + } + + public void addProperty(FdtProp n) { + mProperties.put(n.name(), n.property()); + } + + public String name() { + if (mName.contains("@")) + return mName.split("@")[0]; + return mName; + } + + public boolean hasRegs() { + return mProperties.containsKey("reg"); + } + + private int indexOf(byte[] arr, int val) { + for (int i = 0; i < arr.length; i++) + if (arr[i] == val) + return i; + return -1; + } + + private void getRegNames(ArrayList regs) { + byte[] regNames = mProperties.get("reg-names"); + if (regNames == null) + return; + for (Reg r : regs) { + int pos = indexOf(regNames, 0); + r.name = new String(Arrays.copyOfRange(regNames, 0, pos), StandardCharsets.UTF_8); + regNames = Arrays.copyOfRange(regNames, pos+1, regNames.length); + } + } + + public List getRegs() { + byte[] regs = mProperties.get("reg"); + if (regs == null) + return null; + ArrayList ret = new ArrayList(); + while (regs.length >= 8) { + Reg r = new Reg(); + r.addr = new BigInteger(Arrays.copyOfRange(regs, 0, 4)).intValue() & 0xffffffffL; + r.size = new BigInteger(Arrays.copyOfRange(regs, 4, 8)).intValue() & 0xffffffffL; + regs = Arrays.copyOfRange(regs, 8, regs.length); + ret.add(r); + } + getRegNames(ret); + return ret; + } + + class Reg { + String name; + Long addr; + Long size; + } + } +}