GP-260 Corrected composite resolveequivalence issue introduced with

GP-260
This commit is contained in:
ghidra1 2020-11-12 13:48:03 -05:00
parent bc6a008add
commit 62cb57d8bb
8 changed files with 131 additions and 54 deletions

View file

@ -69,20 +69,26 @@ abstract class CompositeDB extends DataTypeDB implements Composite {
protected abstract void initialize();
/**
* Get the preferred length for a new component. Constraining length of fixed-length datatype
* may not be sustainable in response to datatype size changes over time.
* Get the preferred length for a new component. For Unions and internally
* aligned structures the preferred component length for a fixed-length dataType
* will be the length of that dataType. Otherwise the length returned will be no
* larger than the specified length.
*
* @param dataType new component datatype
* @param length specified length required for Dynamic types such as string
* which must have a positive length specified.
* @param length constrained length or -1 to force use of dataType size.
* Dynamic types such as string must have a positive length
* specified.
* @return preferred component length
*/
protected int getPreferredComponentLength(DataType dataType, int length) {
if (length > 0 && (dataType instanceof Composite) &&
((Composite) dataType).isNotYetDefined()) {
return length;
if ((isInternallyAligned() || (this instanceof Union)) && !(dataType instanceof Dynamic)) {
length = -1; // force use of datatype size
}
int dtLength = dataType.getLength();
if (dtLength > 0) {
if (length <= 0) {
length = dtLength;
}
else if (dtLength > 0 && dtLength < length) {
length = dtLength;
}
if (length <= 0) {

View file

@ -345,17 +345,20 @@ class DataTypeComponentDB implements InternalDataTypeComponent {
DataType myParent = getParent();
boolean aligned =
(myParent instanceof Composite) ? ((Composite) myParent).isInternallyAligned() : false;
// Components don't need to have matching offset when they are aligned, only matching ordinal.
// NOTE: use getOffset() and getOrdinal() methods since returned values will differ from
// Components don't need to have matching offset when they are aligned
// NOTE: use getOffset() method since returned values will differ from
// stored values for flexible array component
if ((!aligned && (getOffset() != dtc.getOffset())) ||
// Components don't need to have matching length when they are aligned. Is this correct?
(!aligned && (getLength() != dtc.getLength())) || getOrdinal() != dtc.getOrdinal() ||
!SystemUtilities.isEqual(getFieldName(), dtc.getFieldName()) ||
!SystemUtilities.isEqual(getComment(), dtc.getComment())) {
return false;
}
// Component lengths need only be checked for dynamic types
if (getLength() != dtc.getLength() && (myDt instanceof Dynamic)) {
return false;
}
return DataTypeUtilities.isSameOrEquivalentDataType(myDt, otherDt);
}

View file

@ -684,8 +684,9 @@ class StructureDB extends CompositeDB implements Structure {
}
/**
* Create copy of structure for target dtm (source archive information is discarded). WARNING!
* copying unaligned structures which contain bitfields can produce invalid results when
* Create copy of structure for target dtm (source archive information is discarded).
* <p>
* WARNING! copying unaligned structures which contain bitfields can produce invalid results when
* switching endianess due to the differences in packing order.
*
* @param dtm target data type manager
@ -1281,7 +1282,22 @@ class StructureDB extends CompositeDB implements Structure {
DataType dt = resolvedDts[i]; // ancestry check already performed by caller
int length = getPreferredComponentLength(dt, dtc.getLength());
int length = dt.getLength();
if (length <= 0 || dtc.isBitFieldComponent()) {
length = dtc.getLength();
}
else {
// do not exceed available space
int maxOffset;
int nextIndex = i + 1;
if (nextIndex < otherComponents.length) {
maxOffset = otherComponents[nextIndex].getOffset();
}
else {
maxOffset = struct.getLength();
}
length = Math.min(length, maxOffset - dtc.getOffset());
}
Record rec = componentAdapter.createRecord(dataMgr.getResolvedID(dt), key, length,
dtc.getOrdinal(), dtc.getOffset(), dtc.getFieldName(), dtc.getComment());
@ -1358,6 +1374,9 @@ class StructureDB extends CompositeDB implements Structure {
@Override
public void dataTypeSizeChanged(DataType dt) {
if (dt instanceof BitFieldDataType) {
return; // unsupported
}
lock.acquire();
try {
checkDeleted();
@ -1374,7 +1393,10 @@ class StructureDB extends CompositeDB implements Structure {
// assume no impact to bitfields since base types
// should not change size
int dtcLen = dtc.getLength();
int length = getPreferredComponentLength(dt, dtcLen);
int length = dt.getLength();
if (length <= 0) {
length = dtcLen;
}
if (length < dtcLen) {
dtc.setLength(length, true);
shiftOffsets(i + 1, dtcLen - length, 0);
@ -1427,7 +1449,10 @@ class StructureDB extends CompositeDB implements Structure {
continue;
}
int dtcLen = dtc.getLength();
int length = getPreferredComponentLength(dt, dtcLen);
int length = dt.getLength();
if (length <= 0) {
length = dtcLen;
}
if (dtcLen != length) {
if (length < dtcLen) {
dtc.setLength(length, true);
@ -1514,14 +1539,18 @@ class StructureDB extends CompositeDB implements Structure {
return false;
}
int myNumComps = getNumComponents();
int otherNumComps = struct.getNumComponents();
int myNumComps = components.size();
int otherNumComps = struct.getNumDefinedComponents();
if (myNumComps != otherNumComps) {
return false;
}
DataTypeComponent[] otherDefinedComponents = struct.getDefinedComponents();
if (otherDefinedComponents.length != myNumComps) { // safety check
return false;
}
for (int i = 0; i < myNumComps; i++) {
DataTypeComponent myDtc = getComponent(i);
DataTypeComponent otherDtc = struct.getComponent(i);
DataTypeComponent myDtc = components.get(i);
DataTypeComponent otherDtc = otherDefinedComponents[i];
if (!myDtc.isEquivalent(otherDtc)) {
return false;
}

View file

@ -418,14 +418,19 @@ class UnionDB extends CompositeDB implements Union {
@Override
public void dataTypeSizeChanged(DataType dt) {
if (dt instanceof BitFieldDataType) {
return; // unsupported
}
lock.acquire();
try {
checkDeleted();
boolean changed = false;
for (DataTypeComponentDB dtc : components) {
int length = dtc.getLength();
if (dtc.getDataType() == dt) {
length = getPreferredComponentLength(dt, length);
int length = dt.getLength();
if (length <= 0) {
length = dtc.getLength();
}
dtc.setLength(length, true);
changed = true;
}
@ -448,7 +453,10 @@ class UnionDB extends CompositeDB implements Union {
dt = adjustBitField(dt); // in case base type changed
}
int dtcLen = dtc.getLength();
int length = getPreferredComponentLength(dt, dtcLen);
int length = dt.getLength();
if (length <= 0) {
length = dtcLen;
}
if (length != dtcLen) {
dtc.setLength(length, true);
changed = true;

View file

@ -160,7 +160,9 @@ public interface DataTypeComponent {
* Returns true if the given dataTypeComponent is equivalent to this dataTypeComponent.
* A dataTypeComponent is "equivalent" if the other component has a data type
* that is equivalent to this component's data type. The dataTypeComponents must
* also have the same offset, length, ordinal, field name, and comment.
* also have the same offset, field name, and comment. The length is only checked
* for components which are dyanmic and whose size must be specified when creating
* a component.
* @param dtc the dataTypeComponent being tested for equivalence.
* @return true if the given dataTypeComponent is equivalent to this dataTypeComponent.
*/

View file

@ -329,17 +329,20 @@ public class DataTypeComponentImpl implements InternalDataTypeComponent, Seriali
DataType myParent = getParent();
boolean aligned =
(myParent instanceof Composite) ? ((Composite) myParent).isInternallyAligned() : false;
// Components don't need to have matching offset when they are aligned, only matching ordinal.
if ((!aligned && (getOffset() != dtc.getOffset())) ||
// Components don't need to have matching length when they are aligned. Is this correct?
// NOTE: use getOffset() and getOrdinal() methods since returned values will differ from
// Components don't need to have matching offset when they are aligned
// NOTE: use getOffset() method since returned values will differ from
// stored values for flexible array component
(!aligned && (getLength() != dtc.getLength())) || getOrdinal() != dtc.getOrdinal() ||
if ((!aligned && (getOffset() != dtc.getOffset())) ||
!SystemUtilities.isEqual(getFieldName(), dtc.getFieldName()) ||
!SystemUtilities.isEqual(getComment(), dtc.getComment())) {
return false;
}
// Component lengths need only be checked for dynamic types
if (getLength() != dtc.getLength() && (myDt instanceof Dynamic)) {
return false;
}
return DataTypeUtilities.isSameOrEquivalentDataType(myDt, otherDt);
}

View file

@ -797,15 +797,18 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur
return false;
}
int myNumComps = getNumComponents();
int otherNumComps = struct.getNumComponents();
int myNumComps = components.size();
int otherNumComps = struct.getNumDefinedComponents();
if (myNumComps != otherNumComps) {
return false;
}
DataTypeComponent[] otherDefinedComponents = struct.getDefinedComponents();
if (otherDefinedComponents.length != myNumComps) { // safety check
return false;
}
for (int i = 0; i < myNumComps; i++) {
DataTypeComponent myDtc = getComponent(i);
DataTypeComponent otherDtc = struct.getComponent(i);
DataTypeComponent myDtc = components.get(i);
DataTypeComponent otherDtc = otherDefinedComponents[i];
if (!myDtc.isEquivalent(otherDtc)) {
return false;
}
@ -815,6 +818,9 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur
@Override
public void dataTypeSizeChanged(DataType dt) {
if (dt instanceof BitFieldDataType) {
return; // unsupported
}
if (isInternallyAligned()) {
adjustInternalAlignment();
return;
@ -823,21 +829,23 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur
int n = components.size();
for (int i = 0; i < n; i++) {
DataTypeComponentImpl dtc = components.get(i);
int nextIndex = i + 1;
if (dtc.getDataType() == dt) {
// assume no impact to bitfields since base types
// should not change size
int dtLen = dt.getLength();
int dtcLen = dtc.getLength();
if (dtLen < dtcLen) {
dtc.setLength(dtLen);
shiftOffsets(nextIndex, dtcLen - dtLen, 0);
int length = dt.getLength();
if (length <= 0) {
length = dtcLen;
}
if (length < dtcLen) {
dtc.setLength(length);
shiftOffsets(i + 1, dtcLen - length, 0);
didChange = true;
}
else if (dtLen > dtcLen) {
int consumed = consumeBytesAfter(i, dtLen - dtcLen);
else if (length > dtcLen) {
int consumed = consumeBytesAfter(i, length - dtcLen);
if (consumed > 0) {
shiftOffsets(nextIndex, 0 - consumed, 0);
shiftOffsets(i + 1, 0 - consumed, 0);
didChange = true;
}
}
@ -890,8 +898,9 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur
}
/**
* Create copy of structure for target dtm (source archive information is discarded). WARNING!
* copying unaligned structures which contain bitfields can produce invalid results when
* Create copy of structure for target dtm (source archive information is discarded).
* <p>
* WARNING! copying unaligned structures which contain bitfields can produce invalid results when
* switching endianess due to the differences in packing order.
*
* @param dtm target data type manager
@ -991,8 +1000,7 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur
private void doReplaceWithAligned(Structure struct) {
// assumes components is clear and that alignment characteristics have been set
DataTypeComponent[] otherComponents = struct.getDefinedComponents();
for (int i = 0; i < otherComponents.length; i++) {
DataTypeComponent dtc = otherComponents[i];
for (DataTypeComponent dtc : otherComponents) {
DataType dt = dtc.getDataType();
int length = (dt instanceof Dynamic) ? dtc.getLength() : -1;
add(dt, length, dtc.getFieldName(), dtc.getComment());
@ -1011,11 +1019,25 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur
DataTypeComponent[] otherComponents = struct.getDefinedComponents();
for (int i = 0; i < otherComponents.length; i++) {
DataTypeComponent dtc = otherComponents[i];
DataType dt = dtc.getDataType().clone(dataMgr);
checkAncestry(dt);
int length = getPreferredComponentLength(dt, dtc.getLength());
int length = dt.getLength();
if (length <= 0 || dtc.isBitFieldComponent()) {
length = dtc.getLength();
}
else {
// do not exceed available space
int maxOffset;
int nextIndex = i + 1;
if (nextIndex < otherComponents.length) {
maxOffset = otherComponents[nextIndex].getOffset();
}
else {
maxOffset = struct.getLength();
}
length = Math.min(length, maxOffset - dtc.getOffset());
}
components.add(new DataTypeComponentImpl(dt, this, length, dtc.getOrdinal(),
dtc.getOffset(), dtc.getFieldName(), dtc.getComment()));
@ -1355,8 +1377,7 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur
@Override
public void deleteAll() {
for (int i = 0; i < components.size(); i++) {
DataTypeComponent dtc = components.get(i);
for (DataTypeComponentImpl dtc : components) {
dtc.getDataType().removeParent(this);
}
components.clear();

View file

@ -372,11 +372,16 @@ public class UnionDataType extends CompositeDataTypeImpl implements Union {
@Override
public void dataTypeSizeChanged(DataType dt) {
if (dt instanceof BitFieldDataType) {
return; // unsupported
}
boolean changed = false;
for (DataTypeComponentImpl dtc : components) {
int length = dtc.getLength();
if (dtc.getDataType() == dt) {
length = getPreferredComponentLength(dt, length);
int length = dt.getLength();
if (length <= 0) {
length = dtc.getLength();
}
dtc.setLength(length);
changed = true;
}