mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 10:49:34 +02:00
GP-862 Refactor of Composite interface and internals. Changes made to
packing and alignment methods (see WhatsNew.html for API changes).
This commit is contained in:
parent
3b867b3444
commit
da800b6e41
166 changed files with 6316 additions and 5486 deletions
|
@ -201,7 +201,9 @@ public class DataTypeArchiveDB extends DomainObjectAdapterDB
|
|||
@Override
|
||||
protected void close() {
|
||||
super.close();
|
||||
dataTypeManager.dispose();
|
||||
if (dataTypeManager != null) {
|
||||
dataTypeManager.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -283,11 +285,15 @@ public class DataTypeArchiveDB extends DomainObjectAdapterDB
|
|||
* notification the a data type has changed
|
||||
* @param dataTypeID the id of the data type that changed.
|
||||
* @param type the type of the change (moved, renamed, etc.)
|
||||
* @param isAutoResponseChange true if change is an auto-response change caused by
|
||||
* another datatype's change (e.g., size, alignment), else false in which case this
|
||||
* change will be added to archive change-set to aid merge conflict detection.
|
||||
* @param oldValue the old data type.
|
||||
* @param newValue the new data type.
|
||||
*/
|
||||
public void dataTypeChanged(long dataTypeID, int type, Object oldValue, Object newValue) {
|
||||
if (recordChanges) {
|
||||
public void dataTypeChanged(long dataTypeID, int type, boolean isAutoResponseChange,
|
||||
Object oldValue, Object newValue) {
|
||||
if (recordChanges && !isAutoResponseChange) {
|
||||
((DataTypeArchiveDBChangeSet) changeSet).dataTypeChanged(dataTypeID);
|
||||
}
|
||||
changed = true;
|
||||
|
|
|
@ -813,11 +813,17 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM
|
|||
* notification the a datatype has changed
|
||||
* @param dataTypeID the id of the datatype that changed.
|
||||
* @param type the type of the change (moved, renamed, etc.)
|
||||
* @param isAutoChange true if change was an automatic change in response to
|
||||
* another datatype's change (e.g., size, alignment), else false in which case this
|
||||
* change will be added to program change-set to aid merge conflict detection.
|
||||
* @param oldValue the old datatype.
|
||||
* @param newValue the new datatype.
|
||||
*/
|
||||
public void dataTypeChanged(long dataTypeID, int type, Object oldValue, Object newValue) {
|
||||
if (recordChanges) {
|
||||
public void dataTypeChanged(long dataTypeID, int type, boolean isAutoChange,
|
||||
Object oldValue, Object newValue) {
|
||||
// TODO: do not need to record type changes for packed composite change which is in repsonse
|
||||
// to component size or alignment change.
|
||||
if (recordChanges && !isAutoChange) {
|
||||
((ProgramDBChangeSet) changeSet).dataTypeChanged(dataTypeID);
|
||||
}
|
||||
changed = true;
|
||||
|
|
|
@ -115,6 +115,11 @@ class ArrayDB extends DataTypeDB implements Array {
|
|||
return getDataType().isDynamicallySized();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isZeroLength() {
|
||||
return getDataType().isZeroLength();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLength() {
|
||||
checkIsValid();
|
||||
|
@ -244,10 +249,10 @@ class ArrayDB extends DataTypeDB implements Array {
|
|||
notifyNameChanged(myOldName);
|
||||
}
|
||||
if (getLength() != oldLength) {
|
||||
notifySizeChanged();
|
||||
notifySizeChanged(false);
|
||||
}
|
||||
else {
|
||||
dataMgr.dataTypeChanged(this);
|
||||
dataMgr.dataTypeChanged(this, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -265,10 +270,21 @@ class ArrayDB extends DataTypeDB implements Array {
|
|||
public void dataTypeSizeChanged(DataType dt) {
|
||||
lock.acquire();
|
||||
try {
|
||||
checkIsValid();
|
||||
if (checkIsValid() && dt == getDataType()) {
|
||||
notifySizeChanged(true);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
if (dt == getDataType()) {
|
||||
notifySizeChanged();
|
||||
@Override
|
||||
public void dataTypeAlignmentChanged(DataType dt) {
|
||||
lock.acquire();
|
||||
try {
|
||||
if (checkIsValid() && dt == getDataType()) {
|
||||
notifyAlignmentChanged(true);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
|
|
|
@ -28,17 +28,7 @@ import ghidra.util.exception.AssertException;
|
|||
/**
|
||||
* Database implementation for a structure or union.
|
||||
*/
|
||||
abstract class CompositeDB extends DataTypeDB implements Composite {
|
||||
|
||||
// Internal Alignment Constants
|
||||
protected static final int UNALIGNED = CompositeDBAdapter.UNALIGNED;
|
||||
protected static final int ALIGNED_NO_PACKING = CompositeDBAdapter.ALIGNED_NO_PACKING;
|
||||
// Otherwise the packing value (1 to (2**32 - 1)).
|
||||
|
||||
// External (Minimum) Alignment Constants
|
||||
protected static final int MACHINE_ALIGNED = CompositeDBAdapter.MACHINE_ALIGNED;
|
||||
protected static final int DEFAULT_ALIGNED = CompositeDBAdapter.DEFAULT_ALIGNED;
|
||||
// Otherwise the alignment value (1 to (2**32 - 1)).
|
||||
abstract class CompositeDB extends DataTypeDB implements CompositeInternal {
|
||||
|
||||
protected CompositeDBAdapter compositeAdapter;
|
||||
protected ComponentDBAdapter componentAdapter;
|
||||
|
@ -81,7 +71,7 @@ abstract class CompositeDB extends DataTypeDB implements Composite {
|
|||
* @return preferred component length
|
||||
*/
|
||||
protected int getPreferredComponentLength(DataType dataType, int length) {
|
||||
if ((isInternallyAligned() || (this instanceof Union)) && !(dataType instanceof Dynamic)) {
|
||||
if ((isPackingEnabled() || (this instanceof Union)) && !(dataType instanceof Dynamic)) {
|
||||
length = -1; // force use of datatype size
|
||||
}
|
||||
int dtLength = dataType.getLength();
|
||||
|
@ -114,7 +104,7 @@ abstract class CompositeDB extends DataTypeDB implements Composite {
|
|||
* @param bitfieldComponent bitfield component
|
||||
* @param oldDt affected datatype which has been removed or replaced
|
||||
* @param newDt replacement datatype
|
||||
* @param true if bitfield component was modified
|
||||
* @return true if bitfield component was modified
|
||||
* @throws InvalidDataTypeException if bitfield was based upon oldDt but new
|
||||
* datatype is invalid for a bitfield
|
||||
*/
|
||||
|
@ -200,7 +190,7 @@ abstract class CompositeDB extends DataTypeDB implements Composite {
|
|||
|
||||
@Override
|
||||
public boolean isDynamicallySized() {
|
||||
return isInternallyAligned();
|
||||
return isPackingEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -301,7 +291,7 @@ abstract class CompositeDB extends DataTypeDB implements Composite {
|
|||
* @throws IllegalArgumentException if the data type is invalid.
|
||||
*/
|
||||
protected void validateDataType(DataType dataType) {
|
||||
if (isInternallyAligned() && dataType == DataType.DEFAULT) {
|
||||
if (isPackingEnabled() && dataType == DataType.DEFAULT) {
|
||||
throw new IllegalArgumentException(
|
||||
"The DEFAULT data type is not allowed in an aligned composite data type.");
|
||||
}
|
||||
|
@ -335,7 +325,7 @@ abstract class CompositeDB extends DataTypeDB implements Composite {
|
|||
checkDeleted();
|
||||
record.setLongValue(CompositeDBAdapter.COMPOSITE_LAST_CHANGE_TIME_COL, lastChangeTime);
|
||||
compositeAdapter.updateRecord(record, false);
|
||||
dataMgr.dataTypeChanged(this);
|
||||
dataMgr.dataTypeChanged(this, false);
|
||||
}
|
||||
catch (IOException e) {
|
||||
dataMgr.dbError(e);
|
||||
|
@ -352,7 +342,7 @@ abstract class CompositeDB extends DataTypeDB implements Composite {
|
|||
checkDeleted();
|
||||
record.setLongValue(CompositeDBAdapter.COMPOSITE_SOURCE_SYNC_TIME_COL, lastChangeTime);
|
||||
compositeAdapter.updateRecord(record, false);
|
||||
dataMgr.dataTypeChanged(this);
|
||||
dataMgr.dataTypeChanged(this, false);
|
||||
}
|
||||
catch (IOException e) {
|
||||
dataMgr.dbError(e);
|
||||
|
@ -374,7 +364,7 @@ abstract class CompositeDB extends DataTypeDB implements Composite {
|
|||
checkDeleted();
|
||||
record.setLongValue(CompositeDBAdapter.COMPOSITE_UNIVERSAL_DT_ID, id.getValue());
|
||||
compositeAdapter.updateRecord(record, false);
|
||||
dataMgr.dataTypeChanged(this);
|
||||
dataMgr.dataTypeChanged(this, false);
|
||||
}
|
||||
catch (IOException e) {
|
||||
dataMgr.dbError(e);
|
||||
|
@ -398,7 +388,7 @@ abstract class CompositeDB extends DataTypeDB implements Composite {
|
|||
checkDeleted();
|
||||
record.setLongValue(CompositeDBAdapter.COMPOSITE_SOURCE_ARCHIVE_ID_COL, id.getValue());
|
||||
compositeAdapter.updateRecord(record, false);
|
||||
dataMgr.dataTypeChanged(this);
|
||||
dataMgr.dataTypeChanged(this, false);
|
||||
}
|
||||
catch (IOException e) {
|
||||
dataMgr.dbError(e);
|
||||
|
@ -409,56 +399,134 @@ abstract class CompositeDB extends DataTypeDB implements Composite {
|
|||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPackingValue() {
|
||||
int dbValue = record.getIntValue(CompositeDBAdapter.COMPOSITE_INTERNAL_ALIGNMENT_COL);
|
||||
if (dbValue == CompositeDB.UNALIGNED || dbValue == CompositeDB.ALIGNED_NO_PACKING) {
|
||||
return 0;
|
||||
protected final int getNonPackedAlignment() {
|
||||
int alignment;
|
||||
int minimumAlignment = getStoredMinimumAlignment();
|
||||
if (minimumAlignment == DEFAULT_ALIGNMENT) {
|
||||
alignment = 1;
|
||||
}
|
||||
else if (minimumAlignment == MACHINE_ALIGNMENT) {
|
||||
alignment = getDataOrganization().getMachineAlignment();
|
||||
}
|
||||
else {
|
||||
alignment = minimumAlignment;
|
||||
}
|
||||
return alignment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get computed alignment and optionally update record. May only be invoked with
|
||||
* lock acquired.
|
||||
* @param updateRecord if true record should be updated without timestamp change
|
||||
* @return computed alignment
|
||||
*/
|
||||
protected abstract int getComputedAlignment(boolean updateRecord);
|
||||
|
||||
@Override
|
||||
public final int getAlignment() {
|
||||
lock.acquire();
|
||||
try {
|
||||
return getComputedAlignment(checkIsValid() && dataMgr.isTransactionActive());
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
return dbValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPackingValue(int packingValue) {
|
||||
boolean changed = false;
|
||||
if (!isInternallyAligned()) {
|
||||
doSetInternallyAligned(true);
|
||||
changed = true;
|
||||
public final void repack() {
|
||||
lock.acquire();
|
||||
try {
|
||||
checkDeleted();
|
||||
repack(false, true);
|
||||
}
|
||||
if (packingValue != getPackingValue()) {
|
||||
doSetPackingValue(packingValue);
|
||||
changed = true;
|
||||
}
|
||||
if (changed) {
|
||||
adjustInternalAlignment(false);
|
||||
notifyAlignmentChanged();
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
public void doSetPackingValue(int packingValue) {
|
||||
if (packingValue < 0) {
|
||||
packingValue = NOT_PACKING;
|
||||
/**
|
||||
* Repack components within this composite based on the current packing, alignment
|
||||
* and {@link DataOrganization} settings. Non-packed Structures: change detection
|
||||
* is limited to component count and length is assumed to already be correct.
|
||||
* May only be invoked with lock acquired.
|
||||
* <p>
|
||||
* NOTE: If modifications to stored length are made prior to invoking this method,
|
||||
* detection of a size change may not be possible.
|
||||
* <p>
|
||||
* NOTE: Currently a change in calculated alignment can not be provided since
|
||||
* this value is not stored.
|
||||
*
|
||||
* @param isAutoChange true if changes are in response to another another datatype's change.
|
||||
* @param notify if true notification will be sent to parents if a size change
|
||||
* or component placement change is detected.
|
||||
* @return true if a layout change was detected.
|
||||
*/
|
||||
protected abstract boolean repack(boolean isAutoChange, boolean notify);
|
||||
|
||||
@Override
|
||||
public int getStoredPackingValue() {
|
||||
lock.acquire();
|
||||
try {
|
||||
checkIsValid();
|
||||
return record.getIntValue(CompositeDBAdapter.COMPOSITE_PACKING_COL);
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public PackingType getPackingType() {
|
||||
int packing = getStoredPackingValue();
|
||||
if (packing < DEFAULT_PACKING) {
|
||||
return PackingType.DISABLED;
|
||||
}
|
||||
if (packing == DEFAULT_PACKING) {
|
||||
return PackingType.DEFAULT;
|
||||
}
|
||||
return PackingType.EXPLICIT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getExplicitPackingValue() {
|
||||
return getStoredPackingValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExplicitPackingValue(int packingValue) {
|
||||
if (packingValue <= 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"explicit packing value must be positive: " + packingValue);
|
||||
}
|
||||
setStoredPackingValue(packingValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setToDefaultPacking() {
|
||||
setStoredPackingValue(DEFAULT_PACKING);
|
||||
}
|
||||
|
||||
private void setStoredPackingValue(int packingValue) {
|
||||
if (packingValue < NO_PACKING) {
|
||||
throw new IllegalArgumentException("invalid packing value: " + packingValue);
|
||||
}
|
||||
lock.acquire();
|
||||
try {
|
||||
checkDeleted();
|
||||
if (packingValue == getPackingValue()) {
|
||||
int oldPackingValue = getStoredPackingValue();
|
||||
if (packingValue == oldPackingValue) {
|
||||
return;
|
||||
}
|
||||
int dbPackingValue;
|
||||
if (packingValue == NOT_PACKING) {
|
||||
if (isInternallyAligned()) {
|
||||
dbPackingValue = ALIGNED_NO_PACKING;
|
||||
}
|
||||
else {
|
||||
dbPackingValue = UNALIGNED;
|
||||
}
|
||||
if (oldPackingValue == NO_PACKING || packingValue == NO_PACKING) {
|
||||
// force default alignment when transitioning to or from disabled packing
|
||||
record.setIntValue(CompositeDBAdapter.COMPOSITE_MIN_ALIGN_COL, DEFAULT_ALIGNMENT);
|
||||
}
|
||||
else {
|
||||
dbPackingValue = packingValue;
|
||||
}
|
||||
record.setIntValue(CompositeDBAdapter.COMPOSITE_INTERNAL_ALIGNMENT_COL, dbPackingValue);
|
||||
record.setIntValue(CompositeDBAdapter.COMPOSITE_PACKING_COL, packingValue);
|
||||
compositeAdapter.updateRecord(record, true);
|
||||
if (!repack(false, true)) {
|
||||
dataMgr.dataTypeChanged(this, false);
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
dataMgr.dbError(e);
|
||||
|
@ -469,125 +537,72 @@ abstract class CompositeDB extends DataTypeDB implements Composite {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean isDefaultAligned() {
|
||||
int dbValue = record.getIntValue(CompositeDBAdapter.COMPOSITE_EXTERNAL_ALIGNMENT_COL);
|
||||
return (dbValue == CompositeDB.DEFAULT_ALIGNED);
|
||||
public AlignmentType getAlignmentType() {
|
||||
int minimumAlignment = getStoredMinimumAlignment();
|
||||
if (minimumAlignment < DEFAULT_ALIGNMENT) {
|
||||
return AlignmentType.MACHINE;
|
||||
}
|
||||
if (minimumAlignment == DEFAULT_ALIGNMENT) {
|
||||
return AlignmentType.DEFAULT;
|
||||
}
|
||||
return AlignmentType.EXPLICIT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMachineAligned() {
|
||||
int dbValue = record.getIntValue(CompositeDBAdapter.COMPOSITE_EXTERNAL_ALIGNMENT_COL);
|
||||
return (dbValue == CompositeDB.MACHINE_ALIGNED);
|
||||
public void setToDefaultAligned() {
|
||||
setStoredMinimumAlignment(DEFAULT_ALIGNMENT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinimumAlignment() {
|
||||
int dbValue = record.getIntValue(CompositeDBAdapter.COMPOSITE_EXTERNAL_ALIGNMENT_COL);
|
||||
if (dbValue == CompositeDB.MACHINE_ALIGNED) {
|
||||
return getMachineAlignment();
|
||||
}
|
||||
if (dbValue == CompositeDB.DEFAULT_ALIGNED) {
|
||||
return getDefaultAlignment();
|
||||
}
|
||||
return dbValue;
|
||||
}
|
||||
|
||||
private int getDefaultAlignment() {
|
||||
return Composite.DEFAULT_ALIGNMENT_VALUE;
|
||||
}
|
||||
|
||||
private int getMachineAlignment() {
|
||||
return dataMgr.getDataOrganization().getMachineAlignment();
|
||||
public void setToMachineAligned() {
|
||||
setStoredMinimumAlignment(MACHINE_ALIGNMENT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMinimumAlignment(int externalAlignment) {
|
||||
boolean changed = false;
|
||||
if (!isInternallyAligned()) {
|
||||
doSetInternallyAligned(true);
|
||||
changed = true;
|
||||
}
|
||||
if (doSetMinimumAlignment(externalAlignment)) {
|
||||
changed = true;
|
||||
}
|
||||
if (changed) {
|
||||
adjustInternalAlignment(false);
|
||||
notifyAlignmentChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean doSetMinimumAlignment(int externalAlignment) {
|
||||
if (externalAlignment < 1) {
|
||||
externalAlignment = DEFAULT_ALIGNED;
|
||||
}
|
||||
return modifyAlignment(externalAlignment);
|
||||
public int getExplicitMinimumAlignment() {
|
||||
return getStoredMinimumAlignment();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setToDefaultAlignment() {
|
||||
boolean changed = false;
|
||||
if (!isInternallyAligned()) {
|
||||
doSetInternallyAligned(true);
|
||||
changed = true;
|
||||
public int getStoredMinimumAlignment() {
|
||||
lock.acquire();
|
||||
try {
|
||||
checkIsValid();
|
||||
return record.getIntValue(CompositeDBAdapter.COMPOSITE_MIN_ALIGN_COL);
|
||||
}
|
||||
if (doSetToDefaultAlignment()) {
|
||||
changed = true;
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
if (changed) {
|
||||
adjustInternalAlignment(false);
|
||||
notifyAlignmentChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean doSetToDefaultAlignment() {
|
||||
return modifyAlignment(CompositeDB.DEFAULT_ALIGNED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setToMachineAlignment() {
|
||||
boolean changed = false;
|
||||
if (!isInternallyAligned()) {
|
||||
doSetInternallyAligned(true);
|
||||
changed = true;
|
||||
}
|
||||
if (doSetToMachineAlignment()) {
|
||||
changed = true;
|
||||
}
|
||||
if (changed) {
|
||||
adjustInternalAlignment(false);
|
||||
notifyAlignmentChanged();
|
||||
public void setExplicitMinimumAlignment(int minimumAlignment) {
|
||||
if (minimumAlignment <= 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"explicit minimum alignment must be positive: " + minimumAlignment);
|
||||
}
|
||||
setStoredMinimumAlignment(minimumAlignment);
|
||||
}
|
||||
|
||||
public boolean doSetToMachineAlignment() {
|
||||
return modifyAlignment(CompositeDB.MACHINE_ALIGNED);
|
||||
}
|
||||
|
||||
private boolean modifyAlignment(int dbExternalAlignment) {
|
||||
private void setStoredMinimumAlignment(int minimumAlignment) {
|
||||
if (minimumAlignment < MACHINE_ALIGNMENT) {
|
||||
throw new IllegalArgumentException(
|
||||
"invalid minimum alignment value: " + minimumAlignment);
|
||||
}
|
||||
lock.acquire();
|
||||
try {
|
||||
checkDeleted();
|
||||
if (isMachineAligned()) {
|
||||
if (dbExternalAlignment == MACHINE_ALIGNED) {
|
||||
return false;
|
||||
}
|
||||
if (minimumAlignment == getStoredMinimumAlignment()) {
|
||||
return;
|
||||
}
|
||||
if (isDefaultAligned()) {
|
||||
if (dbExternalAlignment == DEFAULT_ALIGNED) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (dbExternalAlignment == getMinimumAlignment()) {
|
||||
return false;
|
||||
}
|
||||
record.setIntValue(CompositeDBAdapter.COMPOSITE_EXTERNAL_ALIGNMENT_COL,
|
||||
dbExternalAlignment);
|
||||
record.setIntValue(CompositeDBAdapter.COMPOSITE_MIN_ALIGN_COL, minimumAlignment);
|
||||
compositeAdapter.updateRecord(record, true);
|
||||
return true;
|
||||
if (!repack(false, true)) {
|
||||
dataMgr.dataTypeChanged(this, false);
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
dataMgr.dbError(e);
|
||||
return false;
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
|
@ -618,184 +633,40 @@ abstract class CompositeDB extends DataTypeDB implements Composite {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notification that this composite data type's alignment has changed.
|
||||
*/
|
||||
protected void notifyAlignmentChanged() {
|
||||
// TODO: This method is not properly invoked when new components are
|
||||
// added which could change the alignment of this composite
|
||||
for (DataType dt : dataMgr.getParentDataTypes(key)) {
|
||||
if (dt instanceof Composite) {
|
||||
Composite composite = (Composite) dt;
|
||||
composite.dataTypeAlignmentChanged(this);
|
||||
}
|
||||
}
|
||||
dataMgr.dataTypeChanged(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInternallyAligned() {
|
||||
int dbValue = record.getIntValue(CompositeDBAdapter.COMPOSITE_INTERNAL_ALIGNMENT_COL);
|
||||
return dbValue != UNALIGNED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInternallyAligned(boolean aligned) {
|
||||
if (aligned == isInternallyAligned()) {
|
||||
public void setPackingEnabled(boolean enabled) {
|
||||
if (enabled == isPackingEnabled()) {
|
||||
return;
|
||||
}
|
||||
doSetInternallyAligned(aligned);
|
||||
adjustInternalAlignment(true);
|
||||
notifyAlignmentChanged();
|
||||
}
|
||||
|
||||
protected void doSetInternallyAligned(boolean aligned) {
|
||||
lock.acquire();
|
||||
try {
|
||||
checkDeleted();
|
||||
if (aligned == isInternallyAligned()) {
|
||||
return;
|
||||
}
|
||||
int dbValue = aligned ? CompositeDB.ALIGNED_NO_PACKING : CompositeDB.UNALIGNED;
|
||||
record.setIntValue(CompositeDBAdapter.COMPOSITE_INTERNAL_ALIGNMENT_COL, dbValue);
|
||||
if (!aligned) {
|
||||
int dbExternalAlignment = CompositeDB.DEFAULT_ALIGNED;
|
||||
record.setIntValue(CompositeDBAdapter.COMPOSITE_EXTERNAL_ALIGNMENT_COL,
|
||||
dbExternalAlignment);
|
||||
}
|
||||
compositeAdapter.updateRecord(record, true);
|
||||
}
|
||||
catch (IOException e) {
|
||||
dataMgr.dbError(e);
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
protected void setAlignment(Composite composite, boolean notify) {
|
||||
doSetInternallyAligned(composite.isInternallyAligned());
|
||||
|
||||
doSetPackingValue(composite.getPackingValue());
|
||||
|
||||
if (composite.isDefaultAligned()) {
|
||||
doSetToDefaultAlignment();
|
||||
}
|
||||
else if (composite.isMachineAligned()) {
|
||||
doSetToMachineAlignment();
|
||||
}
|
||||
else {
|
||||
doSetMinimumAlignment(composite.getMinimumAlignment());
|
||||
}
|
||||
adjustInternalAlignment(notify);
|
||||
setStoredPackingValue(enabled ? DEFAULT_PACKING : NO_PACKING);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjusts the internal alignment of components within this composite based on
|
||||
* the current settings of the internal alignment, packing, alignment type and
|
||||
* minimum alignment value. This method should be called whenever any of the
|
||||
* above settings are changed or whenever a components data type is changed or a
|
||||
* component is added or removed.
|
||||
*
|
||||
* @param notify
|
||||
* Copy packing and alignment settings from specified composite without
|
||||
* repacking or notification.
|
||||
* @param composite instance whose packing and alignment are to be copied
|
||||
* @throws IOException if database IO error occured
|
||||
*/
|
||||
protected abstract void adjustInternalAlignment(boolean notify);
|
||||
|
||||
@Override
|
||||
public int getAlignment() {
|
||||
// TODO: use cached value if available (requires DB change to facilitate)
|
||||
return CompositeAlignmentHelper.getAlignment(getDataOrganization(), this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dump all components for use in {@link #toString()} representation.
|
||||
*
|
||||
* @param buffer string buffer
|
||||
* @param pad padding to be used with each component output line
|
||||
*/
|
||||
protected void dumpComponents(StringBuilder buffer, String pad) {
|
||||
// limit output of filler components for unaligned structures
|
||||
DataTypeComponent[] components = getDefinedComponents();
|
||||
for (DataTypeComponent dtc : components) {
|
||||
DataType dataType = dtc.getDataType();
|
||||
buffer.append(pad + dtc.getOffset());
|
||||
buffer.append(pad + dataType.getName());
|
||||
if (dataType instanceof BitFieldDataType) {
|
||||
BitFieldDataType bfDt = (BitFieldDataType) dataType;
|
||||
buffer.append("(");
|
||||
buffer.append(Integer.toString(bfDt.getBitOffset()));
|
||||
buffer.append(")");
|
||||
}
|
||||
buffer.append(pad + dtc.getLength());
|
||||
buffer.append(pad + dtc.getFieldName());
|
||||
String comment = dtc.getComment();
|
||||
if (comment == null) {
|
||||
comment = "";
|
||||
}
|
||||
buffer.append(pad + "\"" + comment + "\"");
|
||||
buffer.append("\n");
|
||||
}
|
||||
protected void doSetPackingAndAlignment(CompositeInternal composite) throws IOException {
|
||||
record.setIntValue(CompositeDBAdapter.COMPOSITE_MIN_ALIGN_COL,
|
||||
composite.getStoredMinimumAlignment());
|
||||
record.setIntValue(CompositeDBAdapter.COMPOSITE_PACKING_COL,
|
||||
composite.getStoredPackingValue());
|
||||
compositeAdapter.updateRecord(record, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder stringBuffer = new StringBuilder();
|
||||
stringBuffer.append(getPathName() + "\n");
|
||||
stringBuffer.append(getAlignmentSettingsString() + "\n");
|
||||
stringBuffer.append(getTypeName() + " " + getDisplayName() + " {\n");
|
||||
dumpComponents(stringBuffer, " ");
|
||||
stringBuffer.append("}\n");
|
||||
stringBuffer.append(
|
||||
"Size = " + getLength() + " Actual Alignment = " + getAlignment() + "\n");
|
||||
return stringBuffer.toString();
|
||||
return CompositeDataTypeImpl.toString(this);
|
||||
}
|
||||
|
||||
private String getTypeName() {
|
||||
if (this instanceof Structure) {
|
||||
return "Structure";
|
||||
}
|
||||
else if (this instanceof Union) {
|
||||
return "Union";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
private String getAlignmentSettingsString() {
|
||||
StringBuffer stringBuffer = new StringBuffer();
|
||||
if (!isInternallyAligned()) {
|
||||
stringBuffer.append("Unaligned");
|
||||
}
|
||||
else if (isDefaultAligned()) {
|
||||
stringBuffer.append("Aligned");
|
||||
}
|
||||
else if (isMachineAligned()) {
|
||||
stringBuffer.append("Machine aligned");
|
||||
}
|
||||
else {
|
||||
long alignment = getMinimumAlignment();
|
||||
stringBuffer.append("align(" + alignment + ")");
|
||||
}
|
||||
stringBuffer.append(getPackingString());
|
||||
return stringBuffer.toString();
|
||||
}
|
||||
|
||||
private String getPackingString() {
|
||||
if (!isInternallyAligned()) {
|
||||
return "";
|
||||
}
|
||||
long packingValue = getPackingValue();
|
||||
if (packingValue == Composite.NOT_PACKING) {
|
||||
return "";
|
||||
}
|
||||
return " pack(" + packingValue + ")";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Perform any neccessary component adjustments based on
|
||||
* sizes and alignment of components differing from their
|
||||
* specification which may be influenced by the data organization.
|
||||
* If this composite changes parents will not be
|
||||
* notified - handling this is the caller's responsibility.
|
||||
* @throws IOException if database IO error occurs
|
||||
*/
|
||||
protected abstract void fixupComponents();
|
||||
protected abstract void fixupComponents() throws IOException;
|
||||
}
|
||||
|
|
|
@ -18,8 +18,10 @@ package ghidra.program.database.data;
|
|||
import java.io.IOException;
|
||||
|
||||
import db.*;
|
||||
import ghidra.program.model.data.CompositeInternal;
|
||||
import ghidra.util.UniversalID;
|
||||
import ghidra.util.exception.*;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.exception.VersionException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
/**
|
||||
|
@ -28,38 +30,29 @@ import ghidra.util.task.TaskMonitor;
|
|||
abstract class CompositeDBAdapter {
|
||||
|
||||
static final String COMPOSITE_TABLE_NAME = "Composite Data Types";
|
||||
static final Schema COMPOSITE_SCHEMA = CompositeDBAdapterV2V3.V2_COMPOSITE_SCHEMA;
|
||||
static final Schema COMPOSITE_SCHEMA = CompositeDBAdapterV5.V5_COMPOSITE_SCHEMA;
|
||||
|
||||
static final int COMPOSITE_NAME_COL = CompositeDBAdapterV2V3.V2_COMPOSITE_NAME_COL;
|
||||
static final int COMPOSITE_COMMENT_COL = CompositeDBAdapterV2V3.V2_COMPOSITE_COMMENT_COL;
|
||||
static final int COMPOSITE_IS_UNION_COL = CompositeDBAdapterV2V3.V2_COMPOSITE_IS_UNION_COL;
|
||||
static final int COMPOSITE_CAT_COL = CompositeDBAdapterV2V3.V2_COMPOSITE_CAT_COL;
|
||||
static final int COMPOSITE_LENGTH_COL = CompositeDBAdapterV2V3.V2_COMPOSITE_LENGTH_COL;
|
||||
static final int COMPOSITE_NAME_COL = CompositeDBAdapterV5.V5_COMPOSITE_NAME_COL;
|
||||
static final int COMPOSITE_COMMENT_COL = CompositeDBAdapterV5.V5_COMPOSITE_COMMENT_COL;
|
||||
static final int COMPOSITE_IS_UNION_COL = CompositeDBAdapterV5.V5_COMPOSITE_IS_UNION_COL;
|
||||
static final int COMPOSITE_CAT_COL = CompositeDBAdapterV5.V5_COMPOSITE_CAT_COL;
|
||||
static final int COMPOSITE_LENGTH_COL = CompositeDBAdapterV5.V5_COMPOSITE_LENGTH_COL;
|
||||
static final int COMPOSITE_ALIGNMENT_COL = CompositeDBAdapterV5.V5_COMPOSITE_ALIGNMENT_COL;
|
||||
static final int COMPOSITE_NUM_COMPONENTS_COL =
|
||||
CompositeDBAdapterV2V3.V2_COMPOSITE_NUM_COMPONENTS_COL;
|
||||
CompositeDBAdapterV5.V5_COMPOSITE_NUM_COMPONENTS_COL;
|
||||
static final int COMPOSITE_SOURCE_ARCHIVE_ID_COL =
|
||||
CompositeDBAdapterV2V3.V2_COMPOSITE_SOURCE_ARCHIVE_ID_COL;
|
||||
CompositeDBAdapterV5.V5_COMPOSITE_SOURCE_ARCHIVE_ID_COL;
|
||||
static final int COMPOSITE_UNIVERSAL_DT_ID =
|
||||
CompositeDBAdapterV2V3.V2_COMPOSITE_UNIVERSAL_DT_ID_COL;
|
||||
CompositeDBAdapterV5.V5_COMPOSITE_UNIVERSAL_DT_ID_COL;
|
||||
static final int COMPOSITE_SOURCE_SYNC_TIME_COL =
|
||||
CompositeDBAdapterV2V3.V2_COMPOSITE_SOURCE_SYNC_TIME_COL;
|
||||
CompositeDBAdapterV5.V5_COMPOSITE_SOURCE_SYNC_TIME_COL;
|
||||
static final int COMPOSITE_LAST_CHANGE_TIME_COL =
|
||||
CompositeDBAdapterV2V3.V2_COMPOSITE_LAST_CHANGE_TIME_COL;
|
||||
static final int COMPOSITE_INTERNAL_ALIGNMENT_COL =
|
||||
CompositeDBAdapterV2V3.V2_COMPOSITE_INTERNAL_ALIGNMENT_COL;
|
||||
static final int COMPOSITE_EXTERNAL_ALIGNMENT_COL =
|
||||
CompositeDBAdapterV2V3.V2_COMPOSITE_EXTERNAL_ALIGNMENT_COL;
|
||||
CompositeDBAdapterV5.V5_COMPOSITE_LAST_CHANGE_TIME_COL;
|
||||
static final int COMPOSITE_PACKING_COL =
|
||||
CompositeDBAdapterV5.V5_COMPOSITE_PACK_COL;
|
||||
static final int COMPOSITE_MIN_ALIGN_COL = CompositeDBAdapterV5.V5_COMPOSITE_MIN_ALIGN_COL;
|
||||
|
||||
// Internal Alignment Constants
|
||||
static final byte UNALIGNED = (byte) -1;
|
||||
static final byte ALIGNED_NO_PACKING = (byte) 0;
|
||||
// Otherwise the packing value.
|
||||
|
||||
// External Alignment Constants
|
||||
static final byte MACHINE_ALIGNED = (byte) -1;
|
||||
static final byte DEFAULT_ALIGNED = (byte) 0;
|
||||
|
||||
// Otherwise the external minimum alignment value.
|
||||
// Stored Packing and Minimum Alignment values are consistent with CompositeInternal
|
||||
|
||||
/**
|
||||
* Gets an adapter for working with the composite data type database table.
|
||||
|
@ -75,18 +68,21 @@ abstract class CompositeDBAdapter {
|
|||
*/
|
||||
static CompositeDBAdapter getAdapter(DBHandle handle, int openMode, TaskMonitor monitor)
|
||||
throws VersionException, IOException, CancelledException {
|
||||
if (openMode == DBConstants.CREATE) {
|
||||
return new CompositeDBAdapterV5(handle, true);
|
||||
}
|
||||
try {
|
||||
return new CompositeDBAdapterV2V3(handle, openMode);
|
||||
return new CompositeDBAdapterV5(handle, false);
|
||||
}
|
||||
catch (VersionException e) {
|
||||
if (openMode == DBConstants.CREATE) {
|
||||
throw new AssertException();
|
||||
if (!e.isUpgradable() || openMode == DBConstants.UPDATE) {
|
||||
throw e;
|
||||
}
|
||||
CompositeDBAdapter adapter = findReadOnlyAdapter(handle);
|
||||
if (openMode == DBConstants.UPGRADE) {
|
||||
CompositeDBAdapter adapter = findReadOnlyAdapter(handle);
|
||||
return upgrade(handle, adapter, monitor);
|
||||
}
|
||||
throw e;
|
||||
return adapter;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -100,7 +96,7 @@ abstract class CompositeDBAdapter {
|
|||
static CompositeDBAdapter findReadOnlyAdapter(DBHandle handle)
|
||||
throws VersionException, IOException {
|
||||
try {
|
||||
return new CompositeDBAdapterV2V3(handle);
|
||||
return new CompositeDBAdapterV2V4(handle);
|
||||
}
|
||||
catch (VersionException e) {
|
||||
// ignore
|
||||
|
@ -132,7 +128,7 @@ abstract class CompositeDBAdapter {
|
|||
long id = tmpHandle.startTransaction();
|
||||
CompositeDBAdapter tmpAdapter = null;
|
||||
try {
|
||||
tmpAdapter = new CompositeDBAdapterV2V3(tmpHandle, DBConstants.CREATE);
|
||||
tmpAdapter = new CompositeDBAdapterV5(tmpHandle, true);
|
||||
RecordIterator it = oldAdapter.getRecords();
|
||||
while (it.hasNext()) {
|
||||
monitor.checkCanceled();
|
||||
|
@ -140,7 +136,7 @@ abstract class CompositeDBAdapter {
|
|||
tmpAdapter.updateRecord(rec, false);
|
||||
}
|
||||
oldAdapter.deleteTable(handle);
|
||||
CompositeDBAdapter newAdapter = new CompositeDBAdapterV2V3(handle, DBConstants.CREATE);
|
||||
CompositeDBAdapter newAdapter = new CompositeDBAdapterV5(handle, true);
|
||||
it = tmpAdapter.getRecords();
|
||||
while (it.hasNext()) {
|
||||
monitor.checkCanceled();
|
||||
|
@ -162,19 +158,20 @@ abstract class CompositeDBAdapter {
|
|||
* @param isUnion true indicates this data type is a union and all component offsets are at zero.
|
||||
* @param categoryID the ID for the category that contains this array.
|
||||
* @param length the total length or size of this data type.
|
||||
* @param computedAlignment computed alignment for composite or -1 if not yet computed
|
||||
* @param sourceArchiveID the ID for the source archive where this data type originated.
|
||||
* @param sourceDataTypeID the ID of the associated data type in the source archive.
|
||||
* @param lastChangeTime the time this data type was last changed.
|
||||
* @param internalAlignment UNALIGNED, ALIGNED_NO_PACKING or the packing value
|
||||
* currently in use by this data type.
|
||||
* @param externalAlignment DEFAULT_ALIGNED, MACHINE_ALIGNED or the minimum alignment value
|
||||
* currently in use by this data type.
|
||||
* @param packValue {@link CompositeInternal#NO_PACKING}, {@link CompositeInternal#DEFAULT_PACKING}
|
||||
* or the explicit pack value currently in use by this data type (positive value).
|
||||
* @param minAlignment {@link CompositeInternal#DEFAULT_ALIGNMENT}, {@link CompositeInternal#MACHINE_ALIGNMENT}
|
||||
* or the minimum alignment value currently in use by this data type (positive value).
|
||||
* @return the database record for this data type.
|
||||
* @throws IOException if the database can't be accessed.
|
||||
*/
|
||||
abstract DBRecord createRecord(String name, String comments, boolean isUnion, long categoryID,
|
||||
int length, long sourceArchiveID, long sourceDataTypeID, long lastChangeTime,
|
||||
int internalAlignment, int externalAlignment) throws IOException;
|
||||
int length, int computedAlignment, long sourceArchiveID, long sourceDataTypeID,
|
||||
long lastChangeTime, int packValue, int minAlignment) throws IOException;
|
||||
|
||||
/**
|
||||
* Gets a composite data type record from the database based on its ID.
|
||||
|
|
|
@ -18,8 +18,7 @@ package ghidra.program.database.data;
|
|||
import java.io.IOException;
|
||||
|
||||
import db.*;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.DataTypeManager;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.UniversalID;
|
||||
import ghidra.util.UniversalIdGenerator;
|
||||
import ghidra.util.exception.VersionException;
|
||||
|
@ -69,8 +68,8 @@ class CompositeDBAdapterV0 extends CompositeDBAdapter implements RecordTranslato
|
|||
|
||||
@Override
|
||||
public DBRecord createRecord(String name, String comments, boolean isUnion, long categoryID,
|
||||
int length, long sourceArchiveID, long sourceDataTypeID, long lastChangeTime,
|
||||
int internalAlignment, int externalAlignment) throws IOException {
|
||||
int length, int computedAlignment, long sourceArchiveID, long sourceDataTypeID,
|
||||
long lastChangeTime, int packValue, int minAlignment) throws IOException {
|
||||
throw new UnsupportedOperationException("Not allowed to update prior version #" + VERSION +
|
||||
" of " + COMPOSITE_TABLE_NAME + " table.");
|
||||
}
|
||||
|
@ -92,7 +91,8 @@ class CompositeDBAdapterV0 extends CompositeDBAdapter implements RecordTranslato
|
|||
|
||||
@Override
|
||||
public boolean removeRecord(long compositeID) throws IOException {
|
||||
return compositeTable.deleteRecord(compositeID);
|
||||
throw new UnsupportedOperationException("Not allowed to update prior version #" + VERSION +
|
||||
" of " + COMPOSITE_TABLE_NAME + " table.");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -129,8 +129,8 @@ class CompositeDBAdapterV0 extends CompositeDBAdapter implements RecordTranslato
|
|||
rec.setLongValue(COMPOSITE_UNIVERSAL_DT_ID, UniversalIdGenerator.nextID().getValue());
|
||||
rec.setLongValue(COMPOSITE_SOURCE_SYNC_TIME_COL, DataType.NO_SOURCE_SYNC_TIME);
|
||||
rec.setLongValue(COMPOSITE_LAST_CHANGE_TIME_COL, DataType.NO_LAST_CHANGE_TIME);
|
||||
rec.setIntValue(COMPOSITE_INTERNAL_ALIGNMENT_COL, CompositeDBAdapter.UNALIGNED);
|
||||
rec.setIntValue(COMPOSITE_EXTERNAL_ALIGNMENT_COL, CompositeDBAdapter.DEFAULT_ALIGNED);
|
||||
rec.setIntValue(COMPOSITE_PACKING_COL, CompositeInternal.NO_PACKING);
|
||||
rec.setIntValue(COMPOSITE_MIN_ALIGN_COL, CompositeInternal.DEFAULT_ALIGNMENT);
|
||||
return rec;
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ package ghidra.program.database.data;
|
|||
import java.io.IOException;
|
||||
|
||||
import db.*;
|
||||
import ghidra.program.model.data.CompositeInternal;
|
||||
import ghidra.util.UniversalID;
|
||||
import ghidra.util.exception.VersionException;
|
||||
|
||||
|
@ -37,13 +38,13 @@ class CompositeDBAdapterV1 extends CompositeDBAdapter implements RecordTranslato
|
|||
static final int V1_COMPOSITE_SOURCE_SYNC_TIME_COL = 8;
|
||||
static final int V1_COMPOSITE_LAST_CHANGE_TIME_COL = 9;
|
||||
|
||||
static final Schema V1_COMPOSITE_SCHEMA = new Schema(VERSION, "Data Type ID",
|
||||
new Field[] { StringField.INSTANCE, StringField.INSTANCE, BooleanField.INSTANCE,
|
||||
LongField.INSTANCE, IntField.INSTANCE, IntField.INSTANCE, LongField.INSTANCE,
|
||||
LongField.INSTANCE, LongField.INSTANCE, LongField.INSTANCE },
|
||||
new String[] { "Name", "Comment", "Is Union", "Category ID", "Length",
|
||||
"Number Of Components", "Source Archive ID", "Source Data Type ID", "Source Sync Time",
|
||||
"Last Change Time" });
|
||||
// static final Schema V1_COMPOSITE_SCHEMA = new Schema(VERSION, "Data Type ID",
|
||||
// new Field[] { StringField.INSTANCE, StringField.INSTANCE, BooleanField.INSTANCE,
|
||||
// LongField.INSTANCE, IntField.INSTANCE, IntField.INSTANCE, LongField.INSTANCE,
|
||||
// LongField.INSTANCE, LongField.INSTANCE, LongField.INSTANCE },
|
||||
// new String[] { "Name", "Comment", "Is Union", "Category ID", "Length",
|
||||
// "Number Of Components", "Source Archive ID", "Source Data Type ID", "Source Sync Time",
|
||||
// "Last Change Time" });
|
||||
|
||||
private Table compositeTable;
|
||||
|
||||
|
@ -72,8 +73,8 @@ class CompositeDBAdapterV1 extends CompositeDBAdapter implements RecordTranslato
|
|||
|
||||
@Override
|
||||
public DBRecord createRecord(String name, String comments, boolean isUnion, long categoryID,
|
||||
int length, long sourceArchiveID, long sourceDataTypeID, long lastChangeTime,
|
||||
int internalAlignment, int externalAlignment) throws IOException {
|
||||
int length, int computedAlignment, long sourceArchiveID, long sourceDataTypeID,
|
||||
long lastChangeTime, int packValue, int minAlignment) throws IOException {
|
||||
throw new UnsupportedOperationException("Not allowed to update prior version #" + VERSION +
|
||||
" of " + COMPOSITE_TABLE_NAME + " table.");
|
||||
}
|
||||
|
@ -95,7 +96,8 @@ class CompositeDBAdapterV1 extends CompositeDBAdapter implements RecordTranslato
|
|||
|
||||
@Override
|
||||
public boolean removeRecord(long compositeID) throws IOException {
|
||||
return compositeTable.deleteRecord(compositeID);
|
||||
throw new UnsupportedOperationException("Not allowed to update prior version #" + VERSION +
|
||||
" of " + COMPOSITE_TABLE_NAME + " table.");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -130,6 +132,7 @@ class CompositeDBAdapterV1 extends CompositeDBAdapter implements RecordTranslato
|
|||
oldRec.getBooleanValue(V1_COMPOSITE_IS_UNION_COL));
|
||||
rec.setLongValue(COMPOSITE_CAT_COL, oldRec.getLongValue(V1_COMPOSITE_CAT_COL));
|
||||
rec.setIntValue(COMPOSITE_LENGTH_COL, oldRec.getIntValue(V1_COMPOSITE_LENGTH_COL));
|
||||
rec.setIntValue(COMPOSITE_ALIGNMENT_COL, oldRec.getIntValue(-1));
|
||||
rec.setIntValue(COMPOSITE_NUM_COMPONENTS_COL,
|
||||
oldRec.getIntValue(V1_COMPOSITE_NUM_COMPONENTS_COL));
|
||||
rec.setLongValue(COMPOSITE_SOURCE_ARCHIVE_ID_COL,
|
||||
|
@ -140,8 +143,8 @@ class CompositeDBAdapterV1 extends CompositeDBAdapter implements RecordTranslato
|
|||
oldRec.getLongValue(V1_COMPOSITE_SOURCE_SYNC_TIME_COL));
|
||||
rec.setLongValue(COMPOSITE_LAST_CHANGE_TIME_COL,
|
||||
oldRec.getLongValue(V1_COMPOSITE_LAST_CHANGE_TIME_COL));
|
||||
rec.setIntValue(COMPOSITE_INTERNAL_ALIGNMENT_COL, CompositeDBAdapter.UNALIGNED);
|
||||
rec.setIntValue(COMPOSITE_EXTERNAL_ALIGNMENT_COL, CompositeDBAdapter.DEFAULT_ALIGNED);
|
||||
rec.setIntValue(COMPOSITE_PACKING_COL, CompositeInternal.NO_PACKING);
|
||||
rec.setIntValue(COMPOSITE_MIN_ALIGN_COL, CompositeInternal.DEFAULT_ALIGNMENT);
|
||||
return rec;
|
||||
}
|
||||
|
||||
|
@ -150,8 +153,8 @@ class CompositeDBAdapterV1 extends CompositeDBAdapter implements RecordTranslato
|
|||
Field[] keys = compositeTable.findRecords(new LongField(datatypeID.getValue()),
|
||||
V1_COMPOSITE_UNIVERSAL_DT_ID_COL);
|
||||
|
||||
for (int i = 0; i < keys.length; i++) {
|
||||
DBRecord record = compositeTable.getRecord(keys[i]);
|
||||
for (Field key : keys) {
|
||||
DBRecord record = compositeTable.getRecord(key);
|
||||
if (record.getLongValue(V1_COMPOSITE_SOURCE_ARCHIVE_ID_COL) == sourceID.getValue()) {
|
||||
return translateRecord(record);
|
||||
}
|
||||
|
|
|
@ -16,17 +16,15 @@
|
|||
package ghidra.program.database.data;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
|
||||
import db.*;
|
||||
import ghidra.util.ReadOnlyException;
|
||||
import ghidra.util.UniversalID;
|
||||
import ghidra.util.exception.VersionException;
|
||||
|
||||
/**
|
||||
* Version 2-3 implementation for accessing the Composite database table.
|
||||
* Version 2-4 implementation for accessing the Composite database table.
|
||||
*/
|
||||
class CompositeDBAdapterV2V3 extends CompositeDBAdapter {
|
||||
class CompositeDBAdapterV2V4 extends CompositeDBAdapter implements RecordTranslator {
|
||||
|
||||
// While the addition of flex-array and bitfields does not impact the
|
||||
// actual schema the presence of such components can not be supported
|
||||
|
@ -50,8 +48,8 @@ class CompositeDBAdapterV2V3 extends CompositeDBAdapter {
|
|||
static final int V2_COMPOSITE_UNIVERSAL_DT_ID_COL = 7;
|
||||
static final int V2_COMPOSITE_SOURCE_SYNC_TIME_COL = 8;
|
||||
static final int V2_COMPOSITE_LAST_CHANGE_TIME_COL = 9;
|
||||
static final int V2_COMPOSITE_INTERNAL_ALIGNMENT_COL = 10;
|
||||
static final int V2_COMPOSITE_EXTERNAL_ALIGNMENT_COL = 11;
|
||||
static final int V2_COMPOSITE_PACK_COL = 10; // renamed from Internal Alignment
|
||||
static final int V2_COMPOSITE_MIN_ALIGN_COL = 11; // renamed from External Alignment
|
||||
|
||||
static final Schema V2_COMPOSITE_SCHEMA = new Schema(VERSION, "Data Type ID",
|
||||
new Field[] { StringField.INSTANCE, StringField.INSTANCE, BooleanField.INSTANCE,
|
||||
|
@ -60,44 +58,9 @@ class CompositeDBAdapterV2V3 extends CompositeDBAdapter {
|
|||
IntField.INSTANCE },
|
||||
new String[] { "Name", "Comment", "Is Union", "Category ID", "Length",
|
||||
"Number Of Components", "Source Archive ID", "Source Data Type ID", "Source Sync Time",
|
||||
"Last Change Time", "Internal Alignment", "External Alignment" });
|
||||
"Last Change Time", "Pack", "MinAlign" });
|
||||
|
||||
private Table compositeTable;
|
||||
private boolean readOnly;
|
||||
|
||||
/**
|
||||
* Gets an adapter for the Composite database table.
|
||||
* @param handle handle to the database containing the table.
|
||||
* @param openMode the open mode
|
||||
* @throws VersionException if the the table's version does not match the expected version
|
||||
* for this adapter.
|
||||
*/
|
||||
public CompositeDBAdapterV2V3(DBHandle handle, int openMode)
|
||||
throws VersionException, IOException {
|
||||
readOnly = (openMode == DBConstants.READ_ONLY);
|
||||
if (openMode == DBConstants.CREATE) {
|
||||
compositeTable = handle.createTable(COMPOSITE_TABLE_NAME, V2_COMPOSITE_SCHEMA,
|
||||
new int[] { V2_COMPOSITE_CAT_COL, V2_COMPOSITE_UNIVERSAL_DT_ID_COL });
|
||||
}
|
||||
else {
|
||||
compositeTable = handle.getTable(COMPOSITE_TABLE_NAME);
|
||||
if (compositeTable == null) {
|
||||
throw new VersionException("Missing Table: " + COMPOSITE_TABLE_NAME);
|
||||
}
|
||||
int version = compositeTable.getSchema().getVersion();
|
||||
if (version != VERSION) {
|
||||
if (version < VERSION && version >= MIN_READ_ONLY_VERSION) {
|
||||
if (openMode == DBConstants.READ_ONLY) {
|
||||
return; // allow read-only immutable use
|
||||
}
|
||||
throw new VersionException(VersionException.OLDER_VERSION, true);
|
||||
}
|
||||
String msg = "Expected version 2-" + VERSION + " for table " +
|
||||
COMPOSITE_TABLE_NAME + " but got " + version;
|
||||
throw new VersionException(msg, VersionException.NEWER_VERSION, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a read-only adapter for the Composite database table.
|
||||
|
@ -105,8 +68,7 @@ class CompositeDBAdapterV2V3 extends CompositeDBAdapter {
|
|||
* @throws VersionException if the the table's version does not match the expected version
|
||||
* for this adapter.
|
||||
*/
|
||||
public CompositeDBAdapterV2V3(DBHandle handle) throws VersionException {
|
||||
readOnly = true;
|
||||
public CompositeDBAdapterV2V4(DBHandle handle) throws VersionException {
|
||||
compositeTable = handle.getTable(COMPOSITE_TABLE_NAME);
|
||||
if (compositeTable == null) {
|
||||
throw new VersionException("Missing Table: " + COMPOSITE_TABLE_NAME);
|
||||
|
@ -124,65 +86,31 @@ class CompositeDBAdapterV2V3 extends CompositeDBAdapter {
|
|||
|
||||
@Override
|
||||
public DBRecord createRecord(String name, String comments, boolean isUnion, long categoryID,
|
||||
int length, long sourceArchiveID, long sourceDataTypeID, long lastChangeTime,
|
||||
int internalAlignment, int externalAlignment) throws IOException {
|
||||
if (readOnly) {
|
||||
throw new ReadOnlyException();
|
||||
}
|
||||
if (internalAlignment == UNALIGNED) {
|
||||
length = 0; // aligned structures always start empty
|
||||
}
|
||||
long tableKey = compositeTable.getKey();
|
||||
// if (tableKey <= DataManager.VOID_DATATYPE_ID) {
|
||||
// tableKey = DataManager.VOID_DATATYPE_ID +1;
|
||||
// }
|
||||
long key = DataTypeManagerDB.createKey(DataTypeManagerDB.COMPOSITE, tableKey);
|
||||
DBRecord record = CompositeDBAdapter.COMPOSITE_SCHEMA.createRecord(key);
|
||||
|
||||
record.setString(V2_COMPOSITE_NAME_COL, name);
|
||||
record.setString(V2_COMPOSITE_COMMENT_COL, comments);
|
||||
record.setBooleanValue(V2_COMPOSITE_IS_UNION_COL, isUnion);
|
||||
record.setLongValue(V2_COMPOSITE_CAT_COL, categoryID);
|
||||
record.setIntValue(V2_COMPOSITE_LENGTH_COL, length);
|
||||
record.setIntValue(V2_COMPOSITE_NUM_COMPONENTS_COL, length);
|
||||
record.setLongValue(V2_COMPOSITE_SOURCE_ARCHIVE_ID_COL, sourceArchiveID);
|
||||
record.setLongValue(V2_COMPOSITE_UNIVERSAL_DT_ID_COL, sourceDataTypeID);
|
||||
record.setLongValue(V2_COMPOSITE_SOURCE_SYNC_TIME_COL, lastChangeTime);
|
||||
record.setLongValue(V2_COMPOSITE_LAST_CHANGE_TIME_COL, lastChangeTime);
|
||||
record.setIntValue(V2_COMPOSITE_INTERNAL_ALIGNMENT_COL, internalAlignment);
|
||||
record.setIntValue(V2_COMPOSITE_EXTERNAL_ALIGNMENT_COL, externalAlignment);
|
||||
compositeTable.putRecord(record);
|
||||
return record;
|
||||
int length, int computedAlignment, long sourceArchiveID, long sourceDataTypeID,
|
||||
long lastChangeTime, int packValue, int minAlignment) throws IOException {
|
||||
throw new UnsupportedOperationException("Not allowed to update prior version #" + VERSION +
|
||||
" of " + COMPOSITE_TABLE_NAME + " table.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public DBRecord getRecord(long dataTypeID) throws IOException {
|
||||
return compositeTable.getRecord(dataTypeID);
|
||||
return translateRecord(compositeTable.getRecord(dataTypeID));
|
||||
}
|
||||
|
||||
@Override
|
||||
public RecordIterator getRecords() throws IOException {
|
||||
return compositeTable.iterator();
|
||||
return new TranslatedRecordIterator(compositeTable.iterator(), this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateRecord(DBRecord record, boolean setLastChangeTime) throws IOException {
|
||||
if (readOnly) {
|
||||
throw new ReadOnlyException();
|
||||
}
|
||||
if (setLastChangeTime) {
|
||||
record.setLongValue(CompositeDBAdapter.COMPOSITE_LAST_CHANGE_TIME_COL,
|
||||
(new Date()).getTime());
|
||||
}
|
||||
compositeTable.putRecord(record);
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeRecord(long compositeID) throws IOException {
|
||||
if (readOnly) {
|
||||
throw new ReadOnlyException();
|
||||
}
|
||||
return compositeTable.deleteRecord(compositeID);
|
||||
throw new UnsupportedOperationException("Not allowed to update prior version #" + VERSION +
|
||||
" of " + COMPOSITE_TABLE_NAME + " table.");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -202,15 +130,46 @@ class CompositeDBAdapterV2V3 extends CompositeDBAdapter {
|
|||
V2_COMPOSITE_SOURCE_ARCHIVE_ID_COL);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see db.RecordTranslator#translateRecord(db.Record)
|
||||
*/
|
||||
@Override
|
||||
public DBRecord translateRecord(DBRecord oldRec) {
|
||||
if (oldRec == null) {
|
||||
return null;
|
||||
}
|
||||
DBRecord rec = CompositeDBAdapter.COMPOSITE_SCHEMA.createRecord(oldRec.getKey());
|
||||
rec.setString(COMPOSITE_NAME_COL, oldRec.getString(V2_COMPOSITE_NAME_COL));
|
||||
rec.setString(COMPOSITE_COMMENT_COL, oldRec.getString(V2_COMPOSITE_COMMENT_COL));
|
||||
rec.setBooleanValue(COMPOSITE_IS_UNION_COL,
|
||||
oldRec.getBooleanValue(V2_COMPOSITE_IS_UNION_COL));
|
||||
rec.setLongValue(COMPOSITE_CAT_COL, oldRec.getLongValue(V2_COMPOSITE_CAT_COL));
|
||||
rec.setIntValue(COMPOSITE_LENGTH_COL, oldRec.getIntValue(V2_COMPOSITE_LENGTH_COL));
|
||||
rec.setIntValue(COMPOSITE_ALIGNMENT_COL, -1);
|
||||
rec.setIntValue(COMPOSITE_NUM_COMPONENTS_COL,
|
||||
oldRec.getIntValue(V2_COMPOSITE_NUM_COMPONENTS_COL));
|
||||
rec.setLongValue(COMPOSITE_SOURCE_ARCHIVE_ID_COL,
|
||||
oldRec.getLongValue(V2_COMPOSITE_SOURCE_ARCHIVE_ID_COL));
|
||||
rec.setLongValue(COMPOSITE_UNIVERSAL_DT_ID,
|
||||
oldRec.getLongValue(V2_COMPOSITE_UNIVERSAL_DT_ID_COL));
|
||||
rec.setLongValue(COMPOSITE_SOURCE_SYNC_TIME_COL,
|
||||
oldRec.getLongValue(V2_COMPOSITE_SOURCE_SYNC_TIME_COL));
|
||||
rec.setLongValue(COMPOSITE_LAST_CHANGE_TIME_COL,
|
||||
oldRec.getLongValue(V2_COMPOSITE_LAST_CHANGE_TIME_COL));
|
||||
rec.setIntValue(COMPOSITE_PACKING_COL, oldRec.getIntValue(V2_COMPOSITE_PACK_COL));
|
||||
rec.setIntValue(COMPOSITE_MIN_ALIGN_COL, oldRec.getIntValue(V2_COMPOSITE_MIN_ALIGN_COL));
|
||||
return rec;
|
||||
}
|
||||
|
||||
@Override
|
||||
DBRecord getRecordWithIDs(UniversalID sourceID, UniversalID datatypeID) throws IOException {
|
||||
Field[] keys = compositeTable.findRecords(new LongField(datatypeID.getValue()),
|
||||
V2_COMPOSITE_UNIVERSAL_DT_ID_COL);
|
||||
|
||||
for (int i = 0; i < keys.length; i++) {
|
||||
DBRecord record = compositeTable.getRecord(keys[i]);
|
||||
for (Field key : keys) {
|
||||
DBRecord record = compositeTable.getRecord(key);
|
||||
if (record.getLongValue(V2_COMPOSITE_SOURCE_ARCHIVE_ID_COL) == sourceID.getValue()) {
|
||||
return record;
|
||||
return translateRecord(record);
|
||||
}
|
||||
}
|
||||
return null;
|
|
@ -0,0 +1,176 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.program.database.data;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
|
||||
import db.*;
|
||||
import ghidra.program.model.data.CompositeInternal;
|
||||
import ghidra.util.UniversalID;
|
||||
import ghidra.util.exception.VersionException;
|
||||
|
||||
/**
|
||||
* Version 5 implementation for accessing the Composite database table.
|
||||
* This version introduces the retained computed alignment to reduce
|
||||
* need for recalculation and to allow for improved change detection.
|
||||
*/
|
||||
class CompositeDBAdapterV5 extends CompositeDBAdapter {
|
||||
|
||||
static final int VERSION = 5;
|
||||
|
||||
static final int V5_COMPOSITE_NAME_COL = 0;
|
||||
static final int V5_COMPOSITE_COMMENT_COL = 1;
|
||||
static final int V5_COMPOSITE_IS_UNION_COL = 2;
|
||||
static final int V5_COMPOSITE_CAT_COL = 3;
|
||||
static final int V5_COMPOSITE_LENGTH_COL = 4;
|
||||
static final int V5_COMPOSITE_ALIGNMENT_COL = 5;
|
||||
static final int V5_COMPOSITE_NUM_COMPONENTS_COL = 6;
|
||||
static final int V5_COMPOSITE_SOURCE_ARCHIVE_ID_COL = 7;
|
||||
static final int V5_COMPOSITE_UNIVERSAL_DT_ID_COL = 8;
|
||||
static final int V5_COMPOSITE_SOURCE_SYNC_TIME_COL = 9;
|
||||
static final int V5_COMPOSITE_LAST_CHANGE_TIME_COL = 10;
|
||||
static final int V5_COMPOSITE_PACK_COL = 11;
|
||||
static final int V5_COMPOSITE_MIN_ALIGN_COL = 12;
|
||||
|
||||
static final Schema V5_COMPOSITE_SCHEMA = new Schema(VERSION, "Data Type ID",
|
||||
new Field[] { StringField.INSTANCE, StringField.INSTANCE, BooleanField.INSTANCE,
|
||||
LongField.INSTANCE, IntField.INSTANCE, IntField.INSTANCE, IntField.INSTANCE,
|
||||
LongField.INSTANCE, LongField.INSTANCE, LongField.INSTANCE, LongField.INSTANCE,
|
||||
IntField.INSTANCE, IntField.INSTANCE },
|
||||
new String[] { "Name", "Comment", "Is Union", "Category ID", "Length", "Alignment",
|
||||
"Number Of Components", "Source Archive ID", "Source Data Type ID", "Source Sync Time",
|
||||
"Last Change Time", "Pack", "MinAlign" });
|
||||
|
||||
private Table compositeTable;
|
||||
|
||||
/**
|
||||
* Gets an adapter for the Composite database table.
|
||||
* @param handle handle to the database containing the table.
|
||||
* @param create true if this constructor should create the table.
|
||||
* @throws VersionException if the the table's version does not match the expected version
|
||||
* for this adapter.
|
||||
* @throws IOException if IO error occurs
|
||||
*/
|
||||
public CompositeDBAdapterV5(DBHandle handle, boolean create)
|
||||
throws VersionException, IOException {
|
||||
if (create) {
|
||||
compositeTable = handle.createTable(COMPOSITE_TABLE_NAME, V5_COMPOSITE_SCHEMA,
|
||||
new int[] { V5_COMPOSITE_CAT_COL, V5_COMPOSITE_UNIVERSAL_DT_ID_COL });
|
||||
}
|
||||
else {
|
||||
compositeTable = handle.getTable(COMPOSITE_TABLE_NAME);
|
||||
if (compositeTable == null) {
|
||||
throw new VersionException("Missing Table: " + COMPOSITE_TABLE_NAME);
|
||||
}
|
||||
int version = compositeTable.getSchema().getVersion();
|
||||
if (version != VERSION) {
|
||||
String msg = "Expected version " + VERSION + " for table " + COMPOSITE_TABLE_NAME +
|
||||
" but got " + version;
|
||||
if (version < VERSION) {
|
||||
throw new VersionException(msg, VersionException.OLDER_VERSION, true);
|
||||
}
|
||||
throw new VersionException(msg, VersionException.NEWER_VERSION, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DBRecord createRecord(String name, String comments, boolean isUnion, long categoryID,
|
||||
int length, int computedAlignment, long sourceArchiveID, long sourceDataTypeID,
|
||||
long lastChangeTime, int packValue, int minAlignment) throws IOException {
|
||||
if (packValue < CompositeInternal.DEFAULT_ALIGNMENT) {
|
||||
packValue = CompositeInternal.NO_PACKING;
|
||||
}
|
||||
else {
|
||||
length = 0; // aligned structures always start empty
|
||||
}
|
||||
long key =
|
||||
DataTypeManagerDB.createKey(DataTypeManagerDB.COMPOSITE, compositeTable.getKey());
|
||||
DBRecord record = CompositeDBAdapter.COMPOSITE_SCHEMA.createRecord(key);
|
||||
|
||||
record.setString(V5_COMPOSITE_NAME_COL, name);
|
||||
record.setString(V5_COMPOSITE_COMMENT_COL, comments);
|
||||
record.setBooleanValue(V5_COMPOSITE_IS_UNION_COL, isUnion);
|
||||
record.setLongValue(V5_COMPOSITE_CAT_COL, categoryID);
|
||||
record.setIntValue(V5_COMPOSITE_LENGTH_COL, length);
|
||||
record.setIntValue(V5_COMPOSITE_ALIGNMENT_COL, computedAlignment);
|
||||
record.setIntValue(V5_COMPOSITE_NUM_COMPONENTS_COL, length);
|
||||
record.setLongValue(V5_COMPOSITE_SOURCE_ARCHIVE_ID_COL, sourceArchiveID);
|
||||
record.setLongValue(V5_COMPOSITE_UNIVERSAL_DT_ID_COL, sourceDataTypeID);
|
||||
record.setLongValue(V5_COMPOSITE_SOURCE_SYNC_TIME_COL, lastChangeTime);
|
||||
record.setLongValue(V5_COMPOSITE_LAST_CHANGE_TIME_COL, lastChangeTime);
|
||||
record.setIntValue(V5_COMPOSITE_PACK_COL, packValue);
|
||||
record.setIntValue(V5_COMPOSITE_MIN_ALIGN_COL, minAlignment);
|
||||
compositeTable.putRecord(record);
|
||||
return record;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DBRecord getRecord(long dataTypeID) throws IOException {
|
||||
return compositeTable.getRecord(dataTypeID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RecordIterator getRecords() throws IOException {
|
||||
return compositeTable.iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateRecord(DBRecord record, boolean setLastChangeTime) throws IOException {
|
||||
if (setLastChangeTime) {
|
||||
record.setLongValue(CompositeDBAdapter.COMPOSITE_LAST_CHANGE_TIME_COL,
|
||||
(new Date()).getTime());
|
||||
}
|
||||
compositeTable.putRecord(record);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeRecord(long compositeID) throws IOException {
|
||||
return compositeTable.deleteRecord(compositeID);
|
||||
}
|
||||
|
||||
@Override
|
||||
void deleteTable(DBHandle handle) throws IOException {
|
||||
handle.deleteTable(COMPOSITE_TABLE_NAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Field[] getRecordIdsInCategory(long categoryID) throws IOException {
|
||||
return compositeTable.findRecords(new LongField(categoryID),
|
||||
CompositeDBAdapter.COMPOSITE_CAT_COL);
|
||||
}
|
||||
|
||||
@Override
|
||||
Field[] getRecordIdsForSourceArchive(long archiveID) throws IOException {
|
||||
return compositeTable.findRecords(new LongField(archiveID),
|
||||
V5_COMPOSITE_SOURCE_ARCHIVE_ID_COL);
|
||||
}
|
||||
|
||||
@Override
|
||||
DBRecord getRecordWithIDs(UniversalID sourceID, UniversalID datatypeID) throws IOException {
|
||||
Field[] keys = compositeTable.findRecords(new LongField(datatypeID.getValue()),
|
||||
V5_COMPOSITE_UNIVERSAL_DT_ID_COL);
|
||||
|
||||
for (Field key : keys) {
|
||||
DBRecord record = compositeTable.getRecord(key);
|
||||
if (record.getLongValue(V5_COMPOSITE_SOURCE_ARCHIVE_ID_COL) == sourceID.getValue()) {
|
||||
return record;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -148,7 +148,7 @@ class DataTypeComponentDB implements InternalDataTypeComponent {
|
|||
@Override
|
||||
public int getOffset() {
|
||||
if (isFlexibleArrayComponent) {
|
||||
if (parent.isNotYetDefined()) {
|
||||
if (parent.isZeroLength()) {
|
||||
// some structures have only a flexible array defined
|
||||
return 0;
|
||||
}
|
||||
|
@ -223,7 +223,7 @@ class DataTypeComponentDB implements InternalDataTypeComponent {
|
|||
if (record != null) {
|
||||
record.setString(ComponentDBAdapter.COMPONENT_COMMENT_COL, comment);
|
||||
adapter.updateRecord(record);
|
||||
notifyChanged();
|
||||
dataMgr.dataTypeChanged(getParent(), false);
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
|
@ -268,7 +268,7 @@ class DataTypeComponentDB implements InternalDataTypeComponent {
|
|||
}
|
||||
record.setString(ComponentDBAdapter.COMPONENT_FIELD_NAME_COL, name);
|
||||
adapter.updateRecord(record);
|
||||
notifyChanged();
|
||||
dataMgr.dataTypeChanged(getParent(), false);
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
|
@ -279,7 +279,7 @@ class DataTypeComponentDB implements InternalDataTypeComponent {
|
|||
|
||||
private void checkDuplicateName(String name) throws DuplicateNameException {
|
||||
DataTypeComponentImpl.checkDefaultFieldName(name);
|
||||
for (DataTypeComponent comp : parent.getComponents()) {
|
||||
for (DataTypeComponent comp : parent.getDefinedComponents()) {
|
||||
if (comp == this) {
|
||||
continue;
|
||||
}
|
||||
|
@ -344,7 +344,7 @@ class DataTypeComponentDB implements InternalDataTypeComponent {
|
|||
}
|
||||
DataType myParent = getParent();
|
||||
boolean aligned =
|
||||
(myParent instanceof Composite) ? ((Composite) myParent).isInternallyAligned() : false;
|
||||
(myParent instanceof Composite) ? ((Composite) myParent).isPackingEnabled() : false;
|
||||
// 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
|
||||
|
@ -452,11 +452,6 @@ class DataTypeComponentDB implements InternalDataTypeComponent {
|
|||
}
|
||||
}
|
||||
|
||||
private void notifyChanged() {
|
||||
DataType dt = getParent();
|
||||
dataMgr.dataTypeChanged(dt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
|
|
|
@ -19,9 +19,6 @@ import java.io.IOException;
|
|||
import java.net.URL;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.event.ChangeEvent;
|
||||
import javax.swing.event.ChangeListener;
|
||||
|
||||
import db.DBRecord;
|
||||
import ghidra.docking.settings.Settings;
|
||||
import ghidra.docking.settings.SettingsDefinition;
|
||||
|
@ -38,7 +35,7 @@ import ghidra.util.exception.NotYetImplementedException;
|
|||
*
|
||||
*
|
||||
*/
|
||||
abstract class DataTypeDB extends DatabaseObject implements DataType, ChangeListener {
|
||||
abstract class DataTypeDB extends DatabaseObject implements DataType {
|
||||
|
||||
protected DBRecord record;
|
||||
protected final DataTypeManagerDB dataMgr;
|
||||
|
@ -125,9 +122,11 @@ abstract class DataTypeDB extends DatabaseObject implements DataType, ChangeList
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.data.DataType#getDisplayName()
|
||||
*/
|
||||
@Override
|
||||
public boolean isZeroLength() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return getName();
|
||||
|
@ -159,9 +158,6 @@ abstract class DataTypeDB extends DatabaseObject implements DataType, ChangeList
|
|||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.data.DataType#getDefaultSettings()
|
||||
*/
|
||||
@Override
|
||||
public Settings getDefaultSettings() {
|
||||
Settings localDefaultSettings = defaultSettings;
|
||||
|
@ -182,9 +178,6 @@ abstract class DataTypeDB extends DatabaseObject implements DataType, ChangeList
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.data.DataType#getDocs()
|
||||
*/
|
||||
@Override
|
||||
public URL getDocs() {
|
||||
return null;
|
||||
|
@ -203,49 +196,31 @@ abstract class DataTypeDB extends DatabaseObject implements DataType, ChangeList
|
|||
throw new NotYetImplementedException("setValue() not implemented");
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.data.DataType#getSettingsDefinitions()
|
||||
*/
|
||||
@Override
|
||||
public SettingsDefinition[] getSettingsDefinitions() {
|
||||
return EMPTY_DEFINITIONS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.data.DataType#isDeleted()
|
||||
*/
|
||||
@Override
|
||||
public boolean isDeleted() {
|
||||
return isDeleted(lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.data.DataType#update(ghidra.program.model.data.DataType)
|
||||
*/
|
||||
@Override
|
||||
public void dataTypeSizeChanged(DataType dt) {
|
||||
// no-op
|
||||
// do nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* @see javax.swing.event.ChangeListener#stateChanged(javax.swing.event.ChangeEvent)
|
||||
*/
|
||||
@Override
|
||||
public void stateChanged(ChangeEvent e) {
|
||||
dataMgr.dataTypeChanged(this);
|
||||
public void dataTypeAlignmentChanged(DataType dt) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.data.DataType#getDataTypeManager()
|
||||
*/
|
||||
@Override
|
||||
public DataTypeManager getDataTypeManager() {
|
||||
return dataMgr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.data.DataType#setDefaultSettings(ghidra.docking.settings.Settings)
|
||||
*/
|
||||
@Override
|
||||
public void setDefaultSettings(Settings settings) {
|
||||
checkIsValid();
|
||||
|
@ -259,12 +234,9 @@ abstract class DataTypeDB extends DatabaseObject implements DataType, ChangeList
|
|||
return 1;
|
||||
}
|
||||
DataOrganization dataOrganization = dataMgr.getDataOrganization();
|
||||
return dataOrganization.getAlignment(this, length);
|
||||
return dataOrganization.getAlignment(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.data.DataType#getPathName()
|
||||
*/
|
||||
@Override
|
||||
public String getPathName() {
|
||||
return getDataTypePath().getPath();
|
||||
|
@ -320,9 +292,6 @@ abstract class DataTypeDB extends DatabaseObject implements DataType, ChangeList
|
|||
return new DataTypePath(getCategoryPath(), getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.data.DataType#setName(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public void setName(String name) throws InvalidNameException, DuplicateNameException {
|
||||
lock.acquire();
|
||||
|
@ -357,9 +326,6 @@ abstract class DataTypeDB extends DatabaseObject implements DataType, ChangeList
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.data.DataType#setCategoryPath(ghidra.program.model.data.CategoryPath)
|
||||
*/
|
||||
@Override
|
||||
public void setCategoryPath(CategoryPath path) throws DuplicateNameException {
|
||||
lock.acquire();
|
||||
|
@ -450,11 +416,28 @@ abstract class DataTypeDB extends DatabaseObject implements DataType, ChangeList
|
|||
}
|
||||
}
|
||||
|
||||
protected void notifySizeChanged() {
|
||||
/**
|
||||
* Notify all parents that the size of this datatype has changed or
|
||||
* other significant change that may affect a parent containing this
|
||||
* datatype.
|
||||
* @param isAutoChange true if changes are in response to another datatype's change.
|
||||
*/
|
||||
protected void notifySizeChanged(boolean isAutoChange) {
|
||||
for (DataType dt : dataMgr.getParentDataTypes(key)) {
|
||||
dt.dataTypeSizeChanged(this);
|
||||
}
|
||||
dataMgr.dataTypeChanged(this);
|
||||
dataMgr.dataTypeChanged(this, isAutoChange);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notification that this composite data type's alignment has changed.
|
||||
* @param isAutoChange true if changes are in response to another datatype's change.
|
||||
*/
|
||||
protected void notifyAlignmentChanged(boolean isAutoChange) {
|
||||
for (DataType dt : dataMgr.getParentDataTypes(key)) {
|
||||
dt.dataTypeAlignmentChanged(this);
|
||||
}
|
||||
dataMgr.dataTypeChanged(this, isAutoChange);
|
||||
}
|
||||
|
||||
protected void notifyNameChanged(String oldName) {
|
||||
|
|
|
@ -490,6 +490,16 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if transaction is active. With proper lock established
|
||||
* this method may be useful for determining if a lazy record update
|
||||
* may be performed.
|
||||
* @return true if database transaction if active, else false
|
||||
*/
|
||||
protected final boolean isTransactionActive() {
|
||||
return dbHandle.isTransactionActive();
|
||||
}
|
||||
|
||||
abstract protected String getDomainFileID();
|
||||
|
||||
abstract protected String getPath();
|
||||
|
@ -983,19 +993,19 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
|||
|
||||
try {
|
||||
if (existingDataType instanceof StructureDB) {
|
||||
if (!(dataType instanceof Structure)) {
|
||||
if (!(dataType instanceof StructureInternal)) {
|
||||
return false;
|
||||
}
|
||||
StructureDB existingStruct = (StructureDB) existingDataType;
|
||||
existingStruct.doReplaceWith((Structure) dataType, true);
|
||||
existingStruct.doReplaceWith((StructureInternal) dataType, true);
|
||||
return true;
|
||||
}
|
||||
else if (existingDataType instanceof UnionDB) {
|
||||
if (!(dataType instanceof Union)) {
|
||||
if (!(dataType instanceof UnionInternal)) {
|
||||
return false;
|
||||
}
|
||||
UnionDB existingUnion = (UnionDB) existingDataType;
|
||||
existingUnion.doReplaceWith((Union) dataType, true);
|
||||
existingUnion.doReplaceWith((UnionInternal) dataType, true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -1121,7 +1131,7 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
|||
long lastChangeTime = dataType.getLastChangeTime();
|
||||
existingDataType.setLastChangeTime(lastChangeTime);
|
||||
existingDataType.setLastChangeTimeInSourceArchive(lastChangeTime);
|
||||
dataTypeChanged(existingDataType);
|
||||
dataTypeChanged(existingDataType, false);
|
||||
return existingDataType;
|
||||
}
|
||||
|
||||
|
@ -1725,7 +1735,7 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
|||
idsToDataTypeMap.removeDataType(sourceArchive, oldDtID);
|
||||
}
|
||||
|
||||
dataTypeChanged(dataType);
|
||||
dataTypeChanged(dataType, false);
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
|
@ -2307,8 +2317,8 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
|||
int len = ptr.isDynamicallySized() ? -1 : ptr.getLength();
|
||||
newDataType = createPointer(ptr.getDataType(), cat, (byte) len, handler);
|
||||
}
|
||||
else if (dt instanceof Structure) {
|
||||
Structure structure = (Structure) dt;
|
||||
else if (dt instanceof StructureInternal) {
|
||||
StructureInternal structure = (StructureInternal) dt;
|
||||
newDataType = createStructure(structure, name, cat, sourceArchiveIdValue,
|
||||
id.getValue());
|
||||
}
|
||||
|
@ -2317,8 +2327,8 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
|||
newDataType =
|
||||
createTypeDef(typedef, name, cat, sourceArchiveIdValue, id.getValue());
|
||||
}
|
||||
else if (dt instanceof Union) {
|
||||
Union union = (Union) dt;
|
||||
else if (dt instanceof UnionInternal) {
|
||||
UnionInternal union = (UnionInternal) dt;
|
||||
newDataType =
|
||||
createUnion(union, name, cat, sourceArchiveIdValue, id.getValue());
|
||||
}
|
||||
|
@ -2352,7 +2362,7 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
|||
return null;
|
||||
}
|
||||
|
||||
private Structure createStructure(Structure struct, String name, CategoryDB category,
|
||||
private Structure createStructure(StructureInternal struct, String name, CategoryDB category,
|
||||
long sourceArchiveIdValue, long universalIdValue)
|
||||
throws IOException {
|
||||
try {
|
||||
|
@ -2361,13 +2371,13 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
|||
}
|
||||
creatingDataType++;
|
||||
int len = struct.getLength();
|
||||
if (struct.isNotYetDefined() || struct.isInternallyAligned()) {
|
||||
if (struct.isZeroLength() || struct.isPackingEnabled()) {
|
||||
len = 0;
|
||||
}
|
||||
DBRecord record = compositeAdapter.createRecord(name, struct.getDescription(), false,
|
||||
category.getID(), len, sourceArchiveIdValue, universalIdValue,
|
||||
struct.getLastChangeTime(), getInternalAlignment(struct),
|
||||
getExternalAlignment(struct));
|
||||
category.getID(), len, -1, sourceArchiveIdValue,
|
||||
universalIdValue, struct.getLastChangeTime(),
|
||||
struct.getStoredPackingValue(), struct.getStoredMinimumAlignment());
|
||||
|
||||
StructureDB structDB =
|
||||
new StructureDB(this, dtCache, compositeAdapter, componentAdapter, record);
|
||||
|
@ -2378,7 +2388,7 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
|||
structDB.doReplaceWith(struct, false);
|
||||
structDB.setDescription(struct.getDescription());
|
||||
// structDB.notifySizeChanged();
|
||||
// doReplaceWith updated the last change time so set it back to what we want.
|
||||
// doReplaceWith may have updated the last change time so set it back to what we want.
|
||||
structDB.setLastChangeTime(struct.getLastChangeTime());
|
||||
|
||||
return structDB;
|
||||
|
@ -2395,32 +2405,32 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
|||
return dbHandle.isChanged();
|
||||
}
|
||||
|
||||
private int getExternalAlignment(Composite struct) {
|
||||
if (struct.isDefaultAligned()) {
|
||||
return CompositeDB.DEFAULT_ALIGNED;
|
||||
}
|
||||
else if (struct.isMachineAligned()) {
|
||||
return CompositeDB.MACHINE_ALIGNED;
|
||||
}
|
||||
else {
|
||||
int alignment = struct.getMinimumAlignment();
|
||||
if (alignment == 0) {
|
||||
return CompositeDB.DEFAULT_ALIGNED;
|
||||
}
|
||||
return alignment;
|
||||
}
|
||||
}
|
||||
// private int getExternalAlignment(Composite struct) {
|
||||
// if (struct.isDefaultAligned()) {
|
||||
// return CompositeDB.DEFAULT_ALIGNED;
|
||||
// }
|
||||
// else if (struct.isMachineAligned()) {
|
||||
// return CompositeDB.MACHINE_ALIGNED;
|
||||
// }
|
||||
// else {
|
||||
// int alignment = struct.getAlignment();
|
||||
// if (alignment <= 0) {
|
||||
// return CompositeDB.DEFAULT_ALIGNED;
|
||||
// }
|
||||
// return alignment;
|
||||
// }
|
||||
// }
|
||||
|
||||
private int getInternalAlignment(Composite struct) {
|
||||
if (struct.isInternallyAligned()) {
|
||||
int packingValue = struct.getPackingValue();
|
||||
if (packingValue == 0) {
|
||||
return CompositeDB.ALIGNED_NO_PACKING;
|
||||
}
|
||||
return packingValue;
|
||||
}
|
||||
return CompositeDB.UNALIGNED;
|
||||
}
|
||||
// private int getInternalAlignment(Composite struct) {
|
||||
// if (struct.isPackingEnabled()) {
|
||||
// int packingValue = struct.getPackingValue();
|
||||
// if (packingValue == 0) {
|
||||
// return CompositeDB.ALIGNED_NO_PACKING;
|
||||
// }
|
||||
// return packingValue;
|
||||
// }
|
||||
// return CompositeDB.UNALIGNED;
|
||||
// }
|
||||
|
||||
private TypeDef createTypeDef(TypeDef typedef, String name, Category cat,
|
||||
long sourceArchiveIdValue, long universalIdValue)
|
||||
|
@ -2437,7 +2447,7 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
|||
return typedefDB;
|
||||
}
|
||||
|
||||
private Union createUnion(Union union, String name, CategoryDB category,
|
||||
private Union createUnion(UnionInternal union, String name, CategoryDB category,
|
||||
long sourceArchiveIdValue, long universalIdValue)
|
||||
throws IOException {
|
||||
if (name == null || name.length() == 0) {
|
||||
|
@ -2446,8 +2456,8 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
|||
try {
|
||||
creatingDataType++;
|
||||
DBRecord record = compositeAdapter.createRecord(name, null, true, category.getID(), 0,
|
||||
sourceArchiveIdValue, universalIdValue, union.getLastChangeTime(),
|
||||
getInternalAlignment(union), getExternalAlignment(union));
|
||||
-1, sourceArchiveIdValue, universalIdValue,
|
||||
union.getLastChangeTime(), union.getStoredPackingValue(), union.getStoredMinimumAlignment());
|
||||
UnionDB unionDB =
|
||||
new UnionDB(this, dtCache, compositeAdapter, componentAdapter, record);
|
||||
|
||||
|
@ -3585,7 +3595,7 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void dataTypeChanged(DataType dt) {
|
||||
public void dataTypeChanged(DataType dt, boolean isAutoChange) {
|
||||
if (dt instanceof Enum) {
|
||||
enumValueMap = null;
|
||||
}
|
||||
|
@ -3852,6 +3862,9 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
|||
}
|
||||
|
||||
}
|
||||
catch (IOException e) {
|
||||
dbError(e);
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
|
|
|
@ -19,8 +19,8 @@ import java.io.IOException;
|
|||
import java.math.BigInteger;
|
||||
import java.util.*;
|
||||
|
||||
import db.Field;
|
||||
import db.DBRecord;
|
||||
import db.Field;
|
||||
import ghidra.docking.settings.Settings;
|
||||
import ghidra.docking.settings.SettingsDefinition;
|
||||
import ghidra.program.database.DBObjectCache;
|
||||
|
@ -216,7 +216,7 @@ class EnumDB extends DataTypeDB implements Enum {
|
|||
valueAdapter.createRecord(key, valueName, value);
|
||||
adapter.updateRecord(record, true);
|
||||
addToCache(valueName, value);
|
||||
dataMgr.dataTypeChanged(this);
|
||||
dataMgr.dataTypeChanged(this, false);
|
||||
|
||||
}
|
||||
catch (IOException e) {
|
||||
|
@ -263,7 +263,7 @@ class EnumDB extends DataTypeDB implements Enum {
|
|||
}
|
||||
}
|
||||
adapter.updateRecord(record, true);
|
||||
dataMgr.dataTypeChanged(this);
|
||||
dataMgr.dataTypeChanged(this, false);
|
||||
}
|
||||
catch (IOException e) {
|
||||
dataMgr.dbError(e);
|
||||
|
@ -309,10 +309,10 @@ class EnumDB extends DataTypeDB implements Enum {
|
|||
}
|
||||
|
||||
if (oldLength != newLength) {
|
||||
notifySizeChanged();
|
||||
notifySizeChanged(false);
|
||||
}
|
||||
else {
|
||||
dataMgr.dataTypeChanged(this);
|
||||
dataMgr.dataTypeChanged(this, false);
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
|
@ -386,7 +386,7 @@ class EnumDB extends DataTypeDB implements Enum {
|
|||
checkDeleted();
|
||||
record.setString(EnumDBAdapter.ENUM_COMMENT_COL, description);
|
||||
adapter.updateRecord(record, true);
|
||||
dataMgr.dataTypeChanged(this);
|
||||
dataMgr.dataTypeChanged(this, false);
|
||||
}
|
||||
catch (IOException e) {
|
||||
dataMgr.dbError(e);
|
||||
|
@ -620,7 +620,7 @@ class EnumDB extends DataTypeDB implements Enum {
|
|||
checkDeleted();
|
||||
record.setLongValue(EnumDBAdapter.ENUM_UNIVERSAL_DT_ID_COL, id.getValue());
|
||||
adapter.updateRecord(record, false);
|
||||
dataMgr.dataTypeChanged(this);
|
||||
dataMgr.dataTypeChanged(this, false);
|
||||
}
|
||||
catch (IOException e) {
|
||||
dataMgr.dbError(e);
|
||||
|
@ -642,7 +642,7 @@ class EnumDB extends DataTypeDB implements Enum {
|
|||
checkDeleted();
|
||||
record.setLongValue(EnumDBAdapter.ENUM_SOURCE_ARCHIVE_ID_COL, id.getValue());
|
||||
adapter.updateRecord(record, false);
|
||||
dataMgr.dataTypeChanged(this);
|
||||
dataMgr.dataTypeChanged(this, false);
|
||||
}
|
||||
catch (IOException e) {
|
||||
dataMgr.dbError(e);
|
||||
|
@ -659,7 +659,7 @@ class EnumDB extends DataTypeDB implements Enum {
|
|||
checkDeleted();
|
||||
record.setLongValue(EnumDBAdapter.ENUM_LAST_CHANGE_TIME_COL, lastChangeTime);
|
||||
adapter.updateRecord(record, false);
|
||||
dataMgr.dataTypeChanged(this);
|
||||
dataMgr.dataTypeChanged(this, false);
|
||||
}
|
||||
catch (IOException e) {
|
||||
dataMgr.dbError(e);
|
||||
|
@ -677,7 +677,7 @@ class EnumDB extends DataTypeDB implements Enum {
|
|||
record.setLongValue(EnumDBAdapter.ENUM_SOURCE_SYNC_TIME_COL,
|
||||
lastChangeTimeInSourceArchive);
|
||||
adapter.updateRecord(record, false);
|
||||
dataMgr.dataTypeChanged(this);
|
||||
dataMgr.dataTypeChanged(this, false);
|
||||
}
|
||||
catch (IOException e) {
|
||||
dataMgr.dbError(e);
|
||||
|
|
|
@ -18,8 +18,8 @@ package ghidra.program.database.data;
|
|||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
import db.Field;
|
||||
import db.DBRecord;
|
||||
import db.Field;
|
||||
import ghidra.docking.settings.Settings;
|
||||
import ghidra.program.database.DBObjectCache;
|
||||
import ghidra.program.model.data.*;
|
||||
|
@ -268,7 +268,7 @@ class FunctionDefinitionDB extends DataTypeDB implements FunctionDefinition {
|
|||
}
|
||||
loadParameters();
|
||||
funDefAdapter.updateRecord(record, true); // update last change time
|
||||
dataMgr.dataTypeChanged(this);
|
||||
dataMgr.dataTypeChanged(this, false);
|
||||
}
|
||||
catch (IOException e) {
|
||||
dataMgr.dbError(e);
|
||||
|
@ -293,7 +293,7 @@ class FunctionDefinitionDB extends DataTypeDB implements FunctionDefinition {
|
|||
dataMgr.getID(resolvedDt));
|
||||
funDefAdapter.updateRecord(record, true);
|
||||
resolvedDt.addParent(this);
|
||||
dataMgr.dataTypeChanged(this);
|
||||
dataMgr.dataTypeChanged(this, false);
|
||||
}
|
||||
catch (IOException e) {
|
||||
dataMgr.dbError(e);
|
||||
|
@ -310,7 +310,7 @@ class FunctionDefinitionDB extends DataTypeDB implements FunctionDefinition {
|
|||
checkDeleted();
|
||||
record.setString(FunctionDefinitionDBAdapter.FUNCTION_DEF_COMMENT_COL, comment);
|
||||
funDefAdapter.updateRecord(record, true);
|
||||
dataMgr.dataTypeChanged(this);
|
||||
dataMgr.dataTypeChanged(this, false);
|
||||
}
|
||||
catch (IOException e) {
|
||||
dataMgr.dbError(e);
|
||||
|
@ -523,7 +523,7 @@ class FunctionDefinitionDB extends DataTypeDB implements FunctionDefinition {
|
|||
record.setByteValue(FunctionDefinitionDBAdapter.FUNCTION_DEF_FLAGS_COL, flags);
|
||||
try {
|
||||
funDefAdapter.updateRecord(record, true);
|
||||
dataMgr.dataTypeChanged(this);
|
||||
dataMgr.dataTypeChanged(this, false);
|
||||
}
|
||||
catch (IOException e) {
|
||||
dataMgr.dbError(e);
|
||||
|
@ -552,7 +552,7 @@ class FunctionDefinitionDB extends DataTypeDB implements FunctionDefinition {
|
|||
record.setByteValue(FunctionDefinitionDBAdapter.FUNCTION_DEF_FLAGS_COL, flags);
|
||||
try {
|
||||
funDefAdapter.updateRecord(record, true);
|
||||
dataMgr.dataTypeChanged(this);
|
||||
dataMgr.dataTypeChanged(this, false);
|
||||
}
|
||||
catch (IOException e) {
|
||||
dataMgr.dbError(e);
|
||||
|
@ -600,7 +600,7 @@ class FunctionDefinitionDB extends DataTypeDB implements FunctionDefinition {
|
|||
record.setLongValue(FunctionDefinitionDBAdapter.FUNCTION_DEF_LAST_CHANGE_TIME_COL,
|
||||
lastChangeTime);
|
||||
funDefAdapter.updateRecord(record, false);
|
||||
dataMgr.dataTypeChanged(this);
|
||||
dataMgr.dataTypeChanged(this, false);
|
||||
}
|
||||
catch (IOException e) {
|
||||
dataMgr.dbError(e);
|
||||
|
@ -618,7 +618,7 @@ class FunctionDefinitionDB extends DataTypeDB implements FunctionDefinition {
|
|||
record.setLongValue(FunctionDefinitionDBAdapter.FUNCTION_DEF_SOURCE_SYNC_TIME_COL,
|
||||
lastChangeTime);
|
||||
funDefAdapter.updateRecord(record, false);
|
||||
dataMgr.dataTypeChanged(this);
|
||||
dataMgr.dataTypeChanged(this, false);
|
||||
}
|
||||
catch (IOException e) {
|
||||
dataMgr.dbError(e);
|
||||
|
@ -642,7 +642,7 @@ class FunctionDefinitionDB extends DataTypeDB implements FunctionDefinition {
|
|||
record.setLongValue(FunctionDefinitionDBAdapter.FUNCTION_DEF_SOURCE_DT_ID_COL,
|
||||
id.getValue());
|
||||
funDefAdapter.updateRecord(record, false);
|
||||
dataMgr.dataTypeChanged(this);
|
||||
dataMgr.dataTypeChanged(this, false);
|
||||
}
|
||||
catch (IOException e) {
|
||||
dataMgr.dbError(e);
|
||||
|
@ -666,7 +666,7 @@ class FunctionDefinitionDB extends DataTypeDB implements FunctionDefinition {
|
|||
record.setLongValue(FunctionDefinitionDBAdapter.FUNCTION_DEF_SOURCE_ARCHIVE_ID_COL,
|
||||
id.getValue());
|
||||
funDefAdapter.updateRecord(record, false);
|
||||
dataMgr.dataTypeChanged(this);
|
||||
dataMgr.dataTypeChanged(this, false);
|
||||
}
|
||||
catch (IOException e) {
|
||||
dataMgr.dbError(e);
|
||||
|
|
|
@ -76,7 +76,7 @@ final class ParameterDefinitionDB implements ParameterDefinition {
|
|||
record.setIntValue(FunctionParameterAdapter.PARAMETER_DT_LENGTH_COL, type.getLength());
|
||||
try {
|
||||
adapter.updateRecord(record);
|
||||
dataMgr.dataTypeChanged(parent);
|
||||
dataMgr.dataTypeChanged(parent, false);
|
||||
}
|
||||
catch (IOException e) {
|
||||
dataMgr.dbError(e);
|
||||
|
@ -109,7 +109,7 @@ final class ParameterDefinitionDB implements ParameterDefinition {
|
|||
record.setString(FunctionParameterAdapter.PARAMETER_NAME_COL, name);
|
||||
try {
|
||||
adapter.updateRecord(record);
|
||||
dataMgr.dataTypeChanged(parent);
|
||||
dataMgr.dataTypeChanged(parent, false);
|
||||
}
|
||||
catch (IOException e) {
|
||||
dataMgr.dbError(e);
|
||||
|
@ -126,7 +126,7 @@ final class ParameterDefinitionDB implements ParameterDefinition {
|
|||
record.setString(FunctionParameterAdapter.PARAMETER_COMMENT_COL, comment);
|
||||
try {
|
||||
adapter.updateRecord(record);
|
||||
dataMgr.dataTypeChanged(parent);
|
||||
dataMgr.dataTypeChanged(parent, false);
|
||||
}
|
||||
catch (IOException e) {
|
||||
dataMgr.dbError(e);
|
||||
|
|
|
@ -130,12 +130,13 @@ public class ProgramDataTypeManager extends DataTypeManagerDB
|
|||
}
|
||||
|
||||
@Override
|
||||
public void dataTypeChanged(DataType dt) {
|
||||
super.dataTypeChanged(dt);
|
||||
public void dataTypeChanged(DataType dt, boolean isAutoChange) {
|
||||
super.dataTypeChanged(dt, isAutoChange);
|
||||
if (!isCreatingDataType()) {
|
||||
program.getCodeManager().invalidateCache(false);
|
||||
program.getFunctionManager().invalidateCache(false);
|
||||
program.dataTypeChanged(getID(dt), ChangeManager.DOCR_DATA_TYPE_CHANGED, null, dt);
|
||||
program.dataTypeChanged(getID(dt), ChangeManager.DOCR_DATA_TYPE_CHANGED,
|
||||
isAutoChange, null, dt);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -149,7 +150,8 @@ public class ProgramDataTypeManager extends DataTypeManagerDB
|
|||
protected void dataTypeReplaced(long existingDtID, DataTypePath existingPath,
|
||||
DataType replacementDt) {
|
||||
super.dataTypeReplaced(existingDtID, existingPath, replacementDt);
|
||||
program.dataTypeChanged(existingDtID, ChangeManager.DOCR_DATA_TYPE_REPLACED, existingPath,
|
||||
program.dataTypeChanged(existingDtID, ChangeManager.DOCR_DATA_TYPE_REPLACED, true,
|
||||
existingPath,
|
||||
replacementDt);
|
||||
}
|
||||
|
||||
|
@ -157,20 +159,20 @@ public class ProgramDataTypeManager extends DataTypeManagerDB
|
|||
protected void dataTypeDeleted(long deletedID, DataTypePath deletedDataTypePath) {
|
||||
super.dataTypeDeleted(deletedID, deletedDataTypePath);
|
||||
program.dataTypeChanged(deletedID, ChangeManager.DOCR_DATA_TYPE_REMOVED,
|
||||
deletedDataTypePath, null);
|
||||
false, deletedDataTypePath, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void dataTypeMoved(DataType dt, DataTypePath oldPath, DataTypePath newPath) {
|
||||
super.dataTypeMoved(dt, oldPath, newPath);
|
||||
Category category = getCategory(oldPath.getCategoryPath());
|
||||
program.dataTypeChanged(getID(dt), ChangeManager.DOCR_DATA_TYPE_MOVED, category, dt);
|
||||
program.dataTypeChanged(getID(dt), ChangeManager.DOCR_DATA_TYPE_MOVED, false, category, dt);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void dataTypeNameChanged(DataType dt, String oldName) {
|
||||
super.dataTypeNameChanged(dt, oldName);
|
||||
program.dataTypeChanged(getID(dt), ChangeManager.DOCR_DATA_TYPE_RENAMED, oldName, dt);
|
||||
program.dataTypeChanged(getID(dt), ChangeManager.DOCR_DATA_TYPE_RENAMED, false, oldName, dt);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -97,12 +97,12 @@ public class ProjectDataTypeManager extends DataTypeManagerDB
|
|||
|
||||
////////////////////
|
||||
@Override
|
||||
public void dataTypeChanged(DataType dt) {
|
||||
super.dataTypeChanged(dt);
|
||||
public void dataTypeChanged(DataType dt, boolean isAutoChange) {
|
||||
super.dataTypeChanged(dt, isAutoChange);
|
||||
// dataTypeArchive.getCodeManager().invalidateCache(false);
|
||||
// TODO
|
||||
dataTypeArchive.dataTypeChanged(getID(dt),
|
||||
DataTypeArchiveChangeManager.DOCR_DATA_TYPE_CHANGED, null, dt);
|
||||
DataTypeArchiveChangeManager.DOCR_DATA_TYPE_CHANGED, isAutoChange, null, dt);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -118,14 +118,15 @@ public class ProjectDataTypeManager extends DataTypeManagerDB
|
|||
DataType replacementDt) {
|
||||
super.dataTypeReplaced(existingDtID, existingPath, replacementDt);
|
||||
dataTypeArchive.dataTypeChanged(existingDtID,
|
||||
DataTypeArchiveChangeManager.DOCR_DATA_TYPE_REPLACED, existingPath, replacementDt);
|
||||
DataTypeArchiveChangeManager.DOCR_DATA_TYPE_REPLACED, false, existingPath,
|
||||
replacementDt);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void dataTypeDeleted(long deletedID, DataTypePath deletedDataTypePath) {
|
||||
super.dataTypeDeleted(deletedID, deletedDataTypePath);
|
||||
dataTypeArchive.dataTypeChanged(deletedID,
|
||||
DataTypeArchiveChangeManager.DOCR_DATA_TYPE_REMOVED, deletedDataTypePath, null);
|
||||
DataTypeArchiveChangeManager.DOCR_DATA_TYPE_REMOVED, false, deletedDataTypePath, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -133,14 +134,14 @@ public class ProjectDataTypeManager extends DataTypeManagerDB
|
|||
super.dataTypeMoved(dt, oldPath, newPath);
|
||||
Category category = getCategory(oldPath.getCategoryPath());
|
||||
dataTypeArchive.dataTypeChanged(getID(dt),
|
||||
DataTypeArchiveChangeManager.DOCR_DATA_TYPE_MOVED, category, dt);
|
||||
DataTypeArchiveChangeManager.DOCR_DATA_TYPE_MOVED, false, category, dt);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void dataTypeNameChanged(DataType dt, String oldName) {
|
||||
super.dataTypeNameChanged(dt, oldName);
|
||||
dataTypeArchive.dataTypeChanged(getID(dt),
|
||||
DataTypeArchiveChangeManager.DOCR_DATA_TYPE_RENAMED, oldName, dt);
|
||||
DataTypeArchiveChangeManager.DOCR_DATA_TYPE_RENAMED, false, oldName, dt);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -18,8 +18,8 @@ package ghidra.program.database.data;
|
|||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
import db.Field;
|
||||
import db.DBRecord;
|
||||
import db.Field;
|
||||
import ghidra.docking.settings.Settings;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.DataTypeComponent;
|
||||
|
@ -63,11 +63,13 @@ class SettingsDBManager implements Settings {
|
|||
}
|
||||
|
||||
private void settingsChanged() {
|
||||
// NOTE: There is currently no merge support for settings so recording within
|
||||
// domain object change set is unneccessary
|
||||
if (dtc != null) {
|
||||
dataMgr.dataTypeChanged(dtc.getParent());
|
||||
dataMgr.dataTypeChanged(dtc.getParent(), true);
|
||||
}
|
||||
else {
|
||||
dataMgr.dataTypeChanged(dataType);
|
||||
dataMgr.dataTypeChanged(dataType, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -178,11 +180,11 @@ class SettingsDBManager implements Settings {
|
|||
|
||||
try {
|
||||
Field[] keys = adapter.getSettingsKeys(dataTypeID);
|
||||
for (int i = 0; i < keys.length; i++) {
|
||||
DBRecord rec = adapter.getSettingsRecord(keys[i].getLongValue());
|
||||
for (Field key : keys) {
|
||||
DBRecord rec = adapter.getSettingsRecord(key.getLongValue());
|
||||
String settingsName = rec.getString(SettingsDBAdapter.SETTINGS_NAME_COL);
|
||||
if (settingsName.equals(name)) {
|
||||
adapter.removeSettingsRecord(keys[i].getLongValue());
|
||||
adapter.removeSettingsRecord(key.getLongValue());
|
||||
settingsChanged();
|
||||
return;
|
||||
}
|
||||
|
@ -197,8 +199,8 @@ class SettingsDBManager implements Settings {
|
|||
public void clearAllSettings() {
|
||||
try {
|
||||
Field[] keys = adapter.getSettingsKeys(dataTypeID);
|
||||
for (int i = 0; i < keys.length; i++) {
|
||||
adapter.removeSettingsRecord(keys[i].getLongValue());
|
||||
for (Field key : keys) {
|
||||
adapter.removeSettingsRecord(key.getLongValue());
|
||||
}
|
||||
settingsChanged();
|
||||
}
|
||||
|
@ -212,8 +214,8 @@ class SettingsDBManager implements Settings {
|
|||
List<String> list = new ArrayList<String>();
|
||||
try {
|
||||
Field[] keys = adapter.getSettingsKeys(dataTypeID);
|
||||
for (int i = 0; i < keys.length; i++) {
|
||||
DBRecord rec = adapter.getSettingsRecord(keys[i].getLongValue());
|
||||
for (Field key : keys) {
|
||||
DBRecord rec = adapter.getSettingsRecord(key.getLongValue());
|
||||
String name = rec.getString(SettingsDBAdapter.SETTINGS_NAME_COL);
|
||||
if (!list.contains(name)) {
|
||||
list.add(name);
|
||||
|
@ -242,8 +244,8 @@ class SettingsDBManager implements Settings {
|
|||
void update(Settings settings) {
|
||||
clearAllSettings();
|
||||
String[] names = settings.getNames();
|
||||
for (int i = 0; i < names.length; i++) {
|
||||
setValue(names[i], settings.getValue(names[i]));
|
||||
for (String name : names) {
|
||||
setValue(name, settings.getValue(name));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -278,8 +280,8 @@ class SettingsDBManager implements Settings {
|
|||
private DBRecord getRecord(String name) {
|
||||
try {
|
||||
Field[] keys = adapter.getSettingsKeys(dataTypeID);
|
||||
for (int i = 0; i < keys.length; i++) {
|
||||
DBRecord rec = adapter.getSettingsRecord(keys[i].getLongValue());
|
||||
for (Field key : keys) {
|
||||
DBRecord rec = adapter.getSettingsRecord(key.getLongValue());
|
||||
if (rec.getString(SettingsDBAdapter.SETTINGS_NAME_COL).equals(name)) {
|
||||
return rec;
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -76,6 +76,11 @@ class TypedefDB extends DataTypeDB implements TypeDef {
|
|||
return getDisplayName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isZeroLength() {
|
||||
return getDataType().isZeroLength();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLength() {
|
||||
return getDataType().getLength();
|
||||
|
@ -108,7 +113,20 @@ class TypedefDB extends DataTypeDB implements TypeDef {
|
|||
lock.acquire();
|
||||
try {
|
||||
if (checkIsValid() && dt == getDataType()) {
|
||||
notifySizeChanged();
|
||||
notifySizeChanged(true);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dataTypeAlignmentChanged(DataType dt) {
|
||||
lock.acquire();
|
||||
try {
|
||||
if (checkIsValid() && dt == getDataType()) {
|
||||
notifyAlignmentChanged(true);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
|
@ -204,10 +222,10 @@ class TypedefDB extends DataTypeDB implements TypeDef {
|
|||
dataMgr.dbError(e);
|
||||
}
|
||||
if (oldLen != getLength()) {
|
||||
notifySizeChanged();
|
||||
notifySizeChanged(false);
|
||||
}
|
||||
else {
|
||||
dataMgr.dataTypeChanged(this);
|
||||
dataMgr.dataTypeChanged(this, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -297,7 +315,7 @@ class TypedefDB extends DataTypeDB implements TypeDef {
|
|||
checkDeleted();
|
||||
record.setLongValue(TypedefDBAdapter.TYPEDEF_UNIVERSAL_DT_ID_COL, id.getValue());
|
||||
adapter.updateRecord(record, false);
|
||||
dataMgr.dataTypeChanged(this);
|
||||
dataMgr.dataTypeChanged(this, false);
|
||||
}
|
||||
catch (IOException e) {
|
||||
dataMgr.dbError(e);
|
||||
|
@ -319,7 +337,7 @@ class TypedefDB extends DataTypeDB implements TypeDef {
|
|||
checkDeleted();
|
||||
record.setLongValue(TypedefDBAdapter.TYPEDEF_SOURCE_ARCHIVE_ID_COL, id.getValue());
|
||||
adapter.updateRecord(record, false);
|
||||
dataMgr.dataTypeChanged(this);
|
||||
dataMgr.dataTypeChanged(this, false);
|
||||
}
|
||||
catch (IOException e) {
|
||||
dataMgr.dbError(e);
|
||||
|
@ -336,7 +354,7 @@ class TypedefDB extends DataTypeDB implements TypeDef {
|
|||
checkDeleted();
|
||||
record.setLongValue(TypedefDBAdapter.TYPEDEF_LAST_CHANGE_TIME_COL, lastChangeTime);
|
||||
adapter.updateRecord(record, false);
|
||||
dataMgr.dataTypeChanged(this);
|
||||
dataMgr.dataTypeChanged(this, false);
|
||||
}
|
||||
catch (IOException e) {
|
||||
dataMgr.dbError(e);
|
||||
|
@ -354,7 +372,7 @@ class TypedefDB extends DataTypeDB implements TypeDef {
|
|||
record.setLongValue(TypedefDBAdapter.TYPEDEF_SOURCE_SYNC_TIME_COL,
|
||||
lastChangeTimeInSourceArchive);
|
||||
adapter.updateRecord(record, false);
|
||||
dataMgr.dataTypeChanged(this);
|
||||
dataMgr.dataTypeChanged(this, false);
|
||||
}
|
||||
catch (IOException e) {
|
||||
dataMgr.dbError(e);
|
||||
|
|
|
@ -18,8 +18,8 @@ package ghidra.program.database.data;
|
|||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
import db.Field;
|
||||
import db.DBRecord;
|
||||
import db.Field;
|
||||
import ghidra.docking.settings.Settings;
|
||||
import ghidra.program.database.DBObjectCache;
|
||||
import ghidra.program.model.data.*;
|
||||
|
@ -29,11 +29,13 @@ import ghidra.util.Msg;
|
|||
/**
|
||||
* Database implementation for the Union data type.
|
||||
*/
|
||||
class UnionDB extends CompositeDB implements Union {
|
||||
class UnionDB extends CompositeDB implements UnionInternal {
|
||||
|
||||
private ArrayList<DataTypeComponentDB> components;
|
||||
private int unionLength;
|
||||
private static MemberComparator comparator = new MemberComparator();
|
||||
private int unionAlignment; // reflects stored alignment, -1 if not yet stored
|
||||
private int computedAlignment = -1; // cached alignment if not yet stored
|
||||
|
||||
private List<DataTypeComponentDB> components;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
|
@ -65,9 +67,10 @@ class UnionDB extends CompositeDB implements Union {
|
|||
catch (IOException e) {
|
||||
dataMgr.dbError(e);
|
||||
}
|
||||
Collections.sort(components, comparator);
|
||||
Collections.sort(components, ComponentComparator.INSTANCE);
|
||||
unionLength = record.getIntValue(CompositeDBAdapter.COMPOSITE_LENGTH_COL);
|
||||
|
||||
unionAlignment = record.getIntValue(CompositeDBAdapter.COMPOSITE_ALIGNMENT_COL);
|
||||
computedAlignment = -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -89,8 +92,11 @@ class UnionDB extends CompositeDB implements Union {
|
|||
lock.acquire();
|
||||
try {
|
||||
checkDeleted();
|
||||
getComputedAlignment(true); // ensure previous alignment has been stored
|
||||
DataTypeComponent dtc = doAdd(dataType, length, componentName, comment, true);
|
||||
adjustLength(true, true);
|
||||
if (!repack(false, true)) {
|
||||
dataMgr.dataTypeChanged(this, false);
|
||||
}
|
||||
return dtc;
|
||||
}
|
||||
catch (DataTypeDependencyException e) {
|
||||
|
@ -103,7 +109,7 @@ class UnionDB extends CompositeDB implements Union {
|
|||
|
||||
private int getBitFieldAllocation(BitFieldDataType bitfieldDt) {
|
||||
|
||||
BitFieldPacking bitFieldPacking = getBitFieldPacking();
|
||||
BitFieldPacking bitFieldPacking = getDataOrganization().getBitFieldPacking();
|
||||
if (bitFieldPacking.useMSConvention()) {
|
||||
return bitfieldDt.getBaseTypeSize();
|
||||
}
|
||||
|
@ -113,8 +119,8 @@ class UnionDB extends CompositeDB implements Union {
|
|||
}
|
||||
|
||||
int length = bitfieldDt.getBaseTypeSize();
|
||||
int packValue = getPackingValue();
|
||||
if (packValue != NOT_PACKING && length > packValue) {
|
||||
int packValue = getStoredPackingValue();
|
||||
if (packValue > 0 && length > packValue) {
|
||||
length =
|
||||
DataOrganizationImpl.getLeastCommonMultiple(bitfieldDt.getStorageSize(), packValue);
|
||||
}
|
||||
|
@ -179,6 +185,8 @@ class UnionDB extends CompositeDB implements Union {
|
|||
dataType = resolve(dataType);
|
||||
checkAncestry(dataType);
|
||||
|
||||
getComputedAlignment(true); // ensure previous alignment has been stored
|
||||
|
||||
length = getPreferredComponentLength(dataType, length);
|
||||
|
||||
DataTypeComponentDB dtc =
|
||||
|
@ -187,7 +195,9 @@ class UnionDB extends CompositeDB implements Union {
|
|||
shiftOrdinals(ordinal, 1);
|
||||
components.add(ordinal, dtc);
|
||||
|
||||
adjustLength(true, true);
|
||||
if (!repack(false, true)) {
|
||||
dataMgr.dataTypeChanged(this, false);
|
||||
}
|
||||
return dtc;
|
||||
}
|
||||
catch (DataTypeDependencyException e) {
|
||||
|
@ -207,10 +217,10 @@ class UnionDB extends CompositeDB implements Union {
|
|||
@Override
|
||||
public DataTypeComponent insertBitField(int ordinal, DataType baseDataType, int bitSize,
|
||||
String componentName, String comment)
|
||||
throws InvalidDataTypeException, ArrayIndexOutOfBoundsException {
|
||||
throws InvalidDataTypeException, IndexOutOfBoundsException {
|
||||
|
||||
if (ordinal < 0 || ordinal > components.size()) {
|
||||
throw new ArrayIndexOutOfBoundsException(ordinal);
|
||||
throw new IndexOutOfBoundsException(ordinal);
|
||||
}
|
||||
|
||||
BitFieldDataType bitFieldDt = new BitFieldDBDataType(baseDataType, bitSize, 0);
|
||||
|
@ -223,12 +233,16 @@ class UnionDB extends CompositeDB implements Union {
|
|||
try {
|
||||
checkDeleted();
|
||||
|
||||
getComputedAlignment(true); // ensure previous alignment has been stored
|
||||
|
||||
DataTypeComponentDB dtc = components.remove(ordinal);
|
||||
dtc.getDataType().removeParent(this);
|
||||
removeComponent(dtc.getKey());
|
||||
shiftOrdinals(ordinal, -1);
|
||||
|
||||
adjustLength(true, true);
|
||||
if (!repack(false, true)) {
|
||||
dataMgr.dataTypeChanged(this, false);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
|
@ -236,26 +250,70 @@ class UnionDB extends CompositeDB implements Union {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void delete(int[] ordinals) {
|
||||
for (int ordinal : ordinals) {
|
||||
delete(ordinal);
|
||||
public void delete(Set<Integer> ordinals) {
|
||||
if (ordinals.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
lock.acquire();
|
||||
try {
|
||||
checkDeleted();
|
||||
|
||||
if (isPackingEnabled()) {
|
||||
getComputedAlignment(true); // ensure previous alignment has been stored
|
||||
}
|
||||
|
||||
List<DataTypeComponentDB> newComponents = new ArrayList<>();
|
||||
int newLength = 0;
|
||||
int ordinalAdjustment = 0;
|
||||
for (DataTypeComponentDB dtc : components) {
|
||||
int ordinal = dtc.getOrdinal();
|
||||
if (ordinals.contains(ordinal)) {
|
||||
// component removed
|
||||
--ordinalAdjustment;
|
||||
}
|
||||
else {
|
||||
if (ordinalAdjustment != 0) {
|
||||
dtc.setOrdinal(dtc.getOrdinal() + ordinalAdjustment, true);
|
||||
}
|
||||
newComponents.add(dtc);
|
||||
newLength = Math.max(newLength, dtc.getLength());
|
||||
}
|
||||
}
|
||||
components = newComponents;
|
||||
|
||||
if (isPackingEnabled()) {
|
||||
if (!repack(false, true)) {
|
||||
dataMgr.dataTypeChanged(this, false);
|
||||
}
|
||||
}
|
||||
else {
|
||||
unionLength = newLength;
|
||||
notifySizeChanged(false);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void replaceWith(DataType dataType) {
|
||||
if (!(dataType instanceof Union)) {
|
||||
if (!(dataType instanceof UnionInternal)) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
lock.acquire();
|
||||
boolean isResolveCacheOwner = dataMgr.activateResolveCache();
|
||||
try {
|
||||
checkDeleted();
|
||||
doReplaceWith((Union) dataType, true);
|
||||
doReplaceWith((UnionInternal) dataType, true);
|
||||
}
|
||||
catch (DataTypeDependencyException e) {
|
||||
throw new IllegalArgumentException(e.getMessage(), e);
|
||||
}
|
||||
catch (IOException e) {
|
||||
dataMgr.dbError(e);
|
||||
}
|
||||
finally {
|
||||
if (isResolveCacheOwner) {
|
||||
dataMgr.flushResolveQueue(true);
|
||||
|
@ -264,8 +322,8 @@ class UnionDB extends CompositeDB implements Union {
|
|||
}
|
||||
}
|
||||
|
||||
void doReplaceWith(Union union, boolean notify)
|
||||
throws DataTypeDependencyException {
|
||||
void doReplaceWith(UnionInternal union, boolean notify)
|
||||
throws DataTypeDependencyException, IOException {
|
||||
|
||||
// pre-resolved component types to catch dependency issues early
|
||||
DataTypeComponent[] otherComponents = union.getComponents();
|
||||
|
@ -275,34 +333,25 @@ class UnionDB extends CompositeDB implements Union {
|
|||
checkAncestry(resolvedDts[i]);
|
||||
}
|
||||
|
||||
int oldLength = unionLength;
|
||||
int oldMinAlignment = getMinimumAlignment();
|
||||
|
||||
for (DataTypeComponentDB dtc : components) {
|
||||
dtc.getDataType().removeParent(this);
|
||||
removeComponent(dtc.getKey());
|
||||
}
|
||||
components.clear();
|
||||
unionAlignment = -1;
|
||||
computedAlignment = -1;
|
||||
|
||||
setAlignment(union, false);
|
||||
doSetPackingAndAlignment(union);
|
||||
|
||||
for (int i = 0; i < otherComponents.length; i++) {
|
||||
DataTypeComponent dtc = otherComponents[i];
|
||||
doAdd(resolvedDts[i], dtc.getLength(), dtc.getFieldName(), dtc.getComment(), false);
|
||||
}
|
||||
|
||||
adjustLength(false, false);
|
||||
repack(false, false);
|
||||
|
||||
if (notify) {
|
||||
if (oldMinAlignment != getMinimumAlignment()) {
|
||||
notifyAlignmentChanged();
|
||||
}
|
||||
else if (oldLength != unionLength) {
|
||||
notifySizeChanged();
|
||||
}
|
||||
else {
|
||||
dataMgr.dataTypeChanged(this);
|
||||
}
|
||||
notifySizeChanged(false); // assume size and/or alignment changed
|
||||
}
|
||||
|
||||
if (pointerPostResolveRequired) {
|
||||
|
@ -394,7 +443,7 @@ class UnionDB extends CompositeDB implements Union {
|
|||
}
|
||||
|
||||
@Override
|
||||
public DataType clone(DataTypeManager dtm) {
|
||||
public Union clone(DataTypeManager dtm) {
|
||||
UnionDataType union = new UnionDataType(getCategoryPath(), getName(), getUniversalID(),
|
||||
getSourceArchive(), getLastChangeTime(), getLastChangeTimeInSourceArchive(), dtm);
|
||||
union.setDescription(getDescription());
|
||||
|
@ -402,6 +451,11 @@ class UnionDB extends CompositeDB implements Union {
|
|||
return union;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isZeroLength() {
|
||||
return unionLength == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLength() {
|
||||
lock.acquire();
|
||||
|
@ -417,6 +471,52 @@ class UnionDB extends CompositeDB implements Union {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void fixupComponents() {
|
||||
boolean changed = false;
|
||||
for (DataTypeComponentDB dtc : components) {
|
||||
DataType dt = dtc.getDataType();
|
||||
if (dt instanceof BitFieldDataType) {
|
||||
dt = adjustBitField(dt); // in case base type changed
|
||||
}
|
||||
int dtcLen = dtc.getLength();
|
||||
int length = dt.getLength();
|
||||
if (length <= 0) {
|
||||
length = dtcLen;
|
||||
}
|
||||
if (length != dtcLen) {
|
||||
dtc.setLength(length, true);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
if (changed) {
|
||||
// NOTE: since we do not retain our external alignment we have no way of knowing if
|
||||
// it has changed, so we must assume it has if we are an aligned union
|
||||
// Do not notify parents
|
||||
if (!repack(false, false)) {
|
||||
dataMgr.dataTypeChanged(this, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dataTypeAlignmentChanged(DataType dt) {
|
||||
if (!isPackingEnabled()) {
|
||||
return;
|
||||
}
|
||||
if (dt instanceof BitFieldDataType) {
|
||||
return; // unsupported
|
||||
}
|
||||
lock.acquire();
|
||||
try {
|
||||
checkDeleted();
|
||||
repack(true, true);
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dataTypeSizeChanged(DataType dt) {
|
||||
if (dt instanceof BitFieldDataType) {
|
||||
|
@ -436,8 +536,8 @@ class UnionDB extends CompositeDB implements Union {
|
|||
changed = true;
|
||||
}
|
||||
}
|
||||
if (changed) {
|
||||
adjustLength(true, false); // notifies parents
|
||||
if (changed && !repack(true, true)) {
|
||||
dataMgr.dataTypeChanged(this, true);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
|
@ -445,38 +545,6 @@ class UnionDB extends CompositeDB implements Union {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void fixupComponents() {
|
||||
boolean changed = false;
|
||||
for (DataTypeComponentDB dtc : components) {
|
||||
DataType dt = dtc.getDataType();
|
||||
if (dt instanceof BitFieldDataType) {
|
||||
dt = adjustBitField(dt); // in case base type changed
|
||||
}
|
||||
int dtcLen = dtc.getLength();
|
||||
int length = dt.getLength();
|
||||
if (length <= 0) {
|
||||
length = dtcLen;
|
||||
}
|
||||
if (length != dtcLen) {
|
||||
dtc.setLength(length, true);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
if (changed || isInternallyAligned()) {
|
||||
// NOTE: since we do not retain our external alignment we have no way of knowing if
|
||||
// it has changed, so we must assume it has if we are an aligned union
|
||||
// Do not notify parents
|
||||
adjustLength(false, false);
|
||||
dataMgr.dataTypeChanged(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dataTypeAlignmentChanged(DataType dt) {
|
||||
adjustInternalAlignment(true);
|
||||
}
|
||||
|
||||
private DataType adjustBitField(DataType dataType) {
|
||||
|
||||
if (!(dataType instanceof BitFieldDataType)) {
|
||||
|
@ -488,8 +556,8 @@ class UnionDB extends CompositeDB implements Union {
|
|||
DataType baseDataType = bitfieldDt.getBaseDataType();
|
||||
baseDataType = resolve(baseDataType);
|
||||
|
||||
// Both aligned and unaligned bitfields use same adjustment
|
||||
// unaligned must force bitfield placement at byte offset 0
|
||||
// Both aligned and non-packed bitfields use same adjustment
|
||||
// non-packed must force bitfield placement at byte offset 0
|
||||
int bitSize = bitfieldDt.getDeclaredBitSize();
|
||||
int effectiveBitSize =
|
||||
BitFieldDataType.getEffectiveBitSize(bitSize, baseDataType.getLength());
|
||||
|
@ -522,32 +590,94 @@ class UnionDB extends CompositeDB implements Union {
|
|||
return bitfieldDt;
|
||||
}
|
||||
|
||||
private void adjustLength(boolean notify, boolean setLastChangeTime) {
|
||||
@Override
|
||||
protected int getComputedAlignment(boolean updateRecord) {
|
||||
if (unionAlignment > 0) {
|
||||
return unionAlignment;
|
||||
}
|
||||
if (computedAlignment <= 0) {
|
||||
if (isPackingEnabled()) {
|
||||
computedAlignment =
|
||||
CompositeAlignmentHelper.getAlignment(getDataOrganization(), this);
|
||||
}
|
||||
else {
|
||||
computedAlignment = getNonPackedAlignment();
|
||||
}
|
||||
}
|
||||
if (updateRecord) {
|
||||
// perform lazy update of stored computed alignment
|
||||
record.setIntValue(CompositeDBAdapter.COMPOSITE_ALIGNMENT_COL, computedAlignment);
|
||||
try {
|
||||
compositeAdapter.updateRecord(record, false);
|
||||
}
|
||||
catch (IOException e) {
|
||||
dataMgr.dbError(e);
|
||||
}
|
||||
unionAlignment = computedAlignment;
|
||||
computedAlignment = -1;
|
||||
return unionAlignment;
|
||||
}
|
||||
return computedAlignment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform union member repack.
|
||||
* Perform lazy update of stored alignment introduced with v5 adapter.
|
||||
*/
|
||||
@Override
|
||||
protected boolean repack(boolean isAutoChange, boolean notify) {
|
||||
lock.acquire();
|
||||
try {
|
||||
checkDeleted();
|
||||
|
||||
int oldLength = unionLength;
|
||||
boolean storeAlignment = (unionAlignment <= 0); // lazy upgrade for v5 adapter
|
||||
int oldAlignment = getComputedAlignment(false);
|
||||
|
||||
unionLength = 0;
|
||||
for (DataTypeComponent dtc : components) {
|
||||
|
||||
// TODO: compute alignment in this loop
|
||||
int length = dtc.getLength();
|
||||
if (isInternallyAligned() && dtc.isBitFieldComponent()) {
|
||||
if (isPackingEnabled() && dtc.isBitFieldComponent()) {
|
||||
// revise length to reflect compiler bitfield allocation rules
|
||||
length = getBitFieldAllocation((BitFieldDataType) dtc.getDataType());
|
||||
}
|
||||
|
||||
unionLength = Math.max(length, unionLength);
|
||||
}
|
||||
|
||||
DataOrganization dataOrganization = getDataOrganization();
|
||||
int alignment = dataOrganization.getAlignment(this, unionLength);
|
||||
int amountFilled = unionLength % alignment;
|
||||
if (amountFilled > 0) {
|
||||
unionLength += alignment - amountFilled;
|
||||
computedAlignment = -1; // force recompute of unionAlignment
|
||||
unionAlignment = -1;
|
||||
unionAlignment = getComputedAlignment(false);
|
||||
|
||||
if (isPackingEnabled()) {
|
||||
unionLength = DataOrganizationImpl.getAlignedOffset(unionAlignment, unionLength);
|
||||
}
|
||||
|
||||
updateLength(oldLength, notify, setLastChangeTime);
|
||||
boolean changed = (oldLength != unionLength) || (oldAlignment != unionAlignment);
|
||||
|
||||
if (changed || storeAlignment) {
|
||||
record.setIntValue(CompositeDBAdapter.COMPOSITE_LENGTH_COL, unionLength);
|
||||
record.setIntValue(CompositeDBAdapter.COMPOSITE_ALIGNMENT_COL, unionAlignment);
|
||||
try {
|
||||
compositeAdapter.updateRecord(record, changed && !isAutoChange);
|
||||
}
|
||||
catch (IOException e) {
|
||||
dataMgr.dbError(e);
|
||||
}
|
||||
}
|
||||
|
||||
if (changed & notify) {
|
||||
if (oldLength != unionLength) {
|
||||
notifySizeChanged(isAutoChange);
|
||||
}
|
||||
else if (oldAlignment != unionAlignment) {
|
||||
notifyAlignmentChanged(isAutoChange);
|
||||
}
|
||||
else {
|
||||
dataMgr.dataTypeChanged(this, isAutoChange);
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
|
@ -559,7 +689,7 @@ class UnionDB extends CompositeDB implements Union {
|
|||
lock.acquire();
|
||||
try {
|
||||
checkDeleted();
|
||||
boolean didChange = false;
|
||||
boolean changed = false;
|
||||
for (int i = components.size() - 1; i >= 0; i--) { // reverse order
|
||||
DataTypeComponentDB dtc = components.get(i);
|
||||
boolean removeBitFieldComponent = false;
|
||||
|
@ -572,11 +702,11 @@ class UnionDB extends CompositeDB implements Union {
|
|||
components.remove(i);
|
||||
removeComponent(dtc.getKey());
|
||||
shiftOrdinals(i, -1);
|
||||
didChange = true;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
if (didChange) {
|
||||
adjustLength(true, true);
|
||||
if (changed && !repack(false, true)) {
|
||||
dataMgr.dataTypeChanged(this, false);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
|
@ -590,7 +720,7 @@ class UnionDB extends CompositeDB implements Union {
|
|||
if (dataType == this) {
|
||||
return true;
|
||||
}
|
||||
if (!(dataType instanceof Union)) {
|
||||
if (!(dataType instanceof UnionInternal)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -609,13 +739,10 @@ class UnionDB extends CompositeDB implements Union {
|
|||
|
||||
try {
|
||||
isEquivalent = false;
|
||||
Union union = (Union) dataType;
|
||||
if (isInternallyAligned() != union.isInternallyAligned() ||
|
||||
isDefaultAligned() != union.isDefaultAligned() ||
|
||||
isMachineAligned() != union.isMachineAligned() ||
|
||||
getMinimumAlignment() != union.getMinimumAlignment() ||
|
||||
getPackingValue() != union.getPackingValue()) {
|
||||
// rely on component match instead of checking length
|
||||
UnionInternal union = (UnionInternal) dataType;
|
||||
if (getStoredPackingValue() != union.getStoredPackingValue() ||
|
||||
getStoredMinimumAlignment() != union.getStoredMinimumAlignment()) {
|
||||
// rely on component match instead of checking length
|
||||
// since dynamic component sizes could affect length
|
||||
return false;
|
||||
}
|
||||
|
@ -637,24 +764,6 @@ class UnionDB extends CompositeDB implements Union {
|
|||
return true;
|
||||
}
|
||||
|
||||
private void updateLength(int oldLength, boolean notify, boolean setLastChangeTime) {
|
||||
if (oldLength != unionLength) {
|
||||
record.setIntValue(CompositeDBAdapter.COMPOSITE_LENGTH_COL, unionLength);
|
||||
try {
|
||||
compositeAdapter.updateRecord(record, setLastChangeTime);
|
||||
}
|
||||
catch (IOException e) {
|
||||
dataMgr.dbError(e);
|
||||
}
|
||||
if (notify) {
|
||||
notifySizeChanged();
|
||||
}
|
||||
}
|
||||
else if (notify) {
|
||||
dataMgr.dataTypeChanged(this);
|
||||
}
|
||||
}
|
||||
|
||||
private void shiftOrdinals(int ordinal, int deltaOrdinal) {
|
||||
for (int i = ordinal; i < components.size(); i++) {
|
||||
DataTypeComponentDB dtc = components.get(i);
|
||||
|
@ -729,8 +838,8 @@ class UnionDB extends CompositeDB implements Union {
|
|||
changed = true;
|
||||
}
|
||||
}
|
||||
if (changed) {
|
||||
adjustLength(true, true);
|
||||
if (changed && !repack(false, true)) {
|
||||
dataMgr.dataTypeChanged(this, false);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
|
@ -759,27 +868,9 @@ class UnionDB extends CompositeDB implements Union {
|
|||
}
|
||||
}
|
||||
|
||||
private static class MemberComparator implements Comparator<DataTypeComponent> {
|
||||
@Override
|
||||
public int compare(DataTypeComponent dtc1, DataTypeComponent dtc2) {
|
||||
return dtc1.getOrdinal() - dtc2.getOrdinal();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDefaultLabelPrefix() {
|
||||
return "UNION_" + getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void realign() {
|
||||
if (isInternallyAligned()) {
|
||||
adjustInternalAlignment(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void adjustInternalAlignment(boolean notify) {
|
||||
adjustLength(notify, false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -112,6 +112,11 @@ public abstract class AbstractDataType implements DataType {
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isZeroLength() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getDisplayName();
|
||||
|
@ -138,6 +143,11 @@ public abstract class AbstractDataType implements DataType {
|
|||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dataTypeAlignmentChanged(DataType dt) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dataTypeDeleted(DataType dt) {
|
||||
// do nothing
|
||||
|
|
|
@ -42,6 +42,7 @@ public abstract class AbstractFloatDataType extends BuiltIn {
|
|||
*
|
||||
* @see ghidra.program.model.data.DataType#getMnemonic(Settings)
|
||||
*/
|
||||
@Override
|
||||
public String getMnemonic(Settings settings) {
|
||||
return name;
|
||||
}
|
||||
|
@ -49,6 +50,7 @@ public abstract class AbstractFloatDataType extends BuiltIn {
|
|||
/**
|
||||
* @see ghidra.program.model.data.DataType#isDynamicallySized()
|
||||
*/
|
||||
@Override
|
||||
public boolean isDynamicallySized() {
|
||||
return false;
|
||||
}
|
||||
|
@ -57,6 +59,7 @@ public abstract class AbstractFloatDataType extends BuiltIn {
|
|||
*
|
||||
* @see ghidra.program.model.data.DataType#getDescription()
|
||||
*/
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "IEEE-754 Float";
|
||||
}
|
||||
|
@ -65,6 +68,7 @@ public abstract class AbstractFloatDataType extends BuiltIn {
|
|||
*
|
||||
* @see ghidra.program.model.data.DataType#getValue(ghidra.program.model.mem.MemBuffer, ghidra.docking.settings.Settings, int)
|
||||
*/
|
||||
@Override
|
||||
public Object getValue(MemBuffer buf, Settings settings, int length) {
|
||||
try {
|
||||
int len = getLength(); // use type length (ignore length arg)
|
||||
|
@ -97,10 +101,12 @@ public abstract class AbstractFloatDataType extends BuiltIn {
|
|||
*
|
||||
* @see ghidra.program.model.data.DataType#getRepresentation(MemBuffer, Settings, int)
|
||||
*/
|
||||
@Override
|
||||
public String getRepresentation(MemBuffer buf, Settings settings, int length) {
|
||||
Object obj = getValue(buf, settings, length);
|
||||
if (obj == null)
|
||||
if (obj == null) {
|
||||
return "??";
|
||||
}
|
||||
return obj.toString();
|
||||
}
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ class AlignedComponentPacker {
|
|||
|
||||
private InternalDataTypeComponent lastComponent;
|
||||
|
||||
private int externalAlignment = 1;
|
||||
private int defaultAlignment = 1;
|
||||
private boolean componentsChanged;
|
||||
|
||||
AlignedComponentPacker(int packValue, DataOrganization dataOrganization) {
|
||||
|
@ -68,7 +68,7 @@ class AlignedComponentPacker {
|
|||
lastComponent = dtc;
|
||||
++nextOrdinal;
|
||||
|
||||
externalAlignment = getComponentAlignmentLCM(externalAlignment);
|
||||
defaultAlignment = getComponentAlignmentLCM(defaultAlignment);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -80,13 +80,13 @@ class AlignedComponentPacker {
|
|||
}
|
||||
|
||||
/**
|
||||
* Get the external structure alignment after all components have been added.
|
||||
* This value does not factor in the affects of any trailing flexible array component
|
||||
* which may exist.
|
||||
* Get the external structure alignment after all components have been packed.
|
||||
* NOTE: This value does not factor in the affects of any trailing flexible array component
|
||||
* which may exist or the alignment which may have been explicitly set on the structure.
|
||||
* @return external alignment
|
||||
*/
|
||||
int getExternalAlignment() {
|
||||
return externalAlignment;
|
||||
int getDefaultAlignment() {
|
||||
return defaultAlignment;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -108,12 +108,11 @@ class AlignedComponentPacker {
|
|||
offset = lastComponent.getOffset() + lastComponent.getLength();
|
||||
if (!bitFieldPacking.useMSConvention() && lastComponent.isZeroBitFieldComponent()) {
|
||||
// factor in trailing zero-length bitfield
|
||||
// TODO: does pack setting need to be considered?
|
||||
BitFieldDataType bitfieldDt = (BitFieldDataType) lastComponent.getDataType();
|
||||
int sizeAlignment = CompositeAlignmentHelper.getPackedAlignment(dataOrganization,
|
||||
Composite.NOT_PACKING, bitfieldDt.getBaseDataType(),
|
||||
bitfieldDt.getBaseTypeSize());
|
||||
int sizeAlignment = bitfieldDt.getBaseDataType().getAlignment();
|
||||
getBitFieldAlignment((BitFieldDataType) lastComponent.getDataType());
|
||||
offset += DataOrganizationImpl.getPaddingSize(sizeAlignment, offset);
|
||||
offset = DataOrganizationImpl.getAlignedOffset(sizeAlignment, offset);
|
||||
}
|
||||
}
|
||||
return offset;
|
||||
|
@ -129,13 +128,13 @@ class AlignedComponentPacker {
|
|||
|
||||
private int getBitFieldAlignment(BitFieldDataType bitfieldDt) {
|
||||
|
||||
if (!bitFieldPacking.useMSConvention() && packValue != Composite.NOT_PACKING) {
|
||||
if (!bitFieldPacking.useMSConvention() && packValue != CompositeInternal.DEFAULT_PACKING) {
|
||||
// GCC always uses 1 when packing regardless of pack value
|
||||
return 1;
|
||||
}
|
||||
|
||||
return CompositeAlignmentHelper.getPackedAlignment(dataOrganization, packValue,
|
||||
bitfieldDt.getBaseDataType(), bitfieldDt.getBaseTypeSize());
|
||||
return CompositeAlignmentHelper
|
||||
.getPackedAlignment(bitfieldDt.getBaseDataType().getAlignment(), packValue);
|
||||
}
|
||||
|
||||
private boolean isIgnoredZeroBitField(BitFieldDataType zeroBitFieldDt) {
|
||||
|
@ -167,11 +166,11 @@ class AlignedComponentPacker {
|
|||
if (!bitFieldPacking.useMSConvention() && !isLastComponent) {
|
||||
// GCC ignores pack value for :0 bitfield alignment but considers it when
|
||||
// passing alignment along to structure
|
||||
pack = Composite.NOT_PACKING;
|
||||
pack = CompositeInternal.NO_PACKING;
|
||||
}
|
||||
|
||||
return CompositeAlignmentHelper.getPackedAlignment(dataOrganization, pack,
|
||||
zeroBitFieldDt.getBaseDataType(), zeroBitFieldDt.getBaseTypeSize());
|
||||
return CompositeAlignmentHelper
|
||||
.getPackedAlignment(zeroBitFieldDt.getBaseDataType().getAlignment(), pack);
|
||||
}
|
||||
|
||||
private void initGroup(InternalDataTypeComponent dataTypeComponent, boolean isLastComponent) {
|
||||
|
@ -248,8 +247,8 @@ class AlignedComponentPacker {
|
|||
*/
|
||||
private void adjustZeroLengthBitField(int ordinal, int minimumAlignment) {
|
||||
|
||||
int minOffset = DataOrganizationImpl.getOffset(minimumAlignment, groupOffset);
|
||||
int zeroAlignmentOffset = DataOrganizationImpl.getOffset(zeroAlignment, groupOffset);
|
||||
int minOffset = DataOrganizationImpl.getAlignedOffset(minimumAlignment, groupOffset);
|
||||
int zeroAlignmentOffset = DataOrganizationImpl.getAlignedOffset(zeroAlignment, groupOffset);
|
||||
|
||||
// Determine component offset of zero-length bitfield and the component
|
||||
// which immediately follows it.
|
||||
|
@ -312,8 +311,8 @@ class AlignedComponentPacker {
|
|||
dtSize = dataTypeComponent.getLength();
|
||||
}
|
||||
|
||||
int alignment = CompositeAlignmentHelper.getPackedAlignment(dataOrganization, packValue,
|
||||
componentDt, dtSize);
|
||||
int alignment =
|
||||
CompositeAlignmentHelper.getPackedAlignment(componentDt.getAlignment(), packValue);
|
||||
|
||||
int offset;
|
||||
if (lastComponent != null && lastComponent.isZeroBitFieldComponent()) {
|
||||
|
@ -322,7 +321,7 @@ class AlignedComponentPacker {
|
|||
offset = groupOffset;
|
||||
}
|
||||
else {
|
||||
offset = DataOrganizationImpl.getOffset(alignment, minOffset);
|
||||
offset = DataOrganizationImpl.getAlignedOffset(alignment, minOffset);
|
||||
if (lastComponent == null) {
|
||||
groupOffset = offset; // establish corrected group offset after alignment
|
||||
}
|
||||
|
@ -345,14 +344,14 @@ class AlignedComponentPacker {
|
|||
int bitsConsumed;
|
||||
|
||||
// update lastAlignment to be conveyed onto structure alignment
|
||||
int alignment = CompositeAlignmentHelper.getPackedAlignment(dataOrganization, packValue,
|
||||
bitfieldDt.getPrimitiveBaseDataType(), bitfieldDt.getBaseTypeSize());
|
||||
int alignment = CompositeAlignmentHelper.getPackedAlignment(
|
||||
bitfieldDt.getPrimitiveBaseDataType().getAlignment(), packValue);
|
||||
|
||||
// Set conveyed alignment early since bitfield alignment may be reduced below
|
||||
lastAlignment = Math.max(alignment, lastAlignment);
|
||||
|
||||
if (lastComponent == null) {
|
||||
offset = DataOrganizationImpl.getOffset(alignment, groupOffset);
|
||||
offset = DataOrganizationImpl.getAlignedOffset(alignment, groupOffset);
|
||||
bitsConsumed = 0;
|
||||
groupOffset = offset; // establish corrected group offset after alignment
|
||||
}
|
||||
|
@ -406,10 +405,10 @@ class AlignedComponentPacker {
|
|||
if (offset % alignment != 0 || byteSize > bitfieldDt.getBaseTypeSize()) {
|
||||
// offset is not an aligned offset (which may be OK when packing with lastComponent)
|
||||
int alignedBaseOffset =
|
||||
DataOrganizationImpl.getOffset(alignment, offset) - alignment;
|
||||
DataOrganizationImpl.getAlignedOffset(alignment, offset) - alignment;
|
||||
if (endOffset >= alignedBaseOffset + bitfieldDt.getBaseTypeSize()) {
|
||||
// skip ahead to next aligned offset
|
||||
offset = DataOrganizationImpl.getOffset(alignment, offset + 1);
|
||||
offset = DataOrganizationImpl.getAlignedOffset(alignment, offset + 1);
|
||||
endOffset = offset + byteSize - 1;
|
||||
bitsConsumed = 0;
|
||||
}
|
||||
|
|
|
@ -31,13 +31,13 @@ import ghidra.util.exception.DuplicateNameException;
|
|||
*/
|
||||
public class AlignedStructureInspector extends AlignedStructurePacker {
|
||||
|
||||
private AlignedStructureInspector(Structure structure) {
|
||||
private AlignedStructureInspector(StructureInternal structure) {
|
||||
super(structure, getComponentWrappers(structure));
|
||||
}
|
||||
|
||||
private static List<ReadOnlyComponentWrapper> getComponentWrappers(Structure structure) {
|
||||
List<ReadOnlyComponentWrapper> list = new ArrayList<>();
|
||||
for (DataTypeComponent c : structure.getComponents()) {
|
||||
for (DataTypeComponent c : structure.getDefinedComponents()) {
|
||||
list.add(new ReadOnlyComponentWrapper(c));
|
||||
}
|
||||
return list;
|
||||
|
@ -168,7 +168,7 @@ public class AlignedStructureInspector extends AlignedStructurePacker {
|
|||
* @param structure
|
||||
* @return aligned packing result
|
||||
*/
|
||||
public static StructurePackResult packComponents(Structure structure) {
|
||||
public static StructurePackResult packComponents(StructureInternal structure) {
|
||||
AlignedStructureInspector packer = new AlignedStructureInspector(structure);
|
||||
return packer.pack();
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ import java.util.List;
|
|||
*/
|
||||
public class AlignedStructurePacker {
|
||||
|
||||
private final Structure structure;
|
||||
private final StructureInternal structure;
|
||||
private final List<? extends InternalDataTypeComponent> components;
|
||||
|
||||
private final DataOrganization dataOrganization;
|
||||
|
@ -38,7 +38,7 @@ public class AlignedStructurePacker {
|
|||
* during packing (ordinal, offset, length and bit-field datatypes may be modified)
|
||||
* @param components list of mutable component
|
||||
*/
|
||||
protected AlignedStructurePacker(Structure structure,
|
||||
protected AlignedStructurePacker(StructureInternal structure,
|
||||
List<? extends InternalDataTypeComponent> components) {
|
||||
this.structure = structure;
|
||||
this.components = components;
|
||||
|
@ -75,7 +75,7 @@ public class AlignedStructurePacker {
|
|||
int componentCount = 0;
|
||||
|
||||
AlignedComponentPacker packer =
|
||||
new AlignedComponentPacker(structure.getPackingValue(), dataOrganization);
|
||||
new AlignedComponentPacker(structure.getStoredPackingValue(), dataOrganization);
|
||||
|
||||
// Remove any default components from list
|
||||
Iterator<? extends InternalDataTypeComponent> componentIterator = components.iterator();
|
||||
|
@ -95,7 +95,7 @@ public class AlignedStructurePacker {
|
|||
packer.addComponent(dataTypeComponent, isLastComponent);
|
||||
}
|
||||
|
||||
int externalAlignment = packer.getExternalAlignment();
|
||||
int defaultAlignment = packer.getDefaultAlignment();
|
||||
|
||||
int length = packer.getLength();
|
||||
componentsChanged |= packer.componentsChanged();
|
||||
|
@ -104,22 +104,25 @@ public class AlignedStructurePacker {
|
|||
if (flexibleArrayComponent != null) {
|
||||
// account for flexible array type and any end of structure padding required
|
||||
int componentAlignment = CompositeAlignmentHelper.getPackedAlignment(dataOrganization,
|
||||
structure.getPackingValue(), flexibleArrayComponent);
|
||||
length = DataOrganizationImpl.getOffset(componentAlignment, length);
|
||||
externalAlignment =
|
||||
DataOrganizationImpl.getLeastCommonMultiple(externalAlignment, componentAlignment);
|
||||
structure.getStoredPackingValue(), flexibleArrayComponent);
|
||||
length = DataOrganizationImpl.getAlignedOffset(componentAlignment, length);
|
||||
defaultAlignment =
|
||||
DataOrganizationImpl.getLeastCommonMultiple(defaultAlignment, componentAlignment);
|
||||
}
|
||||
|
||||
int alignment = structure.getMinimumAlignment();
|
||||
if (alignment < externalAlignment) {
|
||||
alignment = externalAlignment;
|
||||
int alignment = defaultAlignment;
|
||||
AlignmentType alignmentType = structure.getAlignmentType();
|
||||
if (alignmentType != AlignmentType.DEFAULT) {
|
||||
// Apply minimum alignment if applicable - may be reduced by explicit pack
|
||||
// Simplified logic assumes pack and align values which are a power of 2 (1,2,4,8,16...)
|
||||
int minAlign =
|
||||
alignmentType == AlignmentType.MACHINE ? dataOrganization.getMachineAlignment()
|
||||
: structure.getExplicitMinimumAlignment();
|
||||
alignment = Math.max(defaultAlignment, minAlign);
|
||||
}
|
||||
|
||||
if (length != 0) {
|
||||
int padSize = DataOrganizationImpl.getPaddingSize(alignment, length);
|
||||
if (padSize > 0) {
|
||||
length += padSize;
|
||||
}
|
||||
length = DataOrganizationImpl.getAlignedOffset(alignment, length);
|
||||
}
|
||||
|
||||
return new StructurePackResult(componentCount, length, alignment, componentsChanged);
|
||||
|
@ -135,7 +138,7 @@ public class AlignedStructurePacker {
|
|||
* @param components structure components (excludes any trailing flexible array).
|
||||
* @return aligned packing result
|
||||
*/
|
||||
public static StructurePackResult packComponents(Structure structure,
|
||||
public static StructurePackResult packComponents(StructureInternal structure,
|
||||
List<? extends InternalDataTypeComponent> components) {
|
||||
AlignedStructurePacker packer = new AlignedStructurePacker(structure, components);
|
||||
return packer.pack();
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.program.model.data;
|
||||
|
||||
/**
|
||||
* <code>AlignmentType</code> specifies the type of alignment which applies to a composite data type.
|
||||
* This can be DEFAULT, MACHINE, EXPLICIT. For packed composites, the length of the composite
|
||||
* will be padded to force the length to a multiple of the computed alignment.
|
||||
*/
|
||||
public enum AlignmentType {
|
||||
/**
|
||||
* <B>DEFAULT</B> - this data type's alignment is computed based upon its current pack setting
|
||||
* and data organization rules. If packing is disabled the computed alignment will be 1.
|
||||
*/
|
||||
DEFAULT,
|
||||
/**
|
||||
* <B>MACHINE</B> - this data type's alignment will be a multiple of the machine alignment
|
||||
* specified by the data organization. In general, and for all non-packed composites, the
|
||||
* computed alignment will match the machine alignment if this setting is used.
|
||||
*/
|
||||
MACHINE,
|
||||
/**
|
||||
* <B>MACHINE</B> - this data type's alignment will be a multiple of the explicit alignment
|
||||
* value specified for the datatype. For all non-packed composites, the
|
||||
* computed alignment will match the machine alignment if this setting is used.
|
||||
*/
|
||||
EXPLICIT;
|
||||
}
|
|
@ -130,6 +130,11 @@ public class ArrayDataType extends DataTypeImpl implements Array {
|
|||
return DataTypeUtilities.getMnemonic(this, false, settings);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isZeroLength() {
|
||||
return dataType.isZeroLength();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLength() {
|
||||
return numElements * getElementLength();
|
||||
|
@ -160,11 +165,18 @@ public class ArrayDataType extends DataTypeImpl implements Array {
|
|||
|
||||
@Override
|
||||
public void dataTypeSizeChanged(DataType dt) {
|
||||
if (dt.equals(dataType)) {
|
||||
if (dt == dataType) {
|
||||
notifySizeChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dataTypeAlignmentChanged(DataType dt) {
|
||||
if (dt == dataType) {
|
||||
notifyAlignmentChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getValueClass(Settings settings) {
|
||||
return getArrayValueClass(settings);
|
||||
|
|
|
@ -15,56 +15,13 @@
|
|||
*/
|
||||
package ghidra.program.model.data;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Interface for common methods in Structure and Union
|
||||
*/
|
||||
public interface Composite extends DataType {
|
||||
|
||||
/**
|
||||
* AlignmentType defined the three states for the type of alignment of a composite data type.
|
||||
* This can be default aligned, machine aligned or aligned by value.
|
||||
* <BR>This controls how this data type will be aligned within other data types.
|
||||
* <BR><B>Default Aligned</B> means to determine this data type's alignment based upon the
|
||||
* alignments of its components. This is controlled by the Data Organization that is provided
|
||||
* by its data type manager. If there is no data type manager then a default data organization
|
||||
* is used.
|
||||
* <BR><B>Machine Aligned</B> means this data type's alignment will use a minimum alignment that
|
||||
* is the machine alignment specified by the data organization.
|
||||
* <BR><B>Align By Value</B> means that a "minimum alignment value", which is a power of 2 and
|
||||
* specified elsewhere, will affect the alignment so that it will be at least the
|
||||
* indicated value and will be a multiple of the minimum value and of the default value.
|
||||
* <BR>Note: If the data organization specifies a maximum alignment, other than 0, then the
|
||||
* alignment value will not be allowed to exceed the maximum alignment for any of these types.
|
||||
*/
|
||||
public static enum AlignmentType implements NamedAlignment {
|
||||
DEFAULT_ALIGNED("Default Aligned"),
|
||||
MACHINE_ALIGNED("Machine Aligned"),
|
||||
ALIGNED_BY_VALUE("Align By Value");
|
||||
|
||||
private String name;
|
||||
|
||||
AlignmentType(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
interface NamedAlignment {
|
||||
public String getName();
|
||||
}
|
||||
|
||||
public final static int DEFAULT_ALIGNMENT_VALUE = 0;
|
||||
public final static int NOT_PACKING = 0;
|
||||
|
||||
/**
|
||||
* Sets the string describing this data type.
|
||||
* @param desc the new description.
|
||||
|
@ -74,8 +31,8 @@ public interface Composite extends DataType {
|
|||
|
||||
/**
|
||||
* Gets the number of component data types in this composite.
|
||||
* The count will include all undefined filler components which may be present
|
||||
* within an unaligned structure. Structures do not include the
|
||||
* If this is Structure with packing disabled, the count will include all undefined filler
|
||||
* components which may be present. In addition, Structures do not include the
|
||||
* optional trailing flexible array component in this count
|
||||
* (see {@link Structure#hasFlexibleArrayComponent()}).
|
||||
* @return the number of components that make up this composite
|
||||
|
@ -84,9 +41,13 @@ public interface Composite extends DataType {
|
|||
|
||||
/**
|
||||
* Returns the number of explicitly defined components in this composite.
|
||||
* For Unions and aligned Structures this is equivalent to {@link #getNumComponents()}
|
||||
* since they do not contain undefined components. The count will exclude all undefined
|
||||
* filler components which may be present within an unaligned structure.
|
||||
* For Unions and packed Structures this is equivalent to {@link #getNumComponents()}
|
||||
* since they do not contain undefined components.
|
||||
* This count will always exclude all undefined filler components which may be present
|
||||
* within a Structure whoose packing is disabled (see {@link #isPackingEnabled()}).
|
||||
* In addition, Structures do not include the
|
||||
* optional trailing flexible array component in this count
|
||||
* (see {@link Structure#hasFlexibleArrayComponent()}).
|
||||
* @return the number of explicitly defined components in this composite
|
||||
*/
|
||||
public abstract int getNumDefinedComponents();
|
||||
|
@ -95,27 +56,28 @@ public interface Composite extends DataType {
|
|||
* Returns the component of this data type with the indicated ordinal.
|
||||
* @param ordinal the component's ordinal (zero based).
|
||||
* @return the data type component.
|
||||
* @throws ArrayIndexOutOfBoundsException if the ordinal is out of bounds
|
||||
* @throws IndexOutOfBoundsException if the ordinal is out of bounds
|
||||
*/
|
||||
public abstract DataTypeComponent getComponent(int ordinal);
|
||||
public abstract DataTypeComponent getComponent(int ordinal) throws IndexOutOfBoundsException;
|
||||
|
||||
/**
|
||||
* Returns an array of Data Type Components that make up this composite including
|
||||
* undefined filler components which may be present within an unaligned structure.
|
||||
* undefined filler components which may be present within a Structure whch has packing disabled.
|
||||
* Structures do not include the optional trailing flexible array component in the returned array.
|
||||
* The number of components corresponds to {@link #getNumComponents()}.
|
||||
* @return list all components
|
||||
* @return array all components
|
||||
*/
|
||||
public abstract DataTypeComponent[] getComponents();
|
||||
|
||||
/**
|
||||
* Returns an array of Data Type Components that make up this composite excluding
|
||||
* undefined filler components which may be present within an unaligned structure.
|
||||
* The number of components corresponds to {@link #getNumComponents()}. For Unions and
|
||||
* aligned Structures this is equivalent to {@link #getComponents()}
|
||||
* since they do not contain undefined components. Structures do not include the
|
||||
* optional trailing flexible array component in this list
|
||||
* undefined filler components which may be present within Structures where packing is disabled.
|
||||
* The number of components corresponds to {@link #getNumDefinedComponents()}. For Unions and
|
||||
* packed Structures this is equivalent to {@link #getComponents()}
|
||||
* since they do not contain undefined filler components. Structures do not include the
|
||||
* optional trailing flexible array component in the returned array
|
||||
* (see {@link Structure#getFlexibleArrayComponent()}).
|
||||
* @return list all explicitly defined components
|
||||
* @return array all explicitly defined components
|
||||
*/
|
||||
public abstract DataTypeComponent[] getDefinedComponents();
|
||||
|
||||
|
@ -164,9 +126,9 @@ public interface Composite extends DataType {
|
|||
|
||||
/**
|
||||
* Adds a new bitfield to the end of this composite. This method is intended
|
||||
* to be used with aligned structures/unions only where the bitfield will be
|
||||
* to be used with packed structures/unions only where the bitfield will be
|
||||
* appropriately packed. The minimum storage storage byte size will be applied.
|
||||
* It will not provide useful results within unaligned composites.
|
||||
* It will not provide useful results for composites with packing disabled.
|
||||
* @param baseDataType the bitfield base datatype (certain restrictions apply).
|
||||
* @param bitSize the bitfield size in bits
|
||||
* @param componentName the field name to associate with this component.
|
||||
|
@ -208,9 +170,10 @@ public interface Composite extends DataType {
|
|||
* allowed to be inserted into this composite data type.
|
||||
* For example, suppose dt1 contains dt2. Therefore it is not valid
|
||||
* to insert dt1 to dt2 since this would cause a cyclic dependency.
|
||||
* @throws ArrayIndexOutOfBoundsException if component ordinal is out of bounds
|
||||
* @throws IndexOutOfBoundsException if component ordinal is out of bounds
|
||||
*/
|
||||
public DataTypeComponent insert(int ordinal, DataType dataType) throws IllegalArgumentException;
|
||||
public DataTypeComponent insert(int ordinal, DataType dataType)
|
||||
throws IndexOutOfBoundsException, IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Inserts a new datatype at the specified ordinal position in this composite.
|
||||
|
@ -226,10 +189,10 @@ public interface Composite extends DataType {
|
|||
* length is specified.
|
||||
* For example, suppose dt1 contains dt2. Therefore it is not valid
|
||||
* to insert dt1 to dt2 since this would cause a cyclic dependency.
|
||||
* @throws ArrayIndexOutOfBoundsException if component ordinal is out of bounds
|
||||
* @throws IndexOutOfBoundsException if component ordinal is out of bounds
|
||||
*/
|
||||
public DataTypeComponent insert(int ordinal, DataType dataType, int length)
|
||||
throws IllegalArgumentException;
|
||||
throws IndexOutOfBoundsException, IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Inserts a new datatype at the specified ordinal position in this composite.
|
||||
|
@ -247,28 +210,28 @@ public interface Composite extends DataType {
|
|||
* is specified.
|
||||
* For example, suppose dt1 contains dt2. Therefore it is not valid
|
||||
* to insert dt1 to dt2 since this would cause a cyclic dependency.
|
||||
* @throws ArrayIndexOutOfBoundsException if component ordinal is out of bounds
|
||||
* @throws IndexOutOfBoundsException if component ordinal is out of bounds
|
||||
*/
|
||||
public DataTypeComponent insert(int ordinal, DataType dataType, int length, String name,
|
||||
String comment) throws ArrayIndexOutOfBoundsException, IllegalArgumentException;
|
||||
String comment) throws IndexOutOfBoundsException, IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Deletes the component at the given ordinal position.
|
||||
* <BR>Note: Removal of bitfields from an unaligned structure will
|
||||
* not shift other components with vacated bytes reverting to undefined.
|
||||
* <BR>Note: Removal of bitfields from a structure with packing disabled will
|
||||
* not shift other components causing vacated bytes to revert to undefined filler.
|
||||
* @param ordinal the ordinal of the component to be deleted.
|
||||
* @throws ArrayIndexOutOfBoundsException if component ordinal is out of bounds
|
||||
* @throws IndexOutOfBoundsException if component ordinal is out of bounds
|
||||
*/
|
||||
public void delete(int ordinal) throws ArrayIndexOutOfBoundsException;
|
||||
public void delete(int ordinal) throws IndexOutOfBoundsException;
|
||||
|
||||
/**
|
||||
* Deletes the components at the given ordinal positions.
|
||||
* <BR>Note: Removal of bitfields from an unaligned structure will
|
||||
* not shift other components with vacated bytes reverting to undefined.
|
||||
* Deletes the specified set of components at the given ordinal positions.
|
||||
* <BR>Note: Removal of bitfields from a structure with packing disabled will
|
||||
* not shift other components causing vacated bytes to revert to undefined filler.
|
||||
* @param ordinals the ordinals of the component to be deleted.
|
||||
* @throws ArrayIndexOutOfBoundsException if any specified component ordinal is out of bounds
|
||||
* @throws IndexOutOfBoundsException if any specified component ordinal is out of bounds
|
||||
*/
|
||||
public void delete(int[] ordinals) throws ArrayIndexOutOfBoundsException;
|
||||
public void delete(Set<Integer> ordinals) throws IndexOutOfBoundsException;
|
||||
|
||||
/**
|
||||
* Check if a data type is part of this data type. A data type could
|
||||
|
@ -283,111 +246,194 @@ public interface Composite extends DataType {
|
|||
public abstract boolean isPartOf(DataType dataType);
|
||||
|
||||
/**
|
||||
* Updates the composite to any changes in the data organization. If the composite is not
|
||||
* internally aligned, this method does nothing.
|
||||
*/
|
||||
public void realign();
|
||||
|
||||
/**
|
||||
* Determine if this data type has its internal components currently aligned.
|
||||
* @return true if this data type's components are aligned relative to each other using the
|
||||
* current data organization. When internally aligned the end of this data type will be padded
|
||||
* to a multiple of its actual alignment.
|
||||
*/
|
||||
public boolean isInternallyAligned();
|
||||
|
||||
/**
|
||||
* Sets whether this data type's internal components are currently aligned or unaligned.
|
||||
* @param aligned true means align the internal components of this data type.
|
||||
* false means don't align it. True also causes the end of this data type to be padded
|
||||
* to a multiple of its actual alignment.
|
||||
*/
|
||||
public void setInternallyAligned(boolean aligned);
|
||||
|
||||
/**
|
||||
* The overall (external) alignment changed for the specified data type.
|
||||
* In other words, the data type has a different alignment when placed inside other structures.
|
||||
* The alignment changed for the specified data type. If packing is enabled for this
|
||||
* composite, the placement of the component may be affected by a change in its alignment.
|
||||
* A non-packed composite can ignore this notification.
|
||||
* @param dt the data type whose alignment changed.
|
||||
*/
|
||||
@Override
|
||||
public void dataTypeAlignmentChanged(DataType dt);
|
||||
|
||||
/**
|
||||
* Gets the current packing value (typically a power of 2). If this isn't a packed data
|
||||
* type then NOT_PACKING is returned. The packing value only pertains to internally aligned composite
|
||||
* data types. Aligned structures allow packing.
|
||||
* @return the current packing value or NOT_PACKING.
|
||||
* Updates packed composite to any changes in the data organization. If the composite does
|
||||
* not have packing enabled this method does nothing.
|
||||
* <BR>
|
||||
* NOTE: Changes to data organization is discouraged. Attempts to use this method in such
|
||||
* cases should be performed on all composites in dependency order (ignoring pointer components).
|
||||
*/
|
||||
public int getPackingValue();
|
||||
public void repack();
|
||||
|
||||
/**
|
||||
* Sets the current packing value (usually a power of 2). A value of NOT_PACKING should be passed
|
||||
* if this isn't a packed data type. Otherwise this value indicates a maximum alignment
|
||||
* for any component within this data type. Calling this method will cause the data type to
|
||||
* become an internally aligned data type.
|
||||
* <br>Note: If a component's data type has a specific external alignment, it will
|
||||
* override this value if necessary.
|
||||
* @param packingValue the new packing value or 0 for NOT_PACKING.
|
||||
* A negative value will be treated the same as 0.
|
||||
* @return the packing type set for this composite
|
||||
*/
|
||||
public void setPackingValue(int packingValue);
|
||||
public PackingType getPackingType();
|
||||
|
||||
/**
|
||||
* Get the external alignment (a minimum alignment) for this DataType.
|
||||
* This controls where this data type will get aligned within other data types.
|
||||
* It also causes the end of this data type to get padded so its length is a multiple
|
||||
* of the alignment.
|
||||
* @return the external alignment for this DataType or DEFAULT_ALIGNMENT_VALUE.
|
||||
* Determine if this data type has its internal components currently packed
|
||||
* based upon alignment and packing settings. If disabled, component placement
|
||||
* is based upon explicit placement by offset.
|
||||
* @return true if this data type's components auto-packed
|
||||
*/
|
||||
public int getMinimumAlignment();
|
||||
|
||||
/**
|
||||
* Sets the external alignment (a minimum alignment) for this DataType.
|
||||
* This controls where this data type will get aligned within other data types.
|
||||
* It also causes the end of this data type to get padded so its length is a multiple
|
||||
* of the alignment. Calling this method will cause the data type to
|
||||
* become an internally aligned data type.
|
||||
* @param minimumAlignment the external (minimum) alignment for this DataType.
|
||||
* Any value less than 1 will revert to default alignment.
|
||||
*/
|
||||
public void setMinimumAlignment(int minimumAlignment);
|
||||
|
||||
/**
|
||||
* Sets this data type's external (minimum) alignment to the default alignment. This data type's
|
||||
* external alignment will be based upon the components it contains. This should be used
|
||||
* when a data type doesn't have an alignment attribute specified. Calling this method will
|
||||
* cause the data type to become an internally aligned data type.
|
||||
*/
|
||||
public void setToDefaultAlignment();
|
||||
|
||||
/**
|
||||
* Sets this data type's external (minimum) alignment to a multiple of the machine alignment that is
|
||||
* specified in the DataOrganization. The machine alignment is defined as the maximum useful
|
||||
* alignment for the target machine. This should be used when a data type has an alignment
|
||||
* attribute specified without a size (indicating to use the machine alignment).
|
||||
* Calling this method will cause the data type to become an internally aligned data type.
|
||||
*/
|
||||
public void setToMachineAlignment();
|
||||
|
||||
/**
|
||||
* Whether or not this data type is using the default external (minimum) alignment.
|
||||
* @return true if this data type has the default external alignment.
|
||||
*/
|
||||
public boolean isDefaultAligned();
|
||||
|
||||
/**
|
||||
* Whether or not this data type is using the machine alignment value from the
|
||||
* DataOrganization for its external (minimum) alignment.
|
||||
* @return true if this data type is using the machine alignment as the minimum alignment.
|
||||
*/
|
||||
public boolean isMachineAligned();
|
||||
|
||||
/**
|
||||
* Get the bitfield packing information associated with the underlying
|
||||
* data organization.
|
||||
* @return bitfield packing information
|
||||
*/
|
||||
public default BitFieldPacking getBitFieldPacking() {
|
||||
return getDataOrganization().getBitFieldPacking();
|
||||
public default boolean isPackingEnabled() {
|
||||
return getPackingType() != PackingType.DISABLED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether this data type's internal components are currently packed. The
|
||||
* affect of disabled packing differs between {@link Structure} and {@link Union}. When
|
||||
* packing disabled:
|
||||
* <ul>
|
||||
* <li>Structures utilize explicit component offsets and produce undefined filler
|
||||
* components where defined components do not consume space.</li>
|
||||
* <li>Unions always place components at offset 0 and do not pad for alignment.
|
||||
* </ul>
|
||||
* In addition, when packing is disabled the default alignment is always 1 unless a
|
||||
* different minimum alignment has been set. When packing is enabled the overall
|
||||
* composite length infleunced by the composite's minimum alignment setting.
|
||||
* If a change in enablement occurs, the default alignment and packing behavior
|
||||
* will be used.
|
||||
* @param enabled true enables packing of components respecting component
|
||||
* alignment and pack setting, whereas false disables packing.
|
||||
*/
|
||||
public void setPackingEnabled(boolean enabled);
|
||||
|
||||
/**
|
||||
* Determine if packing is enabled with an explicit packing value (see {@link #getExplicitPackingValue()}).
|
||||
* @return true if packing is enabled with an explicit packing value, else false.
|
||||
*/
|
||||
public default boolean hasExplicitPackingValue() {
|
||||
return getPackingType() == PackingType.EXPLICIT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if default packing is enabled.
|
||||
* @return true if default packing is enabled.
|
||||
*/
|
||||
public default boolean hasDefaultPacking() {
|
||||
return getPackingType() == PackingType.DEFAULT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current packing value (typically a power of 2).
|
||||
* If this isn't a packed composite with an explicit packing value (see {@link #hasExplicitPackingValue()})
|
||||
* then the return value is undefined.
|
||||
* @return the current packing value or an undefined non-positive value
|
||||
*/
|
||||
public int getExplicitPackingValue();
|
||||
|
||||
/**
|
||||
* Sets the pack value for this composite (positive value, usually a power of 2).
|
||||
* If packing was previously disabled, packing will be enabled. This value will
|
||||
* establish the maximum effective alignment for this composite and each of the
|
||||
* components during the alignment computation (e.g., a value of 1 will eliminate
|
||||
* any padding). The overall composite length may be infleunced by the composite's
|
||||
* minimum alignment setting.
|
||||
* @param packingValue the new positive packing value.
|
||||
* @throws IllegalArgumentException if a non-positive value is specified.
|
||||
*/
|
||||
public void setExplicitPackingValue(int packingValue);
|
||||
|
||||
/**
|
||||
* Same as {@link #setExplicitPackingValue(int)}.
|
||||
* @param packingValue the new positive packing value.
|
||||
* @throws IllegalArgumentException if a non-positive value is specified.
|
||||
*/
|
||||
public default void pack(int packingValue) {
|
||||
setExplicitPackingValue(packingValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables default packing behavior.
|
||||
* If packing was previously disabled, packing will be enabled.
|
||||
* Composite will automatically pack based upon the alignment requirements
|
||||
* of its components with overall composite length possibly infleunced by the composite's
|
||||
* minimum alignment setting.
|
||||
*/
|
||||
public void setToDefaultPacking();
|
||||
|
||||
/**
|
||||
* Get the computed alignment for this composite based upon packing and minimum
|
||||
* alignment settings as well as component alignment. If packing is disabled,
|
||||
* the alignment will always be 1 unless a minimum alignment has been set.
|
||||
* @return this composites alignment
|
||||
*/
|
||||
@Override
|
||||
abstract int getAlignment();
|
||||
|
||||
/**
|
||||
* @return the alignment type set for this composite
|
||||
*/
|
||||
abstract AlignmentType getAlignmentType();
|
||||
|
||||
/**
|
||||
* Whether or not this data type is using the default alignment. When Structure packing
|
||||
* is disabled the default alignment is always 1 (see {@link Structure#setPackingEnabled(boolean)}.
|
||||
* @return true if this data type is using its default alignment.
|
||||
*/
|
||||
public default boolean isDefaultAligned() {
|
||||
return getAlignmentType() == AlignmentType.DEFAULT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not this data type is using the machine alignment value, specified by
|
||||
* {@link DataOrganization#getMachineAlignment()}, for its alignment.
|
||||
* @return true if this data type is using the machine alignment as its alignment.
|
||||
*/
|
||||
public default boolean isMachineAligned() {
|
||||
return getAlignmentType() == AlignmentType.MACHINE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if an explicit minimum alignment has been set (see {@link #getExplicitMinimumAlignment()}).
|
||||
* An undefined value is returned if default alignment or machine alignment is enabled.
|
||||
* @return true if an explicit minimum alignment has been set, else false
|
||||
*/
|
||||
public default boolean hasExplicitMinimumAlignment() {
|
||||
return getAlignmentType() == AlignmentType.EXPLICIT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the explicitminimum alignment setting for this Composite which contributes
|
||||
* to the actual computed alignment value (see {@link #getAlignment()}.
|
||||
* @return the minimum alignment setting for this Composite or an undefined
|
||||
* non-positive value if an explicit minimum alignment has not been set.
|
||||
*/
|
||||
public int getExplicitMinimumAlignment();
|
||||
|
||||
/**
|
||||
* Sets this data type's explicit minimum alignment (positive value).
|
||||
* Together with the pack setting and component alignments will
|
||||
* affect the actual computed alignment of this composite.
|
||||
* When packing is enabled, the alignment setting may also affect padding
|
||||
* at the end of the composite and its length. When packing is disabled,
|
||||
* this setting will not affect the length of thhis composite.
|
||||
* @param minAlignment the minimum alignment for this Composite.
|
||||
* @throws IllegalArgumentException if a non-positive value is specified
|
||||
*/
|
||||
public void setExplicitMinimumAlignment(int minAlignment);
|
||||
|
||||
/**
|
||||
* Same as {@link #setExplicitMinimumAlignment(int)}.
|
||||
* @param minAlignment the explicit minimum alignment for this Composite.
|
||||
* @throws IllegalArgumentException if a non-positive value is specified
|
||||
*/
|
||||
public default void align(int minAlignment) {
|
||||
setExplicitMinimumAlignment(minAlignment);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this data type's alignment to its default alignment. For packed
|
||||
* composites, this data type's alignment will be based upon the components it contains and
|
||||
* its current pack settings. This is the default state and only needs to be used
|
||||
* when changing from a non-default alignment type.
|
||||
*/
|
||||
public void setToDefaultAligned();
|
||||
|
||||
/**
|
||||
* Sets this data type's minimum alignment to the machine alignment which is
|
||||
* specified by {@link DataOrganization#getMachineAlignment()}. The machine alignment is
|
||||
* defined as the maximum useful alignment for the target machine.
|
||||
*/
|
||||
public void setToMachineAligned();
|
||||
|
||||
}
|
||||
|
|
|
@ -18,14 +18,14 @@ package ghidra.program.model.data;
|
|||
public class CompositeAlignmentHelper {
|
||||
|
||||
private static int getCompositeAlignmentMultiple(DataOrganization dataOrganization,
|
||||
Composite composite) {
|
||||
CompositeInternal composite) {
|
||||
int allComponentsLCM = 1;
|
||||
int packingAlignment = composite.getPackingValue();
|
||||
int packingValue = composite.getStoredPackingValue();
|
||||
|
||||
DataTypeComponent[] dataTypeComponents = composite.getDefinedComponents();
|
||||
for (DataTypeComponent dataTypeComponent : dataTypeComponents) {
|
||||
int impartedAlignment = CompositeAlignmentHelper.getPackedAlignment(dataOrganization,
|
||||
packingAlignment, dataTypeComponent);
|
||||
packingValue, dataTypeComponent);
|
||||
if (impartedAlignment != 0) {
|
||||
allComponentsLCM = DataOrganizationImpl.getLeastCommonMultiple(allComponentsLCM,
|
||||
impartedAlignment);
|
||||
|
@ -36,7 +36,7 @@ public class CompositeAlignmentHelper {
|
|||
DataTypeComponent flexibleArrayComponent = struct.getFlexibleArrayComponent();
|
||||
if (flexibleArrayComponent != null) {
|
||||
allComponentsLCM = getComponentAlignmentLCM(dataOrganization, allComponentsLCM,
|
||||
packingAlignment, flexibleArrayComponent);
|
||||
packingValue, flexibleArrayComponent);
|
||||
}
|
||||
}
|
||||
return allComponentsLCM;
|
||||
|
@ -58,53 +58,33 @@ public class CompositeAlignmentHelper {
|
|||
// Zero-length bitfields ignored within unions for non-MSVC cases
|
||||
return 0;
|
||||
}
|
||||
|
||||
DataType componentDt = component.getDataType();
|
||||
int dtSize = componentDt.getLength();
|
||||
if (dtSize <= 0) {
|
||||
dtSize = component.getLength();
|
||||
}
|
||||
return getPackedAlignment(dataOrganization, packingValue, componentDt, dtSize);
|
||||
return getPackedAlignment(componentDt.getAlignment(), packingValue);
|
||||
}
|
||||
|
||||
private static int getPackedAlignment(int componentAlignment, int forcedAlignment,
|
||||
int packingAlignment) {
|
||||
// Only do packing if we are not forcing an alignment.
|
||||
static int getPackedAlignment(int componentAlignment, int packingValue) {
|
||||
int alignment = componentAlignment;
|
||||
if (packingAlignment != Composite.NOT_PACKING) { // TODO Should this be packingValue > 0?
|
||||
if (forcedAlignment > packingAlignment) {
|
||||
alignment = forcedAlignment;
|
||||
}
|
||||
else if (alignment > packingAlignment) {
|
||||
alignment = packingAlignment;
|
||||
}
|
||||
if (packingValue > 0 && packingValue < componentAlignment) {
|
||||
alignment = packingValue;
|
||||
}
|
||||
return alignment;
|
||||
}
|
||||
|
||||
public static int getPackedAlignment(DataOrganization dataOrganization, int packingAlignment,
|
||||
DataType componentDt, int dtSize) {
|
||||
int componentAlignment = dataOrganization.getAlignment(componentDt, dtSize);
|
||||
int componentForcedAlignment = dataOrganization.getForcedAlignment(componentDt);
|
||||
boolean componentForcingAlignment = componentForcedAlignment > 0;
|
||||
if (componentForcingAlignment) {
|
||||
componentAlignment = DataOrganizationImpl.getLeastCommonMultiple(componentAlignment,
|
||||
componentForcedAlignment);
|
||||
}
|
||||
return getPackedAlignment(componentAlignment, componentForcedAlignment, packingAlignment);
|
||||
}
|
||||
|
||||
public static int getAlignment(DataOrganization dataOrganization, Composite dataType) {
|
||||
public static int getAlignment(DataOrganization dataOrganization, CompositeInternal composite) {
|
||||
|
||||
// TODO: goal is to eliminate this method in favor of pack once and remember alignment
|
||||
|
||||
if (!dataType.isInternallyAligned()) {
|
||||
return 1; // Unaligned
|
||||
int minimumAlignment = composite.getStoredMinimumAlignment();
|
||||
if (minimumAlignment < CompositeInternal.DEFAULT_ALIGNMENT) {
|
||||
minimumAlignment = dataOrganization.getMachineAlignment();
|
||||
}
|
||||
|
||||
if (!composite.isPackingEnabled()) {
|
||||
return minimumAlignment == CompositeInternal.DEFAULT_ALIGNMENT ? 1 : minimumAlignment;
|
||||
}
|
||||
|
||||
int lcm = getCompositeAlignmentMultiple(dataOrganization, dataType);
|
||||
int minimumAlignment = dataType.getMinimumAlignment();
|
||||
if ((minimumAlignment != Composite.DEFAULT_ALIGNMENT_VALUE) &&
|
||||
int lcm = getCompositeAlignmentMultiple(dataOrganization, composite);
|
||||
if ((minimumAlignment != CompositeInternal.DEFAULT_ALIGNMENT) &&
|
||||
(lcm % minimumAlignment != 0)) {
|
||||
lcm = DataOrganizationImpl.getLeastCommonMultiple(lcm, minimumAlignment);
|
||||
}
|
||||
|
|
|
@ -26,17 +26,18 @@ import ghidra.util.exception.NotYetImplementedException;
|
|||
/**
|
||||
* Common implementation methods for structure and union
|
||||
*/
|
||||
public abstract class CompositeDataTypeImpl extends GenericDataType implements Composite {
|
||||
private final static long serialVersionUID = 1;
|
||||
public abstract class CompositeDataTypeImpl extends GenericDataType implements CompositeInternal {
|
||||
|
||||
// Strings used for toString formatting
|
||||
private static final String ALIGN_NAME = "aligned";
|
||||
private static final String PACKING_NAME = "pack";
|
||||
private static final String DISABLED_PACKING_NAME = "disabled";
|
||||
private static final String DEFAULT_PACKING_NAME = "";
|
||||
|
||||
private String description;
|
||||
|
||||
protected boolean aligned = false; // WARNING, changing the initial value for this will cause
|
||||
// subtle errors - One I know of is in the StructureDataType
|
||||
// copyComponent method. It has built in assumptions about this.
|
||||
|
||||
protected AlignmentType alignmentType = AlignmentType.DEFAULT_ALIGNED;
|
||||
protected int packingValue = NOT_PACKING;
|
||||
protected int externalAlignment = DEFAULT_ALIGNMENT_VALUE;
|
||||
protected int minimumAlignment = DEFAULT_ALIGNMENT;
|
||||
protected int packing = NO_PACKING;
|
||||
|
||||
/**
|
||||
* Construct a new composite with the given name
|
||||
|
@ -67,6 +68,21 @@ public abstract class CompositeDataTypeImpl extends GenericDataType implements C
|
|||
description = "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStoredPackingValue() {
|
||||
return packing;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStoredMinimumAlignment() {
|
||||
return minimumAlignment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dataTypeNameChanged(DataType dt, String oldName) {
|
||||
// ignored
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the preferred length for a new component. For Unions and internally
|
||||
* aligned structures the preferred component length for a fixed-length dataType
|
||||
|
@ -80,9 +96,6 @@ public abstract class CompositeDataTypeImpl extends GenericDataType implements C
|
|||
* @return preferred component length
|
||||
*/
|
||||
protected int getPreferredComponentLength(DataType dataType, int length) {
|
||||
if ((isInternallyAligned() || (this instanceof Union)) && !(dataType instanceof Dynamic)) {
|
||||
length = -1; // force use of datatype size
|
||||
}
|
||||
int dtLength = dataType.getLength();
|
||||
if (length <= 0) {
|
||||
length = dtLength;
|
||||
|
@ -99,7 +112,7 @@ public abstract class CompositeDataTypeImpl extends GenericDataType implements C
|
|||
|
||||
@Override
|
||||
public boolean isDynamicallySized() {
|
||||
return isInternallyAligned();
|
||||
return true; // assume dynamically sized component datatype may be present
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -135,10 +148,6 @@ public abstract class CompositeDataTypeImpl extends GenericDataType implements C
|
|||
* @throws IllegalArgumentException if the data type is invalid.
|
||||
*/
|
||||
protected void validateDataType(DataType dataType) {
|
||||
if (isInternallyAligned() && dataType == DataType.DEFAULT) {
|
||||
throw new IllegalArgumentException(
|
||||
"The DEFAULT data type is not allowed in an aligned composite data type.");
|
||||
}
|
||||
if (dataType instanceof FactoryDataType) {
|
||||
throw new IllegalArgumentException("The \"" + dataType.getName() +
|
||||
"\" data type is not allowed in a composite data type.");
|
||||
|
@ -250,139 +259,161 @@ public abstract class CompositeDataTypeImpl extends GenericDataType implements C
|
|||
}
|
||||
|
||||
@Override
|
||||
public int getPackingValue() {
|
||||
return packingValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPackingValue(int packingValue) {
|
||||
if (packingValue < 0) {
|
||||
packingValue = NOT_PACKING;
|
||||
}
|
||||
aligned = true;
|
||||
this.packingValue = packingValue;
|
||||
adjustInternalAlignment();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinimumAlignment() {
|
||||
if (alignmentType == AlignmentType.MACHINE_ALIGNED) {
|
||||
return getMachineAlignment();
|
||||
}
|
||||
if (alignmentType == AlignmentType.DEFAULT_ALIGNED) {
|
||||
return Composite.DEFAULT_ALIGNMENT_VALUE;
|
||||
}
|
||||
return externalAlignment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMinimumAlignment(int externalAlignment) {
|
||||
if (externalAlignment < 1) {
|
||||
this.externalAlignment = DEFAULT_ALIGNMENT_VALUE;
|
||||
alignmentType = AlignmentType.DEFAULT_ALIGNED;
|
||||
}
|
||||
else {
|
||||
this.externalAlignment = externalAlignment;
|
||||
alignmentType = AlignmentType.ALIGNED_BY_VALUE;
|
||||
}
|
||||
aligned = true;
|
||||
adjustInternalAlignment();
|
||||
}
|
||||
|
||||
private int getMachineAlignment() {
|
||||
return getDataOrganization().getMachineAlignment();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInternallyAligned() {
|
||||
return aligned;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDefaultAligned() {
|
||||
return alignmentType == AlignmentType.DEFAULT_ALIGNED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMachineAligned() {
|
||||
return alignmentType == AlignmentType.MACHINE_ALIGNED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInternallyAligned(boolean aligned) {
|
||||
if (this.aligned != aligned) {
|
||||
this.aligned = aligned;
|
||||
if (!aligned) {
|
||||
alignmentType = AlignmentType.DEFAULT_ALIGNED;
|
||||
packingValue = Composite.NOT_PACKING;
|
||||
}
|
||||
}
|
||||
adjustInternalAlignment();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setToDefaultAlignment() {
|
||||
aligned = true;
|
||||
alignmentType = AlignmentType.DEFAULT_ALIGNED;
|
||||
adjustInternalAlignment();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setToMachineAlignment() {
|
||||
aligned = true;
|
||||
alignmentType = AlignmentType.MACHINE_ALIGNED;
|
||||
adjustInternalAlignment();
|
||||
public final void repack() {
|
||||
repack(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify any parent data types that this composite data type's alignment has
|
||||
* changed.
|
||||
* Repack components within this composite based on the current packing, alignment
|
||||
* and {@link DataOrganization} settings. Non-packed Structures: change detection
|
||||
* is limited to component count and length is assumed to already be correct.
|
||||
* <p>
|
||||
* NOTE: If modifications to stored length are made prior to invoking this method,
|
||||
* detection of a size change may not be possible.
|
||||
* <p>
|
||||
* NOTE: Currently a change in calculated alignment can not be provided since
|
||||
* this value is not stored.
|
||||
*
|
||||
* @param notify if true notification will be sent to parents if a size change
|
||||
* or component placement change is detected.
|
||||
* @return true if a layout change was detected.
|
||||
*/
|
||||
protected void notifyAlignmentChanged() {
|
||||
DataType[] parents = getParents();
|
||||
for (DataType dataType : parents) {
|
||||
if (dataType instanceof Composite) {
|
||||
Composite composite = (Composite) dataType;
|
||||
composite.dataTypeAlignmentChanged(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjusts the internal alignment of components within this composite based on
|
||||
* the current settings of the internal alignment, packing, alignment type and
|
||||
* minimum alignment value. This method should be called whenever any of the
|
||||
* above settings are changed or whenever a components data type is changed or a
|
||||
* component is added or removed.
|
||||
*/
|
||||
protected abstract void adjustInternalAlignment();
|
||||
public abstract boolean repack(boolean notify);
|
||||
|
||||
@Override
|
||||
public int getAlignment() {
|
||||
return CompositeAlignmentHelper.getAlignment(getDataOrganization(), this);
|
||||
public void setPackingEnabled(boolean enabled) {
|
||||
if (enabled == isPackingEnabled()) {
|
||||
return;
|
||||
}
|
||||
setStoredPackingValue(enabled ? DEFAULT_PACKING : NO_PACKING);
|
||||
}
|
||||
|
||||
// set my alignment info to the same as the given composite
|
||||
protected void setAlignment(Composite composite) {
|
||||
|
||||
aligned = composite.isInternallyAligned();
|
||||
|
||||
if (composite.isDefaultAligned()) {
|
||||
alignmentType = AlignmentType.DEFAULT_ALIGNED;
|
||||
@Override
|
||||
public PackingType getPackingType() {
|
||||
if (packing < DEFAULT_PACKING) {
|
||||
return PackingType.DISABLED;
|
||||
}
|
||||
else if (composite.isMachineAligned()) {
|
||||
alignmentType = AlignmentType.MACHINE_ALIGNED;
|
||||
if (packing == DEFAULT_PACKING) {
|
||||
return PackingType.DEFAULT;
|
||||
}
|
||||
return PackingType.EXPLICIT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setToDefaultPacking() {
|
||||
setStoredPackingValue(DEFAULT_PACKING);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getExplicitPackingValue() {
|
||||
return packing;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExplicitPackingValue(int packingValue) {
|
||||
if (packingValue <= 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"explicit packing value must be positive: " + packingValue);
|
||||
}
|
||||
setStoredPackingValue(packingValue);
|
||||
}
|
||||
|
||||
private void setStoredPackingValue(int packingValue) {
|
||||
if (minimumAlignment < NO_PACKING) {
|
||||
throw new IllegalArgumentException("invalid packing value: " + packingValue);
|
||||
}
|
||||
if (packingValue == this.packing) {
|
||||
return;
|
||||
}
|
||||
if (this.packing == NO_PACKING || packingValue == NO_PACKING) {
|
||||
// force default alignment when transitioning to or from disabled packing
|
||||
this.minimumAlignment = DEFAULT_ALIGNMENT;
|
||||
}
|
||||
this.packing = packingValue;
|
||||
repack(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AlignmentType getAlignmentType() {
|
||||
if (minimumAlignment < DEFAULT_ALIGNMENT) {
|
||||
return AlignmentType.MACHINE;
|
||||
}
|
||||
if (minimumAlignment == DEFAULT_ALIGNMENT) {
|
||||
return AlignmentType.DEFAULT;
|
||||
}
|
||||
return AlignmentType.EXPLICIT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setToDefaultAligned() {
|
||||
setStoredMinimumAlignment(DEFAULT_ALIGNMENT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setToMachineAligned() {
|
||||
setStoredMinimumAlignment(MACHINE_ALIGNMENT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getExplicitMinimumAlignment() {
|
||||
return minimumAlignment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExplicitMinimumAlignment(int minimumAlignment) {
|
||||
if (minimumAlignment <= 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"explicit minimum alignment must be positive: " + minimumAlignment);
|
||||
}
|
||||
setStoredMinimumAlignment(minimumAlignment);
|
||||
}
|
||||
|
||||
private void setStoredMinimumAlignment(int minimumAlignment) {
|
||||
if (minimumAlignment < MACHINE_ALIGNMENT) {
|
||||
throw new IllegalArgumentException(
|
||||
"invalid minimum alignment value: " + minimumAlignment);
|
||||
}
|
||||
if (this.minimumAlignment == minimumAlignment) {
|
||||
return;
|
||||
}
|
||||
this.minimumAlignment = minimumAlignment;
|
||||
repack(true);
|
||||
}
|
||||
|
||||
protected final int getNonPackedAlignment() {
|
||||
int alignment;
|
||||
if (minimumAlignment == DEFAULT_ALIGNMENT) {
|
||||
alignment = 1;
|
||||
}
|
||||
else if (minimumAlignment == MACHINE_ALIGNMENT) {
|
||||
alignment = getDataOrganization().getMachineAlignment();
|
||||
}
|
||||
else {
|
||||
if (alignmentType != AlignmentType.ALIGNED_BY_VALUE) {
|
||||
alignmentType = AlignmentType.ALIGNED_BY_VALUE;
|
||||
}
|
||||
externalAlignment = composite.getMinimumAlignment();
|
||||
alignment = minimumAlignment;
|
||||
}
|
||||
return alignment;
|
||||
}
|
||||
|
||||
packingValue = composite.getPackingValue();
|
||||
@Override
|
||||
public abstract int getAlignment();
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return toString(this);
|
||||
}
|
||||
|
||||
public static String toString(Composite composite) {
|
||||
|
||||
StringBuilder stringBuffer = new StringBuilder();
|
||||
stringBuffer.append(composite.getPathName() + "\n");
|
||||
stringBuffer.append(getAlignmentAndPackingString(composite) + "\n");
|
||||
stringBuffer.append(getTypeName(composite) + " " + composite.getDisplayName() + " {\n");
|
||||
dumpComponents(composite, stringBuffer, " ");
|
||||
stringBuffer.append("}\n");
|
||||
stringBuffer.append("Size = " + composite.getLength() + " Actual Alignment = " +
|
||||
composite.getAlignment() + "\n");
|
||||
return stringBuffer.toString();
|
||||
|
||||
adjustInternalAlignment();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -391,11 +422,13 @@ public abstract class CompositeDataTypeImpl extends GenericDataType implements C
|
|||
* @param buffer string buffer
|
||||
* @param pad padding to be used with each component output line
|
||||
*/
|
||||
protected void dumpComponents(StringBuilder buffer, String pad) {
|
||||
// limit output of filler components for unaligned structures
|
||||
DataTypeComponent[] components = getDefinedComponents();
|
||||
private static void dumpComponents(Composite composite, StringBuilder buffer, String pad) {
|
||||
// limit output of filler components for non-packed structures
|
||||
DataTypeComponent[] components = composite.getDefinedComponents();
|
||||
for (DataTypeComponent dtc : components) {
|
||||
DataType dataType = dtc.getDataType();
|
||||
// buffer.append(pad + dtc.getOrdinal());
|
||||
// buffer.append(") ");
|
||||
buffer.append(pad + dtc.getOffset());
|
||||
buffer.append(pad + dataType.getName());
|
||||
if (dataType instanceof BitFieldDataType) {
|
||||
|
@ -413,57 +446,76 @@ public abstract class CompositeDataTypeImpl extends GenericDataType implements C
|
|||
buffer.append(pad + "\"" + comment + "\"");
|
||||
buffer.append("\n");
|
||||
}
|
||||
if (composite instanceof Structure) {
|
||||
DataTypeComponent dtc = ((Structure) composite).getFlexibleArrayComponent();
|
||||
if (dtc != null) {
|
||||
DataType dataType = dtc.getDataType();
|
||||
buffer.append(pad + dataType.getDisplayName() + "[0]");
|
||||
buffer.append(pad + dtc.getLength());
|
||||
buffer.append(pad + dtc.getFieldName());
|
||||
String comment = dtc.getComment();
|
||||
if (comment == null) {
|
||||
comment = "";
|
||||
}
|
||||
buffer.append(pad + "\"" + comment + "\"");
|
||||
buffer.append("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder stringBuffer = new StringBuilder();
|
||||
stringBuffer.append(getPathName() + "\n");
|
||||
stringBuffer.append(getAlignmentSettingsString() + "\n");
|
||||
stringBuffer.append(getTypeName() + " " + getDisplayName() + " {\n");
|
||||
dumpComponents(stringBuffer, " ");
|
||||
stringBuffer.append("}\n");
|
||||
stringBuffer.append(
|
||||
"Size = " + getLength() + " Actual Alignment = " + getAlignment() + "\n");
|
||||
return stringBuffer.toString();
|
||||
}
|
||||
|
||||
private String getTypeName() {
|
||||
if (this instanceof Structure) {
|
||||
private static String getTypeName(Composite composite) {
|
||||
if (composite instanceof Structure) {
|
||||
return "Structure";
|
||||
}
|
||||
else if (this instanceof Union) {
|
||||
else if (composite instanceof Union) {
|
||||
return "Union";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
private String getAlignmentSettingsString() {
|
||||
StringBuffer stringBuffer = new StringBuffer();
|
||||
if (!isInternallyAligned()) {
|
||||
stringBuffer.append("Unaligned");
|
||||
public static String getAlignmentAndPackingString(Composite composite) {
|
||||
StringBuilder buf =
|
||||
new StringBuilder(getMinAlignmentString(composite));
|
||||
if (buf.length() != 0) {
|
||||
buf.append(" ");
|
||||
}
|
||||
else if (isDefaultAligned()) {
|
||||
stringBuffer.append("Aligned");
|
||||
}
|
||||
else if (isMachineAligned()) {
|
||||
stringBuffer.append("Machine aligned");
|
||||
}
|
||||
else {
|
||||
long alignment = getMinimumAlignment();
|
||||
stringBuffer.append("align(" + alignment + ")");
|
||||
}
|
||||
stringBuffer.append(getPackingString());
|
||||
return stringBuffer.toString();
|
||||
buf.append(getPackingString(composite));
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
private String getPackingString() {
|
||||
if (!isInternallyAligned()) {
|
||||
public static String getMinAlignmentString(Composite composite) {
|
||||
if (composite.isDefaultAligned()) {
|
||||
return "";
|
||||
}
|
||||
if (packingValue == Composite.NOT_PACKING) {
|
||||
return "";
|
||||
StringBuilder buf = new StringBuilder(ALIGN_NAME);
|
||||
buf.append("(");
|
||||
if (composite.isMachineAligned()) {
|
||||
buf.append("machine:");
|
||||
buf.append(composite.getDataOrganization().getMachineAlignment());
|
||||
}
|
||||
return " pack(" + packingValue + ")";
|
||||
else {
|
||||
buf.append(composite.getExplicitMinimumAlignment());
|
||||
}
|
||||
buf.append(")");
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
public static String getPackingString(Composite composite) {
|
||||
StringBuilder buf = new StringBuilder(PACKING_NAME);
|
||||
buf.append("(");
|
||||
if (composite.isPackingEnabled()) {
|
||||
if (composite.hasExplicitPackingValue()) {
|
||||
buf.append(composite.getExplicitPackingValue());
|
||||
}
|
||||
else {
|
||||
buf.append(DEFAULT_PACKING_NAME);
|
||||
}
|
||||
}
|
||||
else {
|
||||
buf.append(DISABLED_PACKING_NAME); // NO_PACKING
|
||||
}
|
||||
buf.append(")");
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,154 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.program.model.data;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
/**
|
||||
* Interface for common methods in Structure and Union
|
||||
*/
|
||||
public interface CompositeInternal extends Composite {
|
||||
|
||||
/**
|
||||
* The stored packing value which corresponds to a composite that will automatically pack
|
||||
* based upon the alignment requirements of its components. A positive pack value will
|
||||
* also pack in a similar fashion but will use the pack value as a maximum alignment
|
||||
* for each component.
|
||||
* See {@link #getStoredPackingValue}.
|
||||
*/
|
||||
public final static int DEFAULT_PACKING = 0;
|
||||
|
||||
/**
|
||||
* The stored packing value which corresponds to a composite whoose packing has been disabled.
|
||||
* In the case of structures this will permit explicit component placement by
|
||||
* offset within the structure and undefined filler components will be used.
|
||||
* This is the initial state of all newly instantiated structures.
|
||||
* See {@link #getStoredPackingValue()}.
|
||||
*/
|
||||
public final static int NO_PACKING = -1;
|
||||
|
||||
/**
|
||||
* The stored minimum alignment value which indicates the default alignment
|
||||
* should be used based upon the packing and component alignment requirements.
|
||||
* See {@link #getStoredMinimumAlignment}.
|
||||
*/
|
||||
public final static int DEFAULT_ALIGNMENT = 0;
|
||||
|
||||
/**
|
||||
* The stored minimum alignment value which indicates the machine alignment
|
||||
* should be used as the minimum alignment (as defined by the current
|
||||
* {@link DataOrganization#getMachineAlignment()}).
|
||||
* See {@link #getStoredMinimumAlignment()}.
|
||||
*/
|
||||
public final static int MACHINE_ALIGNMENT = -1;
|
||||
|
||||
/**
|
||||
* Gets the current packing value (typically a power of 2). Other special values
|
||||
* which may be returned include {@value #DEFAULT_PACKING} and {@value #NO_PACKING}.
|
||||
* @return the current positive packing value, {@value #DEFAULT_PACKING} or {@value #NO_PACKING}.
|
||||
*/
|
||||
public int getStoredPackingValue();
|
||||
|
||||
/**
|
||||
* Sets the current packing behavior (positive value, usually a power of 2). If a positive
|
||||
* value is specified the use of packing will be enabled if it was previously disabled
|
||||
* (see {@link #setPackingEnabled(boolean)}. A positive value will set the maximum
|
||||
* alignment for this composite and each component within a structure
|
||||
* (e.g., a value of 1 will eliminate any padding).
|
||||
* <br>
|
||||
* Special packing values which may be specified include:
|
||||
* <ul>
|
||||
* <li>{@value #DEFAULT_PACKING} will perform default packing based upon the alignment
|
||||
* requirements of the individual components.</li>
|
||||
* <li>{@link #NO_PACKING} (or any negative value) will disable packing</li>
|
||||
* </ul>
|
||||
* @param packingValue the new positive packing value, or {@value #DEFAULT_PACKING} or
|
||||
* {@link #NO_PACKING}. A negative value will be treated the same as {@link #NO_PACKING}.
|
||||
*/
|
||||
// public void setStoredPackingValue(int packingValue);
|
||||
|
||||
/**
|
||||
* Get the minimum alignment setting for this Composite which contributes
|
||||
* to the actual computed alignment value (see {@link #getAlignment()}.
|
||||
* @return the minimum alignment setting for this Composite or a reserved value to indicate
|
||||
* either {@link #DEFAULT_ALIGNMENT} or {@link #MACHINE_ALIGNMENT}.
|
||||
*/
|
||||
public int getStoredMinimumAlignment();
|
||||
|
||||
/**
|
||||
* <code>ComponentComparator</code> provides ability to compare two DataTypeComponent objects
|
||||
* based upon their ordinal. Intended to be used to sort components based upon ordinal.
|
||||
*/
|
||||
public static class ComponentComparator implements Comparator<DataTypeComponent> {
|
||||
|
||||
public static final ComponentComparator INSTANCE = new ComponentComparator();
|
||||
|
||||
@Override
|
||||
public int compare(DataTypeComponent dtc1, DataTypeComponent dtc2) {
|
||||
return dtc1.getOrdinal() - dtc2.getOrdinal();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>OffsetComparator</code> provides ability to compare an Integer offset with a
|
||||
* DataTypeComponent object. The offset will be consider equal (0) if the component contains the
|
||||
* offset.
|
||||
*/
|
||||
public static class OffsetComparator implements Comparator<Object> {
|
||||
|
||||
public static final OffsetComparator INSTANCE = new OffsetComparator();
|
||||
|
||||
@Override
|
||||
public int compare(Object o1, Object o2) {
|
||||
if (o1 instanceof Integer) {
|
||||
return -compare(o2, o1);
|
||||
}
|
||||
DataTypeComponent dtc = (DataTypeComponent) o1;
|
||||
int offset = ((Integer) o2).intValue();
|
||||
if (offset < dtc.getOffset()) {
|
||||
return 1;
|
||||
}
|
||||
else if (offset > dtc.getEndOffset()) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>OrdinalComparator</code> provides ability to compare an Integer ordinal with a
|
||||
* DataTypeComponent object. The ordinal will be consider equal (0) if the component corresponds
|
||||
* to the specified ordinal.
|
||||
* <p>
|
||||
*/
|
||||
public static class OrdinalComparator implements Comparator<Object> {
|
||||
|
||||
public static final OrdinalComparator INSTANCE = new OrdinalComparator();
|
||||
|
||||
@Override
|
||||
public int compare(Object o1, Object o2) {
|
||||
if (o1 instanceof Integer) {
|
||||
return -compare(o2, o1);
|
||||
}
|
||||
DataTypeComponent dtc = (DataTypeComponent) o1;
|
||||
int ordinal = ((Integer) o2).intValue();
|
||||
return dtc.getOrdinal() - ordinal;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -132,11 +132,6 @@ public interface DataOrganization {
|
|||
*/
|
||||
BitFieldPacking getBitFieldPacking();
|
||||
|
||||
/**
|
||||
* Remove all entries from the size alignment map
|
||||
*/
|
||||
void clearSizeAlignmentMap();
|
||||
|
||||
/**
|
||||
* Gets the number of sizes that have an alignment specified.
|
||||
* @return the number of sizes with an alignment mapped to them.
|
||||
|
@ -161,24 +156,20 @@ public interface DataOrganization {
|
|||
|
||||
/**
|
||||
* Determines the alignment value for the indicated data type. (i.e. how the data type gets
|
||||
* aligned within other data types.) NOTE: the alignment of bitfields is dependent upon packing
|
||||
* rules which must be considered at the composite level.
|
||||
* aligned within other data types.) NOTE: this method should not be used for bitfields
|
||||
* which are highly dependent upon packing for a composite. This method will always return 1
|
||||
* for Dynamic and FactoryDataTypes.
|
||||
* @param dataType the data type
|
||||
* @param dtSize the data type's size or component size
|
||||
* @return the alignment
|
||||
* @return the datatype alignment
|
||||
*/
|
||||
int getAlignment(DataType dataType, int dtSize);
|
||||
int getAlignment(DataType dataType);
|
||||
|
||||
boolean isForcingAlignment(DataType dataType);
|
||||
|
||||
int getForcedAlignment(DataType dataType);
|
||||
|
||||
/**
|
||||
* Determines the offset where the specified data type should be placed to be properly aligned.
|
||||
* @param minimumOffset the minimum allowable offset where the data type can be placed.
|
||||
* @param dataType the data type
|
||||
* @param dtSize the data type's size
|
||||
* @return the aligned offset for the data type
|
||||
*/
|
||||
int getAlignmentOffset(int minimumOffset, DataType dataType, int dtSize);
|
||||
// /**
|
||||
// * Determines the offset where the specified data type should be placed to be properly aligned.
|
||||
// * @param minimumOffset the minimum allowable offset where the data type can be placed.
|
||||
// * @param dataType the data type
|
||||
// * @param dtSize the data type's size
|
||||
// * @return the aligned offset for the data type
|
||||
// */
|
||||
// int getAlignmentOffset(int minimumOffset, DataType dataType, int dtSize);
|
||||
}
|
||||
|
|
|
@ -15,10 +15,10 @@
|
|||
*/
|
||||
package ghidra.program.model.data;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.*;
|
||||
|
||||
import ghidra.program.model.lang.Language;
|
||||
import ghidra.util.datastruct.IntIntHashtable;
|
||||
import ghidra.util.SystemUtilities;
|
||||
import ghidra.util.exception.NoValueException;
|
||||
import ghidra.util.xml.SpecXmlUtils;
|
||||
import ghidra.xml.XmlElement;
|
||||
|
@ -56,7 +56,7 @@ public class DataOrganizationImpl implements DataOrganization {
|
|||
/*
|
||||
* Map for determining the alignment of a data type based upon its size.
|
||||
*/
|
||||
private final IntIntHashtable sizeAlignmentMap = new IntIntHashtable();
|
||||
private final HashMap<Integer, Integer> sizeAlignmentMap = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Creates a new default DataOrganization. This has a mapping which defines the alignment
|
||||
|
@ -166,7 +166,7 @@ public class DataOrganizationImpl implements DataOrganization {
|
|||
|
||||
/**
|
||||
* Set data endianess
|
||||
* @param bigEndian is true to set big endian
|
||||
* @param bigEndian true if big-endian, false if little-endian
|
||||
*/
|
||||
public void setBigEndian(boolean bigEndian) {
|
||||
this.bigEndian = bigEndian;
|
||||
|
@ -411,9 +411,8 @@ public class DataOrganizationImpl implements DataOrganization {
|
|||
/**
|
||||
* Remove all entries from the size alignment map
|
||||
*/
|
||||
@Override
|
||||
public void clearSizeAlignmentMap() {
|
||||
sizeAlignmentMap.removeAll();
|
||||
sizeAlignmentMap.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -431,7 +430,12 @@ public class DataOrganizationImpl implements DataOrganization {
|
|||
*/
|
||||
@Override
|
||||
public int[] getSizes() {
|
||||
int[] keys = sizeAlignmentMap.getKeys();
|
||||
Set<Integer> keySet = sizeAlignmentMap.keySet();
|
||||
int[] keys = new int[keySet.size()];
|
||||
int index = 0;
|
||||
for (Integer k : keySet) {
|
||||
keys[index++] = k;
|
||||
}
|
||||
Arrays.sort(keys);
|
||||
return keys;
|
||||
}
|
||||
|
@ -466,28 +470,19 @@ public class DataOrganizationImpl implements DataOrganization {
|
|||
}
|
||||
|
||||
@Override
|
||||
public int getAlignment(DataType dataType, int dtSize) {
|
||||
// Don't do alignment on dynamic data types.
|
||||
if (dataType instanceof Dynamic) {
|
||||
// throw new AssertException("Dynamic data types don't have an alignment. \"" +
|
||||
// dataType.getName() + "\" is dynamic.");
|
||||
public int getAlignment(DataType dataType) {
|
||||
int dtSize = dataType.getLength();
|
||||
if (dataType instanceof Dynamic || dataType instanceof FactoryDataType || dtSize <= 0) {
|
||||
return 1;
|
||||
}
|
||||
// Typedef is aligned the same as its underlying data type is aligned.
|
||||
if (dataType instanceof TypeDef) {
|
||||
return getAlignment(((TypeDef) dataType).getBaseDataType(), dtSize);
|
||||
return getAlignment(((TypeDef) dataType).getBaseDataType());
|
||||
}
|
||||
// Array alignment is the alignment of its element data type.
|
||||
if (dataType instanceof Array) {
|
||||
DataType elementDt = ((Array) dataType).getDataType();
|
||||
int elementLength = ((Array) dataType).getElementLength();
|
||||
return getAlignment(elementDt, elementLength);
|
||||
}
|
||||
// Pointer alignment is based on its size or default pointer alignment if there is no size????
|
||||
if (dataType instanceof Pointer) {
|
||||
if (dtSize <= 0) {
|
||||
return getDefaultPointerAlignment();
|
||||
}
|
||||
return getAlignment(elementDt);
|
||||
}
|
||||
// Structure's or Union's alignment is a multiple of the least common multiple of
|
||||
// the components. It can also be adjusted by packing and alignment attributes.
|
||||
|
@ -499,19 +494,14 @@ public class DataOrganizationImpl implements DataOrganization {
|
|||
// See AlignedStructurePacker.
|
||||
if (dataType instanceof BitFieldDataType) {
|
||||
BitFieldDataType bitfieldDt = (BitFieldDataType) dataType;
|
||||
return getAlignment(bitfieldDt.getBaseDataType(), bitfieldDt.getBaseTypeSize());
|
||||
return getAlignment(bitfieldDt.getBaseDataType());
|
||||
}
|
||||
// Otherwise get the alignment based on the size.
|
||||
if (sizeAlignmentMap.contains(dtSize)) {
|
||||
try {
|
||||
int sizeAlignment = sizeAlignmentMap.get(dtSize);
|
||||
return ((absoluteMaxAlignment == 0) || (sizeAlignment < absoluteMaxAlignment))
|
||||
? sizeAlignment
|
||||
: absoluteMaxAlignment;
|
||||
}
|
||||
catch (NoValueException e) {
|
||||
// Simply fall through to the default value.
|
||||
}
|
||||
if (sizeAlignmentMap.containsKey(dtSize)) {
|
||||
int sizeAlignment = sizeAlignmentMap.get(dtSize);
|
||||
return ((absoluteMaxAlignment == 0) || (sizeAlignment < absoluteMaxAlignment))
|
||||
? sizeAlignment
|
||||
: absoluteMaxAlignment;
|
||||
}
|
||||
if (dataType instanceof Pointer) {
|
||||
return getDefaultPointerAlignment();
|
||||
|
@ -519,114 +509,26 @@ public class DataOrganizationImpl implements DataOrganization {
|
|||
// Otherwise just assume the default alignment.
|
||||
return getDefaultAlignment();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isForcingAlignment(DataType dataType) {
|
||||
return getForcedAlignment(dataType) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getForcedAlignment(DataType dataType) {
|
||||
// Don't do forced alignment on dynamic data types.
|
||||
if (dataType instanceof Dynamic) {
|
||||
return 0;
|
||||
}
|
||||
// Typedef is aligned the same as its underlying data type is aligned.
|
||||
if (dataType instanceof TypeDef) {
|
||||
return getForcedAlignment(((TypeDef) dataType).getBaseDataType());
|
||||
}
|
||||
// Array alignment is the alignment of its element data type.
|
||||
if (dataType instanceof Array) {
|
||||
DataType elementDt = ((Array) dataType).getDataType();
|
||||
return getForcedAlignment(elementDt);
|
||||
}
|
||||
// We don't allow alignment attribute on pointers.
|
||||
if (dataType instanceof Pointer) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Structure's or Union's alignment is a multiple of the least common multiple of
|
||||
// the components. It can also be adjusted by packing and alignment attributes.
|
||||
if (dataType instanceof Composite) {
|
||||
// Check whether this composite forces the alignment.
|
||||
int forcedLCM = 0;
|
||||
Composite composite = (Composite) dataType;
|
||||
if (!composite.isInternallyAligned()) {
|
||||
return 0;
|
||||
}
|
||||
if (!composite.isDefaultAligned()) {
|
||||
int minimumAlignment = composite.getMinimumAlignment();
|
||||
forcedLCM = (minimumAlignment > 0) ? minimumAlignment : 0;
|
||||
}
|
||||
|
||||
// Check each component and get the least common multiple of their forced minimum alignments.
|
||||
int componentForcedLCM = 0;
|
||||
for (DataTypeComponent dataTypeComponent : composite.getDefinedComponents()) {
|
||||
if (dataTypeComponent.isBitFieldComponent()) {
|
||||
continue;
|
||||
}
|
||||
DataType componentDt = dataTypeComponent.getDataType();
|
||||
int forcedAlignment = getForcedAlignment(componentDt);
|
||||
if (forcedAlignment > 0) {
|
||||
if (componentForcedLCM > 0) {
|
||||
componentForcedLCM =
|
||||
getLeastCommonMultiple(componentForcedLCM, forcedAlignment);
|
||||
}
|
||||
else {
|
||||
componentForcedLCM = forcedAlignment;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (forcedLCM > 0) {
|
||||
if (componentForcedLCM > 0) {
|
||||
// Both this composite and one or more of its children force the alignment.
|
||||
return getLeastCommonMultiple(forcedLCM, componentForcedLCM);
|
||||
}
|
||||
// Children don't force alignment but this composite does.
|
||||
return forcedLCM;
|
||||
}
|
||||
// This composite's forced alignment is based only on its children's forced alignments.
|
||||
return componentForcedLCM;
|
||||
}
|
||||
// Otherwise not forcing alignment.
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the offset where the specified data type should be placed to be properly aligned.
|
||||
* @param minimumOffset the minimum allowable offset where the data type can be placed.
|
||||
* @param dataType the data type
|
||||
* @param dtSize the data type's size
|
||||
* @return the aligned offset for the data type
|
||||
*/
|
||||
@Override
|
||||
public int getAlignmentOffset(int minimumOffset, DataType dataType, int dtSize) {
|
||||
int alignment = getAlignment(dataType, dtSize);
|
||||
return getOffset(alignment, minimumOffset);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determines the first offset that is equal to or greater than the minimum offset which
|
||||
* has the specified alignment.
|
||||
* @param alignment the desired alignment
|
||||
* has the specified alignment. If a non-positive alignment is specified the origina
|
||||
* minimumOffset will be return.
|
||||
* @param alignment the desired alignment (positive value)
|
||||
* @param minimumOffset the minimum offset
|
||||
* @return the aligned offset
|
||||
*/
|
||||
public static int getOffset(int alignment, int minimumOffset) {
|
||||
return alignment + ((minimumOffset - 1) & ~(alignment - 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the amount of padding that should be added to a structure at the indicated
|
||||
* offset in order to get the next component (member) to be aligned with the specified
|
||||
* alignment within the structure.
|
||||
* @param alignment the desired alignment
|
||||
* @param offset the offset that the padding would be placed at to achieve the desired alignment.
|
||||
* @return the padding needed at the offset.
|
||||
*/
|
||||
public static int getPaddingSize(int alignment, int offset) {
|
||||
return (alignment - (offset % alignment)) % alignment;
|
||||
public static int getAlignedOffset(int alignment, int minimumOffset) {
|
||||
if (alignment <= 0) {
|
||||
return minimumOffset;
|
||||
}
|
||||
if ((alignment & 1) == 0) {
|
||||
// handle alignment which is a power-of-2
|
||||
return alignment + ((minimumOffset - 1) & ~(alignment - 1));
|
||||
}
|
||||
int offcut = (minimumOffset % alignment);
|
||||
int adj = (offcut != 0) ? (alignment - offcut) : 0;
|
||||
return minimumOffset + adj;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -731,17 +633,10 @@ public class DataOrganizationImpl implements DataOrganization {
|
|||
buffer.append("/>\n");
|
||||
}
|
||||
if (sizeAlignmentMap.size() != 0) {
|
||||
int[] keys = sizeAlignmentMap.getKeys();
|
||||
buffer.append("<size_alignment_map>\n");
|
||||
for (int key : keys) {
|
||||
for (int key : sizeAlignmentMap.keySet()) {
|
||||
buffer.append("<entry");
|
||||
int value;
|
||||
try {
|
||||
value = sizeAlignmentMap.get(key);
|
||||
}
|
||||
catch (NoValueException e) {
|
||||
value = 0;
|
||||
}
|
||||
int value = sizeAlignmentMap.get(key);
|
||||
SpecXmlUtils.encodeSignedIntegerAttribute(buffer, "size", key);
|
||||
SpecXmlUtils.encodeSignedIntegerAttribute(buffer, "alignment", value);
|
||||
buffer.append("/>\n");
|
||||
|
@ -884,21 +779,16 @@ public class DataOrganizationImpl implements DataOrganization {
|
|||
if (pointerSize != op2.pointerSize || pointerShift != op2.pointerShift) {
|
||||
return false;
|
||||
}
|
||||
int[] keys = sizeAlignmentMap.getKeys();
|
||||
int[] op2keys = op2.sizeAlignmentMap.getKeys();
|
||||
if (keys.length != op2keys.length) {
|
||||
Set<Integer> keys = sizeAlignmentMap.keySet();
|
||||
Set<Integer> op2keys = op2.sizeAlignmentMap.keySet();
|
||||
if (keys.size() != op2keys.size()) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
for (int i = 0; i < keys.length; ++i) {
|
||||
if (sizeAlignmentMap.get(keys[i]) != op2.sizeAlignmentMap.get(op2keys[i])) {
|
||||
return false;
|
||||
}
|
||||
for (int k : keys) {
|
||||
if (!SystemUtilities.isEqual(sizeAlignmentMap.get(k), op2.sizeAlignmentMap.get(k))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (NoValueException ex) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -922,14 +812,8 @@ public class DataOrganizationImpl implements DataOrganization {
|
|||
hash = 79 * hash + pointerSize;
|
||||
hash = 79 * hash + shortSize;
|
||||
hash = 79 * hash + wideCharSize;
|
||||
int[] keys = sizeAlignmentMap.getKeys();
|
||||
try {
|
||||
for (int key : keys) {
|
||||
hash = 79 * hash + sizeAlignmentMap.get(key);
|
||||
}
|
||||
}
|
||||
catch (NoValueException ex) {
|
||||
hash = 0;
|
||||
for (int k : sizeAlignmentMap.keySet()) {
|
||||
hash = 79 * hash + sizeAlignmentMap.get(k);
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
|
|
@ -64,16 +64,20 @@ public interface DataType {
|
|||
public Settings getDefaultSettings();
|
||||
|
||||
/**
|
||||
* Returns a new instance of this DataType with its universalID and SourceArchive identity retained.
|
||||
* Note: for built-in DataType's, clone and copy should have the same affect.
|
||||
* Returns an instance of this DataType with its universalID and SourceArchive identity retained.
|
||||
* The current instanceof will be returned if this datatype's DataTypeManager matches
|
||||
* the specified dtm. The recursion depth of a clone will stop on any datatype whose
|
||||
* DataTypeManager matches the specified dtm and simply use the existing datatype instance.
|
||||
* @param dtm the data-type manager instance whose data-organization should apply.
|
||||
* @return cloned instance which may be the same as this instance
|
||||
*/
|
||||
public DataType clone(DataTypeManager dtm);
|
||||
|
||||
/**
|
||||
* Returns a new instance of this DataType with a new identity.
|
||||
* Note: for built-in DataType's, clone and copy should have the same affect.
|
||||
* Returns a new instance (shallow copy) of this DataType with a new identity.
|
||||
* Any reference to other datatypes will use {@link #clone(DataTypeManager)}.
|
||||
* @param dtm the data-type manager instance whose data-organization should apply.
|
||||
* @return new instanceof of this datatype
|
||||
*/
|
||||
public DataType copy(DataTypeManager dtm);
|
||||
|
||||
|
@ -91,12 +95,14 @@ public interface DataType {
|
|||
|
||||
/**
|
||||
* @param path set the categoryPath associated with this data type
|
||||
* @throws DuplicateNameException
|
||||
* @throws DuplicateNameException if an attempt to place this datatype into the
|
||||
* specified category resulted in a name collision. This should not occur for non-DB
|
||||
* DataType instances.
|
||||
*/
|
||||
public void setCategoryPath(CategoryPath path) throws DuplicateNameException;
|
||||
|
||||
/**
|
||||
* Returns the DataTypeManager that is associated with this dataType.
|
||||
* @return the DataTypeManager that is associated with this dataType.
|
||||
* This association should not be used to indicate whether this DataType has been
|
||||
* resolved, but is intended to indicate whether the appropriate DataOrganization
|
||||
* is being used.
|
||||
|
@ -110,13 +116,13 @@ public interface DataType {
|
|||
public String getDisplayName();
|
||||
|
||||
/**
|
||||
* Return that name of the data type
|
||||
* @return the name of this data type
|
||||
*/
|
||||
public String getName();
|
||||
|
||||
/**
|
||||
* Returns the full category path name that includes this dataType's name. If
|
||||
* the category is null, then this just returns the dataType's name.
|
||||
* @return the full category path name that includes this dataType's name. If
|
||||
* the category is null, then this just the dataType's name is returned.
|
||||
*/
|
||||
public String getPathName();
|
||||
|
||||
|
@ -144,7 +150,7 @@ public interface DataType {
|
|||
|
||||
/**
|
||||
* Get the mnemonic for this DataType.
|
||||
*
|
||||
* @param settings settings which may influence the result or null
|
||||
* @return the mnemonic for this DataType.
|
||||
*/
|
||||
public String getMnemonic(Settings settings);
|
||||
|
@ -155,6 +161,17 @@ public interface DataType {
|
|||
*/
|
||||
public int getLength();
|
||||
|
||||
/**
|
||||
* Indicates is this datatype is defined with a zero length.
|
||||
* This method should not be confused with {@link #isNotYetDefined()}
|
||||
* which indicates that nothing but the name and basic type is known.
|
||||
* NOTE: Support for zero-length datatypes is not yet fully supported, as a result
|
||||
* they will generally return a non-zero length.
|
||||
* @return true if type definition has a length of 0 even though it may report
|
||||
* a length of 1, else false.
|
||||
*/
|
||||
public boolean isZeroLength();
|
||||
|
||||
/**
|
||||
* Get a String briefly describing this DataType.
|
||||
*
|
||||
|
@ -240,7 +257,7 @@ public interface DataType {
|
|||
* @param settings the Settings object
|
||||
* @param len the length of the data.
|
||||
* @param options options for how to format the default label prefix.
|
||||
* @param offcutOffset
|
||||
* @param offcutOffset offset into datatype
|
||||
* @return the default label prefix.
|
||||
*/
|
||||
public String getDefaultOffcutLabelPrefix(MemBuffer buf, Settings settings, int len,
|
||||
|
@ -277,18 +294,26 @@ public interface DataType {
|
|||
* Notification that the given dataType's size has changed. DataTypes may
|
||||
* need to make internal changes in response.
|
||||
* <br>
|
||||
* TODO: This method is reserved for internal DB use and should be removed
|
||||
* from the public DataType interface!!
|
||||
* TODO: This method is reserved for internal DB use.
|
||||
* <br>
|
||||
* @param dt the dataType that has changed.
|
||||
*/
|
||||
public void dataTypeSizeChanged(DataType dt);
|
||||
|
||||
/**
|
||||
* Notification that the given dataType's alignment has changed. DataTypes may
|
||||
* need to make internal changes in response.
|
||||
* <br>
|
||||
* TODO: This method is reserved for internal DB use.
|
||||
* <br>
|
||||
* @param dt the dataType that has changed.
|
||||
*/
|
||||
public void dataTypeAlignmentChanged(DataType dt);
|
||||
|
||||
/**
|
||||
* Informs this dataType that the given dataType has been deleted.
|
||||
* <br>
|
||||
* TODO: This method is reserved for internal DB use and should be removed
|
||||
* from the public DataType interface!!
|
||||
* TODO: This method is reserved for internal DB use.
|
||||
* <br>
|
||||
* @param dt the dataType that has been deleted.
|
||||
*/
|
||||
|
@ -297,8 +322,7 @@ public interface DataType {
|
|||
/**
|
||||
* Informs this data type that the given oldDT has been replaced with newDT
|
||||
* <br>
|
||||
* TODO: This method is reserved for internal DB use and should be removed
|
||||
* from the public DataType interface!!
|
||||
* TODO: This method is reserved for internal DB use.
|
||||
* <br>
|
||||
* @param oldDt old data type
|
||||
* @param newDt new data type
|
||||
|
@ -308,8 +332,7 @@ public interface DataType {
|
|||
/**
|
||||
* Set the default settings for this data type.
|
||||
* <br>
|
||||
* TODO: This method is reserved for internal DB use and should be removed
|
||||
* from the public DataType interface!!
|
||||
* TODO: This method is reserved for internal DB use.
|
||||
* <br>
|
||||
* @param settings the settings to be used as this dataTypes default settings.
|
||||
*/
|
||||
|
@ -318,8 +341,7 @@ public interface DataType {
|
|||
/**
|
||||
* Inform this data type that it has the given parent
|
||||
* <br>
|
||||
* TODO: This method is reserved for internal DB use and should be removed
|
||||
* from the public DataType interface!!
|
||||
* TODO: This method is reserved for internal DB use.
|
||||
* <br>
|
||||
* @param dt parent data type
|
||||
*/
|
||||
|
@ -328,8 +350,7 @@ public interface DataType {
|
|||
/**
|
||||
* Remove a parent data type
|
||||
* <br>
|
||||
* TODO: This method is reserved for internal DB use and should be removed
|
||||
* from the public DataType interface!!
|
||||
* TODO: This method is reserved for internal DB use.
|
||||
* <br>
|
||||
* @param dt parent data type
|
||||
*/
|
||||
|
@ -338,8 +359,7 @@ public interface DataType {
|
|||
/**
|
||||
* Informs this data type that its name has changed from the indicated old name.
|
||||
* <br>
|
||||
* TODO: This method is reserved for internal DB use and should be removed
|
||||
* from the public DataType interface!!
|
||||
* TODO: This method is reserved for internal DB use.
|
||||
* <br>
|
||||
* @param dt the data type whose name changed
|
||||
* @param oldName the data type's old name
|
||||
|
@ -362,6 +382,8 @@ public interface DataType {
|
|||
* For example byte[] depends on byte. If byte were deleted, then byte[] would
|
||||
* also be deleted.
|
||||
* @param dt the dataType to test that this dataType depends on.
|
||||
* @return true if the existence of this datatype relies on the existence
|
||||
* of the specified datatype dt.
|
||||
*/
|
||||
public boolean dependsOn(DataType dt);
|
||||
|
||||
|
|
|
@ -107,7 +107,7 @@ public class DataTypeComponentImpl implements InternalDataTypeComponent, Seriali
|
|||
@Override
|
||||
public int getOffset() {
|
||||
if (isFlexibleArrayComponent) {
|
||||
if (parent.isNotYetDefined()) {
|
||||
if (parent.isZeroLength()) {
|
||||
// some structures have only a flexible array defined
|
||||
return 0;
|
||||
}
|
||||
|
@ -179,7 +179,7 @@ public class DataTypeComponentImpl implements InternalDataTypeComponent, Seriali
|
|||
if (parent == null) {
|
||||
return; // Bad situation
|
||||
}
|
||||
for (DataTypeComponent comp : parent.getComponents()) {
|
||||
for (DataTypeComponent comp : parent.getDefinedComponents()) {
|
||||
if (comp != this && name.equals(comp.getFieldName())) {
|
||||
throw new DuplicateNameException("Duplicate field name: " + name);
|
||||
}
|
||||
|
@ -328,7 +328,7 @@ public class DataTypeComponentImpl implements InternalDataTypeComponent, Seriali
|
|||
DataType otherDt = dtc.getDataType();
|
||||
DataType myParent = getParent();
|
||||
boolean aligned =
|
||||
(myParent instanceof Composite) ? ((Composite) myParent).isInternallyAligned() : false;
|
||||
(myParent instanceof Composite) ? ((Composite) myParent).isPackingEnabled() : false;
|
||||
// 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
|
||||
|
|
|
@ -15,8 +15,9 @@
|
|||
*/
|
||||
package ghidra.program.model.data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import javax.swing.event.ChangeEvent;
|
||||
import javax.swing.event.ChangeListener;
|
||||
|
@ -31,7 +32,7 @@ public abstract class DataTypeImpl extends AbstractDataType implements ChangeLis
|
|||
|
||||
private final static SettingsDefinition[] EMPTY_DEFINITIONS = new SettingsDefinition[0];
|
||||
protected Settings defaultSettings;
|
||||
private ArrayList<DataType> parentList;
|
||||
private List<WeakReference<DataType>> parentList;
|
||||
private UniversalID universalID;
|
||||
private SourceArchive sourceArchive;
|
||||
private long lastChangeTime;
|
||||
|
@ -102,59 +103,78 @@ public abstract class DataTypeImpl extends AbstractDataType implements ChangeLis
|
|||
if (length < 0) {
|
||||
return 1;
|
||||
}
|
||||
return getDataOrganization().getAlignment(this, length);
|
||||
return getDataOrganization().getAlignment(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addParent(DataType dt) {
|
||||
parentList.add(dt);
|
||||
parentList.add(new WeakReference<>(dt));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeParent(DataType dt) {
|
||||
parentList.remove(dt);
|
||||
Iterator<WeakReference<DataType>> iterator = parentList.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
WeakReference<DataType> ref = iterator.next();
|
||||
DataType dataType = ref.get();
|
||||
if (dataType == null) {
|
||||
iterator.remove();
|
||||
}
|
||||
else if (dt == dataType) {
|
||||
iterator.remove();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType[] getParents() {
|
||||
DataType[] dts = new DataType[parentList.size()];
|
||||
return parentList.toArray(dts);
|
||||
|
||||
List<DataType> parents = new ArrayList<>();
|
||||
Iterator<WeakReference<DataType>> iterator = parentList.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
WeakReference<DataType> ref = iterator.next();
|
||||
DataType dataType = ref.get();
|
||||
if (dataType == null) {
|
||||
iterator.remove();
|
||||
}
|
||||
else {
|
||||
parents.add(dataType);
|
||||
}
|
||||
}
|
||||
DataType[] array = new DataType[parents.size()];
|
||||
return parents.toArray(array);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify any parent data types that my size has changed.
|
||||
* Notify all parents that the size of this datatype has changed or
|
||||
* other significant change that may affect a parent containing this
|
||||
* datatype.
|
||||
*/
|
||||
protected void notifySizeChanged() {
|
||||
Iterator<DataType> it = parentList.iterator();
|
||||
while (it.hasNext()) {
|
||||
DataType dt = it.next();
|
||||
dt.dataTypeSizeChanged(this);
|
||||
}
|
||||
notifyParents(dt -> dt.dataTypeSizeChanged(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify any parents that my name has changed.
|
||||
* Notify all parents that this datatype's alignment has changed
|
||||
*/
|
||||
protected void notifyAlignmentChanged() {
|
||||
notifyParents(dt -> dt.dataTypeAlignmentChanged(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify all parents that this datatype's name has changed
|
||||
*
|
||||
* @param oldName
|
||||
*/
|
||||
protected void notifyNameChanged(String oldName) {
|
||||
Iterator<DataType> it = parentList.iterator();
|
||||
while (it.hasNext()) {
|
||||
DataType dt = it.next();
|
||||
dt.dataTypeNameChanged(this, oldName);
|
||||
}
|
||||
notifyParents(dt -> dt.dataTypeNameChanged(this, oldName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify any parents that I am deleted.
|
||||
* Notify all parents that this datatype has been deleted
|
||||
*/
|
||||
protected void notifyDeleted() {
|
||||
Iterator<DataType> it = parentList.iterator();
|
||||
while (it.hasNext()) {
|
||||
DataType dt = it.next();
|
||||
dt.dataTypeDeleted(this);
|
||||
}
|
||||
notifyParents(dt -> dt.dataTypeDeleted(this));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -162,10 +182,20 @@ public abstract class DataTypeImpl extends AbstractDataType implements ChangeLis
|
|||
* @param replacement replacement data type
|
||||
*/
|
||||
protected void notifyReplaced(DataType replacement) {
|
||||
Iterator<DataType> it = parentList.iterator();
|
||||
while (it.hasNext()) {
|
||||
DataType dt = it.next();
|
||||
dt.dataTypeReplaced(this, replacement);
|
||||
notifyParents(dt -> dt.dataTypeReplaced(this, replacement));
|
||||
}
|
||||
|
||||
protected final void notifyParents(Consumer<DataType> consumer) {
|
||||
Iterator<WeakReference<DataType>> iterator = parentList.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
WeakReference<DataType> ref = iterator.next();
|
||||
DataType dataType = ref.get();
|
||||
if (dataType == null) {
|
||||
iterator.remove();
|
||||
}
|
||||
else {
|
||||
consumer.accept(dataType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -249,8 +249,10 @@ public interface DataTypeManager {
|
|||
/**
|
||||
* Notification when data type is changed.
|
||||
* @param dataType data type that is changed
|
||||
* @param isAutoChange true if change was an automatic change in response to
|
||||
* another datatype's change (e.g., size, alignment).
|
||||
*/
|
||||
public void dataTypeChanged(DataType dataType);
|
||||
public void dataTypeChanged(DataType dataType, boolean isAutoChange);
|
||||
|
||||
/**
|
||||
* Add a listener that is notified when the dataTypeManger changes.
|
||||
|
|
|
@ -383,37 +383,12 @@ public class EnumDataType extends GenericDataType implements Enum {
|
|||
valueMap = new HashMap<>();
|
||||
setLength(enumm.getLength());
|
||||
String[] names = enumm.getNames();
|
||||
for (int i = 0; i < names.length; i++) {
|
||||
add(names[i], enumm.getValue(names[i]));
|
||||
for (String name2 : names) {
|
||||
add(name2, enumm.getValue(name2));
|
||||
}
|
||||
stateChanged(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dataTypeSizeChanged(DataType dt) {
|
||||
// not applicable
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dataTypeDeleted(DataType dt) {
|
||||
// not applicable
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dataTypeNameChanged(DataType dt, String oldName) {
|
||||
// not applicable
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dataTypeReplaced(DataType oldDt, DataType newDt) {
|
||||
// not applicable
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dependsOn(DataType dt) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDefaultLabelPrefix() {
|
||||
return name == null ? null : name.toUpperCase();
|
||||
|
|
|
@ -24,8 +24,6 @@ import ghidra.util.exception.DuplicateNameException;
|
|||
*/
|
||||
public abstract class GenericDataType extends DataTypeImpl {
|
||||
|
||||
protected boolean packed = false;
|
||||
|
||||
protected GenericDataType(CategoryPath path, String name, DataTypeManager dataMgr) {
|
||||
super(path, name, dataMgr);
|
||||
if (!DataUtilities.isValidDataTypeName(name)) {
|
||||
|
@ -72,8 +70,9 @@ public abstract class GenericDataType extends DataTypeImpl {
|
|||
}
|
||||
|
||||
private void doSetCategoryPath(CategoryPath path) {
|
||||
if (path == null)
|
||||
if (path == null) {
|
||||
path = CategoryPath.ROOT;
|
||||
}
|
||||
categoryPath = path;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.program.model.data;
|
||||
|
||||
/**
|
||||
* <code>PackingType</code> specifies the pack setting which applies to a composite data type.
|
||||
* This can be DISABLED, DEFAULT, EXPLICIT.
|
||||
*/
|
||||
public enum PackingType {
|
||||
/**
|
||||
* <B>DISABLED</B> - indicates that automatic component placement should not be performed, with
|
||||
* components placed at specified offsets and <code>undefined</code> components used to
|
||||
* reflects padding/unused bytes. This mode is commonly used when reverse-engineering a
|
||||
* composite since a complete and accurate definition may not be known.
|
||||
*/
|
||||
DISABLED,
|
||||
/**
|
||||
* <B>DEFAULT</B> - indicates that components should be placed automatically based upon
|
||||
* their alignment. This is intended to reflect the default behavior of a compiler
|
||||
* when a complete definition of a composite is known as well as the alignment of each
|
||||
* component.
|
||||
*/
|
||||
DEFAULT,
|
||||
/**
|
||||
* <B>EXPLICIT</B> - indicates an explicit pack value has been specified and that components
|
||||
* should be placed automatically based upon their alignment, not to exceed the pack value.
|
||||
*/
|
||||
EXPLICIT;
|
||||
}
|
|
@ -248,7 +248,7 @@ public class ReadOnlyDataTypeComponent implements DataTypeComponent, Serializabl
|
|||
int otherLength = dtc.getLength();
|
||||
DataType myParent = getParent();
|
||||
boolean aligned =
|
||||
(myParent instanceof Composite) ? ((Composite) myParent).isInternallyAligned() : false;
|
||||
(myParent instanceof Composite) ? ((Composite) myParent).isPackingEnabled() : false;
|
||||
// Components don't need to have matching offset when they are aligned, only matching ordinal.
|
||||
if ((!aligned && (offset != dtc.getOffset())) ||
|
||||
// Components don't need to have matching length when they are aligned. Is this correct?
|
||||
|
|
|
@ -23,14 +23,14 @@ import java.util.Comparator;
|
|||
* NOTE: Structures containing only a flexible array will report a length of 1 which will result in
|
||||
* improper code unit sizing since we are unable to support a defined data of length 0.
|
||||
* <p>
|
||||
* NOTE: The use of zero-length bitfields within unaligned structures is discouraged since they have
|
||||
* no real affect and are easily misplaced. Their use should be reserved for aligned/packed
|
||||
* NOTE: The use of zero-length bitfields within non-packed structures is discouraged since they have
|
||||
* no real affect and are easily misplaced. Their use should be reserved for packed
|
||||
* structures.
|
||||
*/
|
||||
public interface Structure extends Composite {
|
||||
|
||||
@Override
|
||||
Structure clone(DataTypeManager dtm);
|
||||
public Structure clone(DataTypeManager dtm);
|
||||
|
||||
/**
|
||||
* Returns the component of this structure with the indicated ordinal. If the specified ordinal
|
||||
|
@ -39,12 +39,12 @@ public interface Structure extends Composite {
|
|||
* {@link #getFlexibleArrayComponent()} is preferred for obtaining this special trailing
|
||||
* component.
|
||||
*
|
||||
* @param ordinal the component's ordinal (zero based).
|
||||
* @param ordinal the ordinal of the component requested.
|
||||
* @return the data type component.
|
||||
* @throws ArrayIndexOutOfBoundsException if the ordinal is out of bounds
|
||||
* @throws IndexOutOfBoundsException if the ordinal is out of bounds
|
||||
*/
|
||||
@Override
|
||||
public abstract DataTypeComponent getComponent(int ordinal);
|
||||
public abstract DataTypeComponent getComponent(int ordinal) throws IndexOutOfBoundsException;
|
||||
|
||||
/**
|
||||
* Gets the immediate child component that contains the byte at the given offset. If the
|
||||
|
@ -68,23 +68,23 @@ public interface Structure extends Composite {
|
|||
public abstract DataTypeComponent getDataTypeAt(int offset);
|
||||
|
||||
/**
|
||||
* Inserts a new bitfield at the specified ordinal position in this structure. Within aligned
|
||||
* Inserts a new bitfield at the specified ordinal position in this structure. Within packed
|
||||
* structures the specified byteWidth and bitOffset will be ignored since packing will occur at
|
||||
* the specified ordinal position. The resulting component length and bitfield details will
|
||||
* reflect the use of minimal storage sizing.
|
||||
* <p>
|
||||
* For unaligned structures, a component shift will only occur if the bitfield placement
|
||||
* For structures with packing disabled, a component shift will only occur if the bitfield placement
|
||||
* conflicts with another component. If no conflict occurs, the bitfield will be placed at the
|
||||
* specified location consuming any DEFAULT components as needed. When a conflict does occur a
|
||||
* shift will be performed at the ordinal position based upon the specified byteWidth. When
|
||||
* located onto existing bitfields they will be packed together provided they do not conflict,
|
||||
* otherwise the conflict rule above applies.
|
||||
* <p>
|
||||
* Supported aligned packing starts with bit-0 (lsb) of the first byte for little-endian, and
|
||||
* Supported packing starts with bit-0 (lsb) of the first byte for little-endian, and
|
||||
* with bit-7 (msb) of the first byte for big-endian. This is the default behavior for most
|
||||
* compilers. Insertion behavior may not work as expected if packing rules differ from this.
|
||||
*
|
||||
* @param ordinal the ordinal where the new datatype is to be inserted.
|
||||
* @param ordinal the ordinal of the component to be inserted.
|
||||
* @param byteWidth the storage allocation unit width which contains the bitfield. Must be large
|
||||
* enough to contain the "effective bit size" and corresponding bitOffset. The actual
|
||||
* component size used will be recomputed during insertion.
|
||||
|
@ -99,22 +99,22 @@ public interface Structure extends Composite {
|
|||
* @return the bitfield component created whose associated data type will be BitFieldDataType.
|
||||
* @throws InvalidDataTypeException if the specified baseDataType is not a valid base type for
|
||||
* bitfields.
|
||||
* @throws ArrayIndexOutOfBoundsException if ordinal is less than 0 or greater than the current
|
||||
* @throws IndexOutOfBoundsException if ordinal is less than 0 or greater than the current
|
||||
* number of components.
|
||||
*/
|
||||
public DataTypeComponent insertBitField(int ordinal, int byteWidth, int bitOffset,
|
||||
DataType baseDataType, int bitSize, String componentName, String comment)
|
||||
throws InvalidDataTypeException, ArrayIndexOutOfBoundsException;
|
||||
throws InvalidDataTypeException, IndexOutOfBoundsException;
|
||||
|
||||
/**
|
||||
* Inserts a new bitfield at the specified location in this composite. This method is intended
|
||||
* to be used with unaligned structures where the bitfield will be precisely placed. Within an
|
||||
* aligned structure the specified byteOffset, byteWidth and bitOffset will be used to identify
|
||||
* to be used with structures with packing disabled where the bitfield will be precisely placed. Within an
|
||||
* packed structure the specified byteOffset, byteWidth and bitOffset will be used to identify
|
||||
* the appropriate ordinal but may not be preserved. The component length will be computed based
|
||||
* upon the specified parameters and will be reduced from byteWidth to its minimal size for the
|
||||
* new component.
|
||||
* <p>
|
||||
* For unaligned mode, a component shift will only occur if the bitfield placement conflicts
|
||||
* When packing disabled, a component shift will only occur if the bitfield placement conflicts
|
||||
* with another component. If no conflict occurs, the bitfield will be placed at the specified
|
||||
* location consuming any DEFAULT components as needed. When a conflict does occur a shift will
|
||||
* be performed at the point of conflict based upon the specified byteWidth. When located onto
|
||||
|
@ -125,8 +125,8 @@ public interface Structure extends Composite {
|
|||
* Insertion behavior may not work as expected if packing rules differ from this.
|
||||
* <p>
|
||||
*
|
||||
* Zero length bitfields may be inserted although they have no real affect for unaligned
|
||||
* structures. Only the resulting byte offset within the structure is of significance in
|
||||
* Zero length bitfields may be inserted although they have no real affect when packing disabled.
|
||||
* Only the resulting byte offset within the structure is of significance in
|
||||
* determining its ordinal placement.
|
||||
* <p>
|
||||
*
|
||||
|
@ -200,67 +200,69 @@ public interface Structure extends Composite {
|
|||
|
||||
/**
|
||||
* Remove all components from this structure (including flex-array), effectively setting the
|
||||
* length to zero.
|
||||
* length to zero. Packing and minimum alignment settings are unaffected.
|
||||
*/
|
||||
public void deleteAll();
|
||||
|
||||
/**
|
||||
* Clears the defined component at the given component index. Clearing a component causes a
|
||||
* defined component to be replaced with a number of undefined dataTypes to offset the removal
|
||||
* of the defined dataType.
|
||||
* Clears the defined component at the given component ordinal. Clearing a component within
|
||||
* a non-packed structure causes a defined component to be replaced with a number of undefined
|
||||
* dataTypes to offset the removal of the defined dataType. In the case of a packed
|
||||
* structure the component is deleted without backfill.
|
||||
*
|
||||
* @param index the index of the component to clear.
|
||||
* @throws ArrayIndexOutOfBoundsException if component ordinal is out of bounds
|
||||
* @param ordinal the ordinal of the component to clear.
|
||||
* @throws IndexOutOfBoundsException if component ordinal is out of bounds
|
||||
*/
|
||||
public void clearComponent(int index) throws ArrayIndexOutOfBoundsException;
|
||||
public void clearComponent(int ordinal) throws IndexOutOfBoundsException;
|
||||
|
||||
/**
|
||||
* Replaces the component at the given component index with a new component of the indicated
|
||||
* Replaces the component at the given component ordinal with a new component of the indicated
|
||||
* data type.
|
||||
*
|
||||
* @param index the index where the datatype is to be replaced.
|
||||
* @param ordinal the ordinal of the component to be replaced.
|
||||
* @param dataType the datatype to insert.
|
||||
* @param length the length of the dataType to insert. For fixed length types a length <= 0
|
||||
* will use the length of the resolved dataType.
|
||||
* @return the new componentDataType at the index.
|
||||
* @return the new component
|
||||
* @throws IllegalArgumentException if the specified data type is not allowed to replace a
|
||||
* component in this composite data type or an invalid length is specified. For
|
||||
* example, suppose dt1 contains dt2. Therefore it is not valid to replace a dt2
|
||||
* component with dt1 since this would cause a cyclic dependency. In addition, any
|
||||
* attempt to replace an existing bit-field component or specify a
|
||||
* {@link BitFieldDataType} will produce this error.
|
||||
* @throws ArrayIndexOutOfBoundsException if component index is out of bounds
|
||||
* @throws IndexOutOfBoundsException if component ordinal is out of bounds
|
||||
*/
|
||||
public DataTypeComponent replace(int index, DataType dataType, int length)
|
||||
throws ArrayIndexOutOfBoundsException, IllegalArgumentException;
|
||||
public DataTypeComponent replace(int ordinal, DataType dataType, int length)
|
||||
throws IndexOutOfBoundsException, IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Replaces the component at the given component index with a new component of the indicated
|
||||
* Replaces the component at the given component ordinal with a new component of the indicated
|
||||
* data type.
|
||||
*
|
||||
* @param index the index where the datatype is to be replaced.
|
||||
* @param ordinal the ordinal of the component to be replaced.
|
||||
* @param dataType the datatype to insert.
|
||||
* @param length the length to associate with the dataType. For fixed length types a length
|
||||
* <= 0 will use the length of the resolved dataType.
|
||||
* @param name the field name to associate with this component.
|
||||
* @param comment the comment to associate with this component.
|
||||
* @return the new componentDataType at the index.
|
||||
* @return the new component.
|
||||
* @throws IllegalArgumentException if the specified data type is not allowed to replace a
|
||||
* component in this composite data type or an invalid length is specified. For
|
||||
* example, suppose dt1 contains dt2. Therefore it is not valid to replace a dt2
|
||||
* component with dt1 since this would cause a cyclic dependency. In addition, any
|
||||
* attempt to replace an existing bit-field component or specify a
|
||||
* {@link BitFieldDataType} will produce this error.
|
||||
* @throws ArrayIndexOutOfBoundsException if component index is out of bounds
|
||||
* @throws IndexOutOfBoundsException if component ordinal is out of bounds
|
||||
*/
|
||||
public DataTypeComponent replace(int index, DataType dataType, int length, String name,
|
||||
String comment) throws ArrayIndexOutOfBoundsException, IllegalArgumentException;
|
||||
public DataTypeComponent replace(int ordinal, DataType dataType, int length, String name,
|
||||
String comment) throws IndexOutOfBoundsException, IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Replaces the component at the specified byte offset with a new component of the indicated
|
||||
* data type. If the offset corresponds to a bit-field, all bit-fields at that offset will be
|
||||
* removed and replaced by the specified component. Keep in mind bit-field or any component
|
||||
* removal must clear sufficient space for an unaligned structure to complete the replacement.
|
||||
* removal must clear sufficient space in a structure with packing disabled to complete
|
||||
* the replacement.
|
||||
*
|
||||
* @param offset the byte offset into the structure where the datatype is to be replaced.
|
||||
* @param dataType the datatype to insert.
|
||||
|
@ -268,7 +270,7 @@ public interface Structure extends Composite {
|
|||
* <= 0 will use the length of the resolved dataType.
|
||||
* @param name the field name to associate with this component.
|
||||
* @param comment the comment to associate with this component.
|
||||
* @return the new componentDataType at the index.
|
||||
* @return the new component.
|
||||
* @throws IllegalArgumentException if the specified data type is not allowed to replace a
|
||||
* component in this composite data type or an invalid length is specified. For
|
||||
* example, suppose dt1 contains dt2. Therefore it is not valid to replace a dt2
|
||||
|
@ -288,6 +290,12 @@ public interface Structure extends Composite {
|
|||
|
||||
/**
|
||||
* Get the optional trailing flexible array component associated with this structure.
|
||||
* <p>
|
||||
* NOTE: The trailing flexable array may be assigned an incorrect offset
|
||||
* when packing is enabled and the minimum alignment is specified. In such cases,
|
||||
* the flex array may be less than the overall structure length. Currently, it is
|
||||
* assumed the trailing flex array will have an offset equal to the overall
|
||||
* structure length.
|
||||
*
|
||||
* @return optional trailing flexible array component associated with this structure or null if
|
||||
* not present.
|
||||
|
@ -314,25 +322,14 @@ public interface Structure extends Composite {
|
|||
public void clearFlexibleArrayComponent();
|
||||
|
||||
/**
|
||||
* Increases the size of the structure by the given amount by adding undefined datatypes at the
|
||||
* end of the structure.
|
||||
* Increases the size of the structure by the given amount by adding undefined filler at the
|
||||
* end of the structure. NOTE: This method only has an affect on structures with packing disabled.
|
||||
*
|
||||
* @param amount the amount by which to grow the structure.
|
||||
* @throws IllegalArgumentException if amount < 1
|
||||
*/
|
||||
public void growStructure(int amount);
|
||||
|
||||
/**
|
||||
* Sets the current packing value (usually a power of 2). A value of NOT_PACKING should be
|
||||
* passed if this isn't a packed data type. Otherwise this value indicates a maximum alignment
|
||||
* for any component within this data type. Calling this method will cause the data type to
|
||||
* become an internally aligned data type. (Same as {@link Composite#setPackingValue(int)})
|
||||
*
|
||||
* @param maxAlignment the new packing value or 0 for NOT_PACKING. A negative value will be
|
||||
* treated the same as 0.
|
||||
*/
|
||||
public void pack(int maxAlignment);
|
||||
|
||||
/**
|
||||
* <code>BitOffsetComparator</code> provides ability to compare an normalized bit offset (see
|
||||
* {@link #getNormalizedBitfieldOffset(int, int, int, int, boolean)}) with a
|
||||
|
@ -365,6 +362,9 @@ public interface Structure extends Composite {
|
|||
*/
|
||||
public static class BitOffsetComparator implements Comparator<Object> {
|
||||
|
||||
public static final Comparator<Object> INSTANCE_LE = new BitOffsetComparator(false);
|
||||
public static final Comparator<Object> INSTANCE_BE = new BitOffsetComparator(true);
|
||||
|
||||
private boolean bigEndian;
|
||||
|
||||
public BitOffsetComparator(boolean bigEndian) {
|
||||
|
@ -439,47 +439,4 @@ public interface Structure extends Composite {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>OffsetComparator</code> provides ability to compare an Integer offset with a
|
||||
* DataTypeComponent object. The offset will be consider equal (0) if the component contains the
|
||||
* offset.
|
||||
*/
|
||||
public static class OffsetComparator implements Comparator<Object> {
|
||||
|
||||
@Override
|
||||
public int compare(Object o1, Object o2) {
|
||||
if (o1 instanceof Integer) {
|
||||
return -compare(o2, o1);
|
||||
}
|
||||
DataTypeComponent dtc = (DataTypeComponent) o1;
|
||||
int offset = ((Integer) o2).intValue();
|
||||
if (offset < dtc.getOffset()) {
|
||||
return 1;
|
||||
}
|
||||
else if (offset > dtc.getEndOffset()) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>OrdinalComparator</code> provides ability to compare an Integer ordinal with a
|
||||
* DataTypeComponent object. The offset will be consider equal (0) if the component corresponds
|
||||
* to the specified ordinal.
|
||||
*/
|
||||
public static class OrdinalComparator implements Comparator<Object> {
|
||||
|
||||
@Override
|
||||
public int compare(Object o1, Object o2) {
|
||||
if (o1 instanceof Integer) {
|
||||
return -compare(o2, o1);
|
||||
}
|
||||
DataTypeComponent dtc = (DataTypeComponent) o1;
|
||||
int ordinal = ((Integer) o2).intValue();
|
||||
return dtc.getOrdinal() - ordinal;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,20 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.program.model.data;
|
||||
|
||||
public interface StructureInternal extends Structure, CompositeInternal {
|
||||
|
||||
}
|
|
@ -141,6 +141,11 @@ public class TypedefDataType extends GenericDataType implements TypeDef {
|
|||
return dataType.getDescription();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isZeroLength() {
|
||||
return dataType.isZeroLength();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLength() {
|
||||
return dataType.getLength();
|
||||
|
@ -182,6 +187,13 @@ public class TypedefDataType extends GenericDataType implements TypeDef {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dataTypeAlignmentChanged(DataType dt) {
|
||||
if (dt == dataType) {
|
||||
notifyAlignmentChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType getBaseDataType() {
|
||||
if (dataType instanceof TypeDef) {
|
||||
|
|
|
@ -24,9 +24,12 @@ package ghidra.program.model.data;
|
|||
*/
|
||||
public interface Union extends Composite {
|
||||
|
||||
@Override
|
||||
public Union clone(DataTypeManager dtm);
|
||||
|
||||
/**
|
||||
* Inserts a new bitfield at the specified ordinal position in this union.
|
||||
* For both aligned and unaligned unions the bitfield starts with bit-0 (lsb) of the first byte
|
||||
* For all Unions, bitfield starts with bit-0 (lsb) of the first byte
|
||||
* for little-endian, and with bit-7 (msb) of the first byte for big-endian. This is the
|
||||
* default behavior for most compilers. Insertion behavior may not work as expected if
|
||||
* packing rules differ from this.
|
||||
|
@ -40,10 +43,10 @@ public interface Union extends Composite {
|
|||
* be BitFieldDataType.
|
||||
* @throws InvalidDataTypeException if the specified baseDataType is
|
||||
* not a valid base type for bitfields.
|
||||
* @throws ArrayIndexOutOfBoundsException if ordinal is less than 0 or greater than the
|
||||
* @throws IndexOutOfBoundsException if ordinal is less than 0 or greater than the
|
||||
* current number of components.
|
||||
*/
|
||||
public DataTypeComponent insertBitField(int ordinal, DataType baseDataType, int bitSize,
|
||||
String componentName, String comment)
|
||||
throws InvalidDataTypeException, ArrayIndexOutOfBoundsException;
|
||||
throws InvalidDataTypeException, IndexOutOfBoundsException;
|
||||
}
|
||||
|
|
|
@ -15,8 +15,7 @@
|
|||
*/
|
||||
package ghidra.program.model.data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.*;
|
||||
|
||||
import ghidra.docking.settings.Settings;
|
||||
import ghidra.program.model.mem.MemBuffer;
|
||||
|
@ -24,11 +23,15 @@ import ghidra.util.Msg;
|
|||
import ghidra.util.UniversalID;
|
||||
|
||||
/**
|
||||
* Basic implementation of the union data type
|
||||
* Basic implementation of the union data type.
|
||||
* NOTE: Implementation is not thread safe when being modified.
|
||||
*/
|
||||
public class UnionDataType extends CompositeDataTypeImpl implements Union {
|
||||
private ArrayList<DataTypeComponentImpl> components;
|
||||
public class UnionDataType extends CompositeDataTypeImpl implements UnionInternal {
|
||||
|
||||
private int unionLength;
|
||||
private int unionAlignment;
|
||||
|
||||
private List<DataTypeComponentImpl> components;
|
||||
|
||||
/**
|
||||
* Construct a new empty union with the given name within the
|
||||
|
@ -96,7 +99,7 @@ public class UnionDataType extends CompositeDataTypeImpl implements Union {
|
|||
|
||||
@Override
|
||||
public boolean isNotYetDefined() {
|
||||
return components.size() == 0;
|
||||
return unionLength == 0 && isDefaultAligned() && !isPackingEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -124,17 +127,30 @@ public class UnionDataType extends CompositeDataTypeImpl implements Union {
|
|||
return components.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getPreferredComponentLength(DataType dataType, int length) {
|
||||
if (!(dataType instanceof Dynamic)) {
|
||||
length = -1;
|
||||
}
|
||||
return super.getPreferredComponentLength(dataType, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataTypeComponent add(DataType dataType, int length, String componentName,
|
||||
String comment) throws IllegalArgumentException {
|
||||
|
||||
int oldAlignment = getAlignment();
|
||||
|
||||
DataTypeComponent dtc = doAdd(dataType, length, componentName, comment);
|
||||
adjustLength(true);
|
||||
if (!repack(true) && isPackingEnabled() && oldAlignment != getAlignment()) {
|
||||
notifyAlignmentChanged();
|
||||
}
|
||||
return dtc;
|
||||
}
|
||||
|
||||
private int getBitFieldAllocation(BitFieldDataType bitfieldDt) {
|
||||
|
||||
BitFieldPacking bitFieldPacking = getBitFieldPacking();
|
||||
BitFieldPacking bitFieldPacking = getDataOrganization().getBitFieldPacking();
|
||||
if (bitFieldPacking.useMSConvention()) {
|
||||
return bitfieldDt.getBaseTypeSize();
|
||||
}
|
||||
|
@ -144,10 +160,9 @@ public class UnionDataType extends CompositeDataTypeImpl implements Union {
|
|||
}
|
||||
|
||||
int length = bitfieldDt.getBaseTypeSize();
|
||||
int packValue = getPackingValue();
|
||||
if (packValue != NOT_PACKING && length > packValue) {
|
||||
if (packing > 0 && length > packing) {
|
||||
length =
|
||||
DataOrganizationImpl.getLeastCommonMultiple(bitfieldDt.getStorageSize(), packValue);
|
||||
DataOrganizationImpl.getLeastCommonMultiple(bitfieldDt.getStorageSize(), packing);
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
@ -177,6 +192,8 @@ public class UnionDataType extends CompositeDataTypeImpl implements Union {
|
|||
String componentName, String comment) throws IllegalArgumentException {
|
||||
validateDataType(dataType);
|
||||
|
||||
int oldAlignment = getAlignment();
|
||||
|
||||
dataType = adjustBitField(dataType);
|
||||
|
||||
dataType = dataType.clone(dataMgr);
|
||||
|
@ -190,7 +207,9 @@ public class UnionDataType extends CompositeDataTypeImpl implements Union {
|
|||
shiftOrdinals(ordinal, 1);
|
||||
components.add(ordinal, dtc);
|
||||
|
||||
adjustLength(true);
|
||||
if (!repack(true) && isPackingEnabled() && oldAlignment != getAlignment()) {
|
||||
notifyAlignmentChanged();
|
||||
}
|
||||
return dtc;
|
||||
}
|
||||
|
||||
|
@ -203,10 +222,10 @@ public class UnionDataType extends CompositeDataTypeImpl implements Union {
|
|||
@Override
|
||||
public DataTypeComponent insertBitField(int ordinal, DataType baseDataType, int bitSize,
|
||||
String componentName, String comment)
|
||||
throws InvalidDataTypeException, ArrayIndexOutOfBoundsException {
|
||||
throws InvalidDataTypeException, IndexOutOfBoundsException {
|
||||
|
||||
if (ordinal < 0 || ordinal > components.size()) {
|
||||
throw new ArrayIndexOutOfBoundsException(ordinal);
|
||||
throw new IndexOutOfBoundsException(ordinal);
|
||||
}
|
||||
|
||||
BitFieldDataType.checkBaseDataType(baseDataType);
|
||||
|
@ -216,16 +235,21 @@ public class UnionDataType extends CompositeDataTypeImpl implements Union {
|
|||
return insert(ordinal, bitFieldDt, bitFieldDt.getStorageSize(), componentName, comment);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isZeroLength() {
|
||||
return unionLength == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLength() {
|
||||
if (unionLength == 0) {
|
||||
return 1;
|
||||
return 1; // 0-length datatype not supported
|
||||
}
|
||||
return unionLength;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType clone(DataTypeManager dtm) {
|
||||
public Union clone(DataTypeManager dtm) {
|
||||
if (dataMgr == dtm) {
|
||||
return this;
|
||||
}
|
||||
|
@ -246,16 +270,54 @@ public class UnionDataType extends CompositeDataTypeImpl implements Union {
|
|||
|
||||
@Override
|
||||
public void delete(int ordinal) {
|
||||
|
||||
int oldAlignment = getAlignment();
|
||||
|
||||
DataTypeComponent dtc = components.remove(ordinal);
|
||||
dtc.getDataType().removeParent(this);
|
||||
shiftOrdinals(ordinal, -1);
|
||||
adjustLength(true);
|
||||
|
||||
if (!repack(true) && isPackingEnabled() && oldAlignment != getAlignment()) {
|
||||
notifyAlignmentChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(int[] ordinals) {
|
||||
for (int ordinal : ordinals) {
|
||||
delete(ordinal);
|
||||
public void delete(Set<Integer> ordinals) {
|
||||
|
||||
if (ordinals.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int oldAlignment = getAlignment();
|
||||
|
||||
List<DataTypeComponentImpl> newComponents = new ArrayList<>();
|
||||
int newLength = 0;
|
||||
int ordinalAdjustment = 0;
|
||||
for (DataTypeComponentImpl dtc : components) {
|
||||
int ordinal = dtc.getOrdinal();
|
||||
if (ordinals.contains(ordinal)) {
|
||||
// component removed
|
||||
--ordinalAdjustment;
|
||||
}
|
||||
else {
|
||||
if (ordinalAdjustment != 0) {
|
||||
dtc.setOrdinal(dtc.getOrdinal() + ordinalAdjustment);
|
||||
}
|
||||
newComponents.add(dtc);
|
||||
newLength = Math.max(newLength, dtc.getLength());
|
||||
}
|
||||
}
|
||||
components = newComponents;
|
||||
|
||||
if (isPackingEnabled()) {
|
||||
if (!repack(true) && oldAlignment != getAlignment()) {
|
||||
notifyAlignmentChanged();
|
||||
}
|
||||
}
|
||||
else {
|
||||
unionLength = newLength;
|
||||
notifySizeChanged();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -270,8 +332,8 @@ public class UnionDataType extends CompositeDataTypeImpl implements Union {
|
|||
DataType baseDataType = bitfieldDt.getBaseDataType();
|
||||
baseDataType = baseDataType.clone(dataMgr);
|
||||
|
||||
// Both aligned and unaligned bitfields use same adjustment
|
||||
// unaligned must force bitfield placement at byte offset 0
|
||||
// Both aligned and non-packed bitfields use same adjustment
|
||||
// non-packed must force bitfield placement at byte offset 0
|
||||
int bitSize = bitfieldDt.getDeclaredBitSize();
|
||||
int effectiveBitSize =
|
||||
BitFieldDataType.getEffectiveBitSize(bitSize, baseDataType.getLength());
|
||||
|
@ -303,22 +365,55 @@ public class UnionDataType extends CompositeDataTypeImpl implements Union {
|
|||
return bitfieldDt;
|
||||
}
|
||||
|
||||
private void adjustLength(boolean notify) {
|
||||
@Override
|
||||
public int getAlignment() {
|
||||
if (unionAlignment > 0) {
|
||||
return unionAlignment;
|
||||
}
|
||||
if (isPackingEnabled()) {
|
||||
unionAlignment = CompositeAlignmentHelper.getAlignment(getDataOrganization(), this);
|
||||
}
|
||||
else {
|
||||
unionAlignment = getNonPackedAlignment();
|
||||
}
|
||||
return unionAlignment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean repack(boolean notify) {
|
||||
|
||||
int oldLength = unionLength;
|
||||
int oldAlignment = getAlignment();
|
||||
|
||||
unionLength = 0;
|
||||
for (DataTypeComponent dtc : components) {
|
||||
|
||||
// TODO: compute alignment in this loop
|
||||
int length = dtc.getLength();
|
||||
if (isInternallyAligned() && dtc.isBitFieldComponent()) {
|
||||
if (isPackingEnabled() && dtc.isBitFieldComponent()) {
|
||||
// revise length to reflect compiler bitfield allocation rules
|
||||
length = getBitFieldAllocation((BitFieldDataType) dtc.getDataType());
|
||||
}
|
||||
|
||||
unionLength = Math.max(length, unionLength);
|
||||
}
|
||||
if (notify && oldLength != unionLength) {
|
||||
notifySizeChanged();
|
||||
|
||||
unionAlignment = -1; // force recompute of unionAlignment
|
||||
getAlignment();
|
||||
|
||||
if (isPackingEnabled()) {
|
||||
unionLength = DataOrganizationImpl.getAlignedOffset(unionAlignment, unionLength);
|
||||
}
|
||||
|
||||
boolean changed = (oldLength != unionLength) || (oldAlignment != unionAlignment);
|
||||
|
||||
if (changed && notify) {
|
||||
if (oldLength != unionLength) {
|
||||
notifySizeChanged();
|
||||
}
|
||||
else if (oldAlignment != unionAlignment) {
|
||||
notifyAlignmentChanged();
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -330,13 +425,10 @@ public class UnionDataType extends CompositeDataTypeImpl implements Union {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (dt instanceof Union) {
|
||||
Union union = (Union) dt;
|
||||
if (isInternallyAligned() != union.isInternallyAligned() ||
|
||||
isDefaultAligned() != union.isDefaultAligned() ||
|
||||
isMachineAligned() != union.isMachineAligned() ||
|
||||
getMinimumAlignment() != union.getMinimumAlignment() ||
|
||||
getPackingValue() != union.getPackingValue()) {
|
||||
if (dt instanceof UnionInternal) {
|
||||
UnionInternal union = (UnionInternal) dt;
|
||||
if (packing != union.getStoredPackingValue() ||
|
||||
minimumAlignment != union.getStoredMinimumAlignment()) {
|
||||
// rely on component match instead of checking length
|
||||
// since dynamic component sizes could affect length
|
||||
return false;
|
||||
|
@ -365,8 +457,23 @@ public class UnionDataType extends CompositeDataTypeImpl implements Union {
|
|||
|
||||
@Override
|
||||
public void dataTypeAlignmentChanged(DataType dt) {
|
||||
if (isInternallyAligned()) {
|
||||
adjustInternalAlignment();
|
||||
if (!isPackingEnabled()) {
|
||||
return;
|
||||
}
|
||||
if (dt instanceof BitFieldDataType) {
|
||||
return; // unsupported
|
||||
}
|
||||
boolean hasPossibleChange = false;
|
||||
for (DataTypeComponentImpl dtc : components) {
|
||||
if (dtc.getDataType() == dt) {
|
||||
hasPossibleChange = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hasPossibleChange && !repack(true) && isPackingEnabled()) {
|
||||
// NOTE: Must assume alignment change since we are unable to determine
|
||||
// without stored alignment
|
||||
notifyAlignmentChanged();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -386,8 +493,10 @@ public class UnionDataType extends CompositeDataTypeImpl implements Union {
|
|||
changed = true;
|
||||
}
|
||||
}
|
||||
if (changed) {
|
||||
adjustLength(true);
|
||||
if (changed && !repack(true) && isPackingEnabled()) {
|
||||
// NOTE: Must assume alignment change since we are unable to determine
|
||||
// without stored alignment
|
||||
notifyAlignmentChanged();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -451,13 +560,14 @@ public class UnionDataType extends CompositeDataTypeImpl implements Union {
|
|||
}
|
||||
}
|
||||
if (changed) {
|
||||
adjustLength(true);
|
||||
repack(false);
|
||||
notifySizeChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dataTypeDeleted(DataType dt) {
|
||||
boolean didDelete = false;
|
||||
boolean changed = false;
|
||||
for (int i = components.size() - 1; i >= 0; i--) { // reverse order
|
||||
DataTypeComponentImpl dtc = components.get(i);
|
||||
boolean removeBitFieldComponent = false;
|
||||
|
@ -469,21 +579,23 @@ public class UnionDataType extends CompositeDataTypeImpl implements Union {
|
|||
dt.removeParent(this);
|
||||
components.remove(i);
|
||||
shiftOrdinals(i, -1);
|
||||
didDelete = true;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
if (didDelete) {
|
||||
adjustLength(true);
|
||||
if (changed && !repack(true) && isPackingEnabled()) {
|
||||
// NOTE: Must assume alignment change since we are unable to determine
|
||||
// without stored alignment
|
||||
notifyAlignmentChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void replaceWith(DataType dataType) throws IllegalArgumentException {
|
||||
if (!(dataType instanceof Union)) {
|
||||
if (!(dataType instanceof UnionInternal)) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
Union union = (Union) dataType;
|
||||
UnionInternal union = (UnionInternal) dataType;
|
||||
|
||||
Iterator<DataTypeComponentImpl> it = components.iterator();
|
||||
while (it.hasNext()) {
|
||||
|
@ -491,8 +603,10 @@ public class UnionDataType extends CompositeDataTypeImpl implements Union {
|
|||
dtc.getDataType().removeParent(this);
|
||||
}
|
||||
components.clear();
|
||||
unionAlignment = -1;
|
||||
|
||||
setAlignment(union);
|
||||
this.packing = union.getStoredPackingValue();
|
||||
this.minimumAlignment = union.getStoredMinimumAlignment();
|
||||
|
||||
DataTypeComponent[] compArray = union.getComponents();
|
||||
for (DataTypeComponent dtc : compArray) {
|
||||
|
@ -500,12 +614,8 @@ public class UnionDataType extends CompositeDataTypeImpl implements Union {
|
|||
doAdd(dt, dtc.getLength(), dtc.getFieldName(), dtc.getComment());
|
||||
}
|
||||
|
||||
adjustLength(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dataTypeNameChanged(DataType dt, String oldName) {
|
||||
// ignored
|
||||
repack(false);
|
||||
notifySizeChanged(); // assume size and/or alignment changed
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -522,16 +632,4 @@ public class UnionDataType extends CompositeDataTypeImpl implements Union {
|
|||
return "UNION_" + getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void realign() {
|
||||
if (isInternallyAligned()) {
|
||||
adjustInternalAlignment();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void adjustInternalAlignment() {
|
||||
adjustLength(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.program.model.data;
|
||||
|
||||
public interface UnionInternal extends Union, CompositeInternal {
|
||||
|
||||
}
|
|
@ -22,6 +22,8 @@ import static org.junit.Assert.*;
|
|||
|
||||
import org.junit.*;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
import generic.test.AbstractGTest;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.InvalidNameException;
|
||||
|
@ -89,10 +91,12 @@ public class StructureDBTest extends AbstractGTest {
|
|||
public void testEmpty() throws Exception {
|
||||
Structure s = new StructureDataType("foo", 0);
|
||||
assertTrue(s.isNotYetDefined());
|
||||
assertTrue(s.isZeroLength());
|
||||
assertEquals(0, s.getNumComponents());
|
||||
assertEquals(0, s.getNumDefinedComponents());
|
||||
Structure s2 = (Structure) dataMgr.resolve(s, null);
|
||||
assertTrue(s2.isNotYetDefined());
|
||||
assertTrue(s2.isZeroLength());
|
||||
assertEquals(0, s2.getNumComponents());
|
||||
assertEquals(0, s.getNumDefinedComponents());
|
||||
}
|
||||
|
@ -101,10 +105,12 @@ public class StructureDBTest extends AbstractGTest {
|
|||
public void testSizeOne() throws Exception {
|
||||
Structure s = new StructureDataType("foo", 1);
|
||||
assertFalse(s.isNotYetDefined());
|
||||
assertFalse(s.isZeroLength());
|
||||
assertEquals(1, s.getNumComponents());
|
||||
assertEquals(0, s.getNumDefinedComponents());
|
||||
Structure s2 = (Structure) dataMgr.resolve(s, null);
|
||||
assertFalse(s2.isNotYetDefined());
|
||||
assertFalse(s2.isZeroLength());
|
||||
assertEquals(1, s2.getNumComponents());
|
||||
assertEquals(0, s2.getNumDefinedComponents());
|
||||
}
|
||||
|
@ -442,7 +448,7 @@ public class StructureDBTest extends AbstractGTest {
|
|||
@Test
|
||||
public void testSetFlexArray() throws Exception {
|
||||
|
||||
struct.setInternallyAligned(true);
|
||||
struct.setPackingEnabled(true);
|
||||
|
||||
struct.delete(2); // remove dword to verify flex array alignment below
|
||||
|
||||
|
@ -450,7 +456,7 @@ public class StructureDBTest extends AbstractGTest {
|
|||
|
||||
//@formatter:off
|
||||
CompositeTestUtils.assertExpectedComposite(this, "/Test\n" +
|
||||
"Aligned\n" +
|
||||
"pack()\n" +
|
||||
"Structure Test {\n" +
|
||||
" 0 byte 1 field1 \"Comment1\"\n" +
|
||||
" 2 word 2 null \"Comment2\"\n" +
|
||||
|
@ -464,7 +470,7 @@ public class StructureDBTest extends AbstractGTest {
|
|||
|
||||
//@formatter:off
|
||||
CompositeTestUtils.assertExpectedComposite(this, "/Test\n" +
|
||||
"Aligned\n" +
|
||||
"pack()\n" +
|
||||
"Structure Test {\n" +
|
||||
" 0 byte 1 field1 \"Comment1\"\n" +
|
||||
" 2 word 2 null \"Comment2\"\n" +
|
||||
|
@ -478,7 +484,7 @@ public class StructureDBTest extends AbstractGTest {
|
|||
@Test
|
||||
public void testZeroBitFields() throws Exception {
|
||||
|
||||
struct.setInternallyAligned(true);
|
||||
struct.setPackingEnabled(true);
|
||||
|
||||
struct.delete(2); // remove dword to verify flex array alignment below
|
||||
|
||||
|
@ -488,7 +494,7 @@ public class StructureDBTest extends AbstractGTest {
|
|||
|
||||
//@formatter:off
|
||||
CompositeTestUtils.assertExpectedComposite(this, "/Test\n" +
|
||||
"Aligned\n" +
|
||||
"pack()\n" +
|
||||
"Structure Test {\n" +
|
||||
" 0 int:3(0) 1 bf1 \"bf1Comment\"\n" +
|
||||
" 4 int:0(0) 1 \"zero bitfield 1\"\n" +
|
||||
|
@ -504,7 +510,7 @@ public class StructureDBTest extends AbstractGTest {
|
|||
|
||||
//@formatter:off
|
||||
CompositeTestUtils.assertExpectedComposite(this, "/Test\n" +
|
||||
"Aligned\n" +
|
||||
"pack()\n" +
|
||||
"Structure Test {\n" +
|
||||
" 0 int:3(0) 1 bf1 \"bf1Comment\"\n" +
|
||||
" 4 int:0(0) 1 \"zero bitfield 1\"\n" +
|
||||
|
@ -525,7 +531,7 @@ public class StructureDBTest extends AbstractGTest {
|
|||
|
||||
//@formatter:off
|
||||
CompositeTestUtils.assertExpectedComposite(this, "/Test\n" +
|
||||
"Unaligned\n" +
|
||||
"pack(disabled)\n" +
|
||||
"Structure Test {\n" +
|
||||
" 0 byte 1 field1 \"Comment1\"\n" +
|
||||
" 1 word 2 null \"Comment2\"\n" +
|
||||
|
@ -543,7 +549,7 @@ public class StructureDBTest extends AbstractGTest {
|
|||
|
||||
//@formatter:off
|
||||
CompositeTestUtils.assertExpectedComposite(this, "/Test\n" +
|
||||
"Unaligned\n" +
|
||||
"pack(disabled)\n" +
|
||||
"Structure Test {\n" +
|
||||
" 0 byte 1 field1 \"Comment1\"\n" +
|
||||
" 1 word 2 null \"Comment2\"\n" +
|
||||
|
@ -562,7 +568,7 @@ public class StructureDBTest extends AbstractGTest {
|
|||
|
||||
//@formatter:off
|
||||
CompositeTestUtils.assertExpectedComposite(this, "/Test\n" +
|
||||
"Unaligned\n" +
|
||||
"pack(disabled)\n" +
|
||||
"Structure Test {\n" +
|
||||
" 0 byte 1 field1 \"Comment1\"\n" +
|
||||
" 1 word 2 null \"Comment2\"\n" +
|
||||
|
@ -585,7 +591,7 @@ public class StructureDBTest extends AbstractGTest {
|
|||
|
||||
//@formatter:off
|
||||
CompositeTestUtils.assertExpectedComposite(this, "/Test\n" +
|
||||
"Unaligned\n" +
|
||||
"pack(disabled)\n" +
|
||||
"Structure Test {\n" +
|
||||
" 0 byte 1 field1 \"Comment1\"\n" +
|
||||
" 1 word 2 null \"Comment2\"\n" +
|
||||
|
@ -605,7 +611,7 @@ public class StructureDBTest extends AbstractGTest {
|
|||
|
||||
//@formatter:off
|
||||
CompositeTestUtils.assertExpectedComposite(this, "/Test\n" +
|
||||
"Unaligned\n" +
|
||||
"pack(disabled)\n" +
|
||||
"Structure Test {\n" +
|
||||
" 0 byte 1 field1 \"Comment1\"\n" +
|
||||
" 1 word 2 null \"Comment2\"\n" +
|
||||
|
@ -630,7 +636,7 @@ public class StructureDBTest extends AbstractGTest {
|
|||
|
||||
//@formatter:off
|
||||
CompositeTestUtils.assertExpectedComposite(this, "/Test\n" +
|
||||
"Unaligned\n" +
|
||||
"pack(disabled)\n" +
|
||||
"Structure Test {\n" +
|
||||
" 0 byte 1 field1 \"Comment1\"\n" +
|
||||
// " 1 undefined 1 null \"\"\n" +
|
||||
|
@ -649,7 +655,7 @@ public class StructureDBTest extends AbstractGTest {
|
|||
|
||||
//@formatter:off
|
||||
CompositeTestUtils.assertExpectedComposite(this, "/Test\n" +
|
||||
"Unaligned\n" +
|
||||
"pack(disabled)\n" +
|
||||
"Structure Test {\n" +
|
||||
" 0 byte 1 field1 \"Comment1\"\n" +
|
||||
// " 1 undefined 1 null \"\"\n" +
|
||||
|
@ -669,7 +675,7 @@ public class StructureDBTest extends AbstractGTest {
|
|||
|
||||
//@formatter:off
|
||||
CompositeTestUtils.assertExpectedComposite(this, "/Test\n" +
|
||||
"Unaligned\n" +
|
||||
"pack(disabled)\n" +
|
||||
"Structure Test {\n" +
|
||||
" 0 byte 1 field1 \"Comment1\"\n" +
|
||||
// " 1 undefined 1 null \"\"\n" +
|
||||
|
@ -697,7 +703,7 @@ public class StructureDBTest extends AbstractGTest {
|
|||
|
||||
//@formatter:off
|
||||
CompositeTestUtils.assertExpectedComposite(this, "/Test\n" +
|
||||
"Unaligned\n" +
|
||||
"pack(disabled)\n" +
|
||||
"Structure Test {\n" +
|
||||
" 0 byte 1 field1 \"Comment1\"\n" +
|
||||
// " 1 undefined 1 null \"\"\n" +
|
||||
|
@ -716,7 +722,7 @@ public class StructureDBTest extends AbstractGTest {
|
|||
|
||||
//@formatter:off
|
||||
CompositeTestUtils.assertExpectedComposite(this, "/Test\n" +
|
||||
"Unaligned\n" +
|
||||
"pack(disabled)\n" +
|
||||
"Structure Test {\n" +
|
||||
" 0 byte 1 field1 \"Comment1\"\n" +
|
||||
// " 1 undefined 1 null \"\"\n" +
|
||||
|
@ -751,7 +757,7 @@ public class StructureDBTest extends AbstractGTest {
|
|||
|
||||
//@formatter:off
|
||||
CompositeTestUtils.assertExpectedComposite(this, "/Test\n" +
|
||||
"Unaligned\n" +
|
||||
"pack(disabled)\n" +
|
||||
"Structure Test {\n" +
|
||||
" 0 byte 1 field1 \"Comment1\"\n" +
|
||||
// " 1 undefined 1 null \"\"\n" +
|
||||
|
@ -770,7 +776,7 @@ public class StructureDBTest extends AbstractGTest {
|
|||
|
||||
//@formatter:off
|
||||
CompositeTestUtils.assertExpectedComposite(this, "/Test\n" +
|
||||
"Unaligned\n" +
|
||||
"pack(disabled)\n" +
|
||||
"Structure Test {\n" +
|
||||
" 0 byte 1 field1 \"Comment1\"\n" +
|
||||
// " 1 undefined 1 null \"\"\n" +
|
||||
|
@ -790,7 +796,7 @@ public class StructureDBTest extends AbstractGTest {
|
|||
|
||||
//@formatter:off
|
||||
CompositeTestUtils.assertExpectedComposite(this, "/Test\n" +
|
||||
"Unaligned\n" +
|
||||
"pack(disabled)\n" +
|
||||
"Structure Test {\n" +
|
||||
" 0 byte 1 field1 \"Comment1\"\n" +
|
||||
// " 1 undefined 1 null \"\"\n" +
|
||||
|
@ -809,7 +815,7 @@ public class StructureDBTest extends AbstractGTest {
|
|||
|
||||
//@formatter:off
|
||||
CompositeTestUtils.assertExpectedComposite(this, "/Test\n" +
|
||||
"Unaligned\n" +
|
||||
"pack(disabled)\n" +
|
||||
"Structure Test {\n" +
|
||||
" 0 byte 1 field1 \"Comment1\"\n" +
|
||||
// " 1 undefined 1 null \"\"\n" +
|
||||
|
@ -828,7 +834,7 @@ public class StructureDBTest extends AbstractGTest {
|
|||
|
||||
//@formatter:off
|
||||
CompositeTestUtils.assertExpectedComposite(this, "/Test\n" +
|
||||
"Unaligned\n" +
|
||||
"pack(disabled)\n" +
|
||||
"Structure Test {\n" +
|
||||
" 0 byte 1 field1 \"Comment1\"\n" +
|
||||
// " 1 undefined 1 null \"\"\n" +
|
||||
|
@ -859,7 +865,7 @@ public class StructureDBTest extends AbstractGTest {
|
|||
|
||||
//@formatter:off
|
||||
CompositeTestUtils.assertExpectedComposite(this, "/Test\n" +
|
||||
"Unaligned\n" +
|
||||
"pack(disabled)\n" +
|
||||
"Structure Test {\n" +
|
||||
" 0 byte 1 field1 \"Comment1\"\n" +
|
||||
// " 1 undefined 1 null \"\"\n" +
|
||||
|
@ -1084,7 +1090,7 @@ public class StructureDBTest extends AbstractGTest {
|
|||
|
||||
//@formatter:off
|
||||
CompositeTestUtils.assertExpectedComposite(this, "/Test\n" +
|
||||
"Unaligned\n" +
|
||||
"pack(disabled)\n" +
|
||||
"Structure Test {\n" +
|
||||
" 0 byte 1 field1 \"Comment1\"\n" +
|
||||
" 1 word 2 null \"Comment2\"\n" +
|
||||
|
@ -1101,7 +1107,7 @@ public class StructureDBTest extends AbstractGTest {
|
|||
|
||||
//@formatter:off
|
||||
CompositeTestUtils.assertExpectedComposite(this, "/Test\n" +
|
||||
"Unaligned\n" +
|
||||
"pack(disabled)\n" +
|
||||
"Structure Test {\n" +
|
||||
" 0 byte 1 field1 \"Comment1\"\n" +
|
||||
" 1 word 2 null \"Comment2\"\n" +
|
||||
|
@ -1118,7 +1124,7 @@ public class StructureDBTest extends AbstractGTest {
|
|||
@Test
|
||||
public void testReplaceFlexArrayDependency() throws DataTypeDependencyException {
|
||||
|
||||
struct.setInternallyAligned(true);
|
||||
struct.setPackingEnabled(true);
|
||||
|
||||
struct.delete(2); // remove dword to verify flex array alignment below
|
||||
|
||||
|
@ -1129,7 +1135,7 @@ public class StructureDBTest extends AbstractGTest {
|
|||
|
||||
//@formatter:off
|
||||
CompositeTestUtils.assertExpectedComposite(this, "/Test\n" +
|
||||
"Aligned\n" +
|
||||
"pack()\n" +
|
||||
"Structure Test {\n" +
|
||||
" 0 byte 1 field1 \"Comment1\"\n" +
|
||||
" 2 word 2 null \"Comment2\"\n" +
|
||||
|
@ -1146,7 +1152,7 @@ public class StructureDBTest extends AbstractGTest {
|
|||
|
||||
//@formatter:off
|
||||
CompositeTestUtils.assertExpectedComposite(this, "/Test\n" +
|
||||
"Aligned\n" +
|
||||
"pack()\n" +
|
||||
"Structure Test {\n" +
|
||||
" 0 byte 1 field1 \"Comment1\"\n" +
|
||||
" 2 word 2 null \"Comment2\"\n" +
|
||||
|
@ -1161,7 +1167,7 @@ public class StructureDBTest extends AbstractGTest {
|
|||
public void testReplaceBitFieldDependency()
|
||||
throws InvalidDataTypeException, DataTypeDependencyException {
|
||||
|
||||
struct.setInternallyAligned(true);
|
||||
struct.setPackingEnabled(true);
|
||||
|
||||
TypeDef td = new TypedefDataType("Foo", IntegerDataType.dataType);
|
||||
td = (TypeDef) dataMgr.resolve(td, null);
|
||||
|
@ -1172,7 +1178,7 @@ public class StructureDBTest extends AbstractGTest {
|
|||
|
||||
//@formatter:off
|
||||
CompositeTestUtils.assertExpectedComposite(this, "/Test\n" +
|
||||
"Aligned\n" +
|
||||
"pack()\n" +
|
||||
"Structure Test {\n" +
|
||||
" 0 byte 1 field1 \"Comment1\"\n" +
|
||||
" 2 word 2 null \"Comment2\"\n" +
|
||||
|
@ -1189,7 +1195,7 @@ public class StructureDBTest extends AbstractGTest {
|
|||
|
||||
//@formatter:off
|
||||
CompositeTestUtils.assertExpectedComposite(this, "/Test\n" +
|
||||
"Aligned\n" +
|
||||
"pack()\n" +
|
||||
"Structure Test {\n" +
|
||||
" 0 byte 1 field1 \"Comment1\"\n" +
|
||||
" 2 word 2 null \"Comment2\"\n" +
|
||||
|
@ -1206,7 +1212,7 @@ public class StructureDBTest extends AbstractGTest {
|
|||
@Test
|
||||
public void testReplaceWith() throws InvalidDataTypeException {
|
||||
|
||||
// NOTE: unaligned bitfields should remain unchanged when
|
||||
// NOTE: non-packed bitfields should remain unchanged when
|
||||
// transitioning endianess even though it makes little sense.
|
||||
// Unaligned structures are not intended to be portable!
|
||||
|
||||
|
@ -1222,7 +1228,7 @@ public class StructureDBTest extends AbstractGTest {
|
|||
|
||||
//@formatter:off
|
||||
CompositeTestUtils.assertExpectedComposite(this, "/Test\n" +
|
||||
"Unaligned\n" +
|
||||
"pack(disabled)\n" +
|
||||
"Structure Test {\n" +
|
||||
" 0 byte 1 field1 \"Comment1\"\n" +
|
||||
" 1 word 2 null \"Comment2\"\n" +
|
||||
|
@ -1246,7 +1252,7 @@ public class StructureDBTest extends AbstractGTest {
|
|||
|
||||
//@formatter:off
|
||||
CompositeTestUtils.assertExpectedComposite(this, "/bigStruct\n" +
|
||||
"Unaligned\n" +
|
||||
"pack(disabled)\n" +
|
||||
"Structure bigStruct {\n" +
|
||||
" 0 byte 1 field1 \"Comment1\"\n" +
|
||||
" 1 word 2 null \"Comment2\"\n" +
|
||||
|
@ -1263,6 +1269,129 @@ public class StructureDBTest extends AbstractGTest {
|
|||
//@formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReplaceWithConflict() {
|
||||
|
||||
// Test case where structure BAR contains a not-yet-defined structure FOO (impl)
|
||||
// which has previously been resolved as fully defined. Test verifies that resolving
|
||||
// BAR properly handles the conflict replacement of the FOO component with a larger
|
||||
// fully defined datatype.
|
||||
|
||||
Structure fooNotYetDefined = new StructureDataType("FOO", 0);
|
||||
|
||||
Structure fooDefined = new StructureDataType("FOO", 0);
|
||||
fooDefined.add(new ArrayDataType(ByteDataType.dataType, 20, 1));
|
||||
fooDefined = (Structure) dataMgr.resolve(fooDefined, null);
|
||||
|
||||
Structure barStruct = new StructureDataType("BAR", 40);
|
||||
barStruct.replaceAtOffset(0, fooNotYetDefined, -1, "f1", null);
|
||||
barStruct.replaceAtOffset(10, ByteDataType.dataType, 1, "f2", null);
|
||||
|
||||
barStruct = (Structure) dataMgr.resolve(barStruct,
|
||||
DataTypeConflictHandler.REPLACE_EMPTY_STRUCTS_OR_RENAME_AND_ADD_HANDLER);
|
||||
|
||||
//@formatter:off
|
||||
CompositeTestUtils.assertExpectedComposite(this, "/BAR\n" +
|
||||
"pack(disabled)\n" +
|
||||
"Structure BAR {\n" +
|
||||
" 0 FOO 10 f1 \"\"\n" +
|
||||
" 10 byte 1 f2 \"\"\n" +
|
||||
"}\n" +
|
||||
"Size = 40 Actual Alignment = 1", barStruct);
|
||||
//@formatter:on
|
||||
|
||||
DataTypeComponent dtc1 = barStruct.getDefinedComponents()[1];
|
||||
assertEquals(1, dtc1.getOrdinal());
|
||||
assertEquals(dtc1, barStruct.getComponent(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReplaceWithConflict2() {
|
||||
|
||||
// Test case where structure BAR contains a not-yet-defined structure FOO (impl)
|
||||
// which has previously been resolved as fully defined. Test verifies that resolving
|
||||
// BAR properly handles the conflict replacement of the FOO component with a larger
|
||||
// fully defined datatype.
|
||||
|
||||
Structure fooNotYetDefined = new StructureDataType("FOO", 0);
|
||||
|
||||
Structure fooDefined = new StructureDataType("FOO", 0);
|
||||
fooDefined.add(new ArrayDataType(ByteDataType.dataType, 5, 1));
|
||||
fooDefined = (Structure) dataMgr.resolve(fooDefined, null);
|
||||
|
||||
Structure barStruct = new StructureDataType("BAR", 40);
|
||||
barStruct.replaceAtOffset(0, fooNotYetDefined, -1, "f1", null);
|
||||
barStruct.replaceAtOffset(10, ByteDataType.dataType, 1, "f2", null);
|
||||
|
||||
barStruct = (Structure) dataMgr.resolve(barStruct,
|
||||
DataTypeConflictHandler.REPLACE_EMPTY_STRUCTS_OR_RENAME_AND_ADD_HANDLER);
|
||||
|
||||
//@formatter:off
|
||||
CompositeTestUtils.assertExpectedComposite(this, "/BAR\n" +
|
||||
"pack(disabled)\n" +
|
||||
"Structure BAR {\n" +
|
||||
" 0 FOO 5 f1 \"\"\n" +
|
||||
" 10 byte 1 f2 \"\"\n" +
|
||||
"}\n" +
|
||||
"Size = 40 Actual Alignment = 1", barStruct);
|
||||
//@formatter:on
|
||||
|
||||
DataTypeComponent dtc1 = barStruct.getDefinedComponents()[1];
|
||||
assertEquals(6, dtc1.getOrdinal());
|
||||
assertEquals(dtc1, barStruct.getComponent(6));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteMany() throws InvalidDataTypeException {
|
||||
|
||||
struct.insertBitFieldAt(2, 4, 0, IntegerDataType.dataType, 3, "bf1", "bf1Comment");
|
||||
struct.insertBitFieldAt(2, 4, 3, IntegerDataType.dataType, 3, "bf2", "bf2Comment");
|
||||
struct.insertBitFieldAt(2, 4, 6, IntegerDataType.dataType, 15, "bf3", "bf3Comment");
|
||||
struct.insertBitFieldAt(2, 4, 21, IntegerDataType.dataType, 11, "bf4", "bf4Comment");
|
||||
|
||||
//@formatter:off
|
||||
CompositeTestUtils.assertExpectedComposite(this, "/Test\n" +
|
||||
"pack(disabled)\n" +
|
||||
"Structure Test {\n" +
|
||||
" 0 byte 1 field1 \"Comment1\"\n" +
|
||||
// " 1 undefined 1 null \"\"\n" +
|
||||
" 2 int:3(0) 1 bf1 \"bf1Comment\"\n" +
|
||||
" 2 int:3(3) 1 bf2 \"bf2Comment\"\n" +
|
||||
" 2 int:15(6) 3 bf3 \"bf3Comment\"\n" +
|
||||
" 4 int:11(5) 2 bf4 \"bf4Comment\"\n" +
|
||||
" 6 word 2 null \"Comment2\"\n" +
|
||||
" 8 dword 4 field3 \"\"\n" +
|
||||
" 12 byte 1 field4 \"Comment4\"\n" +
|
||||
"}\n" +
|
||||
"Size = 13 Actual Alignment = 1", struct);
|
||||
//@formatter:on
|
||||
|
||||
struct.delete(Sets.newHashSet(1, 2, 3, 4, 5, 6));
|
||||
|
||||
//@formatter:off
|
||||
CompositeTestUtils.assertExpectedComposite(this, "/Test\n" +
|
||||
"pack(disabled)\n" +
|
||||
"Structure Test {\n" +
|
||||
" 0 byte 1 field1 \"Comment1\"\n" +
|
||||
// " 1 undefined 1 null \"\"\n" +
|
||||
// " 2 undefined 1 null \"\"\n" +
|
||||
// " 3 undefined 1 null \"\"\n" +
|
||||
// " 4 undefined 1 null \"\"\n" +
|
||||
" 5 dword 4 field3 \"\"\n" +
|
||||
" 9 byte 1 field4 \"Comment4\"\n" +
|
||||
"}\n" +
|
||||
"Size = 10 Actual Alignment = 1", struct);
|
||||
//@formatter:on
|
||||
|
||||
assertEquals(10, struct.getLength());
|
||||
assertEquals(7, struct.getNumComponents());
|
||||
assertEquals(3, struct.getNumDefinedComponents());
|
||||
DataTypeComponent[] comps = struct.getDefinedComponents();
|
||||
assertEquals(DWordDataType.class, comps[1].getDataType().getClass());
|
||||
assertEquals(5, comps[1].getOffset());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDelete() throws InvalidDataTypeException {
|
||||
|
||||
|
@ -1273,7 +1402,7 @@ public class StructureDBTest extends AbstractGTest {
|
|||
|
||||
//@formatter:off
|
||||
CompositeTestUtils.assertExpectedComposite(this, "/Test\n" +
|
||||
"Unaligned\n" +
|
||||
"pack(disabled)\n" +
|
||||
"Structure Test {\n" +
|
||||
" 0 byte 1 field1 \"Comment1\"\n" +
|
||||
// " 1 undefined 1 null \"\"\n" +
|
||||
|
@ -1292,7 +1421,7 @@ public class StructureDBTest extends AbstractGTest {
|
|||
|
||||
//@formatter:off
|
||||
CompositeTestUtils.assertExpectedComposite(this, "/Test\n" +
|
||||
"Unaligned\n" +
|
||||
"pack(disabled)\n" +
|
||||
"Structure Test {\n" +
|
||||
" 0 byte 1 field1 \"Comment1\"\n" +
|
||||
// " 1 undefined 1 null \"\"\n" +
|
||||
|
@ -1310,7 +1439,7 @@ public class StructureDBTest extends AbstractGTest {
|
|||
|
||||
//@formatter:off
|
||||
CompositeTestUtils.assertExpectedComposite(this, "/Test\n" +
|
||||
"Unaligned\n" +
|
||||
"pack(disabled)\n" +
|
||||
"Structure Test {\n" +
|
||||
" 0 byte 1 field1 \"Comment1\"\n" +
|
||||
// " 1 undefined 1 null \"\"\n" +
|
||||
|
@ -1327,7 +1456,7 @@ public class StructureDBTest extends AbstractGTest {
|
|||
|
||||
//@formatter:off
|
||||
CompositeTestUtils.assertExpectedComposite(this, "/Test\n" +
|
||||
"Unaligned\n" +
|
||||
"pack(disabled)\n" +
|
||||
"Structure Test {\n" +
|
||||
" 0 byte 1 field1 \"Comment1\"\n" +
|
||||
// " 1 undefined 1 null \"\"\n" +
|
||||
|
@ -1344,7 +1473,7 @@ public class StructureDBTest extends AbstractGTest {
|
|||
|
||||
//@formatter:off
|
||||
CompositeTestUtils.assertExpectedComposite(this, "/Test\n" +
|
||||
"Unaligned\n" +
|
||||
"pack(disabled)\n" +
|
||||
"Structure Test {\n" +
|
||||
" 0 byte 1 field1 \"Comment1\"\n" +
|
||||
// " 1 undefined 1 null \"\"\n" +
|
||||
|
@ -1362,7 +1491,7 @@ public class StructureDBTest extends AbstractGTest {
|
|||
|
||||
//@formatter:off
|
||||
CompositeTestUtils.assertExpectedComposite(this, "/Test\n" +
|
||||
"Unaligned\n" +
|
||||
"pack(disabled)\n" +
|
||||
"Structure Test {\n" +
|
||||
" 0 byte 1 field1 \"Comment1\"\n" +
|
||||
// " 1 undefined 1 null \"\"\n" +
|
||||
|
@ -1380,7 +1509,7 @@ public class StructureDBTest extends AbstractGTest {
|
|||
|
||||
//@formatter:off
|
||||
CompositeTestUtils.assertExpectedComposite(this, "/Test\n" +
|
||||
"Unaligned\n" +
|
||||
"pack(disabled)\n" +
|
||||
"Structure Test {\n" +
|
||||
" 0 byte 1 field1 \"Comment1\"\n" +
|
||||
// " 1 undefined 1 null \"\"\n" +
|
||||
|
@ -1446,6 +1575,7 @@ public class StructureDBTest extends AbstractGTest {
|
|||
s.deleteAll();
|
||||
assertEquals(1, s.getLength());
|
||||
assertTrue(s.isNotYetDefined());
|
||||
assertTrue(s.isZeroLength());
|
||||
assertEquals(0, s.getNumComponents());
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,8 @@ import static org.junit.Assert.*;
|
|||
|
||||
import org.junit.*;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
import generic.test.AbstractGTest;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
@ -169,7 +171,7 @@ public class UnionDBTest extends AbstractGTest {
|
|||
|
||||
//@formatter:off
|
||||
CompositeTestUtils.assertExpectedComposite(this, "/TestUnion\n" +
|
||||
"Unaligned\n" +
|
||||
"pack(disabled)\n" +
|
||||
"Union TestUnion {\n" +
|
||||
" 0 short 2 null \"\"\n" +
|
||||
" 0 int:2(0) 1 bf1 \"bf1Comment\"\n" +
|
||||
|
@ -179,7 +181,7 @@ public class UnionDBTest extends AbstractGTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testAlignedBitFieldUnion() throws Exception {
|
||||
public void testPackedBitFieldUnion() throws Exception {
|
||||
|
||||
int cnt = union.getNumComponents();
|
||||
for (int i = 0; i < cnt; i++) {
|
||||
|
@ -187,11 +189,11 @@ public class UnionDBTest extends AbstractGTest {
|
|||
}
|
||||
union.insertBitField(0, IntegerDataType.dataType, 2, "bf1", "bf1Comment");
|
||||
union.insert(0, ShortDataType.dataType);
|
||||
union.setInternallyAligned(true);
|
||||
union.setPackingEnabled(true);
|
||||
|
||||
//@formatter:off
|
||||
CompositeTestUtils.assertExpectedComposite(this, "/TestUnion\n" +
|
||||
"Aligned\n" +
|
||||
"pack()\n" +
|
||||
"Union TestUnion {\n" +
|
||||
" 0 short 2 null \"\"\n" +
|
||||
" 0 int:2(0) 1 bf1 \"bf1Comment\"\n" +
|
||||
|
@ -208,7 +210,7 @@ public class UnionDBTest extends AbstractGTest {
|
|||
|
||||
//@formatter:off
|
||||
CompositeTestUtils.assertExpectedComposite(this, "/TestUnion\n" +
|
||||
"Unaligned\n" +
|
||||
"pack(disabled)\n" +
|
||||
"Union TestUnion {\n" +
|
||||
" 0 byte 1 field1 \"Comment1\"\n" +
|
||||
" 0 word 2 null \"Comment2\"\n" +
|
||||
|
@ -231,7 +233,7 @@ public class UnionDBTest extends AbstractGTest {
|
|||
|
||||
//@formatter:off
|
||||
CompositeTestUtils.assertExpectedComposite(this, "/TestUnion\n" +
|
||||
"Unaligned\n" +
|
||||
"pack(disabled)\n" +
|
||||
"Union TestUnion {\n" +
|
||||
" 0 byte 1 field1 \"Comment1\"\n" +
|
||||
" 0 word 2 null \"Comment2\"\n" +
|
||||
|
@ -255,7 +257,7 @@ public class UnionDBTest extends AbstractGTest {
|
|||
|
||||
//@formatter:off
|
||||
CompositeTestUtils.assertExpectedComposite(this, "/TestUnion\n" +
|
||||
"Unaligned\n" +
|
||||
"pack(disabled)\n" +
|
||||
"Union TestUnion {\n" +
|
||||
" 0 byte 1 field1 \"Comment1\"\n" +
|
||||
" 0 word 2 null \"Comment2\"\n" +
|
||||
|
@ -271,7 +273,7 @@ public class UnionDBTest extends AbstractGTest {
|
|||
|
||||
//@formatter:off
|
||||
CompositeTestUtils.assertExpectedComposite(this, "/TestUnion\n" +
|
||||
"Unaligned\n" +
|
||||
"pack(disabled)\n" +
|
||||
"Union TestUnion {\n" +
|
||||
" 0 byte 1 field1 \"Comment1\"\n" +
|
||||
" 0 word 2 null \"Comment2\"\n" +
|
||||
|
@ -294,7 +296,7 @@ public class UnionDBTest extends AbstractGTest {
|
|||
|
||||
//@formatter:off
|
||||
CompositeTestUtils.assertExpectedComposite(this, "/TestUnion\n" +
|
||||
"Unaligned\n" +
|
||||
"pack(disabled)\n" +
|
||||
"Union TestUnion {\n" +
|
||||
" 0 byte 1 field1 \"Comment1\"\n" +
|
||||
" 0 word 2 null \"Comment2\"\n" +
|
||||
|
@ -310,7 +312,7 @@ public class UnionDBTest extends AbstractGTest {
|
|||
|
||||
//@formatter:off
|
||||
CompositeTestUtils.assertExpectedComposite(this, "/TestUnion\n" +
|
||||
"Unaligned\n" +
|
||||
"pack(disabled)\n" +
|
||||
"Union TestUnion {\n" +
|
||||
" 0 byte 1 field1 \"Comment1\"\n" +
|
||||
" 0 word 2 null \"Comment2\"\n" +
|
||||
|
@ -357,6 +359,42 @@ public class UnionDBTest extends AbstractGTest {
|
|||
assertEquals(2, union.getLength());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteMany() throws Exception {
|
||||
Structure struct = createStructure("struct_1", 0);
|
||||
struct.add(new ByteDataType());
|
||||
struct.add(new StringDataType(), 10);
|
||||
union.add(struct);
|
||||
assertEquals(11, union.getLength());
|
||||
|
||||
//@formatter:off
|
||||
CompositeTestUtils.assertExpectedComposite(this, "/TestUnion\n" +
|
||||
"pack(disabled)\n" +
|
||||
"Union TestUnion {\n" +
|
||||
" 0 byte 1 field1 \"Comment1\"\n" +
|
||||
" 0 word 2 null \"Comment2\"\n" +
|
||||
" 0 dword 4 field3 \"\"\n" +
|
||||
" 0 byte 1 field4 \"Comment4\"\n" +
|
||||
" 0 struct_1 11 null \"\"\n" +
|
||||
"}\n" +
|
||||
"Size = 11 Actual Alignment = 1", union);
|
||||
//@formatter:on
|
||||
|
||||
union.delete(Sets.newHashSet(2, 4));
|
||||
|
||||
assertEquals(2, union.getLength());
|
||||
//@formatter:off
|
||||
CompositeTestUtils.assertExpectedComposite(this, "/TestUnion\n" +
|
||||
"pack(disabled)\n" +
|
||||
"Union TestUnion {\n" +
|
||||
" 0 byte 1 field1 \"Comment1\"\n" +
|
||||
" 0 word 2 null \"Comment2\"\n" +
|
||||
" 0 byte 1 field4 \"Comment4\"\n" +
|
||||
"}\n" +
|
||||
"Size = 2 Actual Alignment = 1", union);
|
||||
//@formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsPartOf() {
|
||||
Structure struct = createStructure("struct_1", 0);
|
||||
|
@ -388,7 +426,7 @@ public class UnionDBTest extends AbstractGTest {
|
|||
|
||||
//@formatter:off
|
||||
CompositeTestUtils.assertExpectedComposite(this, "/Replaced\n" +
|
||||
"Unaligned\n" +
|
||||
"pack(disabled)\n" +
|
||||
"Union Replaced {\n" +
|
||||
" 0 byte 1 field0 \"Comment1\"\n" +
|
||||
" 0 word 2 null \"Comment2\"\n" +
|
||||
|
@ -403,7 +441,7 @@ public class UnionDBTest extends AbstractGTest {
|
|||
|
||||
//@formatter:off
|
||||
CompositeTestUtils.assertExpectedComposite(this, "/TestUnion\n" +
|
||||
"Unaligned\n" +
|
||||
"pack(disabled)\n" +
|
||||
"Union TestUnion {\n" +
|
||||
" 0 byte 1 field0 \"Comment1\"\n" +
|
||||
" 0 word 2 null \"Comment2\"\n" +
|
||||
|
|
|
@ -128,6 +128,11 @@ public class TestDoubleDataType implements DataType {
|
|||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isZeroLength() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
throw new UnsupportedOperationException();
|
||||
|
@ -195,6 +200,11 @@ public class TestDoubleDataType implements DataType {
|
|||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dataTypeAlignmentChanged(DataType dt) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dataTypeDeleted(DataType dt) {
|
||||
throw new UnsupportedOperationException();
|
||||
|
|
|
@ -142,7 +142,7 @@ public class TestDoubleDataTypeManager implements DataTypeManager {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void dataTypeChanged(DataType dataType) {
|
||||
public void dataTypeChanged(DataType dataType, boolean isAutoChange) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
|
|
@ -156,7 +156,7 @@ public class TestDummyDataTypeManager implements DataTypeManager {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void dataTypeChanged(DataType dataType) {
|
||||
public void dataTypeChanged(DataType dataType, boolean isAutoChange) {
|
||||
// stub
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue