mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 19:42:36 +02:00
GT-3571 Numerous changes to datatype resolve/replace addressing
performance and conflict handling. Corrected composite merge deficiencies. Added datatype resolve/equivalence caches for performance improvement. Added deferred pointer resolution for structures and unions. Corrected datatype parent/child update
This commit is contained in:
parent
d5cc72fd14
commit
c2d9629f57
113 changed files with 3515 additions and 1853 deletions
|
@ -15,8 +15,7 @@
|
|||
*/
|
||||
package ghidra.app.plugin.core.datamgr.archive;
|
||||
|
||||
import ghidra.program.model.data.ArchiveType;
|
||||
import ghidra.program.model.data.DataTypeManager;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.UniversalID;
|
||||
|
||||
public class BuiltInSourceArchive implements SourceArchive {
|
||||
|
|
|
@ -20,7 +20,6 @@ import java.util.*;
|
|||
|
||||
import db.*;
|
||||
import db.util.ErrorHandler;
|
||||
import ghidra.framework.store.LockException;
|
||||
import ghidra.program.database.*;
|
||||
import ghidra.program.database.data.DataTypeManagerDB;
|
||||
import ghidra.program.database.map.*;
|
||||
|
@ -2140,7 +2139,7 @@ public class CodeManager implements ErrorHandler, ManagerDB {
|
|||
}
|
||||
if (dt instanceof Structure) {
|
||||
Structure structDt = (Structure) dt;
|
||||
for (DataTypeComponent component : structDt.getComponents()) {
|
||||
for (DataTypeComponent component : structDt.getDefinedComponents()) {
|
||||
if (containsAddressComponents(component.getDataType())) {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -184,9 +184,6 @@ class ArrayDB extends DataTypeDB implements Array {
|
|||
|
||||
@Override
|
||||
public boolean isEquivalent(DataType dt) {
|
||||
if (dt == null) {
|
||||
return false;
|
||||
}
|
||||
if (dt == this) {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -252,12 +252,14 @@ class CategoryDB extends DatabaseObject implements Category {
|
|||
mgr.lock.acquire();
|
||||
try {
|
||||
checkDeleted();
|
||||
dt = dt.clone(dt.getDataTypeManager());
|
||||
try {
|
||||
dt.setCategoryPath(getCategoryPath());
|
||||
}
|
||||
catch (DuplicateNameException e) {
|
||||
// can't happen here because we made a copy
|
||||
if (!getCategoryPath().equals(dt.getCategoryPath())) {
|
||||
dt = dt.clone(dt.getDataTypeManager());
|
||||
try {
|
||||
dt.setCategoryPath(getCategoryPath());
|
||||
}
|
||||
catch (DuplicateNameException e) {
|
||||
// can't happen here because we made a copy
|
||||
}
|
||||
}
|
||||
DataType resolvedDataType = mgr.resolve(dt, handler);
|
||||
return resolvedDataType;
|
||||
|
@ -427,6 +429,7 @@ class CategoryDB extends DatabaseObject implements Category {
|
|||
@Override
|
||||
public Category copyCategory(Category category, DataTypeConflictHandler handler,
|
||||
TaskMonitor monitor) {
|
||||
// TODO: source archive handling is not documented
|
||||
boolean isInSameArchive = (mgr == category.getDataTypeManager());
|
||||
mgr.lock.acquire();
|
||||
try {
|
||||
|
|
|
@ -45,11 +45,13 @@ abstract class CompositeDB extends DataTypeDB implements Composite {
|
|||
|
||||
/**
|
||||
* Constructor for a composite data type (structure or union).
|
||||
* @param dataMgr the data type manager containing this data type.
|
||||
* @param cache DataTypeDB object cache
|
||||
*
|
||||
* @param dataMgr the data type manager containing this data type.
|
||||
* @param cache DataTypeDB object cache
|
||||
* @param compositeAdapter the database adapter for this data type.
|
||||
* @param componentAdapter the database adapter for the components of this data type.
|
||||
* @param record the database record for this data type.
|
||||
* @param componentAdapter the database adapter for the components of this data
|
||||
* type.
|
||||
* @param record the database record for this data type.
|
||||
*/
|
||||
CompositeDB(DataTypeManagerDB dataMgr, DBObjectCache<DataTypeDB> cache,
|
||||
CompositeDBAdapter compositeAdapter, ComponentDBAdapter componentAdapter,
|
||||
|
@ -61,19 +63,21 @@ abstract class CompositeDB extends DataTypeDB implements Composite {
|
|||
}
|
||||
|
||||
/**
|
||||
* Perform initialization of instance fields during instantiation
|
||||
* or instance refresh
|
||||
* Perform initialization of instance fields during instantiation or instance
|
||||
* refresh
|
||||
*/
|
||||
protected abstract void initialize();
|
||||
|
||||
/**
|
||||
* Get the preferred length for a new component. For Unions and internally aligned
|
||||
* structures the preferred component length for a fixed-length dataType will be the
|
||||
* length of that dataType. Otherwise the length returned will be no larger than the
|
||||
* specified length.
|
||||
* Get the preferred length for a new component. For Unions and internally
|
||||
* aligned structures the preferred component length for a fixed-length dataType
|
||||
* will be the length of that dataType. Otherwise the length returned will be no
|
||||
* larger than the specified length.
|
||||
*
|
||||
* @param dataType new component datatype
|
||||
* @param length constrained length or -1 to force use of dataType size. Dynamic types
|
||||
* such as string must have a positive length specified.
|
||||
* @param length constrained length or -1 to force use of dataType size.
|
||||
* Dynamic types such as string must have a positive length
|
||||
* specified.
|
||||
* @return preferred component length
|
||||
*/
|
||||
protected int getPreferredComponentLength(DataType dataType, int length) {
|
||||
|
@ -106,12 +110,13 @@ abstract class CompositeDB extends DataTypeDB implements Composite {
|
|||
|
||||
/**
|
||||
* Handle replacement of datatype which may impact bitfield datatype.
|
||||
*
|
||||
* @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
|
||||
* @throws InvalidDataTypeException if bitfield was based upon oldDt but new datatype is
|
||||
* invalid for a bitfield
|
||||
* @param oldDt affected datatype which has been removed or replaced
|
||||
* @param newDt replacement datatype
|
||||
* @param true if bitfield component was modified
|
||||
* @throws InvalidDataTypeException if bitfield was based upon oldDt but new
|
||||
* datatype is invalid for a bitfield
|
||||
*/
|
||||
protected boolean updateBitFieldDataType(DataTypeComponentDB bitfieldComponent, DataType oldDt,
|
||||
DataType newDt) throws InvalidDataTypeException {
|
||||
|
@ -252,24 +257,36 @@ abstract class CompositeDB extends DataTypeDB implements Composite {
|
|||
}
|
||||
|
||||
/**
|
||||
* This method throws an exception if the indicated data type is an ancestor
|
||||
* of this data type. In other words, the specified data type has a component
|
||||
* or sub-component containing this data type.
|
||||
* This method throws an exception if the indicated data type is an ancestor of
|
||||
* this data type. In other words, the specified data type has a component or
|
||||
* sub-component containing this data type.
|
||||
*
|
||||
* @param dataType the data type
|
||||
* @throws IllegalArgumentException if the data type is an ancestor of this
|
||||
* data type.
|
||||
* @throws DataTypeDependencyException if the data type is an ancestor of this
|
||||
* data type.
|
||||
*/
|
||||
protected void checkAncestry(DataType dataType) {
|
||||
protected void checkAncestry(DataType dataType) throws DataTypeDependencyException {
|
||||
if (this.equals(dataType)) {
|
||||
throw new IllegalArgumentException(
|
||||
throw new DataTypeDependencyException(
|
||||
"Data type " + getDisplayName() + " can't contain itself.");
|
||||
}
|
||||
else if (DataTypeUtilities.isSecondPartOfFirst(dataType, this)) {
|
||||
throw new IllegalArgumentException("Data type " + dataType.getDisplayName() + " has " +
|
||||
getDisplayName() + " within it.");
|
||||
throw new DataTypeDependencyException("Data type " + dataType.getDisplayName() +
|
||||
" has " + getDisplayName() + " within it.");
|
||||
}
|
||||
}
|
||||
|
||||
protected DataType doCheckedResolve(DataType dt, DataTypeConflictHandler handler)
|
||||
throws DataTypeDependencyException {
|
||||
if (dt instanceof Pointer) {
|
||||
pointerPostResolveRequired = true;
|
||||
return resolve(((Pointer) dt).newPointer(DataType.DEFAULT));
|
||||
}
|
||||
dt = resolve(dt, handler);
|
||||
checkAncestry(dt);
|
||||
return dt;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doSetNameRecord(String name) throws IOException {
|
||||
record.setString(CompositeDBAdapter.COMPOSITE_NAME_COL, name);
|
||||
|
@ -277,8 +294,9 @@ abstract class CompositeDB extends DataTypeDB implements Composite {
|
|||
}
|
||||
|
||||
/**
|
||||
* This method throws an exception if the indicated data type is not
|
||||
* a valid data type for a component of this composite data type.
|
||||
* This method throws an exception if the indicated data type is not a valid
|
||||
* data type for a component of this composite data type.
|
||||
*
|
||||
* @param dataType the data type to be checked.
|
||||
* @throws IllegalArgumentException if the data type is invalid.
|
||||
*/
|
||||
|
@ -576,6 +594,30 @@ abstract class CompositeDB extends DataTypeDB implements Composite {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract DataTypeComponentDB[] getDefinedComponents();
|
||||
|
||||
@Override
|
||||
protected void postPointerResolve(DataType definitionDt, DataTypeConflictHandler handler) {
|
||||
Composite composite = (Composite) definitionDt;
|
||||
DataTypeComponent[] definedComponents = composite.getDefinedComponents();
|
||||
DataTypeComponentDB[] myDefinedComponents = getDefinedComponents();
|
||||
if (definedComponents.length != myDefinedComponents.length) {
|
||||
throw new IllegalArgumentException("mismatched definition datatype");
|
||||
}
|
||||
for (int i = 0; i < definedComponents.length; i++) {
|
||||
DataTypeComponent dtc = definedComponents[i];
|
||||
DataType dt = dtc.getDataType();
|
||||
if (dt instanceof Pointer) {
|
||||
DataTypeComponentDB myDtc = myDefinedComponents[i];
|
||||
myDtc.getDataType().removeParent(this);
|
||||
dt = dataMgr.resolve(dt, handler);
|
||||
myDtc.setDataType(dt);
|
||||
dt.addParent(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notification that this composite data type's alignment has changed.
|
||||
*/
|
||||
|
@ -649,10 +691,12 @@ abstract class CompositeDB extends DataTypeDB implements Composite {
|
|||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* 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
|
||||
*/
|
||||
protected abstract void adjustInternalAlignment(boolean notify);
|
||||
|
@ -665,11 +709,14 @@ abstract class CompositeDB extends DataTypeDB implements Composite {
|
|||
|
||||
/**
|
||||
* Dump all components for use in {@link #toString()} representation.
|
||||
*
|
||||
* @param buffer string buffer
|
||||
* @param pad padding to be used with each component output line
|
||||
* @param pad padding to be used with each component output line
|
||||
*/
|
||||
protected void dumpComponents(StringBuilder buffer, String pad) {
|
||||
for (DataTypeComponent dtc : getComponents()) {
|
||||
// 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());
|
||||
|
|
|
@ -128,6 +128,9 @@ class CompositeDBAdapterV2V3 extends CompositeDBAdapter {
|
|||
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;
|
||||
|
|
|
@ -30,7 +30,6 @@ import docking.framework.DockingApplicationConfiguration;
|
|||
import docking.widgets.label.GDLabel;
|
||||
import ghidra.GhidraApplicationLayout;
|
||||
import ghidra.GhidraLaunchable;
|
||||
import ghidra.app.plugin.core.datamgr.archive.SourceArchive;
|
||||
import ghidra.framework.Application;
|
||||
import ghidra.framework.ApplicationConfiguration;
|
||||
import ghidra.program.model.data.*;
|
||||
|
@ -472,8 +471,7 @@ public class DataTypeArchiveTransformer implements GhidraLaunchable {
|
|||
}
|
||||
|
||||
private static DataTypeComponent getNamedComponent(Composite composite, String fieldName) {
|
||||
DataTypeComponent[] components = composite.getComponents();
|
||||
for (DataTypeComponent dataTypeComponent : components) {
|
||||
for (DataTypeComponent dataTypeComponent : composite.getDefinedComponents()) {
|
||||
if (fieldName.equals(dataTypeComponent.getFieldName())) {
|
||||
return dataTypeComponent; // found match so return it.
|
||||
}
|
||||
|
|
|
@ -23,7 +23,6 @@ import javax.swing.event.ChangeEvent;
|
|||
import javax.swing.event.ChangeListener;
|
||||
|
||||
import db.Record;
|
||||
import ghidra.app.plugin.core.datamgr.archive.SourceArchive;
|
||||
import ghidra.docking.settings.Settings;
|
||||
import ghidra.docking.settings.SettingsDefinition;
|
||||
import ghidra.program.database.DBObjectCache;
|
||||
|
@ -46,6 +45,7 @@ abstract class DataTypeDB extends DatabaseObject implements DataType, ChangeList
|
|||
private volatile Settings defaultSettings;
|
||||
private final static SettingsDefinition[] EMPTY_DEFINITIONS = new SettingsDefinition[0];
|
||||
protected boolean resolving;
|
||||
protected boolean pointerPostResolveRequired;
|
||||
protected Lock lock;
|
||||
private volatile String name;
|
||||
private volatile Category category;
|
||||
|
@ -64,41 +64,46 @@ abstract class DataTypeDB extends DatabaseObject implements DataType, ChangeList
|
|||
}
|
||||
|
||||
/**
|
||||
* Subclasses implement this to either read the name from the database record or compute
|
||||
* if it is a derived name such as a pointer or array. Implementers can assume that
|
||||
* the database lock will be acquired when this method is called.
|
||||
* Subclasses implement this to either read the name from the database record or
|
||||
* compute if it is a derived name such as a pointer or array. Implementers can
|
||||
* assume that the database lock will be acquired when this method is called.
|
||||
*/
|
||||
protected abstract String doGetName();
|
||||
|
||||
/**
|
||||
* Subclasses implement this to read the category path from the database record.Implementers can assume that
|
||||
* the database lock will be acquired when this method is called.
|
||||
* Subclasses implement this to read the category path from the database
|
||||
* record.Implementers can assume that the database lock will be acquired when
|
||||
* this method is called.
|
||||
*/
|
||||
protected abstract long doGetCategoryID();
|
||||
|
||||
/**
|
||||
* Subclasses implement this to update the category path ID to the database. Implementers can assume that
|
||||
* the database lock will be acquired when this method is called.
|
||||
* Subclasses implement this to update the category path ID to the database.
|
||||
* Implementers can assume that the database lock will be acquired when this
|
||||
* method is called.
|
||||
*/
|
||||
protected abstract void doSetCategoryPathRecord(long categoryID) throws IOException;
|
||||
|
||||
/**
|
||||
* Subclasses implement this to update the to the database. Implementers can assume that
|
||||
* the database lock will be acquired when this method is called.
|
||||
* Subclasses implement this to update the to the database. Implementers can
|
||||
* assume that the database lock will be acquired when this method is called.
|
||||
*
|
||||
* @param newName new data type name
|
||||
*/
|
||||
protected abstract void doSetNameRecord(String newName)
|
||||
throws IOException, InvalidNameException;
|
||||
|
||||
/**
|
||||
* Subclasses implement this to read the source archive id from the record. Implementers can assume that
|
||||
* the database lock will be acquired when this method is called.
|
||||
* Subclasses implement this to read the source archive id from the record.
|
||||
* Implementers can assume that the database lock will be acquired when this
|
||||
* method is called.
|
||||
*/
|
||||
protected abstract UniversalID getSourceArchiveID();
|
||||
|
||||
/**
|
||||
* Subclasses implement this to update the source archive id from the record. Implementers can assume that
|
||||
* the database lock will be acquired when this method is called.
|
||||
* Subclasses implement this to update the source archive id from the record.
|
||||
* Implementers can assume that the database lock will be acquired when this
|
||||
* method is called.
|
||||
*/
|
||||
protected abstract void setSourceArchiveID(UniversalID id);
|
||||
|
||||
|
@ -145,9 +150,9 @@ abstract class DataTypeDB extends DatabaseObject implements DataType, ChangeList
|
|||
}
|
||||
|
||||
/**
|
||||
* Get the current name without refresh.
|
||||
* This is intended to be used for event generation when an old-name
|
||||
* is needed.
|
||||
* Get the current name without refresh. This is intended to be used for event
|
||||
* generation when an old-name is needed.
|
||||
*
|
||||
* @return old name
|
||||
*/
|
||||
protected final String getOldName() {
|
||||
|
@ -177,13 +182,12 @@ abstract class DataTypeDB extends DatabaseObject implements DataType, ChangeList
|
|||
}
|
||||
|
||||
/**
|
||||
* Set the data in the form of the appropriate Object for
|
||||
* this DataType.
|
||||
* Set the data in the form of the appropriate Object for this DataType.
|
||||
*
|
||||
* @param buf the data buffer.
|
||||
* @param buf the data buffer.
|
||||
* @param settings the display settings for the current value.
|
||||
* @param length the number of bytes to set the value from.
|
||||
* @param value the new value to set object
|
||||
* @param length the number of bytes to set the value from.
|
||||
* @param value the new value to set object
|
||||
*/
|
||||
|
||||
public void setValue(MemBuffer buf, Settings settings, int length, Object value) {
|
||||
|
@ -219,9 +223,7 @@ abstract class DataTypeDB extends DatabaseObject implements DataType, ChangeList
|
|||
*/
|
||||
@Override
|
||||
public void stateChanged(ChangeEvent e) {
|
||||
if (dataMgr != null) {
|
||||
dataMgr.dataTypeChanged(this);
|
||||
}
|
||||
dataMgr.dataTypeChanged(this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -266,21 +268,26 @@ abstract class DataTypeDB extends DatabaseObject implements DataType, ChangeList
|
|||
}
|
||||
|
||||
protected DataType resolve(DataType dt) {
|
||||
return resolve(dt, null);
|
||||
return resolve(dt, dataMgr.getCurrentConflictHandler());
|
||||
}
|
||||
|
||||
protected DataType resolve(DataType dt, DataTypeConflictHandler handler) {
|
||||
if (dataMgr != null) {
|
||||
resolving = true;
|
||||
// complex types should keep equivalence checks to a minimum while resolving
|
||||
// and when post-resolve required for pointers
|
||||
resolving = true;
|
||||
try {
|
||||
dt = dataMgr.resolve(dt, handler);
|
||||
}
|
||||
finally {
|
||||
resolving = false;
|
||||
}
|
||||
return dt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.data.DataType#getCategoryPath()
|
||||
*/
|
||||
protected void postPointerResolve(DataType definitionDt, DataTypeConflictHandler handler) {
|
||||
throw new UnsupportedOperationException("post-resolve of pointers not implemented");
|
||||
}
|
||||
|
||||
@Override
|
||||
public CategoryPath getCategoryPath() {
|
||||
validate(lock);
|
||||
|
@ -374,9 +381,6 @@ abstract class DataTypeDB extends DatabaseObject implements DataType, ChangeList
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.data.DataType#setNameAndCategory(ghidra.program.model.data.CategoryPath, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public void setNameAndCategory(CategoryPath path, String name)
|
||||
throws InvalidNameException, DuplicateNameException {
|
||||
|
@ -388,12 +392,14 @@ abstract class DataTypeDB extends DatabaseObject implements DataType, ChangeList
|
|||
"DataType named " + name + " already exists in category " + path.getPath());
|
||||
}
|
||||
|
||||
// generate a name that would not cause a duplicate in either the current path or
|
||||
// the new path. Use the new name if possible.
|
||||
// generate a name that would not cause a duplicate in either the current path
|
||||
// or
|
||||
// the new path. Use the new name if possible.
|
||||
String uniqueName = dataMgr.getUniqueName(path, getCategoryPath(), name);
|
||||
doSetName(uniqueName);
|
||||
|
||||
// set the path - this is guaranteed to work since we make a name that won't conflict
|
||||
// set the path - this is guaranteed to work since we make a name that won't
|
||||
// conflict
|
||||
doSetCategoryPath(path);
|
||||
|
||||
// now, if necessary, rename it to the desired name - guaranteed to work since
|
||||
|
@ -409,15 +415,13 @@ abstract class DataTypeDB extends DatabaseObject implements DataType, ChangeList
|
|||
|
||||
/**
|
||||
* Updates the path for this datatype
|
||||
*
|
||||
* @param dt the dataType whose path has changed.
|
||||
*/
|
||||
protected void updatePath(DataTypeDB dt) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.data.DataType#addParent(ghidra.program.model.data.DataType)
|
||||
*/
|
||||
@Override
|
||||
public void addParent(DataType dt) {
|
||||
if (dt instanceof DataTypeDB && dt.getDataTypeManager() == dataMgr) {
|
||||
|
@ -425,9 +429,6 @@ abstract class DataTypeDB extends DatabaseObject implements DataType, ChangeList
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.data.DataType#removeParent(ghidra.program.model.data.DataType)
|
||||
*/
|
||||
@Override
|
||||
public void removeParent(DataType dt) {
|
||||
if (dt instanceof DataTypeDB && dt.getDataTypeManager() == dataMgr) {
|
||||
|
@ -455,9 +456,6 @@ abstract class DataTypeDB extends DatabaseObject implements DataType, ChangeList
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.data.DataType#getParents()
|
||||
*/
|
||||
@Override
|
||||
public DataType[] getParents() {
|
||||
List<DataType> parents = dataMgr.getParentDataTypes(key);
|
||||
|
@ -465,9 +463,6 @@ abstract class DataTypeDB extends DatabaseObject implements DataType, ChangeList
|
|||
return parents.toArray(array);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.data.DataType#dependsOn(ghidra.program.model.data.DataType)
|
||||
*/
|
||||
@Override
|
||||
public boolean dependsOn(DataType dt) {
|
||||
return false;
|
||||
|
@ -522,9 +517,10 @@ abstract class DataTypeDB extends DatabaseObject implements DataType, ChangeList
|
|||
}
|
||||
|
||||
/**
|
||||
* Sets a String briefly describing this DataType.
|
||||
* <br>If a data type that extends this class wants to allow the description to be changed,
|
||||
* then it must override this method.
|
||||
* Sets a String briefly describing this DataType. <br>
|
||||
* If a data type that extends this class wants to allow the description to be
|
||||
* changed, then it must override this method.
|
||||
*
|
||||
* @param description a one-liner describing this DataType.
|
||||
*/
|
||||
@Override
|
||||
|
@ -533,11 +529,15 @@ abstract class DataTypeDB extends DatabaseObject implements DataType, ChangeList
|
|||
}
|
||||
|
||||
/**
|
||||
* setUniversalID is a package level method that allows you to change a data type's
|
||||
* universal ID. This is only intended to be used when transforming a newly parsed data type
|
||||
* archive so that it can be used as a replacement of the archive from a previous software release.
|
||||
* @param oldUniversalID the old universal ID value that the user is already referencing
|
||||
* with their data types. This is the universal ID that we want the new data type to be known by.
|
||||
* setUniversalID is a package level method that allows you to change a data
|
||||
* type's universal ID. This is only intended to be used when transforming a
|
||||
* newly parsed data type archive so that it can be used as a replacement of the
|
||||
* archive from a previous software release.
|
||||
*
|
||||
* @param oldUniversalID the old universal ID value that the user is already
|
||||
* referencing with their data types. This is the
|
||||
* universal ID that we want the new data type to be known
|
||||
* by.
|
||||
*/
|
||||
abstract void setUniversalID(UniversalID oldUniversalID);
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -18,7 +18,6 @@ package ghidra.program.database.data;
|
|||
import java.util.*;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import ghidra.app.plugin.core.datamgr.archive.SourceArchive;
|
||||
import ghidra.docking.settings.Settings;
|
||||
import ghidra.program.model.address.GlobalNamespace;
|
||||
import ghidra.program.model.data.*;
|
||||
|
@ -157,30 +156,37 @@ public class DataTypeUtilities {
|
|||
if (firstDataType.equals(secondDataType)) {
|
||||
return true;
|
||||
}
|
||||
else if (firstDataType instanceof Array) {
|
||||
if (firstDataType instanceof Array) {
|
||||
DataType elementDataType = ((Array) firstDataType).getDataType();
|
||||
return isSecondPartOfFirst(elementDataType, secondDataType);
|
||||
}
|
||||
else if (firstDataType instanceof TypeDef) {
|
||||
if (firstDataType instanceof TypeDef) {
|
||||
DataType innerDataType = ((TypeDef) firstDataType).getDataType();
|
||||
return isSecondPartOfFirst(innerDataType, secondDataType);
|
||||
}
|
||||
else if (firstDataType instanceof Composite) {
|
||||
if (firstDataType instanceof Composite) {
|
||||
Composite compositeDataType = (Composite) firstDataType;
|
||||
int numComponents = compositeDataType.getNumComponents();
|
||||
for (int i = 0; i < numComponents; i++) {
|
||||
DataTypeComponent dtc = compositeDataType.getComponent(i);
|
||||
for (DataTypeComponent dtc : compositeDataType.getDefinedComponents()) {
|
||||
DataType dataTypeToCheck = dtc.getDataType();
|
||||
if (isSecondPartOfFirst(dataTypeToCheck, secondDataType)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (firstDataType instanceof Structure) {
|
||||
DataTypeComponent flexDtc = ((Structure) firstDataType).getFlexibleArrayComponent();
|
||||
if (flexDtc != null && isSecondPartOfFirst(flexDtc.getDataType(), secondDataType)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the two dataTypes have the same sourceArchive and the same UniversalID.
|
||||
* Returns true if the two dataTypes have the same sourceArchive and the same UniversalID
|
||||
* @param dataType1 first data type
|
||||
* @param dataType2 second data type
|
||||
* @return true if types correspond to the same type from a source archive
|
||||
*/
|
||||
public static boolean isSameDataType(DataType dataType1, DataType dataType2) {
|
||||
UniversalID id1 = dataType1.getUniversalID();
|
||||
|
@ -203,10 +209,15 @@ public class DataTypeUtilities {
|
|||
/**
|
||||
* Returns true if the two dataTypes have the same sourceArchive and the same UniversalID OR
|
||||
* are equivalent
|
||||
* @param dataType1 first data type (if invoked by DB object or manager, this argument
|
||||
* must correspond to the DataTypeDB).
|
||||
* @param dataType2 second data type
|
||||
* @return true if types correspond to the same type from a source archive
|
||||
* or they are equivelent, otherwise false
|
||||
*/
|
||||
public static boolean isSameOrEquivalentDataType(DataType dataType1, DataType dataType2) {
|
||||
// if they contain datatypes that have same ids, then they represent the same dataType
|
||||
if (DataTypeUtilities.isSameDataType(dataType1, dataType2)) {
|
||||
if (isSameDataType(dataType1, dataType2)) {
|
||||
return true;
|
||||
}
|
||||
// otherwise, check if they are equivalent
|
||||
|
|
|
@ -46,7 +46,7 @@ class EnumDB extends DataTypeDB implements Enum {
|
|||
private List<BitGroup> bitGroups;
|
||||
|
||||
EnumDB(DataTypeManagerDB dataMgr, DBObjectCache<DataTypeDB> cache, EnumDBAdapter adapter,
|
||||
EnumValueDBAdapter valueAdapter, Record record) throws IOException {
|
||||
EnumValueDBAdapter valueAdapter, Record record) {
|
||||
super(dataMgr, cache, record);
|
||||
this.adapter = adapter;
|
||||
this.valueAdapter = valueAdapter;
|
||||
|
@ -86,8 +86,8 @@ class EnumDB extends DataTypeDB implements Enum {
|
|||
|
||||
long[] ids = valueAdapter.getValueIdsInEnum(key);
|
||||
|
||||
for (int i = 0; i < ids.length; i++) {
|
||||
Record rec = valueAdapter.getRecord(ids[i]);
|
||||
for (long id : ids) {
|
||||
Record rec = valueAdapter.getRecord(id);
|
||||
String valueName = rec.getString(EnumValueDBAdapter.ENUMVAL_NAME_COL);
|
||||
long value = rec.getLongValue(EnumValueDBAdapter.ENUMVAL_VALUE_COL);
|
||||
addToCache(valueName, value);
|
||||
|
@ -252,10 +252,10 @@ class EnumDB extends DataTypeDB implements Enum {
|
|||
|
||||
long[] ids = valueAdapter.getValueIdsInEnum(key);
|
||||
|
||||
for (int i = 0; i < ids.length; i++) {
|
||||
Record rec = valueAdapter.getRecord(ids[i]);
|
||||
for (long id : ids) {
|
||||
Record rec = valueAdapter.getRecord(id);
|
||||
if (valueName.equals(rec.getString(EnumValueDBAdapter.ENUMVAL_NAME_COL))) {
|
||||
valueAdapter.removeRecord(ids[i]);
|
||||
valueAdapter.removeRecord(id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -285,8 +285,8 @@ class EnumDB extends DataTypeDB implements Enum {
|
|||
valueMap = new HashMap<>();
|
||||
|
||||
long[] ids = valueAdapter.getValueIdsInEnum(key);
|
||||
for (int i = 0; i < ids.length; i++) {
|
||||
valueAdapter.removeRecord(ids[i]);
|
||||
for (long id : ids) {
|
||||
valueAdapter.removeRecord(id);
|
||||
}
|
||||
|
||||
int oldLength = getLength();
|
||||
|
@ -298,11 +298,11 @@ class EnumDB extends DataTypeDB implements Enum {
|
|||
}
|
||||
|
||||
String[] names = enumm.getNames();
|
||||
for (int i = 0; i < names.length; i++) {
|
||||
long value = enumm.getValue(names[i]);
|
||||
valueAdapter.createRecord(key, names[i], value);
|
||||
for (String name2 : names) {
|
||||
long value = enumm.getValue(name2);
|
||||
valueAdapter.createRecord(key, name2, value);
|
||||
adapter.updateRecord(record, true);
|
||||
addToCache(names[i], value);
|
||||
addToCache(name2, value);
|
||||
}
|
||||
|
||||
if (oldLength != newLength) {
|
||||
|
|
|
@ -177,15 +177,24 @@ class FunctionDefinitionDB extends DataTypeDB implements FunctionDefinition {
|
|||
}
|
||||
|
||||
private void doReplaceWith(FunctionDefinition functionDefinition) {
|
||||
setArguments(functionDefinition.getArguments());
|
||||
|
||||
lock.acquire();
|
||||
try {
|
||||
setReturnType(functionDefinition.getReturnType());
|
||||
checkDeleted();
|
||||
|
||||
setArguments(functionDefinition.getArguments());
|
||||
try {
|
||||
setReturnType(functionDefinition.getReturnType());
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
setReturnType(DEFAULT);
|
||||
}
|
||||
setVarArgs(functionDefinition.hasVarArgs());
|
||||
setGenericCallingConvention(functionDefinition.getGenericCallingConvention());
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
setReturnType(DEFAULT);
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
setVarArgs(functionDefinition.hasVarArgs());
|
||||
setGenericCallingConvention(functionDefinition.getGenericCallingConvention());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -251,7 +260,7 @@ class FunctionDefinitionDB extends DataTypeDB implements FunctionDefinition {
|
|||
for (int i = 0; i < args.length; i++) {
|
||||
DataType type =
|
||||
ParameterDefinitionImpl.validateDataType(args[i].getDataType(), dataMgr, false);
|
||||
DataType resolvedDt = resolve(type);
|
||||
DataType resolvedDt = resolve(type, dataMgr.getCurrentConflictHandler());
|
||||
paramAdapter.createRecord(dataMgr.getID(resolvedDt), key, i, args[i].getName(),
|
||||
args[i].getComment(), args[i].getLength());
|
||||
resolvedDt.addParent(this);
|
||||
|
@ -278,7 +287,7 @@ class FunctionDefinitionDB extends DataTypeDB implements FunctionDefinition {
|
|||
if (type == null) {
|
||||
type = DataType.DEFAULT;
|
||||
}
|
||||
DataType resolvedDt = resolve(type);
|
||||
DataType resolvedDt = resolve(type, dataMgr.getCurrentConflictHandler());
|
||||
record.setLongValue(FunctionDefinitionDBAdapter.FUNCTION_DEF_RETURN_ID_COL,
|
||||
dataMgr.getID(resolvedDt));
|
||||
funDefAdapter.updateRecord(record, true);
|
||||
|
@ -332,22 +341,35 @@ class FunctionDefinitionDB extends DataTypeDB implements FunctionDefinition {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean isEquivalent(DataType dt) {
|
||||
if (dt == this) {
|
||||
public boolean isEquivalent(DataType dataType) {
|
||||
|
||||
if (dataType == this) {
|
||||
return true;
|
||||
}
|
||||
if (!(dt instanceof FunctionDefinition)) {
|
||||
if (!(dataType instanceof FunctionDefinition)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
checkIsValid();
|
||||
if (resolving) {
|
||||
if (dt.getUniversalID().equals(getUniversalID())) {
|
||||
if (resolving) { // actively resolving children
|
||||
if (dataType.getUniversalID().equals(getUniversalID())) {
|
||||
return true;
|
||||
}
|
||||
return DataTypeUtilities.equalsIgnoreConflict(getPathName(), dt.getPathName());
|
||||
return DataTypeUtilities.equalsIgnoreConflict(getPathName(), dataType.getPathName());
|
||||
}
|
||||
return isEquivalentSignature((FunctionSignature) dt);
|
||||
|
||||
Boolean isEquivalent = dataMgr.getCachedEquivalence(this, dataType);
|
||||
if (isEquivalent != null) {
|
||||
return isEquivalent;
|
||||
}
|
||||
|
||||
try {
|
||||
isEquivalent = isEquivalentSignature((FunctionSignature) dataType);
|
||||
}
|
||||
finally {
|
||||
dataMgr.putCachedEquivalence(this, dataType, isEquivalent);
|
||||
}
|
||||
return isEquivalent;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -360,15 +382,15 @@ class FunctionDefinitionDB extends DataTypeDB implements FunctionDefinition {
|
|||
if ((DataTypeUtilities.equalsIgnoreConflict(signature.getName(), getName())) &&
|
||||
((comment == null && myComment == null) ||
|
||||
(comment != null && comment.equals(myComment))) &&
|
||||
(DataTypeUtilities.isSameOrEquivalentDataType(signature.getReturnType(),
|
||||
getReturnType())) &&
|
||||
(DataTypeUtilities.isSameOrEquivalentDataType(getReturnType(),
|
||||
signature.getReturnType())) &&
|
||||
(getGenericCallingConvention() == signature.getGenericCallingConvention()) &&
|
||||
(hasVarArgs() == signature.hasVarArgs())) {
|
||||
ParameterDefinition[] args = signature.getArguments();
|
||||
ParameterDefinition[] thisArgs = this.getArguments();
|
||||
if (args.length == thisArgs.length) {
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
if (!args[i].isEquivalent(thisArgs[i])) {
|
||||
if (!thisArgs[i].isEquivalent(args[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -450,7 +472,7 @@ class FunctionDefinitionDB extends DataTypeDB implements FunctionDefinition {
|
|||
param.getDataType().removeParent(this);
|
||||
paramAdapter.removeRecord(param.getKey());
|
||||
}
|
||||
DataType rdt = resolve(dt);
|
||||
DataType rdt = resolve(dt, dataMgr.getCurrentConflictHandler());
|
||||
rdt.addParent(this);
|
||||
paramAdapter.createRecord(dataMgr.getID(rdt), key, ordinal, name, comment,
|
||||
dt.getLength());
|
||||
|
@ -652,4 +674,9 @@ class FunctionDefinitionDB extends DataTypeDB implements FunctionDefinition {
|
|||
lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getPrototypeString(true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,14 +40,15 @@ class PointerDB extends DataTypeDB implements Pointer {
|
|||
private String displayName;
|
||||
|
||||
/**
|
||||
* <code>isEquivalentActive</code> is used to break cyclical recursion
|
||||
* when performing an {@link #isEquivalent(DataType)} checks on pointers
|
||||
* which must also check the base datatype equivelency.
|
||||
* <code>isEquivalentActive</code> is used to break cyclical recursion when
|
||||
* performing an {@link #isEquivalent(DataType)} checks on pointers which must
|
||||
* also check the base datatype equivelency.
|
||||
*/
|
||||
private ThreadLocal<Boolean> isEquivalentActive = ThreadLocal.withInitial(() -> Boolean.FALSE);
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param dataMgr
|
||||
* @param cache
|
||||
* @param adapter
|
||||
|
@ -307,6 +308,15 @@ class PointerDB extends DataTypeDB implements Pointer {
|
|||
return false;
|
||||
}
|
||||
|
||||
// TODO: The pointer deep-dive equivalence checking on the referenced datatype can
|
||||
// cause types containing pointers (composites, functions) to conflict when in
|
||||
// reality the referenced type simply has multiple implementations which differ.
|
||||
// Although without doing this Ghidra may fail to resolve dependencies which differ
|
||||
// from those already contained within a datatype manager.
|
||||
// Ghidra's rigid datatype relationships prevent the flexibility to handle
|
||||
// multiple implementations of a named datatype without inducing a conflicted
|
||||
// datatype hierarchy.
|
||||
|
||||
if (isEquivalentActive.get()) {
|
||||
return true;
|
||||
}
|
||||
|
@ -359,11 +369,12 @@ class PointerDB extends DataTypeDB implements Pointer {
|
|||
/**
|
||||
* @see ghidra.program.model.data.DataType#setCategoryPath(ghidra.program.model.data.CategoryPath)
|
||||
*
|
||||
* Note: this does get called, but in a tricky way. If externally, someone calls
|
||||
* setCategoryPath, nothing happens because it is overridden in this class to do nothing.
|
||||
* However, if updatePath is called, then this method calls super.setCategoryPath which
|
||||
* bypasses the "overriddenness" of setCategoryPath, resulting in this method getting called.
|
||||
|
||||
* Note: this does get called, but in a tricky way. If externally, someone
|
||||
* calls setCategoryPath, nothing happens because it is overridden in this
|
||||
* class to do nothing. However, if updatePath is called, then this method
|
||||
* calls super.setCategoryPath which bypasses the "overriddenness" of
|
||||
* setCategoryPath, resulting in this method getting called.
|
||||
*
|
||||
*/
|
||||
@Override
|
||||
protected void doSetCategoryPathRecord(long categoryID) throws IOException {
|
||||
|
|
|
@ -20,7 +20,7 @@ import java.util.Iterator;
|
|||
import java.util.List;
|
||||
|
||||
import db.*;
|
||||
import ghidra.app.plugin.core.datamgr.archive.SourceArchive;
|
||||
import ghidra.program.model.data.SourceArchive;
|
||||
import ghidra.util.UniversalID;
|
||||
import ghidra.util.exception.VersionException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -16,8 +15,8 @@
|
|||
*/
|
||||
package ghidra.program.database.data;
|
||||
|
||||
import ghidra.app.plugin.core.datamgr.archive.SourceArchive;
|
||||
import ghidra.program.model.data.DataTypeManager;
|
||||
import ghidra.program.model.data.SourceArchive;
|
||||
import ghidra.util.UniversalID;
|
||||
import ghidra.util.exception.VersionException;
|
||||
|
||||
|
|
|
@ -19,8 +19,8 @@ import java.io.IOException;
|
|||
import java.util.*;
|
||||
|
||||
import db.*;
|
||||
import ghidra.app.plugin.core.datamgr.archive.SourceArchive;
|
||||
import ghidra.program.model.data.DataTypeManager;
|
||||
import ghidra.program.model.data.SourceArchive;
|
||||
import ghidra.util.UniversalID;
|
||||
import ghidra.util.exception.VersionException;
|
||||
|
||||
|
|
|
@ -18,11 +18,9 @@ package ghidra.program.database.data;
|
|||
import java.io.IOException;
|
||||
|
||||
import db.Record;
|
||||
import ghidra.app.plugin.core.datamgr.archive.SourceArchive;
|
||||
import ghidra.program.database.DBObjectCache;
|
||||
import ghidra.program.database.DatabaseObject;
|
||||
import ghidra.program.model.data.ArchiveType;
|
||||
import ghidra.program.model.data.DataTypeManager;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.Lock;
|
||||
import ghidra.util.UniversalID;
|
||||
|
||||
|
|
|
@ -18,9 +18,7 @@ package ghidra.program.database.data;
|
|||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import ghidra.app.plugin.core.datamgr.archive.SourceArchive;
|
||||
import ghidra.program.model.data.ArchiveType;
|
||||
import ghidra.program.model.data.DataTypeManager;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.lang.CompilerSpec;
|
||||
import ghidra.program.model.lang.CompilerSpecID;
|
||||
import ghidra.util.UniversalID;
|
||||
|
|
|
@ -26,7 +26,6 @@ import ghidra.program.model.data.AlignedStructurePacker.StructurePackResult;
|
|||
import ghidra.program.model.mem.MemBuffer;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.exception.AssertException;
|
||||
import ghidra.util.exception.InvalidInputException;
|
||||
|
||||
/**
|
||||
* Structure implementation for the Database.
|
||||
|
@ -47,6 +46,7 @@ class StructureDB extends CompositeDB implements Structure {
|
|||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param dataMgr
|
||||
* @param cache
|
||||
* @param compositeAdapter
|
||||
|
@ -96,73 +96,59 @@ class StructureDB extends CompositeDB implements Structure {
|
|||
}
|
||||
|
||||
@Override
|
||||
public DataTypeComponent add(DataType dataType, int length, String name, String comment) {
|
||||
return doAdd(dataType, length, false, name, comment, true);
|
||||
public DataTypeComponent add(DataType dataType, int length, String name, String comment)
|
||||
throws IllegalArgumentException {
|
||||
try {
|
||||
return doAdd(dataType, length, name, comment, true);
|
||||
}
|
||||
catch (DataTypeDependencyException e) {
|
||||
throw new IllegalArgumentException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private DataTypeComponent doAdd(DataType dataType, int length, boolean isFlexibleArray,
|
||||
String name, String comment, boolean alignAndNotify) {
|
||||
private DataTypeComponent doAdd(DataType dataType, int length, String name, String comment,
|
||||
boolean validateAlignAndNotify)
|
||||
throws DataTypeDependencyException, IllegalArgumentException {
|
||||
lock.acquire();
|
||||
try {
|
||||
checkDeleted();
|
||||
|
||||
validateDataType(dataType);
|
||||
|
||||
dataType = resolve(dataType);
|
||||
checkAncestry(dataType);
|
||||
if (validateAlignAndNotify) {
|
||||
validateDataType(dataType);
|
||||
dataType = resolve(dataType, null);
|
||||
checkAncestry(dataType);
|
||||
}
|
||||
|
||||
DataTypeComponentDB dtc = null;
|
||||
try {
|
||||
if (dataType == DataType.DEFAULT && !isFlexibleArray) {
|
||||
if (dataType == DataType.DEFAULT) {
|
||||
dtc = new DataTypeComponentDB(dataMgr, componentAdapter, this, key,
|
||||
numComponents, structLength);
|
||||
}
|
||||
else {
|
||||
|
||||
int offset = structLength;
|
||||
int ordinal = numComponents;
|
||||
|
||||
int componentLength;
|
||||
if (isFlexibleArray) {
|
||||
// assume trailing flexible array component
|
||||
offset = -1;
|
||||
ordinal = -1;
|
||||
if (flexibleArrayComponent != null) {
|
||||
flexibleArrayComponent.getDataType().removeParent(this);
|
||||
componentAdapter.removeRecord(flexibleArrayComponent.getKey());
|
||||
flexibleArrayComponent = null;
|
||||
}
|
||||
componentLength = 0;
|
||||
}
|
||||
else {
|
||||
componentLength = getPreferredComponentLength(dataType, length);
|
||||
}
|
||||
|
||||
int componentLength = getPreferredComponentLength(dataType, length);
|
||||
Record rec = componentAdapter.createRecord(dataMgr.getResolvedID(dataType), key,
|
||||
componentLength, ordinal, offset, name, comment);
|
||||
componentLength, numComponents, structLength, name, comment);
|
||||
dtc = new DataTypeComponentDB(dataMgr, componentAdapter, this, rec);
|
||||
dataType.addParent(this);
|
||||
if (isFlexibleArray) {
|
||||
flexibleArrayComponent = dtc;
|
||||
}
|
||||
else {
|
||||
components.add(dtc);
|
||||
}
|
||||
components.add(dtc);
|
||||
}
|
||||
if (!isFlexibleArray) {
|
||||
|
||||
int structureGrowth = dtc.getLength();
|
||||
if (!isInternallyAligned() && length > 0) {
|
||||
structureGrowth = length;
|
||||
}
|
||||
int structureGrowth = dtc.getLength();
|
||||
if (!isInternallyAligned() && length > 0) {
|
||||
structureGrowth = length;
|
||||
}
|
||||
|
||||
++numComponents;
|
||||
structLength += structureGrowth;
|
||||
|
||||
if (validateAlignAndNotify) {
|
||||
|
||||
record.setIntValue(CompositeDBAdapter.COMPOSITE_NUM_COMPONENTS_COL,
|
||||
++numComponents);
|
||||
structLength += structureGrowth;
|
||||
numComponents);
|
||||
record.setIntValue(CompositeDBAdapter.COMPOSITE_LENGTH_COL, structLength);
|
||||
compositeAdapter.updateRecord(record, true);
|
||||
}
|
||||
if (alignAndNotify) {
|
||||
|
||||
adjustInternalAlignment(false);
|
||||
notifySizeChanged();
|
||||
}
|
||||
|
@ -177,6 +163,60 @@ class StructureDB extends CompositeDB implements Structure {
|
|||
}
|
||||
}
|
||||
|
||||
private DataTypeComponent doAddFlexArray(DataType dataType, String name, String comment,
|
||||
boolean validateAlignAndNotify)
|
||||
throws DataTypeDependencyException, IllegalArgumentException {
|
||||
lock.acquire();
|
||||
try {
|
||||
checkDeleted();
|
||||
|
||||
if (validateAlignAndNotify) {
|
||||
validateDataType(dataType);
|
||||
dataType = resolve(dataType, null);
|
||||
if (isInvalidFlexArrayDataType(dataType)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Unsupported flexType: " + dataType.getDisplayName());
|
||||
}
|
||||
checkAncestry(dataType);
|
||||
}
|
||||
|
||||
DataTypeComponentDB dtc = null;
|
||||
try {
|
||||
|
||||
int oldLength = structLength;
|
||||
|
||||
if (flexibleArrayComponent != null) {
|
||||
flexibleArrayComponent.getDataType().removeParent(this);
|
||||
componentAdapter.removeRecord(flexibleArrayComponent.getKey());
|
||||
flexibleArrayComponent = null;
|
||||
}
|
||||
|
||||
Record rec = componentAdapter.createRecord(dataMgr.getResolvedID(dataType), key, 0,
|
||||
-1, -1, name, comment);
|
||||
dtc = new DataTypeComponentDB(dataMgr, componentAdapter, this, rec);
|
||||
dataType.addParent(this);
|
||||
flexibleArrayComponent = dtc;
|
||||
|
||||
if (validateAlignAndNotify) {
|
||||
adjustInternalAlignment(false);
|
||||
if (oldLength != structLength) {
|
||||
notifySizeChanged();
|
||||
}
|
||||
else {
|
||||
dataMgr.dataTypeChanged(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
dataMgr.dbError(e);
|
||||
}
|
||||
return dtc;
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void growStructure(int amount) {
|
||||
lock.acquire();
|
||||
|
@ -237,7 +277,7 @@ class StructureDB extends CompositeDB implements Structure {
|
|||
if (idx > 0) {
|
||||
DataTypeComponentDB existingDtc = components.get(idx);
|
||||
if (existingDtc.isBitFieldComponent()) {
|
||||
// must shift down to eliminate possible overlap with previous component
|
||||
// must shift down to eliminate possible overlap with previous component
|
||||
DataTypeComponentDB previousDtc = components.get(idx - 1);
|
||||
if (previousDtc.getEndOffset() == existingDtc.getOffset()) {
|
||||
shiftOffsets(idx, 0, 1);
|
||||
|
@ -268,6 +308,9 @@ class StructureDB extends CompositeDB implements Structure {
|
|||
notifySizeChanged();
|
||||
return dtc;
|
||||
}
|
||||
catch (DataTypeDependencyException e) {
|
||||
throw new IllegalArgumentException(e.getMessage(), e);
|
||||
}
|
||||
catch (IOException e) {
|
||||
dataMgr.dbError(e);
|
||||
}
|
||||
|
@ -642,9 +685,11 @@ class StructureDB extends CompositeDB implements Structure {
|
|||
}
|
||||
|
||||
/**
|
||||
* Create copy of structure for target dtm (source archive information is discarded).
|
||||
* WARNING! copying unaligned structures which contain bitfields can produce
|
||||
* invalid results when switching endianess due to the differences in packing order.
|
||||
* Create copy of structure for target dtm (source archive information is
|
||||
* discarded). WARNING! copying unaligned structures which contain bitfields can
|
||||
* produce invalid results when switching endianess due to the differences in
|
||||
* packing order.
|
||||
*
|
||||
* @param dtm target data type manager
|
||||
* @return cloned structure
|
||||
*/
|
||||
|
@ -660,7 +705,9 @@ class StructureDB extends CompositeDB implements Structure {
|
|||
/**
|
||||
* Create cloned structure for target dtm preserving source archive information.
|
||||
* WARNING! cloning unaligned structures which contain bitfields can produce
|
||||
* invalid results when switching endianess due to the differences in packing order.
|
||||
* invalid results when switching endianess due to the differences in packing
|
||||
* order.
|
||||
*
|
||||
* @param dtm target data type manager
|
||||
* @return cloned structure
|
||||
*/
|
||||
|
@ -746,12 +793,13 @@ class StructureDB extends CompositeDB implements Structure {
|
|||
}
|
||||
|
||||
/**
|
||||
* Backup from specified ordinal to the first component which contains
|
||||
* the specified offset. For normal components the specified
|
||||
* ordinal will be returned, however for bit-fields the ordinal of the first
|
||||
* bit-field containing the specified offset will be returned.
|
||||
* Backup from specified ordinal to the first component which contains the
|
||||
* specified offset. For normal components the specified ordinal will be
|
||||
* returned, however for bit-fields the ordinal of the first bit-field
|
||||
* containing the specified offset will be returned.
|
||||
*
|
||||
* @param ordinal component ordinal
|
||||
* @param offset offset within structure
|
||||
* @param offset offset within structure
|
||||
* @return index of first defined component containing specific offset.
|
||||
*/
|
||||
private int backupToFirstComponentContainingOffset(int index, int offset) {
|
||||
|
@ -771,12 +819,13 @@ class StructureDB extends CompositeDB implements Structure {
|
|||
}
|
||||
|
||||
/**
|
||||
* Advance from specified ordinal to the last component which contains
|
||||
* the specified offset. For normal components the specified
|
||||
* ordinal will be returned, however for bit-fields the ordinal of the last
|
||||
* bit-field containing the specified offset will be returned.
|
||||
* Advance from specified ordinal to the last component which contains the
|
||||
* specified offset. For normal components the specified ordinal will be
|
||||
* returned, however for bit-fields the ordinal of the last bit-field containing
|
||||
* the specified offset will be returned.
|
||||
*
|
||||
* @param ordinal component ordinal
|
||||
* @param offset offset within structure
|
||||
* @param offset offset within structure
|
||||
* @return index of last defined component containing specific offset.
|
||||
*/
|
||||
private int advanceToLastComponentContainingOffset(int index, int offset) {
|
||||
|
@ -887,11 +936,11 @@ class StructureDB extends CompositeDB implements Structure {
|
|||
}
|
||||
|
||||
@Override
|
||||
public DataTypeComponent[] getDefinedComponents() {
|
||||
public DataTypeComponentDB[] getDefinedComponents() {
|
||||
lock.acquire();
|
||||
try {
|
||||
checkIsValid();
|
||||
return components.toArray(new DataTypeComponent[components.size()]);
|
||||
return components.toArray(new DataTypeComponentDB[components.size()]);
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
|
@ -899,13 +948,14 @@ class StructureDB extends CompositeDB implements Structure {
|
|||
}
|
||||
|
||||
@Override
|
||||
public final DataTypeComponent insertAtOffset(int offset, DataType dataType, int length) {
|
||||
public final DataTypeComponent insertAtOffset(int offset, DataType dataType, int length)
|
||||
throws IllegalArgumentException {
|
||||
return insertAtOffset(offset, dataType, length, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataTypeComponent insertAtOffset(int offset, DataType dataType, int length, String name,
|
||||
String comment) {
|
||||
String comment) throws IllegalArgumentException {
|
||||
|
||||
if (offset < 0) {
|
||||
throw new IllegalArgumentException("Offset cannot be negative.");
|
||||
|
@ -978,6 +1028,9 @@ class StructureDB extends CompositeDB implements Structure {
|
|||
notifySizeChanged();
|
||||
return dtc;
|
||||
}
|
||||
catch (DataTypeDependencyException e) {
|
||||
throw new IllegalArgumentException(e.getMessage(), e);
|
||||
}
|
||||
catch (IOException e) {
|
||||
dataMgr.dbError(e);
|
||||
}
|
||||
|
@ -989,7 +1042,7 @@ class StructureDB extends CompositeDB implements Structure {
|
|||
|
||||
@Override
|
||||
public DataTypeComponent replace(int ordinal, DataType dataType, int length, String name,
|
||||
String comment) {
|
||||
String comment) throws IllegalArgumentException {
|
||||
lock.acquire();
|
||||
try {
|
||||
checkDeleted();
|
||||
|
@ -1021,19 +1074,23 @@ class StructureDB extends CompositeDB implements Structure {
|
|||
adjustInternalAlignment(true);
|
||||
return replaceComponent;
|
||||
}
|
||||
catch (DataTypeDependencyException e) {
|
||||
throw new IllegalArgumentException(e.getMessage(), e);
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final DataTypeComponent replace(int ordinal, DataType dataType, int length) {
|
||||
public final DataTypeComponent replace(int ordinal, DataType dataType, int length)
|
||||
throws IllegalArgumentException {
|
||||
return replace(ordinal, dataType, length, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataTypeComponent replaceAtOffset(int offset, DataType dataType, int length, String name,
|
||||
String comment) {
|
||||
String comment) throws IllegalArgumentException {
|
||||
if (offset < 0) {
|
||||
throw new IllegalArgumentException("Offset cannot be negative.");
|
||||
}
|
||||
|
@ -1071,6 +1128,9 @@ class StructureDB extends CompositeDB implements Structure {
|
|||
adjustInternalAlignment(true);
|
||||
return replaceComponent;
|
||||
}
|
||||
catch (DataTypeDependencyException e) {
|
||||
throw new IllegalArgumentException(e.getMessage(), e);
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
|
@ -1079,12 +1139,14 @@ class StructureDB extends CompositeDB implements Structure {
|
|||
/**
|
||||
* Replaces the internal components of this structure with components of the
|
||||
* given structure.
|
||||
*
|
||||
* @param dataType the structure to get the component information from.
|
||||
* @throws IllegalArgumentException if any of the component data types
|
||||
* are not allowed to replace a component in this composite data type.
|
||||
* 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.
|
||||
* @throws IllegalArgumentException if any of the component data types are not
|
||||
* allowed to replace a component in this
|
||||
* composite data type. 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.
|
||||
* @see ghidra.program.database.data.DataTypeDB#replaceWith(ghidra.program.model.data.DataType)
|
||||
*/
|
||||
@Override
|
||||
|
@ -1092,92 +1154,130 @@ class StructureDB extends CompositeDB implements Structure {
|
|||
if (!(dataType instanceof Structure)) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
doReplaceWith((Structure) dataType, true, null);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param struct
|
||||
* @param notify
|
||||
* @param handler
|
||||
*/
|
||||
void doReplaceWith(Structure struct, boolean notify, DataTypeConflictHandler handler) {
|
||||
lock.acquire();
|
||||
boolean isResolveCacheOwner = dataMgr.activateResolveCache();
|
||||
try {
|
||||
checkDeleted();
|
||||
|
||||
int oldLength = structLength;
|
||||
int oldMinAlignment = getMinimumAlignment();
|
||||
|
||||
for (int i = 0; i < components.size(); i++) {
|
||||
DataTypeComponentDB dtc = components.get(i);
|
||||
dtc.getDataType().removeParent(this);
|
||||
componentAdapter.removeRecord(dtc.getKey());
|
||||
}
|
||||
components.clear();
|
||||
numComponents = 0;
|
||||
structLength = 0;
|
||||
|
||||
if (flexibleArrayComponent != null) {
|
||||
flexibleArrayComponent.getDataType().removeParent(this);
|
||||
componentAdapter.removeRecord(flexibleArrayComponent.getKey());
|
||||
flexibleArrayComponent = null;
|
||||
}
|
||||
|
||||
setAlignment(struct, false);
|
||||
|
||||
if (struct.isInternallyAligned()) {
|
||||
doReplaceWithAligned(struct);
|
||||
}
|
||||
else {
|
||||
doReplaceWithUnaligned(struct);
|
||||
}
|
||||
|
||||
DataTypeComponent flexComponent = struct.getFlexibleArrayComponent();
|
||||
if (flexComponent != null) {
|
||||
setFlexibleArrayComponent(flexComponent.getDataType(), flexComponent.getFieldName(),
|
||||
flexComponent.getComment());
|
||||
}
|
||||
|
||||
record.setIntValue(CompositeDBAdapter.COMPOSITE_NUM_COMPONENTS_COL, numComponents);
|
||||
record.setIntValue(CompositeDBAdapter.COMPOSITE_LENGTH_COL, structLength);
|
||||
|
||||
compositeAdapter.updateRecord(record, false);
|
||||
|
||||
if (notify) {
|
||||
if (oldMinAlignment != getMinimumAlignment()) {
|
||||
notifyAlignmentChanged();
|
||||
}
|
||||
else if (oldLength != structLength) {
|
||||
notifySizeChanged();
|
||||
}
|
||||
else {
|
||||
dataMgr.dataTypeChanged(this);
|
||||
}
|
||||
}
|
||||
doReplaceWith((Structure) dataType, true, dataMgr.getCurrentConflictHandler());
|
||||
}
|
||||
catch (DataTypeDependencyException e) {
|
||||
throw new IllegalArgumentException(e.getMessage(), e);
|
||||
}
|
||||
catch (IOException e) {
|
||||
dataMgr.dbError(e);
|
||||
}
|
||||
finally {
|
||||
if (isResolveCacheOwner) {
|
||||
dataMgr.flushResolveCacheAndClearQueue(null);
|
||||
}
|
||||
lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
private void doReplaceWithAligned(Structure struct) {
|
||||
/**
|
||||
* Perform component replacement.
|
||||
*
|
||||
* @param struct
|
||||
* @param notify
|
||||
* @param handler
|
||||
* @return true if fully completed else false if pointer component post resolve
|
||||
* required
|
||||
* @throws DataTypeDependencyException
|
||||
* @throws IOException
|
||||
*/
|
||||
void doReplaceWith(Structure struct, boolean notify, DataTypeConflictHandler handler)
|
||||
throws DataTypeDependencyException, IOException {
|
||||
|
||||
// pre-resolved component types to catch dependency issues early
|
||||
DataTypeComponent flexComponent = struct.getFlexibleArrayComponent();
|
||||
DataTypeComponent[] otherComponents = struct.getDefinedComponents();
|
||||
DataType[] resolvedDts = new DataType[otherComponents.length];
|
||||
for (int i = 0; i < otherComponents.length; i++) {
|
||||
resolvedDts[i] = doCheckedResolve(otherComponents[i].getDataType(), handler);
|
||||
}
|
||||
DataType resolvedFlexDt = null;
|
||||
if (flexComponent != null) {
|
||||
resolvedFlexDt = doCheckedResolve(flexComponent.getDataType(), handler);
|
||||
if (isInvalidFlexArrayDataType(resolvedFlexDt)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Unsupported flexType: " + resolvedFlexDt.getDisplayName());
|
||||
}
|
||||
}
|
||||
|
||||
int oldLength = structLength;
|
||||
int oldMinAlignment = getMinimumAlignment();
|
||||
|
||||
for (int i = 0; i < components.size(); i++) {
|
||||
DataTypeComponentDB dtc = components.get(i);
|
||||
dtc.getDataType().removeParent(this);
|
||||
componentAdapter.removeRecord(dtc.getKey());
|
||||
}
|
||||
components.clear();
|
||||
numComponents = 0;
|
||||
structLength = 0;
|
||||
|
||||
if (flexibleArrayComponent != null) {
|
||||
flexibleArrayComponent.getDataType().removeParent(this);
|
||||
componentAdapter.removeRecord(flexibleArrayComponent.getKey());
|
||||
flexibleArrayComponent = null;
|
||||
}
|
||||
|
||||
setAlignment(struct, false);
|
||||
|
||||
if (struct.isInternallyAligned()) {
|
||||
doReplaceWithAligned(struct, resolvedDts);
|
||||
}
|
||||
else {
|
||||
doReplaceWithUnaligned(struct, resolvedDts);
|
||||
}
|
||||
|
||||
if (flexComponent != null) {
|
||||
doAddFlexArray(resolvedFlexDt, flexComponent.getFieldName(), flexComponent.getComment(),
|
||||
false);
|
||||
}
|
||||
|
||||
record.setIntValue(CompositeDBAdapter.COMPOSITE_NUM_COMPONENTS_COL, numComponents);
|
||||
record.setIntValue(CompositeDBAdapter.COMPOSITE_LENGTH_COL, structLength);
|
||||
|
||||
compositeAdapter.updateRecord(record, false);
|
||||
|
||||
adjustInternalAlignment(false);
|
||||
|
||||
if (notify) {
|
||||
if (oldMinAlignment != getMinimumAlignment()) {
|
||||
notifyAlignmentChanged();
|
||||
}
|
||||
else if (oldLength != structLength) {
|
||||
notifySizeChanged();
|
||||
}
|
||||
else {
|
||||
dataMgr.dataTypeChanged(this);
|
||||
}
|
||||
}
|
||||
|
||||
if (pointerPostResolveRequired) {
|
||||
dataMgr.queuePostResolve(this, struct);
|
||||
}
|
||||
}
|
||||
|
||||
private void doReplaceWithAligned(Structure struct, DataType[] resolvedDts) {
|
||||
// assumes components is clear and that alignment characteristics have been set
|
||||
DataTypeComponent[] otherComponents = struct.getDefinedComponents();
|
||||
for (int i = 0; i < otherComponents.length; i++) {
|
||||
DataTypeComponent dtc = otherComponents[i];
|
||||
DataType dt = dtc.getDataType();
|
||||
int length = (dt instanceof Dynamic) ? dtc.getLength() : -1;
|
||||
doAdd(dt, length, false, dtc.getFieldName(), dtc.getComment(), false);
|
||||
try {
|
||||
doAdd(resolvedDts[i], length, dtc.getFieldName(), dtc.getComment(), false);
|
||||
}
|
||||
catch (DataTypeDependencyException e) {
|
||||
throw new AssertException(e); // ancestry check already performed by caller
|
||||
}
|
||||
}
|
||||
adjustInternalAlignment(false);
|
||||
dataMgr.dataTypeChanged(this);
|
||||
}
|
||||
|
||||
private void doReplaceWithUnaligned(Structure struct) throws IOException {
|
||||
private void doReplaceWithUnaligned(Structure struct, DataType[] resolvedDts)
|
||||
throws IOException {
|
||||
// assumes components is clear and that alignment characteristics have been set.
|
||||
if (struct.isNotYetDefined()) {
|
||||
return;
|
||||
|
@ -1190,8 +1290,7 @@ class StructureDB extends CompositeDB implements Structure {
|
|||
for (int i = 0; i < otherComponents.length; i++) {
|
||||
DataTypeComponent dtc = otherComponents[i];
|
||||
|
||||
DataType dt = resolve(dtc.getDataType());
|
||||
checkAncestry(dt);
|
||||
DataType dt = resolvedDts[i]; // ancestry check already performed by caller
|
||||
|
||||
int length = getPreferredComponentLength(dt, dtc.getLength());
|
||||
|
||||
|
@ -1205,6 +1304,28 @@ class StructureDB extends CompositeDB implements Structure {
|
|||
adjustComponents(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void postPointerResolve(DataType definitionDt, DataTypeConflictHandler handler) {
|
||||
|
||||
Structure struct = (Structure) definitionDt;
|
||||
if (struct.hasFlexibleArrayComponent() != hasFlexibleArrayComponent()) {
|
||||
throw new IllegalArgumentException("mismatched definition datatype");
|
||||
}
|
||||
|
||||
super.postPointerResolve(definitionDt, handler);
|
||||
|
||||
if (flexibleArrayComponent != null) {
|
||||
DataTypeComponent flexDtc = struct.getFlexibleArrayComponent();
|
||||
DataType dt = flexDtc.getDataType();
|
||||
if (dt instanceof Pointer) {
|
||||
flexibleArrayComponent.getDataType().removeParent(this);
|
||||
dt = dataMgr.resolve(dt, handler);
|
||||
flexibleArrayComponent.setDataType(dt);
|
||||
dt.addParent(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dataTypeDeleted(DataType dt) {
|
||||
lock.acquire();
|
||||
|
@ -1261,7 +1382,7 @@ class StructureDB extends CompositeDB implements Structure {
|
|||
DataTypeComponentDB dtc = components.get(i);
|
||||
int nextIndex = i + 1;
|
||||
if (dtc.getDataType() == dt) {
|
||||
// assume no impact to bitfields since base types
|
||||
// assume no impact to bitfields since base types
|
||||
// should not change size
|
||||
int dtLen = dt.getLength();
|
||||
int dtcLen = dtc.getLength();
|
||||
|
@ -1304,62 +1425,74 @@ class StructureDB extends CompositeDB implements Structure {
|
|||
|
||||
@Override
|
||||
public boolean isEquivalent(DataType dataType) {
|
||||
|
||||
if (dataType == this) {
|
||||
return true;
|
||||
}
|
||||
if (dataType == null || !(dataType instanceof Structure)) {
|
||||
if (!(dataType instanceof Structure)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
checkIsValid();
|
||||
if (resolving) {
|
||||
if (resolving) { // actively resolving children
|
||||
if (dataType.getUniversalID().equals(getUniversalID())) {
|
||||
return true;
|
||||
}
|
||||
return DataTypeUtilities.equalsIgnoreConflict(getPathName(), dataType.getPathName());
|
||||
}
|
||||
Structure struct = (Structure) dataType;
|
||||
if (isInternallyAligned() != struct.isInternallyAligned() ||
|
||||
isDefaultAligned() != struct.isDefaultAligned() ||
|
||||
isMachineAligned() != struct.isMachineAligned() ||
|
||||
getMinimumAlignment() != struct.getMinimumAlignment() ||
|
||||
getPackingValue() != struct.getPackingValue() ||
|
||||
(!isInternallyAligned() && (getLength() != struct.getLength()))) {
|
||||
return false;
|
||||
|
||||
Boolean isEquivalent = dataMgr.getCachedEquivalence(this, dataType);
|
||||
if (isEquivalent != null) {
|
||||
return isEquivalent;
|
||||
}
|
||||
|
||||
DataTypeComponent myFlexComp = getFlexibleArrayComponent();
|
||||
DataTypeComponent otherFlexComp = struct.getFlexibleArrayComponent();
|
||||
if (myFlexComp != null) {
|
||||
if (otherFlexComp == null || !myFlexComp.isEquivalent(otherFlexComp)) {
|
||||
try {
|
||||
isEquivalent = false;
|
||||
Structure struct = (Structure) dataType;
|
||||
if (isInternallyAligned() != struct.isInternallyAligned() ||
|
||||
isDefaultAligned() != struct.isDefaultAligned() ||
|
||||
isMachineAligned() != struct.isMachineAligned() ||
|
||||
getMinimumAlignment() != struct.getMinimumAlignment() ||
|
||||
getPackingValue() != struct.getPackingValue() ||
|
||||
(!isInternallyAligned() && (getLength() != struct.getLength()))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (otherFlexComp != null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int myNumComps = getNumComponents();
|
||||
int otherNumComps = struct.getNumComponents();
|
||||
if (myNumComps != otherNumComps) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < myNumComps; i++) {
|
||||
DataTypeComponent myDtc = getComponent(i);
|
||||
DataTypeComponent otherDtc = struct.getComponent(i);
|
||||
|
||||
if (!myDtc.isEquivalent(otherDtc)) {
|
||||
DataTypeComponent myFlexComp = getFlexibleArrayComponent();
|
||||
DataTypeComponent otherFlexComp = struct.getFlexibleArrayComponent();
|
||||
if (myFlexComp != null) {
|
||||
if (otherFlexComp == null || !myFlexComp.isEquivalent(otherFlexComp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (otherFlexComp != null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int myNumComps = getNumComponents();
|
||||
int otherNumComps = struct.getNumComponents();
|
||||
if (myNumComps != otherNumComps) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < myNumComps; i++) {
|
||||
DataTypeComponent myDtc = getComponent(i);
|
||||
DataTypeComponent otherDtc = struct.getComponent(i);
|
||||
if (!myDtc.isEquivalent(otherDtc)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
isEquivalent = true;
|
||||
}
|
||||
finally {
|
||||
dataMgr.putCachedEquivalence(this, dataType, isEquivalent);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param definedComponentIndex the index of the defined component that is consuming the bytes.
|
||||
* @param numBytes the number of undefined bytes to consume
|
||||
* @param definedComponentIndex the index of the defined component that is
|
||||
* consuming the bytes.
|
||||
* @param numBytes the number of undefined bytes to consume
|
||||
* @return the number of bytes actually consumed
|
||||
*/
|
||||
private int consumeBytesAfter(int definedComponentIndex, int numBytes) {
|
||||
|
@ -1422,19 +1555,20 @@ class StructureDB extends CompositeDB implements Structure {
|
|||
}
|
||||
|
||||
/**
|
||||
* Replace the indicated component with a new component containing the
|
||||
* specified data type. Flex-array component not handled.
|
||||
* @param origDtc the original data type component in this structure.
|
||||
* Replace the indicated component with a new component containing the specified
|
||||
* data type. Flex-array component not handled.
|
||||
*
|
||||
* @param origDtc the original data type component in this structure.
|
||||
* @param resolvedDataType the data type of the new component
|
||||
* @param length the length of the new component
|
||||
* @param name the field name of the new component
|
||||
* @param comment the comment for the new component
|
||||
* @param length the length of the new component
|
||||
* @param name the field name of the new component
|
||||
* @param comment the comment for the new component
|
||||
* @return the new component or null if the new component couldn't fit.
|
||||
*/
|
||||
private DataTypeComponent replaceComponent(DataTypeComponent origDtc, DataType resolvedDataType,
|
||||
int length, String name, String comment, boolean doNotify) {
|
||||
|
||||
// FIXME: Unsure how o support replace operation with bit-fields. Within unaligned structure
|
||||
// FIXME: Unsure how to support replace operation with bit-fields. Within unaligned structure
|
||||
// the packing behavior for bit-fields prevents a one-for-one replacement and things may shift
|
||||
// around which the unaligned structure tries to avoid. Insert and delete are less of a concern
|
||||
// since movement already can occur, although insert at offset may not retain the offset if it
|
||||
|
@ -1506,8 +1640,9 @@ class StructureDB extends CompositeDB implements Structure {
|
|||
|
||||
/**
|
||||
* Gets the number of Undefined bytes beginning at the indicated component
|
||||
* ordinal. Undefined bytes that have a field name or comment specified are
|
||||
* also included.
|
||||
* ordinal. Undefined bytes that have a field name or comment specified are also
|
||||
* included.
|
||||
*
|
||||
* @param ordinal the component ordinal to begin checking at.
|
||||
* @return the number of contiguous undefined bytes
|
||||
*/
|
||||
|
@ -1653,7 +1788,8 @@ class StructureDB extends CompositeDB implements Structure {
|
|||
comp.setLength(len, true);
|
||||
shiftOffsets(nextIndex, -bytesNeeded, 0);
|
||||
}
|
||||
else if (comp.getOrdinal() == getLastDefinedComponentIndex()) { // we are the last defined component, grow structure
|
||||
else if (comp.getOrdinal() == getLastDefinedComponentIndex()) {
|
||||
// we are the last defined component, grow structure
|
||||
doGrowStructure(bytesNeeded - bytesAvailable);
|
||||
comp.setLength(len, true);
|
||||
shiftOffsets(nextIndex, -bytesNeeded, 0);
|
||||
|
@ -1711,8 +1847,9 @@ class StructureDB extends CompositeDB implements Structure {
|
|||
}
|
||||
|
||||
/**
|
||||
* <code>ComponentComparator</code> provides ability to compare two DataTypeComponent objects
|
||||
* based upon their ordinal. Intended to be used to sort components based upon ordinal.
|
||||
* <code>ComponentComparator</code> provides ability to compare two
|
||||
* DataTypeComponent objects based upon their ordinal. Intended to be used to
|
||||
* sort components based upon ordinal.
|
||||
*/
|
||||
private static class ComponentComparator implements Comparator<DataTypeComponent> {
|
||||
@Override
|
||||
|
@ -1722,15 +1859,17 @@ class StructureDB extends CompositeDB implements Structure {
|
|||
}
|
||||
|
||||
/**
|
||||
* Adjust the alignment, packing and padding of components within this structure based upon the
|
||||
* current alignment and packing attributes for this structure. This method should be
|
||||
* called to basically fix up the layout of the internal components of the structure
|
||||
* after other code has changed the attributes of the structure.
|
||||
* <BR>When switching between internally aligned and unaligned this method corrects the
|
||||
* component ordinal numbering also.
|
||||
* @param notify if true this method will do data type change notification
|
||||
* when it changes the layout of the components or when it changes the
|
||||
* overall size of the structure.
|
||||
* Adjust the alignment, packing and padding of components within this structure
|
||||
* based upon the current alignment and packing attributes for this structure.
|
||||
* This method should be called to basically fix up the layout of the internal
|
||||
* components of the structure after other code has changed the attributes of
|
||||
* the structure. <BR>
|
||||
* When switching between internally aligned and unaligned this method corrects
|
||||
* the component ordinal numbering also.
|
||||
*
|
||||
* @param notify if true this method will do data type change notification when
|
||||
* it changes the layout of the components or when it changes the
|
||||
* overall size of the structure.
|
||||
* @return true if the structure was changed by this method.
|
||||
*/
|
||||
private boolean adjustComponents(boolean notify) {
|
||||
|
@ -1858,7 +1997,7 @@ class StructureDB extends CompositeDB implements Structure {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void pack(int packingSize) throws InvalidInputException {
|
||||
public void pack(int packingSize) {
|
||||
setPackingValue(packingSize);
|
||||
}
|
||||
|
||||
|
@ -1873,7 +2012,7 @@ class StructureDB extends CompositeDB implements Structure {
|
|||
}
|
||||
|
||||
@Override
|
||||
public DataTypeComponent getFlexibleArrayComponent() {
|
||||
public DataTypeComponentDB getFlexibleArrayComponent() {
|
||||
return flexibleArrayComponent;
|
||||
}
|
||||
|
||||
|
@ -1885,12 +2024,17 @@ class StructureDB extends CompositeDB implements Structure {
|
|||
|
||||
@Override
|
||||
public DataTypeComponent setFlexibleArrayComponent(DataType flexType, String name,
|
||||
String comment) {
|
||||
String comment) throws IllegalArgumentException {
|
||||
if (isInvalidFlexArrayDataType(flexType)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Unsupported flexType: " + flexType.getDisplayName());
|
||||
}
|
||||
return doAdd(flexType, 0, true, name, comment, true);
|
||||
try {
|
||||
return doAddFlexArray(flexType, name, comment, true);
|
||||
}
|
||||
catch (DataTypeDependencyException e) {
|
||||
throw new IllegalArgumentException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -27,8 +27,6 @@ import ghidra.util.Msg;
|
|||
|
||||
/**
|
||||
* Database implementation for the Union data type.
|
||||
*
|
||||
*
|
||||
*/
|
||||
class UnionDB extends CompositeDB implements Union {
|
||||
|
||||
|
@ -38,6 +36,7 @@ class UnionDB extends CompositeDB implements Union {
|
|||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param dataMgr
|
||||
* @param cache
|
||||
* @param compositeAdapter
|
||||
|
@ -57,8 +56,8 @@ class UnionDB extends CompositeDB implements Union {
|
|||
|
||||
try {
|
||||
long[] ids = componentAdapter.getComponentIdsInComposite(key);
|
||||
for (int i = 0; i < ids.length; i++) {
|
||||
Record rec = componentAdapter.getRecord(ids[i]);
|
||||
for (long id : ids) {
|
||||
Record rec = componentAdapter.getRecord(id);
|
||||
components.add(new DataTypeComponentDB(dataMgr, componentAdapter, this, rec));
|
||||
}
|
||||
}
|
||||
|
@ -84,14 +83,18 @@ class UnionDB extends CompositeDB implements Union {
|
|||
}
|
||||
|
||||
@Override
|
||||
public DataTypeComponent add(DataType dataType, int length, String name, String comment) {
|
||||
public DataTypeComponent add(DataType dataType, int length, String componentName,
|
||||
String comment) throws IllegalArgumentException {
|
||||
lock.acquire();
|
||||
try {
|
||||
checkDeleted();
|
||||
DataTypeComponent dtc = doAdd(dataType, length, name, comment);
|
||||
DataTypeComponent dtc = doAdd(dataType, length, componentName, comment, true);
|
||||
adjustLength(true, true);
|
||||
return dtc;
|
||||
}
|
||||
catch (DataTypeDependencyException e) {
|
||||
throw new IllegalArgumentException(e.getMessage(), e);
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
|
@ -117,14 +120,17 @@ class UnionDB extends CompositeDB implements Union {
|
|||
return length;
|
||||
}
|
||||
|
||||
private DataTypeComponent doAdd(DataType dataType, int length, String name, String comment) {
|
||||
private DataTypeComponent doAdd(DataType dataType, int length, String name, String comment,
|
||||
boolean validateAlignAndNotify) throws DataTypeDependencyException {
|
||||
|
||||
validateDataType(dataType);
|
||||
|
||||
dataType = adjustBitField(dataType);
|
||||
|
||||
dataType = resolve(dataType);
|
||||
checkAncestry(dataType);
|
||||
if (validateAlignAndNotify) {
|
||||
dataType = resolve(dataType);
|
||||
checkAncestry(dataType);
|
||||
}
|
||||
|
||||
length = getPreferredComponentLength(dataType, length);
|
||||
|
||||
|
@ -161,7 +167,7 @@ class UnionDB extends CompositeDB implements Union {
|
|||
|
||||
@Override
|
||||
public DataTypeComponent insert(int ordinal, DataType dataType, int length, String name,
|
||||
String comment) {
|
||||
String comment) throws IllegalArgumentException {
|
||||
lock.acquire();
|
||||
try {
|
||||
checkDeleted();
|
||||
|
@ -183,6 +189,9 @@ class UnionDB extends CompositeDB implements Union {
|
|||
adjustLength(true, true);
|
||||
return dtc;
|
||||
}
|
||||
catch (DataTypeDependencyException e) {
|
||||
throw new IllegalArgumentException(e.getMessage(), e);
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
|
@ -232,56 +241,75 @@ class UnionDB extends CompositeDB implements Union {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the internal components of this union with components of the
|
||||
* given union.
|
||||
* @param dataType the union to get the component information from.
|
||||
* @throws IllegalArgumentException if any of the component data types
|
||||
* are not allowed to replace a component in this composite data type.
|
||||
* 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.
|
||||
*/
|
||||
@Override
|
||||
public void replaceWith(DataType dataType) {
|
||||
if (!(dataType instanceof Union)) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
doReplaceWith((Union) dataType, true, null);
|
||||
}
|
||||
|
||||
void doReplaceWith(Union union, boolean notify, DataTypeConflictHandler handler) {
|
||||
lock.acquire();
|
||||
boolean isResolveCacheOwner = dataMgr.activateResolveCache();
|
||||
try {
|
||||
checkDeleted();
|
||||
|
||||
long oldMinAlignment = getMinimumAlignment();
|
||||
for (int i = 0; i < components.size(); i++) {
|
||||
DataTypeComponentDB dtc = components.get(i);
|
||||
dtc.getDataType().removeParent(this);
|
||||
removeComponent(dtc.getKey());
|
||||
}
|
||||
components.clear();
|
||||
|
||||
setAlignment(union, notify);
|
||||
|
||||
for (DataTypeComponent dtc : union.getComponents()) {
|
||||
DataType dt = dtc.getDataType();
|
||||
doAdd(dt, dtc.getLength(), dtc.getFieldName(), dtc.getComment());
|
||||
}
|
||||
|
||||
adjustLength(notify, true); // TODO: VERIFY! is it always appropriate to set update time??
|
||||
|
||||
if (notify && (oldMinAlignment != getMinimumAlignment())) {
|
||||
notifyAlignmentChanged();
|
||||
}
|
||||
|
||||
doReplaceWith((Union) dataType, true, dataMgr.getCurrentConflictHandler());
|
||||
}
|
||||
catch (DataTypeDependencyException e) {
|
||||
throw new IllegalArgumentException(e.getMessage(), e);
|
||||
}
|
||||
finally {
|
||||
if (isResolveCacheOwner) {
|
||||
dataMgr.flushResolveCacheAndClearQueue(null);
|
||||
}
|
||||
lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
void doReplaceWith(Union union, boolean notify, DataTypeConflictHandler handler)
|
||||
throws DataTypeDependencyException {
|
||||
|
||||
// pre-resolved component types to catch dependency issues early
|
||||
DataTypeComponent[] otherComponents = union.getComponents();
|
||||
DataType[] resolvedDts = new DataType[otherComponents.length];
|
||||
for (int i = 0; i < otherComponents.length; i++) {
|
||||
resolvedDts[i] = doCheckedResolve(otherComponents[i].getDataType(), handler);
|
||||
checkAncestry(resolvedDts[i]);
|
||||
}
|
||||
|
||||
int oldLength = unionLength;
|
||||
int oldMinAlignment = getMinimumAlignment();
|
||||
|
||||
for (int i = 0; i < components.size(); i++) {
|
||||
DataTypeComponentDB dtc = components.get(i);
|
||||
dtc.getDataType().removeParent(this);
|
||||
removeComponent(dtc.getKey());
|
||||
}
|
||||
components.clear();
|
||||
|
||||
setAlignment(union, false);
|
||||
|
||||
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);
|
||||
|
||||
if (notify) {
|
||||
if (oldMinAlignment != getMinimumAlignment()) {
|
||||
notifyAlignmentChanged();
|
||||
}
|
||||
else if (oldLength != unionLength) {
|
||||
notifySizeChanged();
|
||||
}
|
||||
else {
|
||||
dataMgr.dataTypeChanged(this);
|
||||
}
|
||||
}
|
||||
|
||||
if (pointerPostResolveRequired) {
|
||||
dataMgr.queuePostResolve(this, union);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPartOf(DataType dataType) {
|
||||
lock.acquire();
|
||||
|
@ -320,6 +348,11 @@ class UnionDB extends CompositeDB implements Union {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumDefinedComponents() {
|
||||
return getNumComponents();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataTypeComponent getComponent(int ordinal) {
|
||||
lock.acquire();
|
||||
|
@ -336,17 +369,22 @@ class UnionDB extends CompositeDB implements Union {
|
|||
}
|
||||
|
||||
@Override
|
||||
public DataTypeComponent[] getComponents() {
|
||||
public DataTypeComponentDB[] getComponents() {
|
||||
lock.acquire();
|
||||
try {
|
||||
checkIsValid();
|
||||
return components.toArray(new DataTypeComponent[components.size()]);
|
||||
return components.toArray(new DataTypeComponentDB[components.size()]);
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataTypeComponentDB[] getDefinedComponents() {
|
||||
return getComponents();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType copy(DataTypeManager dtm) {
|
||||
UnionDataType union = new UnionDataType(getCategoryPath(), getName(), dtm);
|
||||
|
@ -419,7 +457,7 @@ class UnionDB extends CompositeDB implements Union {
|
|||
baseDataType = resolve(baseDataType);
|
||||
|
||||
// Both aligned and unaligned bitfields use same adjustment
|
||||
// unaligned must force bitfield placement at byte offset 0
|
||||
// unaligned must force bitfield placement at byte offset 0
|
||||
int bitSize = bitfieldDt.getDeclaredBitSize();
|
||||
int effectiveBitSize =
|
||||
BitFieldDataType.getEffectiveBitSize(bitSize, baseDataType.getLength());
|
||||
|
@ -515,40 +553,54 @@ class UnionDB extends CompositeDB implements Union {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean isEquivalent(DataType dt) {
|
||||
if (dt == this) {
|
||||
public boolean isEquivalent(DataType dataType) {
|
||||
|
||||
if (dataType == this) {
|
||||
return true;
|
||||
}
|
||||
if (dt == null || !(dt instanceof Union)) {
|
||||
if (!(dataType instanceof Union)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
checkIsValid();
|
||||
if (resolving) {
|
||||
if (dt.getUniversalID().equals(getUniversalID())) {
|
||||
if (resolving) { // actively resolving children
|
||||
if (dataType.getUniversalID().equals(getUniversalID())) {
|
||||
return true;
|
||||
}
|
||||
return DataTypeUtilities.equalsIgnoreConflict(getPathName(), dt.getPathName());
|
||||
return DataTypeUtilities.equalsIgnoreConflict(getPathName(), dataType.getPathName());
|
||||
}
|
||||
Union union = (Union) dt;
|
||||
if (isInternallyAligned() != union.isInternallyAligned() ||
|
||||
isDefaultAligned() != union.isDefaultAligned() ||
|
||||
isMachineAligned() != union.isMachineAligned() ||
|
||||
getMinimumAlignment() != union.getMinimumAlignment() ||
|
||||
getPackingValue() != union.getPackingValue()) {
|
||||
// rely on component match instead of checking length
|
||||
// since dynamic component sizes could affect length
|
||||
return false;
|
||||
|
||||
Boolean isEquivalent = dataMgr.getCachedEquivalence(this, dataType);
|
||||
if (isEquivalent != null) {
|
||||
return isEquivalent;
|
||||
}
|
||||
DataTypeComponent[] myComps = getComponents();
|
||||
DataTypeComponent[] otherComps = union.getComponents();
|
||||
if (myComps.length != otherComps.length) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < myComps.length; i++) {
|
||||
if (!myComps[i].isEquivalent(otherComps[i])) {
|
||||
|
||||
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
|
||||
// since dynamic component sizes could affect length
|
||||
return false;
|
||||
}
|
||||
DataTypeComponent[] myComps = getComponents();
|
||||
DataTypeComponent[] otherComps = union.getComponents();
|
||||
if (myComps.length != otherComps.length) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < myComps.length; i++) {
|
||||
if (!myComps[i].isEquivalent(otherComps[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
isEquivalent = true;
|
||||
}
|
||||
finally {
|
||||
dataMgr.putCachedEquivalence(this, dataType, isEquivalent);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -261,7 +261,6 @@ public class ExternalManagerDB implements ManagerDB, ExternalManager {
|
|||
SourceType locSourceType = checkExternalLabel(extLabel, extAddr, sourceType);
|
||||
lock.acquire();
|
||||
try {
|
||||
// FIXME:
|
||||
Namespace libraryScope = getLibraryScope(extLibraryName);
|
||||
if (libraryScope == null) {
|
||||
libraryScope = addExternalName(extLibraryName, null,
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -16,6 +15,9 @@
|
|||
*/
|
||||
package ghidra.program.model.block;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSet;
|
||||
import ghidra.program.model.listing.Program;
|
||||
|
@ -23,9 +25,6 @@ import ghidra.program.model.symbol.FlowType;
|
|||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
|
||||
/**
|
||||
* <CODE>IsolatedEntryCodeSubModel</CODE> (S-model) defines subroutines with a
|
||||
* unique entry point, which may share code with other subroutines. Each entry-
|
||||
|
@ -34,7 +33,7 @@ import java.util.LinkedList;
|
|||
* the set of addresses contained within each subroutine. Unlike the
|
||||
* OverlapCodeSubModel, the address set of a IsolatedEntryCodeSubModel
|
||||
* subroutine is permitted to span entry-points of other subroutines based upon
|
||||
* the possible flows from its' entry- point.
|
||||
* the possible flows from its entry- point.
|
||||
*
|
||||
* @see ghidra.program.model.block.CodeBlockModel
|
||||
* @see ghidra.program.model.block.OverlapCodeSubModel
|
||||
|
@ -79,13 +78,15 @@ public class IsolatedEntrySubModel extends OverlapCodeSubModel {
|
|||
|
||||
// Create address list which contains all other entry points for this M-model sub
|
||||
CodeBlock mSub = modelM.getCodeBlockAt(mStartAddr, monitor);
|
||||
if (mSub == null)
|
||||
return null;
|
||||
if (mSub == null) {
|
||||
return null;
|
||||
}
|
||||
Address[] mEntryPts = mSub.getStartAddresses();
|
||||
ArrayList<Address> startSet = new ArrayList<Address>();
|
||||
for (int i = 0; i < mEntryPts.length; i++) {
|
||||
if (!mStartAddr.equals(mEntryPts[i]))
|
||||
startSet.add(mEntryPts[i]);
|
||||
for (Address mEntryPt : mEntryPts) {
|
||||
if (!mStartAddr.equals(mEntryPt)) {
|
||||
startSet.add(mEntryPt);
|
||||
}
|
||||
}
|
||||
|
||||
// create a holder for the blockSet
|
||||
|
@ -100,20 +101,25 @@ public class IsolatedEntrySubModel extends OverlapCodeSubModel {
|
|||
// Build model-S subroutine from basic blocks
|
||||
while (!todoList.isEmpty()) {
|
||||
|
||||
if (monitor.isCancelled())
|
||||
throw new CancelledException();
|
||||
if (monitor.isCancelled()) {
|
||||
throw new CancelledException();
|
||||
}
|
||||
|
||||
// Get basic block at the specified address
|
||||
Address a = todoList.removeLast();
|
||||
if (addrSet.contains(a) || startSet.contains(a)) // <<-- only difference from Model-O
|
||||
continue; // already processed this block or encountered another Model-M entry point
|
||||
if (addrSet.contains(a) || startSet.contains(a))
|
||||
{
|
||||
continue; // already processed this block or encountered another Model-M entry point
|
||||
}
|
||||
CodeBlock bblock = bbModel.getFirstCodeBlockContaining(a, monitor);
|
||||
if (bblock == null)
|
||||
continue;
|
||||
if (bblock == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Verify that the block contains instructions
|
||||
if (listing.getInstructionAt(a) == null)
|
||||
continue;
|
||||
if (listing.getInstructionAt(a) == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add basic block to subroutine address set
|
||||
addrSet.add(bblock);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -16,6 +15,9 @@
|
|||
*/
|
||||
package ghidra.program.model.block;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.listing.Listing;
|
||||
import ghidra.program.model.listing.Program;
|
||||
|
@ -23,15 +25,12 @@ import ghidra.program.model.symbol.*;
|
|||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
|
||||
/**
|
||||
* <CODE>OverlapCodeSubModel</CODE> (O-model) defines subroutines with a
|
||||
* unique entry point, which may share code with other subroutines. Each entry-
|
||||
* point may either be a source or called entry-point and is identified using
|
||||
* the MultEntSubModel. This model defines the set of addresses contained
|
||||
* within each subroutine based upon the possible flows from its' entry- point.
|
||||
* within each subroutine based upon the possible flows from its entry- point.
|
||||
* Flows which encounter another entry-point are terminated.
|
||||
* <P>
|
||||
* NOTE: This differs from the original definition of an entry point, however,
|
||||
|
@ -104,20 +103,25 @@ public class OverlapCodeSubModel implements SubroutineBlockModel {
|
|||
// Build model-O subroutine from basic blocks
|
||||
while (!todoList.isEmpty()) {
|
||||
|
||||
if (monitor.isCancelled())
|
||||
throw new CancelledException();
|
||||
if (monitor.isCancelled()) {
|
||||
throw new CancelledException();
|
||||
}
|
||||
|
||||
// Get basic block at the specified address
|
||||
Address a = todoList.removeLast();
|
||||
if (addrSet.contains(a))
|
||||
continue; // already processed this block
|
||||
{
|
||||
continue; // already processed this block
|
||||
}
|
||||
CodeBlock bblock = bbModel.getFirstCodeBlockContaining(a, monitor);
|
||||
if (bblock == null)
|
||||
continue;
|
||||
if (bblock == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Verify that the block contains instructions
|
||||
if (listing.getInstructionAt(a) == null)
|
||||
continue;
|
||||
if (listing.getInstructionAt(a) == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add basic block to subroutine address set
|
||||
addrSet.add(bblock);
|
||||
|
@ -140,7 +144,8 @@ public class OverlapCodeSubModel implements SubroutineBlockModel {
|
|||
/**
|
||||
* @see ghidra.program.model.block.CodeBlockModel#getCodeBlockAt(ghidra.program.model.address.Address, ghidra.util.task.TaskMonitor)
|
||||
*/
|
||||
public CodeBlock getCodeBlockAt(Address addr, TaskMonitor monitor) throws CancelledException {
|
||||
@Override
|
||||
public CodeBlock getCodeBlockAt(Address addr, TaskMonitor monitor) throws CancelledException {
|
||||
|
||||
// First check out the Block cache
|
||||
CodeBlock block = foundOSubs.getBlockAt(addr);
|
||||
|
@ -170,7 +175,8 @@ public class OverlapCodeSubModel implements SubroutineBlockModel {
|
|||
* contains the address empty array otherwise.
|
||||
* @throws CancelledException if the monitor cancels the operation.
|
||||
*/
|
||||
public CodeBlock[] getCodeBlocksContaining(Address addr, TaskMonitor monitor) throws CancelledException {
|
||||
@Override
|
||||
public CodeBlock[] getCodeBlocksContaining(Address addr, TaskMonitor monitor) throws CancelledException {
|
||||
|
||||
// First check out the Block cache
|
||||
CodeBlock[] blocks = foundOSubs.getBlocksContaining(addr);
|
||||
|
@ -179,8 +185,9 @@ public class OverlapCodeSubModel implements SubroutineBlockModel {
|
|||
}
|
||||
|
||||
CodeBlock modelMSub = modelM.getFirstCodeBlockContaining(addr, monitor);
|
||||
if (modelMSub == null)
|
||||
return emptyBlockArray;
|
||||
if (modelMSub == null) {
|
||||
return emptyBlockArray;
|
||||
}
|
||||
Address[] entPts = modelMSub.getStartAddresses();
|
||||
|
||||
// Single-entry MSub same as OSub
|
||||
|
@ -195,8 +202,9 @@ public class OverlapCodeSubModel implements SubroutineBlockModel {
|
|||
ArrayList<CodeBlock> blockList = new ArrayList<CodeBlock>();
|
||||
for (int i = 0; i < cnt; i++) {
|
||||
CodeBlock block = getSubroutine(entPts[i], monitor);
|
||||
if (block.contains(addr))
|
||||
blockList.add(block);
|
||||
if (block.contains(addr)) {
|
||||
blockList.add(block);
|
||||
}
|
||||
}
|
||||
return blockList.toArray(new CodeBlock[blockList.size()]);
|
||||
}
|
||||
|
@ -205,7 +213,8 @@ public class OverlapCodeSubModel implements SubroutineBlockModel {
|
|||
/**
|
||||
* @see ghidra.program.model.block.CodeBlockModel#getFirstCodeBlockContaining(ghidra.program.model.address.Address, ghidra.util.task.TaskMonitor)
|
||||
*/
|
||||
public CodeBlock getFirstCodeBlockContaining(Address addr, TaskMonitor monitor) throws CancelledException {
|
||||
@Override
|
||||
public CodeBlock getFirstCodeBlockContaining(Address addr, TaskMonitor monitor) throws CancelledException {
|
||||
|
||||
// First check out the Block cache
|
||||
CodeBlock block = foundOSubs.getFirstBlockContaining(addr);
|
||||
|
@ -214,8 +223,9 @@ public class OverlapCodeSubModel implements SubroutineBlockModel {
|
|||
}
|
||||
|
||||
CodeBlock modelMSub = modelM.getFirstCodeBlockContaining(addr, monitor);
|
||||
if (modelMSub == null)
|
||||
return null;
|
||||
if (modelMSub == null) {
|
||||
return null;
|
||||
}
|
||||
Address[] entPts = modelMSub.getStartAddresses();
|
||||
|
||||
// Single-entry MSub same as OSub
|
||||
|
@ -227,8 +237,9 @@ public class OverlapCodeSubModel implements SubroutineBlockModel {
|
|||
// Return first OSub which contains addr
|
||||
for (int i = 0; i < cnt; i++) {
|
||||
block = getSubroutine(entPts[i], monitor);
|
||||
if (block != null && block.contains(addr))
|
||||
return block;
|
||||
if (block != null && block.contains(addr)) {
|
||||
return block;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -236,14 +247,16 @@ public class OverlapCodeSubModel implements SubroutineBlockModel {
|
|||
/**
|
||||
* @see ghidra.program.model.block.CodeBlockModel#getCodeBlocks(ghidra.util.task.TaskMonitor)
|
||||
*/
|
||||
public CodeBlockIterator getCodeBlocks(TaskMonitor monitor) throws CancelledException {
|
||||
@Override
|
||||
public CodeBlockIterator getCodeBlocks(TaskMonitor monitor) throws CancelledException {
|
||||
return new SingleEntSubIterator(this, monitor);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.block.CodeBlockModel#getCodeBlocksContaining(ghidra.program.model.address.AddressSetView, ghidra.util.task.TaskMonitor)
|
||||
*/
|
||||
public CodeBlockIterator getCodeBlocksContaining(AddressSetView addrSet, TaskMonitor monitor) throws CancelledException {
|
||||
@Override
|
||||
public CodeBlockIterator getCodeBlocksContaining(AddressSetView addrSet, TaskMonitor monitor) throws CancelledException {
|
||||
return new SingleEntSubIterator(this, addrSet, monitor);
|
||||
}
|
||||
|
||||
|
@ -259,7 +272,8 @@ public class OverlapCodeSubModel implements SubroutineBlockModel {
|
|||
/**
|
||||
* @see ghidra.program.model.block.CodeBlockModel#getProgram()
|
||||
*/
|
||||
public Program getProgram() {
|
||||
@Override
|
||||
public Program getProgram() {
|
||||
return program;
|
||||
}
|
||||
|
||||
|
@ -274,14 +288,16 @@ public class OverlapCodeSubModel implements SubroutineBlockModel {
|
|||
/**
|
||||
* @see ghidra.program.model.block.CodeBlockModel#getName(ghidra.program.model.block.CodeBlock)
|
||||
*/
|
||||
public String getName(CodeBlock block) {
|
||||
@Override
|
||||
public String getName(CodeBlock block) {
|
||||
// get the start address for the block
|
||||
// look up the symbol in the symbol table.
|
||||
// it should have one if anyone calls it.
|
||||
// if not, make up a label
|
||||
|
||||
if (!(block.getModel() instanceof OverlapCodeSubModel))
|
||||
throw new IllegalArgumentException();
|
||||
if (!(block.getModel() instanceof OverlapCodeSubModel)) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
Address start = block.getFirstStartAddress();
|
||||
|
||||
|
@ -309,7 +325,8 @@ public class OverlapCodeSubModel implements SubroutineBlockModel {
|
|||
*
|
||||
* @return flow type of this node
|
||||
*/
|
||||
public FlowType getFlowType(CodeBlock block) {
|
||||
@Override
|
||||
public FlowType getFlowType(CodeBlock block) {
|
||||
/* If there are multiple unique ways out of the node, then we
|
||||
should return FlowType.UNKNOWN (or FlowType.MULTIFLOW ?).
|
||||
Possible considerations for the future which are particularly
|
||||
|
@ -318,8 +335,9 @@ public class OverlapCodeSubModel implements SubroutineBlockModel {
|
|||
(as opposed to jumping within the subroutine).
|
||||
Might want to consider FlowType.MULTITERMINAL for multiple returns? */
|
||||
|
||||
if (!(block.getModel() instanceof OverlapCodeSubModel))
|
||||
throw new IllegalArgumentException();
|
||||
if (!(block.getModel() instanceof OverlapCodeSubModel)) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
return RefType.FLOW;
|
||||
}
|
||||
|
@ -327,10 +345,12 @@ public class OverlapCodeSubModel implements SubroutineBlockModel {
|
|||
/**
|
||||
* @see ghidra.program.model.block.CodeBlockModel#getSources(ghidra.program.model.block.CodeBlock, ghidra.util.task.TaskMonitor)
|
||||
*/
|
||||
public CodeBlockReferenceIterator getSources(CodeBlock block, TaskMonitor monitor) throws CancelledException {
|
||||
@Override
|
||||
public CodeBlockReferenceIterator getSources(CodeBlock block, TaskMonitor monitor) throws CancelledException {
|
||||
|
||||
if (!(block.getModel() instanceof OverlapCodeSubModel))
|
||||
throw new IllegalArgumentException();
|
||||
if (!(block.getModel() instanceof OverlapCodeSubModel)) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
return new SubroutineSourceReferenceIterator(block, monitor);
|
||||
}
|
||||
|
@ -338,10 +358,12 @@ public class OverlapCodeSubModel implements SubroutineBlockModel {
|
|||
/**
|
||||
* @see ghidra.program.model.block.CodeBlockModel#getNumSources(ghidra.program.model.block.CodeBlock, ghidra.util.task.TaskMonitor)
|
||||
*/
|
||||
public int getNumSources(CodeBlock block, TaskMonitor monitor) throws CancelledException {
|
||||
@Override
|
||||
public int getNumSources(CodeBlock block, TaskMonitor monitor) throws CancelledException {
|
||||
|
||||
if (!(block.getModel() instanceof OverlapCodeSubModel))
|
||||
throw new IllegalArgumentException();
|
||||
if (!(block.getModel() instanceof OverlapCodeSubModel)) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
return SubroutineSourceReferenceIterator.getNumSources(block, monitor);
|
||||
}
|
||||
|
@ -349,7 +371,8 @@ public class OverlapCodeSubModel implements SubroutineBlockModel {
|
|||
/**
|
||||
* @see ghidra.program.model.block.CodeBlockModel#getDestinations(ghidra.program.model.block.CodeBlock, ghidra.util.task.TaskMonitor)
|
||||
*/
|
||||
public CodeBlockReferenceIterator getDestinations(CodeBlock block, TaskMonitor monitor) throws CancelledException {
|
||||
@Override
|
||||
public CodeBlockReferenceIterator getDestinations(CodeBlock block, TaskMonitor monitor) throws CancelledException {
|
||||
// destinations of Fallthroughs are the follow on block
|
||||
// destinations of all others are the instruction's operand referents
|
||||
|
||||
|
@ -367,8 +390,9 @@ public class OverlapCodeSubModel implements SubroutineBlockModel {
|
|||
// nor that any destination is a good destination unless the instruction
|
||||
// is looked at.
|
||||
|
||||
if (!(block.getModel() instanceof OverlapCodeSubModel))
|
||||
throw new IllegalArgumentException();
|
||||
if (!(block.getModel() instanceof OverlapCodeSubModel)) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
return new SubroutineDestReferenceIterator(block, monitor);
|
||||
}
|
||||
|
@ -376,10 +400,12 @@ public class OverlapCodeSubModel implements SubroutineBlockModel {
|
|||
/**
|
||||
* @see ghidra.program.model.block.CodeBlockModel#getNumDestinations(ghidra.program.model.block.CodeBlock, ghidra.util.task.TaskMonitor)
|
||||
*/
|
||||
public int getNumDestinations(CodeBlock block, TaskMonitor monitor) throws CancelledException {
|
||||
@Override
|
||||
public int getNumDestinations(CodeBlock block, TaskMonitor monitor) throws CancelledException {
|
||||
|
||||
if (!(block.getModel() instanceof OverlapCodeSubModel))
|
||||
throw new IllegalArgumentException();
|
||||
if (!(block.getModel() instanceof OverlapCodeSubModel)) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
return SubroutineDestReferenceIterator.getNumDestinations(block, monitor);
|
||||
}
|
||||
|
@ -393,8 +419,9 @@ public class OverlapCodeSubModel implements SubroutineBlockModel {
|
|||
*/
|
||||
protected CodeBlock createSub(AddressSetView addrSet, Address entryPt) {
|
||||
|
||||
if (addrSet.isEmpty())
|
||||
if (addrSet.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Address[] entryPts = new Address[1];
|
||||
entryPts[0] = entryPt;
|
||||
|
@ -408,6 +435,7 @@ public class OverlapCodeSubModel implements SubroutineBlockModel {
|
|||
/**
|
||||
* @see ghidra.program.model.block.CodeBlockModel#getBasicBlockModel()
|
||||
*/
|
||||
@Override
|
||||
public CodeBlockModel getBasicBlockModel() {
|
||||
return modelM.getBasicBlockModel();
|
||||
}
|
||||
|
@ -415,6 +443,7 @@ public class OverlapCodeSubModel implements SubroutineBlockModel {
|
|||
/**
|
||||
* @see ghidra.program.model.block.CodeBlockModel#getName()
|
||||
*/
|
||||
@Override
|
||||
public String getName() {
|
||||
return OVERLAP_MODEL_NAME;
|
||||
}
|
||||
|
@ -422,6 +451,7 @@ public class OverlapCodeSubModel implements SubroutineBlockModel {
|
|||
/**
|
||||
* @see ghidra.program.model.block.SubroutineBlockModel#getBaseSubroutineModel()
|
||||
*/
|
||||
@Override
|
||||
public SubroutineBlockModel getBaseSubroutineModel() {
|
||||
return modelM;
|
||||
}
|
||||
|
@ -429,10 +459,12 @@ public class OverlapCodeSubModel implements SubroutineBlockModel {
|
|||
/**
|
||||
* @see ghidra.program.model.block.CodeBlockModel#allowsBlockOverlap()
|
||||
*/
|
||||
@Override
|
||||
public boolean allowsBlockOverlap() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean externalsIncluded() {
|
||||
return modelM.externalsIncluded();
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@ package ghidra.program.model.data;
|
|||
|
||||
import java.net.URL;
|
||||
|
||||
import ghidra.app.plugin.core.datamgr.archive.SourceArchive;
|
||||
import ghidra.docking.settings.Settings;
|
||||
import ghidra.program.model.mem.MemBuffer;
|
||||
import ghidra.util.InvalidNameException;
|
||||
|
|
|
@ -48,10 +48,11 @@ public class ArrayDataType extends DataTypeImpl implements Array {
|
|||
* @param dataType the dataType of the elements in the array.
|
||||
* @param numElements the number of elements in the array.
|
||||
* @param elementLength the length of an individual element in the array.
|
||||
* @param dtm datatype manager or null
|
||||
*/
|
||||
public ArrayDataType(DataType dataType, int numElements, int elementLength,
|
||||
DataTypeManager dtm) {
|
||||
super(CategoryPath.ROOT, "array", dtm);
|
||||
super(dataType.getCategoryPath(), "array", dtm);
|
||||
validate(dataType);
|
||||
if (dataType.getDataTypeManager() != dtm) {
|
||||
dataType = dataType.clone(dtm);
|
||||
|
@ -100,9 +101,6 @@ public class ArrayDataType extends DataTypeImpl implements Array {
|
|||
|
||||
@Override
|
||||
public boolean isEquivalent(DataType obj) {
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ import utilities.util.ArrayUtilities;
|
|||
* for use within data structures. The length (i.e., storage size) of this bitfield datatype is
|
||||
* the minimum number of bytes required to contain the bitfield at its specified offset.
|
||||
* The effective bit-size of a bitfield will be limited by the size of the base
|
||||
* datatype whose size may be controlled by its' associated datatype manager and data organization
|
||||
* datatype whose size may be controlled by its associated datatype manager and data organization
|
||||
* (e.g., {@link IntegerDataType}).
|
||||
* <p>
|
||||
* NOTE: Instantiation of this datatype implementation is intended for internal use only.
|
||||
|
|
|
@ -20,7 +20,6 @@ import java.util.List;
|
|||
|
||||
import javax.swing.event.ChangeListener;
|
||||
|
||||
import ghidra.app.plugin.core.datamgr.archive.SourceArchive;
|
||||
import ghidra.framework.ShutdownHookRegistry;
|
||||
import ghidra.framework.ShutdownPriority;
|
||||
import ghidra.util.*;
|
||||
|
|
|
@ -73,11 +73,24 @@ public interface Composite extends DataType {
|
|||
public void setDescription(String desc);
|
||||
|
||||
/**
|
||||
* Gets the number of component data types in this data type.
|
||||
* @return the number of components that make up this data prototype
|
||||
* 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
|
||||
* optional trailing flexible array component in this count
|
||||
* (see {@link Structure#hasFlexibleArrayComponent()}).
|
||||
* @return the number of components that make up this composite
|
||||
*/
|
||||
public abstract int getNumComponents();
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @return the number of explicitly defined components in this composite
|
||||
*/
|
||||
public abstract int getNumDefinedComponents();
|
||||
|
||||
/**
|
||||
* Returns the component of this data type with the indicated ordinal.
|
||||
* @param ordinal the component's ordinal (zero based).
|
||||
|
@ -87,11 +100,25 @@ public interface Composite extends DataType {
|
|||
public abstract DataTypeComponent getComponent(int ordinal);
|
||||
|
||||
/**
|
||||
* Returns an array of Data Type Components that make up this data type.
|
||||
* Returns an array of length 0 if there are no subcomponents.
|
||||
* Returns an array of Data Type Components that make up this composite including
|
||||
* undefined filler components which may be present within an unaligned structure.
|
||||
* The number of components corresponds to {@link #getNumComponents()}.
|
||||
* @return list 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
|
||||
* (see {@link Structure#getFlexibleArrayComponent()}).
|
||||
* @return list all explicitly defined components
|
||||
*/
|
||||
public abstract DataTypeComponent[] getDefinedComponents();
|
||||
|
||||
/**
|
||||
* Adds a new datatype to the end of this composite. This is the preferred method
|
||||
* to use for adding components to an aligned structure for fixed-length dataTypes.
|
||||
|
@ -102,7 +129,7 @@ public interface Composite extends DataType {
|
|||
* For example, suppose dt1 contains dt2. Therefore it is not valid
|
||||
* to add dt1 to dt2 since this would cause a cyclic dependency.
|
||||
*/
|
||||
public DataTypeComponent add(DataType dataType);
|
||||
public DataTypeComponent add(DataType dataType) throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Adds a new datatype to the end of this composite. This is the preferred method
|
||||
|
@ -118,7 +145,7 @@ public interface Composite extends DataType {
|
|||
* For example, suppose dt1 contains dt2. Therefore it is not valid
|
||||
* to add dt1 to dt2 since this would cause a cyclic dependency.
|
||||
*/
|
||||
public DataTypeComponent add(DataType dataType, int length);
|
||||
public DataTypeComponent add(DataType dataType, int length) throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Adds a new datatype to the end of this composite. This is the preferred method
|
||||
|
@ -132,7 +159,8 @@ public interface Composite extends DataType {
|
|||
* For example, suppose dt1 contains dt2. Therefore it is not valid
|
||||
* to add dt1 to dt2 since this would cause a cyclic dependency.
|
||||
*/
|
||||
public DataTypeComponent add(DataType dataType, String name, String comment);
|
||||
public DataTypeComponent add(DataType dataType, String name, String comment)
|
||||
throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Adds a new bitfield to the end of this composite. This method is intended
|
||||
|
@ -166,7 +194,8 @@ public interface Composite extends DataType {
|
|||
* For example, suppose dt1 contains dt2. Therefore it is not valid
|
||||
* to add dt1 to dt2 since this would cause a cyclic dependency.
|
||||
*/
|
||||
public DataTypeComponent add(DataType dataType, int length, String name, String comment);
|
||||
public DataTypeComponent add(DataType dataType, int length, String name, String comment)
|
||||
throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Inserts a new datatype at the specified ordinal position in this composite.
|
||||
|
@ -181,7 +210,7 @@ public interface Composite extends DataType {
|
|||
* to insert dt1 to dt2 since this would cause a cyclic dependency.
|
||||
* @throws ArrayIndexOutOfBoundsException if component ordinal is out of bounds
|
||||
*/
|
||||
public DataTypeComponent insert(int ordinal, DataType dataType);
|
||||
public DataTypeComponent insert(int ordinal, DataType dataType) throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Inserts a new datatype at the specified ordinal position in this composite.
|
||||
|
@ -199,7 +228,8 @@ public interface Composite extends DataType {
|
|||
* to insert dt1 to dt2 since this would cause a cyclic dependency.
|
||||
* @throws ArrayIndexOutOfBoundsException if component ordinal is out of bounds
|
||||
*/
|
||||
public DataTypeComponent insert(int ordinal, DataType dataType, int length);
|
||||
public DataTypeComponent insert(int ordinal, DataType dataType, int length)
|
||||
throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Inserts a new datatype at the specified ordinal position in this composite.
|
||||
|
@ -220,7 +250,7 @@ public interface Composite extends DataType {
|
|||
* @throws ArrayIndexOutOfBoundsException if component ordinal is out of bounds
|
||||
*/
|
||||
public DataTypeComponent insert(int ordinal, DataType dataType, int length, String name,
|
||||
String comment);
|
||||
String comment) throws ArrayIndexOutOfBoundsException, IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Deletes the component at the given ordinal position.
|
||||
|
@ -229,7 +259,7 @@ public interface Composite extends DataType {
|
|||
* @param ordinal the ordinal of the component to be deleted.
|
||||
* @throws ArrayIndexOutOfBoundsException if component ordinal is out of bounds
|
||||
*/
|
||||
public void delete(int ordinal);
|
||||
public void delete(int ordinal) throws ArrayIndexOutOfBoundsException;
|
||||
|
||||
/**
|
||||
* Deletes the components at the given ordinal positions.
|
||||
|
@ -238,7 +268,7 @@ public interface Composite extends DataType {
|
|||
* @param ordinals the ordinals of the component to be deleted.
|
||||
* @throws ArrayIndexOutOfBoundsException if any specified component ordinal is out of bounds
|
||||
*/
|
||||
public void delete(int[] ordinals);
|
||||
public void delete(int[] ordinals) throws ArrayIndexOutOfBoundsException;
|
||||
|
||||
/**
|
||||
* Check if a data type is part of this data type. A data type could
|
||||
|
|
|
@ -22,7 +22,7 @@ public class CompositeAlignmentHelper {
|
|||
int allComponentsLCM = 1;
|
||||
int packingAlignment = composite.getPackingValue();
|
||||
|
||||
DataTypeComponent[] dataTypeComponents = composite.getComponents();
|
||||
DataTypeComponent[] dataTypeComponents = composite.getDefinedComponents();
|
||||
for (DataTypeComponent dataTypeComponent : dataTypeComponents) {
|
||||
int impartedAlignment = CompositeAlignmentHelper.getPackedAlignment(dataOrganization,
|
||||
packingAlignment, dataTypeComponent);
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
*/
|
||||
package ghidra.program.model.data;
|
||||
|
||||
import ghidra.app.plugin.core.datamgr.archive.SourceArchive;
|
||||
import ghidra.docking.settings.Settings;
|
||||
import ghidra.program.database.data.DataTypeUtilities;
|
||||
import ghidra.program.model.mem.MemBuffer;
|
||||
|
@ -25,26 +24,35 @@ import ghidra.util.exception.AssertException;
|
|||
import ghidra.util.exception.NotYetImplementedException;
|
||||
|
||||
/**
|
||||
* Common implementation methods for structure and union
|
||||
* Common implementation methods for structure and union
|
||||
*/
|
||||
public abstract class CompositeDataTypeImpl extends GenericDataType implements Composite {
|
||||
private final static long serialVersionUID = 1;
|
||||
private String description;
|
||||
|
||||
protected boolean aligned = false; //WARNING, changing the initial value for this will cause
|
||||
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.
|
||||
// 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;
|
||||
|
||||
/**
|
||||
* Creates an empty CompositeDataType with the specified name.
|
||||
* @param path the category path indicating where this data type is located.
|
||||
* @param name the data type's name
|
||||
* @param dataTypeManager the data type manager associated with this data type. This can be null.
|
||||
* Also, the data type manager may not contain this actual data type.
|
||||
* Construct a new composite with the given name
|
||||
*
|
||||
* @param path the category path indicating where this
|
||||
* data type is located.
|
||||
* @param name the name of the new structure
|
||||
* @param universalID the id for the data type
|
||||
* @param sourceArchive the source archive for this data type
|
||||
* @param lastChangeTime the last time this data type was changed
|
||||
* @param lastChangeTimeInSourceArchive the last time this data type was changed
|
||||
* in its source archive.
|
||||
* @param dtm the data type manager associated with
|
||||
* this data type. This can be null. Also,
|
||||
* the data type manager may not yet
|
||||
* contain this actual data type.
|
||||
*/
|
||||
CompositeDataTypeImpl(CategoryPath path, String name, UniversalID universalID,
|
||||
SourceArchive sourceArchive, long lastChangeTime, long lastChangeTimeInSourceArchive,
|
||||
|
@ -60,13 +68,15 @@ public abstract class CompositeDataTypeImpl extends GenericDataType implements C
|
|||
}
|
||||
|
||||
/**
|
||||
* Get the preferred length for a new component. For Unions and internally aligned
|
||||
* structures the preferred component length for a fixed-length dataType will be the
|
||||
* length of that dataType. Otherwise the length returned will be no larger than the
|
||||
* specified length.
|
||||
* Get the preferred length for a new component. For Unions and internally
|
||||
* aligned structures the preferred component length for a fixed-length dataType
|
||||
* will be the length of that dataType. Otherwise the length returned will be no
|
||||
* larger than the specified length.
|
||||
*
|
||||
* @param dataType new component datatype
|
||||
* @param length constrained length or -1 to force use of dataType size. Dynamic types
|
||||
* such as string must have a positive length specified.
|
||||
* @param length constrained length or -1 to force use of dataType size.
|
||||
* Dynamic types such as string must have a positive length
|
||||
* specified.
|
||||
* @return preferred component length
|
||||
*/
|
||||
protected int getPreferredComponentLength(DataType dataType, int length) {
|
||||
|
@ -98,15 +108,15 @@ public abstract class CompositeDataTypeImpl extends GenericDataType implements C
|
|||
}
|
||||
|
||||
/**
|
||||
* This method throws an exception if the indicated data type is an ancestor
|
||||
* of this data type. In other words, the specified data type has a component
|
||||
* or sub-component containing this data type.
|
||||
* This method throws an exception if the indicated data type is an ancestor of
|
||||
* this data type. In other words, the specified data type has a component or
|
||||
* sub-component containing this data type.
|
||||
*
|
||||
* @param dataType the data type
|
||||
* @throws IllegalArgumentException if the data type is an ancestor of this
|
||||
* data type.
|
||||
* @throws IllegalArgumentException if the data type is an ancestor of this data
|
||||
* type.
|
||||
*/
|
||||
protected void checkAncestry(DataType dataType) {
|
||||
// TODO: cyclic checks are easily bypassed by renaming multiple composite instances
|
||||
protected void checkAncestry(DataType dataType) throws IllegalArgumentException {
|
||||
if (this.equals(dataType)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Data type " + getDisplayName() + " can't contain itself.");
|
||||
|
@ -118,8 +128,9 @@ public abstract class CompositeDataTypeImpl extends GenericDataType implements C
|
|||
}
|
||||
|
||||
/**
|
||||
* This method throws an exception if the indicated data type is not
|
||||
* a valid data type for a component of this composite data type.
|
||||
* This method throws an exception if the indicated data type is not a valid
|
||||
* data type for a component of this composite data type.
|
||||
*
|
||||
* @param dataType the data type to be checked.
|
||||
* @throws IllegalArgumentException if the data type is invalid.
|
||||
*/
|
||||
|
@ -143,11 +154,12 @@ public abstract class CompositeDataTypeImpl extends GenericDataType implements C
|
|||
|
||||
/**
|
||||
* Handle replacement of datatype which may impact bitfield datatype.
|
||||
*
|
||||
* @param bitfieldComponent bitfield component
|
||||
* @param oldDt affected datatype which has been removed or replaced
|
||||
* @param newDt replacement datatype
|
||||
* @param oldDt affected datatype which has been removed or replaced
|
||||
* @param newDt replacement datatype
|
||||
* @return true if bitfield component was modified
|
||||
* @throws InvalidDataTypeException if new datatype is not
|
||||
* @throws InvalidDataTypeException if new datatype is not
|
||||
*/
|
||||
protected boolean updateBitFieldDataType(DataTypeComponentImpl bitfieldComponent,
|
||||
DataType oldDt, DataType newDt) throws InvalidDataTypeException {
|
||||
|
@ -323,7 +335,8 @@ public abstract class CompositeDataTypeImpl extends GenericDataType implements C
|
|||
}
|
||||
|
||||
/**
|
||||
* Notify any parent data types that this composite data type's alignment has changed.
|
||||
* Notify any parent data types that this composite data type's alignment has
|
||||
* changed.
|
||||
*/
|
||||
protected void notifyAlignmentChanged() {
|
||||
DataType[] parents = getParents();
|
||||
|
@ -336,10 +349,11 @@ public abstract class CompositeDataTypeImpl extends GenericDataType implements C
|
|||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* 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();
|
||||
|
||||
|
@ -373,11 +387,14 @@ public abstract class CompositeDataTypeImpl extends GenericDataType implements C
|
|||
|
||||
/**
|
||||
* Dump all components for use in {@link #toString()} representation.
|
||||
*
|
||||
* @param buffer string buffer
|
||||
* @param pad padding to be used with each component output line
|
||||
* @param pad padding to be used with each component output line
|
||||
*/
|
||||
protected void dumpComponents(StringBuilder buffer, String pad) {
|
||||
for (DataTypeComponent dtc : getComponents()) {
|
||||
// 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());
|
||||
|
|
|
@ -558,14 +558,7 @@ public class DataOrganizationImpl implements DataOrganization {
|
|||
|
||||
// Check each component and get the least common multiple of their forced minimum alignments.
|
||||
int componentForcedLCM = 0;
|
||||
DataTypeComponent[] dataTypeComponents;
|
||||
if (composite instanceof Structure) {
|
||||
dataTypeComponents = ((Structure) composite).getDefinedComponents();
|
||||
}
|
||||
else {
|
||||
dataTypeComponents = composite.getComponents();
|
||||
}
|
||||
for (DataTypeComponent dataTypeComponent : dataTypeComponents) {
|
||||
for (DataTypeComponent dataTypeComponent : composite.getDefinedComponents()) {
|
||||
if (dataTypeComponent.isBitFieldComponent()) {
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@ package ghidra.program.model.data;
|
|||
|
||||
import java.net.URL;
|
||||
|
||||
import ghidra.app.plugin.core.datamgr.archive.SourceArchive;
|
||||
import ghidra.docking.settings.Settings;
|
||||
import ghidra.docking.settings.SettingsDefinition;
|
||||
import ghidra.program.model.mem.MemBuffer;
|
||||
|
@ -261,6 +260,9 @@ public interface DataType {
|
|||
/**
|
||||
* Returns true if the given dataType is equivalent to this dataType. The
|
||||
* precise meaning of "equivalent" is dataType dependent.
|
||||
* <br>
|
||||
* NOTE: if invoked by a DB object or manager it should be invoked on the
|
||||
* DataTypeDB object passing the other datatype as the argument.
|
||||
* @param dt the dataType being tested for equivalence.
|
||||
* @return true if the if the given dataType is equivalent to this dataType.
|
||||
*/
|
||||
|
|
|
@ -15,8 +15,6 @@
|
|||
*/
|
||||
package ghidra.program.model.data;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import ghidra.util.Msg;
|
||||
|
||||
public abstract class DataTypeConflictHandler {
|
||||
|
@ -61,13 +59,6 @@ public abstract class DataTypeConflictHandler {
|
|||
RENAME_AND_ADD, USE_EXISTING, REPLACE_EXISTING;
|
||||
}
|
||||
|
||||
/**
|
||||
* Due to the locking concerns which can arise with a DataTypeConflictHandler,
|
||||
* definition of new implementations must be done here.
|
||||
*/
|
||||
private DataTypeConflictHandler() {
|
||||
}
|
||||
|
||||
public final static DataTypeConflictHandler DEFAULT_HANDLER = new DataTypeConflictHandler() {
|
||||
@Override
|
||||
public ConflictResult resolveConflict(DataType addedDataType, DataType existingDataType) {
|
||||
|
@ -168,281 +159,52 @@ public abstract class DataTypeConflictHandler {
|
|||
};
|
||||
|
||||
/**
|
||||
* This {@link DataTypeConflictHandler conflict handler} attempts to match conflicting
|
||||
* {@link Composite composite data types} (structure or union) when they have compatible
|
||||
* data layouts. (Data types that are exactly equiv will not be subjected to conflict
|
||||
* handling and will never reach here)
|
||||
* <p>
|
||||
* A default/empty sized structure, or structures with the same size are candidates
|
||||
* for matching.
|
||||
* <p>
|
||||
* Structures that have a subset of the other's field definition are candidates for matching.
|
||||
* <p>
|
||||
* When a candidate data type is matched with an existing data type, this conflict handler
|
||||
* will specify that the new data type is:<p>
|
||||
* <ul>
|
||||
* <li>discarded and replaced by the existing data type ({@link ConflictResult#USE_EXISTING})
|
||||
* <li>used to overwrite the existing data type ({@link ConflictResult#REPLACE_EXISTING})
|
||||
* </ul>
|
||||
* or the candidate data type was <b>NOT</b> matched with an existing data type, and the new data type is:<p>
|
||||
* <ul>
|
||||
* <li>kept, but renamed with a .conflictNNNN suffix to make it unique ({@link ConflictResult#RENAME_AND_ADD})
|
||||
* </ul>
|
||||
* <b>NOTE:</b> structures with alignment (instead of being statically laid out) are not
|
||||
* treated specially and will not match other aligned or non-aligned structures.
|
||||
*
|
||||
* This {@link DataTypeConflictHandler conflict handler} behaves similar to
|
||||
* the {@link #DEFAULT_HANDLER} with the difference being that a
|
||||
* empty composite (see {@link Composite#isNotYetDefined()}) will be
|
||||
* replaced by a similar non-empty composite type. Alignment (e.g., packing)
|
||||
* is not considered when determining conflict resolution.
|
||||
* <br>
|
||||
* For datatypes originating from a source archive with matching ID, the
|
||||
* replacment strategy will utilize the implementation with the
|
||||
* latest timestamp.
|
||||
* <br>
|
||||
* Unlike the {@link #DEFAULT_HANDLER}, follow-on dependency datatype
|
||||
* resolutions will retain the same conflict resolution strategy.
|
||||
*/
|
||||
public final static DataTypeConflictHandler REPLACE_EMPTY_STRUCTS_OR_RENAME_AND_ADD_HANDLER =
|
||||
new DataTypeConflictHandler() {
|
||||
|
||||
/**
|
||||
* Returns true if src can overwrite the target composite based on size
|
||||
* @param src
|
||||
* @param target
|
||||
* @return
|
||||
*/
|
||||
private boolean isSizeCompatible(Composite src, Composite target) {
|
||||
return (target.getLength() <= 1) || (src.getLength() == target.getLength());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the {@link Composite composite} is empty (to get around the lying that
|
||||
* {@link Composite#getLength()} does.)
|
||||
* @param composite
|
||||
* @return
|
||||
*/
|
||||
private boolean isCompositeEmpty(Composite composite) {
|
||||
return composite.getLength() <= 1 && composite.getNumComponents() == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the given composite is filled with default values (all components are default).
|
||||
* @param composite composite to check
|
||||
* @return true if default and false otherwise
|
||||
*/
|
||||
private boolean isCompositeDefault(Composite composite) {
|
||||
if (composite.getLength() == composite.getNumComponents()) {
|
||||
DataTypeComponent[] comps = composite.getComponents();
|
||||
boolean isDefault = true;
|
||||
for (int i = 0; i < comps.length; i++) {
|
||||
if (comps[i].getDataType() != DataType.DEFAULT) {
|
||||
isDefault = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isDefault) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isCompositePart(Composite full, Composite part,
|
||||
Map<DataType, DataType> visitedDataTypes) {
|
||||
if (full instanceof Structure && part instanceof Structure) {
|
||||
return isStructurePart((Structure) full, (Structure) part, visitedDataTypes);
|
||||
}
|
||||
else if (full instanceof Union && part instanceof Union) {
|
||||
return isUnionPart((Union) full, (Union) part, visitedDataTypes);
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if one union is a subset of another union.
|
||||
* <p>
|
||||
* Each component of the candidate partial union must be present in the
|
||||
* 'full' union and must be 'equiv'.
|
||||
* <p>
|
||||
* Order of components is ignored, except for unnamed components, which receive
|
||||
* a default name created using their ordinal position.
|
||||
*
|
||||
* @param full {@link Union} datatype that is expected to be a superset of the next param.
|
||||
* @param part {@link Union} datatype that is expected to be a subset of the previous param.
|
||||
* @param visitedDataTypes identity map of datatypes to prevent loops.
|
||||
* @return true if part is a subset (or equal) to full.
|
||||
*/
|
||||
private boolean isUnionPart(Union full, Union part,
|
||||
Map<DataType, DataType> visitedDataTypes) {
|
||||
if (full.getLength() < part.getLength()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Map<String, DataTypeComponent> fullComponentsByName = new HashMap<>();
|
||||
for (DataTypeComponent dtc : full.getComponents()) {
|
||||
String name = dtc.getFieldName();
|
||||
if (name == null) {
|
||||
name = dtc.getDefaultFieldName();
|
||||
}
|
||||
fullComponentsByName.put(name, dtc);
|
||||
}
|
||||
for (DataTypeComponent dtc : part.getComponents()) {
|
||||
String name = dtc.getFieldName();
|
||||
if (name == null) {
|
||||
name = dtc.getDefaultFieldName();
|
||||
}
|
||||
DataTypeComponent fullDTC = fullComponentsByName.get(name);
|
||||
if (fullDTC == null) {
|
||||
return false;
|
||||
}
|
||||
DataType partDT = dtc.getDataType();
|
||||
DataType fullDT = fullDTC.getDataType();
|
||||
if (doRelaxedCompare(partDT, fullDT,
|
||||
visitedDataTypes) == ConflictResult.RENAME_AND_ADD) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns true if one structure is a partial definition of another structure.
|
||||
* <p>
|
||||
* Each defined component in the candidate partial structure must be present
|
||||
* in the 'full' structure and must be equiv.
|
||||
* <p>
|
||||
* The order and sparseness of the candidate partial structure is not important,
|
||||
* only that all of its defined components are present in the full structure.
|
||||
* <p>
|
||||
*/
|
||||
private boolean isStructurePart(Structure full, Structure part,
|
||||
Map<DataType, DataType> visitedDataTypes) {
|
||||
// Both structures should be equal in length
|
||||
if (full.getLength() != part.getLength()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean[] fullCompsUsedFlag = new boolean[full.getComponents().length];
|
||||
DataTypeComponent[] partComps = part.getDefinedComponents();
|
||||
|
||||
// Find a match in the full structure's component list for each
|
||||
// component in the partial structure.
|
||||
// Use resolveConflict() == USE_EXISTING to test for equiv in addition to
|
||||
// isEquiv().
|
||||
// Ensure that two components in the partial struct don't map to the same
|
||||
// component in the full structure.
|
||||
for (int i = 0; i < partComps.length; i++) {
|
||||
DataTypeComponent partDTC = partComps[i];
|
||||
DataTypeComponent fullDTCAt = full.getComponentAt(partDTC.getOffset());
|
||||
int fullOrd = fullDTCAt.getOrdinal();
|
||||
if (fullCompsUsedFlag[fullOrd]) {
|
||||
return false;
|
||||
}
|
||||
DataType partDT = partDTC.getDataType();
|
||||
DataType fullDT = fullDTCAt.getDataType();
|
||||
if (doRelaxedCompare(partDT, fullDT,
|
||||
visitedDataTypes) == ConflictResult.RENAME_AND_ADD) {
|
||||
return false;
|
||||
}
|
||||
fullCompsUsedFlag[fullOrd] = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Strict compare will compare its parameters.
|
||||
* The contents of these datatypes (ie. contents of structs, pointers, arrays)
|
||||
* will be compared with relaxed typedef checking.
|
||||
*/
|
||||
private ConflictResult doStrictCompare(DataType addedDataType,
|
||||
DataType existingDataType, Map<DataType, DataType> visitedDataTypes) {
|
||||
visitedDataTypes.put(existingDataType, addedDataType);
|
||||
if (existingDataType.isEquivalent(addedDataType)) {
|
||||
private ConflictResult resolveConflictReplaceEmpty(DataType addedDataType,
|
||||
DataType existingDataType) {
|
||||
if (addedDataType.isNotYetDefined()) {
|
||||
return ConflictResult.USE_EXISTING;
|
||||
}
|
||||
else if (existingDataType instanceof Composite &&
|
||||
addedDataType instanceof Composite) {
|
||||
Composite existingComposite = (Composite) existingDataType;
|
||||
Composite addedComposite = (Composite) addedDataType;
|
||||
|
||||
// Check to see if we are adding a default/empty data type
|
||||
if ((isCompositeEmpty(addedComposite) || isCompositeDefault(addedComposite)) &&
|
||||
isSizeCompatible(existingComposite, addedComposite)) {
|
||||
return ConflictResult.USE_EXISTING;
|
||||
}
|
||||
// Check to see if the existing type is a default/empty data type
|
||||
if ((isCompositeEmpty(existingComposite) ||
|
||||
isCompositeDefault(existingComposite)) &&
|
||||
isSizeCompatible(addedComposite, existingComposite)) {
|
||||
return ConflictResult.REPLACE_EXISTING;
|
||||
}
|
||||
// Check to see if the added type is part of the existing type first to
|
||||
// generate more USE_EXISTINGS when possible.
|
||||
if (isCompositePart(existingComposite, addedComposite, visitedDataTypes)) {
|
||||
return ConflictResult.USE_EXISTING;
|
||||
}
|
||||
// Check to see if the existing type is a part of the added type
|
||||
if (isCompositePart(addedComposite, existingComposite, visitedDataTypes)) {
|
||||
return ConflictResult.REPLACE_EXISTING;
|
||||
}
|
||||
if (existingDataType.isNotYetDefined()) {
|
||||
return ConflictResult.REPLACE_EXISTING;
|
||||
}
|
||||
else if (existingDataType instanceof TypeDef && addedDataType instanceof TypeDef) {
|
||||
TypeDef addedTypeDef = (TypeDef) addedDataType;
|
||||
TypeDef existingTypeDef = (TypeDef) existingDataType;
|
||||
return doRelaxedCompare(addedTypeDef.getBaseDataType(),
|
||||
existingTypeDef.getBaseDataType(), visitedDataTypes);
|
||||
}
|
||||
else if (existingDataType instanceof Array && addedDataType instanceof Array) {
|
||||
Array addedArray = (Array) addedDataType;
|
||||
Array existingArray = (Array) existingDataType;
|
||||
|
||||
if (addedArray.getNumElements() != existingArray.getNumElements() ||
|
||||
addedArray.getElementLength() != existingArray.getElementLength()) {
|
||||
return ConflictResult.RENAME_AND_ADD;
|
||||
}
|
||||
|
||||
return doRelaxedCompare(addedArray.getDataType(), existingArray.getDataType(),
|
||||
visitedDataTypes);
|
||||
}
|
||||
|
||||
return ConflictResult.RENAME_AND_ADD;
|
||||
}
|
||||
|
||||
/*
|
||||
* Relaxed compare will take liberties in skipping typedefs to try to compare
|
||||
* the types that the typedef are hiding. This is useful when comparing types
|
||||
* that were embedded in differently compiled files, where you might end up with
|
||||
* a raw basetype in one file and a typedef to a basetype in another file.
|
||||
*/
|
||||
private ConflictResult doRelaxedCompare(DataType addedDataType,
|
||||
DataType existingDataType, Map<DataType, DataType> visitedDataTypes) {
|
||||
|
||||
if (existingDataType instanceof Pointer && addedDataType instanceof Pointer) {
|
||||
DataType ptrAddedDataType = ((Pointer) addedDataType).getDataType();
|
||||
DataType ptrExistingDataType = ((Pointer) existingDataType).getDataType();
|
||||
// only descend into the pointed-to-type if we haven't looked at it before.
|
||||
// if you don't do this, you will have a stack-overflow issue when a struct
|
||||
// has a pointer to its same type.
|
||||
if (!visitedDataTypes.containsKey(ptrExistingDataType)) {
|
||||
visitedDataTypes.put(ptrExistingDataType, ptrAddedDataType);
|
||||
addedDataType = ptrAddedDataType;
|
||||
existingDataType = ptrExistingDataType;
|
||||
}
|
||||
|
||||
}
|
||||
// unwrap typedefs, possibly asymmetrically. (ie. only unwrap added vs. existing)
|
||||
if (addedDataType instanceof TypeDef) {
|
||||
addedDataType = ((TypeDef) addedDataType).getBaseDataType();
|
||||
}
|
||||
if (existingDataType instanceof TypeDef) {
|
||||
existingDataType = ((TypeDef) existingDataType).getBaseDataType();
|
||||
}
|
||||
return doStrictCompare(addedDataType, existingDataType, visitedDataTypes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConflictResult resolveConflict(DataType addedDataType,
|
||||
DataType existingDataType) {
|
||||
IdentityHashMap<DataType, DataType> visitedDataTypes = new IdentityHashMap<>();
|
||||
return doStrictCompare(addedDataType, existingDataType, visitedDataTypes);
|
||||
if (addedDataType instanceof Structure) {
|
||||
if (existingDataType instanceof Structure) {
|
||||
return resolveConflictReplaceEmpty(addedDataType, existingDataType);
|
||||
}
|
||||
}
|
||||
else if (addedDataType instanceof Union) {
|
||||
if (existingDataType instanceof Union) {
|
||||
return resolveConflictReplaceEmpty(addedDataType, existingDataType);
|
||||
}
|
||||
}
|
||||
return ConflictResult.RENAME_AND_ADD;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldUpdate(DataType sourceDataType, DataType localDataType) {
|
||||
return false;
|
||||
return sourceDataType.getLastChangeTime() > localDataType.getLastChangeTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -21,7 +21,6 @@ import java.util.Iterator;
|
|||
import javax.swing.event.ChangeEvent;
|
||||
import javax.swing.event.ChangeListener;
|
||||
|
||||
import ghidra.app.plugin.core.datamgr.archive.SourceArchive;
|
||||
import ghidra.docking.settings.*;
|
||||
import ghidra.util.*;
|
||||
|
||||
|
|
|
@ -17,9 +17,9 @@ package ghidra.program.model.data;
|
|||
|
||||
import java.util.*;
|
||||
|
||||
import ghidra.app.plugin.core.datamgr.archive.SourceArchive;
|
||||
import ghidra.util.InvalidNameException;
|
||||
import ghidra.util.UniversalID;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
/**
|
||||
|
@ -97,6 +97,18 @@ public interface DataTypeManager {
|
|||
*/
|
||||
public DataType addDataType(DataType dataType, DataTypeConflictHandler handler);
|
||||
|
||||
/**
|
||||
* Sequentially adds a collection of datatypes to this data manager.
|
||||
* This method provides the added benefit of equivalence caching
|
||||
* for improved performance.
|
||||
* @param dataTypes collection of datatypes
|
||||
* @param handler conflict handler
|
||||
* @param monitor task monitor
|
||||
* @throws CancelledException if monitor is cancelled
|
||||
*/
|
||||
public void addDataTypes(Collection<DataType> dataTypes, DataTypeConflictHandler handler,
|
||||
TaskMonitor monitor) throws CancelledException;
|
||||
|
||||
/**
|
||||
* Returns an iterator over all the dataTypes in this manager
|
||||
* @return an iterator over all the dataTypes in this manager
|
||||
|
|
|
@ -15,8 +15,6 @@
|
|||
*/
|
||||
package ghidra.program.model.data;
|
||||
|
||||
import ghidra.app.plugin.core.datamgr.archive.SourceArchive;
|
||||
|
||||
/**
|
||||
* The listener interface for notification of changes to a DataTypeManager
|
||||
*/
|
||||
|
|
|
@ -15,8 +15,6 @@
|
|||
*/
|
||||
package ghidra.program.model.data;
|
||||
|
||||
import ghidra.app.plugin.core.datamgr.archive.SourceArchive;
|
||||
|
||||
/**
|
||||
* Adapter for a Category change listener.
|
||||
*/
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
*/
|
||||
package ghidra.program.model.data;
|
||||
|
||||
import ghidra.app.plugin.core.datamgr.archive.SourceArchive;
|
||||
import ghidra.util.datastruct.WeakDataStructureFactory;
|
||||
import ghidra.util.datastruct.WeakSet;
|
||||
|
||||
|
|
|
@ -19,7 +19,6 @@ import java.io.IOException;
|
|||
import java.io.Writer;
|
||||
import java.util.*;
|
||||
|
||||
import ghidra.app.plugin.core.datamgr.archive.SourceArchive;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
@ -352,7 +351,7 @@ public class DataTypeWriter {
|
|||
}
|
||||
|
||||
private boolean containsComposite(Composite container, Composite contained) {
|
||||
for (DataTypeComponent component : container.getComponents()) {
|
||||
for (DataTypeComponent component : container.getDefinedComponents()) {
|
||||
DataType dt = getBaseArrayTypedefType(component.getDataType());
|
||||
if (dt instanceof Composite && dt.getName().equals(contained.getName()) &&
|
||||
dt.isEquivalent(contained)) {
|
||||
|
|
|
@ -18,7 +18,6 @@ package ghidra.program.model.data;
|
|||
import java.math.BigInteger;
|
||||
import java.util.*;
|
||||
|
||||
import ghidra.app.plugin.core.datamgr.archive.SourceArchive;
|
||||
import ghidra.docking.settings.Settings;
|
||||
import ghidra.docking.settings.SettingsDefinition;
|
||||
import ghidra.program.database.data.DataTypeUtilities;
|
||||
|
|
|
@ -17,7 +17,6 @@ package ghidra.program.model.data;
|
|||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import ghidra.app.plugin.core.datamgr.archive.SourceArchive;
|
||||
import ghidra.docking.settings.Settings;
|
||||
import ghidra.program.database.data.DataTypeUtilities;
|
||||
import ghidra.program.model.lang.PrototypeModel;
|
||||
|
@ -304,10 +303,10 @@ public class FunctionDefinitionDataType extends GenericDataType implements Funct
|
|||
if (dt == this) {
|
||||
return true;
|
||||
}
|
||||
if (!(dt instanceof FunctionSignature)) {
|
||||
if (!(dt instanceof FunctionDefinition)) {
|
||||
return false;
|
||||
}
|
||||
return isEquivalentSignature((FunctionSignature) dt);
|
||||
return isEquivalentSignature((FunctionDefinition) dt);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -409,4 +408,9 @@ public class FunctionDefinitionDataType extends GenericDataType implements Funct
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getPrototypeString(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
*/
|
||||
package ghidra.program.model.data;
|
||||
|
||||
import ghidra.app.plugin.core.datamgr.archive.SourceArchive;
|
||||
import ghidra.util.InvalidNameException;
|
||||
import ghidra.util.UniversalID;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
|
|
@ -55,7 +55,7 @@ public class ParameterDefinitionImpl implements ParameterDefinition {
|
|||
}
|
||||
|
||||
/**
|
||||
* Validate the specified datatype based upon its' use as a parameter or return type.
|
||||
* Validate the specified datatype based upon its use as a parameter or return type.
|
||||
* Ensure that the datatype has been cloned to the specified datatype manager (dtMgr).
|
||||
* @param dataType datatype to be validated
|
||||
* @param dtMgr target datatype manager
|
||||
|
|
|
@ -27,7 +27,7 @@ import ghidra.program.model.symbol.*;
|
|||
import ghidra.util.DataConverter;
|
||||
|
||||
/**
|
||||
* Basic implementation for a pointer dataType
|
||||
* Basic implementation for a pointer dataType
|
||||
*/
|
||||
public class PointerDataType extends BuiltIn implements Pointer {
|
||||
|
||||
|
@ -48,26 +48,27 @@ public class PointerDataType extends BuiltIn implements Pointer {
|
|||
private String displayName;
|
||||
|
||||
/**
|
||||
* <code>isEquivalentActive</code> is used to break cyclical recursion
|
||||
* when performing an {@link #isEquivalent(DataType)} checks on pointers
|
||||
* which must also check the base datatype equivelency.
|
||||
* <code>isEquivalentActive</code> is used to break cyclical recursion when
|
||||
* performing an {@link #isEquivalent(DataType)} checks on pointers which must
|
||||
* also check the base datatype equivelency.
|
||||
*/
|
||||
private ThreadLocal<Boolean> isEquivalentActive = ThreadLocal.withInitial(() -> Boolean.FALSE);
|
||||
|
||||
/**
|
||||
* Creates a dynamically-sized default pointer data type.
|
||||
* A dynamic pointer size of 4-bytes will be in used, but will adapt to a data type manager's
|
||||
* data organization when resolved.
|
||||
* Creates a dynamically-sized default pointer data type. A dynamic pointer size
|
||||
* of 4-bytes will be in used, but will adapt to a data type manager's data
|
||||
* organization when resolved.
|
||||
*/
|
||||
public PointerDataType() {
|
||||
this(null, -1, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a dynamically-sized default pointer data type.
|
||||
* The pointer size is established dynamically based upon the data organization
|
||||
* associated with the specified dtm but can adapt to another data type manager's
|
||||
* data organization when resolved.
|
||||
* Creates a dynamically-sized default pointer data type. The pointer size is
|
||||
* established dynamically based upon the data organization associated with the
|
||||
* specified dtm but can adapt to another data type manager's data organization
|
||||
* when resolved.
|
||||
*
|
||||
* @param dtm data-type manager whose data organization should be used
|
||||
*/
|
||||
public PointerDataType(DataTypeManager dtm) {
|
||||
|
@ -75,9 +76,10 @@ public class PointerDataType extends BuiltIn implements Pointer {
|
|||
}
|
||||
|
||||
/**
|
||||
* Construct a dynamically-sized pointer to a referencedDataType
|
||||
* A dynamic pointer size of 4-bytes will be in used, but will adapt to a data type manager's
|
||||
* data organization when resolved.
|
||||
* Construct a dynamically-sized pointer to a referencedDataType A dynamic
|
||||
* pointer size of 4-bytes will be in used, but will adapt to a data type
|
||||
* manager's data organization when resolved.
|
||||
*
|
||||
* @param referencedDataType data type this pointer points to
|
||||
*/
|
||||
public PointerDataType(DataType referencedDataType) {
|
||||
|
@ -85,37 +87,44 @@ public class PointerDataType extends BuiltIn implements Pointer {
|
|||
}
|
||||
|
||||
/**
|
||||
* Construct a pointer of a specified length to a referencedDataType.
|
||||
* Note: It is preferred to use default sized pointers when possible (i.e., length=-1,
|
||||
* see {@link #PointerDataType(DataType)}) instead of explicitly specifying
|
||||
* the pointer length value.
|
||||
* Construct a pointer of a specified length to a referencedDataType. Note: It
|
||||
* is preferred to use default sized pointers when possible (i.e., length=-1,
|
||||
* see {@link #PointerDataType(DataType)}) instead of explicitly specifying the
|
||||
* pointer length value.
|
||||
*
|
||||
* @param referencedDataType data type this pointer points to
|
||||
* @param length pointer length (values <= 0 will result in dynamically-sized pointer)
|
||||
* @param length pointer length (values <= 0 will result in
|
||||
* dynamically-sized pointer)
|
||||
*/
|
||||
public PointerDataType(DataType referencedDataType, int length) {
|
||||
this(referencedDataType, length, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a dynamically-sized pointer to the given data type.
|
||||
* The pointer size is established dynamically based upon the data organization
|
||||
* associated with the specified dtm but can adapt to another data type manager's
|
||||
* data organization when resolved.
|
||||
* Construct a dynamically-sized pointer to the given data type. The pointer
|
||||
* size is established dynamically based upon the data organization associated
|
||||
* with the specified dtm but can adapt to another data type manager's data
|
||||
* organization when resolved.
|
||||
*
|
||||
* @param referencedDataType data type this pointer points to
|
||||
* @param dtm data-type manager whose data organization should be used
|
||||
* @param dtm data-type manager whose data organization should be
|
||||
* used
|
||||
*/
|
||||
public PointerDataType(DataType referencedDataType, DataTypeManager dtm) {
|
||||
this(referencedDataType, -1, dtm);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a pointer of a specified length to a referencedDataType.
|
||||
* Note: It is preferred to use default sized pointers when possible (i.e., length=-1,
|
||||
* see {@link #PointerDataType(DataType, DataTypeManager)}) instead of explicitly specifying
|
||||
* the pointer length value.
|
||||
* @param referencedDataType
|
||||
* @param length pointer length (-1 will result in dynamically-sized pointer)
|
||||
* @param dtm associated data type manager whose data organization will be used
|
||||
* Construct a pointer of a specified length to a referencedDataType. Note: It
|
||||
* is preferred to use default sized pointers when possible (i.e., length=-1,
|
||||
* see {@link #PointerDataType(DataType, DataTypeManager)}) instead of
|
||||
* explicitly specifying the pointer length value.
|
||||
*
|
||||
* @param referencedDataType data type this pointer points to
|
||||
* @param length pointer length (-1 will result in dynamically-sized
|
||||
* pointer)
|
||||
* @param dtm associated data type manager whose data
|
||||
* organization will be used
|
||||
*/
|
||||
public PointerDataType(DataType referencedDataType, int length, DataTypeManager dtm) {
|
||||
super(referencedDataType != null ? referencedDataType.getCategoryPath() : null,
|
||||
|
@ -208,7 +217,7 @@ public class PointerDataType extends BuiltIn implements Pointer {
|
|||
private enum PointerReferenceClassification {
|
||||
// NORMAL - use recursive name generation (e.g., PTR_PTR_BYTE)
|
||||
NORMAL,
|
||||
// LOOP - references loop back - use label prefix PTR_LOOP
|
||||
// LOOP - references loop back - use label prefix PTR_LOOP
|
||||
LOOP,
|
||||
// DEEP - references are too deep - use simple default label prefix
|
||||
DEEP
|
||||
|
@ -330,9 +339,11 @@ public class PointerDataType extends BuiltIn implements Pointer {
|
|||
}
|
||||
|
||||
/**
|
||||
* Generate an address value based upon bytes stored at the specified buf location
|
||||
* @param buf memory buffer and stored pointer location
|
||||
* @param size pointer size in bytes
|
||||
* Generate an address value based upon bytes stored at the specified buf
|
||||
* location
|
||||
*
|
||||
* @param buf memory buffer and stored pointer location
|
||||
* @param size pointer size in bytes
|
||||
* @param targetSpace address space for returned pointer
|
||||
* @return pointer value or null if unusable buf or data
|
||||
*/
|
||||
|
@ -377,13 +388,13 @@ public class PointerDataType extends BuiltIn implements Pointer {
|
|||
}
|
||||
|
||||
/**
|
||||
* Read segmented address from memory.
|
||||
* NOTE: little-endian memory assumed.
|
||||
* @param buf memory buffer associated with a segmented-address space
|
||||
* positioned at start of address value to be read
|
||||
* Read segmented address from memory. NOTE: little-endian memory assumed.
|
||||
*
|
||||
* @param buf memory buffer associated with a segmented-address space
|
||||
* positioned at start of address value to be read
|
||||
* @param dataLen pointer-length (2 and 4-byte pointers supported)
|
||||
* @return address value returned as segmented Address object or null
|
||||
* for unsupported pointer length or meory access error occurs.
|
||||
* @return address value returned as segmented Address object or null for
|
||||
* unsupported pointer length or meory access error occurs.
|
||||
*/
|
||||
private static Address getSegmentedAddressValue(MemBuffer buf, int dataLen) {
|
||||
SegmentedAddress a = (SegmentedAddress) buf.getAddress();
|
||||
|
@ -461,7 +472,8 @@ public class PointerDataType extends BuiltIn implements Pointer {
|
|||
return false;
|
||||
}
|
||||
|
||||
// if they contain datatypes that have same ids, then we are essentially equivalent.
|
||||
// if they contain datatypes that have same ids, then we are essentially
|
||||
// equivalent.
|
||||
if (DataTypeUtilities.isSameDataType(referencedDataType, otherDataType)) {
|
||||
return true;
|
||||
}
|
||||
|
@ -471,6 +483,15 @@ public class PointerDataType extends BuiltIn implements Pointer {
|
|||
return false;
|
||||
}
|
||||
|
||||
// TODO: The pointer deep-dive equivalence checking on the referenced datatype can
|
||||
// cause types containing pointers (composites, functions) to conflict when in
|
||||
// reality the referenced type simply has multiple implementations which differ.
|
||||
// Although without doing this Ghidra may fail to resolve dependencies which differ
|
||||
// from those already contained within a datatype manager.
|
||||
// Ghidra's rigid datatype relationships prevent the flexibility to handle
|
||||
// multiple implementations of a named datatype without inducing a conflicted
|
||||
// datatype hierarchy.
|
||||
|
||||
if (isEquivalentActive.get()) {
|
||||
return true;
|
||||
}
|
||||
|
@ -538,9 +559,10 @@ public class PointerDataType extends BuiltIn implements Pointer {
|
|||
|
||||
/**
|
||||
* Get a pointer data-type instance with a default size
|
||||
* @param dt data-type referenced by pointer
|
||||
* @param dtm program data-type manager (required)
|
||||
* a generic data-type will be returned if possible.
|
||||
*
|
||||
* @param dt data-type referenced by pointer
|
||||
* @param dtm program data-type manager (required) a generic data-type will be
|
||||
* returned if possible.
|
||||
* @return signed integer data type
|
||||
*/
|
||||
public static Pointer getPointer(DataType dt, DataTypeManager dtm) {
|
||||
|
@ -548,14 +570,14 @@ public class PointerDataType extends BuiltIn implements Pointer {
|
|||
}
|
||||
|
||||
/**
|
||||
* Get a pointer data-type instance of the requested size.
|
||||
* NOTE: The returned data-type will not be associated with any
|
||||
* particular data-type-manager and may therefore not utilize
|
||||
* dynamically-sized-pointers when a valid pointerSize is specified.
|
||||
* If an invalid pointerSize is specified, a dynamically-size pointer
|
||||
* will be returned whose length is based upon the default-data-organization.
|
||||
* Get a pointer data-type instance of the requested size. NOTE: The returned
|
||||
* data-type will not be associated with any particular data-type-manager and
|
||||
* may therefore not utilize dynamically-sized-pointers when a valid pointerSize
|
||||
* is specified. If an invalid pointerSize is specified, a dynamically-size
|
||||
* pointer will be returned whose length is based upon the
|
||||
* default-data-organization.
|
||||
*
|
||||
* @param dt data-type referenced by pointer
|
||||
* @param dt data-type referenced by pointer
|
||||
* @param pointerSize pointer size
|
||||
* @return signed integer data type
|
||||
*/
|
||||
|
@ -578,7 +600,7 @@ public class PointerDataType extends BuiltIn implements Pointer {
|
|||
@Override
|
||||
public String getName() {
|
||||
if (referencedDataType != null) {
|
||||
// referencedDataType may have had name set, so re-create this pointer name.
|
||||
// referencedDataType may have had name set, so re-create this pointer name.
|
||||
name = constructUniqueName(referencedDataType, length);
|
||||
}
|
||||
return super.getName();
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -14,9 +13,8 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.app.plugin.core.datamgr.archive;
|
||||
package ghidra.program.model.data;
|
||||
|
||||
import ghidra.program.model.data.ArchiveType;
|
||||
import ghidra.util.UniversalID;
|
||||
|
||||
|
|
@ -17,8 +17,6 @@ package ghidra.program.model.data;
|
|||
|
||||
import java.util.Comparator;
|
||||
|
||||
import ghidra.util.exception.InvalidInputException;
|
||||
|
||||
/**
|
||||
* The structure interface.
|
||||
* <p>
|
||||
|
@ -127,7 +125,7 @@ public interface Structure extends Composite {
|
|||
* <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 determining its' ordinal placement.
|
||||
* is of significance in determining its ordinal placement.
|
||||
* <p>
|
||||
* @param byteOffset the first byte offset within this structure which corresponds to the
|
||||
* first byte of the specified storage unit identified by its byteWidth.
|
||||
|
@ -166,7 +164,8 @@ public interface Structure extends Composite {
|
|||
* For example, suppose dt1 contains dt2. Therefore it is not valid
|
||||
* to insert dt1 to dt2 since this would cause a cyclic dependency.
|
||||
*/
|
||||
public DataTypeComponent insertAtOffset(int offset, DataType dataType, int length);
|
||||
public DataTypeComponent insertAtOffset(int offset, DataType dataType, int length)
|
||||
throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Inserts a new datatype at the specified offset into this structure.
|
||||
|
@ -185,7 +184,7 @@ public interface Structure extends Composite {
|
|||
* to insert dt1 to dt2 since this would cause a cyclic dependency.
|
||||
*/
|
||||
public DataTypeComponent insertAtOffset(int offset, DataType dataType, int length, String name,
|
||||
String comment);
|
||||
String comment) throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Deletes the component containing the specified offset in this structure. If the offset
|
||||
|
@ -208,7 +207,7 @@ public interface Structure extends Composite {
|
|||
* @param index the index of the component to clear.
|
||||
* @throws ArrayIndexOutOfBoundsException if component ordinal is out of bounds
|
||||
*/
|
||||
public void clearComponent(int index);
|
||||
public void clearComponent(int index) throws ArrayIndexOutOfBoundsException;
|
||||
|
||||
/**
|
||||
* Replaces the component at the given component index with a new component
|
||||
|
@ -227,7 +226,8 @@ public interface Structure extends Composite {
|
|||
* component or specify a {@link BitFieldDataType} will produce this error.
|
||||
* @throws ArrayIndexOutOfBoundsException if component index is out of bounds
|
||||
*/
|
||||
public DataTypeComponent replace(int index, DataType dataType, int length);
|
||||
public DataTypeComponent replace(int index, DataType dataType, int length)
|
||||
throws ArrayIndexOutOfBoundsException, IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Replaces the component at the given component index with a new component
|
||||
|
@ -249,7 +249,7 @@ public interface Structure extends Composite {
|
|||
* @throws ArrayIndexOutOfBoundsException if component index is out of bounds
|
||||
*/
|
||||
public DataTypeComponent replace(int index, DataType dataType, int length, String name,
|
||||
String comment);
|
||||
String comment) throws ArrayIndexOutOfBoundsException, IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Replaces the component at the specified byte offset with a new component
|
||||
|
@ -274,21 +274,7 @@ public interface Structure extends Composite {
|
|||
* component or specify a {@link BitFieldDataType} will produce this error.
|
||||
*/
|
||||
public DataTypeComponent replaceAtOffset(int offset, DataType dataType, int length, String name,
|
||||
String comment);
|
||||
|
||||
/**
|
||||
* Returns a list of all components that make up this data type excluding any trailing
|
||||
* flexible array component if present.
|
||||
* @return an array containing the components
|
||||
*/
|
||||
@Override
|
||||
public abstract DataTypeComponent[] getComponents();
|
||||
|
||||
/**
|
||||
* Returns the list of components that are defined. (As opposed to "filler"
|
||||
* undefined bytes.). Any trailing flexible array component will be omitted.
|
||||
*/
|
||||
public DataTypeComponent[] getDefinedComponents();
|
||||
String comment) throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Determine if a trailing flexible array component has been defined.
|
||||
|
@ -309,32 +295,17 @@ public interface Structure extends Composite {
|
|||
* @param name component field name or null for default name
|
||||
* @param comment component comment
|
||||
* @return updated flexible array component
|
||||
* @throws IllegalArgumentException if specified flexType is not permitted (e.g.,
|
||||
* self referencing or unsupported type)
|
||||
*/
|
||||
public DataTypeComponent setFlexibleArrayComponent(DataType flexType, String name,
|
||||
String comment);
|
||||
String comment) throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Remove the optional trailing flexible array component associated with this structure.
|
||||
*/
|
||||
public void clearFlexibleArrayComponent();
|
||||
|
||||
/**
|
||||
* Gets the number of component data types in this data type excluding any trailing flexible
|
||||
* array component if present.
|
||||
* @return the number of components that make up this data prototype
|
||||
*/
|
||||
@Override
|
||||
public abstract int getNumComponents();
|
||||
|
||||
/**
|
||||
* Returns the number of non-undefined components in this composite. For example, say
|
||||
* a structure has an int (4 bytes) at offset 0 and another int at offset 8. This structure
|
||||
* would have 6 total components (one for each undefined between the two ints), but only
|
||||
* 2 defined components. Any trailing flexible array component will not be included in this count.
|
||||
* @return the number of non-undefined components in this composite
|
||||
*/
|
||||
public abstract int getNumDefinedComponents();
|
||||
|
||||
/**
|
||||
* Increases the size of the structure by the given amount by adding undefined datatypes
|
||||
* at the end of the structure.
|
||||
|
@ -343,7 +314,16 @@ public interface Structure extends Composite {
|
|||
*/
|
||||
public void growStructure(int amount);
|
||||
|
||||
public void pack(int maxAlignment) throws InvalidInputException;
|
||||
/**
|
||||
* 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
|
||||
|
|
|
@ -17,14 +17,12 @@ package ghidra.program.model.data;
|
|||
|
||||
import java.util.*;
|
||||
|
||||
import ghidra.app.plugin.core.datamgr.archive.SourceArchive;
|
||||
import ghidra.docking.settings.Settings;
|
||||
import ghidra.program.model.data.AlignedStructurePacker.StructurePackResult;
|
||||
import ghidra.program.model.mem.MemBuffer;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.UniversalID;
|
||||
import ghidra.util.exception.AssertException;
|
||||
import ghidra.util.exception.InvalidInputException;
|
||||
|
||||
/**
|
||||
* Basic implementation of the structure data type
|
||||
|
@ -42,28 +40,55 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur
|
|||
private int alignment = -1;
|
||||
|
||||
/**
|
||||
* Construct a new structure with the given name and number of undefined bytes
|
||||
* Construct a new structure with the given name and length.
|
||||
* The root category will be used.
|
||||
* @param name the name of the new structure
|
||||
* @param length the initial size of the structure
|
||||
* @param length the initial size of the structure in bytes. If 0 is specified
|
||||
* the structure will report its length as 1 and {@link #isNotYetDefined()}
|
||||
* will return true.
|
||||
*/
|
||||
public StructureDataType(String name, int length) {
|
||||
this(CategoryPath.ROOT, name, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new structure with the given name, length and datatype manager
|
||||
* which conveys data organization. The root category will be used.
|
||||
* @param name the name of the new structure
|
||||
* @param length the initial size of the structure in bytes. If 0 is specified
|
||||
* the structure will report its length as 1 and {@link #isNotYetDefined()}
|
||||
* will return true.
|
||||
* @param dtm the data type manager associated with this data type. This can be null.
|
||||
* Also, the data type manager may not yet contain this actual data type.
|
||||
*/
|
||||
public StructureDataType(String name, int length, DataTypeManager dtm) {
|
||||
this(CategoryPath.ROOT, name, length, dtm);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new structure with the given name and number of undefined bytes
|
||||
* Construct a new structure with the given name and length within the
|
||||
* specified categry path.
|
||||
* @param path the category path indicating where this data type is located.
|
||||
* @param name the name of the new structure
|
||||
* @param length the initial size of the structure
|
||||
* @param length the initial size of the structure in bytes. If 0 is specified
|
||||
* the structure will report its length as 1 and {@link #isNotYetDefined()}
|
||||
* will return true.
|
||||
*/
|
||||
public StructureDataType(CategoryPath path, String name, int length) {
|
||||
this(path, name, length, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new structure with the given name, length and datatype manager
|
||||
* within the specified categry path.
|
||||
* @param path the category path indicating where this data type is located.
|
||||
* @param name the name of the new structure
|
||||
* @param length the initial size of the structure in bytes. If 0 is specified
|
||||
* the structure will report its length as 1 and {@link #isNotYetDefined()}
|
||||
* will return true.
|
||||
* @param dtm the data type manager associated with this data type. This can be null.
|
||||
* Also, the data type manager may not yet contain this actual data type.
|
||||
*/
|
||||
public StructureDataType(CategoryPath path, String name, int length, DataTypeManager dtm) {
|
||||
super(path, name, dtm);
|
||||
if (length < 0) {
|
||||
|
@ -76,17 +101,19 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur
|
|||
}
|
||||
|
||||
/**
|
||||
* Construct a new structure with the given name and number of undefined bytes
|
||||
* Construct a new structure with the given name and length
|
||||
* @param path the category path indicating where this data type is located.
|
||||
* @param name the name of the new structure
|
||||
* @param length the initial size of the structure
|
||||
* @param length the initial size of the structure in bytes. If 0 is specified
|
||||
* the structure will report its length as 1 and {@link #isNotYetDefined()}
|
||||
* will return true.
|
||||
* @param universalID the id for the data type
|
||||
* @param sourceArchive the source archive for this data type
|
||||
* @param lastChangeTime the last time this data type was changed
|
||||
* @param lastChangeTimeInSourceArchive the last time this data type was changed in
|
||||
* its source archive.
|
||||
* @param dtm the data type manager associated with this data type. This can be null.
|
||||
* Also, the data type manager may not contain this actual data type.
|
||||
* Also, the data type manager may not yet contain this actual data type.
|
||||
*/
|
||||
public StructureDataType(CategoryPath path, String name, int length, UniversalID universalID,
|
||||
SourceArchive sourceArchive, long lastChangeTime, long lastChangeTimeInSourceArchive,
|
||||
|
@ -297,7 +324,7 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur
|
|||
|
||||
@Override
|
||||
public DataTypeComponentImpl insertAtOffset(int offset, DataType dataType, int length,
|
||||
String componentName, String comment) {
|
||||
String componentName, String comment) throws IllegalArgumentException {
|
||||
|
||||
if (offset < 0) {
|
||||
throw new IllegalArgumentException("Offset cannot be negative.");
|
||||
|
@ -384,10 +411,12 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur
|
|||
* set based upon the specified fixed-length dataType;
|
||||
* @param componentName component name
|
||||
* @param comment componetn comment
|
||||
* @return
|
||||
* @return newly added component
|
||||
* @throws IllegalArgumentException if the specified data type is not
|
||||
* allowed to be added to this composite data type or an invalid length is specified.
|
||||
*/
|
||||
private DataTypeComponent doAdd(DataType dataType, int length, boolean isFlexibleArray,
|
||||
String componentName, String comment) {
|
||||
String componentName, String comment) throws IllegalArgumentException {
|
||||
|
||||
validateDataType(dataType);
|
||||
|
||||
|
@ -450,7 +479,7 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur
|
|||
|
||||
@Override
|
||||
public DataTypeComponent insert(int index, DataType dataType, int length, String componentName,
|
||||
String comment) {
|
||||
String comment) throws ArrayIndexOutOfBoundsException, IllegalArgumentException {
|
||||
if (index < 0 || index > numComponents) {
|
||||
throw new ArrayIndexOutOfBoundsException(index);
|
||||
}
|
||||
|
@ -741,51 +770,49 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur
|
|||
|
||||
@Override
|
||||
public boolean isEquivalent(DataType dataType) {
|
||||
|
||||
if (dataType == this) {
|
||||
return true;
|
||||
}
|
||||
if (dataType == null) {
|
||||
if (!(dataType instanceof Structure)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dataType instanceof Structure) {
|
||||
Structure struct = (Structure) dataType;
|
||||
if (isInternallyAligned() != struct.isInternallyAligned() ||
|
||||
isDefaultAligned() != struct.isDefaultAligned() ||
|
||||
isMachineAligned() != struct.isMachineAligned() ||
|
||||
getMinimumAlignment() != struct.getMinimumAlignment() ||
|
||||
getPackingValue() != struct.getPackingValue() ||
|
||||
(!isInternallyAligned() && (getLength() != struct.getLength()))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DataTypeComponent myFlexComp = getFlexibleArrayComponent();
|
||||
DataTypeComponent otherFlexComp = struct.getFlexibleArrayComponent();
|
||||
if (myFlexComp != null) {
|
||||
if (otherFlexComp == null || !myFlexComp.isEquivalent(otherFlexComp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (otherFlexComp != null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int myNumComps = getNumComponents();
|
||||
int otherNumComps = struct.getNumComponents();
|
||||
if (myNumComps != otherNumComps) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < myNumComps; i++) {
|
||||
DataTypeComponent myDtc = getComponent(i);
|
||||
DataTypeComponent otherDtc = struct.getComponent(i);
|
||||
|
||||
if (!myDtc.isEquivalent(otherDtc)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
Structure struct = (Structure) dataType;
|
||||
if (isInternallyAligned() != struct.isInternallyAligned() ||
|
||||
isDefaultAligned() != struct.isDefaultAligned() ||
|
||||
isMachineAligned() != struct.isMachineAligned() ||
|
||||
getMinimumAlignment() != struct.getMinimumAlignment() ||
|
||||
getPackingValue() != struct.getPackingValue() ||
|
||||
(!isInternallyAligned() && (getLength() != struct.getLength()))) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
|
||||
DataTypeComponent myFlexComp = getFlexibleArrayComponent();
|
||||
DataTypeComponent otherFlexComp = struct.getFlexibleArrayComponent();
|
||||
if (myFlexComp != null) {
|
||||
if (otherFlexComp == null || !myFlexComp.isEquivalent(otherFlexComp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (otherFlexComp != null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int myNumComps = getNumComponents();
|
||||
int otherNumComps = struct.getNumComponents();
|
||||
if (myNumComps != otherNumComps) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < myNumComps; i++) {
|
||||
DataTypeComponent myDtc = getComponent(i);
|
||||
DataTypeComponent otherDtc = struct.getComponent(i);
|
||||
|
||||
if (!myDtc.isEquivalent(otherDtc)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -973,7 +1000,7 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur
|
|||
}
|
||||
}
|
||||
|
||||
private void doReplaceWithUnaligned(Structure struct) {
|
||||
private void doReplaceWithUnaligned(Structure struct) throws IllegalArgumentException {
|
||||
// assumes components is clear and that alignment characteristics have been set.
|
||||
if (struct.isNotYetDefined()) {
|
||||
return;
|
||||
|
@ -1027,7 +1054,8 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur
|
|||
}
|
||||
|
||||
@Override
|
||||
public void dataTypeReplaced(DataType oldDt, DataType replacementDt) {
|
||||
public void dataTypeReplaced(DataType oldDt, DataType replacementDt)
|
||||
throws IllegalArgumentException {
|
||||
DataType newDt = replacementDt;
|
||||
try {
|
||||
validateDataType(replacementDt);
|
||||
|
@ -1150,7 +1178,7 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur
|
|||
|
||||
@Override
|
||||
public DataTypeComponent replace(int index, DataType dataType, int length, String componentName,
|
||||
String comment) {
|
||||
String comment) throws ArrayIndexOutOfBoundsException, IllegalArgumentException {
|
||||
if (index < 0 || index >= numComponents) {
|
||||
throw new ArrayIndexOutOfBoundsException(index);
|
||||
}
|
||||
|
@ -1185,7 +1213,7 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur
|
|||
|
||||
@Override
|
||||
public DataTypeComponent replaceAtOffset(int offset, DataType dataType, int length,
|
||||
String componentName, String comment) {
|
||||
String componentName, String comment) throws IllegalArgumentException {
|
||||
if (offset < 0) {
|
||||
throw new IllegalArgumentException("Offset cannot be negative.");
|
||||
}
|
||||
|
@ -1351,7 +1379,7 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur
|
|||
}
|
||||
|
||||
@Override
|
||||
public void pack(int packingSize) throws InvalidInputException {
|
||||
public void pack(int packingSize) {
|
||||
setPackingValue(packingSize);
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
*/
|
||||
package ghidra.program.model.data;
|
||||
|
||||
import ghidra.app.plugin.core.datamgr.archive.SourceArchive;
|
||||
import ghidra.docking.settings.Settings;
|
||||
import ghidra.docking.settings.SettingsDefinition;
|
||||
import ghidra.program.database.data.DataTypeUtilities;
|
||||
|
@ -233,4 +232,9 @@ public class TypedefDataType extends GenericDataType implements TypeDef {
|
|||
return (myDt == dt || myDt.dependsOn(dt));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "typedef " + getName() + " " + dataType.getName();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,7 +18,6 @@ package ghidra.program.model.data;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
|
||||
import ghidra.app.plugin.core.datamgr.archive.SourceArchive;
|
||||
import ghidra.docking.settings.Settings;
|
||||
import ghidra.program.model.mem.MemBuffer;
|
||||
import ghidra.util.Msg;
|
||||
|
@ -32,21 +31,34 @@ public class UnionDataType extends CompositeDataTypeImpl implements Union {
|
|||
private int unionLength;
|
||||
|
||||
/**
|
||||
* Construct a new UnionDataType
|
||||
* Construct a new empty union with the given name within the
|
||||
* specified categry path. An empty union will report its length as 1 and
|
||||
* {@link #isNotYetDefined()} will return true.
|
||||
* @param path the category path indicating where this data type is located.
|
||||
* @param name the name of this dataType
|
||||
* @param name the name of the new union
|
||||
*/
|
||||
public UnionDataType(CategoryPath path, String name) {
|
||||
this(path, name, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new empty union with the given name and datatype manager
|
||||
* within the specified categry path. An empty union will report its
|
||||
* length as 1 and {@link #isNotYetDefined()} will return true.
|
||||
* @param path the category path indicating where this data type is located.
|
||||
* @param name the name of the new union
|
||||
* @param dtm the data type manager associated with this data type. This can be null.
|
||||
* Also, the data type manager may not yet contain this actual data type.
|
||||
*/
|
||||
public UnionDataType(CategoryPath path, String name, DataTypeManager dtm) {
|
||||
super(path, name, dtm);
|
||||
components = new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new UnionDataType
|
||||
* Construct a new empty union with the given name within the specified categry path.
|
||||
* An empty union will report its length as 1 and {@link #isNotYetDefined()}
|
||||
* will return true.
|
||||
* @param path the category path indicating where this data type is located.
|
||||
* @param name the name of the new structure
|
||||
* @param universalID the id for the data type
|
||||
|
@ -97,14 +109,24 @@ public class UnionDataType extends CompositeDataTypeImpl implements Union {
|
|||
return components.toArray(new DataTypeComponent[components.size()]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataTypeComponent[] getDefinedComponents() {
|
||||
return getComponents();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumComponents() {
|
||||
return components.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumDefinedComponents() {
|
||||
return components.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataTypeComponent add(DataType dataType, int length, String componentName,
|
||||
String comment) {
|
||||
String comment) throws IllegalArgumentException {
|
||||
DataTypeComponent dtc = doAdd(dataType, length, componentName, comment);
|
||||
adjustLength(true);
|
||||
return dtc;
|
||||
|
@ -130,7 +152,8 @@ public class UnionDataType extends CompositeDataTypeImpl implements Union {
|
|||
return length;
|
||||
}
|
||||
|
||||
DataTypeComponent doAdd(DataType dataType, int length, String componentName, String comment) {
|
||||
DataTypeComponent doAdd(DataType dataType, int length, String componentName, String comment)
|
||||
throws IllegalArgumentException {
|
||||
|
||||
validateDataType(dataType);
|
||||
|
||||
|
@ -151,8 +174,7 @@ public class UnionDataType extends CompositeDataTypeImpl implements Union {
|
|||
|
||||
@Override
|
||||
public DataTypeComponent insert(int ordinal, DataType dataType, int length,
|
||||
String componentName, String comment) {
|
||||
|
||||
String componentName, String comment) throws IllegalArgumentException {
|
||||
validateDataType(dataType);
|
||||
|
||||
dataType = adjustBitField(dataType);
|
||||
|
@ -365,7 +387,7 @@ public class UnionDataType extends CompositeDataTypeImpl implements Union {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void dataTypeReplaced(DataType oldDt, DataType newDt) {
|
||||
public void dataTypeReplaced(DataType oldDt, DataType newDt) throws IllegalArgumentException {
|
||||
DataType replacementDt = newDt;
|
||||
try {
|
||||
validateDataType(replacementDt);
|
||||
|
@ -450,18 +472,8 @@ public class UnionDataType extends CompositeDataTypeImpl implements Union {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the internal components of this union with components of the
|
||||
* given union.
|
||||
* @param dataType the union to get the component information from.
|
||||
* @throws IllegalArgumentException if any of the component data types
|
||||
* are not allowed to replace a component in this composite data type.
|
||||
* 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.
|
||||
*/
|
||||
@Override
|
||||
public void replaceWith(DataType dataType) {
|
||||
public void replaceWith(DataType dataType) throws IllegalArgumentException {
|
||||
if (!(dataType instanceof Union)) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
@ -478,8 +490,7 @@ public class UnionDataType extends CompositeDataTypeImpl implements Union {
|
|||
setAlignment(union);
|
||||
|
||||
DataTypeComponent[] compArray = union.getComponents();
|
||||
for (int i = 0; i < compArray.length; i++) {
|
||||
DataTypeComponent dtc = compArray[i];
|
||||
for (DataTypeComponent dtc : compArray) {
|
||||
DataType dt = dtc.getDataType();
|
||||
doAdd(dt, dtc.getLength(), dtc.getFieldName(), dtc.getComment());
|
||||
}
|
||||
|
|
|
@ -965,7 +965,7 @@ public class SymbolUtilities {
|
|||
* may be returned. If attempting to create a global symbol and the name already exists
|
||||
* at the address no symbol will be created and null will be returned.
|
||||
* If attempting to create a non-global symbol, which does not exist,
|
||||
* and a global symbol does exist with same name its' namespace will be changed.
|
||||
* and a global symbol does exist with same name its namespace will be changed.
|
||||
* @param program program within which the symbol should be created
|
||||
* @param address memory address where symbol should be created
|
||||
* @param namespace symbol namespace or null for global
|
||||
|
|
|
@ -15,8 +15,7 @@
|
|||
*/
|
||||
package ghidra.program.model.data;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
|
@ -111,7 +110,7 @@ public class CompositeTestUtils {
|
|||
}
|
||||
|
||||
private static void collectComposites(Composite composite, Set<Composite> collection) {
|
||||
for (DataTypeComponent c : composite.getComponents()) {
|
||||
for (DataTypeComponent c : composite.getDefinedComponents()) {
|
||||
DataType dt = c.getDataType();
|
||||
if (dt instanceof Composite) {
|
||||
Composite childComposite = (Composite) dt;
|
||||
|
|
|
@ -17,7 +17,6 @@ package ghidra.program.model.data;
|
|||
|
||||
import java.net.URL;
|
||||
|
||||
import ghidra.app.plugin.core.datamgr.archive.SourceArchive;
|
||||
import ghidra.docking.settings.Settings;
|
||||
import ghidra.docking.settings.SettingsDefinition;
|
||||
import ghidra.program.model.mem.MemBuffer;
|
||||
|
|
|
@ -17,8 +17,8 @@ package ghidra.program.model.data;
|
|||
|
||||
import java.util.*;
|
||||
|
||||
import ghidra.app.plugin.core.datamgr.archive.SourceArchive;
|
||||
import ghidra.util.*;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
/**
|
||||
|
@ -58,6 +58,12 @@ public class TestDoubleDataTypeManager implements DataTypeManager {
|
|||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addDataTypes(Collection<DataType> dataTypes, DataTypeConflictHandler handler,
|
||||
TaskMonitor monitor) throws CancelledException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<DataType> getAllDataTypes() {
|
||||
throw new UnsupportedOperationException();
|
||||
|
|
|
@ -17,9 +17,9 @@ package ghidra.program.model.data;
|
|||
|
||||
import java.util.*;
|
||||
|
||||
import ghidra.app.plugin.core.datamgr.archive.SourceArchive;
|
||||
import ghidra.util.InvalidNameException;
|
||||
import ghidra.util.UniversalID;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
/**
|
||||
|
@ -57,6 +57,12 @@ public class TestDummyDataTypeManager implements DataTypeManager {
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addDataTypes(Collection<DataType> dataTypes, DataTypeConflictHandler handler,
|
||||
TaskMonitor monitor) throws CancelledException {
|
||||
// stub
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<DataType> getAllDataTypes() {
|
||||
// stub
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue