BitFields - added preliminary support for composite bitfields

This commit is contained in:
ghidra1 2019-03-26 15:23:27 -04:00
parent c23ae691e2
commit a7345527c9
209 changed files with 18617 additions and 6720 deletions

View file

@ -71,7 +71,6 @@
<optional>
<element name="long_double_size"><ref name="value_type"/></element>
</optional>
<optional>
<element name="size_alignment_map">
<zeroOrMore>
@ -82,6 +81,24 @@
</zeroOrMore>
</element>
</optional>
<optional>
<element name="bitfield_packing">
<interleave>
<optional>
<!-- boolean value, default: false (MSVC should be true) -->
<element name="use_MS_convention"><ref name="value_type"/></element>
</optional>
<optional>
<!-- boolean value, default: true -->
<element name="type_alignment_enabled"><ref name="value_type"/></element>
</optional>
<optional>
<!-- int value: number of bytes -->
<element name="zero_length_boundary"><ref name="value_type"/></element>
</optional>
</interleave>
</element>
</optional>
</interleave>
</element>
</optional>

View file

@ -15,7 +15,7 @@
*/
package ghidra.app.util;
import java.util.ConcurrentModificationException;
import java.util.*;
import ghidra.docking.settings.Settings;
import ghidra.program.database.ProgramDB;
@ -53,7 +53,7 @@ public class PseudoData extends PseudoCodeUnit implements Data {
this.dataType = dataType;
baseDataType = getBaseDataType(dataType);
if (program instanceof ProgramDB) {
dataMgr = ((ProgramDB) program).getDataManager();
dataMgr = ((ProgramDB) program).getDataTypeManager();
}
}
@ -103,7 +103,7 @@ public class PseudoData extends PseudoCodeUnit implements Data {
}
/**
/**
* @see ghidra.program.model.listing.Data#getComponent(int)
*/
@Override
@ -187,7 +187,7 @@ public class PseudoData extends PseudoCodeUnit implements Data {
}
/**
*
*
* @see ghidra.program.model.listing.CodeUnit#toString()
*/
@Override
@ -384,6 +384,46 @@ public class PseudoData extends PseudoCodeUnit implements Data {
return null;
}
@Override
public List<Data> getComponentsContaining(int offset) {
List<Data> list = new ArrayList<>();
if (offset < 0 || offset >= length) {
return null;
}
if (baseDataType instanceof Array) {
Array array = (Array) baseDataType;
int elementLength = array.getElementLength();
int index = offset / elementLength;
list.add(getComponent(index));
}
else if (baseDataType instanceof Structure) {
Structure struct = (Structure) baseDataType;
DataTypeComponent dtc = struct.getComponentAt(offset);
// Logic handles overlapping bit-fields
while (dtc != null && offset <= (dtc.getOffset() + dtc.getLength() - 1)) {
int ordinal = dtc.getOrdinal();
list.add(getComponent(ordinal++));
dtc = ordinal < struct.getNumComponents() ? struct.getComponent(ordinal) : null;
}
}
else if (baseDataType instanceof DynamicDataType) {
DynamicDataType ddt = (DynamicDataType) baseDataType;
DataTypeComponent dtc = ddt.getComponentAt(offset, this);
if (dtc != null) {
list.add(getComponent(dtc.getOrdinal()));
}
}
else if (baseDataType instanceof Union) {
if (offset == 0) {
for (int i = 0; i < getNumComponents(); i++) {
list.add(getComponent(i));
}
}
}
return list;
}
/**
* @see ghidra.program.model.listing.Data#getComponentIndex()
*/
@ -431,14 +471,14 @@ public class PseudoData extends PseudoCodeUnit implements Data {
// for(int i=0;i<n;i++) {
// retData[i] = getComponent(i);
// }
// }
// }
// else if (baseDataType instanceof Array) {
// Array array = (Array)baseDataType;
// int n = array.getNumElements();
// retData = new Data[n];
// for(int i=0;i<n;i++) {
// retData[i] = getComponent(i);
// }
// }
// }
// else if (baseDataType instanceof DynamicDataType) {
// DynamicDataType ddt = (DynamicDataType)baseDataType;

View file

@ -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,10 @@
*/
package ghidra.program.database;
import java.io.IOException;
import java.util.*;
import db.*;
import ghidra.framework.Application;
import ghidra.framework.data.DomainObjectAdapterDB;
import ghidra.framework.model.*;
@ -31,16 +34,11 @@ import ghidra.util.exception.*;
import ghidra.util.task.TaskMonitor;
import ghidra.util.task.TaskMonitorAdapter;
import java.io.IOException;
import java.util.*;
import db.*;
/**
* Database implementation for Data Type Archive.
*/
public class DataTypeArchiveDB extends DomainObjectAdapterDB implements DataTypeArchive,
DataTypeArchiveChangeManager {
public class DataTypeArchiveDB extends DomainObjectAdapterDB
implements DataTypeArchive, DataTypeArchiveChangeManager {
/**
* DB_VERSION should be incremented any time a change is made to the overall
@ -80,8 +78,8 @@ public class DataTypeArchiveDB extends DomainObjectAdapterDB implements DataType
private final static Class<?>[] COL_CLASS = new Class[] { StringField.class };
private final static String[] COL_TYPES = new String[] { "Value" };
private final static Schema SCHEMA = new Schema(0, StringField.class, "Key", COL_CLASS,
COL_TYPES);
private final static Schema SCHEMA =
new Schema(0, StringField.class, "Key", COL_CLASS, COL_TYPES);
private ProjectDataTypeManager dataTypeManager;
@ -98,8 +96,8 @@ public class DataTypeArchiveDB extends DomainObjectAdapterDB implements DataType
* @throws InvalidNameException
* @throws DuplicateNameException
*/
public DataTypeArchiveDB(DomainFolder folder, String name, Object consumer) throws IOException,
DuplicateNameException, InvalidNameException {
public DataTypeArchiveDB(DomainFolder folder, String name, Object consumer)
throws IOException, DuplicateNameException, InvalidNameException {
super(new DBHandle(), name, 500, 1000, consumer);
this.name = name;
@ -118,7 +116,9 @@ public class DataTypeArchiveDB extends DomainObjectAdapterDB implements DataType
endTransaction(id, true);
clearUndo(false);
folder.createFile(name, this, TaskMonitorAdapter.DUMMY_MONITOR);
if (folder != null) {
folder.createFile(name, this, TaskMonitorAdapter.DUMMY_MONITOR);
}
success = true;
}
@ -136,7 +136,7 @@ public class DataTypeArchiveDB extends DomainObjectAdapterDB implements DataType
}
/**
* Constructs a new DataTypeArchivemDB
* Constructs a new DataTypeArchiveDB
* @param dbh a handle to an open data type archive database.
* @param openMode one of:
* READ_ONLY: the original database will not be modified
@ -207,8 +207,8 @@ public class DataTypeArchiveDB extends DomainObjectAdapterDB implements DataType
private void propertiesRestore() {
Options pl = getOptions(ARCHIVE_INFO);
boolean origChangeState = changed;
pl.registerOption(CREATED_WITH_GHIDRA_VERSION, "4.3",
null, "Version of Ghidra used to create this program.");
pl.registerOption(CREATED_WITH_GHIDRA_VERSION, "4.3", null,
"Version of Ghidra used to create this program.");
pl.registerOption(DATE_CREATED, JANUARY_1_1970, null, "Date this program was created");
// registerDefaultPointerSize();
changed = origChangeState;

View file

@ -156,14 +156,15 @@ abstract public class DatabaseObject {
* This method provides a cheap (lock free) way to test if an object is valid. If
* this object is invalid, then the lock will be used to refresh as needed.
* @param lock the lock that will be used if the object needs to be refreshed.
* @return true if object is valid, else false
*/
public void validate(Lock lock) {
public boolean validate(Lock lock) {
if (!deleted && !isInvalid()) {
return;
return true;
}
lock.acquire();
try {
checkIsValid();
return checkIsValid();
}
finally {
lock.release();

View file

@ -595,7 +595,7 @@ class ListingDB implements Listing {
*/
@Override
public DataTypeManager getDataTypeManager() {
return program.getDataManager();
return program.getDataTypeManager();
}
/* (non-Javadoc)

View file

@ -30,7 +30,6 @@ import ghidra.framework.store.LockException;
import ghidra.program.database.bookmark.BookmarkDBManager;
import ghidra.program.database.code.CodeManager;
import ghidra.program.database.code.InstructionDB;
import ghidra.program.database.data.DataTypeManagerDB;
import ghidra.program.database.data.ProgramDataTypeManager;
import ghidra.program.database.external.ExternalManagerDB;
import ghidra.program.database.function.FunctionManagerDB;
@ -623,13 +622,6 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM
return (TreeManager) managers[TREE_MGR];
}
/**
* Returns the DataManager
*/
public DataTypeManagerDB getDataManager() {
return (DataTypeManagerDB) managers[DATA_MGR];
}
/**
* @see ghidra.program.model.listing.Program#getDataTypeManager()
*/
@ -2657,7 +2649,7 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM
metadata.put("# of Defined Data", "" + listing.getNumDefinedData());
metadata.put("# of Functions", "" + getFunctionManager().getFunctionCount());
metadata.put("# of Symbols", "" + getSymbolTable().getNumSymbols());
metadata.put("# of Data Types", "" + getDataManager().getDataTypeCount(true));
metadata.put("# of Data Types", "" + getDataTypeManager().getDataTypeCount(true));
metadata.put("# of Data Type Categories", "" + getDataTypeManager().getCategoryCount());
Options propList = getOptions(Program.PROGRAM_INFO);

View file

@ -227,7 +227,7 @@ public class CodeManager implements ErrorHandler, ManagerDB {
contextMgr = program.getProgramContext();
refManager = program.getReferenceManager();
propertyMapMgr = program.getUsrPropertyManager();
dataManager = program.getDataManager();
dataManager = program.getDataTypeManager();
protoMgr.setProgram(program);
}
@ -1976,6 +1976,10 @@ public class CodeManager implements ErrorHandler, ManagerDB {
DataDB data = null;
try {
if (dataType instanceof BitFieldDataType) {
throw new CodeUnitInsertionException("Bitfields not supported for Data");
}
DataType originalDataType = dataType;
if (dataType instanceof FactoryDataType) {
MemBuffer memBuffer = new MemoryBufferImpl(program.getMemory(), addr);

View file

@ -16,6 +16,7 @@
package ghidra.program.database.code;
import java.util.ArrayList;
import java.util.List;
import db.Record;
import ghidra.docking.settings.Settings;
@ -66,7 +67,7 @@ class DataDB extends CodeUnitDB implements Data {
dataType = DataType.DEFAULT;
}
this.dataType = dataType;
dataMgr = program.getDataManager();
dataMgr = program.getDataTypeManager();
baseDataType = getBaseDataType(dataType);
@ -554,9 +555,6 @@ class DataDB extends CodeUnitDB implements Data {
}
}
/**
* @see ghidra.program.model.listing.Data#getComponentAt(int)
*/
@Override
public Data getComponentAt(int offset) {
lock.acquire();
@ -594,6 +592,56 @@ class DataDB extends CodeUnitDB implements Data {
}
@Override
public List<Data> getComponentsContaining(int offset) {
List<Data> list = new ArrayList<>();
lock.acquire();
try {
checkIsValid();
if (offset < 0 || offset >= length) {
return null;
}
if (baseDataType instanceof Array) {
Array array = (Array) baseDataType;
int elementLength = array.getElementLength();
int index = offset / elementLength;
list.add(getComponent(index));
}
else if (baseDataType instanceof Structure) {
Structure struct = (Structure) baseDataType;
DataTypeComponent dtc = struct.getComponentAt(offset);
// Logic handles overlapping bit-fields
// Include if offset is contains within bounds of component
while (dtc != null && (offset >= dtc.getOffset()) &&
(offset <= (dtc.getOffset() + dtc.getLength() - 1))) {
int ordinal = dtc.getOrdinal();
list.add(getComponent(ordinal++));
dtc = ordinal < struct.getNumComponents() ? struct.getComponent(ordinal) : null;
}
}
else if (baseDataType instanceof DynamicDataType) {
DynamicDataType ddt = (DynamicDataType) baseDataType;
DataTypeComponent dtc = ddt.getComponentAt(offset, this);
if (dtc != null) {
list.add(getComponent(dtc.getOrdinal()));
}
}
else if (baseDataType instanceof Union) {
if (offset == 0) {
for (int i = 0; i < getNumComponents(); i++) {
list.add(getComponent(i));
}
}
}
return list;
}
finally {
lock.release();
}
}
/**
* @see ghidra.program.model.listing.Data#getComponentIndex()
*/

View file

@ -0,0 +1,251 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.program.database.data;
import ghidra.program.model.data.*;
import ghidra.program.model.data.Enum;
import ghidra.util.Msg;
import ghidra.util.exception.AssertException;
/**
* <code>BitFieldDBDataType</code> extends BitFieldDataType for DataTypeManagerDB use.
* This class provides the ability to generate a datatype ID and reconstruct a bit-field
* datatype from an ID.
*/
class BitFieldDBDataType extends BitFieldDataType {
// Bit Field ID Encoding (expressed as the following 4-bit nibble fields): XXTTTTTTTTBBOOSS
//
// XX - reserved for datatype manager table ID
// TTTTTTTT - TypeDef/Enum ID (32-bits, excludes table ID, applies to resolved TypeDef/Enum only)
// BB - Encoded base type (8-bits, consists of the following bit fields: xttsbbbb)
// x - 1-bit, unused
// t - 2-bit, =0: base type only, =1:TypeDef used, =2: enum used, =3: abstract-int
// s - 1-bit, storage +1
// xxxx - 4-bits, unused
// OO - bit offset (i.e., right-shift factor, relative to packing base type)
// SS - bit field size in bits
private static final int BIT_OFFSET_SHIFT = 8;
private static final int BASE_TYPE_SHIFT = 16;
private static final int DATATYPE_INDEX_SHIFT = 24;
public static final long MAX_DATATYPE_INDEX = 0xffffffffL; // 32-bits
private static final long ID_TO_INDEX_MASK = ~-(1L << DataTypeManagerDB.DATA_TYPE_KIND_SHIFT);
BitFieldDBDataType(DataType baseDataType, int bitSize, int bitOffset, int storageSize,
DataTypeManager dtm) throws InvalidDataTypeException {
// avoid clone of baseDataType during construction
super(baseDataType, bitSize, bitOffset, storageSize);
}
private static enum BaseDatatypeKind {
NONE(0), TYPEDEF(1), ENUM(2), INTEGER(3);
final int id;
BaseDatatypeKind(int id) {
this.id = id;
}
static BaseDatatypeKind getKind(int value) {
for (BaseDatatypeKind kind : values()) {
if (kind.id == value) {
return kind;
}
}
return NONE;
}
}
/**
* Get a generated ID for this bit-field which is suitable for reconstruction
* via the {@link #getBitFieldDataType(long)} method. This ID encodes the base
* datatype (including typedef/enum and packing data),
* bit-size and bit-offset. The upper byte of the ID will always be zero and
* is reserved for use by the DataTypeManager.
* <p>
* The ability to reference base datatypes (e.g., TypeDef, Enum) is currently limited
* (i.e. 32-bit base datatype ID).
* @param bitfieldDt the resolved bitfield datatype whose ID is needed. This must first be
* resolved by a DataTypeManagerDB.
* @return bit-field ID
*/
static final long getId(BitFieldDataType bitfieldDt) {
DataTypeManager dtm = bitfieldDt.getDataTypeManager();
if (!(dtm instanceof DataTypeManagerDB)) {
throw new AssertException("bitfieldDt must first be resolved");
}
BaseDatatypeKind dataTypeKind = BaseDatatypeKind.NONE;
long dataTypeIndex = 0;
DataType baseDataType = bitfieldDt.getBaseDataType();
if (baseDataType instanceof TypeDef) {
dataTypeKind = BaseDatatypeKind.TYPEDEF;
}
else if (baseDataType instanceof Enum) {
dataTypeKind = BaseDatatypeKind.ENUM;
}
else if (baseDataType instanceof AbstractIntegerDataType) {
dataTypeKind = BaseDatatypeKind.INTEGER;
}
if (dataTypeKind != BaseDatatypeKind.NONE) {
dataTypeIndex = getResolvedDataTypeIndex(baseDataType, (DataTypeManagerDB) dtm);
if (dataTypeIndex == DataTypeManager.NULL_DATATYPE_ID) {
Msg.debug(BitFieldDBDataType.class,
"Bit-Field data type not resolved: " + baseDataType.getName());
dataTypeIndex = MAX_DATATYPE_INDEX;
dataTypeKind = BaseDatatypeKind.NONE;
}
else if (dataTypeIndex >= MAX_DATATYPE_INDEX) {
// TypeDef index exceeds 32-bit limit
Msg.debug(BitFieldDBDataType.class,
"Bit-Field data type index out of range: " + baseDataType.getName());
dataTypeIndex = MAX_DATATYPE_INDEX;
dataTypeKind = BaseDatatypeKind.NONE;
}
}
long id = (dataTypeIndex << DATATYPE_INDEX_SHIFT) |
(getBaseTypeEncodedField(bitfieldDt, dataTypeKind) << BASE_TYPE_SHIFT) |
(bitfieldDt.getBitOffset() << BIT_OFFSET_SHIFT) | bitfieldDt.getDeclaredBitSize();
return id;
}
private static final long getBaseTypeEncodedField(BitFieldDataType bitFieldDt,
BaseDatatypeKind dataTypeKind) {
int nominalStorageSize = BitFieldDataType.getMinimumStorageSize(bitFieldDt.getBitSize());
boolean extraStorageUsed = bitFieldDt.getStorageSize() > nominalStorageSize;
return (dataTypeKind.id << 5) | (extraStorageUsed ? 0x10L : 0L);
}
/**
* Get a bit-field datatype instance for a given ID. The upper byte of the ID will be ignored.
* @param id bit-field datatype ID
* @param dtm data type manager
* @return bit-field data type
*/
static final BitFieldDataType getBitFieldDataType(long id, DataTypeManager dtm) {
int bitSize = (int) (id & 0xff); // 8-bits
int bitOffset = (int) ((id >> BIT_OFFSET_SHIFT) & 0xff); // 8-bits
int baseTypeInfo = (int) ((id >> BASE_TYPE_SHIFT) & 0xff); // 8-bit encoded field
BaseDatatypeKind baseDataTypeKind = BaseDatatypeKind.getKind((baseTypeInfo >> 5) & 3);
boolean extraStorageUsed = (baseTypeInfo & 0x10) != 0;
DataType baseDataType = null;
long dataTypeIndex = (id >> DATATYPE_INDEX_SHIFT) & MAX_DATATYPE_INDEX; // 32-bits
if (baseDataTypeKind != BaseDatatypeKind.NONE && dataTypeIndex != MAX_DATATYPE_INDEX) {
if (baseDataTypeKind == BaseDatatypeKind.TYPEDEF) {
baseDataType = getTypeDef(dataTypeIndex, dtm);
}
else if (baseDataTypeKind == BaseDatatypeKind.ENUM) {
baseDataType = getEnum(dataTypeIndex, dtm);
}
else {
baseDataType = getIntegerType(dataTypeIndex, dtm);
}
}
try {
if (baseDataType == null) {
// use integer datatype on failure
baseDataType = IntegerDataType.dataType.clone(dtm);
}
int effectiveBitSize = getEffectiveBitSize(bitSize, baseDataType.getLength());
int storageSize = getMinimumStorageSize(effectiveBitSize);
if (extraStorageUsed) {
++storageSize;
}
return new BitFieldDBDataType(baseDataType, bitSize, bitOffset, storageSize, dtm);
}
catch (InvalidDataTypeException e) {
return null;
}
}
private static final long getResolvedDataTypeIndex(DataType dataType, DataTypeManagerDB dtm) {
long dataTypeId = dtm.getID(dataType);
if (dataTypeId == DataTypeManager.NULL_DATATYPE_ID) {
return DataTypeManager.NULL_DATATYPE_ID;
}
return dataTypeId & ID_TO_INDEX_MASK;
}
/**
* Get the TypeDef which corresponds to the specified typeDefIndex and the
* specified data type manager.
* @param typeDefIndex base data type index used by bit-field
* @param primitiveBaseDataType expected primitive base datatype
* @param dtm data type manager
* @return TypeDef data type or null if not found
*/
private static final TypeDef getTypeDef(long typeDefIndex, DataTypeManager dtm) {
long dataTypeId =
((long) DataTypeManagerDB.TYPEDEF << DataTypeManagerDB.DATA_TYPE_KIND_SHIFT) |
typeDefIndex;
DataType dataType = dtm.getDataType(dataTypeId);
if (!(dataType instanceof TypeDef)) {
return null;
}
TypeDef typeDefDt = (TypeDef) dataType;
DataType dt = typeDefDt.getBaseDataType();
if (dt instanceof Enum) {
// TODO: how restrictive should we be on matching enum size?
return typeDefDt;
}
if (dt instanceof AbstractIntegerDataType) {
return typeDefDt;
}
return null; // unsupported typedef
}
/**
* Get the Enum which corresponds to the specified enumIndex and the
* specified data type manager.
* @param enumIndex enum data type index used by bit-field
* @param dtm data type manager
* @return Enum data type or null if not found
*/
private static final Enum getEnum(long enumIndex, DataTypeManager dtm) {
long dataTypeId =
((long) DataTypeManagerDB.ENUM << DataTypeManagerDB.DATA_TYPE_KIND_SHIFT) | enumIndex;
DataType dataType = dtm.getDataType(dataTypeId);
if (!(dataType instanceof Enum)) {
return null;
}
return (Enum) dataType;
}
/**
* Get the integer base type which corresponds to the specified intTypeIndex and the
* specified data type manager.
* @param intTypeIndex base data type index used by bit-field
* @param dtm data type manager
* @return integer data type or null if not found
*/
private static final AbstractIntegerDataType getIntegerType(long intTypeIndex,
DataTypeManager dtm) {
long dataTypeId =
((long) DataTypeManagerDB.BUILT_IN << DataTypeManagerDB.DATA_TYPE_KIND_SHIFT) |
intTypeIndex;
DataType dataType = dtm.getDataType(dataTypeId);
if (!(dataType instanceof AbstractIntegerDataType)) {
return null;
}
return (AbstractIntegerDataType) dataType;
}
}

View file

@ -24,7 +24,6 @@ import ghidra.program.model.data.*;
import ghidra.program.model.mem.MemBuffer;
import ghidra.util.UniversalID;
import ghidra.util.exception.AssertException;
import ghidra.util.exception.InvalidInputException;
/**
* Database implementation for a structure or union.
@ -67,6 +66,34 @@ abstract class CompositeDB extends DataTypeDB implements Composite {
*/
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 then 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.
* @return preferred component length
*/
protected int getPreferredComponentLength(DataType dataType, int length) {
if ((isInternallyAligned() || (this instanceof Union)) && !(dataType instanceof Dynamic)) {
length = -1; // force use of datatype size
}
int dtLength = dataType.getLength();
if (length <= 0) {
length = dtLength;
}
else if (dtLength > 0 && dtLength < length) {
length = dtLength;
}
if (length <= 0) {
throw new IllegalArgumentException("Positive length must be specified for " +
dataType.getDisplayName() + " component");
}
return length;
}
@Override
protected String doGetName() {
return record.getString(CompositeDBAdapter.COMPOSITE_NAME_COL);
@ -78,20 +105,53 @@ abstract class CompositeDB extends DataTypeDB implements Composite {
}
@Override
public DataTypeComponent add(DataType dataType) {
lock.acquire();
try {
checkDeleted();
int length = dataType.getLength();
if (dataType.getLength() < 1) {
throw new IllegalArgumentException("Minimum data type length is 1 byte");
public DataTypeComponent addBitField(DataType baseDataType, int bitSize, String componentName,
String comment) throws InvalidDataTypeException {
BitFieldDataType bitFieldDt = new BitFieldDBDataType(baseDataType, bitSize, 0, 0, dataMgr);
return add(bitFieldDt, bitFieldDt.getStorageSize(), componentName, comment);
}
/**
* 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
*/
protected boolean updateBitFieldDataType(DataTypeComponentDB bitfieldComponent, DataType oldDt,
DataType newDt) throws InvalidDataTypeException {
if (!bitfieldComponent.isBitFieldComponent()) {
throw new AssertException("expected bitfield component");
}
BitFieldDBDataType bitfieldDt = (BitFieldDBDataType) bitfieldComponent.getDataType();
if (bitfieldDt.getBaseDataType() != oldDt) {
return false;
}
if (newDt != null) {
BitFieldDataType.checkBaseDataType(newDt);
int maxBitSize = 8 * newDt.getLength();
if (bitfieldDt.getBitSize() > maxBitSize) {
throw new InvalidDataTypeException("Replacement datatype too small for bitfield");
}
DataTypeComponent addedComponent = add(dataType, length, null, null);
return addedComponent;
}
finally {
lock.release();
try {
BitFieldDBDataType newBitfieldDt =
new BitFieldDBDataType(newDt, bitfieldDt.getDeclaredBitSize(),
bitfieldDt.getBitOffset(), bitfieldDt.getStorageSize(), dataMgr);
bitfieldComponent.setDataType(newBitfieldDt);
oldDt.removeParent(this);
newDt.addParent(this);
}
catch (InvalidDataTypeException e) {
throw new AssertException("unexpected");
}
return true;
}
@Override
@ -141,9 +201,6 @@ abstract class CompositeDB extends DataTypeDB implements Composite {
}
}
/**
* @see ghidra.program.model.data.DataType#isDynamicallySized()
*/
@Override
public boolean isDynamicallySized() {
return isInternallyAligned();
@ -155,23 +212,28 @@ abstract class CompositeDB extends DataTypeDB implements Composite {
}
@Override
public DataTypeComponent add(DataType dataType, int length) {
public final DataTypeComponent add(DataType dataType) {
return add(dataType, -1, null, null);
}
@Override
public final DataTypeComponent add(DataType dataType, int length) {
return add(dataType, length, null, null);
}
@Override
public DataTypeComponent add(DataType dataType, String fieldName, String comment) {
return add(dataType, dataType.getLength(), fieldName, comment);
public final DataTypeComponent add(DataType dataType, String fieldName, String comment) {
return add(dataType, -1, fieldName, comment);
}
@Override
public DataTypeComponent insert(int ordinal, DataType dataType, int length) {
public final DataTypeComponent insert(int ordinal, DataType dataType, int length) {
return insert(ordinal, dataType, length, null, null);
}
@Override
public DataTypeComponent insert(int ordinal, DataType dataType) {
return insert(ordinal, dataType, dataType.getLength(), null, null);
public final DataTypeComponent insert(int ordinal, DataType dataType) {
return insert(ordinal, dataType, -1, null, null);
}
@Override
@ -179,13 +241,6 @@ abstract class CompositeDB extends DataTypeDB implements Composite {
return getDisplayName();
}
/**
* Notifies the composite data type that a component in it has changed.
* @param component the component that changed.
*/
protected void componentChanged(DataTypeComponent component) {
}
@Override
protected void doSetCategoryPathRecord(long categoryID) throws IOException {
record.setLongValue(CompositeDBAdapter.COMPOSITE_CAT_COL, categoryID);
@ -236,6 +291,10 @@ abstract class CompositeDB extends DataTypeDB implements Composite {
* @throws IllegalArgumentException if the data type is invalid.
*/
protected void validateDataType(DataType dataType) {
if (isInternallyAligned() && dataType == DataType.DEFAULT) {
throw new IllegalArgumentException(
"The DEFAULT data type is not allowed in an aligned composite data type.");
}
if (dataType instanceof FactoryDataType) {
throw new IllegalArgumentException("The \"" + dataType.getName() +
"\" data type is not allowed in a composite data type.");
@ -350,7 +409,7 @@ abstract class CompositeDB extends DataTypeDB implements Composite {
}
@Override
public void setPackingValue(int packingValue) throws InvalidInputException {
public void setPackingValue(int packingValue) {
boolean changed = false;
if (!isInternallyAligned()) {
doSetInternallyAligned(true);
@ -366,9 +425,9 @@ abstract class CompositeDB extends DataTypeDB implements Composite {
}
}
public void doSetPackingValue(int packingValue) throws InvalidInputException {
public void doSetPackingValue(int packingValue) {
if (packingValue < 0) {
throw new InvalidInputException(packingValue + "is not a valid packing value.");
packingValue = NOT_PACKING;
}
lock.acquire();
try {
@ -432,7 +491,7 @@ abstract class CompositeDB extends DataTypeDB implements Composite {
}
@Override
public void setMinimumAlignment(int externalAlignment) throws InvalidInputException {
public void setMinimumAlignment(int externalAlignment) {
boolean changed = false;
if (!isInternallyAligned()) {
doSetInternallyAligned(true);
@ -447,10 +506,9 @@ abstract class CompositeDB extends DataTypeDB implements Composite {
}
}
public boolean doSetMinimumAlignment(int externalAlignment) throws InvalidInputException {
if (externalAlignment <= 0) {
throw new InvalidInputException(externalAlignment +
" is not a valid external alignment. It must be greater than 0.");
public boolean doSetMinimumAlignment(int externalAlignment) {
if (externalAlignment < 1) {
externalAlignment = DEFAULT_ALIGNED;
}
return modifyAlignment(externalAlignment);
}
@ -504,6 +562,11 @@ abstract class CompositeDB extends DataTypeDB implements Composite {
return false;
}
}
if (isDefaultAligned()) {
if (dbExternalAlignment == DEFAULT_ALIGNED) {
return false;
}
}
else if (dbExternalAlignment == getMinimumAlignment()) {
return false;
}
@ -525,31 +588,17 @@ abstract class CompositeDB extends DataTypeDB implements Composite {
* Notification that this composite data type's alignment has changed.
*/
protected void notifyAlignmentChanged() {
DataType[] dts = dataMgr.getParentDataTypes(key);
for (int i = 0; i < dts.length; i++) {
if (dts[i] instanceof Composite) {
Composite composite = (Composite) dts[i];
// TODO: This method is not properly invoked when new components are
// added which could change the alignment of this composite
for (DataType dt : dataMgr.getParentDataTypes(key)) {
if (dt instanceof Composite) {
Composite composite = (Composite) dt;
composite.dataTypeAlignmentChanged(this);
}
}
dataMgr.dataTypeChanged(this);
}
/**
* Gets the data organization object for this data type. The data organization has the alignment
* and size information for data types.
* @return the data organization
*/
protected DataOrganization getDataOrganization() {
if (dataMgr != null) {
DataOrganization dataOrganization = dataMgr.getDataOrganization();
if (dataOrganization != null) {
return dataOrganization;
}
}
return DataOrganizationImpl.getDefaultOrganization();
}
@Override
public boolean isInternallyAligned() {
int dbValue = record.getIntValue(CompositeDBAdapter.COMPOSITE_INTERNAL_ALIGNMENT_COL);
@ -593,12 +642,7 @@ abstract class CompositeDB extends DataTypeDB implements Composite {
protected void setAlignment(Composite composite, boolean notify) {
doSetInternallyAligned(composite.isInternallyAligned());
try {
doSetPackingValue(composite.getPackingValue());
}
catch (InvalidInputException e) {
throw new AssertException("Got bad pack value from existing composite.", e);
}
doSetPackingValue(composite.getPackingValue());
if (composite.isDefaultAligned()) {
doSetToDefaultAlignment();
@ -607,12 +651,7 @@ abstract class CompositeDB extends DataTypeDB implements Composite {
doSetToMachineAlignment();
}
else {
try {
doSetMinimumAlignment(composite.getMinimumAlignment());
}
catch (InvalidInputException e) {
throw new AssertException("Got bad minimum alignment from existing composite.", e);
}
doSetMinimumAlignment(composite.getMinimumAlignment());
}
adjustInternalAlignment(notify);
}
@ -628,7 +667,8 @@ abstract class CompositeDB extends DataTypeDB implements Composite {
@Override
public int getAlignment() {
return getDataOrganization().getAlignment(this, getLength());
// TODO: use cached value if available (requires DB change to facilitate)
return CompositeAlignmentHelper.getAlignment(getDataOrganization(), this);
}
/**
@ -639,7 +679,14 @@ abstract class CompositeDB extends DataTypeDB implements Composite {
protected void dumpComponents(StringBuilder buffer, String pad) {
for (DataTypeComponent dtc : getComponents()) {
DataType dataType = dtc.getDataType();
buffer.append(pad + dtc.getOffset());
buffer.append(pad + dataType.getDisplayName());
if (dataType instanceof BitFieldDataType) {
BitFieldDataType bfDt = (BitFieldDataType) dataType;
buffer.append("(");
buffer.append(Integer.toString(bfDt.getBitOffset()));
buffer.append(")");
}
buffer.append(pad + dtc.getLength());
buffer.append(pad + dtc.getFieldName());
String comment = dtc.getComment();

View file

@ -23,6 +23,7 @@ import java.io.IOException;
import db.Record;
import ghidra.docking.settings.Settings;
import ghidra.program.model.data.*;
import ghidra.util.SystemUtilities;
import ghidra.util.exception.DuplicateNameException;
/**
@ -30,12 +31,14 @@ import ghidra.util.exception.DuplicateNameException;
* component is for an undefined data type, then the record object is
* null.
*/
class DataTypeComponentDB implements DataTypeComponent {
class DataTypeComponentDB implements InternalDataTypeComponent {
private final DataTypeManagerDB dataMgr;
private final ComponentDBAdapter adapter;
private final Record record; // null record -> undefined component
private final Composite parent;
private DataType cachedDataType; // required for bit-fields during packing process
private boolean isFlexibleArrayComponent = false;
private int ordinal;
@ -96,6 +99,24 @@ class DataTypeComponentDB implements DataTypeComponent {
return isFlexibleArrayComponent;
}
@Override
public boolean isBitFieldComponent() {
if (record == null) {
return false;
}
long id = record.getLongValue(ComponentDBAdapter.COMPONENT_DT_ID_COL);
return DataTypeManagerDB.getTableID(id) == DataTypeManagerDB.BITFIELD;
}
@Override
public boolean isZeroBitFieldComponent() {
if (isBitFieldComponent()) {
BitFieldDataType bitField = (BitFieldDataType) getDataType();
return bitField.getBitSize() == 0;
}
return false;
}
/**
* Get record key
* @return record key or -1 for undefined component without a record
@ -109,6 +130,9 @@ class DataTypeComponentDB implements DataTypeComponent {
if (record == null) {
return DataType.DEFAULT;
}
if (cachedDataType != null) {
return cachedDataType;
}
long id = record.getLongValue(ComponentDBAdapter.COMPONENT_DT_ID_COL);
if (id == -1) {
return DataType.DEFAULT;
@ -133,6 +157,13 @@ class DataTypeComponentDB implements DataTypeComponent {
return offset;
}
boolean containsOffset(int off) {
if (isFlexibleArrayComponent) {
return false;
}
return off >= offset && off <= (offset + length - 1);
}
@Override
public int getOrdinal() {
if (isFlexibleArrayComponent) {
@ -202,6 +233,9 @@ class DataTypeComponentDB implements DataTypeComponent {
@Override
public String getFieldName() {
if (isZeroBitFieldComponent()) {
return "";
}
if (record != null) {
return record.getString(ComponentDBAdapter.COMPONENT_FIELD_NAME_COL);
}
@ -210,6 +244,9 @@ class DataTypeComponentDB implements DataTypeComponent {
@Override
public String getDefaultFieldName() {
if (isZeroBitFieldComponent()) {
return "";
}
if (parent instanceof Structure) {
return DEFAULT_FIELD_NAME_PREFIX + "_0x" + Integer.toHexString(getOffset());
}
@ -252,6 +289,12 @@ class DataTypeComponentDB implements DataTypeComponent {
}
}
@Override
public int hashCode() {
// It is not expected that these objects ever be put in a hash map
return super.hashCode();
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof DataTypeComponent)) {
@ -261,11 +304,12 @@ class DataTypeComponentDB implements DataTypeComponent {
DataType myDt = getDataType();
DataType otherDt = dtc.getDataType();
// NOTE: use getOffset() and getOrdinal() methods since returned values will differ from
// NOTE: use getOffset() and getOrdinal() methods since returned values will differ from
// stored values for flexible array component
if (getOffset() != dtc.getOffset() || getLength() != dtc.getLength() ||
getOrdinal() != dtc.getOrdinal() || !isSameString(getFieldName(), dtc.getFieldName()) ||
!isSameString(getComment(), dtc.getComment())) {
getOrdinal() != dtc.getOrdinal() ||
!SystemUtilities.isEqual(getFieldName(), dtc.getFieldName()) ||
!SystemUtilities.isEqual(getComment(), dtc.getComment())) {
return false;
}
if (!(myDt instanceof Pointer) && !myDt.getPathName().equals(otherDt.getPathName())) {
@ -302,25 +346,39 @@ class DataTypeComponentDB implements DataTypeComponent {
boolean aligned =
(myParent instanceof Composite) ? ((Composite) myParent).isInternallyAligned() : false;
// Components don't need to have matching offset when they are aligned, only matching ordinal.
// NOTE: use getOffset() and getOrdinal() methods since returned values will differ from
// NOTE: use getOffset() and getOrdinal() methods since returned values will differ from
// stored values for flexible array component
if ((!aligned && (getOffset() != dtc.getOffset())) ||
// Components don't need to have matching length when they are aligned. Is this correct?
(!aligned && (getLength() != dtc.getLength())) || getOrdinal() != dtc.getOrdinal() ||
!isSameString(getFieldName(), dtc.getFieldName()) ||
!isSameString(getComment(), dtc.getComment())) {
!SystemUtilities.isEqual(getFieldName(), dtc.getFieldName()) ||
!SystemUtilities.isEqual(getComment(), dtc.getComment())) {
return false;
}
return DataTypeUtilities.isSameOrEquivalentDataType(myDt, otherDt);
}
private boolean isSameString(String s1, String s2) {
if (s1 == null) {
return s2 == null;
@Override
public void update(int newOrdinal, int newOffset, int newLength) {
if (isFlexibleArrayComponent) {
return;
}
if (length < 0) {
throw new IllegalArgumentException(
"Cannot set data type component length to " + length + ".");
}
ordinal = newOrdinal;
offset = newOffset;
length = newLength;
if (record != null) {
record.setIntValue(ComponentDBAdapter.COMPONENT_ORDINAL_COL, ordinal);
record.setIntValue(ComponentDBAdapter.COMPONENT_OFFSET_COL, offset);
record.setIntValue(ComponentDBAdapter.COMPONENT_SIZE_COL, length);
updateRecord();
}
return s1.equals(s2);
}
void setOffset(int newOffset, boolean updateRecord) {
@ -350,7 +408,7 @@ class DataTypeComponentDB implements DataTypeComponent {
}
void setLength(int length, boolean updateRecord) {
if (isFlexibleArrayComponent) {
if (isFlexibleArrayComponent || length == this.length) {
return;
}
this.length = length;
@ -381,12 +439,9 @@ class DataTypeComponentDB implements DataTypeComponent {
return record;
}
/**
* @param oldDt
* @param newDt
* @return
*/
void setDataType(DataType newDt) {
@Override
public void setDataType(DataType newDt) {
// intended for internal use only
if (record != null) {
record.setLongValue(ComponentDBAdapter.COMPONENT_DT_ID_COL,
dataMgr.getResolvedID(newDt));
@ -404,10 +459,14 @@ class DataTypeComponentDB implements DataTypeComponent {
StringBuffer buffer = new StringBuffer();
buffer.append(" " + getOrdinal());
buffer.append(" " + getOffset());
buffer.append(" " + getDataType().getDisplayName());
DataType dt = getDataType();
buffer.append(" " + dt.getDisplayName());
if (isFlexibleArrayComponent) {
buffer.append("[0]");
}
else if (dt instanceof BitFieldDataType) {
buffer.append("(" + ((BitFieldDataType) dt).getBitOffset() + ")");
}
buffer.append(" " + getLength());
buffer.append(" " + getFieldName());
String comment = getComment();

View file

@ -17,6 +17,7 @@ package ghidra.program.database.data;
import java.io.IOException;
import java.net.URL;
import java.util.List;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
@ -41,7 +42,7 @@ import ghidra.util.exception.NotYetImplementedException;
abstract class DataTypeDB extends DatabaseObject implements DataType, ChangeListener {
protected Record record;
protected DataTypeManagerDB dataMgr;
protected final DataTypeManagerDB dataMgr;
private volatile Settings defaultSettings;
private final static SettingsDefinition[] EMPTY_DEFINITIONS = new SettingsDefinition[0];
protected boolean resolving;
@ -101,6 +102,11 @@ abstract class DataTypeDB extends DatabaseObject implements DataType, ChangeList
*/
protected abstract void setSourceArchiveID(UniversalID id);
@Override
public final DataOrganization getDataOrganization() {
return dataMgr.getDataOrganization();
}
@Override
protected boolean refresh() {
category = null;
@ -241,8 +247,7 @@ abstract class DataTypeDB extends DatabaseObject implements DataType, ChangeList
if (length < 0) {
return 1;
}
DataTypeManager dtm = getDataTypeManager();
DataOrganization dataOrganization = dtm.getDataOrganization();
DataOrganization dataOrganization = dataMgr.getDataOrganization();
return dataOrganization.getAlignment(this, length);
}
@ -414,7 +419,7 @@ abstract class DataTypeDB extends DatabaseObject implements DataType, ChangeList
*/
@Override
public void addParent(DataType dt) {
if (dt instanceof DataTypeDB) {
if (dt instanceof DataTypeDB && dt.getDataTypeManager() == dataMgr) {
dataMgr.addParentChildRecord(((DataTypeDB) dt).key, key);
}
}
@ -424,31 +429,28 @@ abstract class DataTypeDB extends DatabaseObject implements DataType, ChangeList
*/
@Override
public void removeParent(DataType dt) {
if (dt instanceof DataTypeDB) {
if (dt instanceof DataTypeDB && dt.getDataTypeManager() == dataMgr) {
dataMgr.removeParentChildRecord(((DataTypeDB) dt).key, key);
}
}
protected void notifySizeChanged() {
DataType[] dts = dataMgr.getParentDataTypes(key);
for (int i = 0; i < dts.length; i++) {
dts[i].dataTypeSizeChanged(this);
for (DataType dt : dataMgr.getParentDataTypes(key)) {
dt.dataTypeSizeChanged(this);
}
dataMgr.dataTypeChanged(this);
}
protected void notifyNameChanged(String oldName) {
DataType[] dts = dataMgr.getParentDataTypes(key);
for (int i = 0; i < dts.length; i++) {
dts[i].dataTypeNameChanged(this, oldName);
for (DataType dt : dataMgr.getParentDataTypes(key)) {
dt.dataTypeNameChanged(this, oldName);
}
dataMgr.dataTypeNameChanged(this, oldName);
}
protected void notifyDeleted() {
DataType[] dts = dataMgr.getParentDataTypes(key);
for (int i = 0; i < dts.length; i++) {
dts[i].dataTypeDeleted(this);
for (DataType dt : dataMgr.getParentDataTypes(key)) {
dt.dataTypeDeleted(this);
}
}
@ -457,7 +459,9 @@ abstract class DataTypeDB extends DatabaseObject implements DataType, ChangeList
*/
@Override
public DataType[] getParents() {
return dataMgr.getParentDataTypes(key);
List<DataType> parents = dataMgr.getParentDataTypes(key);
DataType[] array = new DataType[parents.size()];
return parents.toArray(array);
}
/**

View file

@ -58,6 +58,9 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
static final int FUNCTION_DEF = 6;
static final int PARAMETER = 7;
static final int ENUM = 8;
static final int BITFIELD = 9; // see BitFieldDataType - used for encoding only (no table)
static final int DATA_TYPE_KIND_SHIFT = 56;
private BuiltinDBAdapter builtinAdapter;
private ComponentDBAdapter componentAdapter;
@ -695,6 +698,9 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
if (dataType == DataType.DEFAULT) {
return dataType;
}
if (dataType instanceof BitFieldDataType) {
return resolveBitFieldDataType((BitFieldDataType) dataType, handler);
}
lock.acquire();
DataTypeConflictHandler originalHandler = null;
try {
@ -757,6 +763,34 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
return createDataType(dataType, BuiltInSourceArchive.INSTANCE);
}
private DataType resolveBitFieldDataType(BitFieldDataType bitFieldDataType,
DataTypeConflictHandler handler) {
// NOTE: When a bit-field is getting adding added it will get resolved more than once.
// The first time we will ensure that the base data type, which may be a TypeDef, gets
// resolved. If the bit-offset is too large it will be set to 0
// with the expectation that it will get corrected during subsequent packing.
DataType baseDt = bitFieldDataType.getBaseDataType();
DataType resolvedBaseDt = resolve(baseDt, handler);
int baseLength = resolvedBaseDt.getLength();
int baseLengthBits = 8 * baseLength;
int bitSize = bitFieldDataType.getDeclaredBitSize();
int bitOffset = bitFieldDataType.getBitOffset();
int storageSize = bitFieldDataType.getStorageSize();
int storageSizeBits = 8 * storageSize;
if ((bitOffset + bitSize) > storageSizeBits) {
// should get recomputed during packing when used within aligned structure
bitOffset = getDataOrganization().isBigEndian() ? baseLengthBits - bitSize : 0;
storageSize = baseLength;
}
try {
return new BitFieldDBDataType(resolvedBaseDt, bitSize, bitOffset, storageSize, this);
}
catch (InvalidDataTypeException e) {
throw new AssertException("unexpected", e);
}
}
/**
* Either finds an equivalent dataType with the same categoryPath and name (or conflict name)
* to the given dataType. Otherwise, it creates a new dataType in this archive equivalent to
@ -1305,6 +1339,9 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
if (dt == DataType.DEFAULT) {
return DEFAULT_DATATYPE_ID;
}
if (dt instanceof BitFieldDataType) {
return createKey(BITFIELD, BitFieldDBDataType.getId((BitFieldDataType) dt));
}
if (dt instanceof BadDataType) {
return BAD_DATATYPE_ID;
}
@ -1632,6 +1669,10 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
// an undo. So make sure it really is there.
if (dataType instanceof DataTypeDB) {
long id = ((DataTypeDB) dataType).getKey();
// NOTE: Does not seem to help following an undo/redo
// DataTypeDB existingDt = dtCache.get(id);
// return existingDt == dataType && existingDt.validate(lock);
//
return dtCache.get(id) != null;
}
return builtIn2IdMap.containsKey(dataType);
@ -1768,8 +1809,8 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
}
}
private int getTableID(long dataID) {
return (int) (dataID >> 56);
static int getTableID(long dataID) {
return (int) (dataID >> DATA_TYPE_KIND_SHIFT);
}
private DataType getDataType(long dataTypeID, Record record) {
@ -1789,6 +1830,8 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
return getFunctionDefDataType(dataTypeID, record);
case ENUM:
return getEnumDataType(dataTypeID, record);
case BITFIELD:
return BitFieldDBDataType.getBitFieldDataType(dataTypeID, this);
default:
return null;
}
@ -2108,6 +2151,7 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
category.dataTypeAdded(structDB);
structDB.doReplaceWith(struct, false, handler);
structDB.setDescription(struct.getDescription());
structDB.notifySizeChanged();
// doReplaceWith updated the last change time so set it back to what we want.
structDB.setLastChangeTime(struct.getLastChangeTime());
@ -2176,6 +2220,7 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
category.dataTypeAdded(unionDB);
unionDB.doReplaceWith(union, false, handler);
unionDB.setDescription(union.getDescription());
unionDB.notifySizeChanged();
// doReplaceWith updated the last change time so set it back to what we want.
unionDB.setLastChangeTime(union.getLastChangeTime());
@ -3115,7 +3160,7 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
* the bits are from the tableKey.
*/
static long createKey(int tableID, long tableKey) {
long key = (long) tableID << 56;
long key = (long) tableID << DATA_TYPE_KIND_SHIFT;
return key |= tableKey;
}
@ -3152,21 +3197,46 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
}
}
DataType[] getParentDataTypes(long childID) {
List<DataType> getParentDataTypes(long childID) {
lock.acquire();
try {
long[] ids = parentChildAdapter.getParentIds(childID);
DataType[] dts = new DataType[ids.length];
for (int i = 0; i < dts.length; i++) {
dts[i] = getDataType(ids[i]);
// TODO: consider deduping ids using Set
List<DataType> dts = new ArrayList<>();
for (int i = 0; i < ids.length; i++) {
DataType dt = getDataType(ids[i]);
if (dt == null) {
// cleanup invalid records for missing parent
attemptRecordRemovalForParent(ids[i]);
}
else {
dts.add(dt);
}
}
return dts;
}
catch (IOException e) {
dbError(e);
}
finally {
lock.release();
}
return null;
}
private void attemptRecordRemovalForParent(long parentKey) throws IOException {
lock.acquire();
try {
if (dbHandle.isTransactionActive()) {
parentChildAdapter.removeAllRecordsForParent(parentKey);
}
}
finally {
lock.release();
}
}
@Override
public Set<DataType> getDataTypesContaining(DataType dataType) {
Set<DataType> set = new HashSet<>();

View file

@ -124,6 +124,10 @@ public class DataTypeUtilities {
else if (dt instanceof BuiltInDataType) {
// no-op; prevents assert exception below
}
else if (dt instanceof BitFieldDataType) {
BitFieldDataType bitFieldDt = (BitFieldDataType) dt;
list.add(bitFieldDt.getBaseDataType());
}
else if (dt instanceof MissingBuiltInDataType) {
// no-op; prevents assert exception below
}

View file

@ -16,6 +16,7 @@
package ghidra.program.database.data;
import java.io.IOException;
import java.math.BigInteger;
import java.util.*;
import db.Record;
@ -435,11 +436,7 @@ class EnumDB extends DataTypeDB implements Enum {
value = buf.getLong(0);
break;
}
String valueName = getName(value);
if (valueName == null) {
valueName = getCompoundValue(value);
}
return valueName;
return getRepresentation(value);
}
catch (MemoryAccessException e) {
return "??";
@ -449,6 +446,19 @@ class EnumDB extends DataTypeDB implements Enum {
}
}
@Override
public String getRepresentation(BigInteger bigInt, Settings settings, int bitLength) {
return getRepresentation(bigInt.longValue());
}
private String getRepresentation(long value) {
String valueName = getName(value);
if (valueName == null) {
valueName = getCompoundValue(value);
}
return valueName;
}
private String getCompoundValue(long value) {
if (value == 0) {
return "0";

View file

@ -70,6 +70,7 @@ public class ProgramDataTypeManager extends DataTypeManagerDB
@Override
public void setProgram(ProgramDB p) {
this.program = p;
dataOrganization = p.getCompilerSpec().getDataOrganization();
removeOldFileNameList();
}

View file

@ -35,8 +35,8 @@ import ghidra.util.task.TaskMonitor;
/**
* Class for managing data types in a project archive
*/
public class ProjectDataTypeManager extends DataTypeManagerDB implements
ProjectArchiveBasedDataTypeManager {
public class ProjectDataTypeManager extends DataTypeManagerDB
implements ProjectArchiveBasedDataTypeManager {
// private static final String DT_ARCHIVE_FILENAMES = "DataTypeArchiveFilenames";
// private static final String FILENAME_SEPARATOR = ";";
@ -57,9 +57,8 @@ public class ProjectDataTypeManager extends DataTypeManagerDB implements
* @throws VersionException if the database does not match the expected version.
* @throws IOException if a database I/O error occurs.
*/
public ProjectDataTypeManager(DBHandle handle, int openMode, ErrorHandler errHandler,
Lock lock, TaskMonitor monitor) throws CancelledException, VersionException,
IOException {
public ProjectDataTypeManager(DBHandle handle, int openMode, ErrorHandler errHandler, Lock lock,
TaskMonitor monitor) throws CancelledException, VersionException, IOException {
super(handle, null, openMode, errHandler, lock, monitor);
}
@ -252,16 +251,6 @@ public class ProjectDataTypeManager extends DataTypeManagerDB implements
return ArchiveType.PROJECT;
}
@Override
public DataOrganization getDataOrganization() {
if (dataOrganization == null) {
dataOrganization = DataOrganizationImpl.getDefaultOrganization();
}
return dataOrganization;
// // For now project data type archive will use the default data organization.
// return DataOrganization.getDefaultOrganization();
}
public void archiveReady(int openMode, TaskMonitor monitor) throws CancelledException {
if (openMode == DBConstants.UPGRADE) {
doSourceArchiveUpdates(null, monitor);

View file

@ -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,16 +15,15 @@
*/
package ghidra.program.database.data;
import ghidra.app.plugin.core.datamgr.archive.SourceArchive;
import ghidra.util.UniversalID;
import ghidra.util.exception.VersionException;
import ghidra.util.task.TaskMonitor;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import db.*;
import ghidra.app.plugin.core.datamgr.archive.SourceArchive;
import ghidra.util.UniversalID;
import ghidra.util.exception.VersionException;
import ghidra.util.task.TaskMonitor;
/**
* Adapter to access the data type archive identifier table.

View file

@ -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,15 +15,14 @@
*/
package ghidra.program.database.data;
import ghidra.app.plugin.core.datamgr.archive.SourceArchive;
import ghidra.program.model.data.DataTypeManager;
import ghidra.util.UniversalID;
import ghidra.util.exception.VersionException;
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.util.UniversalID;
import ghidra.util.exception.VersionException;
/**
* Version 0 implementation for accessing the Data Type Archive ID database table.
@ -39,8 +37,8 @@ class SourceArchiveAdapterV0 extends SourceArchiveAdapter {
static final Schema V0_SCHEMA = new Schema(VERSION, "Archive ID",
new Class[] { StringField.class, StringField.class, ByteField.class, LongField.class,
BooleanField.class }, new String[] { "Domain File ID", "Name", "Type",
"Last Sync Time", "Dirty Flag" });
BooleanField.class },
new String[] { "Domain File ID", "Name", "Type", "Last Sync Time", "Dirty Flag" });
private Table table;
@ -51,8 +49,8 @@ class SourceArchiveAdapterV0 extends SourceArchiveAdapter {
* @throws VersionException if the the table's version does not match the expected version
* for this adapter.
*/
public SourceArchiveAdapterV0(DBHandle handle, boolean create) throws VersionException,
IOException {
public SourceArchiveAdapterV0(DBHandle handle, boolean create)
throws VersionException, IOException {
if (create) {
table = handle.createTable(TABLE_NAME, V0_SCHEMA);
@ -66,9 +64,8 @@ class SourceArchiveAdapterV0 extends SourceArchiveAdapter {
}
int version = table.getSchema().getVersion();
if (version != VERSION) {
String msg =
"Expected version " + VERSION + " for table " + TABLE_NAME + " but got " +
table.getSchema().getVersion();
String msg = "Expected version " + VERSION + " for table " + TABLE_NAME +
" but got " + table.getSchema().getVersion();
if (version < VERSION) {
throw new VersionException(msg, VersionException.OLDER_VERSION, true);
}
@ -112,7 +109,7 @@ class SourceArchiveAdapterV0 extends SourceArchiveAdapter {
@Override
public List<Record> getRecords() throws IOException {
List<Record> records = new ArrayList<Record>();
List<Record> records = new ArrayList<>();
RecordIterator iterator = table.iterator();
while (iterator.hasNext()) {
records.add(iterator.next());

View file

@ -23,6 +23,7 @@ import ghidra.docking.settings.Settings;
import ghidra.program.database.DBObjectCache;
import ghidra.program.model.data.*;
import ghidra.program.model.mem.MemBuffer;
import ghidra.util.Msg;
/**
* Database implementation for the Union data type.
@ -69,9 +70,6 @@ class UnionDB extends CompositeDB implements Union {
}
/* (non-Javadoc)
* @see ghidra.program.model.data.DataType#getRepresentation(ghidra.program.model.mem.MemBuffer, ghidra.util.settings.Settings, int)
*/
@Override
public String getRepresentation(MemBuffer buf, Settings settings, int length) {
if (isNotYetDefined()) {
@ -85,24 +83,13 @@ class UnionDB extends CompositeDB implements Union {
return components.size() == 0;
}
/**
* @see ghidra.program.model.data.EditableComposite#add(ghidra.program.model.data.DataType, int, java.lang.String, java.lang.String)
*/
@Override
public DataTypeComponent add(DataType dataType, int length, String name, String comment) {
lock.acquire();
try {
checkDeleted();
if (length < 1) {
throw new IllegalArgumentException("Minimum component length is 1 byte");
}
validateDataType(dataType);
dataType = resolve(dataType);
checkAncestry(dataType);
int oldLength = unionLength;
DataTypeComponent dtc = doAdd(dataType, length, name, comment);
adjustInternalAlignment(false);
updateLength(oldLength, true, true);
adjustLength(true, true);
return dtc;
}
finally {
@ -110,21 +97,41 @@ class UnionDB extends CompositeDB implements Union {
}
}
private DataTypeComponent doAdd(DataType resolvedDataType, int length, String name,
String comment) {
private int getBitFieldAllocation(BitFieldDataType bitfieldDt) {
// TODO Is this the right place to adjust the length?
int dtLength = resolvedDataType.getLength();
if (dtLength > 0 && dtLength < length) {
length = dtLength;
BitFieldPacking bitFieldPacking = getBitFieldPacking();
if (bitFieldPacking.useMSConvention()) {
return bitfieldDt.getBaseTypeSize();
}
DataTypeComponentDB dtc = createComponent(dataMgr.getResolvedID(resolvedDataType), length,
if (bitfieldDt.getBitSize() == 0) {
return 0;
}
int length = bitfieldDt.getBaseTypeSize();
int packValue = getPackingValue();
if (packValue != NOT_PACKING && length > packValue) {
length =
DataOrganizationImpl.getLeastCommonMultiple(bitfieldDt.getStorageSize(), packValue);
}
return length;
}
private DataTypeComponent doAdd(DataType dataType, int length, String name, String comment) {
validateDataType(dataType);
dataType = resolve(dataType);
checkAncestry(dataType);
length = getPreferredComponentLength(dataType, length);
DataTypeComponentDB dtc = createComponent(dataMgr.getResolvedID(dataType), length,
components.size(), 0, name, comment);
resolvedDataType.addParent(this);
dataType.addParent(this);
components.add(dtc);
unionLength = Math.max(unionLength, length);
return dtc;
}
@ -150,37 +157,26 @@ class UnionDB extends CompositeDB implements Union {
}
}
/**
* @see ghidra.program.model.data.EditableComposite#insert(int, ghidra.program.model.data.DataType, int, java.lang.String, java.lang.String)
*/
@Override
public DataTypeComponent insert(int ordinal, DataType dataType, int length, String name,
String comment) {
lock.acquire();
try {
checkDeleted();
if (length < 1) {
throw new IllegalArgumentException("Minimum component length is 1 byte");
}
validateDataType(dataType);
dataType = resolve(dataType);
checkAncestry(dataType);
// TODO Is this the right place to adjust the length?
int dtLength = dataType.getLength();
if (dtLength > 0 && dtLength < length) {
length = dtLength;
}
length = getPreferredComponentLength(dataType, length);
int oldLength = unionLength;
DataTypeComponentDB dtc =
createComponent(dataMgr.getResolvedID(dataType), length, ordinal, 0, name, comment);
dataType.addParent(this);
shiftOrdinals(ordinal, 1);
components.add(ordinal, dtc);
// unionLength = Math.max(unionLength, length);
adjustInternalAlignment(true);
updateLength(oldLength, true, true);
adjustLength(true, true);
return dtc;
}
finally {
@ -188,22 +184,68 @@ class UnionDB extends CompositeDB implements Union {
}
}
/**
* @see ghidra.program.model.data.EditableComposite#delete(int)
*/
@Override
public DataTypeComponent insertBitField(int ordinal, int byteWidth, int bitOffset,
DataType baseDataType, int bitSize, String componentName, String comment)
throws InvalidDataTypeException, ArrayIndexOutOfBoundsException {
if (ordinal < 0 || ordinal > components.size()) {
throw new ArrayIndexOutOfBoundsException(ordinal);
}
if (isInternallyAligned()) {
BitFieldDataType bitFieldDt =
new BitFieldDBDataType(baseDataType, bitSize, 0, 0, dataMgr);
return insert(ordinal, bitFieldDt, bitFieldDt.getStorageSize(), componentName, comment);
}
if (byteWidth <= 0) {
throw new IllegalArgumentException("Invalid byteWidth");
}
// handle unaligned case - use minimal storage
// bitfield value will be forced based upon byteWidth, bitSize and endianess
boolean bigEndian = getDataOrganization().isBigEndian();
int effectiveBitSize =
BitFieldDataType.getEffectiveBitSize(bitSize, baseDataType.getLength());
int storageSize = BitFieldDataType.getMinimumStorageSize(effectiveBitSize);
if (byteWidth < storageSize) {
throw new IllegalArgumentException(
"Bitfield does not fit within specified constraints");
}
int storageBitOffset = 0;
if (bigEndian) {
storageBitOffset = (8 * storageSize) - effectiveBitSize;
}
BitFieldDataType bitfieldDt = new BitFieldDBDataType(baseDataType, bitSize,
storageBitOffset, storageSize, getDataTypeManager());
DataTypeComponentDB dtc = createComponent(dataMgr.getResolvedID(bitfieldDt), storageSize,
ordinal, 0, componentName, comment);
bitfieldDt.addParent(this); // currently has no affect
shiftOrdinals(ordinal, 1);
components.add(ordinal, dtc);
adjustLength(true, true);
return dtc;
}
@Override
public void delete(int ordinal) {
lock.acquire();
try {
checkDeleted();
int oldLength = unionLength;
DataTypeComponentDB dtc = components.remove(ordinal);
dtc.getDataType().removeParent(this);
removeComponent(dtc.getKey());
shiftOrdinals(ordinal, -1);
// unionLength = computeUnpaddedUnionLength();
adjustInternalAlignment(false);
updateLength(oldLength, true, true);
adjustLength(true, true);
}
finally {
lock.release();
@ -232,18 +274,14 @@ class UnionDB extends CompositeDB implements Union {
if (!(dataType instanceof Union)) {
throw new IllegalArgumentException();
}
doReplaceWith((Union) dataType, true);
}
void doReplaceWith(Union union, boolean notify) {
doReplaceWith(union, notify, null);
doReplaceWith((Union) dataType, true, null);
}
void doReplaceWith(Union union, boolean notify, DataTypeConflictHandler handler) {
lock.acquire();
try {
checkDeleted();
int oldLength = unionLength;
long oldMinAlignment = getMinimumAlignment();
for (int i = 0; i < components.size(); i++) {
DataTypeComponentDB dtc = components.get(i);
@ -252,21 +290,15 @@ class UnionDB extends CompositeDB implements Union {
}
components.clear();
DataTypeComponent[] otherComponents = union.getComponents();
for (int i = 0; i < otherComponents.length; i++) {
DataTypeComponent dtc = otherComponents[i];
DataType dt = dtc.getDataType();
dt = resolve(dt, handler);
checkAncestry(dt);
int dtLength = dt.getLength();
if (dtLength <= 0) {
dtLength = dtc.getLength();
}
doAdd(dt, dtLength, dtc.getFieldName(), dtc.getComment());
}
setDescription(union.getDescription());
setAlignment(union, notify);
updateLength(oldLength, notify, true);
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();
}
@ -277,31 +309,6 @@ class UnionDB extends CompositeDB implements Union {
}
}
/**
* @see ghidra.program.model.data.EditableComposite#contains(ghidra.program.model.data.DataType)
*/
public boolean contains(DataType dataType) {
lock.acquire();
try {
checkIsValid();
for (int i = 0; i < components.size(); i++) {
DataTypeComponent dtc = components.get(i);
DataType dt = dtc.getDataType();
if (dt == dataType) {
return true;
}
}
return false;
}
finally {
lock.release();
}
}
/**
* @see ghidra.program.model.data.EditableComposite#isPartOf(ghidra.program.model.data.DataType)
*/
@Override
public boolean isPartOf(DataType dataType) {
lock.acquire();
@ -310,8 +317,7 @@ class UnionDB extends CompositeDB implements Union {
if (equals(dataType)) {
return true;
}
for (int i = 0; i < components.size(); i++) {
DataTypeComponent dtc = components.get(i);
for (DataTypeComponent dtc : components) {
DataType subDt = dtc.getDataType();
if (subDt instanceof Composite) {
if (((Composite) subDt).isPartOf(dataType)) {
@ -329,17 +335,11 @@ class UnionDB extends CompositeDB implements Union {
}
}
/**
* @see ghidra.program.model.data.Composite#getNumComponents(ghidra.program.model.mem.MemBuffer)
*/
@Override
public int getNumComponents() {
lock.acquire();
try {
checkIsValid();
// if (components.size() == 0) {
// return 1; // lie
// }
return components.size();
}
finally {
@ -347,9 +347,6 @@ class UnionDB extends CompositeDB implements Union {
}
}
/**
* @see ghidra.program.model.data.Composite#getComponent(int, ghidra.program.model.mem.MemBuffer)
*/
@Override
public DataTypeComponent getComponent(int ordinal) {
lock.acquire();
@ -365,9 +362,6 @@ class UnionDB extends CompositeDB implements Union {
}
}
/**
* @see ghidra.program.model.data.Composite#getComponents(ghidra.program.model.mem.MemBuffer)
*/
@Override
public DataTypeComponent[] getComponents() {
lock.acquire();
@ -397,9 +391,6 @@ class UnionDB extends CompositeDB implements Union {
return union;
}
/**
* @see ghidra.program.model.data.DataType#getLength()
*/
@Override
public int getLength() {
lock.acquire();
@ -415,30 +406,22 @@ class UnionDB extends CompositeDB implements Union {
}
}
/**
* @see ghidra.program.model.data.DataType#dataTypeSizeChanged(ghidra.program.model.data.DataType)
*/
@Override
public void dataTypeSizeChanged(DataType dt) {
lock.acquire();
try {
checkDeleted();
boolean changed = false;
int oldLength = unionLength;
unionLength = 0;
for (int i = 0; i < components.size(); i++) {
DataTypeComponentDB dtc = components.get(i);
DataType tmpDt = dtc.getDataType();
int tmpLen = tmpDt.getLength();
if ((tmpDt.isEquivalent(dt)) && (tmpLen > 0) && (tmpLen != dtc.getLength())) {
dtc.setLength(tmpLen, true);
for (DataTypeComponentDB dtc : components) {
int length = dtc.getLength();
if (dtc.getDataType() == dt) {
length = getPreferredComponentLength(dt, length);
dtc.setLength(length, true);
changed = true;
}
unionLength = Math.max(unionLength, dtc.getLength());
}
if (changed) {
adjustInternalAlignment(false);
updateLength(oldLength, true, false);
adjustLength(true, false);
}
}
finally {
@ -451,51 +434,61 @@ class UnionDB extends CompositeDB implements Union {
adjustInternalAlignment(true);
}
public void adjustLength() {
adjustLength(true);
}
public void adjustLength(boolean notify) {
private void adjustLength(boolean notify, boolean setLastChangeTime) {
lock.acquire();
try {
checkDeleted();
int oldLength = unionLength;
unionLength = getLength(getDataOrganization(), isInternallyAligned());
updateLength(oldLength, notify, false);
unionLength = 0;
for (DataTypeComponent dtc : components) {
int length = dtc.getLength();
if (isInternallyAligned() && dtc.isBitFieldComponent()) {
// revise length to reflect compiler bitfield allocation rules
length = getBitFieldAllocation((BitFieldDataType) dtc.getDataType());
}
unionLength = Math.max(length, unionLength);
}
DataOrganization dataOrganization = getDataOrganization();
int alignment = dataOrganization.getAlignment(this, unionLength);
int amountFilled = unionLength % alignment;
if (amountFilled > 0) {
unionLength += alignment - amountFilled;
}
updateLength(oldLength, notify, setLastChangeTime);
}
finally {
lock.release();
}
}
/**
* @see ghidra.program.model.data.DataType#dataTypeDeleted(ghidra.program.model.data.DataType)
*/
@Override
public void dataTypeDeleted(DataType dt) {
lock.acquire();
try {
checkDeleted();
int oldLength = unionLength;
boolean didDelete = false;
for (int i = components.size() - 1; i >= 0; i--) {
boolean didChange = false;
for (int i = components.size() - 1; i >= 0; i--) { // reverse order
DataTypeComponentDB dtc = components.get(i);
if (dtc.getDataType() == dt) {
boolean removeBitFieldComponent = false;
if (dtc.isBitFieldComponent()) {
BitFieldDataType bitfieldDt = (BitFieldDataType) dtc.getDataType();
removeBitFieldComponent = bitfieldDt.getBaseDataType() == dt;
}
if (removeBitFieldComponent || dtc.getDataType() == dt) {
dt.removeParent(this);
components.remove(i);
removeComponent(dtc.getKey());
shiftOrdinals(i, -1);
didDelete = true;
didChange = true;
}
}
if (didDelete) {
adjustInternalAlignment(false);
if (unionLength == 0) {
dataMgr.addDataTypeToDelete(key);
}
else {
updateLength(oldLength, true, false);
}
if (didChange) {
adjustLength(true, true);
}
}
finally {
@ -503,10 +496,6 @@ class UnionDB extends CompositeDB implements Union {
}
}
/**
*
* @see ghidra.program.model.data.DataType#isEquivalent(ghidra.program.model.data.DataType)
*/
@Override
public boolean isEquivalent(DataType dt) {
if (dt == this) {
@ -549,32 +538,19 @@ class UnionDB extends CompositeDB implements Union {
private void updateLength(int oldLength, boolean notify, boolean setLastChangeTime) {
if (oldLength != unionLength) {
record.setIntValue(CompositeDBAdapter.COMPOSITE_LENGTH_COL, unionLength);
// record.setLongValue(CompositeDBAdapter.COMPOSITE_LAST_CHANGE_TIME_COL,
// (new Date()).getTime());
try {
compositeAdapter.updateRecord(record, setLastChangeTime);
}
catch (IOException e) {
dataMgr.dbError(e);
}
// if (notify) {
notifySizeChanged();
// }
}
else if (notify) {
dataMgr.dataTypeChanged(this);
}
}
private int computeUnpaddedUnionLength() {
int unpaddedLength = 0;
for (int i = 0; i < components.size(); i++) {
unpaddedLength =
Math.max(unpaddedLength, ((DataTypeComponent) components.get(i)).getLength());
}
return unpaddedLength;
}
private void shiftOrdinals(int ordinal, int deltaOrdinal) {
for (int i = ordinal; i < components.size(); i++) {
DataTypeComponentDB dtc = components.get(i);
@ -582,9 +558,6 @@ class UnionDB extends CompositeDB implements Union {
}
}
/**
* @see ghidra.program.model.data.DataType#dataTypeReplaced(ghidra.program.model.data.DataType, ghidra.program.model.data.DataType)
*/
@Override
public void dataTypeReplaced(DataType oldDt, DataType newDt) {
if (oldDt == this) {
@ -593,39 +566,67 @@ class UnionDB extends CompositeDB implements Union {
lock.acquire();
try {
checkDeleted();
DataType replacementDt = newDt;
try {
validateDataType(newDt);
if (!(newDt instanceof DataTypeDB) ||
(newDt.getDataTypeManager() != getDataTypeManager())) {
newDt = resolve(newDt);
validateDataType(replacementDt);
if (!(replacementDt instanceof DataTypeDB) ||
(replacementDt.getDataTypeManager() != getDataTypeManager())) {
replacementDt = resolve(replacementDt);
}
checkAncestry(newDt);
checkAncestry(replacementDt);
}
catch (Exception e) {
newDt = new ByteDataType();
// TODO: should we use Undefined instead since we do not support
// DEFAULT in Unions
replacementDt = DataType.DEFAULT;
}
boolean changed = false;
int oldLength = getLength();
Iterator<DataTypeComponentDB> it = components.iterator();
while (it.hasNext()) {
DataTypeComponentDB comp = it.next();
DataType compDt = comp.getDataType();
if (oldDt == compDt) {
oldDt.removeParent(this);
comp.setDataType(newDt);
newDt.addParent(this);
int len = newDt.getLength();
if (len > 0) {
comp.setLength(len, true);
for (int i = components.size() - 1; i >= 0; i--) {
DataTypeComponentDB dtc = components.get(i);
boolean remove = false;
if (dtc.isBitFieldComponent()) {
try {
changed |= updateBitFieldDataType(dtc, oldDt, replacementDt);
}
catch (InvalidDataTypeException e) {
Msg.error(this,
"Invalid bitfield replacement type " + newDt.getName() +
", removing bitfield " + dtc.getDataType().getName() + ": " +
getPathName());
remove = true;
}
}
else if (dtc.getDataType() == oldDt) {
if (replacementDt == DEFAULT) {
Msg.error(this,
"Invalid replacement type " + newDt.getName() +
", removing component " + dtc.getDataType().getName() + ": " +
getPathName());
remove = true;
}
else {
oldDt.removeParent(this);
dtc.setDataType(replacementDt);
replacementDt.addParent(this);
int len = replacementDt.getLength();
if (len > 0) {
dtc.setLength(len, true);
}
changed = true;
}
}
if (remove) {
oldDt.removeParent(this);
components.remove(i);
removeComponent(dtc.getKey());
shiftOrdinals(i, -1);
changed = true;
}
}
if (changed) {
adjustInternalAlignment(false);
if (oldLength != getLength()) {
updateLength(oldLength, true, true);
}
adjustLength(true, true);
}
}
finally {
@ -633,16 +634,11 @@ class UnionDB extends CompositeDB implements Union {
}
}
/**
* @see ghidra.program.model.data.DataType#dataTypeNameChanged(ghidra.program.model.data.DataType, java.lang.String)
*/
@Override
public void dataTypeNameChanged(DataType dt, String oldName) {
// ignored
}
/**
* @see ghidra.program.model.data.DataType#dependsOn(ghidra.program.model.data.DataType)
*/
@Override
public boolean dependsOn(DataType dt) {
lock.acquire();
@ -671,33 +667,6 @@ class UnionDB extends CompositeDB implements Union {
return "UNION_" + getName();
}
public int getLength(DataOrganization dataOrganization, boolean padEnd) {
int unpaddedLength = computeUnpaddedUnionLength();
int newLength = unpaddedLength;
if (padEnd) {
newLength += getPaddingSize(dataOrganization, unpaddedLength);
}
return newLength;
}
private int getPaddingSize(DataOrganization dataOrganization, int unpaddedLength) {
int alignment = dataOrganization.getAlignment(this, unpaddedLength);
int amountFilled = unpaddedLength % alignment;
if (amountFilled > 0) {
return alignment - amountFilled;
}
return 0;
}
/* (non-Javadoc)
* @see ghidra.program.model.data.Composite#setAligned(boolean)
*/
@Override
public void setInternallyAligned(boolean aligned) {
super.setInternallyAligned(aligned);
adjustInternalAlignment(true);
}
@Override
public void realign() {
if (isInternallyAligned()) {
@ -707,6 +676,6 @@ class UnionDB extends CompositeDB implements Union {
@Override
public void adjustInternalAlignment(boolean notify) {
adjustLength(notify);
adjustLength(notify, false);
}
}

View file

@ -82,7 +82,7 @@ public class OldFunctionManager implements ErrorHandler {
throw new AssertException("Function manager already upgraded");
}
this.program = upgradeProgram;
dataManager = upgradeProgram.getDataManager();
dataManager = upgradeProgram.getDataTypeManager();
monitor.setMessage("Upgrading Functions...");
monitor.initialize(getFunctionCount());

View file

@ -151,7 +151,7 @@ public class EquateDB extends DatabaseObject implements Equate {
public String getDisplayName() {
String equateName = getName();
if (isEnumBased()) {
DataTypeManager dtm = equateMgr.getProgram().getDataManager();
DataTypeManager dtm = equateMgr.getProgram().getDataTypeManager();
UniversalID id = EquateManager.getDataTypeUUID(equateName);
Enum enoom = (Enum) dtm.findDataTypeForID(id);
if (enoom == null || enoom.getName(getValue()) == null) {

View file

@ -197,10 +197,10 @@ public class EquateManager implements EquateTable, ErrorHandler, ManagerDB {
return;
}
if (program.getDataManager().findDataTypeForID(enoom.getUniversalID()) == null) {
if (program.getDataTypeManager().findDataTypeForID(enoom.getUniversalID()) == null) {
int transactionID = program.startTransaction("Set Equate Dialog");
try {
enoom = (Enum) program.getDataManager().addDataType(enoom, null);
enoom = (Enum) program.getDataTypeManager().addDataType(enoom, null);
}
finally {
program.endTransaction(transactionID, true);

View file

@ -0,0 +1,257 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.program.model.data;
import java.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;
import ghidra.util.UniversalID;
import ghidra.util.exception.DuplicateNameException;
/**
* Base class for DataType classes. Many of the DataType methods are stubbed out so simple datatype
* classes can be created without implementing too many methods.
*/
public abstract class AbstractDataType implements DataType {
protected String name;
protected CategoryPath categoryPath;
protected final DataTypeManager dataMgr;
private DataOrganization dataOrganization;
protected AbstractDataType(CategoryPath path, String name, DataTypeManager dataTypeManager) {
if (path == null) {
throw new IllegalArgumentException("Category Path is null!");
}
if (name == null || name.length() == 0) {
throw new IllegalArgumentException("Name is null or empty!");
}
// allow spaces since derived types may have spaces (pointers for example: foo *32)
if (!DataUtilities.isValidDataTypeName(name)) {
throw new IllegalArgumentException("Invalid DataType name: " + name);
}
this.categoryPath = path;
this.name = name;
this.dataMgr = dataTypeManager;
}
@Override
public CategoryPath getCategoryPath() {
return categoryPath;
}
/**
* @see ghidra.program.model.data.DataType#getDataTypeManager()
*/
@Override
public final DataTypeManager getDataTypeManager() {
return dataMgr;
}
@Override
public final DataOrganization getDataOrganization() {
if (dataOrganization != null) {
return dataOrganization;
}
if (dataMgr != null) {
dataOrganization = dataMgr.getDataOrganization();
}
if (dataOrganization == null) {
dataOrganization = DataOrganizationImpl.getDefaultOrganization();
}
return dataOrganization;
}
@Override
public DataTypePath getDataTypePath() {
return new DataTypePath(categoryPath, name);
}
@Override
public URL getDocs() {
return null;
}
@Override
public String getName() {
return name;
}
@Override
public String getPathName() {
return getDataTypePath().getPath();
}
@Override
public String getDisplayName() {
return getName();
}
@Override
public String getMnemonic(Settings settings) {
return name;
}
@Override
public boolean isNotYetDefined() {
return false;
}
@Override
public String toString() {
return getDisplayName();
}
@Override
public boolean isDeleted() {
return false;
}
@Override
public void setName(String name) throws InvalidNameException {
// default is immutable
}
@Override
public void setNameAndCategory(CategoryPath path, String name)
throws InvalidNameException, DuplicateNameException {
// default is immutable
}
@Override
public void dataTypeSizeChanged(DataType dt) {
// do nothing
}
@Override
public void dataTypeDeleted(DataType dt) {
// do nothing
}
@Override
public void dataTypeReplaced(DataType oldDt, DataType newDt) {
// do nothing
}
@Override
public void addParent(DataType dt) {
// not-applicable
}
@Override
public void removeParent(DataType dt) {
// not-applicable
}
@Override
public DataType[] getParents() {
// not-applicable
return null;
}
@Override
public boolean dependsOn(DataType dt) {
return false;
}
@Override
public SourceArchive getSourceArchive() {
return null; // do nothing
}
@Override
public void setSourceArchive(SourceArchive archive) {
// do nothing
}
@Override
public long getLastChangeTime() {
// do nothing
return 0;
}
@Override
public long getLastChangeTimeInSourceArchive() {
// do nothing
return 0;
}
@Override
public UniversalID getUniversalID() {
return null;
}
@Override
public void dataTypeNameChanged(DataType dt, String oldName) {
// do nothing
}
@Override
public void replaceWith(DataType dataType) {
// do nothing
}
@Override
public void setLastChangeTime(long lastChangeTime) {
// do nothing
}
@Override
public void setLastChangeTimeInSourceArchive(long lastChangeTimeInSourceArchive) {
// do nothing
}
@Override
public void setDescription(String description) throws UnsupportedOperationException {
// immutable
}
@Override
public boolean isDynamicallySized() {
return false; // not applicable
}
@Override
public String getDefaultLabelPrefix() {
return null;
}
@Override
public String getDefaultAbbreviatedLabelPrefix() {
return getDefaultLabelPrefix();
}
@Override
public void setCategoryPath(CategoryPath path) throws DuplicateNameException {
// not-applicable
}
@Override
public String getDefaultLabelPrefix(MemBuffer buf, Settings settings, int len,
DataTypeDisplayOptions options) {
return getDefaultLabelPrefix();
}
@Override
public String getDefaultOffcutLabelPrefix(MemBuffer buf, Settings settings, int len,
DataTypeDisplayOptions options, int offcutLength) {
// By default we will do nothing different for offcut values
return getDefaultLabelPrefix(buf, settings, len, options);
}
}

View file

@ -18,6 +18,7 @@ package ghidra.program.model.data;
import java.math.BigInteger;
import ghidra.docking.settings.*;
import ghidra.program.model.mem.ByteMemBufferImpl;
import ghidra.program.model.mem.MemBuffer;
import ghidra.program.model.scalar.Scalar;
import ghidra.util.StringFormat;
@ -162,9 +163,27 @@ public abstract class AbstractIntegerDataType extends BuiltIn implements ArraySt
}
/**
*
* @see ghidra.program.model.data.DataType#getValue(ghidra.program.model.mem.MemBuffer, ghidra.docking.settings.Settings, int)
* Get the value of integer data as a BigInteger
* @param buf the data buffer.
* @param settings the settings to use.
* @return BigInteger data value
*/
public BigInteger getBigIntegerValue(MemBuffer buf, Settings settings) {
Object value = getValue(buf, settings, getLength());
if (value instanceof Scalar) {
Scalar s = (Scalar) value;
return s.getBigInteger();
}
if (value instanceof BigInteger) {
return (BigInteger) value;
}
if (value instanceof Character) {
// FIXME: consider flipping around getValue and getBigIntegerValue
return BigInteger.valueOf((Character) value);
}
return null;
}
@Override
public Object getValue(MemBuffer buf, Settings settings, int length) {
@ -233,8 +252,6 @@ public abstract class AbstractIntegerDataType extends BuiltIn implements ArraySt
return "??";
}
int format = getFormatSettingsDefinition().getFormat(settings);
boolean padded = PADDING.isPadded(settings);
boolean isBigEndian = ENDIAN.isBigEndian(settings, buf);
if (!isBigEndian) {
@ -245,78 +262,72 @@ public abstract class AbstractIntegerDataType extends BuiltIn implements ArraySt
bytes = flipped;
}
return getRepresentation(new BigInteger(bytes), settings, 8 * length);
}
/**
* Get integer representation of the big-endian value.
* @param bigInt BigInteger value with the appropriate sign
* @param settings integer format settings (PADDING, FORMAT, etc.)
* @return formatted integer string
*/
public String getRepresentation(BigInteger bigInt, Settings settings, int bitLength) {
int format = getFormatSettingsDefinition().getFormat(settings);
boolean padded = PADDING.isPadded(settings);
boolean negative = bigInt.signum() < 0;
if (negative && (!signed || (format != FormatSettingsDefinition.DECIMAL))) {
// force use of unsigned value
bigInt = bigInt.add(BigInteger.valueOf(2).pow(bitLength));
}
int nominalLen;
if (format == FormatSettingsDefinition.CHAR) {
int charSize = Math.min(getDataOrganization().getCharSize(), getLength());
return new StringDataInstance(this, settings, buf, charSize).getCharRepresentation();
nominalLen = (bitLength + 7) / 8;
byte[] bytes = bigInt.toByteArray();
if (bytes.length > nominalLen) {
// BigInteger supplied too many bytes
byte[] chars = new byte[nominalLen];
System.arraycopy(bytes, bytes.length - nominalLen, chars, 0, nominalLen);
bytes = chars;
}
else if (bytes.length < nominalLen) {
// BigInteger supplied too few bytes
byte[] chars = new byte[nominalLen];
System.arraycopy(bytes, 0, chars, nominalLen - bytes.length, bytes.length);
bytes = chars;
}
MemBuffer memBuf = new ByteMemBufferImpl(null, bytes, true);
return new StringDataInstance(this, settings, memBuf, charSize).getCharRepresentation();
}
boolean negative = (bytes[0] < 0); // check most-significant-byte sign
int nominalLen;
String valStr;
if (size >= 8) {
// Use BigInteger - too big for long
if ((negative && !signed) || (format != FormatSettingsDefinition.DECIMAL)) {
byte[] unsignedBytes = new byte[size + 1];
unsignedBytes[size] = 0;
System.arraycopy(bytes, 0, unsignedBytes, 1, size);
bytes = unsignedBytes;
}
BigInteger bigInt = new BigInteger(bytes);
switch (format) {
default:
case FormatSettingsDefinition.HEX:
valStr = bigInt.toString(16).toUpperCase() + "h";
nominalLen = (2 * size) + 1;
break;
case FormatSettingsDefinition.DECIMAL:
String sign = "";
if (negative && signed) {
sign = "-";
bigInt = bigInt.negate();
}
return sign + bigInt.toString(10);
case FormatSettingsDefinition.BINARY:
valStr = bigInt.toString(2) + "b";
nominalLen = (8 * size) + 1;
break;
case FormatSettingsDefinition.OCTAL:
valStr = bigInt.toString(8) + "o";
nominalLen = (3 * size) + 1;
break;
}
}
else {
// Use long when possible
long val = 0;
for (byte b : bytes) {
val = (val << 8) + (b & 0x0ffL);
}
switch (format) {
default:
case FormatSettingsDefinition.HEX:
valStr = Long.toString(val, 16).toUpperCase() + 'h';
nominalLen = (2 * size) + 1;
break;
case FormatSettingsDefinition.DECIMAL:
String sign = "";
if (negative && signed) {
sign = "-";
val = (~val + 1) & ~-(1L << (8 * size));
}
return sign + Long.toString(val);
case FormatSettingsDefinition.BINARY:
valStr = Long.toString(val, 2) + 'b';
nominalLen = (8 * size) + 1;
break;
case FormatSettingsDefinition.OCTAL:
valStr = Long.toString(val, 8) + 'o';
nominalLen = (3 * size) + 1;
break;
}
switch (format) {
default:
case FormatSettingsDefinition.HEX:
valStr = bigInt.toString(16).toUpperCase() + "h";
nominalLen = (bitLength + 3) / 4;
break;
case FormatSettingsDefinition.DECIMAL:
return bigInt.toString(10);
case FormatSettingsDefinition.BINARY:
valStr = bigInt.toString(2) + "b";
nominalLen = bitLength;
break;
case FormatSettingsDefinition.OCTAL:
valStr = bigInt.toString(8) + "o";
nominalLen = (bitLength + 2) / 3;
break;
}
if (padded) {
valStr = StringFormat.padIt(valStr, nominalLen, (char) 0, true);
// +1 to account for format suffix char
valStr = StringFormat.padIt(valStr, nominalLen + 1, (char) 0, true);
}
return valStr;
}
@ -356,7 +367,7 @@ public abstract class AbstractIntegerDataType extends BuiltIn implements ArraySt
* this data-type. For example, this method on IntegerDataType will
* return an instance of UnsignedIntegerDataType.
*/
public abstract DataType getOppositeSignednessDataType();
public abstract AbstractIntegerDataType getOppositeSignednessDataType();
@Override
public boolean isEquivalent(DataType dt) {
@ -452,21 +463,19 @@ public abstract class AbstractIntegerDataType extends BuiltIn implements ArraySt
if (dataOrganization != null) {
int index = dataOrganization.getLongLongSize() - 1;
if (index >= 0 && index < 8) {
dataTypes[index] =
(AbstractIntegerDataType) LongLongDataType.dataType.clone(dtm);
dataTypes[index] = LongLongDataType.dataType.clone(dtm);
}
index = dataOrganization.getLongSize() - 1;
if (index >= 0 && index < 8) {
dataTypes[index] = (AbstractIntegerDataType) LongDataType.dataType.clone(dtm);
dataTypes[index] = LongDataType.dataType.clone(dtm);
}
index = dataOrganization.getShortSize() - 1;
if (index >= 0 && index < 8) {
dataTypes[index] = (AbstractIntegerDataType) ShortDataType.dataType.clone(dtm);
dataTypes[index] = ShortDataType.dataType.clone(dtm);
}
index = dataOrganization.getIntegerSize() - 1;
if (index >= 0 && index < 8) {
dataTypes[index] =
(AbstractIntegerDataType) IntegerDataType.dataType.clone(dtm);
dataTypes[index] = IntegerDataType.dataType.clone(dtm);
}
}
}
@ -523,26 +532,23 @@ public abstract class AbstractIntegerDataType extends BuiltIn implements ArraySt
if (dataOrganization != null) {
int index = dataOrganization.getLongLongSize() - 1;
if (index >= 0 && index < 8) {
dataTypes[index] =
(AbstractIntegerDataType) UnsignedLongLongDataType.dataType.clone(dtm);
dataTypes[index] = UnsignedLongLongDataType.dataType.clone(dtm);
}
index = dataOrganization.getLongSize() - 1;
if (index >= 0 && index < 8) {
dataTypes[index] =
(AbstractIntegerDataType) UnsignedLongDataType.dataType.clone(dtm);
dataTypes[index] = UnsignedLongDataType.dataType.clone(dtm);
}
index = dataOrganization.getShortSize() - 1;
if (index >= 0 && index < 8) {
dataTypes[index] =
(AbstractIntegerDataType) UnsignedShortDataType.dataType.clone(dtm);
dataTypes[index] = UnsignedShortDataType.dataType.clone(dtm);
}
index = dataOrganization.getIntegerSize() - 1;
if (index >= 0 && index < 8) {
dataTypes[index] =
(AbstractIntegerDataType) UnsignedIntegerDataType.dataType.clone(dtm);
dataTypes[index] = UnsignedIntegerDataType.dataType.clone(dtm);
}
}
}
return dataTypes;
}
}

View file

@ -0,0 +1,170 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.program.model.data;
import java.util.ArrayList;
import java.util.List;
import javax.help.UnsupportedOperationException;
import ghidra.docking.settings.Settings;
import ghidra.util.exception.DuplicateNameException;
public class AlignedStructureInspector extends AlignedStructurePacker {
private AlignedStructureInspector(Structure structure) {
super(structure, getComponentWrappers(structure));
}
private static List<ReadOnlyComponentWrapper> getComponentWrappers(Structure structure) {
List<ReadOnlyComponentWrapper> list = new ArrayList<>();
for (DataTypeComponent c : structure.getComponents()) {
list.add(new ReadOnlyComponentWrapper(c));
}
return list;
}
private static class ReadOnlyComponentWrapper implements InternalDataTypeComponent {
private final DataTypeComponent component;
private int ordinal;
private int offset;
private int length;
private DataType dataType;
ReadOnlyComponentWrapper(DataTypeComponent component) {
this.component = component;
this.ordinal = component.getOrdinal();
this.offset = component.getOffset();
this.length = component.getLength();
this.dataType = component.getDataType();
}
@Override
public void update(int ordinal, int offset, int length) {
this.ordinal = ordinal;
this.offset = offset;
this.length = length;
}
@Override
public DataType getDataType() {
return dataType;
}
@Override
public DataType getParent() {
return component.getParent();
}
@Override
public boolean isFlexibleArrayComponent() {
return false;
}
@Override
public boolean isBitFieldComponent() {
return component.isBitFieldComponent();
}
@Override
public boolean isZeroBitFieldComponent() {
return component.isZeroBitFieldComponent();
}
@Override
public int getOrdinal() {
return ordinal;
}
@Override
public int getOffset() {
return offset;
}
@Override
public int getEndOffset() {
return offset + length - 1;
}
@Override
public int getLength() {
return length;
}
@Override
public String getComment() {
return component.getComment();
}
@Override
public Settings getDefaultSettings() {
return component.getDefaultSettings();
}
@Override
public void setDefaultSettings(Settings settings) {
throw new UnsupportedOperationException();
}
@Override
public void setComment(String comment) {
throw new UnsupportedOperationException();
}
@Override
public String getFieldName() {
return component.getFieldName();
}
@Override
public void setFieldName(String fieldName) throws DuplicateNameException {
throw new UnsupportedOperationException();
}
@Override
public String getDefaultFieldName() {
if (isZeroBitFieldComponent()) {
return "";
}
return DEFAULT_FIELD_NAME_PREFIX + "_0x" + Integer.toHexString(getOffset());
}
@Override
public boolean isEquivalent(DataTypeComponent dtc) {
throw new UnsupportedOperationException();
}
@Override
public void setDataType(DataType dataType) {
this.dataType = dataType;
}
}
/**
* Perform structure component packing in a read-only fashion primarily
* for the purpose of computing external alignment for existing structures.
* @param structure
* @return aligned packing result
*/
public static StructurePackResult packComponents(Structure structure) {
AlignedStructureInspector packer = new AlignedStructureInspector(structure);
return packer.pack();
}
}

View file

@ -0,0 +1,591 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.program.model.data;
import java.util.Iterator;
import java.util.List;
import ghidra.util.exception.AssertException;
/**
* <code>AlignedStructurePacker</code> provides support for performing aligned packing
* of Structure components.
* <p>
* NOTE: We currently have no way of conveying or supporting explicit bitfield component pragmas
* supported by some compilers (e.g., bit_field_size, bit_field_align, bit_packing).
*/
public class AlignedStructurePacker {
private final Structure structure;
private final List<? extends InternalDataTypeComponent> components;
private DataOrganization dataOrganization;
private BitFieldPacking bitFieldPacking;
/**
* Constructor.
* @param structure structure whose components need to be packed and updated
* during packing (ordinal, offset, length and bit-field datatypes may be modified)
* @param components list of mutable component
*/
protected AlignedStructurePacker(Structure structure,
List<? extends InternalDataTypeComponent> components) {
this.structure = structure;
this.components = components;
dataOrganization = structure.getDataOrganization();
bitFieldPacking = dataOrganization.getBitFieldPacking();
}
/**
* <code>StructurePackResult</code> provides access to aligned
* packing results
*/
public static class StructurePackResult {
public final int numComponents;
public final int structureLength;
public final int alignment;
public final boolean componentsChanged;
StructurePackResult(int numComponents, int structureLength, int alignment,
boolean componentsChanged) {
this.numComponents = numComponents;
this.structureLength = structureLength;
this.alignment = alignment;
this.componentsChanged = componentsChanged;
}
}
private class AlignedGroupPacker {
private int nextOrdinal;
// We hang onto the imposed alignment and resulting offset for the last component
// since the update of a zero-length bitfield must be deferred since it can be influenced
// by the next component and we only want to update it once.
private int zeroAlignment; // imposed alignment on next component by zero bitfield
private int lastAlignment; // identifies last component alignment
// The groupOffset is used to identify start of zero-length bitfield as well
// as fixed-length groups when groupSameSizeOnly is true. Under other situations
// its value can not be relied upon. -1 value indicates no active group.
private int groupOffset = -1;
private InternalDataTypeComponent lastComponent;
private boolean componentsChanged;
void addComponent(InternalDataTypeComponent dataTypeComponent, boolean isLastComponent) {
if (!packComponent(dataTypeComponent)) {
initGroup(dataTypeComponent, isLastComponent);
}
lastComponent = dataTypeComponent;
++nextOrdinal;
}
int getLength() {
if (lastComponent == null) {
return 0;
}
int offset = 0;
if (groupOffset >= 0 && lastComponent.isBitFieldComponent() &&
bitFieldPacking.useMSConvention()) {
// skip beyond unused bits based upon allocation size
BitFieldDataType lastBitFieldDt = (BitFieldDataType) lastComponent.getDataType();
offset = groupOffset + lastBitFieldDt.getBaseTypeSize();
}
else {
offset = lastComponent.getOffset() + lastComponent.getLength();
if (!bitFieldPacking.useMSConvention() && lastComponent.isZeroBitFieldComponent()) {
// factor in trailing zero-length bitfield
BitFieldDataType bitfieldDt = (BitFieldDataType) lastComponent.getDataType();
int sizeAlignment = CompositeAlignmentHelper.getPackedAlignment(
dataOrganization, Composite.NOT_PACKING, bitfieldDt.getBaseDataType(),
bitfieldDt.getBaseTypeSize());
getBitFieldAlignment((BitFieldDataType) lastComponent.getDataType());
offset += DataOrganizationImpl.getPaddingSize(sizeAlignment, offset);
}
}
return offset;
}
private int getBitFieldTypeSize(InternalDataTypeComponent dataTypeComponent) {
DataType componentDt = dataTypeComponent.getDataType();
if (componentDt instanceof BitFieldDataType) {
return ((BitFieldDataType) componentDt).getBaseTypeSize();
}
throw new AssertException("expected bitfield component only");
}
private int getBitFieldAlignment(BitFieldDataType bitfieldDt) {
int packValue = structure.getPackingValue();
if (!bitFieldPacking.useMSConvention() && packValue != Composite.NOT_PACKING) {
// GCC always uses 1 when packing regardless of pack value
return 1;
}
return CompositeAlignmentHelper.getPackedAlignment(dataOrganization, packValue,
bitfieldDt.getBaseDataType(), bitfieldDt.getBaseTypeSize());
}
private boolean isIgnoredZeroBitField(BitFieldDataType zeroBitFieldDt) {
if (!zeroBitFieldDt.isZeroLengthField()) {
return false;
}
if (bitFieldPacking.useMSConvention()) {
// TODO: verify when :0 is first component
return lastComponent == null || !lastComponent.isBitFieldComponent();
}
return false;
}
private int getZeroBitFieldAlignment(BitFieldDataType zeroBitFieldDt,
boolean isLastComponent) {
if (isIgnoredZeroBitField(zeroBitFieldDt)) {
return -1;
}
if (!bitFieldPacking.isTypeAlignmentEnabled()) {
int zeroLengthBitFieldBoundary = bitFieldPacking.getZeroLengthBoundary();
if (zeroLengthBitFieldBoundary > 0) {
return zeroLengthBitFieldBoundary;
}
return 1;
}
int packValue = structure.getPackingValue();
if (!bitFieldPacking.useMSConvention() && !isLastComponent) {
// GCC ignores pack value for :0 bitfield alignment but considers it when
// passing alignment along to structure
packValue = Composite.NOT_PACKING;
}
return CompositeAlignmentHelper.getPackedAlignment(dataOrganization, packValue,
zeroBitFieldDt.getBaseDataType(), zeroBitFieldDt.getBaseTypeSize());
}
private void initGroup(InternalDataTypeComponent dataTypeComponent,
boolean isLastComponent) {
groupOffset = getLength();
lastAlignment = 1;
if (dataTypeComponent.isBitFieldComponent()) {
BitFieldDataType zeroBitFieldDt =
(BitFieldDataType) dataTypeComponent.getDataType();
if (dataTypeComponent.isZeroBitFieldComponent()) {
// An alignment of -1 indicates field is ignored
int alignment = getZeroBitFieldAlignment(zeroBitFieldDt, isLastComponent);
int zeroBitOffset = dataOrganization.isBigEndian() ? 7 : 0;
if (zeroBitFieldDt.getBitOffset() != zeroBitOffset ||
zeroBitFieldDt.getStorageSize() != 1) {
try {
BitFieldDataType packedBitFieldDt = new BitFieldDataType(
zeroBitFieldDt.getBaseDataType(), 0, zeroBitOffset, 1);
dataTypeComponent.setDataType(packedBitFieldDt);
}
catch (InvalidDataTypeException e) {
throw new AssertException("unexpected", e);
}
componentsChanged = true;
}
if (isLastComponent) {
// special handling of zero-length bitfield when it is last component,
// place on last byte within structure.
int offset = groupOffset;
int length = 1;
if (lastComponent != null) {
offset = groupOffset - 1; // lastComponent.getEndOffset();
}
updateComponent(dataTypeComponent, nextOrdinal, offset, length,
alignment > 0 ? alignment : 1);
groupOffset = -1;
}
else {
// Avoid conveying zero alignment onto structure
// Next component can influence alignment
zeroAlignment = alignment;
// NOTE: MSVC always conveys zero-length alignment
if (bitFieldPacking.useMSConvention()) {
lastAlignment = alignment;
}
// defer update of zero-length component and final determination of alignment.
}
}
else {
lastComponent = null; // first in allocation group
alignAndPackBitField(dataTypeComponent); // relies on groupOffset when lastComponent==null
}
}
else {
// pack non-bitfield
lastComponent = null; // first in allocation group
alignAndPackNonBitfieldComponent(dataTypeComponent, groupOffset);
}
}
/**
* Adjust lastComponent which must be a zero-length bitfield and its associated
* groupOffset based upon the adjusted alignment.
* @param ordinal component ordinal assignment
* @param minimumAlignment minimum alignment of component immediately after
* the zero-length component
*/
private void adjustZeroLengthBitField(int ordinal, int minimumAlignment) {
int minOffset = DataOrganizationImpl.getOffset(minimumAlignment, groupOffset);
int zeroAlignmentOffset = DataOrganizationImpl.getOffset(zeroAlignment, groupOffset);
// Determine component offset of zero-length bitfield and the component
// which immediately follows it.
if (minOffset >= zeroAlignmentOffset) {
// natural offset satisfies :0 alignment
groupOffset = minOffset;
}
else {
groupOffset = zeroAlignmentOffset;
}
updateComponent(lastComponent, ordinal, groupOffset, 1, minimumAlignment);
}
private boolean canPack(DataType dataType) {
if (dataType instanceof TypeDef) {
dataType = ((TypeDef) dataType).getBaseDataType();
}
if (dataType instanceof BitFieldDataType) {
return true;
}
if (dataType instanceof AbstractIntegerDataType) {
return true;
}
if (dataType instanceof Enum) {
return true;
}
return false;
}
private boolean packComponent(InternalDataTypeComponent dataTypeComponent) {
if (lastComponent == null || dataTypeComponent.isZeroBitFieldComponent() ||
!canPack(lastComponent.getDataType()) ||
!canPack(dataTypeComponent.getDataType())) {
return false; // can't pack incompatible types - start new group
}
if (dataTypeComponent.isBitFieldComponent()) {
if (!lastComponent.isZeroBitFieldComponent() && bitFieldPacking.useMSConvention()) {
if (!lastComponent.isBitFieldComponent()) {
return false; // can't pack bitfield with non-bitfield - start new group
}
if (getBitFieldTypeSize(dataTypeComponent) != getBitFieldTypeSize(
lastComponent)) {
return false; // bitfield base types differ in size - start new group
}
}
alignAndPackBitField(dataTypeComponent); // relies on lastComponent
return true;
}
if (!lastComponent.isZeroBitFieldComponent() && bitFieldPacking.useMSConvention()) {
return false; // start new group for non-bitfield
}
int offset;
if (lastComponent.isZeroBitFieldComponent()) {
offset = groupOffset;
}
else {
offset = lastComponent.getOffset() + lastComponent.getLength();
}
alignAndPackNonBitfieldComponent(dataTypeComponent, offset);
return true;
}
private void alignAndPackNonBitfieldComponent(InternalDataTypeComponent dataTypeComponent,
int minOffset) {
DataType componentDt = dataTypeComponent.getDataType();
int dtSize = componentDt.getLength();
if (dtSize <= 0) {
dtSize = dataTypeComponent.getLength();
}
int alignment = CompositeAlignmentHelper.getPackedAlignment(dataOrganization,
structure.getPackingValue(), componentDt, dtSize);
int offset;
if (lastComponent != null && lastComponent.isZeroBitFieldComponent()) {
// adjust group alignment and offset of zero-length component (properly aligns groupOffset)
adjustZeroLengthBitField(nextOrdinal - 1, alignment);
offset = groupOffset;
}
else {
offset = DataOrganizationImpl.getOffset(alignment, minOffset);
if (lastComponent == null) {
groupOffset = offset; // establish corrected group offset after alignment
}
}
updateComponent(dataTypeComponent, nextOrdinal, offset, dtSize, alignment);
}
private void alignAndPackBitField(InternalDataTypeComponent dataTypeComponent) {
BitFieldDataType bitfieldDt = (BitFieldDataType) dataTypeComponent.getDataType();
if (lastComponent != null && lastComponent.isZeroBitFieldComponent()) {
int alignment = bitFieldPacking.useMSConvention() ? getBitFieldAlignment(bitfieldDt)
: zeroAlignment;
adjustZeroLengthBitField(nextOrdinal - 1, alignment);
}
int offset;
int bitsConsumed;
// update lastAlignment to be conveyed onto structure alignment
int alignment = CompositeAlignmentHelper.getPackedAlignment(dataOrganization,
structure.getPackingValue(), bitfieldDt.getPrimitiveBaseDataType(),
bitfieldDt.getBaseTypeSize());
// Set conveyed alignment early since bitfield alignment may be reduced below
lastAlignment = Math.max(alignment, lastAlignment);
if (lastComponent == null) {
offset = DataOrganizationImpl.getOffset(alignment, groupOffset);
bitsConsumed = 0;
groupOffset = offset; // establish corrected group offset after alignment
}
else if (lastComponent.isZeroBitFieldComponent()) {
// - assume lastComponent (zero-length bitfield) has already been adjusted and updated
// - first bitfield following a :0 bitfield which has already been adjusted by packComponent
// - groupOffset contains aligned offset to be used
offset = groupOffset;
bitsConsumed = 0;
}
else {
// follow normal rule for aligning bitfield which may differ from the alignment
// imparted onto structure via lastAlignment
alignment = getBitFieldAlignment(bitfieldDt);
BitFieldDataType lastBitfieldDt = null;
if (lastComponent.isBitFieldComponent()) {
// assume lastComponent bit-field has already been packed and has correct bit-offset
lastBitfieldDt = (BitFieldDataType) lastComponent.getDataType();
offset = lastComponent.getEndOffset();
if (dataOrganization.isBigEndian()) {
// filled left-to-right
bitsConsumed = 8 - lastBitfieldDt.getBitOffset();
// bitsConsumed range: 1 to 8, where 8 indicates last byte fully consumed
}
else { // little-endian
// filled right-to-left (viewed from normalized form after byte-swap)
bitsConsumed =
(lastBitfieldDt.getBitSize() + lastBitfieldDt.getBitOffset()) % 8;
// bitsConsumed range: 0 to 7, where 0 indicates last byte fully consumed
}
if (bitsConsumed == 8 || bitsConsumed == 0) {
// last byte is fully consumed
bitsConsumed = 0;
++offset;
}
}
else {
// previous field is non-bitfield
offset = lastComponent.getOffset() + lastComponent.getLength();
bitsConsumed = 0;
}
int byteSize = (bitfieldDt.getBitSize() + bitsConsumed + 7) / 8;
int endOffset = offset + byteSize - 1;
if (offset % alignment != 0 || byteSize > bitfieldDt.getBaseTypeSize()) {
// offset is not an aligned offset (which may be OK when packing with lastComponent)
int alignedBaseOffset =
DataOrganizationImpl.getOffset(alignment, offset) - alignment;
if (endOffset >= alignedBaseOffset + bitfieldDt.getBaseTypeSize()) {
// skip ahead to next aligned offset
offset = DataOrganizationImpl.getOffset(alignment, offset + 1);
endOffset = offset + byteSize - 1;
bitsConsumed = 0;
}
}
// establish new groupOffset if necessary
if (groupOffset >= 0 && lastBitfieldDt != null &&
endOffset >= (groupOffset + lastBitfieldDt.getBaseTypeSize())) {
groupOffset = bitFieldPacking.useMSConvention() ? offset : -1;
}
}
int byteSize = setBitFieldDataType(dataTypeComponent, bitfieldDt, bitsConsumed);
updateComponent(dataTypeComponent, nextOrdinal, offset, byteSize, alignment);
}
private int setBitFieldDataType(InternalDataTypeComponent dataTypeComponent,
BitFieldDataType currentBitFieldDt, int bitsConsumed) {
int byteSize = (currentBitFieldDt.getBitSize() + bitsConsumed + 7) / 8;
int bitOffset;
if (dataOrganization.isBigEndian()) {
// filled left-to-right
bitOffset = (byteSize * 8) - currentBitFieldDt.getBitSize() - bitsConsumed;
}
else { // little-endian
// filled right-to-left (viewed from normalized form after byte-swap)
bitOffset = bitsConsumed;
}
if (bitOffset != currentBitFieldDt.getBitOffset() ||
byteSize != currentBitFieldDt.getStorageSize()) {
try {
BitFieldDataType packedBitFieldDt =
new BitFieldDataType(currentBitFieldDt.getBaseDataType(),
currentBitFieldDt.getDeclaredBitSize(), bitOffset, byteSize);
dataTypeComponent.setDataType(packedBitFieldDt);
}
catch (InvalidDataTypeException e) {
throw new AssertException("unexpected", e);
}
componentsChanged = true;
}
return byteSize;
}
private void updateComponent(InternalDataTypeComponent dataTypeComponent, int ordinal,
int offset, int length, int alignment) {
if (ordinal != dataTypeComponent.getOrdinal() ||
offset != dataTypeComponent.getOffset() ||
length != dataTypeComponent.getLength()) {
dataTypeComponent.update(ordinal, offset, length);
componentsChanged = true;
}
lastAlignment = Math.max(lastAlignment, alignment);
}
int getComponentAlignmentLCM(int allComponentsLCM) {
if (lastAlignment == 0) {
return lastAlignment;
}
// factor in pack value, which may have been ignored when aligning component
int alignment = lastAlignment;
int packValue = structure.getPackingValue();
if (packValue > 0 && alignment > packValue) {
alignment = packValue;
}
return DataOrganizationImpl.getLeastCommonMultiple(allComponentsLCM, alignment);
}
}
protected StructurePackResult pack() {
boolean componentsChanged = false;
int componentCount = 0;
int allComponentsLCM = 1;
AlignedGroupPacker packer = new AlignedGroupPacker();
// Remove any default components from list
Iterator<? extends InternalDataTypeComponent> componentIterator = components.iterator();
while (componentIterator.hasNext()) {
InternalDataTypeComponent dataTypeComponent = componentIterator.next();
DataType componentDt = dataTypeComponent.getDataType();
if (DataType.DEFAULT == componentDt) {
componentIterator.remove(); // remove default components.
componentsChanged = true;
}
++componentCount;
}
int index = 0;
for (InternalDataTypeComponent dataTypeComponent : components) {
boolean isLastComponent = (++index == componentCount);
packer.addComponent(dataTypeComponent, isLastComponent);
allComponentsLCM = packer.getComponentAlignmentLCM(allComponentsLCM);
}
int length = packer.getLength();
componentsChanged |= packer.componentsChanged;
DataTypeComponent flexibleArrayComponent = structure.getFlexibleArrayComponent();
if (flexibleArrayComponent != null) {
// account for flexible array type and any end of structure padding required
int componentAlignment = CompositeAlignmentHelper.getPackedAlignment(dataOrganization,
structure.getPackingValue(), flexibleArrayComponent);
length = DataOrganizationImpl.getOffset(componentAlignment, length);
allComponentsLCM =
DataOrganizationImpl.getLeastCommonMultiple(allComponentsLCM, componentAlignment);
}
int alignment = structure.getMinimumAlignment();
if (alignment < allComponentsLCM) {
alignment = allComponentsLCM;
}
if (length != 0) {
int padSize = DataOrganizationImpl.getPaddingSize(alignment, length);
if (padSize > 0) {
length += padSize;
}
}
return new StructurePackResult(componentCount, length, alignment, componentsChanged);
}
/**
* Perform structure component packing. Specified components may be updated to reflect
* packing (ordinal, offset, length and bit-field datatypes may be modified). The caller
* is responsible for updating structure length and component count based upon
* returned result. Component count is should only change if component
* list includes DEFAULT members which will be ignored.
* @param structure structure whose members are to be aligned/packed.
* @param components structure components (excludes any trailing flexible array).
* @return aligned packing result
*/
public static StructurePackResult packComponents(Structure structure,
List<? extends InternalDataTypeComponent> components) {
AlignedStructurePacker packer = new AlignedStructurePacker(structure, components);
return packer.pack();
}
}

View file

@ -169,7 +169,7 @@ public class ArrayDataType extends DataTypeImpl implements Array {
}
@Override
public void setName(String name) throws InvalidNameException, DuplicateNameException {
public void setName(String name) throws InvalidNameException {
// unsupported - ignore
}

View file

@ -0,0 +1,417 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.program.model.data;
import java.math.BigInteger;
import ghidra.docking.settings.Settings;
import ghidra.docking.settings.SettingsDefinition;
import ghidra.program.model.mem.MemBuffer;
import ghidra.program.model.scalar.Scalar;
import ghidra.util.exception.AssertException;
/**
* <code>BitFieldDataType</code> provides a means of defining a minimally sized bit-field
* for use within data structures. The length (i.e., storage size) of this datatype
* less than or equal to the base datatype size and will always be the smallest possible size
* to contain the bitfield and offset within the least significant byte containing the
* lsb of the bitfield.
*/
public class BitFieldDataType extends AbstractDataType {
private static final int MAX_BIT_LENGTH = 255;
private final DataType baseDataType; // bit-field definition data type which corresponds to baseType
private final int bitSize; // number of bits, reflects declaration which may exceed base type size
private final int effectiveBitSize; // number of bits constrained by size of base type
// The bitOffset is established during packing and reflects the right-shift amount within the
// normalized big-endian view of the allocated byte storage as defined by the corresponding
// composite DataTypeComponent.
private final int bitOffset; // indicates right-shift within big-endian view of component storage
private final int storageSize; // component storage size to which bitOffset applies
protected Settings defaultSettings;
/**
* Construct a bit-field type based upon a specified base type. The baseDataType will
* take precedence if specified. Either baseType or baseDatatype must be specified.
* @param baseDataType base data type (integer/enum type or typedef to same)
* @param bitSize size of bit-field expressed as number of bits
* @param bitOffset right shift factor within storage unit when viewed as a big-endian dd
* scalar value. Based upon minimal storage bitOffset should be in the range 0 to 7.
* @param storageSize minimal storage allocation to which bitOffset is applied or 0 to use
* minimum storage size.
* @throws InvalidDataTypeException
*/
// FIXME: Remove storage parameter (compute based upon bitSize and bitOffset)
protected BitFieldDataType(DataType baseDataType, int bitSize, int bitOffset, int storageSize)
throws InvalidDataTypeException {
super(CategoryPath.ROOT, baseDataType.getName() + ":" + bitSize,
baseDataType.getDataTypeManager());
checkBaseDataType(baseDataType);
if (bitSize < 0 || bitSize > MAX_BIT_LENGTH) {
throw new InvalidDataTypeException("unsupported bit size: " + bitSize);
}
if (bitOffset < 0 || bitOffset > 7) {
throw new InvalidDataTypeException("unsupported minimal bit offset: " + bitOffset);
}
this.baseDataType = baseDataType;
this.bitSize = bitSize;
this.bitOffset = bitOffset;
effectiveBitSize = getEffectiveBitSize(bitSize, this.baseDataType.getLength());
if (storageSize == 0) {
storageSize = getMinimumStorageSize(effectiveBitSize, bitOffset);
}
this.storageSize = storageSize;
checkStorage();
if (bitOffset < 0 || bitOffset > ((8 * storageSize) - effectiveBitSize)) {
throw new InvalidDataTypeException("invalid bit offset: " + bitOffset);
}
this.defaultSettings = this.baseDataType.getDefaultSettings();
}
/**
* Construct a bit-field type based upon a supported baseDataType.
* @param baseDataType a supported primitive integer data type or TypeDef to such a type.
* A deep clone of this type will be performed using the specified dataMgr.
* @param bitSize size of bit-field expressed as number of bits
* @throws InvalidDataTypeException if specified baseDataType is not permitted
*/
protected BitFieldDataType(DataType baseDataType, int bitSize) throws InvalidDataTypeException {
this(baseDataType, bitSize, 0, 0);
}
private void checkStorage() throws IllegalArgumentException {
int minimumStorageSize = getMinimumStorageSize(effectiveBitSize);
if (storageSize != minimumStorageSize && storageSize != ++minimumStorageSize) {
throw new IllegalArgumentException("minimal storage size required");
}
}
/**
* Determine if this bit-field has a zero length (i.e., alignment field)
* @return true if this bit-field has a zero length
*/
public boolean isZeroLengthField() {
return bitSize == 0;
}
/**
* Get the effective bit-size based upon the specified base type size. A bit size
* larger than the base type size will truncated to the base type size.
* @param declaredBitSize
* @param baseTypeByteSize
* @return effective bit-size
*/
public static int getEffectiveBitSize(int declaredBitSize, int baseTypeByteSize) {
return Math.min(8 * baseTypeByteSize, declaredBitSize);
}
/**
* Get the minimum storage size in bytes for a given size in bits.
* This does not consider the bit offset which may increase the required
* storage.
* @param bitSize number of bits within bitfield
* @return minimum storage size in bytes
*/
public static int getMinimumStorageSize(int bitSize) {
return getMinimumStorageSize(bitSize, 0);
}
/**
* Get the minimum storage size in bytes for a given size in bits with
* the specified bitOffset (lsb position within big endian storage)
* @param bitSize number of bits within bitfield
* @param bitOffset normalized bitfield offset within storage (lsb)
* @return minimum storage size in bytes
*/
public static int getMinimumStorageSize(int bitSize, int bitOffset) {
if (bitSize == 0) {
return 1;
}
return (bitSize + (bitOffset % 8) + 7) / 8;
}
/**
* Check a bitfield base datatype
* @param baseDataType bitfield base data type (Enum, AbstractIntegerDataType and derived TypeDefs permitted)
* @throws InvalidDataTypeException if baseDataType is invalid as a bitfield base type.
*/
public static void checkBaseDataType(DataType baseDataType) throws InvalidDataTypeException {
if (!isValidBaseDataType(baseDataType)) {
throw new InvalidDataTypeException(
"Unsupported base data type for bitfield: " + baseDataType.getName());
}
}
/**
* Check if a specified baseDataType is valid for use with a bitfield
* @param baseDataType bitfield base data type (Enum, AbstractIntegerDataType and derived TypeDefs permitted)
* @returns true if baseDataType is valid else false
*/
public static boolean isValidBaseDataType(DataType baseDataType) {
if (baseDataType instanceof TypeDef) {
baseDataType = ((TypeDef) baseDataType).getBaseDataType();
}
if (baseDataType instanceof Enum) {
return true;
}
if (baseDataType instanceof AbstractIntegerDataType) {
return true;
}
return false;
}
@Override
public void addParent(DataType dt) {
if ((baseDataType instanceof TypeDef) || (baseDataType instanceof Enum)) {
baseDataType.addParent(dt); // add composite as parent of baseDataType
}
}
/**
* Get the size of the base data type based upon the associated data organization.
* @return base type size
*/
public int getBaseTypeSize() {
return baseDataType.getLength();
}
/**
* Get the packing storage size in bytes associated with this bit-field which may be
* larger than the base type associated with the fields original definition.
* @return packing storage size in bytes
*/
public int getStorageSize() {
return storageSize;
}
/**
* Get the effective bit size of this bit-field which may not exceed the size of the
* base datatype.
* @return bit size
*/
public int getBitSize() {
return effectiveBitSize;
}
/**
* Get the declared bit size of this bit-field which may be larger than the effective
* size which could be truncated.
* @return bit size as defined by the field construction/declaration.
*/
public int getDeclaredBitSize() {
return bitSize;
}
/**
* Get the bit offset of the least-significant bit relative to bit-0 of the
* base datatype (i.e., least significant bit). This corresponds to the
* right-shift amount within the base data type when viewed as a big-endian value.
* @return bit offset
*/
public int getBitOffset() {
return bitOffset;
}
/**
* Get the base datatype associated with this bit-field
* (e.g., int, long, etc., or TypeDef to supported base type)
* @return base data type
*/
public DataType getBaseDataType() {
return baseDataType;
}
/**
* Get the base datatype associated with this bit-field
* (e.g., int, long, etc., or TypeDef to supported base type)
* @return base data type
*/
public AbstractIntegerDataType getPrimitiveBaseDataType() {
// assumes proper enforcement during construction
DataType dt = baseDataType;
if (baseDataType instanceof TypeDef) {
dt = ((TypeDef) baseDataType).getBaseDataType();
}
if (dt instanceof Enum) {
// TODO: uncertain if we should use signed or unsigned, although size
// is most important
dt = AbstractIntegerDataType.getUnsignedDataType(((Enum) dt).getLength(), dataMgr);
}
return (AbstractIntegerDataType) dt;
}
/**
* Gets a list of all the settingsDefinitions used by this datatype.
* @return a list of the settingsDefinitions used by this datatype.
*/
@Override
public final SettingsDefinition[] getSettingsDefinitions() {
return baseDataType.getSettingsDefinitions();
}
@Override
public final boolean isEquivalent(DataType dt) {
if (dt == this) {
return true;
}
if (dt == null) {
return false;
}
if (!(dt instanceof BitFieldDataType)) {
return false;
}
BitFieldDataType otherBitField = (BitFieldDataType) dt;
// Specific packing and use of typedef ignored for equivalence check
return otherBitField.bitSize == bitSize &&
baseDataType.isEquivalent(otherBitField.baseDataType);
}
@Override
public final int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + baseDataType.hashCode();
result = prime * result + bitOffset;
result = prime * result + bitSize;
return result;
}
@Override
public final boolean equals(Object obj) {
if (!(obj instanceof BitFieldDataType)) {
return false;
}
BitFieldDataType otherDt = (BitFieldDataType) obj;
return (otherDt.getDataTypeManager() == getDataTypeManager()) && isEquivalent(otherDt) &&
(bitOffset == otherDt.bitOffset) && (storageSize == otherDt.storageSize) &&
baseDataType.equals(otherDt.baseDataType);
}
@Override
public Settings getDefaultSettings() {
return defaultSettings;
}
/**
* Returns a clone of this built-in DataType
* @see ghidra.program.model.data.DataType#copy(ghidra.program.model.data.DataTypeManager)
*/
@Override
public final DataType copy(DataTypeManager dtm) {
return clone(dtm);
}
@Override
public BitFieldDataType clone(DataTypeManager dtm) {
if (dtm == dataMgr) {
return this;
}
try {
return new BitFieldDataType(baseDataType.clone(dtm), bitSize, bitOffset, storageSize);
}
catch (InvalidDataTypeException e) {
throw new AssertException("unexpected", e);
}
}
@Override
public int getLength() {
return storageSize;
}
@Override
public String getDescription() {
return getName() + " BitField";
}
@Override
public Object getValue(MemBuffer buf, Settings settings, int length) {
if (effectiveBitSize == 0) {
return new Scalar(0, 0);
}
BigInteger big = getBigIntegerValue(buf, settings);
if (big == null) {
return null;
}
if (effectiveBitSize <= 64) {
return new Scalar(effectiveBitSize, big.longValue(),
getPrimitiveBaseDataType().isSigned());
}
return big;
}
public BigInteger getBigIntegerValue(MemBuffer buf, Settings settings) {
if (effectiveBitSize == 0) {
return BigInteger.ZERO;
}
try {
BigInteger big = buf.getBigInteger(0, storageSize, false);
BigInteger pow = BigInteger.valueOf(2).pow(effectiveBitSize);
BigInteger mask = pow.subtract(BigInteger.ONE);
big = big.shiftRight(bitOffset).and(mask);
if (big.testBit(effectiveBitSize - 1)) {
big = big.subtract(pow);
}
return big;
}
catch (Exception e) {
// ignore
}
return null;
}
@Override
public Class<?> getValueClass(Settings settings) {
return baseDataType.getValueClass(settings);
}
@Override
public String getRepresentation(MemBuffer buf, Settings settings, int length) {
if (bitSize == 0) {
return "";
}
BigInteger big = getBigIntegerValue(buf, settings);
if (big == null) {
return "??";
}
DataType dt = baseDataType;
if (dt instanceof TypeDef) {
dt = ((TypeDef) dt).getBaseDataType();
}
if (dt instanceof Enum) {
return ((Enum) dt).getRepresentation(big, settings, effectiveBitSize);
}
return ((AbstractIntegerDataType) dt).getRepresentation(big, settings, effectiveBitSize);
}
@Override
public void setDefaultSettings(Settings settings) {
this.defaultSettings = settings;
}
@Override
public int getAlignment() {
return baseDataType.getAlignment();
}
@Override
public String toString() {
return getDisplayName() + "(storage:" + storageSize + ",bitOffset:" + bitOffset + ")";
}
}

View file

@ -0,0 +1,47 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.program.model.data;
public interface BitFieldPacking {
/**
* Control if the alignment and packing of bit-fields follows MSVC conventions.
* When this is enabled it takes precedence over all other bitfield packing controls.
* @return true if MSVC packing conventions are used, else false (e.g., GNU conventions apply).
*/
boolean useMSConvention();
/**
* Control whether the alignment of bit-field types is respected when laying out structures.
* Corresponds to PCC_BITFIELD_TYPE_MATTERS in GCC.
* @return true when the alignment of the bit-field type should be used to impact the
* alignment of the containing structure, and ensure that individual bit-fields will not
* straddle an alignment boundary.
*/
boolean isTypeAlignmentEnabled();
/**
* A non-zero value indicates the fixed alignment size for bit-fields which follow
* a zero-length bitfield if greater than a bitfields base type normal alignment.
* Corresponds to EMPTY_FIELD_BOUNDARY in GCC.
* This value is only used when {@link #isTypeAlignmentEnabled()} returns false
* and {@link #isZeroLengthAlignmentEnabled()} returns true.
* @return fixed alignment size as number of bytes for a bit-field which follows
* a zero-length bit-field
*/
int getZeroLengthBoundary();
}

View file

@ -0,0 +1,68 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.program.model.data;
public class BitFieldPackingImpl implements BitFieldPacking {
private boolean useMSConvention = false;
private boolean typeAlignmentEnabled = true;
private int zeroLengthBoundary = 0;
@Override
public boolean useMSConvention() {
return useMSConvention;
}
@Override
public boolean isTypeAlignmentEnabled() {
return useMSConvention || typeAlignmentEnabled; // same as PCC_BITFIELD_TYPE_MATTERS
}
@Override
public int getZeroLengthBoundary() {
return useMSConvention ? 0 : zeroLengthBoundary;
}
/**
* Control if the alignment and packing of bit-fields follows MSVC conventions.
* When this is enabled it takes precedence over all other bitfield packing controls.
* @param useMSConvention true if MSVC packing conventions are used, else false (e.g., GNU conventions apply).
*/
public void setUseMSConvention(boolean useMSConvention) {
this.useMSConvention = useMSConvention;
}
/**
* Control whether the alignment of bit-field types is respected when laying out structures.
* Corresponds to PCC_BITFIELD_TYPE_MATTERS in gcc.
* @param typeAlignmentEnabled true if the alignment of the bit-field type should be used
* to impact the alignment of the containing structure, and ensure that individual bit-fields
* will not straddle an alignment boundary.
*/
public void setTypeAlignmentEnabled(boolean typeAlignmentEnabled) {
this.typeAlignmentEnabled = typeAlignmentEnabled;
}
/**
* Indicate a fixed alignment size in bytes which should be used for zero-length bit-fields.
* @param zeroLengthBoundary fixed alignment size as number of bytes for a bit-field
* which follows a zero-length bit-field. A value of 0 causes zero-length type size to be used.
*/
public void setZeroLengthBoundary(int zeroLengthBoundary) {
this.zeroLengthBoundary = zeroLengthBoundary;
}
}

View file

@ -30,27 +30,28 @@ import ghidra.util.exception.DuplicateNameException;
* searched for in the classpath and added automatically to the available
* data types in the data type manager.
*/
public abstract class BuiltIn extends DataTypeImpl implements BuiltInDataType {
private static SettingsDefinition[] STANDARD_SETTINGS_DEFINITIONS = new SettingsDefinition[] {
MutabilitySettingsDefinition.DEF
};
public abstract class BuiltIn extends DataTypeImpl implements BuiltInDataType {
private static SettingsDefinition[] STANDARD_SETTINGS_DEFINITIONS =
new SettingsDefinition[] { MutabilitySettingsDefinition.DEF };
private SettingsDefinition[] settingDefs;
public BuiltIn(CategoryPath path, String name, DataTypeManager dataMgr) {
// Change any category path so that it is under the built in category.
super(path==null ? CategoryPath.ROOT : path, name, null, BuiltInSourceArchive.INSTANCE, NO_SOURCE_SYNC_TIME, NO_LAST_CHANGE_TIME, dataMgr);
super(path == null ? CategoryPath.ROOT : path, name, null, BuiltInSourceArchive.INSTANCE,
NO_SOURCE_SYNC_TIME, NO_LAST_CHANGE_TIME, dataMgr);
}
/**
* Returns a clone of this built-in DataType
* @see ghidra.program.model.data.DataType#copy(ghidra.program.model.data.DataTypeManager)
*/
@Override
public final DataType copy(DataTypeManager dtm) {
return clone(dtm);
}
/**
* Gets a list of all the settingsDefinitions used by this datatype.
* @return a list of the settingsDefinitions used by this datatype.
@ -82,19 +83,19 @@ public abstract class BuiltIn extends DataTypeImpl implements BuiltInDataType {
}
return getClass() == dt.getClass();
}
@Override
public void dataTypeSizeChanged(DataType dt) {
// Default implementation does nothing.
}
@Override
public final void setCategoryPath(CategoryPath path) throws DuplicateNameException {
// Default implementation does nothing.
}
@Override
public final void setName(String name) throws InvalidNameException, DuplicateNameException {
public final void setName(String name) throws InvalidNameException {
// Default implementation does nothing.
}
@ -105,12 +106,12 @@ public abstract class BuiltIn extends DataTypeImpl implements BuiltInDataType {
}
@Override
public final void addParent(DataType dt) {
public final void addParent(DataType dt) {
// Default implementation does nothing.
}
@Override
public final void removeParent(DataType dt) {
public final void removeParent(DataType dt) {
// Default implementation does nothing.
}
@ -118,7 +119,7 @@ public abstract class BuiltIn extends DataTypeImpl implements BuiltInDataType {
public void dataTypeNameChanged(DataType dt, String oldName) {
// Default implementation does nothing.
}
@Override
public void dataTypeReplaced(DataType oldDt, DataType newDt) {
// Default implementation does nothing.
@ -137,12 +138,12 @@ public abstract class BuiltIn extends DataTypeImpl implements BuiltInDataType {
// dt.dataMgr = dataManager;
// return dt;
// }
@Override
public boolean dependsOn(DataType dt) {
return false;
}
@Override
public UniversalID getUniversalID() {
return null;
@ -163,25 +164,29 @@ public abstract class BuiltIn extends DataTypeImpl implements BuiltInDataType {
}
protected String getCTypeDeclaration(String typeName, String ctypeName, boolean useDefine) {
return useDefine ?
"#define " + typeName + " " + ctypeName :
"typedef " + ctypeName + " " + typeName + ";";
return useDefine ? "#define " + typeName + " " + ctypeName
: "typedef " + ctypeName + " " + typeName + ";";
}
protected String getCTypeDeclaration(String typeName, int typeLen, boolean signed, DataOrganization dataOrganization, boolean useDefine) {
return getCTypeDeclaration(typeName, dataOrganization.getIntegerCTypeApproximation(typeLen, signed), useDefine);
protected String getCTypeDeclaration(String typeName, int typeLen, boolean signed,
DataOrganization dataOrganization, boolean useDefine) {
return getCTypeDeclaration(typeName,
dataOrganization.getIntegerCTypeApproximation(typeLen, signed), useDefine);
}
protected String getCTypeDeclaration(BuiltIn dt, boolean signed, DataOrganization dataOrganization, boolean useDefine) {
return getCTypeDeclaration(dt.getDecompilerDisplayName(DecompilerLanguage.C_LANGUAGE), dataOrganization.getIntegerCTypeApproximation(dt.getLength(), signed), useDefine);
protected String getCTypeDeclaration(BuiltIn dt, boolean signed,
DataOrganization dataOrganization, boolean useDefine) {
return getCTypeDeclaration(dt.getDecompilerDisplayName(DecompilerLanguage.C_LANGUAGE),
dataOrganization.getIntegerCTypeApproximation(dt.getLength(), signed), useDefine);
}
/**
* Returns null for FactoryDataType (which should never be used) and Dynamic types which should
* generally be replaced by a primitive array (e.g., char[5]) or, a primitive pointer (e.g., char *).
* For other types an appropriately sized unsigned integer typedef is returned.
* @see ghidra.program.model.data.BuiltInDataType#getCTypeDeclaration(ghidra.program.model.data.DataOrganization)
*/
@Override
public String getCTypeDeclaration(DataOrganization dataOrganization) {
if ((this instanceof Dynamic) || (this instanceof FactoryDataType)) {
return null;

View file

@ -35,10 +35,12 @@ public class ByteDataType extends AbstractIntegerDataType {
super("byte", false, dtm);
}
@Override
public String getDescription() {
return "Unsigned Byte (db)";
}
@Override
public int getLength() {
return 1;
}
@ -56,11 +58,12 @@ public class ByteDataType extends AbstractIntegerDataType {
}
@Override
public DataType getOppositeSignednessDataType() {
return SignedByteDataType.dataType;
public SignedByteDataType getOppositeSignednessDataType() {
return SignedByteDataType.dataType.clone(getDataTypeManager());
}
public DataType clone(DataTypeManager dtm) {
@Override
public ByteDataType clone(DataTypeManager dtm) {
if (dtm == getDataTypeManager()) {
return this;
}

View file

@ -138,7 +138,10 @@ public class CharDataType extends AbstractIntegerDataType implements DataTypeWit
}
@Override
public DataType clone(DataTypeManager dtm) {
public CharDataType clone(DataTypeManager dtm) {
if (dtm == getDataTypeManager()) {
return this;
}
return new CharDataType(dtm);
}
@ -176,8 +179,9 @@ public class CharDataType extends AbstractIntegerDataType implements DataTypeWit
}
@Override
public DataType getOppositeSignednessDataType() {
return isSigned() ? UnsignedCharDataType.dataType : SignedCharDataType.dataType;
public CharDataType getOppositeSignednessDataType() {
return isSigned() ? UnsignedCharDataType.dataType.clone(getDataTypeManager())
: SignedCharDataType.dataType.clone(getDataTypeManager());
}
@Override

View file

@ -15,8 +15,6 @@
*/
package ghidra.program.model.data;
import ghidra.util.exception.InvalidInputException;
/**
* Interface for common methods in Structure and Union
*/
@ -95,7 +93,8 @@ public interface Composite extends DataType {
public abstract DataTypeComponent[] getComponents();
/**
* Adds a new datatype to the end of this composite.
* 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.
* @param dataType the datatype to add.
* @return the DataTypeComponent created.
* @throws IllegalArgumentException if the specified data type is not
@ -106,21 +105,24 @@ public interface Composite extends DataType {
public DataTypeComponent add(DataType dataType);
/**
* Adds a new datatype to the end of this composite.
* 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 dynamic dataTypes such as
* strings whose length must be specified.
* @param dataType the datatype to add.
* @param length the length to associate with the datatype.
* For fixed length types a length &lt;= 0 will use the length of the resolved dataType.
* @return the componentDataType created.
* @throws IllegalArgumentException if the dataType.getLength() is positive
* and does not match the given length parameter.
* @throws IllegalArgumentException if the specified data type is not
* allowed to be added to this composite data type.
* allowed to be added to this composite data type or an invalid length
* is specified.
* 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);
/**
* Adds a new datatype to the end of this composite.
* 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.
* @param dataType the datatype to add.
* @param name the field name to associate with this component.
* @param comment the comment to associate with this component.
@ -133,16 +135,34 @@ public interface Composite extends DataType {
public DataTypeComponent add(DataType dataType, String name, String comment);
/**
* Adds a new datatype to the end of this composite.
* Adds a new bitfield to the end of this composite. This method is intended
* to be used with aligned structures/unions only where the bitfield will be
* appropriately packed. The minimum storage storage byte size will be applied.
* It will not provide useful results within unaligned composites.
* @param baseDataType the bitfield base datatype (certain restrictions apply).
* @param bitSize the bitfield size in bits
* @param componentName the field name to associate with this component.
* @param comment the comment to associate with this component.
* @return the componentDataType created whose associated data type will
* be BitFieldDataType.
* @throws InvalidDataTypeException if the specified data type is
* not a valid base type for bitfields.
*/
public DataTypeComponent addBitField(DataType baseDataType, int bitSize, String componentName,
String comment) throws InvalidDataTypeException;
/**
* 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 dynamic dataTypes such as
* strings whose length must be specified.
* @param dataType the datatype to add.
* @param length the length to associate with the datatype.
* For fixed length types a length &lt;= 0 will use the length of the resolved dataType.
* @param name the field name to associate with this component.
* @param comment the comment to associate with this component.
* @return the componentDataType created.
* @throws IllegalArgumentException if the dataType.getLength() is positive
* and does not match the given length parameter.
* @throws IllegalArgumentException if the specified data type is not
* allowed to be added to this composite data type.
* allowed to be added to this composite data type or an invalid length is specified.
* For example, suppose dt1 contains dt2. Therefore it is not valid
* to add dt1 to dt2 since this would cause a cyclic dependency.
*/
@ -159,6 +179,7 @@ public interface Composite extends DataType {
* allowed to be inserted into this composite data type.
* For example, suppose dt1 contains dt2. Therefore it is not valid
* to insert dt1 to dt2 since this would cause a cyclic dependency.
* @throws ArrayIndexOutOfBoundsException if component ordinal is out of bounds
*/
public DataTypeComponent insert(int ordinal, DataType dataType);
@ -169,16 +190,55 @@ public interface Composite extends DataType {
* @param ordinal the ordinal where the new datatype is to be inserted.
* @param dataType the datatype to insert.
* @param length the length to associate with the datatype.
* For fixed length types a length &lt;= 0 will use the length of the resolved dataType.
* @return the componentDataType created.
* @throws IllegalArgumentException if the dataType.getLength() is positive
* and does not match the given length parameter.
* @throws IllegalArgumentException if the specified data type is not
* allowed to be inserted into this composite data type.
* allowed to be inserted into this composite data type or an invalid
* length is specified.
* For example, suppose dt1 contains dt2. Therefore it is not valid
* to insert dt1 to dt2 since this would cause a cyclic dependency.
* @throws ArrayIndexOutOfBoundsException if component ordinal is out of bounds
*/
public DataTypeComponent insert(int ordinal, DataType dataType, int length);
/**
* Inserts a new bitfield at the specified ordinal position in this composite.
* Within an aligned composites the specified byteWidth and bitOffset will be ignored
* while bitOffset is always ignored for unions.
* The component length will be computed based upon the specified parameters and will
* be reduced from byteWidth to its minimal size for the new component.
* <p>
* For unaligned structures, a component shift will only occur if the bitfield placement
* conflicts with another component. If no conflict occurs, the bitfield will be placed
* at the specified location consuming any DEFAULT components as needed. When a conflict
* does occur a shift will be performed at the ordinal position based upon the specified
* byteWidth. When located onto existing bitfields they will be packed together
* provided they do not conflict, otherwise the conflict rule above applies.
* <p>
* Supported packing for little-endian fills lsb first, whereas big-endian fills msb first.
* Insertion behavior may not work as expected if packing rules differ from this.
* @param ordinal the ordinal where the new datatype is to be inserted.
* @param byteWidth the storage unit width which contains the bitfield. Must be large
* enough to contain the specified bitSize and corresponding bitOffset. The actual
* component size used will be recomputed during insertion.
* @param bitOffset corresponds to the bitfield left-shift amount with the storage
* unit when viewed as big-endian. The final offset may be reduced based upon
* the minimal storage size determined during insertion.
* @param baseDataType the bitfield base datatype (certain restrictions apply).
* @param bitSize the bitfield size in bits
* @param componentName the field name to associate with this component.
* @param comment the comment to associate with this component.
* @return the componentDataType created whose associated data type will
* be BitFieldDataType.
* @throws InvalidDataTypeException if the specified data type is
* not a valid base type for bitfields.
* @throws ArrayIndexOutOfBoundsException if ordinal is less than 0 or greater than the
* current number of components.
*/
public DataTypeComponent insertBitField(int ordinal, int byteWidth, int bitOffset,
DataType baseDataType, int bitSize, String componentName, String comment)
throws InvalidDataTypeException, ArrayIndexOutOfBoundsException;
/**
* Inserts a new datatype at the specified ordinal position in this composite.
* <BR>Note: For an aligned structure the ordinal position will get adjusted
@ -186,15 +246,16 @@ public interface Composite extends DataType {
* @param ordinal the ordinal where the new datatype is to be inserted.
* @param dataType the datatype to insert.
* @param length the length to associate with the datatype.
* For fixed length types a length &lt;= 0 will use the length of the resolved dataType.
* @param name the field name to associate with this component.
* @param comment the comment to associate with this component.
* @return the componentDataType created.
* @throws IllegalArgumentException if the dataType.getLength() is positive
* and does not match the given length parameter.
* @throws IllegalArgumentException if the specified data type is not
* allowed to be inserted into this composite data type.
* allowed to be inserted into this composite data type or an invalid length
* is specified.
* For example, suppose dt1 contains dt2. Therefore it is not valid
* to insert dt1 to dt2 since this would cause a cyclic dependency.
* @throws ArrayIndexOutOfBoundsException if component ordinal is out of bounds
*/
public DataTypeComponent insert(int ordinal, DataType dataType, int length, String name,
String comment);
@ -204,14 +265,18 @@ public interface Composite extends DataType {
* <BR>Note: For an aligned structure the delete will have no effect if the
* ordinal position is a component that provides alignment padding.
* @param ordinal the ordinal of the component to be deleted.
* @throws ArrayIndexOutOfBoundsException if component ordinal is out of bounds
*/
public void delete(int ordinal);
/**
* Deletes the components at the given ordinal positions.
* <BR>Note: For an aligned structure the delete will have no effect if the
* <BR>Note 1: For an aligned structure the delete will have no effect if the
* ordinal position is a component that provides alignment padding.
* <BR>Note 2: Removal of bitfields from an unaligned structure will
* not shift other components with vacated bytes reverting to undefined.
* @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);
@ -271,10 +336,10 @@ public interface Composite extends DataType {
* become an internally aligned data type.
* <br>Note: If a component's data type has a specific external alignment, it will
* override this value if necessary.
* @param packingValue the new packing value or 0NOT_PACKING.
* @throws InvalidInputException if the packingValue isn't valid.
* @param packingValue the new packing value or 0 for NOT_PACKING.
* A negative value will be treated the same as 0.
*/
public void setPackingValue(int packingValue) throws InvalidInputException;
public void setPackingValue(int packingValue);
/**
* Get the external alignment (a minimum alignment) for this DataType.
@ -292,9 +357,9 @@ public interface Composite extends DataType {
* of the alignment. Calling this method will cause the data type to
* become an internally aligned data type.
* @param minimumAlignment the external (minimum) alignment for this DataType.
* @throws InvalidInputException if the external alignment isn't valid.
* Any value less than 1 will revert to default alignment.
*/
public void setMinimumAlignment(int minimumAlignment) throws InvalidInputException;
public void setMinimumAlignment(int minimumAlignment);
/**
* Sets this data type's external (minimum) alignment to the default alignment. This data type's
@ -326,4 +391,13 @@ public interface Composite extends DataType {
*/
public boolean isMachineAligned();
/**
* Get the bitfield packing information associated with the underlying
* data organization.
* @return bitfield packing information
*/
public default BitFieldPacking getBitFieldPacking() {
return getDataOrganization().getBitFieldPacking();
}
}

View file

@ -0,0 +1,143 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.program.model.data;
public class CompositeAlignmentHelper {
private static int getImpartedAlignment(DataOrganization dataOrganization, int packingAlignment,
DataTypeComponent dataTypeComponent) {
// FIXME: try to eliminate this method.
// DataType componentDt = dataTypeComponent.getDataType();
//
// if (componentDt instanceof BitFieldDataType) {
// BitFieldPacking bitFieldPacking = dataOrganization.getBitFieldPacking();
// if (!bitFieldPacking.isTypeAlignmentEnabled() ||
// isBitFieldPackingEnabled(dataOrganization, packingAlignment)) {
// return 0;
// }
// BitFieldDataType bitFieldDt = (BitFieldDataType) componentDt;
// // zero-length bitfield assumed not to influence composite alignment, only component alignment
// if (!bitFieldPacking.zeroLengthAffectsContainerAlignment() &&
// bitFieldDt.getBitSize() == 0) {
// return 0;
// }
// // largest bit-field base-type will provide composite alignment constraint
// return getPackedAlignment(dataOrganization, packingAlignment,
// bitFieldDt.getBaseDataType(), bitFieldDt.getBaseTypeSize());
// }
return CompositeAlignmentHelper.getPackedAlignment(dataOrganization, packingAlignment,
dataTypeComponent);
}
private static int getCompositeAlignmentMultiple(DataOrganization dataOrganization,
Composite composite) {
int allComponentsLCM = 1;
int packingAlignment = composite.getPackingValue();
DataTypeComponent[] dataTypeComponents = composite.getComponents();
for (DataTypeComponent dataTypeComponent : dataTypeComponents) {
int impartedAlignment = CompositeAlignmentHelper.getPackedAlignment(dataOrganization,
packingAlignment, dataTypeComponent);
if (impartedAlignment != 0) {
allComponentsLCM = DataOrganizationImpl.getLeastCommonMultiple(allComponentsLCM,
impartedAlignment);
}
}
if (composite instanceof Structure) {
Structure struct = (Structure) composite;
DataTypeComponent flexibleArrayComponent = struct.getFlexibleArrayComponent();
if (flexibleArrayComponent != null) {
allComponentsLCM = getComponentAlignmentLCM(dataOrganization, allComponentsLCM,
packingAlignment, flexibleArrayComponent);
}
}
return allComponentsLCM;
}
private static int getComponentAlignmentLCM(DataOrganization dataOrganization,
int allComponentsLCM, int packingValue, DataTypeComponent component) {
int componentAlignment = getPackedAlignment(dataOrganization, packingValue, component);
allComponentsLCM =
DataOrganizationImpl.getLeastCommonMultiple(allComponentsLCM, componentAlignment);
return allComponentsLCM;
}
public static int getPackedAlignment(DataOrganization dataOrganization, int packingValue,
DataTypeComponent component) {
if (component.isZeroBitFieldComponent() && (component.getParent() instanceof Union) &&
!dataOrganization.getBitFieldPacking().useMSConvention()) {
// Zero-length bitfields ignored within unions for non-MSVC cases
return 0;
}
DataType componentDt = component.getDataType();
int dtSize = componentDt.getLength();
if (dtSize <= 0) {
dtSize = component.getLength();
}
return getPackedAlignment(dataOrganization, packingValue, componentDt, dtSize);
}
private static int getPackedAlignment(int componentAlignment, int forcedAlignment,
int packingAlignment) {
// Only do packing if we are not forcing an alignment.
int alignment = componentAlignment;
if (packingAlignment != Composite.NOT_PACKING) { // TODO Should this be packingValue > 0?
if (forcedAlignment > packingAlignment) {
alignment = forcedAlignment;
}
else if (alignment > packingAlignment) {
alignment = packingAlignment;
}
}
return alignment;
}
public static int getPackedAlignment(DataOrganization dataOrganization, int packingAlignment,
DataType componentDt, int dtSize) {
int componentAlignment = dataOrganization.getAlignment(componentDt, dtSize);
int componentForcedAlignment = dataOrganization.getForcedAlignment(componentDt);
boolean componentForcingAlignment = componentForcedAlignment > 0;
if (componentForcingAlignment) {
componentAlignment = DataOrganizationImpl.getLeastCommonMultiple(componentAlignment,
componentForcedAlignment);
}
return getPackedAlignment(componentAlignment, componentForcedAlignment, packingAlignment);
}
public static int getAlignment(DataOrganization dataOrganization, Composite dataType) {
// TODO: goal is to eliminate this method in favor of pack once and remember alignment
if (!dataType.isInternallyAligned()) {
return 1; // Unaligned
}
int lcm = getCompositeAlignmentMultiple(dataOrganization, dataType);
int minimumAlignment = dataType.getMinimumAlignment();
if ((minimumAlignment != Composite.DEFAULT_ALIGNMENT_VALUE) &&
(lcm % minimumAlignment != 0)) {
lcm = DataOrganizationImpl.getLeastCommonMultiple(lcm, minimumAlignment);
}
int absoluteMaxAlignment = dataOrganization.getAbsoluteMaxAlignment();
return ((absoluteMaxAlignment == 0) || (lcm < absoluteMaxAlignment)) ? lcm
: absoluteMaxAlignment;
}
}

View file

@ -21,6 +21,7 @@ import ghidra.program.database.data.DataTypeUtilities;
import ghidra.program.model.mem.MemBuffer;
import ghidra.util.InvalidNameException;
import ghidra.util.UniversalID;
import ghidra.util.exception.AssertException;
import ghidra.util.exception.NotYetImplementedException;
/**
@ -34,7 +35,7 @@ public abstract class CompositeDataTypeImpl extends GenericDataType implements C
// subtle errors - One I know of is in the StructureDataType
// copyComponent method. It has built in assumptions about this.
protected AlignmentType currentAlignment = AlignmentType.DEFAULT_ALIGNED;
protected AlignmentType alignmentType = AlignmentType.DEFAULT_ALIGNED;
protected int packingValue = NOT_PACKING;
protected int externalAlignment = DEFAULT_ALIGNMENT_VALUE;
@ -58,6 +59,34 @@ public abstract class CompositeDataTypeImpl extends GenericDataType implements C
description = "";
}
/**
* 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 then 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.
* @return preferred component length
*/
protected int getPreferredComponentLength(DataType dataType, int length) {
if ((isInternallyAligned() || (this instanceof Union)) && !(dataType instanceof Dynamic)) {
length = -1; // force use of datatype size
}
int dtLength = dataType.getLength();
if (length <= 0) {
length = dtLength;
}
else if (dtLength > 0 && dtLength < length) {
length = dtLength;
}
if (length <= 0) {
throw new IllegalArgumentException("Positive length must be specified for " +
dataType.getDisplayName() + " component");
}
return length;
}
@Override
public boolean isDynamicallySized() {
return isInternallyAligned();
@ -77,6 +106,7 @@ public abstract class CompositeDataTypeImpl extends GenericDataType implements C
* data type.
*/
protected void checkAncestry(DataType dataType) {
// TODO: cyclic checks are easily bypassed by renaming multiple composite instances
if (this.equals(dataType)) {
throw new IllegalArgumentException(
"Data type " + getDisplayName() + " can't contain itself.");
@ -94,6 +124,10 @@ public abstract class CompositeDataTypeImpl extends GenericDataType implements C
* @throws IllegalArgumentException if the data type is invalid.
*/
protected void validateDataType(DataType dataType) {
if (isInternallyAligned() && dataType == DataType.DEFAULT) {
throw new IllegalArgumentException(
"The DEFAULT data type is not allowed in an aligned composite data type.");
}
if (dataType instanceof FactoryDataType) {
throw new IllegalArgumentException("The \"" + dataType.getName() +
"\" data type is not allowed in a composite data type.");
@ -108,9 +142,56 @@ public abstract class CompositeDataTypeImpl extends GenericDataType implements C
}
@Override
public DataTypeComponent add(DataType dataType) {
dataType = dataType.clone(getDataTypeManager());
return add(dataType, dataType.getLength(), null, null);
public DataTypeComponent addBitField(DataType baseDataType, int bitSize, String componentName,
String comment) throws InvalidDataTypeException {
BitFieldDataType.checkBaseDataType(baseDataType);
baseDataType = baseDataType.clone(getDataTypeManager());
BitFieldDataType bitFieldDt = new BitFieldDataType(baseDataType, bitSize);
return add(bitFieldDt, bitFieldDt.getStorageSize(), componentName, comment);
}
/**
* 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 new datatype is not
*/
protected boolean updateBitFieldDataType(DataTypeComponentImpl bitfieldComponent,
DataType oldDt, DataType newDt) throws InvalidDataTypeException {
if (!bitfieldComponent.isBitFieldComponent()) {
throw new AssertException("expected bitfield component");
}
BitFieldDataType bitfieldDt = (BitFieldDataType) bitfieldComponent.getDataType();
if (bitfieldDt.getBaseDataType() != oldDt) {
return false;
}
if (newDt != null) {
BitFieldDataType.checkBaseDataType(newDt);
int maxBitSize = 8 * newDt.getLength();
if (bitfieldDt.getBitSize() > maxBitSize) {
throw new InvalidDataTypeException("Replacement datatype too small for bitfield");
}
}
try {
BitFieldDataType newBitfieldDt =
new BitFieldDataType(newDt, bitfieldDt.getDeclaredBitSize(),
bitfieldDt.getBitOffset(), bitfieldDt.getStorageSize());
bitfieldComponent.setDataType(newBitfieldDt);
oldDt.removeParent(this);
newDt.addParent(this);
}
catch (InvalidDataTypeException e) {
throw new AssertException("unexpected");
}
return true;
}
@Override
@ -133,23 +214,28 @@ public abstract class CompositeDataTypeImpl extends GenericDataType implements C
}
@Override
public DataTypeComponent add(DataType dataType, int length) {
public final DataTypeComponent add(DataType dataType) {
return add(dataType, -1, null, null);
}
@Override
public final DataTypeComponent add(DataType dataType, int length) {
return add(dataType, length, null, null);
}
@Override
public DataTypeComponent add(DataType dataType, String fieldName, String comment) {
return add(dataType, dataType.getLength(), fieldName, comment);
public final DataTypeComponent add(DataType dataType, String fieldName, String comment) {
return add(dataType, -1, fieldName, comment);
}
@Override
public DataTypeComponent insert(int ordinal, DataType dataType, int length) {
public final DataTypeComponent insert(int ordinal, DataType dataType, int length) {
return insert(ordinal, dataType, length, null, null);
}
@Override
public DataTypeComponent insert(int ordinal, DataType dataType) {
return insert(ordinal, dataType, dataType.getLength(), null, null);
public final DataTypeComponent insert(int ordinal, DataType dataType) {
return insert(ordinal, dataType, -1, null, null);
}
@Override
@ -170,6 +256,9 @@ public abstract class CompositeDataTypeImpl extends GenericDataType implements C
@Override
public void setPackingValue(int packingValue) {
if (packingValue < 0) {
packingValue = NOT_PACKING;
}
aligned = true;
this.packingValue = packingValue;
adjustInternalAlignment();
@ -177,19 +266,33 @@ public abstract class CompositeDataTypeImpl extends GenericDataType implements C
@Override
public int getMinimumAlignment() {
if (alignmentType == AlignmentType.MACHINE_ALIGNED) {
return getMachineAlignment();
}
if (alignmentType == AlignmentType.DEFAULT_ALIGNED) {
return Composite.DEFAULT_ALIGNMENT_VALUE;
}
return externalAlignment;
}
@Override
public void setMinimumAlignment(int externalAlignment) {
aligned = true;
if (currentAlignment != AlignmentType.ALIGNED_BY_VALUE) {
currentAlignment = AlignmentType.ALIGNED_BY_VALUE;
if (externalAlignment < 1) {
this.externalAlignment = DEFAULT_ALIGNMENT_VALUE;
alignmentType = AlignmentType.DEFAULT_ALIGNED;
}
this.externalAlignment = externalAlignment;
else {
this.externalAlignment = externalAlignment;
alignmentType = AlignmentType.ALIGNED_BY_VALUE;
}
aligned = true;
adjustInternalAlignment();
}
private int getMachineAlignment() {
return getDataOrganization().getMachineAlignment();
}
@Override
public boolean isInternallyAligned() {
return aligned;
@ -197,12 +300,12 @@ public abstract class CompositeDataTypeImpl extends GenericDataType implements C
@Override
public boolean isDefaultAligned() {
return currentAlignment == AlignmentType.DEFAULT_ALIGNED;
return alignmentType == AlignmentType.DEFAULT_ALIGNED;
}
@Override
public boolean isMachineAligned() {
return currentAlignment == AlignmentType.MACHINE_ALIGNED;
return alignmentType == AlignmentType.MACHINE_ALIGNED;
}
@Override
@ -210,7 +313,7 @@ public abstract class CompositeDataTypeImpl extends GenericDataType implements C
if (this.aligned != aligned) {
this.aligned = aligned;
if (!aligned) {
currentAlignment = AlignmentType.DEFAULT_ALIGNED;
alignmentType = AlignmentType.DEFAULT_ALIGNED;
packingValue = Composite.NOT_PACKING;
}
}
@ -220,14 +323,14 @@ public abstract class CompositeDataTypeImpl extends GenericDataType implements C
@Override
public void setToDefaultAlignment() {
aligned = true;
currentAlignment = AlignmentType.DEFAULT_ALIGNED;
alignmentType = AlignmentType.DEFAULT_ALIGNED;
adjustInternalAlignment();
}
@Override
public void setToMachineAlignment() {
aligned = true;
currentAlignment = AlignmentType.MACHINE_ALIGNED;
alignmentType = AlignmentType.MACHINE_ALIGNED;
adjustInternalAlignment();
}
@ -254,23 +357,23 @@ public abstract class CompositeDataTypeImpl extends GenericDataType implements C
@Override
public int getAlignment() {
return getDataOrganization().getAlignment(this, getLength());
return CompositeAlignmentHelper.getAlignment(getDataOrganization(), this);
}
// set my alignment info to the same as the given composite
protected void setDataAlignmentInfo(Composite composite) {
protected void setAlignment(Composite composite) {
aligned = composite.isInternallyAligned();
if (composite.isDefaultAligned()) {
currentAlignment = AlignmentType.DEFAULT_ALIGNED;
alignmentType = AlignmentType.DEFAULT_ALIGNED;
}
else if (composite.isMachineAligned()) {
currentAlignment = AlignmentType.MACHINE_ALIGNED;
alignmentType = AlignmentType.MACHINE_ALIGNED;
}
else {
if (currentAlignment != AlignmentType.ALIGNED_BY_VALUE) {
currentAlignment = AlignmentType.ALIGNED_BY_VALUE;
if (alignmentType != AlignmentType.ALIGNED_BY_VALUE) {
alignmentType = AlignmentType.ALIGNED_BY_VALUE;
}
externalAlignment = composite.getMinimumAlignment();
}
@ -288,7 +391,14 @@ public abstract class CompositeDataTypeImpl extends GenericDataType implements C
protected void dumpComponents(StringBuilder buffer, String pad) {
for (DataTypeComponent dtc : getComponents()) {
DataType dataType = dtc.getDataType();
buffer.append(pad + dtc.getOffset());
buffer.append(pad + dataType.getDisplayName());
if (dataType instanceof BitFieldDataType) {
BitFieldDataType bfDt = (BitFieldDataType) dataType;
buffer.append("(");
buffer.append(Integer.toString(bfDt.getBitOffset()));
buffer.append(")");
}
buffer.append(pad + dtc.getLength());
buffer.append(pad + dtc.getFieldName());
String comment = dtc.getComment();

View file

@ -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.
@ -34,10 +33,12 @@ public class DWordDataType extends AbstractIntegerDataType {
super("dword", false, dtm);
}
@Override
public String getDescription() {
return "Unsigned Double-Word (ddw, 4-bytes)";
}
@Override
public int getLength() {
return 4;
}
@ -48,11 +49,12 @@ public class DWordDataType extends AbstractIntegerDataType {
}
@Override
public DataType getOppositeSignednessDataType() {
return SignedDWordDataType.dataType;
public SignedDWordDataType getOppositeSignednessDataType() {
return SignedDWordDataType.dataType.clone(getDataTypeManager());
}
public DataType clone(DataTypeManager dtm) {
@Override
public DWordDataType clone(DataTypeManager dtm) {
if (dtm == getDataTypeManager()) {
return this;
}

View file

@ -38,7 +38,7 @@ public interface DataOrganization {
* @return the left shift amount for shifted-pointers.
*/
int getPointerShift();
/**
* @return true if the "char" type is signed
*/
@ -126,6 +126,12 @@ public interface DataOrganization {
*/
int getSizeAlignment(int size) throws NoValueException;
/**
* Get the composite bitfield packing information associated with this data organization.
* @return composite bitfield packing information
*/
BitFieldPacking getBitFieldPacking();
/**
* Remove all entries from the size alignment map
*/
@ -154,10 +160,11 @@ public interface DataOrganization {
String getIntegerCTypeApproximation(int size, boolean signed);
/**
* Determines the alignment value for the indicated data type. (i.e. how the dat type gets
* aligned within other data types.)
* Determines the alignment value for the indicated data type. (i.e. how the data type gets
* aligned within other data types.) NOTE: the alignment of bitfields is dependent upon packing
* rules which must be considered at the composite level.
* @param dataType the data type
* @param dtSize the data type's size
* @param dtSize the data type's size or component size
* @return the alignment
*/
int getAlignment(DataType dataType, int dtSize);
@ -174,5 +181,4 @@ public interface DataOrganization {
* @return the aligned offset for the data type
*/
int getAlignmentOffset(int minimumOffset, DataType dataType, int dtSize);
}

View file

@ -15,7 +15,7 @@
*/
package ghidra.program.model.data;
import java.util.*;
import java.util.Arrays;
import ghidra.program.model.lang.Language;
import ghidra.util.datastruct.IntIntHashtable;
@ -48,7 +48,7 @@ public class DataOrganizationImpl implements DataOrganization {
private boolean bigEndian = false;
private boolean isSignedChar = true;
private String[] callingConventionNames;
private BitFieldPacking bitFieldPacking = new BitFieldPackingImpl();
/*
* Map for determining the alignment of a data type based upon its size.
@ -82,59 +82,25 @@ public class DataOrganizationImpl implements DataOrganization {
dataOrganization.setPointerSize(language.getDefaultSpace().getPointerSize());
dataOrganization.setBigEndian(language.isBigEndian());
}
// Create list of acceptable calling conventions (include all generic conventions by default)
GenericCallingConvention[] genericCallingConventions = GenericCallingConvention.values();
List<String> names = new ArrayList<>();
for (GenericCallingConvention convention : genericCallingConventions) {
if (convention != GenericCallingConvention.unknown) {
names.add(convention.name());
}
}
Collections.sort(names);
dataOrganization.callingConventionNames = new String[names.size()];
names.toArray(dataOrganization.callingConventionNames);
return dataOrganization;
}
/**
* Creates a new default DataOrganization with an empty size to alignment mapping which
* defines the alignment of a data type based on its size.
* Creates a new default DataOrganization with an empty size to alignment mapping.
*/
private DataOrganizationImpl() {
}
/**
* Set data endianess
* @param bigEndian
*/
public void setBigEndian(boolean bigEndian) {
this.bigEndian = bigEndian;
}
/**
* @return true if data stored big-endian byte order
*/
@Override
public boolean isBigEndian() {
return bigEndian;
}
/**
* @return the size of a pointer data type.
*/
@Override
public int getPointerSize() {
return pointerSize;
}
/**
* Shift amount affects interpretation of in-memory pointer values only
* and will also be reflected within instruction pcode. A value of zero indicates
* that shifted-pointers are not supported.
* @return the left shift amount for shifted-pointers.
*/
@Override
public int getPointerShift() {
return pointerShift;
@ -145,78 +111,64 @@ public class DataOrganizationImpl implements DataOrganization {
return isSignedChar;
}
/**
* @return the size of a char (char) primitive data type.
*/
@Override
public int getCharSize() {
return charSize;
}
/**
* @return the size of a wide-char (wchar_t) primitive data type.
*/
@Override
public int getWideCharSize() {
return wideCharSize;
}
/**
* @return the size of a short primitive data type.
*/
@Override
public int getShortSize() {
return shortSize;
}
/**
* @return the size of a int primitive data type.
*/
@Override
public int getIntegerSize() {
return integerSize;
}
/**
* @return the size of a long primitive data type.
*/
@Override
public int getLongSize() {
return longSize;
}
/**
* @return the size of a long long primitive data type.
*/
@Override
public int getLongLongSize() {
return longLongSize;
}
/**
* @return the size of a float primitive data type.
*/
@Override
public int getFloatSize() {
return floatSize;
}
/**
* @return the size of a double primitive data type.
*/
@Override
public int getDoubleSize() {
return doubleSize;
}
/**
* @return the size of a long double primitive data type.
*/
@Override
public int getLongDoubleSize() {
return longDoubleSize;
}
@Override
public BitFieldPacking getBitFieldPacking() {
return bitFieldPacking;
}
/**
* Set data endianess
* @param bigEndian
*/
public void setBigEndian(boolean bigEndian) {
this.bigEndian = bigEndian;
}
/**
* Defines the size of a pointer data type.
* @param shortSize the size of a short.
@ -425,8 +377,6 @@ public class DataOrganizationImpl implements DataOrganization {
this.defaultPointerAlignment = defaultPointerAlignment;
}
// ALIGNMENTS BASED ON SIZE
/**
* Gets the alignment that is defined for a data type of the indicated size if one is defined.
* @param size the size of the data type
@ -439,7 +389,7 @@ public class DataOrganizationImpl implements DataOrganization {
}
/**
* Gets the alignment that is defined for a data type of the indicated size if one is defined.
* Sets the alignment that is defined for a data type of the indicated size if one is defined.
* @param size the size of the data type
* @param alignment the alignment of the data type.
*/
@ -447,6 +397,14 @@ public class DataOrganizationImpl implements DataOrganization {
sizeAlignmentMap.put(size, alignment);
}
/**
* Set the bitfield packing information associated with this data organization.
* @param bitFieldPacking bitfield packing information
*/
public void setBitFieldPacking(BitFieldPacking bitFieldPacking) {
this.bitFieldPacking = bitFieldPacking;
}
/**
* Remove all entries from the size alignment map
*/
@ -504,13 +462,6 @@ public class DataOrganizationImpl implements DataOrganization {
return ctype;
}
/**
* Determines the alignment value for the indicated data type. (i.e. how the dat type gets
* aligned within other data types.)
* @param dataType the data type
* @param dtSize the data type's size
* @return the alignment
*/
@Override
public int getAlignment(DataType dataType, int dtSize) {
// Don't do alignment on dynamic data types.
@ -538,7 +489,14 @@ public class DataOrganizationImpl implements DataOrganization {
// Structure's or Union's alignment is a multiple of the least common multiple of
// the components. It can also be adjusted by packing and alignment attributes.
if (dataType instanceof Composite) {
return getAlignment((Composite) dataType);
// IMPORTANT: composites are now responsible for computing their own alignment !!
return ((Composite) dataType).getAlignment();
}
// Bit field alignment must be determined within the context of the containing structure.
// See AlignedStructurePacker.
if (dataType instanceof BitFieldDataType) {
BitFieldDataType bitfieldDt = (BitFieldDataType) dataType;
return getAlignment(bitfieldDt.getBaseDataType(), bitfieldDt.getBaseTypeSize());
}
// Otherwise get the alignment based on the size.
if (sizeAlignmentMap.contains(dtSize)) {
@ -583,6 +541,7 @@ public class DataOrganizationImpl implements DataOrganization {
if (dataType instanceof Pointer) {
return 0;
}
// Structure's or Union's alignment is a multiple of the least common multiple of
// the components. It can also be adjusted by packing and alignment attributes.
if (dataType instanceof Composite) {
@ -607,6 +566,9 @@ public class DataOrganizationImpl implements DataOrganization {
dataTypeComponents = composite.getComponents();
}
for (DataTypeComponent dataTypeComponent : dataTypeComponents) {
if (dataTypeComponent.isBitFieldComponent()) {
continue;
}
DataType componentDt = dataTypeComponent.getDataType();
int forcedAlignment = getForcedAlignment(componentDt);
if (forcedAlignment > 0) {
@ -635,66 +597,6 @@ public class DataOrganizationImpl implements DataOrganization {
return 0;
}
private int getComponentAlignmentMultiple(Composite dataType) {
int allComponentsLCM = 1;
int packingValue = dataType.getPackingValue();
DataTypeComponent[] dataTypeComponents = dataType.getComponents();
for (DataTypeComponent dataTypeComponent : dataTypeComponents) {
allComponentsLCM =
getComponentAlignmentLCM(allComponentsLCM, packingValue, dataTypeComponent);
}
if (dataType instanceof Structure) {
Structure struct = (Structure) dataType;
DataTypeComponent flexibleArrayComponent = struct.getFlexibleArrayComponent();
if (flexibleArrayComponent != null) {
allComponentsLCM = getComponentAlignmentLCM(allComponentsLCM, packingValue,
flexibleArrayComponent);
}
}
return allComponentsLCM;
}
private int getComponentAlignmentLCM(int allComponentsLCM, int packingValue,
DataTypeComponent component) {
DataType componentDt = component.getDataType();
int dtSize = componentDt.getLength();
if (dtSize <= 0) {
dtSize = component.getLength();
}
int componentAlignment = getAlignment(componentDt, dtSize);
int componentForcedAlignment = getForcedAlignment(componentDt);
boolean componentForcingAlignment = componentForcedAlignment > 0;
if (componentForcingAlignment) {
componentAlignment =
getLeastCommonMultiple(componentAlignment, componentForcedAlignment);
}
// Only do packing if we are not forcing an alignment.
if (packingValue != Composite.NOT_PACKING) { // TODO Should this be packingValue > 0?
if (componentForcedAlignment > packingValue) {
componentAlignment = componentForcedAlignment;
}
else if (componentAlignment > packingValue) {
componentAlignment = packingValue;
}
}
allComponentsLCM = getLeastCommonMultiple(allComponentsLCM, componentAlignment);
return allComponentsLCM;
}
private int getAlignment(Composite dataType) {
if (!dataType.isInternallyAligned()) {
return 1; // Unaligned
}
int lcm = getComponentAlignmentMultiple(dataType);
int minimumAlignment = dataType.getMinimumAlignment();
if ((minimumAlignment != Composite.DEFAULT_ALIGNMENT_VALUE) &&
(lcm % minimumAlignment != 0)) {
lcm = getLeastCommonMultiple(lcm, minimumAlignment);
}
return ((absoluteMaxAlignment == 0) || (lcm < absoluteMaxAlignment)) ? lcm
: absoluteMaxAlignment;
}
/**
* Determines the offset where the specified data type should be placed to be properly aligned.
* @param minimumOffset the minimum allowable offset where the data type can be placed.

View file

@ -418,4 +418,9 @@ public interface DataType {
*/
public void setLastChangeTimeInSourceArchive(long lastChangeTimeInSourceArchive);
/**
* Returns the DataOrganization associated with this data-type
*/
public DataOrganization getDataOrganization();
}

View file

@ -26,7 +26,7 @@ import ghidra.util.exception.DuplicateNameException;
* and Unions) dataTypes.
* <p>
* While most all components must have a fixed length greater than 0, structures support an
* optional trailing flexible array component whose length is zero and whose offset equals
* optional trailing flexible array component whose length is zero and whose offset equals
* the length of the structure.
*/
public interface DataTypeComponent {
@ -37,7 +37,7 @@ public interface DataTypeComponent {
/**
* Returns the dataType in this component.
* <p>
* NOTE: If this component corresponds to a structure flexible array the returned data type
* NOTE: If this component corresponds to a structure flexible array the returned data type
* reflects the base type of the array (e.g., char is returned for a flexible char array).
* @return the dataType in this component
*/
@ -51,18 +51,30 @@ public interface DataTypeComponent {
/**
* Determine if this component corresponds to a unsized flexible array which is
* permitted as the trailing component within a structure.
* permitted as the trailing component within a structure.
* @return true if component is a trailing flexible array component.
*/
public boolean isFlexibleArrayComponent();
/**
* Determine if the specified component corresponds to a bit-field.
* @return true if bit-field else false
*/
public boolean isBitFieldComponent();
/**
* Determine if the specified component corresponds to a zero-length bit-field.
* @return true if zer-length bit-field else false
*/
public boolean isZeroBitFieldComponent();
/**
* Get the ordinal position within the parent dataType.
* <p>
* NOTE: The special case of a structure flexible array component returns an ordinal equal
* to the parent structure's {@link Structure#getNumComponents()} since it is not included
* in the list of normal components (see {@link Structure#getFlexibleArrayComponent()}.
* @return ordinal of this component within the parent data type.
* in the list of normal components (see {@link Structure#getFlexibleArrayComponent()}.
* @return ordinal of this component within the parent data type.
*/
public int getOrdinal();
@ -80,19 +92,19 @@ public interface DataTypeComponent {
/**
* Get the byte offset of where this component ends relative to the start of the parent
* data type.
* data type.
* <p>
* NOTE: The special case of a structure flexible array component returns -1 since its
* NOTE: The special case of a structure flexible array component returns -1 since its
* length is undefined.
* @return offset of end of component relative to the start of the parent
* data type.
* data type.
*/
public int getEndOffset();
/**
* Get the length of this component.
* <p>
* NOTE: The special case of a structure flexible array component returns 0 since its
* NOTE: The special case of a structure flexible array component returns 0 since its
* length is undefined.
* @return the length of this component or 0 for a structure flexible array.
*/
@ -153,4 +165,5 @@ public interface DataTypeComponent {
* @return true if the given dataTypeComponent is equivalent to this dataTypeComponent.
*/
public boolean isEquivalent(DataTypeComponent dtc);
}

View file

@ -26,7 +26,7 @@ import ghidra.util.exception.DuplicateNameException;
/**
* Basic implementation of a DataTypeComponent
*/
public class DataTypeComponentImpl implements DataTypeComponent, Serializable {
public class DataTypeComponentImpl implements InternalDataTypeComponent, Serializable {
private final static long serialVersionUID = 1;
private DataType dataType;
@ -53,17 +53,21 @@ public class DataTypeComponentImpl implements DataTypeComponent, Serializable {
public DataTypeComponentImpl(DataType dataType, CompositeDataTypeImpl parent, int length,
int ordinal, int offset, String fieldName, String comment) {
this.dataType = dataType;
this.parent = parent;
this.ordinal = ordinal;
this.offset = offset;
this.length = length;
this.fieldName = fieldName;
this.comment = comment;
setDataType(dataType);
initFlexibleArrayComponent();
}
private void initFlexibleArrayComponent() {
if (dataType instanceof BitFieldDataType || dataType instanceof Dynamic ||
dataType instanceof FactoryDataType) {
return;
}
isFlexibleArrayComponent =
length == 0 && offset < 0 && ordinal < 0 && (parent instanceof Structure);
}
@ -86,6 +90,20 @@ public class DataTypeComponentImpl implements DataTypeComponent, Serializable {
return isFlexibleArrayComponent;
}
@Override
public boolean isBitFieldComponent() {
return dataType instanceof BitFieldDataType;
}
@Override
public boolean isZeroBitFieldComponent() {
if (isBitFieldComponent()) {
BitFieldDataType bitField = (BitFieldDataType) getDataType();
return bitField.getBitSize() == 0;
}
return false;
}
@Override
public int getOffset() {
if (isFlexibleArrayComponent) {
@ -98,6 +116,13 @@ public class DataTypeComponentImpl implements DataTypeComponent, Serializable {
return offset;
}
boolean containsOffset(int off) {
if (isFlexibleArrayComponent) {
return false;
}
return off >= offset && off <= (offset + length - 1);
}
@Override
public int getEndOffset() {
return offset + length - 1;
@ -115,11 +140,17 @@ public class DataTypeComponentImpl implements DataTypeComponent, Serializable {
@Override
public String getFieldName() {
if (isZeroBitFieldComponent()) {
return "";
}
return fieldName;
}
@Override
public String getDefaultFieldName() {
if (isZeroBitFieldComponent()) {
return "";
}
if (parent instanceof Structure) {
return DEFAULT_FIELD_NAME_PREFIX + "_0x" + Integer.toHexString(getOffset());
}
@ -186,6 +217,13 @@ public class DataTypeComponentImpl implements DataTypeComponent, Serializable {
return parent;
}
@Override
public void update(int ordinal, int offset, int length) {
this.ordinal = ordinal;
this.offset = offset;
this.length = length;
}
/**
* Set the byte offset of where this component begins in its immediate parent
* data type.
@ -248,10 +286,13 @@ public class DataTypeComponentImpl implements DataTypeComponent, Serializable {
DataTypeComponent dtc = (DataTypeComponent) obj;
DataType myDt = getDataType();
DataType otherDt = dtc.getDataType();
if (offset != dtc.getOffset() || length != dtc.getLength() || ordinal != dtc.getOrdinal() ||
// NOTE: use getOffset() and getOrdinal() methods since returned values will differ from
// stored values for flexible array component
if (getOffset() != dtc.getOffset() || getLength() != dtc.getLength() ||
getOrdinal() != dtc.getOrdinal() ||
!SystemUtilities.isEqual(getFieldName(), dtc.getFieldName()) ||
!SystemUtilities.isEqual(getComment(), dtc.getComment())) {
return false;
}
if (!(myDt instanceof Pointer)) {
@ -285,25 +326,48 @@ public class DataTypeComponentImpl implements DataTypeComponent, Serializable {
public boolean isEquivalent(DataTypeComponent dtc) {
DataType myDt = getDataType();
DataType otherDt = dtc.getDataType();
int otherLength = dtc.getLength();
DataType myParent = getParent();
boolean aligned =
(myParent instanceof Composite) ? ((Composite) myParent).isInternallyAligned() : false;
// Components don't need to have matching offset when they are aligned, only matching ordinal.
if ((!aligned && (getOffset() != dtc.getOffset())) ||
// Components don't need to have matching length when they are aligned. Is this correct?
(!aligned && (getLength() != otherLength)) || getOrdinal() != dtc.getOrdinal() ||
// NOTE: use getOffset() and getOrdinal() methods since returned values will differ from
// stored values for flexible array component
(!aligned && (getLength() != dtc.getLength())) || getOrdinal() != dtc.getOrdinal() ||
!SystemUtilities.isEqual(getFieldName(), dtc.getFieldName()) ||
!SystemUtilities.isEqual(getComment(), dtc.getComment())) {
return false;
}
return DataTypeUtilities.isSameOrEquivalentDataType(myDt, otherDt);
}
void setDataType(DataType dt) {
@Override
public void setDataType(DataType dt) {
dataType = dt;
if (dt instanceof BitFieldDataType) {
// bit-field packing may change component size
setLength(dt.getLength());
}
}
@Override
public String toString() {
StringBuffer buffer = new StringBuffer();
buffer.append(" " + ordinal);
buffer.append(" " + offset);
buffer.append(" " + dataType.getDisplayName());
if (isFlexibleArrayComponent) {
buffer.append("[ ]");
}
else if (dataType instanceof BitFieldDataType) {
buffer.append("(" + ((BitFieldDataType) dataType).getBitOffset() + ")");
}
buffer.append(" " + length);
buffer.append(" " + fieldName);
buffer.append(" " + ((comment != null) ? ("\"" + comment + "\"") : comment));
return buffer.toString();
}
}

View file

@ -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.
@ -17,16 +16,16 @@
package ghidra.program.model.data;
/**
* Exception thrown when trying to replace a dataType with a dataType that depends
* on the dataType being replaced. For example try to replace byte with byte[] fail
* because byte[] depends on byte.
* <code>DataTypeDependencyException</code> corresponds to a datatype dependency failure.
* This can occur under various situations, including when trying to replace a dataType
* with a dataType that depends on the dataType being replaced. This error may also occur
* when a datatype dependency can not be satisfied.
*/
public class DataTypeDependencyException extends Exception {
public DataTypeDependencyException() {
super();
// TODO Auto-generated constructor stub
}
public DataTypeDependencyException(String message) {

View file

@ -15,8 +15,6 @@
*/
package ghidra.program.model.data;
import java.io.Serializable;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
@ -25,23 +23,20 @@ import javax.swing.event.ChangeListener;
import ghidra.app.plugin.core.datamgr.archive.SourceArchive;
import ghidra.docking.settings.*;
import ghidra.program.model.mem.MemBuffer;
import ghidra.util.*;
/**
* Base implementation for dataTypes.
*/
public abstract class DataTypeImpl implements DataType, ChangeListener, Serializable {
public abstract class DataTypeImpl extends AbstractDataType implements ChangeListener {
private final static SettingsDefinition[] EMPTY_DEFINITIONS = new SettingsDefinition[0];
protected Settings defaultSettings;
protected String name;
protected CategoryPath categoryPath;
private ArrayList<DataType> parentList;
private UniversalID universalID;
private SourceArchive sourceArchive;
private long lastChangeTime;
private long lastChangeTimeInSourceArchive;
private DataTypeManager dataMgr;
protected DataTypeImpl(CategoryPath path, String name, DataTypeManager dataMgr) {
this(path, name, null, null, System.currentTimeMillis(), NO_LAST_CHANGE_TIME, dataMgr);
@ -50,20 +45,7 @@ public abstract class DataTypeImpl implements DataType, ChangeListener, Serializ
DataTypeImpl(CategoryPath path, String name, UniversalID universalID,
SourceArchive sourceArchive, long lastChangeTime, long lastChangeTimeInSourceArchive,
DataTypeManager dataMgr) {
if (path == null) {
throw new IllegalArgumentException("Category Path is null!");
}
if (name == null || name.length() == 0) {
throw new IllegalArgumentException("Name is null or empty!");
}
// allow spaces since derived types may have spaces (pointers for example: foo *32)
if (!DataUtilities.isValidDataTypeName(name)) {
throw new IllegalArgumentException("Invalid DataType name: " + name);
}
this.categoryPath = path;
this.name = name;
this.dataMgr = dataMgr;
super(path, name, dataMgr);
defaultSettings = new SettingsImpl(this, null);
parentList = new ArrayList<>();
this.universalID = universalID == null ? UniversalIdGenerator.nextID() : universalID;
@ -72,94 +54,26 @@ public abstract class DataTypeImpl implements DataType, ChangeListener, Serializ
this.lastChangeTimeInSourceArchive = lastChangeTimeInSourceArchive;
}
/**
* Returns the DataOrganization associated with this
* data-types DataTypeManager
*/
protected final DataOrganization getDataOrganization() {
DataOrganization dataOrganization = null;
if (dataMgr != null) {
dataOrganization = dataMgr.getDataOrganization();
}
if (dataOrganization == null) {
dataOrganization = DataOrganizationImpl.getDefaultOrganization();
}
return dataOrganization;
}
@Override
public boolean isNotYetDefined() {
return false;
}
@Override
public Class<?> getValueClass(Settings settings) {
return null;
}
/**
* @see ghidra.program.model.data.DataType#getDefaultSettings()
*/
@Override
public Settings getDefaultSettings() {
return defaultSettings;
}
/* (non-Javadoc)
* @see ghidra.program.model.data.DataType#getCategoryPath()
*/
@Override
public CategoryPath getCategoryPath() {
return categoryPath;
}
@Override
public DataTypePath getDataTypePath() {
return new DataTypePath(categoryPath, name);
}
/**
* @see ghidra.program.model.data.DataType#getDocs()
*/
@Override
public URL getDocs() {
return null;
}
/**
* @see ghidra.program.model.data.DataType#getSettingsDefinitions()
*/
@Override
public SettingsDefinition[] getSettingsDefinitions() {
return EMPTY_DEFINITIONS;
}
/**
* @see ghidra.program.model.data.DataType#getName()
*/
@Override
public String getName() {
return name;
}
/* (non-Javadoc)
* @see ghidra.program.model.data.DataType#getDisplayName()
*/
@Override
public String getDisplayName() {
return getName();
}
@Override
public String toString() {
return getDisplayName();
}
/**
* Check if the name is a valid name for a data type
*
*
* @param checkedName name to check
*
*
* @throws InvalidNameException if the name is invalid
*/
void checkValidName(String checkedName) throws InvalidNameException {
@ -168,42 +82,16 @@ public abstract class DataTypeImpl implements DataType, ChangeListener, Serializ
}
}
/**
* @see ghidra.program.model.data.DataType#isDeleted()
*/
@Override
public boolean isDeleted() {
return false;
}
/**
* @see javax.swing.event.ChangeListener#stateChanged(javax.swing.event.ChangeEvent)
*/
@Override
public void stateChanged(ChangeEvent e) {
// don't care
}
/**
* @see ghidra.program.model.data.DataType#getDataTypeManager()
*/
@Override
public DataTypeManager getDataTypeManager() {
return dataMgr;
}
/**
*
* @see ghidra.program.model.data.DataType#setDefaultSettings(ghidra.docking.settings.Settings)
*/
@Override
public void setDefaultSettings(Settings settings) {
defaultSettings = settings;
}
/**
* @see ghidra.program.model.data.DataType#getPathName()
*/
@Override
public String getPathName() {
return getDataTypePath().getPath();
@ -218,25 +106,16 @@ public abstract class DataTypeImpl implements DataType, ChangeListener, Serializ
return getDataOrganization().getAlignment(this, length);
}
/**
* @see ghidra.program.model.data.DataType#addParent(ghidra.program.model.data.DataType)
*/
@Override
public void addParent(DataType dt) {
parentList.add(dt);
}
/**
* @see ghidra.program.model.data.DataType#removeParent(ghidra.program.model.data.DataType)
*/
@Override
public void removeParent(DataType dt) {
parentList.remove(dt);
}
/* (non-Javadoc)
* @see ghidra.program.model.data.DataType#getParents()
*/
@Override
public DataType[] getParents() {
DataType[] dts = new DataType[parentList.size()];
@ -257,7 +136,7 @@ public abstract class DataTypeImpl implements DataType, ChangeListener, Serializ
/**
* Notify any parents that my name has changed.
*
*
* @param oldName
*/
protected void notifyNameChanged(String oldName) {
@ -291,29 +170,6 @@ public abstract class DataTypeImpl implements DataType, ChangeListener, Serializ
}
}
@Override
public String getDefaultLabelPrefix() {
return null;
}
@Override
public String getDefaultAbbreviatedLabelPrefix() {
return getDefaultLabelPrefix();
}
@Override
public String getDefaultLabelPrefix(MemBuffer buf, Settings settings, int len,
DataTypeDisplayOptions options) {
return getDefaultLabelPrefix();
}
@Override
public String getDefaultOffcutLabelPrefix(MemBuffer buf, Settings settings, int len,
DataTypeDisplayOptions options, int offcutLength) {
// By default we will do nothing different for offcut values
return getDefaultLabelPrefix(buf, settings, len, options);
}
@Override
public long getLastChangeTime() {
return lastChangeTime;
@ -370,7 +226,7 @@ public abstract class DataTypeImpl implements DataType, ChangeListener, Serializ
@Override
public int hashCode() {
// Note: this works because the DTMs have to be equal and there can be only one DT with
// the same name and category path
// the same name and category path
return getName().hashCode();
}

View file

@ -484,7 +484,8 @@ public interface DataTypeManager {
public boolean updateSourceArchiveName(UniversalID sourceID, String name);
/**
* Get the data organization associated with this data type manager
* Get the data organization associated with this data type manager. Note that the
* DataOrganization settings may not be changed dynamically.
* @return data organization (will never be null)
*/
public DataOrganization getDataOrganization();

View file

@ -40,6 +40,7 @@ public class DefaultDataType extends DataTypeImpl {
*
* @see ghidra.program.model.data.DataType#getMnemonic(Settings)
*/
@Override
public String getMnemonic(Settings settings) {
return "??";
}
@ -48,6 +49,7 @@ public class DefaultDataType extends DataTypeImpl {
*
* @see ghidra.program.model.data.DataType#getLength()
*/
@Override
public int getLength() {
return 1;
}
@ -55,6 +57,7 @@ public class DefaultDataType extends DataTypeImpl {
/**
* @see ghidra.program.model.data.DataType#isDynamicallySized()
*/
@Override
public boolean isDynamicallySized() {
return false;
}
@ -63,6 +66,7 @@ public class DefaultDataType extends DataTypeImpl {
*
* @see ghidra.program.model.data.DataType#getDescription()
*/
@Override
public String getDescription() {
return "Undefined Byte";
}
@ -71,6 +75,7 @@ public class DefaultDataType extends DataTypeImpl {
*
* @see ghidra.program.model.data.DataType#getRepresentation(MemBuffer, Settings, int)
*/
@Override
public String getRepresentation(MemBuffer buf, Settings settings, int length) {
try {
int b = buf.getByte(0) & 0xff;
@ -96,6 +101,7 @@ public class DefaultDataType extends DataTypeImpl {
* @param length the number of bytes to get the value from.
* @return the data Object.
*/
@Override
public Object getValue(MemBuffer buf, Settings settings, int length) {
try {
return new Scalar(8, buf.getByte(0));
@ -105,10 +111,12 @@ public class DefaultDataType extends DataTypeImpl {
}
}
@Override
public DataType clone(DataTypeManager dtm) {
return this;
}
@Override
public DataType copy(DataTypeManager dtm) {
return this;
}
@ -116,12 +124,14 @@ public class DefaultDataType extends DataTypeImpl {
/**
* @see ghidra.program.model.data.DataType#dataTypeSizeChanged(ghidra.program.model.data.DataType)
*/
@Override
public void dataTypeSizeChanged(DataType dt) {
}
/**
* @see ghidra.program.model.data.DataType#isEquivalent(ghidra.program.model.data.DataType)
*/
@Override
public boolean isEquivalent(DataType dt) {
return dt == this;
}
@ -129,43 +139,50 @@ public class DefaultDataType extends DataTypeImpl {
/**
* @see ghidra.program.model.data.DataType#setCategoryPath(ghidra.program.model.data.CategoryPath)
*/
@Override
public void setCategoryPath(CategoryPath path) throws DuplicateNameException {
}
/**
* @see ghidra.program.model.data.DataType#setName(java.lang.String)
*/
public void setName(String name) throws InvalidNameException, DuplicateNameException {
@Override
public void setName(String name) {
}
/**
* @see ghidra.program.model.data.DataType#setNameAndCategory(ghidra.program.model.data.CategoryPath, java.lang.String)
*/
public void setNameAndCategory(CategoryPath path, String name) throws InvalidNameException,
DuplicateNameException {
@Override
public void setNameAndCategory(CategoryPath path, String name)
throws InvalidNameException, DuplicateNameException {
}
/**
* @see ghidra.program.model.data.DataType#dataTypeDeleted(ghidra.program.model.data.DataType)
*/
@Override
public void dataTypeDeleted(DataType dt) {
}
/**
* @see ghidra.program.model.data.DataType#dataTypeNameChanged(ghidra.program.model.data.DataType, java.lang.String)
*/
@Override
public void dataTypeNameChanged(DataType dt, String oldName) {
}
/**
* @see ghidra.program.model.data.DataType#dataTypeReplaced(ghidra.program.model.data.DataType, ghidra.program.model.data.DataType)
*/
@Override
public void dataTypeReplaced(DataType oldDt, DataType newDt) {
}
/**
* @see ghidra.program.model.data.DataType#dependsOn(ghidra.program.model.data.DataType)
*/
@Override
public boolean dependsOn(DataType dt) {
return false;
}

View file

@ -15,8 +15,11 @@
*/
package ghidra.program.model.data;
import java.math.BigInteger;
import java.util.NoSuchElementException;
import ghidra.docking.settings.Settings;
public interface Enum extends DataType {
/**
@ -69,4 +72,12 @@ public interface Enum extends DataType {
*/
@Override
public void setDescription(String description);
/**
* Get enum representation of the big-endian value.
* @param bigInt BigInteger value with the appropriate sign
* @param settings integer format settings (PADDING, FORMAT, etc.)
* @return formatted integer string
*/
public String getRepresentation(BigInteger bigInt, Settings settings, int bitLength);
}

View file

@ -15,6 +15,7 @@
*/
package ghidra.program.model.data;
import java.math.BigInteger;
import java.util.*;
import ghidra.app.plugin.core.datamgr.archive.SourceArchive;
@ -267,17 +268,26 @@ public class EnumDataType extends GenericDataType implements Enum {
value = buf.getLong(0);
break;
}
String valueName = getName(value);
if (valueName == null) {
valueName = getCompoundValue(value);
}
return valueName;
return getRepresentation(value);
}
catch (MemoryAccessException e) {
return "??";
}
}
@Override
public String getRepresentation(BigInteger bigInt, Settings settings, int bitLength) {
return getRepresentation(bigInt.longValue());
}
private String getRepresentation(long value) {
String valueName = getName(value);
if (valueName == null) {
valueName = getCompoundValue(value);
}
return valueName;
}
private String getCompoundValue(long value) {
if (value == 0) {
return "0";

View file

@ -33,20 +33,23 @@ public class Integer16DataType extends AbstractIntegerDataType {
super("int16", true, dtm);
}
@Override
public String getDescription() {
return "Signed 16-Byte Integer";
}
@Override
public int getLength() {
return 16;
}
@Override
public DataType getOppositeSignednessDataType() {
return UnsignedInteger16DataType.dataType;
public UnsignedInteger16DataType getOppositeSignednessDataType() {
return UnsignedInteger16DataType.dataType.clone(getDataTypeManager());
}
public DataType clone(DataTypeManager dtm) {
@Override
public Integer16DataType clone(DataTypeManager dtm) {
if (dtm == getDataTypeManager()) {
return this;
}

View file

@ -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.
@ -31,20 +30,23 @@ public class Integer3DataType extends AbstractIntegerDataType {
super("int3", true, dtm);
}
@Override
public String getDescription() {
return "Signed 3-Byte Integer";
}
@Override
public int getLength() {
return 3;
}
@Override
public DataType getOppositeSignednessDataType() {
return UnsignedInteger3DataType.dataType;
public UnsignedInteger3DataType getOppositeSignednessDataType() {
return UnsignedInteger3DataType.dataType.clone(getDataTypeManager());
}
public DataType clone(DataTypeManager dtm) {
@Override
public Integer3DataType clone(DataTypeManager dtm) {
if (dtm == getDataTypeManager()) {
return this;
}

View file

@ -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.
@ -31,20 +30,23 @@ public class Integer5DataType extends AbstractIntegerDataType {
super("int5", true, dtm);
}
@Override
public String getDescription() {
return "Signed 5-Byte Integer";
}
@Override
public int getLength() {
return 5;
}
@Override
public DataType getOppositeSignednessDataType() {
return UnsignedInteger5DataType.dataType;
public UnsignedInteger5DataType getOppositeSignednessDataType() {
return UnsignedInteger5DataType.dataType.clone(getDataTypeManager());
}
public DataType clone(DataTypeManager dtm) {
@Override
public Integer5DataType clone(DataTypeManager dtm) {
if (dtm == getDataTypeManager()) {
return this;
}

View file

@ -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.
@ -31,20 +30,23 @@ public class Integer6DataType extends AbstractIntegerDataType {
super("int6", true, dtm);
}
@Override
public String getDescription() {
return "Signed 6-Byte Integer";
}
@Override
public int getLength() {
return 6;
}
@Override
public DataType getOppositeSignednessDataType() {
return UnsignedInteger6DataType.dataType;
public UnsignedInteger6DataType getOppositeSignednessDataType() {
return UnsignedInteger6DataType.dataType.clone(getDataTypeManager());
}
public DataType clone(DataTypeManager dtm) {
@Override
public Integer6DataType clone(DataTypeManager dtm) {
if (dtm == getDataTypeManager()) {
return this;
}

View file

@ -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.
@ -31,20 +30,23 @@ public class Integer7DataType extends AbstractIntegerDataType {
super("int7", true, dtm);
}
@Override
public String getDescription() {
return "Signed 7-Byte Integer";
}
@Override
public int getLength() {
return 7;
}
@Override
public DataType getOppositeSignednessDataType() {
return UnsignedInteger7DataType.dataType;
public UnsignedInteger7DataType getOppositeSignednessDataType() {
return UnsignedInteger7DataType.dataType.clone(getDataTypeManager());
}
public DataType clone(DataTypeManager dtm) {
@Override
public Integer7DataType clone(DataTypeManager dtm) {
if (dtm == getDataTypeManager()) {
return this;
}

View file

@ -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.
@ -45,6 +44,7 @@ public class IntegerDataType extends AbstractIntegerDataType {
/**
* @see ghidra.program.model.data.DataType#getLength()
*/
@Override
public int getLength() {
return getDataOrganization().getIntegerSize();
}
@ -53,6 +53,7 @@ public class IntegerDataType extends AbstractIntegerDataType {
*
* @see ghidra.program.model.data.DataType#getDescription()
*/
@Override
public String getDescription() {
return "Signed Integer (compiler-specific size)";
}
@ -63,11 +64,12 @@ public class IntegerDataType extends AbstractIntegerDataType {
}
@Override
public DataType getOppositeSignednessDataType() {
public UnsignedIntegerDataType getOppositeSignednessDataType() {
return UnsignedIntegerDataType.dataType.clone(getDataTypeManager());
}
public DataType clone(DataTypeManager dtm) {
@Override
public IntegerDataType clone(DataTypeManager dtm) {
if (dtm == getDataTypeManager()) {
return this;
}

View file

@ -0,0 +1,34 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.program.model.data;
public interface InternalDataTypeComponent extends DataTypeComponent {
/**
* Sets the DataType for this component
* @param dataType the new DataType for this component
*/
public void setDataType(DataType dataType);
/**
* Update component ordinal, offset and length during alignment
* @param ordinal
* @param offset
* @param length
*/
void update(int ordinal, int offset, int length);
}

View file

@ -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.
@ -37,6 +36,7 @@ public class LongDataType extends AbstractIntegerDataType {
/**
* @see ghidra.program.model.data.DataType#getLength()
*/
@Override
public int getLength() {
return getDataOrganization().getLongSize();
}
@ -53,6 +53,7 @@ public class LongDataType extends AbstractIntegerDataType {
*
* @see ghidra.program.model.data.DataType#getDescription()
*/
@Override
public String getDescription() {
return "Signed Long Integer (compiler-specific size)";
}
@ -63,11 +64,12 @@ public class LongDataType extends AbstractIntegerDataType {
}
@Override
public DataType getOppositeSignednessDataType() {
public UnsignedLongDataType getOppositeSignednessDataType() {
return UnsignedLongDataType.dataType.clone(getDataTypeManager());
}
public DataType clone(DataTypeManager dtm) {
@Override
public LongDataType clone(DataTypeManager dtm) {
if (dtm == getDataTypeManager()) {
return this;
}

View file

@ -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.
@ -37,6 +36,7 @@ public class LongLongDataType extends AbstractIntegerDataType {
/**
* @see ghidra.program.model.data.DataType#getLength()
*/
@Override
public int getLength() {
return getDataOrganization().getLongLongSize();
}
@ -53,6 +53,7 @@ public class LongLongDataType extends AbstractIntegerDataType {
*
* @see ghidra.program.model.data.DataType#getDescription()
*/
@Override
public String getDescription() {
return "Signed Long Long Integer (compiler-specific size)";
}
@ -63,11 +64,12 @@ public class LongLongDataType extends AbstractIntegerDataType {
}
@Override
public DataType getOppositeSignednessDataType() {
public UnsignedLongLongDataType getOppositeSignednessDataType() {
return UnsignedLongLongDataType.dataType.clone(getDataTypeManager());
}
public DataType clone(DataTypeManager dtm) {
@Override
public LongLongDataType clone(DataTypeManager dtm) {
if (dtm == getDataTypeManager()) {
return this;
}

View file

@ -72,6 +72,7 @@ public class MissingBuiltInDataType extends DataTypeImpl implements Dynamic {
/* (non-Javadoc)
* @see ghidra.program.model.data.DataType#getMnemonic(ghidra.program.model.data.Settings)
*/
@Override
public String getMnemonic(Settings settings) {
return getName();
}
@ -79,6 +80,7 @@ public class MissingBuiltInDataType extends DataTypeImpl implements Dynamic {
/* (non-Javadoc)
* @see ghidra.program.model.data.DataType#getLength()
*/
@Override
public int getLength() {
return -1;
}
@ -86,10 +88,12 @@ public class MissingBuiltInDataType extends DataTypeImpl implements Dynamic {
/**
* @see ghidra.program.model.data.DataType#isDynamicallySized()
*/
@Override
public boolean isDynamicallySized() {
return true;
}
@Override
public boolean canSpecifyLength() {
return true;
}
@ -97,6 +101,7 @@ public class MissingBuiltInDataType extends DataTypeImpl implements Dynamic {
/**
* @see ghidra.program.model.data.Dynamic#getLength(ghidra.program.model.mem.MemBuffer, int)
*/
@Override
public int getLength(MemBuffer buf, int maxLength) {
return -1;
}
@ -104,6 +109,7 @@ public class MissingBuiltInDataType extends DataTypeImpl implements Dynamic {
/* (non-Javadoc)
* @see ghidra.program.model.data.DataType#getDescription()
*/
@Override
public String getDescription() {
return "Missing Built-In Data Type: " + missingBuiltInClassPath;
}
@ -111,6 +117,7 @@ public class MissingBuiltInDataType extends DataTypeImpl implements Dynamic {
/* (non-Javadoc)
* @see ghidra.program.model.data.DataType#getRepresentation(ghidra.program.model.mem.MemBuffer, ghidra.program.model.lang.ProcessorContext, ghidra.program.model.data.Settings, int)
*/
@Override
public String getRepresentation(MemBuffer buf, Settings settings, int length) {
return missingBuiltInClassPath;
}
@ -118,41 +125,50 @@ public class MissingBuiltInDataType extends DataTypeImpl implements Dynamic {
/* (non-Javadoc)
* @see ghidra.program.model.data.DataType#getValue(ghidra.program.model.mem.MemBuffer, ghidra.program.model.lang.ProcessorContext, ghidra.program.model.data.Settings, int)
*/
@Override
public Object getValue(MemBuffer buf, Settings settings, int length) {
return missingBuiltInClassPath;
}
@Override
public DataType clone(DataTypeManager dtm) {
if (dtm == getDataTypeManager()) {
return this;
}
return new MissingBuiltInDataType(categoryPath, missingBuiltInName,
missingBuiltInClassPath, dtm);
return new MissingBuiltInDataType(categoryPath, missingBuiltInName, missingBuiltInClassPath,
dtm);
}
/**
* @see ghidra.program.model.data.DataType#copy(ghidra.program.model.data.DataTypeManager)
*/
@Override
public final DataType copy(DataTypeManager dtm) {
return clone(dtm);
}
@Override
public void dataTypeDeleted(DataType dt) {
}
@Override
public void dataTypeNameChanged(DataType dt, String oldName) {
}
@Override
public void dataTypeReplaced(DataType oldDt, DataType newDt) {
}
@Override
public void dataTypeSizeChanged(DataType dt) {
}
@Override
public boolean dependsOn(DataType dt) {
return false;
}
@Override
public boolean isEquivalent(DataType dt) {
if (dt == null) {
return false;
@ -163,17 +179,21 @@ public class MissingBuiltInDataType extends DataTypeImpl implements Dynamic {
if (!(dt instanceof MissingBuiltInDataType)) {
return false;
}
return missingBuiltInClassPath.equals(((MissingBuiltInDataType) dt).missingBuiltInClassPath);
return missingBuiltInClassPath.equals(
((MissingBuiltInDataType) dt).missingBuiltInClassPath);
}
@Override
public void setCategoryPath(CategoryPath path) throws DuplicateNameException {
}
public void setName(String name) throws InvalidNameException, DuplicateNameException {
@Override
public void setName(String name) throws InvalidNameException {
}
public void setNameAndCategory(CategoryPath path, String name) throws InvalidNameException,
DuplicateNameException {
@Override
public void setNameAndCategory(CategoryPath path, String name)
throws InvalidNameException, DuplicateNameException {
}
@Override
@ -184,10 +204,12 @@ public class MissingBuiltInDataType extends DataTypeImpl implements Dynamic {
/**
* @see ghidra.program.model.data.BuiltInDataType#getCTypeDeclaration(ghidra.program.model.data.DataOrganization)
*/
@Override
public String getCTypeDeclaration(DataOrganization dataOrganization) {
return null; // missing type
}
@Override
public DataType getReplacementBaseType() {
return null;
}

View file

@ -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.
@ -34,10 +33,12 @@ public class QWordDataType extends AbstractIntegerDataType {
super("qword", false, dtm);
}
@Override
public String getDescription() {
return "Unsigned Quad-Word (dq, 8-bytes)";
}
@Override
public int getLength() {
return 8;
}
@ -48,11 +49,12 @@ public class QWordDataType extends AbstractIntegerDataType {
}
@Override
public DataType getOppositeSignednessDataType() {
return SignedQWordDataType.dataType;
public SignedQWordDataType getOppositeSignednessDataType() {
return SignedQWordDataType.dataType.clone(getDataTypeManager());
}
public DataType clone(DataTypeManager dtm) {
@Override
public QWordDataType clone(DataTypeManager dtm) {
if (dtm == getDataTypeManager()) {
return this;
}

View file

@ -78,6 +78,19 @@ public class ReadOnlyDataTypeComponent implements DataTypeComponent, Serializabl
return false; // Unsupported use
}
@Override
public boolean isBitFieldComponent() {
return dataType instanceof BitFieldDataType;
}
@Override
public boolean isZeroBitFieldComponent() {
if (dataType instanceof BitFieldDataType) {
return ((BitFieldDataType) dataType).getBitSize() == 0;
}
return false;
}
/**
* @see ghidra.program.model.data.DataTypeComponent#getOffset()
*/

View file

@ -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.
@ -37,6 +36,7 @@ public class ShortDataType extends AbstractIntegerDataType {
/**
* @see ghidra.program.model.data.DataType#getLength()
*/
@Override
public int getLength() {
return getDataOrganization().getShortSize();
}
@ -53,6 +53,7 @@ public class ShortDataType extends AbstractIntegerDataType {
*
* @see ghidra.program.model.data.DataType#getDescription()
*/
@Override
public String getDescription() {
return "Signed Short Integer (compiler-specific size)";
}
@ -63,11 +64,12 @@ public class ShortDataType extends AbstractIntegerDataType {
}
@Override
public DataType getOppositeSignednessDataType() {
public UnsignedShortDataType getOppositeSignednessDataType() {
return UnsignedShortDataType.dataType.clone(getDataTypeManager());
}
public DataType clone(DataTypeManager dtm) {
@Override
public ShortDataType clone(DataTypeManager dtm) {
if (dtm == getDataTypeManager()) {
return this;
}

View file

@ -35,10 +35,12 @@ public class SignedByteDataType extends AbstractIntegerDataType {
super("sbyte", true, dtm);
}
@Override
public String getDescription() {
return "Signed Byte (sdb)";
}
@Override
public int getLength() {
return 1;
}
@ -56,11 +58,12 @@ public class SignedByteDataType extends AbstractIntegerDataType {
}
@Override
public DataType getOppositeSignednessDataType() {
return ByteDataType.dataType;
public ByteDataType getOppositeSignednessDataType() {
return ByteDataType.dataType.clone(getDataTypeManager());
}
public DataType clone(DataTypeManager dtm) {
@Override
public SignedByteDataType clone(DataTypeManager dtm) {
if (dtm == getDataTypeManager()) {
return this;
}

View file

@ -43,7 +43,10 @@ public class SignedCharDataType extends CharDataType {
}
@Override
public DataType clone(DataTypeManager dtm) {
public SignedCharDataType clone(DataTypeManager dtm) {
if (dtm == getDataTypeManager()) {
return this;
}
return new SignedCharDataType(dtm);
}

View file

@ -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.
@ -34,10 +33,12 @@ public class SignedDWordDataType extends AbstractIntegerDataType {
super("sdword", true, dtm);
}
@Override
public String getDescription() {
return "Signed Double-Word (sddw, 4-bytes)";
}
@Override
public int getLength() {
return 4;
}
@ -48,11 +49,12 @@ public class SignedDWordDataType extends AbstractIntegerDataType {
}
@Override
public DataType getOppositeSignednessDataType() {
return DWordDataType.dataType;
public DWordDataType getOppositeSignednessDataType() {
return DWordDataType.dataType.clone(getDataTypeManager());
}
public DataType clone(DataTypeManager dtm) {
@Override
public SignedDWordDataType clone(DataTypeManager dtm) {
if (dtm == getDataTypeManager()) {
return this;
}

View file

@ -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.
@ -34,10 +33,12 @@ public class SignedQWordDataType extends AbstractIntegerDataType {
super("sqword", true, dtm);
}
@Override
public String getDescription() {
return "Signed Quad-Word (sdq, 8-bytes)";
}
@Override
public int getLength() {
return 8;
}
@ -48,11 +49,12 @@ public class SignedQWordDataType extends AbstractIntegerDataType {
}
@Override
public DataType getOppositeSignednessDataType() {
return QWordDataType.dataType;
public QWordDataType getOppositeSignednessDataType() {
return QWordDataType.dataType.clone(getDataTypeManager());
}
public DataType clone(DataTypeManager dtm) {
@Override
public SignedQWordDataType clone(DataTypeManager dtm) {
if (dtm == getDataTypeManager()) {
return this;
}

View file

@ -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.
@ -34,10 +33,12 @@ public class SignedWordDataType extends AbstractIntegerDataType {
super("sword", true, dtm);
}
@Override
public String getDescription() {
return "Signed Word (sdw, 2-bytes)";
}
@Override
public int getLength() {
return 2;
}
@ -48,11 +49,12 @@ public class SignedWordDataType extends AbstractIntegerDataType {
}
@Override
public DataType getOppositeSignednessDataType() {
return WordDataType.dataType;
public WordDataType getOppositeSignednessDataType() {
return WordDataType.dataType.clone(getDataTypeManager());
}
public DataType clone(DataTypeManager dtm) {
@Override
public SignedWordDataType clone(DataTypeManager dtm) {
if (dtm == getDataTypeManager()) {
return this;
}

View file

@ -15,14 +15,20 @@
*/
package ghidra.program.model.data;
import java.util.Comparator;
import ghidra.util.exception.InvalidInputException;
/**
* The structure interface.
*
* <p>
* NOTE: Structures containing only a flexible array will report a length of 1
* which will result in improper code unit sizing since we are unable to support a
* defined data of length 0.
* <p>
* NOTE: The use of zero-length bitfields within unaligned structures is discouraged since
* they have no real affect and are easily misplaced. Their use should be reserved for
* aligned/packed structures.
*/
public interface Structure extends Composite {
@ -41,7 +47,9 @@ public interface Structure extends Composite {
/**
* Gets the immediate child component that contains the byte
* at the given offset.
* at the given offset. If the specified offset corresponds to
* a bit-field,the first bit-field component containing the offset
* will be returned.
* @param offset the byte offset into this data type
* @return the immediate child component.
*/
@ -50,71 +58,71 @@ public interface Structure extends Composite {
/**
* Returns the primitive Data Type that is at this offset. This is useful
* for prototypes that have components that are made up of other components
* If the specified offset corresponds to
* a bit-field,the BitFieldDataType of the first bit-field component containing
* the offset will be returned.
* @param offset the byte offset into this data type.
* @return the primitive data type at the offset.
*/
public abstract DataTypeComponent getDataTypeAt(int offset);
/**
*
* @see ghidra.program.model.data.Composite#add(ghidra.program.model.data.DataType)
* Inserts a new bitfield at the specified location in this composite.
* This method is intended to be used with unaligned structures where
* the bitfield will be precisely placed. Within an aligned structure the specified
* byteOffset, byteWidth and bitOffset will be used to identify the appropriate ordinal
* but may not be preserved. The component length will be computed
* based upon the specified parameters and will be reduced from byteWidth to
* its minimal size for the new component.
* <p>
* For unaligned mode, a component shift will only occur if the bitfield placement
* conflicts with another component. If no conflict occurs, the bitfield will be placed
* at the specified location consuming any DEFAULT components as needed. When a conflict
* does occur a shift will be performed at the point of conflict based upon the specified
* byteWidth. When located onto existing bitfields they will be packed together
* provided they do not conflict, otherwise the conflict rule above applies.
* <p>
* Supported packing for little-endian fills lsb first, whereas big-endian fills msb first.
* Insertion behavior may not work as expected if packing rules differ from this.
* <p>
* Zero length bitfields may be inserted although they have no real affect for
* unaligned structures. Only the resulting byte offset within the structure
* is of significance in 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.
* @param byteWidth the storage unit width which contains the bitfield. Must be large
* enough to contain the specified bitSize and corresponding bitOffset. The actual
* component size used will be recomputed during insertion.
* @param bitOffset corresponds to the bitfield left-shift amount with the storage
* unit when viewed as big-endian. The final offset may be reduced based upon
* the minimal storage size determined during insertion.
* @param baseDataType the bitfield base datatype (certain restrictions apply).
* @param componentName the field name to associate with this component.
* @param bitSize the bitfield size in bits. A bitSize of 0 may be specified
* although its name will be ignored.
* @param comment the comment to associate with this component.
* @return the componentDataType created whose associated data type will
* be BitFieldDataType.
* @throws InvalidDataTypeException if the specified data type is
* not a valid base type for bitfields.
*/
@Override
public DataTypeComponent add(DataType dataType);
public DataTypeComponent insertBitFieldAt(int byteOffset, int byteWidth, int bitOffset,
DataType baseDataType, int bitSize, String componentName, String comment)
throws InvalidDataTypeException;
/**
*
* @see ghidra.program.model.data.Composite#add(ghidra.program.model.data.DataType, int)
*/
@Override
public DataTypeComponent add(DataType dataType, int length);
/**
*
* @see ghidra.program.model.data.Composite#add(ghidra.program.model.data.DataType, int, java.lang.String, java.lang.String)
*/
@Override
public DataTypeComponent add(DataType dataType, int length, String name, String comment);
/**
*
* @see ghidra.program.model.data.Composite#insert(int, ghidra.program.model.data.DataType)
*/
@Override
public DataTypeComponent insert(int index, DataType dataType);
/**
*
* @see ghidra.program.model.data.Composite#insert(int, ghidra.program.model.data.DataType, int)
*/
@Override
public DataTypeComponent insert(int index, DataType dataType, int length);
/**
*
* @see ghidra.program.model.data.Composite#insert(int, ghidra.program.model.data.DataType, int, java.lang.String, java.lang.String)
*/
@Override
public DataTypeComponent insert(int index, DataType dataType, int length, String name,
String comment);
public void insert(int ordinal, DataType dataType, int length, String name, String comment,
int numCopies);
/**
* Deletes the ComponentDataType at the given index
* @param index the index of the component to be deleted.
*/
@Override
public void delete(int index);
/**
* Inserts a new datatype at the specified offset into this structure.
* Inserts a new datatype at the specified offset into this structure.
* Inserting a component will causing any conflicting component
* to shift down to the extent necessary to avoid a conflict.
* @param offset the byte offset into the structure where the new datatype is to be inserted.
* @param dataType the datatype to insert.
* @param length the length to associate with the dataType.
* For fixed length types a length &lt;= 0 will use the length of the resolved dataType.
* @return the componentDataType created.
* @throws IllegalArgumentException if the specified data type is not
* allowed to be inserted into this composite data type.
* allowed to be inserted into this composite data type or an invalid length
* is specified.
* For example, suppose dt1 contains dt2. Therefore it is not valid
* to insert dt1 to dt2 since this would cause a cyclic dependency.
*/
@ -122,16 +130,17 @@ public interface Structure extends Composite {
/**
* Inserts a new datatype at the specified offset into this structure.
* Inserting a component will causing any conflicting component
* to shift down to the extent necessary to avoid a conflict.
* @param offset the byte offset into the structure where the new datatype is to be inserted.
* @param dataType the datatype to insert.
* @param length the length to associate with the dataType;
* @param length the length to associate with the dataType.
* For fixed length types a length &lt;= 0 will use the length of the resolved dataType.
* @param name the field name to associate with this component.
* @param comment the comment to associate with this component.
* @return the componentDataType created.
* @throws IllegalArgumentException if the dataType.getLength() is positive
* and does not match the given length parameter.
* @throws IllegalArgumentException if the specified data type is not
* allowed to be inserted into this composite data type.
* allowed to be inserted into this composite data type or an invalid length is specified.
* For example, suppose dt1 contains dt2. Therefore it is not valid
* to insert dt1 to dt2 since this would cause a cyclic dependency.
*/
@ -139,7 +148,9 @@ public interface Structure extends Composite {
String comment);
/**
* Deletes the datatype at the specified offset in this structure.
* Deletes the component containing the specified offset in this structure. If the offset
* corresponds to a bit-field, all bit-fields whose base type group contains the offset will
* be removed.
* @param offset the byte offset into the structure where the datatype is to be deleted.
*/
public void deleteAtOffset(int offset);
@ -152,10 +163,11 @@ public interface Structure extends Composite {
public void deleteAll();
/**
* clears the defined component at the given component index. Clearing a
* Clears the defined component at the given component index. Clearing a
* component causes a defined component to be replaced with a number of
* undefined dataTypes to offset the removal of the defined dataType.
* @param index the index of the component to clear.
* @throws ArrayIndexOutOfBoundsException if component ordinal is out of bounds
*/
public void clearComponent(int index);
@ -164,13 +176,17 @@ public interface Structure extends Composite {
* of the indicated data type.
* @param index the index where the datatype is to be replaced.
* @param dataType the datatype to insert.
* @param length the length of the dataType to insert
* @param length the length of the dataType to insert.
* For fixed length types a length &lt;= 0 will use the length of the resolved dataType.
* @return the new componentDataType at the index.
* @throws IllegalArgumentException if the specified data type is not
* allowed to replace a component in this composite data type.
* allowed to replace a component in this composite data type or an invalid
* length is specified.
* For example, suppose dt1 contains dt2. Therefore it is not valid
* to replace a dt2 component with dt1 since this would cause a cyclic
* dependency.
* dependency. In addition, any attempt to replace an existing bit-field
* component or specify a {@link BitFieldDatatype} will produce this error.
* @throws ArrayIndexOutOfBoundsException if component index is out of bounds
*/
public DataTypeComponent replace(int index, DataType dataType, int length);
@ -179,38 +195,44 @@ public interface Structure extends Composite {
* of the indicated data type.
* @param index the index where the datatype is to be replaced.
* @param dataType the datatype to insert.
* @param length the length to associate with the dataType;
* @param length the length to associate with the dataType.
* For fixed length types a length &lt;= 0 will use the length of the resolved dataType.
* @param name the field name to associate with this component.
* @param comment the comment to associate with this component.
* @return the new componentDataType at the index.
* @throws IllegalArgumentException if the dataType.getLength() is positive
* and does not match the given length parameter.
* @throws IllegalArgumentException if the specified data type is not
* allowed to replace a component in this composite data type.
* allowed to replace a component in this composite data type or an invalid
* length is specified.
* For example, suppose dt1 contains dt2. Therefore it is not valid
* to replace a dt2 component with dt1 since this would cause a cyclic
* dependency.
* dependency. In addition, any attempt to replace an existing bit-field
* component or specify a {@link BitFieldDatatype} will produce this error.
* @throws ArrayIndexOutOfBoundsException if component index is out of bounds
*/
public DataTypeComponent replace(int index, DataType dataType, int length, String name,
String comment);
/**
* Replaces the component at the specified byte offset with a new component
* of the indicated data type.
* of the indicated data type. If the offset corresponds to a bit-field, all bit-fields
* at that offset will be removed and replaced by the specified component. Keep in mind
* bit-field or any component removal must clear sufficient space for an unaligned
* structure to complete the replacement.
* @param offset the byte offset into the structure where the datatype is
* to be replaced.
* @param dataType the datatype to insert.
* @param length the length to associate with the dataType;
* @param length the length to associate with the dataType.
* For fixed length types a length &lt;= 0 will use the length of the resolved dataType.
* @param name the field name to associate with this component.
* @param comment the comment to associate with this component.
* @return the new componentDataType at the index.
* @throws IllegalArgumentException if the dataType.getLength() is positive
* and does not match the given length parameter.
* @throws IllegalArgumentException if the specified data type is not
* allowed to replace a component in this composite data type.
* allowed to replace a component in this composite data type or an invalid
* length is specified.
* For example, suppose dt1 contains dt2. Therefore it is not valid
* to replace a dt2 component with dt1 since this would cause a cyclic
* dependency.
* dependency. In addition, any attempt to replace an existing bit-field
* component or specify a {@link BitFieldDatatype} will produce this error.
*/
public DataTypeComponent replaceAtOffset(int offset, DataType dataType, int length, String name,
String comment);
@ -284,4 +306,128 @@ public interface Structure extends Composite {
public void pack(int maxAlignment) throws InvalidInputException;
/**
* <code>BitOffsetComparator</code> provides ability to compare an Integer bit offset
* with a DataTypeComponent object. The offset will be consider equal (0) if
* the component contains the offset. Bit offsets for this comparator number the
* msb of the first byte in the structure as 0 and the lsb of the last byte as
* (8 * structLength) - 1. Due to the storage order of bitfields within little-endian
* organization a normalized bit-offset must be used which corresponds to the msb getting
* filled first (in reality little-endian fills the lsb first).
*/
public static class BitOffsetComparator implements Comparator<Object> {
private boolean bigEndian;
public BitOffsetComparator(boolean bigEndian) {
this.bigEndian = bigEndian;
}
@Override
public int compare(Object o1, Object o2) {
if (o1 instanceof Integer) {
return -compare(o2, o1);
}
DataTypeComponent dtc = (DataTypeComponent) o1;
int bitOffset = ((Integer) o2).intValue();
int startBit, endBit;
if (dtc.isBitFieldComponent()) {
BitFieldDataType bitfield = (BitFieldDataType) dtc.getDataType();
startBit = getNormalizedBitfieldOffset(dtc.getOffset(), dtc.getLength(),
bitfield.getBitSize(), bitfield.getBitOffset(), bigEndian);
endBit = startBit + bitfield.getBitSize() - 1;
}
else {
startBit = 8 * dtc.getOffset();
endBit = startBit + (8 * dtc.getLength()) - 1;
}
if (bitOffset < startBit) {
return 1;
}
if (bitOffset > endBit) {
return -1;
}
return 0;
}
/**
* Compute the normalize bit offset of a bitfield relative to the start of a structure where
* the lsb of a bit-field is assigned an offset smaller than the msb.
* @param byteOffset byte offset within structure of storage unit
* @param storageSize storage unit size (i.e., component length)
* @param effectiveBitSize size of bitfield in bits
* @param bitOffset left shift amount for bitfield based upon a big-endian view of the
* storage unit
* @param bigEndian true if big-endian packing applies
* @return normalized bit-offset
*/
public static int getNormalizedBitfieldOffset(int byteOffset, int storageSize,
int effectiveBitSize, int bitOffset, boolean bigEndian) {
int offset = (8 * byteOffset);
if (effectiveBitSize == 0) {
// force zero-length bitfield placement
effectiveBitSize = 1;
if (bigEndian) {
bitOffset |= 7;
}
else {
bitOffset &= 0xfffffff8;
}
}
if (bigEndian) {
offset += (8 * storageSize) - effectiveBitSize - bitOffset;
}
else {
offset += bitOffset;
}
return offset;
}
}
/**
* <code>OffsetComparator</code> provides ability to compare an Integer offset
* with a DataTypeComponent object. The offset will be consider equal (0) if
* the component contains the offset.
*/
public static class OffsetComparator implements Comparator<Object> {
@Override
public int compare(Object o1, Object o2) {
if (o1 instanceof Integer) {
return -compare(o2, o1);
}
DataTypeComponent dtc = (DataTypeComponent) o1;
int offset = ((Integer) o2).intValue();
if (offset < dtc.getOffset()) {
return 1;
}
else if (offset > dtc.getEndOffset()) {
return -1;
}
return 0;
}
}
/**
* <code>OrdinalComparator</code> provides ability to compare an Integer ordinal
* with a DataTypeComponent object. The offset will be consider equal (0) if
* the component corresponds to the specified ordinal.
*/
public static class OrdinalComparator implements Comparator<Object> {
@Override
public int compare(Object o1, Object o2) {
if (o1 instanceof Integer) {
return -compare(o2, o1);
}
DataTypeComponent dtc = (DataTypeComponent) o1;
int ordinal = ((Integer) o2).intValue();
return dtc.getOrdinal() - ordinal;
}
}
}

View file

@ -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.
@ -17,51 +16,8 @@
package ghidra.program.model.data;
/**
* The union interface
* The Union marker interface
*/
public interface Union extends Composite {
/**
*
* @see ghidra.program.model.data.Composite#add(ghidra.program.model.data.DataType)
*/
public DataTypeComponent add(DataType dataType);
/**
* @see ghidra.program.model.data.Composite#add(ghidra.program.model.data.DataType, int)
*/
public DataTypeComponent add(DataType dataType, int length);
/**
* @see ghidra.program.model.data.Composite#add(ghidra.program.model.data.DataType, int, java.lang.String, java.lang.String)
*/
public DataTypeComponent add(DataType dataType, int length, String name, String comment);
/**
* @see ghidra.program.model.data.Composite#insert(int, ghidra.program.model.data.DataType)
*/
public DataTypeComponent insert(int ordinal, DataType dataType);
/**
* @see ghidra.program.model.data.Composite#insert(int, ghidra.program.model.data.DataType, int)
*/
public DataTypeComponent insert(int ordinal, DataType dataType, int length);
/**
* @see ghidra.program.model.data.Composite#insert(int, ghidra.program.model.data.DataType, int, java.lang.String, java.lang.String)
*/
public DataTypeComponent insert(int ordinal, DataType dataType, int length, String name,
String comment);
/**
*
* @see ghidra.program.model.data.Composite#delete(int)
*/
public void delete(int ordinal);
/**
*
* @see ghidra.program.model.data.Composite#getComponents()
*/
public abstract DataTypeComponent[] getComponents();
}

View file

@ -21,13 +21,14 @@ 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;
import ghidra.util.UniversalID;
/**
* Basic implementation of the union data type
*/
public class UnionDataType extends CompositeDataTypeImpl implements Union {
private ArrayList<DataTypeComponent> components;
private ArrayList<DataTypeComponentImpl> components;
private int unionLength;
/**
@ -68,9 +69,6 @@ public class UnionDataType extends CompositeDataTypeImpl implements Union {
this(CategoryPath.ROOT, name);
}
/* (non-Javadoc)
* @see ghidra.program.model.data.DataType#getRepresentation(ghidra.program.model.mem.MemBuffer, ghidra.util.settings.Settings, int)
*/
@Override
public String getRepresentation(MemBuffer buf, Settings settings, int length) {
if (isNotYetDefined()) {
@ -84,111 +82,141 @@ public class UnionDataType extends CompositeDataTypeImpl implements Union {
return components.size() == 0;
}
/**
*
* @see ghidra.program.model.data.Composite#getComponent(int)
*/
@Override
public DataTypeComponent getComponent(int ordinal) {
return components.get(ordinal);
}
/**
*
* @see ghidra.program.model.data.Composite#getComponents()
*/
@Override
public DataTypeComponent[] getComponents() {
return components.toArray(new DataTypeComponent[components.size()]);
}
/**
*
* @see ghidra.program.model.data.Composite#getNumComponents()
*/
@Override
public int getNumComponents() {
return components.size();
}
/**
*
* @see ghidra.program.model.data.Composite#add(ghidra.program.model.data.DataType, int, java.lang.String, java.lang.String)
*/
@Override
public DataTypeComponent add(DataType dataType, int length, String componentName,
String comment) {
int oldLength = unionLength;
DataTypeComponent dtc = doAdd(dataType, length, componentName, comment);
adjustInternalAlignment();
if (oldLength != unionLength) {
notifySizeChanged();
}
adjustLength(true);
return dtc;
}
private int getBitFieldAllocation(BitFieldDataType bitfieldDt) {
BitFieldPacking bitFieldPacking = getBitFieldPacking();
if (bitFieldPacking.useMSConvention()) {
return bitfieldDt.getBaseTypeSize();
}
if (bitfieldDt.getBitSize() == 0) {
return 0;
}
int length = bitfieldDt.getBaseTypeSize();
int packValue = getPackingValue();
if (packValue != NOT_PACKING && length > packValue) {
length =
DataOrganizationImpl.getLeastCommonMultiple(bitfieldDt.getStorageSize(), packValue);
}
return length;
}
DataTypeComponent doAdd(DataType dataType, int length, String componentName, String comment) {
validateDataType(dataType);
dataType = dataType.clone(getDataTypeManager());
checkAncestry(dataType);
if (length < 1) {
throw new IllegalArgumentException("Length must be >= 1!");
}
length = getPreferredComponentLength(dataType, length);
dataType = dataType.clone(getDataTypeManager());
// TODO Is this the right place to adjust the length?
int dtLength = dataType.getLength();
if (dtLength > 0 && dtLength < length) {
length = dtLength;
}
DataTypeComponent dtc = new DataTypeComponentImpl(dataType, this, length, components.size(),
0, componentName, comment);
DataTypeComponentImpl dtc = new DataTypeComponentImpl(dataType, this, length,
components.size(), 0, componentName, comment);
dataType.addParent(this);
components.add(dtc);
unionLength = Math.max(unionLength, length);
return dtc;
}
/**
*
* @see ghidra.program.model.data.Composite#insert(int, ghidra.program.model.data.DataType, int, java.lang.String, java.lang.String)
*/
@Override
public DataTypeComponent insert(int ordinal, DataType dataType, int length,
String componentName, String comment) {
validateDataType(dataType);
checkAncestry(dataType);
dataType = dataType.clone(getDataTypeManager());
checkAncestry(dataType);
// TODO Is this the right place to adjust the length?
int dtLength = dataType.getLength();
if (dtLength > 0 && dtLength < length) {
length = dtLength;
}
length = getPreferredComponentLength(dataType, length);
DataTypeComponent dtc =
DataTypeComponentImpl dtc =
new DataTypeComponentImpl(dataType, this, length, ordinal, 0, componentName, comment);
dataType.addParent(this);
shiftOrdinals(ordinal, 1);
components.add(ordinal, dtc);
int oldLength = unionLength;
unionLength = Math.max(unionLength, length);
adjustInternalAlignment();
if (oldLength != unionLength) {
notifySizeChanged();
}
adjustLength(true);
return dtc;
}
@Override
public DataTypeComponent insertBitField(int ordinal, int byteWidth, int bitOffset,
DataType baseDataType, int bitSize, String componentName, String comment)
throws InvalidDataTypeException, ArrayIndexOutOfBoundsException {
if (ordinal < 0 || ordinal > components.size()) {
throw new ArrayIndexOutOfBoundsException(ordinal);
}
BitFieldDataType.checkBaseDataType(baseDataType);
baseDataType = baseDataType.clone(getDataTypeManager());
if (isInternallyAligned()) {
BitFieldDataType bitFieldDt = new BitFieldDataType(baseDataType, bitSize);
return insert(ordinal, bitFieldDt, bitFieldDt.getStorageSize(), componentName, comment);
}
if (byteWidth <= 0) {
throw new IllegalArgumentException("Invalid byteWidth");
}
// TODO: How should zero-length bitfields be handled ?
// handle unaligned case - use minimal storage
// bitfield value will be forced based upon byteWidth, bitSize and endianess
boolean bigEndian = getDataOrganization().isBigEndian();
int effectiveBitSize =
BitFieldDataType.getEffectiveBitSize(bitSize, baseDataType.getLength());
int storageSize = BitFieldDataType.getMinimumStorageSize(effectiveBitSize);
if (byteWidth < storageSize) {
throw new IllegalArgumentException(
"Bitfield does not fit within specified constraints");
}
int storageBitOffset = 0;
if (bigEndian) {
storageBitOffset = (8 * storageSize) - effectiveBitSize;
}
BitFieldDataType bitfieldDt =
new BitFieldDataType(baseDataType, bitSize, storageBitOffset, storageSize);
DataTypeComponentImpl dtc = new DataTypeComponentImpl(bitfieldDt, this, storageSize,
ordinal, 0, componentName, comment);
bitfieldDt.addParent(this); // currently has no affect
shiftOrdinals(ordinal, 1);
components.add(ordinal, dtc);
adjustLength(true);
return dtc;
}
/**
*
* @see ghidra.program.model.data.DataType#getLength()
*/
@Override
public int getLength() {
if (unionLength == 0) {
@ -217,20 +245,12 @@ public class UnionDataType extends CompositeDataTypeImpl implements Union {
return union;
}
/**
* @see ghidra.program.model.data.Composite#delete(int)
*/
@Override
public void delete(int ordinal) {
int oldLength = unionLength;
DataTypeComponent dtc = components.remove(ordinal);
dtc.getDataType().removeParent(this);
shiftOrdinals(ordinal, -1);
computeUnionLength();
adjustInternalAlignment();
if (oldLength != unionLength) {
notifySizeChanged();
}
adjustLength(true);
}
@Override
@ -240,17 +260,24 @@ public class UnionDataType extends CompositeDataTypeImpl implements Union {
}
}
private void computeUnionLength() {
private void adjustLength(boolean notify) {
int oldLength = unionLength;
unionLength = 0;
for (int i = 0; i < components.size(); i++) {
unionLength = Math.max(unionLength, (components.get(i)).getLength());
for (DataTypeComponent dtc : components) {
int length = dtc.getLength();
if (isInternallyAligned() && dtc.isBitFieldComponent()) {
// revise length to reflect compiler bitfield allocation rules
length = getBitFieldAllocation((BitFieldDataType) dtc.getDataType());
}
unionLength = Math.max(length, unionLength);
}
if (notify && oldLength != unionLength) {
notifySizeChanged();
}
}
/**
*
* @see ghidra.program.model.data.DataType#isEquivalent(ghidra.program.model.data.DataType)
*/
@Override
public boolean isEquivalent(DataType dt) {
if (dt == this) {
@ -288,85 +315,109 @@ public class UnionDataType extends CompositeDataTypeImpl implements Union {
private void shiftOrdinals(int ordinal, int deltaOrdinal) {
for (int i = ordinal; i < components.size(); i++) {
DataTypeComponentImpl dtc = (DataTypeComponentImpl) components.get(i);
DataTypeComponentImpl dtc = components.get(i);
dtc.setOrdinal(dtc.getOrdinal() + deltaOrdinal);
}
}
@Override
public void dataTypeAlignmentChanged(DataType dt) {
// TODO I don't think we need to do anything here.
adjustInternalAlignment();
if (isInternallyAligned()) {
adjustInternalAlignment();
}
}
/**
* @see ghidra.program.model.data.DataType#dataTypeSizeChanged(ghidra.program.model.data.DataType)
*/
@Override
public void dataTypeSizeChanged(DataType dt) {
int oldLength = unionLength;
unionLength = 0;
for (int i = 0; i < components.size(); i++) {
DataTypeComponentImpl dtc = (DataTypeComponentImpl) components.get(i);
DataType tmpDt = dtc.getDataType();
int tmpLen = tmpDt.getLength();
if ((tmpDt.isEquivalent(dt)) && (tmpLen > 0) && (tmpLen != dtc.getLength())) {
dtc.setLength(tmpLen);
}
unionLength = Math.max(unionLength, dtc.getLength());
}
adjustInternalAlignment();
if (oldLength != unionLength) {
notifySizeChanged();
}
}
/* (non-Javadoc)
* @see ghidra.program.model.data.DataType#dataTypeReplaced(ghidra.program.model.data.DataType, ghidra.program.model.data.DataType)
*/
@Override
public void dataTypeReplaced(DataType oldDt, DataType newDt) {
try {
validateDataType(newDt);
checkAncestry(newDt);
}
catch (Exception e) {
newDt = DataType.DEFAULT;
}
int oldLength = unionLength;
unionLength = 0;
boolean changed = false;
for (int i = 0; i < components.size(); i++) {
DataTypeComponentImpl dtc = (DataTypeComponentImpl) components.get(i);
if (dtc.getDataType() == oldDt) {
oldDt.removeParent(this);
dtc.setDataType(newDt);
newDt.addParent(this);
int len = newDt.getLength();
if (len > 0) {
dtc.setLength(len);
}
for (DataTypeComponentImpl dtc : components) {
int length = dtc.getLength();
if (dtc.getDataType() == dt) {
length = getPreferredComponentLength(dt, length);
dtc.setLength(length);
changed = true;
}
}
if (changed) {
computeUnionLength();
adjustInternalAlignment();
if (oldLength != unionLength) {
notifySizeChanged();
}
adjustLength(true);
}
}
@Override
public void dataTypeReplaced(DataType oldDt, DataType newDt) {
DataType replacementDt = newDt;
try {
validateDataType(replacementDt);
if (replacementDt.getDataTypeManager() != dataMgr) {
replacementDt = replacementDt.clone(dataMgr);
}
checkAncestry(replacementDt);
}
catch (Exception e) {
// TODO: should we use Undefined instead since we do not support
// DEFAULT in Unions
replacementDt = DataType.DEFAULT;
}
boolean changed = false;
for (int i = components.size() - 1; i >= 0; i--) {
DataTypeComponentImpl dtc = components.get(i);
boolean remove = false;
if (dtc.isBitFieldComponent()) {
try {
changed |= updateBitFieldDataType(dtc, oldDt, replacementDt);
}
catch (InvalidDataTypeException e) {
Msg.error(this,
"Invalid bitfield replacement type " + newDt.getName() +
", removing bitfield " + dtc.getDataType().getName() + ": " +
getPathName());
remove = true;
}
}
else if (dtc.getDataType() == oldDt) {
if (replacementDt == DEFAULT) {
Msg.error(this,
"Invalid replacement type " + newDt.getName() + ", removing component " +
dtc.getDataType().getName() + ": " + getPathName());
remove = true;
}
else {
oldDt.removeParent(this);
dtc.setDataType(replacementDt);
replacementDt.addParent(this);
int len = replacementDt.getLength();
if (len > 0) {
dtc.setLength(len);
}
changed = true;
}
}
if (remove) {
// error case - remove component
oldDt.removeParent(this);
components.remove(i);
shiftOrdinals(i, -1);
changed = true;
}
}
if (changed) {
adjustLength(true);
}
}
/**
* @see ghidra.program.model.data.DataType#dataTypeDeleted(ghidra.program.model.data.DataType)
*/
@Override
public void dataTypeDeleted(DataType dt) {
boolean didDelete = false;
for (int i = components.size() - 1; i >= 0; i--) {
DataTypeComponent dtc = components.get(i);
if (dtc.getDataType() == dt) {
for (int i = components.size() - 1; i >= 0; i--) { // reverse order
DataTypeComponentImpl dtc = components.get(i);
boolean removeBitFieldComponent = false;
if (dtc.isBitFieldComponent()) {
BitFieldDataType bitfieldDt = (BitFieldDataType) dtc.getDataType();
removeBitFieldComponent = bitfieldDt.getBaseDataType() == dt;
}
if (removeBitFieldComponent || dtc.getDataType() == dt) {
dt.removeParent(this);
components.remove(i);
shiftOrdinals(i, -1);
@ -374,12 +425,7 @@ public class UnionDataType extends CompositeDataTypeImpl implements Union {
}
}
if (didDelete) {
int oldLength = unionLength;
computeUnionLength();
adjustInternalAlignment();
if (oldLength != unionLength) {
notifySizeChanged();
}
adjustLength(true);
}
}
@ -398,48 +444,33 @@ public class UnionDataType extends CompositeDataTypeImpl implements Union {
if (!(dataType instanceof Union)) {
throw new IllegalArgumentException();
}
int oldLength = unionLength;
doReplaceWith((Union) dataType);
if (oldLength != unionLength) {
notifySizeChanged();
}
}
private void doReplaceWith(Union union) {
Iterator<DataTypeComponent> it = components.iterator();
Union union = (Union) dataType;
Iterator<DataTypeComponentImpl> it = components.iterator();
while (it.hasNext()) {
DataTypeComponent dtc = it.next();
dtc.getDataType().removeParent(this);
}
components.clear();
unionLength = 0;
setAlignment(union);
DataTypeComponent[] compArray = union.getComponents();
for (int i = 0; i < compArray.length; i++) {
DataTypeComponent dtc = compArray[i];
DataType dt = dtc.getDataType();
validateDataType(dt);
dt = dt.clone(getDataTypeManager());
int dtLength = dt.getLength();
if (dtLength <= 0) {
dtLength = dtc.getLength();
}
doAdd(dt, dtLength, dtc.getFieldName(), dtc.getComment());
doAdd(dt, dtc.getLength(), dtc.getFieldName(), dtc.getComment());
}
setDataAlignmentInfo(union);
adjustLength(true);
}
/**
* @see ghidra.program.model.data.DataType#dataTypeNameChanged(ghidra.program.model.data.DataType, java.lang.String)
*/
@Override
public void dataTypeNameChanged(DataType dt, String oldName) {
// ignored
}
/**
* @see ghidra.program.model.data.DataType#dependsOn(ghidra.program.model.data.DataType)
*/
@Override
public boolean dependsOn(DataType dt) {
if (getNumComponents() == 1) {
@ -454,33 +485,15 @@ public class UnionDataType extends CompositeDataTypeImpl implements Union {
return "UNION_" + getName();
}
public void align(DataOrganization dataOrganization) {
// TODO Auto-generated method stub
}
private void adjustLength() {
// TODO WHat should we do here?
}
@Override
public int getPackingValue() {
return packingValue;
}
@Override
public void setPackingValue(int packingValue) {
this.packingValue = packingValue;
adjustInternalAlignment();
public void realign() {
if (isInternallyAligned()) {
adjustInternalAlignment();
}
}
@Override
public void adjustInternalAlignment() {
adjustLength();
adjustLength(true);
}
@Override
public void realign() {
adjustInternalAlignment();
}
}

View file

@ -43,7 +43,10 @@ public class UnsignedCharDataType extends CharDataType {
}
@Override
public DataType clone(DataTypeManager dtm) {
public UnsignedCharDataType clone(DataTypeManager dtm) {
if (dtm == getDataTypeManager()) {
return this;
}
return new UnsignedCharDataType(dtm);
}

View file

@ -33,20 +33,23 @@ public class UnsignedInteger16DataType extends AbstractIntegerDataType {
super("uint16", false, dtm);
}
@Override
public String getDescription() {
return "Unsigned 16-Byte Integer";
}
@Override
public int getLength() {
return 16;
}
@Override
public DataType getOppositeSignednessDataType() {
return Integer16DataType.dataType;
public Integer16DataType getOppositeSignednessDataType() {
return Integer16DataType.dataType.clone(getDataTypeManager());
}
public DataType clone(DataTypeManager dtm) {
@Override
public UnsignedInteger16DataType clone(DataTypeManager dtm) {
if (dtm == getDataTypeManager()) {
return this;
}

View file

@ -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.
@ -38,20 +37,23 @@ public class UnsignedInteger3DataType extends AbstractIntegerDataType {
super("uint3", false, dtm);
}
@Override
public String getDescription() {
return "Unsigned 3-Byte Integer)";
}
@Override
public int getLength() {
return 3;
}
@Override
public DataType getOppositeSignednessDataType() {
return Integer3DataType.dataType;
public Integer3DataType getOppositeSignednessDataType() {
return Integer3DataType.dataType.clone(getDataTypeManager());
}
public DataType clone(DataTypeManager dtm) {
@Override
public UnsignedInteger3DataType clone(DataTypeManager dtm) {
if (dtm == getDataTypeManager()) {
return this;
}

View file

@ -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.
@ -31,20 +30,23 @@ public class UnsignedInteger5DataType extends AbstractIntegerDataType {
super("uint5", false, dtm);
}
@Override
public String getDescription() {
return "Unsigned 5-Byte Integer";
}
@Override
public int getLength() {
return 5;
}
@Override
public DataType getOppositeSignednessDataType() {
return Integer5DataType.dataType;
public Integer5DataType getOppositeSignednessDataType() {
return Integer5DataType.dataType.clone(getDataTypeManager());
}
public DataType clone(DataTypeManager dtm) {
@Override
public UnsignedInteger5DataType clone(DataTypeManager dtm) {
if (dtm == getDataTypeManager()) {
return this;
}

View file

@ -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.
@ -31,20 +30,23 @@ public class UnsignedInteger6DataType extends AbstractIntegerDataType {
super("uint6", false, dtm);
}
@Override
public String getDescription() {
return "Unsigned 6-Byte Integer";
}
@Override
public int getLength() {
return 6;
}
@Override
public DataType getOppositeSignednessDataType() {
return Integer6DataType.dataType;
public Integer6DataType getOppositeSignednessDataType() {
return Integer6DataType.dataType.clone(getDataTypeManager());
}
public DataType clone(DataTypeManager dtm) {
@Override
public UnsignedInteger6DataType clone(DataTypeManager dtm) {
if (dtm == getDataTypeManager()) {
return this;
}

View file

@ -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.
@ -31,20 +30,23 @@ public class UnsignedInteger7DataType extends AbstractIntegerDataType {
super("uint7", false, dtm);
}
@Override
public String getDescription() {
return "Unsigned 7-Byte Integer";
}
@Override
public int getLength() {
return 7;
}
@Override
public DataType getOppositeSignednessDataType() {
return Integer7DataType.dataType;
public Integer7DataType getOppositeSignednessDataType() {
return Integer7DataType.dataType.clone(getDataTypeManager());
}
public DataType clone(DataTypeManager dtm) {
@Override
public UnsignedInteger7DataType clone(DataTypeManager dtm) {
if (dtm == getDataTypeManager()) {
return this;
}

View file

@ -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.
@ -38,6 +37,7 @@ public class UnsignedIntegerDataType extends AbstractIntegerDataType {
*
* @see ghidra.program.model.data.DataType#getLength()
*/
@Override
public int getLength() {
return getDataOrganization().getIntegerSize();
}
@ -54,6 +54,7 @@ public class UnsignedIntegerDataType extends AbstractIntegerDataType {
*
* @see ghidra.program.model.data.DataType#getDescription()
*/
@Override
public String getDescription() {
return "Unsigned Integer (compiler-specific size)";
}
@ -64,11 +65,12 @@ public class UnsignedIntegerDataType extends AbstractIntegerDataType {
}
@Override
public DataType getOppositeSignednessDataType() {
public IntegerDataType getOppositeSignednessDataType() {
return IntegerDataType.dataType.clone(getDataTypeManager());
}
public DataType clone(DataTypeManager dtm) {
@Override
public UnsignedIntegerDataType clone(DataTypeManager dtm) {
if (dtm == getDataTypeManager()) {
return this;
}

View file

@ -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.
@ -38,6 +37,7 @@ public class UnsignedLongDataType extends AbstractIntegerDataType {
*
* @see ghidra.program.model.data.DataType#getLength()
*/
@Override
public int getLength() {
return getDataOrganization().getLongSize();
}
@ -54,6 +54,7 @@ public class UnsignedLongDataType extends AbstractIntegerDataType {
*
* @see ghidra.program.model.data.DataType#getDescription()
*/
@Override
public String getDescription() {
return "Unsigned Long Integer (compiler-specific size)";
}
@ -64,11 +65,12 @@ public class UnsignedLongDataType extends AbstractIntegerDataType {
}
@Override
public DataType getOppositeSignednessDataType() {
public LongDataType getOppositeSignednessDataType() {
return LongDataType.dataType.clone(getDataTypeManager());
}
public DataType clone(DataTypeManager dtm) {
@Override
public UnsignedLongDataType clone(DataTypeManager dtm) {
if (dtm == getDataTypeManager()) {
return this;
}

View file

@ -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.
@ -38,6 +37,7 @@ public class UnsignedLongLongDataType extends AbstractIntegerDataType {
*
* @see ghidra.program.model.data.DataType#getLength()
*/
@Override
public int getLength() {
return getDataOrganization().getLongLongSize();
}
@ -54,6 +54,7 @@ public class UnsignedLongLongDataType extends AbstractIntegerDataType {
*
* @see ghidra.program.model.data.DataType#getDescription()
*/
@Override
public String getDescription() {
return "Unsigned Long Long Integer (compiler-specific size)";
}
@ -64,11 +65,12 @@ public class UnsignedLongLongDataType extends AbstractIntegerDataType {
}
@Override
public DataType getOppositeSignednessDataType() {
public LongLongDataType getOppositeSignednessDataType() {
return LongLongDataType.dataType.clone(getDataTypeManager());
}
public DataType clone(DataTypeManager dtm) {
@Override
public UnsignedLongLongDataType clone(DataTypeManager dtm) {
if (dtm == getDataTypeManager()) {
return this;
}

View file

@ -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.
@ -38,6 +37,7 @@ public class UnsignedShortDataType extends AbstractIntegerDataType {
*
* @see ghidra.program.model.data.DataType#getLength()
*/
@Override
public int getLength() {
return getDataOrganization().getShortSize();
}
@ -54,6 +54,7 @@ public class UnsignedShortDataType extends AbstractIntegerDataType {
*
* @see ghidra.program.model.data.DataType#getDescription()
*/
@Override
public String getDescription() {
return "Unsigned Short Integer (compiler-specific size)";
}
@ -64,11 +65,12 @@ public class UnsignedShortDataType extends AbstractIntegerDataType {
}
@Override
public DataType getOppositeSignednessDataType() {
public ShortDataType getOppositeSignednessDataType() {
return ShortDataType.dataType.clone(getDataTypeManager());
}
public DataType clone(DataTypeManager dtm) {
@Override
public UnsignedShortDataType clone(DataTypeManager dtm) {
if (dtm == getDataTypeManager()) {
return this;
}

View file

@ -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.
@ -34,10 +33,12 @@ public class WordDataType extends AbstractIntegerDataType {
super("word", false, dtm);
}
@Override
public String getDescription() {
return "Unsigned Word (dw, 2-bytes)";
}
@Override
public int getLength() {
return 2;
}
@ -48,11 +49,12 @@ public class WordDataType extends AbstractIntegerDataType {
}
@Override
public DataType getOppositeSignednessDataType() {
return SignedWordDataType.dataType;
public SignedWordDataType getOppositeSignednessDataType() {
return SignedWordDataType.dataType.clone(getDataTypeManager());
}
public DataType clone(DataTypeManager dtm) {
@Override
public WordDataType clone(DataTypeManager dtm) {
if (dtm == getDataTypeManager()) {
return this;
}

View file

@ -41,7 +41,7 @@ public class BasicCompilerSpec implements CompilerSpec {
public static final String DECOMPILER_OUTPUT_LANGUAGE = "Output Language";
public final static DecompilerLanguage DECOMPILER_OUTPUT_DEF = DecompilerLanguage.C_LANGUAGE;
public final static String DECOMPILER_OUTPUT_DESC =
"Select the source language output by the decompiler.";
"Select the source language output by the decompiler.";
private static final String EVALUATION_MODEL_PROPERTY_NAME = "Prototype Evaluation";
public static final String STACK_SPACE_NAME = "stack";
@ -51,7 +51,7 @@ public class BasicCompilerSpec implements CompilerSpec {
private String sourceName;
private final SleighLanguage language;
private DataOrganizationImpl dataOrganization;
private List<ContextSetting> ctxsetting = new ArrayList<ContextSetting>();
private List<ContextSetting> ctxsetting = new ArrayList<>();
private PrototypeModel defaultModel;
private PrototypeModel defaultEvaluationModel;
private PrototypeModel[] models;
@ -62,12 +62,11 @@ public class BasicCompilerSpec implements CompilerSpec {
private AddressSpace joinSpace;
private boolean stackGrowsNegative = true;
private boolean reverseJustifyStack = false;
private Map<String, AddressSpace> spaceBases = new HashMap<String, AddressSpace>();
private Map<String, AddressSpace> spaceBases = new HashMap<>();
private PcodeInjectLibrary pcodeInject;
private AddressSet globalSet;
private LinkedHashMap<String, String> properties = new LinkedHashMap<String, String>();
private Map<String, PrototypeModel> callingConventionMap =
new HashMap<String, PrototypeModel>();
private LinkedHashMap<String, String> properties = new LinkedHashMap<>();
private Map<String, PrototypeModel> callingConventionMap = new HashMap<>();
private String[] evaluationModelChoices;
private String specString;
private ResourceFile specFile;
@ -119,7 +118,7 @@ public class BasicCompilerSpec implements CompilerSpec {
Throwable cause = e.getCause(); // Recover the cause (from the validator exception)
if (cause != null) {
if (cause instanceof SAXException || cause instanceof IOException)
parseException = (Exception)cause;
parseException = (Exception) cause;
}
}
catch (FileNotFoundException e) {
@ -137,7 +136,7 @@ public class BasicCompilerSpec implements CompilerSpec {
if (parseException != null) {
throw new CompilerSpecNotFoundException(language.getLanguageID(),
description.getCompilerSpecID(), cspecFile.getName(),parseException);
description.getCompilerSpecID(), cspecFile.getName(), parseException);
}
}
@ -155,7 +154,7 @@ public class BasicCompilerSpec implements CompilerSpec {
@SuppressWarnings("unchecked")
private void buildInjectLibrary() {
String classname =
language.getProperty(GhidraLanguagePropertyKeys.PCODE_INJECT_LIBRARY_CLASS);
language.getProperty(GhidraLanguagePropertyKeys.PCODE_INJECT_LIBRARY_CLASS);
if (classname == null) {
pcodeInject = new PcodeInjectLibrary(language); // This is the default implementation
return;
@ -163,23 +162,24 @@ public class BasicCompilerSpec implements CompilerSpec {
try {
Class<?> c = Class.forName(classname);
if (!PcodeInjectLibrary.class.isAssignableFrom(c)) {
Msg.error(this, "Language " + language.getLanguageID() +
" does not specify a valid " +
Msg.error(this,
"Language " + language.getLanguageID() + " does not specify a valid " +
GhidraLanguagePropertyKeys.PCODE_INJECT_LIBRARY_CLASS);
throw new RuntimeException(classname + " does not implement interface " +
PcodeInjectLibrary.class.getName());
PcodeInjectLibrary.class.getName());
}
Class<? extends PcodeInjectLibrary> injectLibraryClass =
(Class<? extends PcodeInjectLibrary>) c;
(Class<? extends PcodeInjectLibrary>) c;
Constructor<? extends PcodeInjectLibrary> constructor =
injectLibraryClass.getConstructor(SleighLanguage.class);
injectLibraryClass.getConstructor(SleighLanguage.class);
pcodeInject = constructor.newInstance(language);
}
catch (Exception e) {
Msg.error(this, "Language " + language.getLanguageID() + " does not specify a valid " +
GhidraLanguagePropertyKeys.PCODE_INJECT_LIBRARY_CLASS);
throw new RuntimeException("Failed to instantiate " + classname + " for language " +
language.getLanguageID(), e);
GhidraLanguagePropertyKeys.PCODE_INJECT_LIBRARY_CLASS);
throw new RuntimeException(
"Failed to instantiate " + classname + " for language " + language.getLanguageID(),
e);
}
List<InjectPayloadSleigh> additionalInject = language.getAdditionalInject();
if (additionalInject != null) {
@ -188,7 +188,7 @@ public class BasicCompilerSpec implements CompilerSpec {
}
}
}
private void addThisCallConventionIfMissing() {
boolean foundThisCall = false;
for (PrototypeModel model : models) {
@ -434,7 +434,7 @@ public class BasicCompilerSpec implements CompilerSpec {
private void restoreXml(XmlPullParser parser) throws XmlParseException {
stackPointer = null;
List<PrototypeModel> modelList = new ArrayList<PrototypeModel>();
List<PrototypeModel> modelList = new ArrayList<>();
String evalCurrentPrototype = null;
parser.start("compiler_spec");
@ -489,9 +489,9 @@ public class BasicCompilerSpec implements CompilerSpec {
}
if (stackPointer == null) {
stackSpace =
new GenericAddressSpace(STACK_SPACE_NAME, language.getDefaultSpace().getSize(),
language.getDefaultSpace().getAddressableUnitSize(), AddressSpace.TYPE_STACK, 0);
stackSpace = new GenericAddressSpace(STACK_SPACE_NAME,
language.getDefaultSpace().getSize(),
language.getDefaultSpace().getAddressableUnitSize(), AddressSpace.TYPE_STACK, 0);
}
buildModelArrays(modelList);
@ -534,22 +534,22 @@ public class BasicCompilerSpec implements CompilerSpec {
parser.end();
}
private void restoreDataOrganization(XmlPullParser parser) {
private void restoreDataOrganization(XmlPullParser parser) throws XmlParseException {
parser.start();
while (parser.peek().isStart()) {
XmlElement subel = parser.start();
String name = subel.getName();
if (name.equals("char_type")) {
String boolStr = subel.getAttribute("signed");
dataOrganization.setCharIsSigned(SpecXmlUtils.decodeBoolean(boolStr));
parser.end(subel);
continue;
}
String value = subel.getAttribute("value");
if (name.equals("absolute_max_alignment")) {
dataOrganization.setAbsoluteMaxAlignment(SpecXmlUtils.decodeInt(value));
}
@ -605,12 +605,37 @@ public class BasicCompilerSpec implements CompilerSpec {
parser.end(subsubel);
}
}
else if (name.equals("bitfield_packing")) {
dataOrganization.setBitFieldPacking(parseBitFieldPacking(parser));
}
parser.end(subel);
}
parser.end();
}
private BitFieldPacking parseBitFieldPacking(XmlPullParser parser) {
BitFieldPackingImpl bitFieldPacking = new BitFieldPackingImpl();
while (parser.peek().isStart()) {
XmlElement subel = parser.start();
String name = subel.getName();
String value = subel.getAttribute("value");
if (name.equals("use_MS_convention")) {
bitFieldPacking.setUseMSConvention(SpecXmlUtils.decodeBoolean(value));
}
else if (name.equals("type_alignment_enabled")) {
bitFieldPacking.setTypeAlignmentEnabled(SpecXmlUtils.decodeBoolean(value));
}
else if (name.equals("zero_length_boundary")) {
bitFieldPacking.setZeroLengthBoundary(SpecXmlUtils.decodeInt(value));
}
parser.end(subel);
}
return bitFieldPacking;
}
private void restoreSpaceBase(XmlPullParser parser) {
XmlElement el = parser.start();
String name = el.getAttribute("name");
@ -749,8 +774,8 @@ public class BasicCompilerSpec implements CompilerSpec {
stackGrowsNegative = false;
}
else {
throw new SleighException("Bad stack growth " + growth +
" should be 'positive' or 'negative'");
throw new SleighException(
"Bad stack growth " + growth + " should be 'positive' or 'negative'");
}
parser.end(el);
}
@ -833,7 +858,7 @@ public class BasicCompilerSpec implements CompilerSpec {
public DecompilerLanguage getDecompilerOutputLanguage(Program program) {
Options options = program.getOptions(DECOMPILER_PROPERTY_LIST_NAME);
if (options.contains(DECOMPILER_OUTPUT_LANGUAGE)) {
return options.getEnum(DECOMPILER_OUTPUT_LANGUAGE,DECOMPILER_OUTPUT_DEF);
return options.getEnum(DECOMPILER_OUTPUT_LANGUAGE, DECOMPILER_OUTPUT_DEF);
}
return DECOMPILER_OUTPUT_DEF;
}
@ -846,21 +871,15 @@ public class BasicCompilerSpec implements CompilerSpec {
// for upgrading/moving old property values.
Options decompilerPropertyList = program.getOptions(DECOMPILER_PROPERTY_LIST_NAME);
decompilerPropertyList.registerOption(
EVALUATION_MODEL_PROPERTY_NAME,
OptionType.STRING_TYPE,
evaluationModelChoices[0],
null,
decompilerPropertyList.registerOption(EVALUATION_MODEL_PROPERTY_NAME,
OptionType.STRING_TYPE, evaluationModelChoices[0], null,
"Select the default function prototype/evaluation model to be used during Decompiler analysis",
new StringWithChoicesEditor(evaluationModelChoices));
if (decompilerPropertyList.contains(DECOMPILER_OUTPUT_LANGUAGE)) {
decompilerPropertyList.registerOption(
DECOMPILER_OUTPUT_LANGUAGE,
DECOMPILER_OUTPUT_DEF,
null,
DECOMPILER_OUTPUT_DESC);
decompilerPropertyList.registerOption(DECOMPILER_OUTPUT_LANGUAGE, DECOMPILER_OUTPUT_DEF,
null, DECOMPILER_OUTPUT_DESC);
}
Options analysisPropertyList =
@ -939,12 +958,12 @@ public class BasicCompilerSpec implements CompilerSpec {
* @param program to be enabled
*/
public static void enableJavaLanguageDecompilation(Program program) {
Options decompilerPropertyList = program.getOptions(BasicCompilerSpec.DECOMPILER_PROPERTY_LIST_NAME);
decompilerPropertyList.registerOption(
BasicCompilerSpec.DECOMPILER_OUTPUT_LANGUAGE,
BasicCompilerSpec.DECOMPILER_OUTPUT_DEF,
null,
Options decompilerPropertyList =
program.getOptions(BasicCompilerSpec.DECOMPILER_PROPERTY_LIST_NAME);
decompilerPropertyList.registerOption(BasicCompilerSpec.DECOMPILER_OUTPUT_LANGUAGE,
BasicCompilerSpec.DECOMPILER_OUTPUT_DEF, null,
BasicCompilerSpec.DECOMPILER_OUTPUT_DESC);
decompilerPropertyList.setEnum(BasicCompilerSpec.DECOMPILER_OUTPUT_LANGUAGE, DecompilerLanguage.JAVA_LANGUAGE);
decompilerPropertyList.setEnum(BasicCompilerSpec.DECOMPILER_OUTPUT_LANGUAGE,
DecompilerLanguage.JAVA_LANGUAGE);
}
}

View file

@ -15,6 +15,8 @@
*/
package ghidra.program.model.listing;
import java.util.List;
import ghidra.docking.settings.Settings;
import ghidra.program.model.address.Address;
import ghidra.program.model.data.DataType;
@ -23,7 +25,7 @@ import ghidra.program.model.symbol.RefType;
import ghidra.program.model.symbol.Reference;
/**
* Interface for interacting with data at an address in a program.
* Interface for interacting with data at an address in a program.
*/
public interface Data extends CodeUnit, Settings {
@ -35,7 +37,7 @@ public interface Data extends CodeUnit, Settings {
/**
* Get the class used to express the value of this data.
* NOTE: This determination is made based upon data type
* NOTE: This determination is made based upon data type
* and settings only and does not examine memory bytes
* which are used to construct the data value object.
* @return value class or null if a consistent class is not
@ -74,7 +76,7 @@ public interface Data extends CodeUnit, Settings {
public DataType getDataType();
/**
* If the dataType is a typeDef, then the typeDef's base type is returned,
* If the dataType is a typeDef, then the typeDef's base type is returned,
* otherwise, the datatType is returned.
*/
public DataType getBaseDataType();
@ -200,9 +202,22 @@ public interface Data extends CodeUnit, Settings {
*/
Data getComponentAt(int offset);
/**
* Returns a list of all the immediate child components that contain the byte at the
* given offset.
* <P>
* For a union, this will return all the components (if the offset is 0). For a structure,
* this will be either a single non bit field element or a list of bit field elements.
* @param offset the amount to add to this data items address to get the
* address of the requested data item.
* @return a list of all the immediate child components that contain the byte at the
* given offset.
*/
List<Data> getComponentsContaining(int offset);
/**
* Returns the primitive component that is at this offset. This is useful
* for data items are made up of multiple layers of other data items. This
* for data items are made up of multiple layers of other data items. This
* method immediately goes to the lowest level data item.
*/
Data getPrimitiveAt(int offset);

View file

@ -17,6 +17,7 @@ package ghidra.program.model.listing;
import java.math.BigInteger;
import java.util.Iterator;
import java.util.List;
import ghidra.docking.settings.Settings;
import ghidra.program.model.address.Address;
@ -33,7 +34,7 @@ import ghidra.util.prop.PropertyVisitor;
/**
* DataStub can be extended for use by tests. It throws an UnsupportedOperationException
* for all methods in the Data interface. Any method that is needed for your test can then
* for all methods in the Data interface. Any method that is needed for your test can then
* be overridden so it can provide its own test implementation and return value.
*/
public class DataStub implements Data {
@ -526,6 +527,11 @@ public class DataStub implements Data {
throw new UnsupportedOperationException();
}
@Override
public List<Data> getComponentsContaining(int offset) {
throw new UnsupportedOperationException();
}
@Override
public Data getPrimitiveAt(int offset) {
throw new UnsupportedOperationException();

View file

@ -263,6 +263,9 @@ public class VariableUtilities {
*/
public static DataType checkDataType(DataType dataType, boolean voidOK, int defaultSize,
Program program) throws InvalidInputException {
if (dataType instanceof BitFieldDataType) {
throw new InvalidInputException("Bitfields not supported for variable");
}
if (dataType == null) {
if (voidOK) {
return VoidDataType.dataType;

View file

@ -35,8 +35,9 @@ public class ByteMemBufferImpl implements MemBuffer {
/**
* Construct a ByteMemBufferImpl object
* @param addr that address to associate with the bytes
* @param bytes the data that normally would be comming from memory.
* @param addr the address to associate with the bytes
* @param bytes the data that normally would be coming from memory.
* @param isBigEndian true for BigEndian, false for LittleEndian.
*/
public ByteMemBufferImpl(Address addr, byte[] bytes, boolean isBigEndian) {
this.addr = addr;
@ -44,6 +45,26 @@ public class ByteMemBufferImpl implements MemBuffer {
this.isBigEndian = isBigEndian;
}
/**
* Convenience constructor using varargs for specifying byte values.
* @param addr the address to associate with the bytes
* @param isBigEndian true for BigEndian, false for LittleEndian.
* @param byteValues varargs for specifying the individual byte values. The int argument
* will be truncated to a byte value.
*/
public ByteMemBufferImpl(Address addr, boolean isBigEndian, int... byteValues) {
this.addr = addr;
this.isBigEndian = isBigEndian;
bytes = new byte[byteValues.length];
for (int i = 0; i < bytes.length; i++) {
bytes[i] = (byte) byteValues[i];
}
}
/**
* Get number of bytes contained within buffer
* @return byte count
*/
public int getLength() {
return bytes.length;
}

View file

@ -22,14 +22,10 @@ import java.util.Collection;
import org.junit.Test;
import generic.test.AbstractGenericTest;
import generic.test.AbstractGTest;
import ghidra.program.database.data.DataTypeUtilities;
public class DataTypeUtilitiesTest extends AbstractGenericTest {
public DataTypeUtilitiesTest() {
super();
}
public class DataTypeUtilitiesTest extends AbstractGTest {
@Test
public void testGetContainedDataTypes() {

View file

@ -22,11 +22,11 @@ import java.io.StringWriter;
import org.junit.*;
import generic.test.AbstractGenericTest;
import generic.test.AbstractGTest;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitorAdapter;
public class DataTypeWriterTest extends AbstractGenericTest {
public class DataTypeWriterTest extends AbstractGTest {
private static String EOL = System.getProperty("line.separator");

View file

@ -21,53 +21,36 @@ import java.util.NoSuchElementException;
import org.junit.*;
import generic.test.AbstractGenericTest;
import generic.test.AbstractGTest;
import ghidra.util.task.TaskMonitorAdapter;
/**
* Tests for Enum data types.
*/
public class EnumTest extends AbstractGenericTest {
public class EnumTest extends AbstractGTest {
private DataTypeManager dataMgr;
private int transactionID;
/**
* Constructor for EnumTest.
* @param arg0
*/
public EnumTest() {
super();
@Before
public void setUp() throws Exception {
dataMgr = new StandAloneDataTypeManager("Test");
dataMgr.startTransaction("");
}
/*
* @see TestCase#setUp()
*/
@Before
public void setUp() throws Exception {
dataMgr = new StandAloneDataTypeManager("Test");
transactionID = dataMgr.startTransaction("");
}
@After
public void tearDown() {
dataMgr.endTransaction(transactionID, true);
dataMgr.close();
}
@Test
public void testCreateEnum() throws Exception {
@Test
public void testCreateEnum() throws Exception {
Enum enumm = new EnumDataType("Color", 1);
enumm.add("Red", 0);
enumm.add("Green", 1);
enumm.add("Blue", 2);
Category root = dataMgr.getRootCategory();
Category c = root.createCategory("enumms");
Enum enummDT = (Enum)c.addDataType(enumm, DataTypeConflictHandler.DEFAULT_HANDLER);
Enum enummDT = (Enum) c.addDataType(enumm, DataTypeConflictHandler.DEFAULT_HANDLER);
assertNotNull(enummDT);
assertEquals("Color", enummDT.getName());
assertEquals(0, enummDT.getValue("Red"));
assertEquals(1, enummDT.getValue("Green"));
@ -75,56 +58,59 @@ public class EnumTest extends AbstractGenericTest {
assertEquals(1, enummDT.getLength());
assertEquals(3, enummDT.getCount());
assertTrue(enumm.isEquivalent(enummDT));
assertTrue(enumm.isEquivalent(enummDT));
assertTrue(enummDT.isEquivalent(enumm));
assertEquals(c.getCategoryPath(), enummDT.getCategoryPath());
assertNotNull(c.getDataType("Color"));
}
@Test
public void testRemoveValue() throws Exception {
@Test
public void testRemoveValue() throws Exception {
Enum enumm = new EnumDataType("Color", 1);
enumm.add("Red", 0);
enumm.add("Green", 1);
enumm.add("Blue", 2);
Category root = dataMgr.getRootCategory();
Category c = root.createCategory("enumms");
Enum enummDT = (Enum)c.addDataType(enumm, DataTypeConflictHandler.DEFAULT_HANDLER);
Enum enummDT = (Enum) c.addDataType(enumm, DataTypeConflictHandler.DEFAULT_HANDLER);
assertEquals(3, enummDT.getCount());
enummDT.remove("Green");
assertEquals(2, enummDT.getCount());
}
@Test
public void testAddValue() throws Exception {
@Test
public void testAddValue() throws Exception {
Enum enumm = new EnumDataType("Color", 1);
enumm.add("Red", 0);
enumm.add("Green", 1);
enumm.add("Blue", 2);
Category root = dataMgr.getRootCategory();
Category c = root.createCategory("enumms");
Enum enummDT = (Enum)c.addDataType(enumm, DataTypeConflictHandler.DEFAULT_HANDLER);
Enum enummDT = (Enum) c.addDataType(enumm, DataTypeConflictHandler.DEFAULT_HANDLER);
enummDT.add("Purple", 7);
assertEquals(4, enummDT.getCount());
assertEquals(7, enummDT.getValue("Purple"));
}
@Test
public void testEditValue() throws Exception {
@Test
public void testEditValue() throws Exception {
Enum enumm = new EnumDataType("Color", 1);
enumm.add("Red", 10);
enumm.add("Green", 15);
enumm.add("Blue", 20);
Category root = dataMgr.getRootCategory();
Category c = root.createCategory("enumms");
Enum enummDT = (Enum)c.addDataType(enumm, DataTypeConflictHandler.DEFAULT_HANDLER);
Enum enummDT = (Enum) c.addDataType(enumm, DataTypeConflictHandler.DEFAULT_HANDLER);
enummDT.remove("Blue");
assertEquals(2, enummDT.getCount());
enummDT.add("Blue", 30);
@ -132,100 +118,101 @@ public class EnumTest extends AbstractGenericTest {
assertEquals("Blue", enummDT.getName(30));
assertNull(enummDT.getName(20));
}
@Test
public void testCloneRetain() throws Exception {
@Test
public void testCloneRetain() throws Exception {
Enum enumm = new EnumDataType("Color", 1);
enumm.add("Red", 10);
enumm.add("Green", 15);
enumm.add("Blue", 20);
Category root = dataMgr.getRootCategory();
Category c = root.createCategory("enumms");
Enum enummDT = (Enum)c.addDataType(enumm, DataTypeConflictHandler.DEFAULT_HANDLER);
Enum enummDT = (Enum) c.addDataType(enumm, DataTypeConflictHandler.DEFAULT_HANDLER);
Enum copyDT = (Enum)enummDT.clone(null);
Enum copyDT = (Enum) enummDT.clone(null);
assertNotNull(copyDT);
Enum c2 = (Enum)root.addDataType(copyDT, DataTypeConflictHandler.DEFAULT_HANDLER);
Enum c2 = (Enum) root.addDataType(copyDT, DataTypeConflictHandler.DEFAULT_HANDLER);
assertNotNull(c2);
assertTrue(copyDT.isEquivalent(c2));
}
@Test
public void testCopyDontRetain() throws Exception {
@Test
public void testCopyDontRetain() throws Exception {
Enum enumm = new EnumDataType("Color", 1);
enumm.add("Red", 10);
enumm.add("Green", 15);
enumm.add("Blue", 20);
Category root = dataMgr.getRootCategory();
Category c = root.createCategory("enumms");
Enum enummDT = (Enum)c.addDataType(enumm, DataTypeConflictHandler.DEFAULT_HANDLER);
Enum enummDT = (Enum) c.addDataType(enumm, DataTypeConflictHandler.DEFAULT_HANDLER);
Enum copyDT = (Enum)enummDT.copy(null);
Enum copyDT = (Enum) enummDT.copy(null);
assertNotNull(copyDT);
Enum c2 = (Enum)root.addDataType(copyDT, DataTypeConflictHandler.DEFAULT_HANDLER);
Enum c2 = (Enum) root.addDataType(copyDT, DataTypeConflictHandler.DEFAULT_HANDLER);
assertNotNull(c2);
assertTrue(copyDT.isEquivalent(c2));
}
@Test
public void testRemoveEnum() throws Exception {
@Test
public void testRemoveEnum() throws Exception {
Enum enumm = new EnumDataType("Color", 1);
enumm.add("Red", 10);
enumm.add("Green", 15);
enumm.add("Blue", 20);
Category root = dataMgr.getRootCategory();
Category c = root.createCategory("enumms");
Enum enummDT = (Enum)c.addDataType(enumm, DataTypeConflictHandler.DEFAULT_HANDLER);
Enum enummDT = (Enum) c.addDataType(enumm, DataTypeConflictHandler.DEFAULT_HANDLER);
assertNotNull(enummDT);
c.remove(enummDT, TaskMonitorAdapter.DUMMY_MONITOR);
assertNull(c.getDataType("Color"));
assertTrue(enummDT.isDeleted());
}
@Test
public void testMoveEnum() throws Exception {
@Test
public void testMoveEnum() throws Exception {
Enum enumm = new EnumDataType("Color", 1);
enumm.add("Red", 10);
enumm.add("Green", 15);
enumm.add("Blue", 20);
Category root = dataMgr.getRootCategory();
Category c = root.createCategory("enumms");
Enum enummDT = (Enum)c.addDataType(enumm, DataTypeConflictHandler.DEFAULT_HANDLER);
Enum enummDT = (Enum) c.addDataType(enumm, DataTypeConflictHandler.DEFAULT_HANDLER);
root.moveDataType(enummDT, null);
assertNotNull(root.getDataType(enumm.getName()));
assertNull(c.getDataType(enumm.getName()));
}
@Test
public void testResolve() throws Exception {
@Test
public void testResolve() throws Exception {
Enum enumm = new EnumDataType("Color", 1);
enumm.add("Red", 10);
enumm.add("Green", 15);
enumm.add("Blue", 20);
Enum enummDT = (Enum)dataMgr.resolve(enumm, null);
Enum enummDT = (Enum) dataMgr.resolve(enumm, null);
assertNotNull(enummDT);
long id = dataMgr.getResolvedID(enummDT);
assertEquals(enummDT, dataMgr.getDataType(id));
assertEquals(enummDT, dataMgr.getDataType(id));
}
@Test
public void testReplace() throws Exception {
@Test
public void testReplace() throws Exception {
Enum enumm = new EnumDataType("Color", 1);
enumm.add("Red", 10);
enumm.add("Green", 15);
enumm.add("Blue", 20);
Category root = dataMgr.getRootCategory();
Category c = root.createCategory("enumms");
Enum enummDT = (Enum)c.addDataType(enumm, DataTypeConflictHandler.DEFAULT_HANDLER);
Enum enummDT = (Enum) c.addDataType(enumm, DataTypeConflictHandler.DEFAULT_HANDLER);
Enum myEnum = new EnumDataType("my enumm", 1);
myEnum.add("My red", 0);
myEnum.add("My Green", 5);
@ -233,39 +220,22 @@ public class EnumTest extends AbstractGenericTest {
myEnum.add("Purple", 10);
enummDT.replaceWith(myEnum);
assertEquals(4, enummDT.getCount());
long[] values = enummDT.getValues();
assertEquals(4, values.length);
assertEquals(0, values[0]);
assertEquals(5, values[1]);
assertEquals(10, values[2]);
assertEquals(25, values[3]);
try {
try {
enummDT.getValue("Red");
Assert.fail("Should have gotten no such element exception!");
} catch (NoSuchElementException e) {
}
catch (NoSuchElementException e) {
}
}
// private class DomainObjListener implements DomainObjectListener {
// private int count;
//
// /* (non-Javadoc)
// * @see ghidra.framework.model.DomainObjectListener#domainObjectChanged(ghidra.framework.model.DomainObjectChangedEvent)
// */
// public void domainObjectChanged(DomainObjectChangedEvent ev) {
// for (int i=0; i<ev.numRecords(); i++) {
// DomainObjectChangeRecord rec = ev.getChangeRecord(i);
// if (rec.getEventType() == ChangeManager.DOCR_DATA_TYPE_CHANGED) {
// ++count;
// }
// }
// }
// int getCount() {
// return count;
// }
// }
}

View file

@ -29,10 +29,6 @@ public class FileDataTypeManagerTest extends AbstractGenericTest {
private File testArchiveFile;
public FileDataTypeManagerTest() {
super();
}
@Before
public void setUp() throws Exception {
testArchiveFile =
@ -74,7 +70,7 @@ public class FileDataTypeManagerTest extends AbstractGenericTest {
dtMgr = FileDataTypeManager.openFileArchive(testArchiveFile, false);
assertFalse(dtMgr.isUpdatable());
ArrayList<DataType> list = new ArrayList<DataType>();
ArrayList<DataType> list = new ArrayList<>();
dtMgr.getAllDataTypes(list);
int size = list.size();
@ -86,8 +82,9 @@ public class FileDataTypeManagerTest extends AbstractGenericTest {
"\n");
}
Assert.fail("Did not get exptected data types of byte, Typdef and Typedef. Instead found:\n" +
buffy.toString());
Assert.fail(
"Did not get exptected data types of byte, Typdef and Typedef. Instead found:\n" +
buffy.toString());
}
assertTrue(dt1.isEquivalent(dtMgr.getDataType(CategoryPath.ROOT, "T1")));
@ -148,7 +145,7 @@ public class FileDataTypeManagerTest extends AbstractGenericTest {
dtMgr = FileDataTypeManager.openFileArchive(testArchiveFile, false);
assertFalse(dtMgr.isUpdatable());
ArrayList<DataType> list = new ArrayList<DataType>();
ArrayList<DataType> list = new ArrayList<>();
dtMgr.getAllDataTypes(list);
assertEquals(13, list.size());

View file

@ -19,18 +19,10 @@ import static org.junit.Assert.assertEquals;
import org.junit.Test;
import generic.test.AbstractGenericTest;
import generic.test.AbstractGTest;
import ghidra.program.model.mem.ByteMemBufferImpl;
public class FloatDataTypeTest extends AbstractGenericTest {
/**
* Constructor for LongDoubleDataTypeTest.
* @param arg0
*/
public FloatDataTypeTest() {
super();
}
public class FloatDataTypeTest extends AbstractGTest {
private byte[] getBytes(long value, int size) {
byte[] bytes = new byte[size];
@ -41,8 +33,8 @@ public class FloatDataTypeTest extends AbstractGenericTest {
return bytes;
}
@Test
public void testFloat4Extremes() {
@Test
public void testFloat4Extremes() {
int bits = Float.floatToRawIntBits(Float.NaN);
byte[] bytes = getBytes(bits, 4);
@ -94,8 +86,8 @@ public class FloatDataTypeTest extends AbstractGenericTest {
}
@Test
public void testFloat8Extremes() {
@Test
public void testFloat8Extremes() {
long bits = Double.doubleToRawLongBits(Double.NaN);
byte[] bytes = getBytes(bits, 8);

View file

@ -19,44 +19,24 @@ import static org.junit.Assert.*;
import org.junit.*;
import generic.test.AbstractGenericTest;
import generic.test.AbstractGTest;
import ghidra.docking.settings.SettingsImpl;
public class FunctionDefinitionDataTypeTest extends AbstractGenericTest {
public class FunctionDefinitionDataTypeTest extends AbstractGTest {
private StandAloneDataTypeManager dtm;
private FunctionDefinition functionDt;
private int transactionID;
private FunctionDefinition createFunctionDefinition(String name) {
return (FunctionDefinition) dtm.resolve(new FunctionDefinitionDataType(name), null);
}
/**
* Constructor for FunctionDefinitionDataTypeTest.
*/
public FunctionDefinitionDataTypeTest() {
super();
}
/*
* @see TestCase#setUp()
*/
@Before
public void setUp() throws Exception {
dtm = new StandAloneDataTypeManager("dummyDTM");
transactionID = dtm.startTransaction("");
dtm.startTransaction("");
functionDt = createFunctionDefinition("Test");
}
/*
* @see TestCase#tearDown()
*/
@After
public void tearDown() throws Exception {
dtm.endTransaction(transactionID, true);
dtm.close();
}
@Test
public void testConstructor_WithName() {
FunctionDefinitionDataType impl;

View file

@ -1,969 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
*
*/
package ghidra.program.model.data;
import static org.junit.Assert.*;
import org.junit.*;
import generic.test.AbstractGTest;
/**
*
*/
public class StructureTest extends AbstractGTest {
private Structure struct;
/**
* @param arg0
*/
public StructureTest() {
super();
}
private Structure createStructure(String name, int length) {
return new StructureDataType(name, length);
}
private Union createUnion(String name) {
return new UnionDataType(name);
}
private TypeDef createTypeDef(DataType dataType) {
return new TypedefDataType(dataType.getName() + "TypeDef", dataType);
}
private Array createArray(DataType dataType, int numElements) {
return new ArrayDataType(dataType, numElements, dataType.getLength());
}
private Pointer createPointer(DataType dataType, int length) {
return new PointerDataType(dataType, length);
}
@Before
public void setUp() throws Exception {
struct = createStructure("TestStruct", 0);
struct.add(new ByteDataType(), "field1", "Comment1");
struct.add(new WordDataType(), null, "Comment2");
struct.add(new DWordDataType(), "field3", null);
struct.add(new ByteDataType(), "field4", "Comment4");
}
@Test
public void testAdd() throws Exception {
assertEquals(8, struct.getLength());
assertEquals(4, struct.getNumComponents());
DataTypeComponent dtc = struct.getComponent(0);
assertEquals(0, dtc.getOffset());
assertEquals(0, dtc.getOrdinal());
assertEquals("field1", dtc.getFieldName());
assertEquals("Comment1", dtc.getComment());
assertEquals(ByteDataType.class, dtc.getDataType().getClass());
dtc = struct.getComponent(1);
assertEquals(1, dtc.getOffset());
assertEquals(1, dtc.getOrdinal());
assertEquals("field_0x1", dtc.getDefaultFieldName());
assertEquals(null, dtc.getFieldName());
assertEquals("Comment2", dtc.getComment());
assertEquals(WordDataType.class, dtc.getDataType().getClass());
dtc = struct.getComponent(2);
assertEquals(3, dtc.getOffset());
assertEquals(2, dtc.getOrdinal());
assertEquals("field3", dtc.getFieldName());
assertEquals(null, dtc.getComment());
assertEquals(DWordDataType.class, dtc.getDataType().getClass());
dtc = struct.getComponent(3);
assertEquals(7, dtc.getOffset());
assertEquals(3, dtc.getOrdinal());
assertEquals("field4", dtc.getFieldName());
assertEquals("Comment4", dtc.getComment());
assertEquals(ByteDataType.class, dtc.getDataType().getClass());
}
@Test
public void testAdd2() throws Exception {
struct = createStructure("Test", 10);
assertEquals(10, struct.getLength());
assertEquals(10, struct.getNumComponents());
struct.add(new ByteDataType(), "field1", "Comment1");
struct.add(new WordDataType(), null, "Comment2");
struct.add(new DWordDataType(), "field3", null);
struct.add(new ByteDataType(), "field4", "Comment4");
assertEquals(18, struct.getLength());
assertEquals(14, struct.getNumComponents());
DataTypeComponent dtc = struct.getComponent(0);
assertEquals(0, dtc.getOffset());
assertEquals(0, dtc.getOrdinal());
assertEquals("field_0x0", dtc.getDefaultFieldName());
assertNull(dtc.getFieldName());
assertNull(dtc.getComment());
assertEquals(DataType.DEFAULT, dtc.getDataType());
dtc = struct.getComponent(1);
assertEquals(1, dtc.getOffset());
assertEquals(1, dtc.getOrdinal());
assertEquals("field_0x1", dtc.getDefaultFieldName());
assertNull(dtc.getFieldName());
assertEquals(null, dtc.getComment());
assertEquals(DataType.DEFAULT, dtc.getDataType());
dtc = struct.getComponent(10);
assertEquals(10, dtc.getOffset());
assertEquals(10, dtc.getOrdinal());
assertEquals("field1", dtc.getFieldName());
assertEquals("Comment1", dtc.getComment());
assertEquals(ByteDataType.class, dtc.getDataType().getClass());
dtc = struct.getComponent(11);
assertEquals(11, dtc.getOffset());
assertEquals(11, dtc.getOrdinal());
assertEquals("field_0xb", dtc.getDefaultFieldName());
assertNull(dtc.getFieldName());
assertEquals("Comment2", dtc.getComment());
assertEquals(WordDataType.class, dtc.getDataType().getClass());
dtc = struct.getComponent(12);
assertEquals(13, dtc.getOffset());
assertEquals(12, dtc.getOrdinal());
assertEquals("field3", dtc.getFieldName());
assertEquals(null, dtc.getComment());
assertEquals(DWordDataType.class, dtc.getDataType().getClass());
}
@Test
public void testInsert_beginning() {
struct.insert(0, new FloatDataType());
assertEquals(12, struct.getLength());
assertEquals(5, struct.getNumComponents());
DataTypeComponent dtc = struct.getComponent(0);
assertEquals(0, dtc.getOffset());
assertEquals(0, dtc.getOrdinal());
assertEquals("field_0x0", dtc.getDefaultFieldName());
assertNull(dtc.getFieldName());
assertNull(dtc.getComment());
assertEquals(FloatDataType.class, dtc.getDataType().getClass());
dtc = struct.getComponent(1);
assertEquals(4, dtc.getOffset());
assertEquals(1, dtc.getOrdinal());
assertEquals("field1", dtc.getFieldName());
assertEquals("Comment1", dtc.getComment());
assertEquals(ByteDataType.class, dtc.getDataType().getClass());
dtc = struct.getComponent(2);
assertEquals(5, dtc.getOffset());
assertEquals(2, dtc.getOrdinal());
assertEquals("field_0x5", dtc.getDefaultFieldName());
assertNull(dtc.getFieldName());
assertEquals("Comment2", dtc.getComment());
assertEquals(WordDataType.class, dtc.getDataType().getClass());
dtc = struct.getComponent(3);
assertEquals(7, dtc.getOffset());
assertEquals(3, dtc.getOrdinal());
assertEquals("field3", dtc.getFieldName());
assertEquals(null, dtc.getComment());
assertEquals(DWordDataType.class, dtc.getDataType().getClass());
dtc = struct.getComponent(4);
assertEquals(11, dtc.getOffset());
assertEquals(4, dtc.getOrdinal());
assertEquals("field4", dtc.getFieldName());
assertEquals("Comment4", dtc.getComment());
assertEquals(ByteDataType.class, dtc.getDataType().getClass());
}
@Test
public void testInsert_end() {
struct.insert(4, new FloatDataType());
assertEquals(12, struct.getLength());
assertEquals(5, struct.getNumComponents());
DataTypeComponent dtc = struct.getComponent(0);
assertEquals(0, dtc.getOffset());
assertEquals(0, dtc.getOrdinal());
assertEquals("field1", dtc.getFieldName());
assertEquals("Comment1", dtc.getComment());
assertEquals(ByteDataType.class, dtc.getDataType().getClass());
dtc = struct.getComponent(1);
assertEquals(1, dtc.getOffset());
assertEquals(1, dtc.getOrdinal());
assertEquals("field_0x1", dtc.getDefaultFieldName());
assertNull(dtc.getFieldName());
assertEquals("Comment2", dtc.getComment());
assertEquals(WordDataType.class, dtc.getDataType().getClass());
dtc = struct.getComponent(2);
assertEquals(3, dtc.getOffset());
assertEquals(2, dtc.getOrdinal());
assertEquals("field3", dtc.getFieldName());
assertEquals(null, dtc.getComment());
assertEquals(DWordDataType.class, dtc.getDataType().getClass());
dtc = struct.getComponent(3);
assertEquals(7, dtc.getOffset());
assertEquals(3, dtc.getOrdinal());
assertEquals("field4", dtc.getFieldName());
assertEquals("Comment4", dtc.getComment());
assertEquals(ByteDataType.class, dtc.getDataType().getClass());
dtc = struct.getComponent(4);
assertEquals(8, dtc.getOffset());
assertEquals(4, dtc.getOrdinal());
assertEquals("field_0x8", dtc.getDefaultFieldName());
assertNull(dtc.getFieldName());
assertEquals(null, dtc.getComment());
assertEquals(FloatDataType.class, dtc.getDataType().getClass());
}
@Test
public void testInsert_middle() {
struct.insert(2, new FloatDataType());
assertEquals(12, struct.getLength());
assertEquals(5, struct.getNumComponents());
DataTypeComponent dtc = struct.getComponent(0);
assertEquals(0, dtc.getOffset());
assertEquals(0, dtc.getOrdinal());
assertEquals("field1", dtc.getFieldName());
assertEquals("Comment1", dtc.getComment());
assertEquals(ByteDataType.class, dtc.getDataType().getClass());
dtc = struct.getComponent(1);
assertEquals(1, dtc.getOffset());
assertEquals(1, dtc.getOrdinal());
assertEquals("field_0x1", dtc.getDefaultFieldName());
assertNull(dtc.getFieldName());
assertEquals("Comment2", dtc.getComment());
assertEquals(WordDataType.class, dtc.getDataType().getClass());
dtc = struct.getComponent(2);
assertEquals(3, dtc.getOffset());
assertEquals(2, dtc.getOrdinal());
assertEquals("field_0x3", dtc.getDefaultFieldName());
assertNull(dtc.getFieldName());
assertNull(dtc.getComment());
assertEquals(FloatDataType.class, dtc.getDataType().getClass());
dtc = struct.getComponent(3);
assertEquals(7, dtc.getOffset());
assertEquals(3, dtc.getOrdinal());
assertEquals("field3", dtc.getFieldName());
assertEquals(null, dtc.getComment());
assertEquals(DWordDataType.class, dtc.getDataType().getClass());
dtc = struct.getComponent(4);
assertEquals(11, dtc.getOffset());
assertEquals(4, dtc.getOrdinal());
assertEquals("field4", dtc.getFieldName());
assertEquals("Comment4", dtc.getComment());
assertEquals(ByteDataType.class, dtc.getDataType().getClass());
}
@Test
public void testInsertWithEmptySpace() {
struct = createStructure("Test", 100);
struct.insert(40, new ByteDataType());
struct.insert(20, new WordDataType());
struct.insert(10, new FloatDataType());
assertEquals(107, struct.getLength());
assertEquals(103, struct.getNumComponents());
DataTypeComponent[] comps = struct.getDefinedComponents();
assertEquals(3, comps.length);
assertEquals(10, comps[0].getOffset());
assertEquals(10, comps[0].getOrdinal());
assertEquals(FloatDataType.class, comps[0].getDataType().getClass());
assertEquals(24, comps[1].getOffset());
assertEquals(21, comps[1].getOrdinal());
assertEquals(WordDataType.class, comps[1].getDataType().getClass());
assertEquals(46, comps[2].getOffset());
assertEquals(42, comps[2].getOrdinal());
assertEquals(ByteDataType.class, comps[2].getDataType().getClass());
}
// test inserting at offset 0
@Test
public void testInsertAtOffset() {
struct.insertAtOffset(0, new FloatDataType(), 4);
assertEquals(12, struct.getLength());
DataTypeComponent[] comps = struct.getDefinedComponents();
assertEquals(5, comps.length);
assertEquals(0, comps[0].getOffset());
assertEquals(0, comps[0].getOrdinal());
assertEquals(FloatDataType.class, comps[0].getDataType().getClass());
assertEquals(4, comps[1].getOffset());
assertEquals(1, comps[1].getOrdinal());
assertEquals(ByteDataType.class, comps[1].getDataType().getClass());
assertEquals(5, comps[2].getOffset());
assertEquals(2, comps[2].getOrdinal());
assertEquals(WordDataType.class, comps[2].getDataType().getClass());
assertEquals(7, comps[3].getOffset());
assertEquals(3, comps[3].getOrdinal());
assertEquals(DWordDataType.class, comps[3].getDataType().getClass());
}
// test inserting at offset 1
@Test
public void testInsertAtOffset1() {
struct.insertAtOffset(1, new FloatDataType(), 4);
assertEquals(12, struct.getLength());
DataTypeComponent[] comps = struct.getDefinedComponents();
assertEquals(5, comps.length);
assertEquals(0, comps[0].getOffset());
assertEquals(0, comps[0].getOrdinal());
assertEquals(ByteDataType.class, comps[0].getDataType().getClass());
assertEquals(1, comps[1].getOffset());
assertEquals(1, comps[1].getOrdinal());
assertEquals(FloatDataType.class, comps[1].getDataType().getClass());
assertEquals(5, comps[2].getOffset());
assertEquals(2, comps[2].getOrdinal());
assertEquals(WordDataType.class, comps[2].getDataType().getClass());
assertEquals(7, comps[3].getOffset());
assertEquals(3, comps[3].getOrdinal());
assertEquals(DWordDataType.class, comps[3].getDataType().getClass());
}
// test inserting at offset 1
@Test
public void testInsertAtOffset2() {
struct.insertAtOffset(2, new FloatDataType(), 4);
assertEquals(13, struct.getLength());
DataTypeComponent[] comps = struct.getDefinedComponents();
assertEquals(5, comps.length);
assertEquals(0, comps[0].getOffset());
assertEquals(0, comps[0].getOrdinal());
assertEquals(ByteDataType.class, comps[0].getDataType().getClass());
assertEquals(2, comps[1].getOffset());
assertEquals(2, comps[1].getOrdinal());
assertEquals(FloatDataType.class, comps[1].getDataType().getClass());
assertEquals(6, comps[2].getOffset());
assertEquals(3, comps[2].getOrdinal());
assertEquals(WordDataType.class, comps[2].getDataType().getClass());
assertEquals(8, comps[3].getOffset());
assertEquals(4, comps[3].getOrdinal());
assertEquals(DWordDataType.class, comps[3].getDataType().getClass());
}
@Test
public void testInsertAtOffsetPastEnd() {
struct.insertAtOffset(100, new FloatDataType(), 4);
assertEquals(104, struct.getLength());
}
@Test
public void testClearComponent() {
struct.clearComponent(0);
assertEquals(8, struct.getLength());
assertEquals(4, struct.getNumComponents());
DataTypeComponent dtc = struct.getComponent(0);
assertEquals(DataType.DEFAULT, dtc.getDataType());
dtc = struct.getComponent(1);
assertEquals(WordDataType.class, dtc.getDataType().getClass());
}
@Test
public void testClearComponent1() {
struct.clearComponent(1);
assertEquals(8, struct.getLength());
assertEquals(5, struct.getNumComponents());
DataTypeComponent dtc = struct.getComponent(1);
assertEquals(DataType.DEFAULT, dtc.getDataType());
dtc = struct.getComponent(2);
assertEquals(DataType.DEFAULT, dtc.getDataType());
dtc = struct.getComponent(0);
assertEquals(ByteDataType.class, dtc.getDataType().getClass());
dtc = struct.getComponent(3);
assertEquals(DWordDataType.class, dtc.getDataType().getClass());
assertEquals(3, dtc.getOrdinal());
assertEquals(3, dtc.getOffset());
}
@Test
public void testReplace() { // bigger, no space below
try {
struct.replace(0, new QWordDataType(), 8);
Assert.fail();
}
catch (Exception e) {
}
}
@Test
public void testReplace1() { // bigger, space below
struct.insert(1, new QWordDataType());
struct.clearComponent(1);
assertEquals(16, struct.getLength());
assertEquals(12, struct.getNumComponents());
struct.replace(0, new QWordDataType(), 8);
assertEquals(16, struct.getLength());
assertEquals(5, struct.getNumComponents());
DataTypeComponent[] comps = struct.getDefinedComponents();
assertEquals(9, comps[1].getOffset());
assertEquals(2, comps[1].getOrdinal());
}
@Test
public void testReplace2() { // same size
struct.replace(0, new CharDataType(), 1);
assertEquals(8, struct.getLength());
assertEquals(4, struct.getNumComponents());
DataTypeComponent[] comps = struct.getDefinedComponents();
assertEquals(CharDataType.class, comps[0].getDataType().getClass());
assertEquals(1, comps[1].getOffset());
assertEquals(1, comps[1].getOrdinal());
}
@Test
public void testReplace3() { // smaller
struct.replace(1, new CharDataType(), 1);
assertEquals(8, struct.getLength());
assertEquals(5, struct.getNumComponents());
DataTypeComponent[] comps = struct.getDefinedComponents();
assertEquals(CharDataType.class, comps[1].getDataType().getClass());
assertEquals(1, comps[1].getOffset());
assertEquals(1, comps[1].getOrdinal());
assertEquals(3, comps[2].getOffset());
assertEquals(3, comps[2].getOrdinal());
assertEquals(DWordDataType.class, comps[2].getDataType().getClass());
}
@Test
public void testDelete() {
struct.delete(1);
assertEquals(6, struct.getLength());
assertEquals(3, struct.getNumComponents());
DataTypeComponent[] comps = struct.getDefinedComponents();
assertEquals(DWordDataType.class, comps[1].getDataType().getClass());
assertEquals(1, comps[1].getOffset());
}
@Test
public void testDeleteAtOffset() {
struct.deleteAtOffset(2);
assertEquals(6, struct.getLength());
assertEquals(3, struct.getNumComponents());
DataTypeComponent[] comps = struct.getDefinedComponents();
assertEquals(DWordDataType.class, comps[1].getDataType().getClass());
assertEquals(1, comps[1].getOffset());
}
@Test
public void testDeleteAll() {
Structure s = new StructureDataType("test1", 0);
s.add(new ByteDataType());
s.add(new FloatDataType());
struct.add(s);
s.deleteAll();
assertEquals(1, s.getLength());
assertTrue(s.isNotYetDefined());
assertEquals(0, s.getNumComponents());
}
@Test
public void testGetComponents() {
struct = createStructure("Test", 8);
struct.insert(2, new ByteDataType(), 1, "field3", "Comment1");
struct.insert(5, new WordDataType(), 2, null, "Comment2");
struct.insert(7, new DWordDataType(), 4, "field8", null);
assertEquals(15, struct.getLength());
assertEquals(11, struct.getNumComponents());
DataTypeComponent[] dtcs = struct.getComponents();
assertEquals(11, dtcs.length);
int offset = 0;
for (int i = 0; i < 11; i++) {
assertEquals(i, dtcs[i].getOrdinal());
assertEquals(offset, dtcs[i].getOffset());
offset += dtcs[i].getLength();
}
assertEquals(DataType.DEFAULT, dtcs[0].getDataType());
assertEquals(DataType.DEFAULT, dtcs[1].getDataType());
assertEquals(ByteDataType.class, dtcs[2].getDataType().getClass());
assertEquals(DataType.DEFAULT, dtcs[3].getDataType());
assertEquals(DataType.DEFAULT, dtcs[4].getDataType());
assertEquals(WordDataType.class, dtcs[5].getDataType().getClass());
assertEquals(DataType.DEFAULT, dtcs[6].getDataType());
assertEquals(DWordDataType.class, dtcs[7].getDataType().getClass());
assertEquals(DataType.DEFAULT, dtcs[8].getDataType());
assertEquals(DataType.DEFAULT, dtcs[9].getDataType());
assertEquals(DataType.DEFAULT, dtcs[10].getDataType());
}
@Test
public void testGetDefinedComponents() {
struct = createStructure("Test", 8);
struct.insert(2, new ByteDataType(), 1, "field3", "Comment1");
struct.insert(5, new WordDataType(), 2, null, "Comment2");
struct.insert(7, new DWordDataType(), 4, "field8", null);
assertEquals(15, struct.getLength());
assertEquals(11, struct.getNumComponents());
DataTypeComponent[] dtcs = struct.getDefinedComponents();
assertEquals(3, dtcs.length);
assertEquals(ByteDataType.class, dtcs[0].getDataType().getClass());
assertEquals(2, dtcs[0].getOrdinal());
assertEquals(2, dtcs[0].getOffset());
assertEquals(WordDataType.class, dtcs[1].getDataType().getClass());
assertEquals(5, dtcs[1].getOrdinal());
assertEquals(5, dtcs[1].getOffset());
assertEquals(DWordDataType.class, dtcs[2].getDataType().getClass());
assertEquals(7, dtcs[2].getOrdinal());
assertEquals(8, dtcs[2].getOffset());
}
@Test
public void testGetComponentAt() {
DataTypeComponent dtc = struct.getComponentAt(4);
assertEquals(DWordDataType.class, dtc.getDataType().getClass());
assertEquals(2, dtc.getOrdinal());
assertEquals(3, dtc.getOffset());
}
@Test
public void testGetDataTypeAt() {
Structure s1 = createStructure("Test1", 0);
s1.add(new WordDataType());
s1.add(struct);
s1.add(new ByteDataType());
DataTypeComponent dtc = s1.getComponentAt(7);
assertEquals(struct, dtc.getDataType());
dtc = s1.getDataTypeAt(7);
assertEquals(DWordDataType.class, dtc.getDataType().getClass());
}
@Test
public void testReplaceWith() {
assertEquals(8, struct.getLength());
assertEquals(4, struct.getNumComponents());
Structure newStruct = createStructure("Replaced", 8);
newStruct.setDescription("testReplaceWith()");
DataTypeComponent dtc0 = newStruct.insert(2, new ByteDataType(), 1, "field3", "Comment1");
DataTypeComponent dtc1 = newStruct.insert(5, new WordDataType(), 2, null, "Comment2");
DataTypeComponent dtc2 = newStruct.insert(7, new DWordDataType(), 4, "field8", null);
struct.replaceWith(newStruct);
assertEquals(15, struct.getLength());
assertEquals(11, struct.getNumComponents());
DataTypeComponent[] dtcs = struct.getDefinedComponents();
assertEquals(3, dtcs.length);
assertEquals(dtc0, dtcs[0]);
assertEquals(dtc1, dtcs[1]);
assertEquals(dtc2, dtcs[2]);
assertEquals("TestStruct", struct.getName());
assertEquals("", struct.getDescription());
}
/**
* Test that a structure can't ... ???
*/
@Test
public void testCyclingProblem() {
Structure newStruct = createStructure("TestStruct", 80);
newStruct.setDescription("testReplaceWith()");
newStruct.add(new ByteDataType(), "field0", "Comment1");
newStruct.add(struct, "field1", null);
newStruct.add(new WordDataType(), null, "Comment2");
newStruct.add(new DWordDataType(), "field3", null);
try {
struct.add(newStruct);
Assert.fail();
}
catch (IllegalArgumentException e) {
}
try {
struct.insert(0, newStruct);
Assert.fail();
}
catch (IllegalArgumentException e) {
}
try {
struct.replace(0, newStruct, newStruct.getLength());
Assert.fail();
}
catch (IllegalArgumentException e) {
}
}
/**
* Test that a structure can't be added to itself.
*/
@Test
public void testCyclicDependencyProblem1() {
try {
struct.add(struct);
Assert.fail("Shouldn't be able to add a structure to itself.");
}
catch (IllegalArgumentException e) {
// Should get an exception from adding the struct to itself.
}
try {
struct.insert(0, struct);
Assert.fail("Shouldn't be able to insert a structure into itself.");
}
catch (IllegalArgumentException e) {
// Should get an exception from inserting the struct to itself.
}
try {
struct.replace(0, struct, struct.getLength());
Assert.fail(
"Shouldn't be able to replace a structure component with the structure itself.");
}
catch (IllegalArgumentException e) {
// Should get an exception from replacing the struct to itself.
}
}
/**
* Test that a structure array can't be added to the same structure.
*/
@Test
public void testCyclicDependencyProblem2() {
Array array = createArray(struct, 3);
try {
struct.add(array);
Assert.fail("Shouldn't be able to add a structure array to the same structure.");
}
catch (IllegalArgumentException e) {
// Should get an exception from adding the struct to itself.
}
try {
struct.insert(0, array);
Assert.fail("Shouldn't be able to insert a structure array into the same structure.");
}
catch (IllegalArgumentException e) {
// Should get an exception from inserting the struct to itself.
}
try {
struct.replace(0, array, array.getLength());
Assert.fail(
"Shouldn't be able to replace a structure component with an array of the same structure.");
}
catch (IllegalArgumentException e) {
// Should get an exception from replacing the struct to itself.
}
}
/**
* Test that a typedef of a structure can't be added to the structure.
*/
@Test
public void testCyclicDependencyProblem3() {
TypeDef typeDef = createTypeDef(struct);
try {
struct.add(typeDef);
Assert.fail("Shouldn't be able to add a structure typedef to the typedef's structure.");
}
catch (IllegalArgumentException e) {
// Should get an exception from adding the struct to itself.
}
try {
struct.insert(0, typeDef);
Assert.fail(
"Shouldn't be able to insert a structure typedef into the typedef's structure.");
}
catch (IllegalArgumentException e) {
// Should get an exception from inserting the struct to itself.
}
try {
struct.replace(0, typeDef, typeDef.getLength());
Assert.fail(
"Shouldn't be able to replace a structure component with the structure's typedef.");
}
catch (IllegalArgumentException e) {
// Should get an exception from replacing the struct to itself.
}
}
/**
* Test that a structure can't contain another structure that contains it.
*/
@Test
public void testCyclicDependencyProblem4() {
Structure anotherStruct = createStructure("AnotherStruct", 0);
anotherStruct.add(struct);
try {
struct.add(anotherStruct);
Assert.fail(
"Shouldn't be able to add another structure, which contains this structure, to this structure.");
}
catch (IllegalArgumentException e) {
// Should get an exception from adding the struct to itself.
}
try {
struct.insert(0, anotherStruct);
Assert.fail(
"Shouldn't be able to insert another structure, which contains this structure, to this structure.");
}
catch (IllegalArgumentException e) {
// Should get an exception from inserting the struct to itself.
}
try {
struct.replace(0, anotherStruct, anotherStruct.getLength());
Assert.fail(
"Shouldn't be able to replace a structure component with another structure which contains this structure.");
}
catch (IllegalArgumentException e) {
// Should get an exception from replacing the struct to itself.
}
}
/**
* Test that a structure can't contain another structure that contains a typedef to it.
*/
@Test
public void testCyclicDependencyProblem5() {
Structure anotherStruct = createStructure("AnotherStruct", 0);
TypeDef typeDef = createTypeDef(struct);
anotherStruct.add(typeDef);
try {
struct.add(anotherStruct);
Assert.fail(
"Shouldn't be able to add another structure, which contains a typedef of this structure, to this structure.");
}
catch (IllegalArgumentException e) {
// Should get an exception from adding the struct to itself.
}
try {
struct.insert(0, anotherStruct);
Assert.fail(
"Shouldn't be able to insert another structure, which contains a typedef of this structure, to this structure.");
}
catch (IllegalArgumentException e) {
// Should get an exception from inserting the struct to itself.
}
try {
struct.replace(0, anotherStruct, anotherStruct.getLength());
Assert.fail(
"Shouldn't be able to replace a structure component with another structure which contains a typedef of this structure.");
}
catch (IllegalArgumentException e) {
// Should get an exception from replacing the struct to itself.
}
}
/**
* Test that a structure can't contain a union that contains that structure.
*/
@Test
public void testCyclicDependencyProblem6() {
Union union = createUnion("TestUnion");
union.add(struct);
try {
struct.add(union);
Assert.fail(
"Shouldn't be able to add a union, which contains this structure, to this structure.");
}
catch (IllegalArgumentException e) {
// Should get an exception from adding the struct to itself.
}
try {
struct.insert(0, union);
Assert.fail(
"Shouldn't be able to insert a union, which contains this structure, to this structure.");
}
catch (IllegalArgumentException e) {
// Should get an exception from inserting the struct to itself.
}
try {
struct.replace(0, union, union.getLength());
Assert.fail(
"Shouldn't be able to replace a structure component with a union, which contains this structure.");
}
catch (IllegalArgumentException e) {
// Should get an exception from replacing the struct to itself.
}
}
/**
* Test that a structure can't contain a typedef of a union that contains that structure.
*/
@Test
public void testCyclicDependencyProblem7() {
Union union = createUnion("TestUnion");
union.add(struct);
TypeDef typeDef = createTypeDef(union);
try {
struct.add(typeDef);
Assert.fail(
"Shouldn't be able to add a typedef of a union, which contains this structure, to this structure.");
}
catch (IllegalArgumentException e) {
// Should get an exception from adding the union typedef to the struct.
}
try {
struct.insert(0, typeDef);
Assert.fail(
"Shouldn't be able to insert a typedef of a union, which contains this structure, to this structure.");
}
catch (IllegalArgumentException e) {
// Should get an exception from inserting the union typedef to the struct.
}
try {
struct.replace(0, typeDef, typeDef.getLength());
Assert.fail(
"Shouldn't be able to replace a structure component with a typedef of a union, which contains this structure.");
}
catch (IllegalArgumentException e) {
// Should get an exception from replacing the struct component with the union typedef.
}
}
/**
* Test that a structure can contain a pointer in it to the same structure.
*/
@Test
public void testNoCyclicDependencyProblemForStructurePointer() {
Pointer structurePointer = createPointer(struct, 4);
try {
struct.add(structurePointer);
}
catch (IllegalArgumentException e) {
Assert.fail("Should be able to add a structure pointer to the pointer's structure.");
}
try {
struct.insert(0, structurePointer);
}
catch (IllegalArgumentException e) {
Assert.fail(
"Should be able to insert a structure pointer into the pointer's structure.");
}
try {
struct.replace(0, structurePointer, structurePointer.getLength());
}
catch (IllegalArgumentException e) {
Assert.fail(
"Should be able to replace a structure component with the structure's pointer.");
}
}
/**
* Test that a structure can contain a pointer in it to a typedef of the same structure.
*/
@Test
public void testNoCyclicDependencyProblemForTypedefPointer() {
TypeDef typeDef = createTypeDef(struct);
Pointer typedefPointer = createPointer(typeDef, 4);
try {
struct.add(typedefPointer);
}
catch (IllegalArgumentException e) {
Assert.fail(
"Should be able to add a structure typedef pointer to the pointer's structure.");
}
try {
struct.insert(0, typedefPointer);
}
catch (IllegalArgumentException e) {
Assert.fail(
"Should be able to insert a structure typedef pointer into the pointer's structure.");
}
try {
struct.replace(0, typedefPointer, typedefPointer.getLength());
}
catch (IllegalArgumentException e) {
Assert.fail(
"Should be able to replace a structure component with the structure's typedef pointer.");
}
}
/**
* Test that a structure can contain a pointer in it to a typedef of the same structure.
*/
@Test
public void testNoCyclicDependencyProblemForArrayPointer() {
TypeDef typeDef = createTypeDef(struct);
Array array = createArray(typeDef, 5);
Pointer arrayPointer = createPointer(array, 4);
try {
struct.add(arrayPointer);
}
catch (IllegalArgumentException e) {
Assert.fail(
"Should be able to add a structure typedef array pointer to the pointer's structure.");
}
try {
struct.insert(0, arrayPointer);
}
catch (IllegalArgumentException e) {
Assert.fail(
"Should be able to insert a structure typedef arrayointer into the pointer's structure.");
}
try {
struct.replace(0, arrayPointer, arrayPointer.getLength());
}
catch (IllegalArgumentException e) {
Assert.fail(
"Should be able to replace a structure component with the structure's typedef array pointer.");
}
}
}

View file

@ -1,448 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
*
*/
package ghidra.program.model.data;
import static org.junit.Assert.*;
import org.junit.*;
import generic.test.AbstractGenericTest;
/**
*
*/
public class UnionTest extends AbstractGenericTest {
private DataTypeManager dtm;
private Union union;
private int id;
private Union createUnion(String name) {
Union unionDt = new UnionDataType(name);
return (Union)dtm.addDataType(unionDt,DataTypeConflictHandler.DEFAULT_HANDLER);
}
private Structure createStructure(String name, int size) {
return (Structure)dtm.addDataType(new StructureDataType(name, size),DataTypeConflictHandler.DEFAULT_HANDLER);
}
private TypeDef createTypeDef(DataType dataType) {
return new TypedefDataType(dataType.getName()+"TypeDef", dataType);
}
private Array createArray(DataType dataType, int numElements) {
return new ArrayDataType(dataType, numElements, dataType.getLength());
}
private Pointer createPointer(DataType dataType, int length) {
return new PointerDataType(dataType, length);
}
/**
* Constructor for UnionTest.
* @param arg0
*/
public UnionTest() {
super();
}
/*
* @see TestCase#setUp()
*/
@Before
public void setUp() throws Exception {
dtm = new StandAloneDataTypeManager("dummyDTM");
id = dtm.startTransaction("");
union = createUnion("TestUnion");
union.add(new ByteDataType(), "field1", "Comment1");
union.add(new WordDataType(), null, "Comment2");
union.add(new DWordDataType(), "field3", null);
union.add(new ByteDataType(), "field4", "Comment4");
}
/*
* @see TestCase#tearDown()
*/
@After
public void tearDown() throws Exception {
dtm.endTransaction(id, true);
dtm.close();
}
@Test
public void testAdd() throws Exception {
assertEquals(4, union.getLength());
assertEquals(4, union.getNumComponents());
DataTypeComponent[] dtcs = union.getComponents();
assertEquals(4, dtcs.length);
DataTypeComponent dtc = union.getComponent(3);
assertEquals("field4", dtc.getFieldName());
assertEquals("byte", dtc.getDataType().getName());
Structure struct = new StructureDataType("struct_1", 0);
struct.add(new ByteDataType());
struct.add(new StringDataType(), 10);
union.add(struct);
assertEquals(struct.getLength(), union.getLength());
}
@Test
public void testAdd2() {
Structure struct = createStructure("struct_1", 0);
struct.add(new ByteDataType());
struct.add(new StringDataType(), 10);
union.add(struct);
union.delete(4);
assertEquals(4, union.getNumComponents());
assertEquals(4, union.getLength());
}
@Test
public void testGetComponent() {
Structure struct = createStructure("struct_1", 0);
struct.add(new ByteDataType());
struct.add(new StringDataType(), 10);
DataTypeComponent newdtc = union.add(struct, "field5", "comments");
DataTypeComponent dtc = union.getComponent(4);
assertEquals(newdtc, dtc);
assertEquals("field5", dtc.getFieldName());
assertEquals("comments", dtc.getComment());
}
@Test
public void testGetComponents() {
Structure struct = createStructure("struct_1", 0);
struct.add(new ByteDataType());
struct.add(new StringDataType(), 10);
union.add(struct, "field5", "comments");
DataTypeComponent[] dtcs = union.getComponents();
assertEquals(5, dtcs.length);
assertEquals(5, union.getNumComponents());
}
@Test
public void testInsert() {
Structure struct = createStructure("struct_1", 0);
struct.add(new ByteDataType());
struct.add(new StringDataType(), 10);
DataTypeComponent dtc = union.getComponent(2);
assertEquals("field3", dtc.getFieldName());
union.insert(2, struct, struct.getLength(), "field5", "field5 comments");
assertEquals(11, union.getLength());
dtc = union.getComponent(2);
assertEquals("field5", dtc.getFieldName());
}
@Test
public void testGetName() {
assertEquals("TestUnion", union.getName());
}
@Test
public void testCloneRetainIdentity() throws Exception {
Union unionCopy = (Union)union.clone(null);
assertNull(unionCopy.getDataTypeManager());
assertEquals(4, union.getLength());
}
@Test
public void testCopyDontRetain() throws Exception {
Union unionCopy = (Union)union.copy(null);
assertNull(unionCopy.getDataTypeManager());
assertEquals(4, union.getLength());
}
@Test
public void testDelete() throws Exception {
Structure struct = createStructure("struct_1", 0);
struct.add(new ByteDataType());
struct.add(new StringDataType(), 10);
union.add(struct);
assertEquals(11, union.getLength());
union.delete(4);
assertEquals(4, union.getLength());
union.delete(2);
assertEquals(2, union.getLength());
}
@Test
public void testIsPartOf() {
Structure struct = createStructure("struct_1", 0);
struct.add(new ByteDataType());
DataTypeComponent dtc = struct.add(createStructure("mystring", 10));
DataType dt = dtc.getDataType();
DataTypeComponent newdtc = union.add(struct);
assertTrue(union.isPartOf(dt));
Structure newstruct = (Structure)newdtc.getDataType();
Structure s1 = (Structure)newstruct.add(createStructure("s1", 1)).getDataType();
dt = s1.add(new QWordDataType()).getDataType();
assertTrue(union.isPartOf(dt));
}
@Test
public void testReplaceWith() {
assertEquals(4, union.getLength());
assertEquals(4, union.getNumComponents());
Union newUnion = createUnion("Replaced");
newUnion.setDescription("testReplaceWith()");
DataTypeComponent dtc2 = newUnion.insert(0, new DWordDataType(), 4, "field2", null);
DataTypeComponent dtc1 = newUnion.insert(0, new WordDataType(), 2, null, "Comment2");
DataTypeComponent dtc0 = newUnion.insert(0, new ByteDataType(), 1, "field0", "Comment1");
union.replaceWith(newUnion);
assertEquals(4, union.getLength());
assertEquals(3, union.getNumComponents());
DataTypeComponent[] dtcs = union.getComponents();
assertEquals(3, dtcs.length);
assertEquals(dtc0, dtcs[0]);
assertEquals(dtc1, dtcs[1]);
assertEquals(dtc2, dtcs[2]);
assertEquals("TestUnion", union.getName());
assertEquals("testReplaceWith()", union.getDescription());
}
@Test
public void testCyclingProblem() {
Union newUnion = createUnion("Test");
newUnion.setDescription("testReplaceWith()");
newUnion.add(new ByteDataType(), "field0", "Comment1");
newUnion.add(union, "field1", null);
newUnion.add(new WordDataType(), null, "Comment2");
newUnion.add(new DWordDataType(), "field3", null);
try {
union.add(newUnion);
Assert.fail();
} catch (IllegalArgumentException e) {
}
try {
union.insert(0, newUnion);
Assert.fail();
} catch (IllegalArgumentException e) {
}
}
/**
* Test that a structure can't be added to itself.
*/
@Test
public void testCyclicDependencyProblem1() {
try {
union.add(union);
Assert.fail("Shouldn't be able to add a union to itself.");
} catch (IllegalArgumentException e) {
// Should get an exception from adding the union to itself.
}
try {
union.insert(0, union);
Assert.fail("Shouldn't be able to insert a union into itself.");
} catch (IllegalArgumentException e) {
// Should get an exception from inserting the union to itself.
}
}
/**
* Test that a structure array can't be added to the same structure.
*/
@Test
public void testCyclicDependencyProblem2() {
Array array = createArray(union, 3);
try {
union.add(array);
Assert.fail("Shouldn't be able to add a union array to the same union.");
} catch (IllegalArgumentException e) {
// Should get an exception from adding the union to itself.
}
try {
union.insert(0, array);
Assert.fail("Shouldn't be able to insert a union array into the same union.");
} catch (IllegalArgumentException e) {
// Should get an exception from inserting the union to itself.
}
}
/**
* Test that a typedef of a union can't be added to the union.
*/
@Test
public void testCyclicDependencyProblem3() {
TypeDef typeDef = createTypeDef(union);
try {
union.add(typeDef);
Assert.fail("Shouldn't be able to add a union typedef to the typedef's union.");
} catch (IllegalArgumentException e) {
// Should get an exception from adding the union to itself.
}
try {
union.insert(0, typeDef);
Assert.fail("Shouldn't be able to insert a union typedef into the typedef's union.");
} catch (IllegalArgumentException e) {
// Should get an exception from inserting the union to itself.
}
}
/**
* Test that a union can't contain another union that contains it.
*/
@Test
public void testCyclicDependencyProblem4() {
Union anotherUnion = createUnion("AnotherUnion");
anotherUnion.add(union);
try {
union.add(anotherUnion);
Assert.fail("Shouldn't be able to add another union, which contains this union, to this union.");
} catch (IllegalArgumentException e) {
// Should get an exception from adding the union to itself.
}
try {
union.insert(0, anotherUnion);
Assert.fail("Shouldn't be able to insert another union, which contains this union, to this union.");
} catch (IllegalArgumentException e) {
// Should get an exception from inserting the union to itself.
}
}
/**
* Test that a union can't contain another union that contains a typedef to it.
*/
@Test
public void testCyclicDependencyProblem5() {
Union anotherUnion = createUnion("AnotherUnion");
TypeDef typeDef = createTypeDef(union);
anotherUnion.add(typeDef);
try {
union.add(anotherUnion);
Assert.fail("Shouldn't be able to add another union, which contains a typedef of this union, to this union.");
} catch (IllegalArgumentException e) {
// Should get an exception from adding the union to itself.
}
try {
union.insert(0, anotherUnion);
Assert.fail("Shouldn't be able to insert another union, which contains a typedef of this union, to this union.");
} catch (IllegalArgumentException e) {
// Should get an exception from inserting the union to itself.
}
}
/**
* Test that a union can't contain a structure that contains that union.
*/
@Test
public void testCyclicDependencyProblem6() {
Union structure = createUnion("TestStructure");
structure.add(union);
try {
union.add(structure);
Assert.fail("Shouldn't be able to add a structure, which contains this union, to this union.");
} catch (IllegalArgumentException e) {
// Should get an exception from adding the union to itself.
}
try {
union.insert(0, structure);
Assert.fail("Shouldn't be able to insert a structure, which contains this union, to this union.");
} catch (IllegalArgumentException e) {
// Should get an exception from inserting the union to itself.
}
}
/**
* Test that a structure can't contain a typedef of a union that contains that structure.
*/
@Test
public void testCyclicDependencyProblem7() {
Structure structure = createStructure("TestStructure", 0);
structure.add(union);
TypeDef typeDef = createTypeDef(structure);
try {
union.add(typeDef);
Assert.fail("Shouldn't be able to add a typedef of a strucutre, which contains this union, to this union.");
} catch (IllegalArgumentException e) {
// Should get an exception from adding the structure typedef to the union.
}
try {
union.insert(0, typeDef);
Assert.fail("Shouldn't be able to insert a typedef of a structure, which contains this union, to this union.");
} catch (IllegalArgumentException e) {
// Should get an exception from inserting the structure typedef to the union.
}
}
/**
* Test that a structure can contain a pointer in it to the same structure.
*/
@Test
public void testNoCyclicDependencyProblemForStructurePointer() {
Pointer unionPointer = createPointer(union, 4);
try {
union.add(unionPointer);
} catch (IllegalArgumentException e) {
Assert.fail("Should be able to add a union pointer to the pointer's union.");
}
try {
union.insert(0, unionPointer);
} catch (IllegalArgumentException e) {
Assert.fail("Should be able to insert a union pointer into the pointer's union.");
}
}
/**
* Test that a union can contain a pointer in it to a typedef of the same union.
*/
@Test
public void testNoCyclicDependencyProblemForTypedefPointer() {
TypeDef typeDef = createTypeDef(union);
Pointer typedefPointer = createPointer(typeDef, 4);
try {
union.add(typedefPointer);
} catch (IllegalArgumentException e) {
Assert.fail("Should be able to add a union typedef pointer to the pointer's union.");
}
try {
union.insert(0, typedefPointer);
} catch (IllegalArgumentException e) {
Assert.fail("Should be able to insert a union typedef pointer into the pointer's union.");
}
}
/**
* Test that a union can contain a pointer in it to a typedef of the same union.
*/
@Test
public void testNoCyclicDependencyProblemForArrayPointer() {
TypeDef typeDef = createTypeDef(union);
Array array = createArray(typeDef, 5);
Pointer arrayPointer = createPointer(array, 4);
try {
union.add(arrayPointer);
} catch (IllegalArgumentException e) {
Assert.fail("Should be able to add a union typedef array pointer to the pointer's union.");
}
try {
union.insert(0, arrayPointer);
} catch (IllegalArgumentException e) {
Assert.fail("Should be able to insert a union typedef array pointer into the pointer's union.");
}
}
}

View file

@ -0,0 +1,91 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.program.database.data;
import static org.junit.Assert.assertEquals;
import org.junit.Before;
import org.junit.Test;
import generic.test.AbstractGTest;
import ghidra.program.model.data.*;
public class BitFieldDBDataTypeTest extends AbstractGTest {
private DataTypeManager dataMgr;
@Before
public void setup() throws Exception {
dataMgr = new StandAloneDataTypeManager("dummyDTM");
dataMgr.startTransaction("Test");
}
@Test
public void testGetIdAndGetDataTypeFromId() throws Exception {
testRoundTrip(new BitFieldDBDataType(CharDataType.dataType, 1, 4, 1, dataMgr));
testRoundTrip(new BitFieldDBDataType(CharDataType.dataType, 2, 6, 1, dataMgr));
testRoundTrip(new BitFieldDBDataType(ShortDataType.dataType, 3, 2, 2, dataMgr));
testRoundTrip(new BitFieldDBDataType(UnsignedShortDataType.dataType, 4, 4, 1, dataMgr));
testRoundTrip(new BitFieldDBDataType(IntegerDataType.dataType, 5, 7, 2, dataMgr));
testRoundTrip(new BitFieldDBDataType(UnsignedIntegerDataType.dataType, 14, 2, 3, dataMgr));
testRoundTrip(new BitFieldDBDataType(LongDataType.dataType, 27, 2, 5, dataMgr));
testRoundTrip(new BitFieldDBDataType(UnsignedLongDataType.dataType, 6, 0, 1, dataMgr));
testRoundTrip(new BitFieldDBDataType(LongLongDataType.dataType, 6, 2, 2, dataMgr));
testRoundTrip(new BitFieldDBDataType(UnsignedLongLongDataType.dataType, 6, 2, 1, dataMgr));
// non-standard integer base types
testRoundTrip(new BitFieldDBDataType(ByteDataType.dataType, 6, 2, 1, dataMgr));
testRoundTrip(new BitFieldDBDataType(QWordDataType.dataType, 6, 2, 1, dataMgr));
// TypeDef base types
TypeDef foo = new TypedefDataType("foo", IntegerDataType.dataType);
testRoundTrip(new BitFieldDBDataType(foo, 6, 3, 2, dataMgr));
// Enum base types
EnumDataType fum = new EnumDataType("fum", 4);
fum.add("A", 1);
testRoundTrip(new BitFieldDBDataType(fum, 6, 2, 1, dataMgr));
}
private void testRoundTrip(BitFieldDataType packedBitFieldDataType) throws Exception {
// must resolve first to ensure that TypeDef ID can be encoded within ID,
// otherwise it will be omitted from ID if TypeDef does not already exist
// within corresponding data type manager.
// This is intended to replicate the order of events when a bit-field
// component is established where the component size corresponds to the
// exact storage size determined by the BitFieldAccumulator during packing
BitFieldDataType bitFieldDataType =
(BitFieldDataType) dataMgr.resolve(packedBitFieldDataType, null);
long id = BitFieldDBDataType.getId(bitFieldDataType);
// The only thing which is preserved is the bitSize, storageSize and bitOffset/Shift
bitFieldDataType = BitFieldDBDataType.getBitFieldDataType(id, dataMgr);
assertEquals(packedBitFieldDataType.getBitSize(), bitFieldDataType.getBitSize());
assertEquals(packedBitFieldDataType.getDeclaredBitSize(),
bitFieldDataType.getDeclaredBitSize());
assertEquals(packedBitFieldDataType.getBitOffset(), bitFieldDataType.getBitOffset());
assertEquals(packedBitFieldDataType.getStorageSize(), bitFieldDataType.getStorageSize());
}
}

View file

@ -0,0 +1,654 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
*
*/
package ghidra.program.database.data;
import static org.junit.Assert.*;
import org.junit.*;
import generic.test.AbstractGTest;
import ghidra.program.model.data.*;
import ghidra.util.task.TaskMonitor;
/**
*
*/
public class UnionDBTest extends AbstractGTest {
private DataTypeManager dataMgr;
private UnionDB union;
@Before
public void setUp() throws Exception {
dataMgr = new StandAloneDataTypeManager("dummydataMgr");
// default data organization is little-endian
dataMgr.startTransaction("Test");
union = createUnion("TestUnion");
union.add(new ByteDataType(), "field1", "Comment1");
union.add(new WordDataType(), null, "Comment2");
union.add(new DWordDataType(), "field3", null);
union.add(new ByteDataType(), "field4", "Comment4");
}
private void transitionToBigEndian() {
Union unionClone = (Union) union.clone(null);
dataMgr.remove(union, TaskMonitor.DUMMY);
DataOrganizationImpl dataOrg = (DataOrganizationImpl) dataMgr.getDataOrganization();
dataOrg.setBigEndian(true);
// re-resolve with modified endianess
union = (UnionDB) dataMgr.resolve(unionClone, null);
}
private UnionDB createUnion(String name) {
Union unionDt = new UnionDataType(name);
return (UnionDB) dataMgr.addDataType(unionDt, DataTypeConflictHandler.DEFAULT_HANDLER);
}
private Structure createStructure(String name, int size) {
return (Structure) dataMgr.addDataType(new StructureDataType(name, size),
DataTypeConflictHandler.DEFAULT_HANDLER);
}
private TypeDef createTypeDef(DataType dataType) {
return new TypedefDataType(dataType.getName() + "TypeDef", dataType);
}
private Array createArray(DataType dataType, int numElements) {
return new ArrayDataType(dataType, numElements, dataType.getLength());
}
private Pointer createPointer(DataType dataType, int length) {
return new PointerDataType(dataType, length);
}
@Test
public void testAdd() throws Exception {
assertEquals(4, union.getLength());
assertEquals(4, union.getNumComponents());
DataTypeComponent[] dtcs = union.getComponents();
assertEquals(4, dtcs.length);
DataTypeComponent dtc = union.getComponent(3);
assertEquals("field4", dtc.getFieldName());
assertEquals("byte", dtc.getDataType().getName());
Structure struct = new StructureDataType("struct_1", 0);
struct.add(new ByteDataType());
struct.add(new StringDataType(), 10);
union.add(struct);
assertEquals(struct.getLength(), union.getLength());
}
@Test
public void testAdd2() {
Structure struct = createStructure("struct_1", 0);
struct.add(new ByteDataType());
struct.add(new StringDataType(), 10);
union.add(struct);
union.delete(4);
assertEquals(4, union.getNumComponents());
assertEquals(4, union.getLength());
}
@Test
public void testGetComponent() {
Structure struct = createStructure("struct_1", 0);
struct.add(new ByteDataType());
struct.add(new StringDataType(), 10);
DataTypeComponent newdtc = union.add(struct, "field5", "comments");
DataTypeComponent dtc = union.getComponent(4);
assertEquals(newdtc, dtc);
assertEquals("field5", dtc.getFieldName());
assertEquals("comments", dtc.getComment());
}
@Test
public void testGetComponents() {
Structure struct = createStructure("struct_1", 0);
struct.add(new ByteDataType());
struct.add(new StringDataType(), 10);
union.add(struct, "field5", "comments");
DataTypeComponent[] dtcs = union.getComponents();
assertEquals(5, dtcs.length);
assertEquals(5, union.getNumComponents());
}
@Test
public void testInsert() {
Structure struct = createStructure("struct_1", 0);
struct.add(new ByteDataType());
struct.add(new StringDataType(), 10);
DataTypeComponent dtc = union.getComponent(2);
assertEquals("field3", dtc.getFieldName());
union.insert(2, struct, struct.getLength(), "field5", "field5 comments");
assertEquals(11, union.getLength());
dtc = union.getComponent(2);
assertEquals("field5", dtc.getFieldName());
}
@Test
public void testBitFieldUnionLength() throws Exception {
int cnt = union.getNumComponents();
for (int i = 0; i < cnt; i++) {
union.delete(0);
}
union.insertBitField(0, 4, 12, IntegerDataType.dataType, 2, "bf1", "bf1Comment");
union.insert(0, ShortDataType.dataType);
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/TestUnion\n" +
"Unaligned\n" +
"Union TestUnion {\n" +
" 0 short 2 null \"\"\n" +
" 1 byte:2(4) 1 bf1 \"bf1Comment\"\n" +
"}\n" +
"Size = 4 Actual Alignment = 1", union);
//@formatter:on
}
@Test
public void testInsertBitFieldLittleEndian() throws Exception {
union.insertBitField(2, 4, 0, IntegerDataType.dataType, 4, "bf1", "bf1Comment");
union.insertBitField(3, 1, 0, ByteDataType.dataType, 4, "bf2", "bf2Comment");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/TestUnion\n" +
"Unaligned\n" +
"Union TestUnion {\n" +
" 0 byte 1 field1 \"Comment1\"\n" +
" 0 word 2 null \"Comment2\"\n" +
" 0 int:4(0) 1 bf1 \"bf1Comment\"\n" +
" 0 byte:4(0) 1 bf2 \"bf2Comment\"\n" +
" 0 dword 4 field3 \"\"\n" +
" 0 byte 1 field4 \"Comment4\"\n" +
"}\n" +
"Size = 4 Actual Alignment = 1", union);
//@formatter:on
}
@Test
public void testInsertBitFieldBigEndian() throws Exception {
transitionToBigEndian();
union.insertBitField(2, 4, 0, IntegerDataType.dataType, 4, "bf1", "bf1Comment");
union.insertBitField(3, 1, 0, ByteDataType.dataType, 4, "bf2", "bf2Comment");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/TestUnion\n" +
"Unaligned\n" +
"Union TestUnion {\n" +
" 0 byte 1 field1 \"Comment1\"\n" +
" 0 word 2 null \"Comment2\"\n" +
" 0 int:4(4) 1 bf1 \"bf1Comment\"\n" +
" 0 byte:4(4) 1 bf2 \"bf2Comment\"\n" +
" 0 dword 4 field3 \"\"\n" +
" 0 byte 1 field4 \"Comment4\"\n" +
"}\n" +
"Size = 4 Actual Alignment = 1", union);
//@formatter:on
}
@Test
public void testDeleteBitFieldDependency() throws InvalidDataTypeException {
TypeDef td = new TypedefDataType("Foo", IntegerDataType.dataType);
td = (TypeDef) dataMgr.resolve(td, null);
union.insertBitField(2, 4, 0, td, 4, "bf1", "bf1Comment");
union.insertBitField(3, 1, 0, td, 4, "bf2", "bf2Comment");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/TestUnion\n" +
"Unaligned\n" +
"Union TestUnion {\n" +
" 0 byte 1 field1 \"Comment1\"\n" +
" 0 word 2 null \"Comment2\"\n" +
" 0 Foo:4(0) 1 bf1 \"bf1Comment\"\n" +
" 0 Foo:4(0) 1 bf2 \"bf2Comment\"\n" +
" 0 dword 4 field3 \"\"\n" +
" 0 byte 1 field4 \"Comment4\"\n" +
"}\n" +
"Size = 4 Actual Alignment = 1", union);
//@formatter:on
dataMgr.remove(td, TaskMonitor.DUMMY);
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/TestUnion\n" +
"Unaligned\n" +
"Union TestUnion {\n" +
" 0 byte 1 field1 \"Comment1\"\n" +
" 0 word 2 null \"Comment2\"\n" +
" 0 dword 4 field3 \"\"\n" +
" 0 byte 1 field4 \"Comment4\"\n" +
"}\n" +
"Size = 4 Actual Alignment = 1", union);
//@formatter:on
}
@Test
public void testReplaceBitFieldDependency()
throws InvalidDataTypeException, DataTypeDependencyException {
TypeDef td = new TypedefDataType("Foo", IntegerDataType.dataType);
td = (TypeDef) dataMgr.resolve(td, null);
union.insertBitField(2, 4, 0, td, 4, "bf1", "bf1Comment");
union.insertBitField(3, 1, 0, td, 4, "bf2", "bf2Comment");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/TestUnion\n" +
"Unaligned\n" +
"Union TestUnion {\n" +
" 0 byte 1 field1 \"Comment1\"\n" +
" 0 word 2 null \"Comment2\"\n" +
" 0 Foo:4(0) 1 bf1 \"bf1Comment\"\n" +
" 0 Foo:4(0) 1 bf2 \"bf2Comment\"\n" +
" 0 dword 4 field3 \"\"\n" +
" 0 byte 1 field4 \"Comment4\"\n" +
"}\n" +
"Size = 4 Actual Alignment = 1", union);
//@formatter:on
dataMgr.replaceDataType(td, CharDataType.dataType, false);
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/TestUnion\n" +
"Unaligned\n" +
"Union TestUnion {\n" +
" 0 byte 1 field1 \"Comment1\"\n" +
" 0 word 2 null \"Comment2\"\n" +
" 0 char:4(0) 1 bf1 \"bf1Comment\"\n" +
" 0 char:4(0) 1 bf2 \"bf2Comment\"\n" +
" 0 dword 4 field3 \"\"\n" +
" 0 byte 1 field4 \"Comment4\"\n" +
"}\n" +
"Size = 4 Actual Alignment = 1", union);
//@formatter:on
}
@Test
public void testGetName() {
assertEquals("TestUnion", union.getName());
}
@Test
public void testCloneRetainIdentity() throws Exception {
Union unionCopy = (Union) union.clone(null);
assertNull(unionCopy.getDataTypeManager());
assertEquals(4, union.getLength());
}
@Test
public void testCopyDontRetain() throws Exception {
Union unionCopy = (Union) union.copy(null);
assertNull(unionCopy.getDataTypeManager());
assertEquals(4, union.getLength());
}
@Test
public void testDelete() throws Exception {
Structure struct = createStructure("struct_1", 0);
struct.add(new ByteDataType());
struct.add(new StringDataType(), 10);
union.add(struct);
assertEquals(11, union.getLength());
union.delete(4);
assertEquals(4, union.getLength());
union.delete(2);
assertEquals(2, union.getLength());
}
@Test
public void testIsPartOf() {
Structure struct = createStructure("struct_1", 0);
struct.add(new ByteDataType());
DataTypeComponent dtc = struct.add(createStructure("mystring", 10));
DataType dt = dtc.getDataType();
DataTypeComponent newdtc = union.add(struct);
assertTrue(union.isPartOf(dt));
Structure newstruct = (Structure) newdtc.getDataType();
Structure s1 = (Structure) newstruct.add(createStructure("s1", 1)).getDataType();
dt = s1.add(new QWordDataType()).getDataType();
assertTrue(union.isPartOf(dt));
}
@Test
public void testReplaceWith() throws InvalidDataTypeException {
assertEquals(4, union.getLength());
assertEquals(4, union.getNumComponents());
Union newUnion = createUnion("Replaced");
newUnion.setDescription("testReplaceWith()");
newUnion.insert(0, new DWordDataType(), 4, "field2", null);
newUnion.insert(0, new WordDataType(), 2, null, "Comment2");
newUnion.insert(0, new ByteDataType(), 1, "field0", "Comment1");
newUnion.addBitField(IntegerDataType.dataType, 4, "MyBit1", "bitComment1");
newUnion.addBitField(IntegerDataType.dataType, 3, "MyBit2", "bitComment2");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/Replaced\n" +
"Unaligned\n" +
"Union Replaced {\n" +
" 0 byte 1 field0 \"Comment1\"\n" +
" 0 word 2 null \"Comment2\"\n" +
" 0 dword 4 field2 \"\"\n" +
" 0 int:4(0) 1 MyBit1 \"bitComment1\"\n" +
" 0 int:3(0) 1 MyBit2 \"bitComment2\"\n" +
"}\n" +
"Size = 4 Actual Alignment = 1", newUnion);
//@formatter:on
union.replaceWith(newUnion);
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/TestUnion\n" +
"Unaligned\n" +
"Union TestUnion {\n" +
" 0 byte 1 field0 \"Comment1\"\n" +
" 0 word 2 null \"Comment2\"\n" +
" 0 dword 4 field2 \"\"\n" +
" 0 int:4(0) 1 MyBit1 \"bitComment1\"\n" +
" 0 int:3(0) 1 MyBit2 \"bitComment2\"\n" +
"}\n" +
"Size = 4 Actual Alignment = 1", union);
//@formatter:on
assertEquals("", union.getDescription()); // unchanged
}
@Test
public void testCyclingProblem() {
Union newUnion = createUnion("Test");
newUnion.setDescription("testReplaceWith()");
newUnion.add(new ByteDataType(), "field0", "Comment1");
newUnion.add(union, "field1", null);
newUnion.add(new WordDataType(), null, "Comment2");
newUnion.add(new DWordDataType(), "field3", null);
try {
union.add(newUnion);
Assert.fail();
}
catch (IllegalArgumentException e) {
// expected
}
try {
union.insert(0, newUnion);
Assert.fail();
}
catch (IllegalArgumentException e) {
// expected
}
}
/**
* Test that a structure can't be added to itself.
*/
@Test
public void testCyclicDependencyProblem1() {
try {
union.add(union);
Assert.fail("Shouldn't be able to add a union to itself.");
}
catch (IllegalArgumentException e) {
// Should get an exception from adding the union to itself.
}
try {
union.insert(0, union);
Assert.fail("Shouldn't be able to insert a union into itself.");
}
catch (IllegalArgumentException e) {
// Should get an exception from inserting the union to itself.
}
}
/**
* Test that a structure array can't be added to the same structure.
*/
@Test
public void testCyclicDependencyProblem2() {
Array array = createArray(union, 3);
try {
union.add(array);
Assert.fail("Shouldn't be able to add a union array to the same union.");
}
catch (IllegalArgumentException e) {
// Should get an exception from adding the union to itself.
}
try {
union.insert(0, array);
Assert.fail("Shouldn't be able to insert a union array into the same union.");
}
catch (IllegalArgumentException e) {
// Should get an exception from inserting the union to itself.
}
}
/**
* Test that a typedef of a union can't be added to the union.
*/
@Test
public void testCyclicDependencyProblem3() {
TypeDef typeDef = createTypeDef(union);
try {
union.add(typeDef);
Assert.fail("Shouldn't be able to add a union typedef to the typedef's union.");
}
catch (IllegalArgumentException e) {
// Should get an exception from adding the union to itself.
}
try {
union.insert(0, typeDef);
Assert.fail("Shouldn't be able to insert a union typedef into the typedef's union.");
}
catch (IllegalArgumentException e) {
// Should get an exception from inserting the union to itself.
}
}
/**
* Test that a union can't contain another union that contains it.
*/
@Test
public void testCyclicDependencyProblem4() {
Union anotherUnion = createUnion("AnotherUnion");
anotherUnion.add(union);
try {
union.add(anotherUnion);
Assert.fail(
"Shouldn't be able to add another union, which contains this union, to this union.");
}
catch (IllegalArgumentException e) {
// Should get an exception from adding the union to itself.
}
try {
union.insert(0, anotherUnion);
Assert.fail(
"Shouldn't be able to insert another union, which contains this union, to this union.");
}
catch (IllegalArgumentException e) {
// Should get an exception from inserting the union to itself.
}
}
/**
* Test that a union can't contain another union that contains a typedef to it.
*/
@Test
public void testCyclicDependencyProblem5() {
Union anotherUnion = createUnion("AnotherUnion");
TypeDef typeDef = createTypeDef(union);
anotherUnion.add(typeDef);
try {
union.add(anotherUnion);
Assert.fail(
"Shouldn't be able to add another union, which contains a typedef of this union, to this union.");
}
catch (IllegalArgumentException e) {
// Should get an exception from adding the union to itself.
}
try {
union.insert(0, anotherUnion);
Assert.fail(
"Shouldn't be able to insert another union, which contains a typedef of this union, to this union.");
}
catch (IllegalArgumentException e) {
// Should get an exception from inserting the union to itself.
}
}
/**
* Test that a union can't contain a structure that contains that union.
*/
@Test
public void testCyclicDependencyProblem6() {
Union structure = createUnion("TestStructure");
structure.add(union);
try {
union.add(structure);
Assert.fail(
"Shouldn't be able to add a structure, which contains this union, to this union.");
}
catch (IllegalArgumentException e) {
// Should get an exception from adding the union to itself.
}
try {
union.insert(0, structure);
Assert.fail(
"Shouldn't be able to insert a structure, which contains this union, to this union.");
}
catch (IllegalArgumentException e) {
// Should get an exception from inserting the union to itself.
}
}
/**
* Test that a structure can't contain a typedef of a union that contains that structure.
*/
@Test
public void testCyclicDependencyProblem7() {
Structure structure = createStructure("TestStructure", 0);
structure.add(union);
TypeDef typeDef = createTypeDef(structure);
try {
union.add(typeDef);
Assert.fail(
"Shouldn't be able to add a typedef of a strucutre, which contains this union, to this union.");
}
catch (IllegalArgumentException e) {
// Should get an exception from adding the structure typedef to the union.
}
try {
union.insert(0, typeDef);
Assert.fail(
"Shouldn't be able to insert a typedef of a structure, which contains this union, to this union.");
}
catch (IllegalArgumentException e) {
// Should get an exception from inserting the structure typedef to the union.
}
}
/**
* Test that a structure can contain a pointer in it to the same structure.
*/
@Test
public void testNoCyclicDependencyProblemForStructurePointer() {
Pointer unionPointer = createPointer(union, 4);
try {
union.add(unionPointer);
}
catch (IllegalArgumentException e) {
Assert.fail("Should be able to add a union pointer to the pointer's union.");
}
try {
union.insert(0, unionPointer);
}
catch (IllegalArgumentException e) {
e.printStackTrace();
Assert.fail("Should be able to insert a union pointer into the pointer's union.");
}
}
/**
* Test that a union can contain a pointer in it to a typedef of the same union.
*/
@Test
public void testNoCyclicDependencyProblemForTypedefPointer() {
TypeDef typeDef = createTypeDef(union);
Pointer typedefPointer = createPointer(typeDef, 4);
try {
union.add(typedefPointer);
}
catch (IllegalArgumentException e) {
Assert.fail("Should be able to add a union typedef pointer to the pointer's union.");
}
try {
union.insert(0, typedefPointer);
}
catch (IllegalArgumentException e) {
Assert.fail(
"Should be able to insert a union typedef pointer into the pointer's union.");
}
}
/**
* Test that a union can contain a pointer in it to a typedef of the same union.
*/
@Test
public void testNoCyclicDependencyProblemForArrayPointer() {
TypeDef typeDef = createTypeDef(union);
Array array = createArray(typeDef, 5);
Pointer arrayPointer = createPointer(array, 4);
try {
union.add(arrayPointer);
}
catch (IllegalArgumentException e) {
Assert.fail(
"Should be able to add a union typedef array pointer to the pointer's union.");
}
try {
union.insert(0, arrayPointer);
}
catch (IllegalArgumentException e) {
Assert.fail(
"Should be able to insert a union typedef array pointer into the pointer's union.");
}
}
}

View file

@ -0,0 +1,193 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.program.model.data;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import generic.test.AbstractGTest;
import ghidra.docking.settings.*;
import ghidra.program.model.mem.ByteMemBufferImpl;
import ghidra.program.model.mem.MemBuffer;
import ghidra.program.model.scalar.Scalar;
public class BitFieldDataTypeTest extends AbstractGTest {
@Test
public void testGetBaseSize() throws Exception {
assertEquals(1, new BitFieldDataType(CharDataType.dataType, 1).getBaseTypeSize());
assertEquals(1, new BitFieldDataType(UnsignedCharDataType.dataType, 1).getBaseTypeSize());
assertEquals(2, new BitFieldDataType(ShortDataType.dataType, 1).getBaseTypeSize());
assertEquals(2, new BitFieldDataType(UnsignedShortDataType.dataType, 1).getBaseTypeSize());
assertEquals(4, new BitFieldDataType(IntegerDataType.dataType, 1).getBaseTypeSize());
assertEquals(4,
new BitFieldDataType(UnsignedIntegerDataType.dataType, 1).getBaseTypeSize());
}
@Test
public void testGetName() throws Exception {
assertEquals("char:1", new BitFieldDataType(CharDataType.dataType, 1).getName());
assertEquals("uchar:2", new BitFieldDataType(UnsignedCharDataType.dataType, 2).getName());
assertEquals("short:3", new BitFieldDataType(ShortDataType.dataType, 3).getName());
assertEquals("ushort:4", new BitFieldDataType(UnsignedShortDataType.dataType, 4).getName());
assertEquals("int:5", new BitFieldDataType(IntegerDataType.dataType, 5).getName());
assertEquals("uint:6", new BitFieldDataType(UnsignedIntegerDataType.dataType, 6).getName());
}
@Test
public void testGetBaseDataType() throws Exception {
assertEquals(new CharDataType(),
new BitFieldDataType(CharDataType.dataType, 1).getBaseDataType());
assertEquals(new UnsignedCharDataType(),
new BitFieldDataType(UnsignedCharDataType.dataType, 1).getBaseDataType());
assertEquals(new ShortDataType(),
new BitFieldDataType(ShortDataType.dataType, 1).getBaseDataType());
assertEquals(new UnsignedShortDataType(),
new BitFieldDataType(UnsignedShortDataType.dataType, 1).getBaseDataType());
assertEquals(new IntegerDataType(),
new BitFieldDataType(IntegerDataType.dataType, 1).getBaseDataType());
assertEquals(new UnsignedIntegerDataType(),
new BitFieldDataType(UnsignedIntegerDataType.dataType, 1).getBaseDataType());
DataType typeDef = new TypedefDataType("Foo", LongDataType.dataType);
BitFieldDataType bf = new BitFieldDataType(typeDef, 1);
assertEquals(typeDef, bf.getBaseDataType());
assertEquals(typeDef, bf.clone(null).getBaseDataType());
}
@Test
public void testClone() throws Exception {
BitFieldDataType bf = new BitFieldDataType(UnsignedIntegerDataType.dataType, 1);
assertEquals(UnsignedIntegerDataType.dataType, bf.getBaseDataType());
BitFieldDataType bfClone = bf.clone(null);
assertEquals(UnsignedIntegerDataType.dataType, bfClone.getBaseDataType());
assertEquals(bfClone, bf);
DataType typeDef = new TypedefDataType("Foo", LongDataType.dataType);
bf = new BitFieldDataType(typeDef, 1);
assertEquals(typeDef, bf.getBaseDataType());
bfClone = bf.clone(null);
assertEquals(typeDef, bfClone.getBaseDataType());
assertEquals(bfClone, bf);
}
@Test
public void testGetBitSize() throws Exception {
assertEquals(1, new BitFieldDataType(CharDataType.dataType, 1).getBitSize());
assertEquals(2, new BitFieldDataType(UnsignedCharDataType.dataType, 2).getBitSize());
assertEquals(3, new BitFieldDataType(ShortDataType.dataType, 3).getBitSize());
assertEquals(4, new BitFieldDataType(UnsignedShortDataType.dataType, 4).getBitSize());
assertEquals(5, new BitFieldDataType(IntegerDataType.dataType, 5).getBitSize());
assertEquals(6, new BitFieldDataType(UnsignedIntegerDataType.dataType, 6).getBitSize());
}
// @Test
// public void testGetBitOffset() throws Exception {
// assertEquals(0,
// new BitFieldDataType(IntegerDataType.dataType, 1, null).deriveBitField(0, 4, 1, 4).getBitOffset());
// assertEquals(1,
// new BitFieldDataType(IntegerDataType.dataType, 2, null).deriveBitField(1, 4, 1, 4).getBitOffset());
// assertEquals(2,
// new BitFieldDataType(IntegerDataType.dataType, 3, null).deriveBitField(2, 4, 1, 4).getBitOffset());
// assertEquals(3,
// new BitFieldDataType(IntegerDataType.dataType, 4, null).deriveBitField(3, 4, 1, 4).getBitOffset());
// assertEquals(4,
// new BitFieldDataType(IntegerDataType.dataType, 5, null).deriveBitField(4, 4, 1, 4).getBitOffset());
// assertEquals(5,
// new BitFieldDataType(IntegerDataType.dataType, 6, null).deriveBitField(5, 4, 1, 4).getBitOffset());
// }
@Test
public void testGetValueWithSignedBaseType() throws Exception {
assertEquals(-1, getValue(bitField(1, 0), 0x55));
assertEquals(0, getValue(bitField(1, 1), 0x55));
assertEquals(1, getValue(bitField(2, 0), 0x55));
assertEquals(-3, getValue(bitField(3, 0), 0x55));
assertEquals(5, getValue(bitField(4, 0), 0x55));
}
@Test
public void testGetValueWithUnsignedBaseType() throws Exception {
assertEquals(1, getValue(unsignedBitField(1, 0), 0x55));
assertEquals(0, getValue(unsignedBitField(1, 1), 0x55));
assertEquals(1, getValue(unsignedBitField(2, 0), 0x55));
assertEquals(5, getValue(unsignedBitField(3, 0), 0x55));
assertEquals(5, getValue(unsignedBitField(4, 0), 0x55));
}
@Test
public void testHexRepresentationSignedBaseType() throws Exception {
assertEquals("1h", getRepresentation(bitField(1, 0), 0x55));
assertEquals("0h", getRepresentation(bitField(1, 1), 0x55));
assertEquals("1h", getRepresentation(bitField(2, 0), 0x55));
assertEquals("5h", getRepresentation(bitField(3, 0), 0x55));
assertEquals("5h", getRepresentation(bitField(4, 0), 0x55));
}
@Test
public void testDecimalRepresentationSignedBaseType() throws Exception {
assertEquals("-1", getDecimalRepresentation(bitField(1, 0), 0x55));
assertEquals("0", getDecimalRepresentation(bitField(1, 1), 0x55));
assertEquals("1", getDecimalRepresentation(bitField(2, 0), 0x55));
assertEquals("-3", getDecimalRepresentation(bitField(3, 0), 0x55));
assertEquals("5", getDecimalRepresentation(bitField(4, 0), 0x55));
}
@Test
public void testDecimalRepresentationUnsignedBaseType() throws Exception {
assertEquals("1", getDecimalRepresentation(unsignedBitField(1, 0), 0x55));
assertEquals("0", getDecimalRepresentation(unsignedBitField(1, 1), 0x55));
assertEquals("1", getDecimalRepresentation(unsignedBitField(2, 0), 0x55));
assertEquals("5", getDecimalRepresentation(unsignedBitField(3, 0), 0x55));
assertEquals("5", getDecimalRepresentation(unsignedBitField(4, 0), 0x55));
}
private String getRepresentation(BitFieldDataType bitField, int... bytes) throws Exception {
MemBuffer membuf = membuf(bytes);
return bitField.getRepresentation(membuf, null, 4);
}
private String getDecimalRepresentation(BitFieldDataType bitField, int... bytes)
throws Exception {
MemBuffer membuf = membuf(bytes);
Settings settings = new SettingsImpl();
FormatSettingsDefinition.DEF_DECIMAL.setDisplayChoice(settings, "decimal");
return bitField.getRepresentation(membuf, settings, bitField.getStorageSize());
}
private int getValue(BitFieldDataType bitField, int... bytes) throws Exception {
MemBuffer membuf = membuf(bytes);
Scalar scalar = (Scalar) bitField.getValue(membuf, null, bitField.getStorageSize());
return (int) scalar.getValue();
}
private BitFieldDataType bitField(int size, int offset) throws Exception {
int storageSize = BitFieldDataType.getMinimumStorageSize(size);
return new BitFieldDataType(IntegerDataType.dataType, size, offset, storageSize);
}
private BitFieldDataType unsignedBitField(int size, int offset) throws Exception {
int storageSize = BitFieldDataType.getMinimumStorageSize(size);
return new BitFieldDataType(UnsignedIntegerDataType.dataType, size, offset, storageSize);
}
private MemBuffer membuf(int... bytes) throws Exception {
return new ByteMemBufferImpl(null, true, bytes);
}
}

Some files were not shown because too many files have changed in this diff Show more