diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/AddressXML.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/AddressXML.java index 6ac3f1478d..4e001d33bf 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/AddressXML.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/AddressXML.java @@ -421,8 +421,8 @@ public class AddressXML { } else { decoder.rewindAttributes(); - Varnode[] pieces = Varnode.decodePieces(decoder); - storage = pcodeFactory.getJoinStorage(pieces); + Varnode.Join join = Varnode.decodePieces(decoder); + storage = pcodeFactory.getJoinStorage(join.pieces); } } catch (InvalidInputException e) { diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/Varnode.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/Varnode.java index 76c386fd78..d484e99257 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/Varnode.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/pcode/Varnode.java @@ -19,7 +19,8 @@ import static ghidra.program.model.pcode.AttributeId.*; import static ghidra.program.model.pcode.ElementId.*; import java.io.IOException; -import java.util.*; +import java.util.ArrayList; +import java.util.Iterator; import ghidra.program.model.address.*; import ghidra.program.model.lang.Language; @@ -38,6 +39,15 @@ public class Varnode { private static final long masks[] = { 0L, 0xffL, 0xffffL, 0xffffffL, 0xffffffffL, 0xffffffffffL, 0xffffffffffffL, 0xffffffffffffffL, 0xffffffffffffffffL }; + /** + * Set of Varnode pieces referred to by a single Varnode in join space + * as returned by Varnode.decodePieces + */ + public static class Join { + public Varnode[] pieces; // The list of individual Varnodes being joined + public int logicalSize; // The size (in bytes) of the logical whole. + } + private Address address; private int size; private int spaceID; @@ -384,12 +394,12 @@ public class Varnode { if ((spc != null) && (spc.getType() == AddressSpace.TYPE_VARIABLE)) { // Check for a composite Address decoder.rewindAttributes(); try { - Varnode[] pieces = decodePieces(decoder); - VariableStorage storage = factory.getJoinStorage(pieces); + Join join = decodePieces(decoder); + VariableStorage storage = factory.getJoinStorage(join.pieces); // Update "join" address to the one just registered with the pieces addr = factory.getJoinAddress(storage); // Update size to be the size of the pieces - sz = Arrays.stream(pieces).map(x -> x.getSize()).reduce(0, Integer::sum); + sz = join.logicalSize; } catch (InvalidInputException e) { throw new DecoderException("Invalid varnode pieces: " + e.getMessage()); @@ -488,16 +498,21 @@ public class Varnode { * space, a contiguous sequence of bytes, at a specific Address, represent a logical value * that may physically be split across multiple registers or other storage locations. * @param decoder is the stream decoder - * @return an array of decoded Varnodes + * @return an array of decoded Varnodes and the logical size * @throws DecoderException for any errors in the encoding */ - public static Varnode[] decodePieces(Decoder decoder) throws DecoderException { + public static Join decodePieces(Decoder decoder) throws DecoderException { ArrayList list = new ArrayList<>(); + int sizeAccum = 0; + int logicalSize = 0; for (;;) { int attribId = decoder.getNextAttributeId(); if (attribId == 0) { break; } + else if (attribId == ATTRIB_LOGICALSIZE.id()) { + logicalSize = (int) decoder.readUnsignedInteger(); + } else if (attribId == ATTRIB_UNKNOWN.id()) { attribId = decoder.getIndexedAttributeId(ATTRIB_PIECE); } @@ -510,12 +525,16 @@ public class Varnode { if (index != list.size()) { throw new DecoderException("\"piece\" attributes must be in order"); } - list.add(decodePiece(decoder.readString(), decoder.getAddressFactory())); + Varnode vn = decodePiece(decoder.readString(), decoder.getAddressFactory()); + list.add(vn); + sizeAccum += vn.getSize(); } } - Varnode[] pieces = new Varnode[list.size()]; - list.toArray(pieces); - return pieces; + Join join = new Join(); + join.pieces = new Varnode[list.size()]; + join.logicalSize = (logicalSize != 0) ? logicalSize : sizeAccum; + list.toArray(join.pieces); + return join; } /**