GP-943 Added support for zero-length arrays and

zero-length components.  NOTE: We still never return 0 for
DataType.getLength().  Added DataType.isZeroLength().
This commit is contained in:
ghidra1
2021-08-10 17:51:35 -04:00
parent 579e3bacf7
commit cfdec26da4
188 changed files with 7968 additions and 6645 deletions
@@ -116,8 +116,14 @@ public interface DBTraceDefinedDataAdapter extends DBTraceDataAdapter {
}
}
@Deprecated
@Override
default DBTraceDefinedDataAdapter getComponentAt(int offset) {
return getComponentContaining(offset);
}
@Override
default DBTraceDefinedDataAdapter getComponentContaining(int offset) {
// We may write to the cache
try (LockHold hold = LockHold.lock(getTrace().getReadWriteLock().writeLock())) {
if (offset < 0 || offset >= getLength()) {
@@ -133,7 +139,7 @@ public interface DBTraceDefinedDataAdapter extends DBTraceDataAdapter {
}
if (baseDataType instanceof Structure) {
Structure structure = (Structure) baseDataType;
DataTypeComponent dtc = structure.getComponentAt(offset);
DataTypeComponent dtc = structure.getComponentContaining(offset);
return dtc == null ? null : getComponent(dtc.getOrdinal());
}
if (baseDataType instanceof Union) {
@@ -155,7 +161,6 @@ public interface DBTraceDefinedDataAdapter extends DBTraceDataAdapter {
if (offset < 0 || offset >= getLength()) {
return null;
}
DataType baseDataType = getBaseDataType();
if (baseDataType instanceof Array) {
Array array = (Array) baseDataType;
@@ -163,24 +168,30 @@ public interface DBTraceDefinedDataAdapter extends DBTraceDataAdapter {
int index = offset / elementLength;
return Collections.singletonList(getComponent(index));
}
if (baseDataType instanceof Structure) {
Structure structure = (Structure) baseDataType;
DataTypeComponent dtc = structure.getComponentAt(offset);
else if (baseDataType instanceof Structure) {
Structure struct = (Structure) baseDataType;
List<Data> result = new ArrayList<>();
// Logic handles overlapping bit fields
for (DataTypeComponent dtc : struct.getComponentsContaining(offset)) {
result.add(getComponent(dtc.getOrdinal()));
}
return result;
}
else if (baseDataType instanceof DynamicDataType) {
DynamicDataType ddt = (DynamicDataType) baseDataType;
DataTypeComponent dtc = ddt.getComponentAt(offset, this);
List<Data> result = new ArrayList<>();
// Logic handles overlapping bit-fields
// Include if offset is contained within bounds of component
while (dtc != null && offset >= dtc.getOffset() &&
offset <= dtc.getOffset() + dtc.getLength() - 1) {
int ordinal = dtc.getOrdinal(); // TODO: Seems I could move this before while
result.add(getComponent(ordinal));
ordinal++;
dtc = ordinal < structure.getNumComponents() ? structure.getComponent(ordinal)
while (dtc != null && (offset >= dtc.getOffset()) &&
(offset < (dtc.getOffset() + dtc.getLength()))) {
int ordinal = dtc.getOrdinal();
result.add(getComponent(ordinal++));
dtc = ordinal < ddt.getNumComponents(this) ? ddt.getComponent(ordinal, this)
: null;
}
return result;
}
if (baseDataType instanceof Union) {
/** NOTE: The {@link DataDB} implementation seems hasty */
else if (baseDataType instanceof Union) {
Union union = (Union) baseDataType;
List<Data> result = new ArrayList<>();
for (DataTypeComponent dtc : union.getComponents()) {
@@ -190,12 +201,6 @@ public interface DBTraceDefinedDataAdapter extends DBTraceDataAdapter {
}
return result;
}
if (baseDataType instanceof DynamicDataType) {
DynamicDataType dynamic = (DynamicDataType) baseDataType;
DataTypeComponent dtc = dynamic.getComponentAt(offset, this);
return dtc == null ? Collections.emptyList()
: Collections.singletonList(getComponent(dtc.getOrdinal()));
}
return Collections.emptyList();
}
}
@@ -237,6 +237,11 @@ public class UndefinedDBTraceData implements DBTraceDataAdapter, DBTraceSpaceKey
return null;
}
@Override
public Data getComponentContaining(int offset) {
return null;
}
@Override
public List<Data> getComponentsContaining(int offset) {
if (offset < 0 || offset >= getLength()) {
@@ -1414,8 +1414,8 @@ public class DBTraceCodeUnitTest extends AbstractGhidraHeadlessIntegrationTest
assertNull(u3fff.getFieldName());
assertNull(s4000.getFieldName());
assertEquals("nuD", s4000nuD.getFieldName());
assertEquals("field_0x4", s4000lE.getFieldName());
assertEquals("field_0x8", s4000pF.getFieldName());
assertEquals("field2_0x4", s4000lE.getFieldName());
assertEquals("field3_0x8", s4000pF.getFieldName());
// TODO: DAT... may change when proper symbols are implemented
assertEquals("DAT_00003fff", u3fff.getPathName());
@@ -85,6 +85,10 @@ public abstract class DBDomainObjectSupport extends DomainObjectAdapterDB {
}
catch (VersionException e) {
versionExc = e.combine(versionExc);
// TODO: (see GP-1238) Consider properly supporting VersionException and upgrades.
// Returning a null manager will likely induce an NPE down the line.
return null;
}
}
Binary file not shown.
@@ -373,28 +373,22 @@
<P><IMG alt="Note:" src="../../shared/note.png">The use of bitfield components is not
currently reflected in decompiler results or assembly markup. </P>
<H2><A name="Structure_Editor_Flex_Array"></A>Flexible Array Component</H2>
<H2><A name="Structure_Editor_Flex_Array"></A>Zero-Element / Flexible Array Components</H2>
<P>A structure may be defined with a trailing flexible array component which corresponds to
an unsized array (e.g., char[0]). Such a component, if it exists, is always displayed as the
last row within the structure editor with the open edit row for additional components located
directly above it. The <I>DataType</I> column for a flexible array always shows
the base type of the unsized array which can be modified similar to other components. A
flexible array is added to the end of a structure by adding a last row specified by the base
<I>DataType</I> (e.g. char)
then invoking the array action and specifying an element count of 0. Attempting to specify
an element count of 0 is only permitted on the last component row when a flexible array component
does not already exist. The presence of a flexible array component does not affect the size of a
structure and will not appear within the structure when applied to Data within memory as it
corresponds to the memory location which immediately follows the end of the structure.</P>
<P>A structure may be defined with zero-element array components, also referred to as a
flexible array, which correspond to an unsized array (e.g., char[0]). Such a component
is created by simply specifying a zero-element array datatype as you would a sized-array component
(see <A href="#Structure_Editor_Create_FlexArray">Create
Zero-Element / Flexible Array Component</A>).
The resulting component will not consume any space within the structure and will report a component
size of 0. As such, it may reside at the same offset as a subsequent component and/or may have an offset
equal to the length of the structure. When packing is enabled such a component may influence the
overall alignment of the structure and its length.
<P><IMG alt="Note:" src="../../shared/note.png">The use of flexible array components is not
currently reflected in decompiler results or listing reference markup. Its primary purpose
if to reflect the C/C++ source definition of a structure with correct alignment and structure sizing.</P>
<P><IMG alt="Note:" src="../../shared/note.png">While C/C++ support flexible arrays anywhere
within a structure, Ghidra only supports the case where it is the last structure component.</P>
<DIV style="text-align: center;">
<IMG alt="" src="images/StructureEditorWithFlexArray.png"><BR>
<BR>
@@ -415,7 +409,7 @@
<BLOCKQUOTE>
<P>Within a non-packed structure <i>undefined</i> components are inserted before the current selection by clicking the <IMG src=
"images/Plus.png" alt=""> <B>Insert Undefined Byte</B> button. Within a packed structure an <i>undefined1<i> datatype component
"images/Plus.png" alt=""> <B>Insert Undefined Byte</B> button. Within a packed structure an <i>undefined1</i> datatype component
is inserted in a similar fashion, although in packed structures it is more appropriate to use a properly sized datatype (e.g., modify datatype
on inserted component).</P>
</BLOCKQUOTE>
@@ -587,24 +581,14 @@
</BLOCKQUOTE>
<H3><A name="Structure_Editor_Create_FlexArray"></A> <IMG src="images/Array.png" alt="">Create
Flexible Array</H3>
Zero-Element / Flexible Array Component</H3>
<BLOCKQUOTE>
<P>To create an unsized flexible array as the last structure component (assuming one
is not already defined):</P>
<OL>
<LI>Add a component whose <I>DataType</I> corresponds to the base type of the unsized array.</LI>
<LI>Select this last structure component in the table.</LI>
<LI>Press the <IMG src="images/Array.png" alt=""> <B>Create Array</B> button or the '['
action key binding.</LI>
<LI>A dialog pops up to request
the number of elements in the array. Specify 0 as the number of elements in the popup
dialog and click OK.</LI>
</OL>
<P>To create an unsized flexible array component you must use the datatype cell edit feature
to select/enter the datatype by name including the array-sizing-specification (e.g., char[0]).
To initiate edit mode for a component datatype you must double-click the datatype cell for the component
you wish to modify. This may be an existing component or the empty row at the end of the table.
See <A href="#Structure_Editor_Editing_DataType">Editing the DataType Field</A> for more details.
</BLOCKQUOTE>
<H3><A name="Structure_Editor_Unpackage_Component"></A> <IMG src="images/Unpackage.gif" alt="">
@@ -617,8 +601,7 @@
button. For example, the array component Word[4] would become four Word components. If the
structure struct_1 was composed of a Float and a DWord, then unpackaging it would replace the
struct_1 component with a Float component and a DWord component.</P>
</BLOCKQUOTE><BR>
</BLOCKQUOTE>
<H3><A name="Structure_Editor_Create_Structure_From_Selection"></A> <IMG src=
"images/cstruct.png" alt=""> Create Structure From Selection</H3>
@@ -778,49 +761,81 @@
session top to bottom in the table.</P>
</BLOCKQUOTE>
<H3>Editing the <I>DataType</I> Field</H3>
<H3><A name="Structure_Editor_Editing_DataType"></A>Editing the <I>DataType</I> Field</H3>
<P>This can be any data type that is available in the data type manager. To edit the data
type double-click the data type cell. This will show the <A href=
<P>To edit the data type double-click the data type cell. This will show the <A href=
"help/topics/DataTypeEditors/DataTypeSelectionDialog.htm">Data Type Selection Dialog</A>,
which allows you to easily enter a data type. It can also be Undefined, a pointer to a data
type, or an array.</P>
which allows you to easily enter a data type or select/modify an existing one from one of the open
datatype managers. It can also be Undefined, a pointer to a datatype, or an array.</P>
<P><IMG alt="Note:" src="../../shared/note.png"> Certain restrictions may apply when specifying
or modifying a component's datatype which could cause a modification to fail. Some common restrictions include
but are not limited to:</P>
<BLOCKQUOTE>
<ul>
<li>Fit (non-packed structure only) - when modifying a component
there must be adequate space to place the component. Any undefined components which immediately follow
the modified component may be consumed or added based upon the component size change. It may be neccessary to
insert undefined bytes or clear other components before the modification may be completed.</li>
<li>Illegal Datatype - certain datatypes are not permitted (e.g., data driven Dynamic types, Factory types).</li>
<li>Zero-Length Components (non-packed structure only) - modification of an existing zero-length component may
not change its size.</li>
</ul>
</BLOCKQUOTE>
<P>Examples of datatypes which may be specified, include:</P>
<BLOCKQUOTE>
<P><B>Basic Data Type</B></P>
<P><A name="Structure_Editor_Basic_Data_Type"></A><B>Basic Data Type</B></P>
<P>This can be a built-in data type (Byte, Word, etc.), a structure, a union, or a
typedef.</P>
<P>For example, Word.</P>
<P>This can be any fixed-length built-in data type (e.g., byte, word, etc.), structure, union, typedef, or enum.
<P><B>Sizable Dynamic Data Type</B></P>
<P>A sizable built-in Dynamic data type such as <i>string</i> may be specified in which case the user
will be prompted to specify the component size.</P>
<P><B>Pointer Data Type</B></P>
<P>This can be the basic Pointer data type or a pointer to a data type. A pointer to a data
type is indicated by following the data type with an *.</P>
<P>This can be a named Pointer data type (e.g., <i>pointer</i>, <i>pointer16</i>, etc.) or a pointer to a specific data type. A pointer to a data
type is indicated by following the data type name with an * (i.e., asterisk symbol). It is also possible to stipulate a specific pointer-size, although it should be
only done when the default pointer size is inappropriate. A stipulated pointer size may be specified by following the * with its bit-size
(16,24,32..64). The pointer * designation may also be stacked for a pointer-to-pointer type.</P>
<P>For example, Word * is a pointer to a Word.</P>
<P>For example, <i>word*</i> is a pointer to a Word using the default pointer size. If a non-default size is needed <i>word*16</i> would force
the use of a 16-bit pointer.</P>
<P><B>Array</B></P>
<P>This can be a multidimensional array of any data type.</P>
<P>A single or multidimensional array of any <A href="#Structure_Editor_Basic_Data_Type">basic data type</A> may be specified.</P>
<P>For example, DWord[2][4] is an array with 2 elements, where each element is an array
with 4 elements that are DWords.</P>
<P>For example, <i>dword[2][4]</i> is an array with 2 elements, where each element is an array
with 4 elements that are DWords; In a similar fashion a zero-element character array may be specified
as <i>char[0]</i>.</P>
<P><B>Array of Pointers</B></P>
<P>Arrays of pointers can also be specified.</P>
<P>Arrays of pointers may also be specified.</P>
<P>For example, Float*[5] is an array with five elements where each element is a pointer to
<P>For example, <i>float*[5]</i> is an array with five elements where each element is a pointer to
a Float.</P>
<P><B>Bitfields</B></P>
<P>A bitfield may be specified by appending <b>:&lt;bitsize&gt;</b> to the end of a valid base datatype. Valid base datatypes include
all integer types (e.g., byte, char, int, etc.), a defined enum, or a typedef which corresponds to an integer-type or enum.
It is important to note that specifying a bitfield in this manner works well for packed structures, however for non-packed
structures it may be neccessary to use the <A href="#Structure_Editor_Bitfield_Actions">Bitfield Actions</A> to properly define a bitfield.</P>
<P>For example, <i>int:4</i> defines a signed integer bitfield which is 4-bits in length.
<H4><A name="EffectOfChangingDataTypeSize"></A> <U>Effect of Changing a Component's
Size</U></H4>
<P>A non-packed union's size will always be the size of its largest component. If you
change a data type for a component and the component size changes, the union size will
change if necessary. A packed union is padded to make its size a multiple of the union's
change if necessary. A packed union is padded to make its size a multiple of the union's
alignment.<BR>
</P>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 52 KiB

@@ -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.
@@ -22,9 +21,10 @@ import ghidra.program.model.address.*;
import ghidra.program.model.data.*;
import ghidra.program.model.listing.*;
import ghidra.program.model.util.CodeUnitInsertionException;
import ghidra.util.Msg;
/**
* Command to create an array.
* Command to create an array. All conflicting data will be cleared.
*
*/
public class CreateArrayCmd implements Command {
@@ -37,9 +37,11 @@ public class CreateArrayCmd implements Command {
/**
* Constructs a new command for creating arrays.
* @param addr The address at which to create an array.
* @param numElements the number of elements in the array to be created.
* @param numElements the number of elements in the array to be created.
* A 0 element count is permitted but a minimum length will apply for all array instances.
* @param dt the dataType of the elements in the array to be created.
* @param elementLength the size of an element in the array.
* @param elementLength the size of an element in the array. Only used for Dynamic
* datatype <code>dt</code> when {@link Dynamic#canSpecifyLength()} returns true.
*/
public CreateArrayCmd(Address addr, int numElements, DataType dt, int elementLength) {
this.addr = addr;
@@ -47,69 +49,47 @@ public class CreateArrayCmd implements Command {
this.dataType = dt;
this.elementLength = elementLength;
}
/**
*
* @see ghidra.framework.cmd.Command#applyTo(ghidra.framework.model.DomainObject)
*/
@Override
public boolean applyTo(DomainObject obj) {
Program program = (Program)obj;
Listing listing = program.getListing();
if (dataType instanceof FactoryDataType) {
msg = "Array not allowed on a Factory data-type: " + dataType.getName();
return false;
}
if (dataType instanceof Dynamic && !((Dynamic)dataType).canSpecifyLength()) {
msg = "Array not allowed on a non-sizable Dynamic data-type: " + dataType.getName();
return false;
}
if (elementLength <=0) {
msg = "DataType must have fixed size > 0, not "+dataType.getLength();
return false;
}
if (numElements <= 0) {
msg = "Number of elements must be positive, not "+numElements;
return false;
}
int length = numElements*elementLength;
Address endAddr;
try {
endAddr = addr.addNoWrap(length - 1);
ArrayDataType adt = new ArrayDataType(dataType, numElements, elementLength,
program.getDataTypeManager());
int length = adt.getLength();
Address endAddr = addr.addNoWrap(length - 1);
AddressSet set = new AddressSet(addr, endAddr);
InstructionIterator iter = listing.getInstructions(set, true);
if (iter.hasNext()) {
msg = "Can't create data because the current selection contains instructions";
return false;
}
listing.clearCodeUnits(addr, endAddr, false);
listing.createData(addr, adt, adt.getLength());
} catch (AddressOverflowException e1) {
msg = "Can't create data because length exceeds address space";
return false;
}
AddressSet set = new AddressSet(addr, endAddr);
InstructionIterator iter = listing.getInstructions(set, true);
if (iter.hasNext()) {
msg = "Can't create data because the current selection contains instructions";
return false;
}
listing.clearCodeUnits(addr, endAddr, false);
ArrayDataType adt = new ArrayDataType(dataType, numElements, elementLength);
try {
listing.createData(addr, adt, adt.getLength());
} catch(CodeUnitInsertionException e) {
catch (IllegalArgumentException | CodeUnitInsertionException e) {
msg = e.getMessage();
return false;
}
catch (RuntimeException e) {
msg = "Unexpected error: " + e.toString();
Msg.error(this, msg, e);
return false;
}
return true;
}
/**
* @see ghidra.framework.cmd.Command#getStatusMsg()
*/
@Override
public String getStatusMsg() {
return msg;
}
/**
* @see ghidra.framework.cmd.Command#getName()
*/
@Override
public String getName() {
return "Create Array";
}
@@ -20,9 +20,11 @@ import ghidra.framework.model.DomainObject;
import ghidra.program.model.address.Address;
import ghidra.program.model.data.*;
import ghidra.program.model.listing.*;
import ghidra.util.Msg;
/**
* Command to create an array inside of a structure.
* Command to create an array inside of a structure. All conflicting components
* within the targeted structure will be replaced with the new array component.
*
*/
public class CreateArrayInStructureCmd implements Command {
@@ -32,14 +34,21 @@ public class CreateArrayInStructureCmd implements Command {
private DataType dataType;
private int[] compPath;
// NOTE: This command does not currently handle Dynamic types whose length may
// be specified since no elementLength parameter exists.
/**
* Constructs a new command for creating arrays inside of structures.
* The specified component will be replaced as will subsequent components within
* the structure required to make room for the new array component.
* NOTE: This is intended for replacing existing components and not for
* simply inserting an array component.
* @param addr The address of the structure that will contain the new array.
* @param numElements the number of elements in the array to be created.
* @param numElements the number of elements in the array to be created. A 0 element count is permitted.
* @param dt the dataType of the elements in the array to be created.
* @param compPath the component path within the structure at which to create
* the array. The component path is an array of integers where each integer
* is a component index of the component above it.
* @param compPath the target component path within the structure of an existing component where
* the array should be created. The component path is an array of integers where each integer
* is a component index of the component above it.
*/
public CreateArrayInStructureCmd(Address addr, int numElements, DataType dt,
int[] compPath) {
@@ -48,42 +57,18 @@ public class CreateArrayInStructureCmd implements Command {
this.dataType = dt;
this.compPath = compPath;
}
/**
*
* @see ghidra.framework.cmd.Command#applyTo(ghidra.framework.model.DomainObject)
*/
@Override
public boolean applyTo(DomainObject obj) {
Program program = (Program)obj;
Listing listing = program.getListing();
if (dataType instanceof FactoryDataType) {
msg = "Array not allowed on a Factory data-type: " + dataType.getName();
return false;
}
if (dataType instanceof Dynamic && !((Dynamic)dataType).canSpecifyLength()) {
msg = "Array not allowed on a non-sizable Dynamic data-type: " + dataType.getName();
return false;
}
if (numElements <= 0) {
msg = "Number of elements must be positive, not "+numElements;
return false;
}
Data data = listing.getDataContaining(addr);
Data compData = data.getComponent(compPath);
int elementLength;
if (dataType instanceof Dynamic) {
elementLength = compData.getLength();
}
else {
elementLength = dataType.getLength();
}
if (elementLength <=0) {
msg = "DataType must have fixed size > 0, not "+elementLength;
if (compData == null) {
msg = "Invalid target component path specified";
return false;
}
int length = numElements*elementLength;
int index = compData.getComponentIndex();
int offset = compData.getParentOffset();
@@ -94,23 +79,34 @@ public class CreateArrayInStructureCmd implements Command {
return false;
}
Structure struct = (Structure)parentDataType;
if (offset+length > struct.getLength()) {
msg = "Array too big for structure";
return false;
}
DataType baseDt = dataType;
if (dataType instanceof TypeDef) {
baseDt = ((TypeDef) dataType).getBaseDataType();
}
if (baseDt instanceof Dynamic) {
msg = "Dynamic data-type may not be specified: " + dataType.getName();
return false;
}
try {
ArrayDataType adt = new ArrayDataType(dataType, numElements, dataType.getLength());
int length = adt.isZeroLength() ? 0 : adt.getLength();
if (!struct.isPackingEnabled() && (offset + length) > struct.getLength()) {
msg = "Array too big for structure";
return false;
}
clearStruct(struct, compData.getParentOffset(), length);
if (struct.isPackingEnabled()) {
struct.insert(index, adt, adt.getLength());
struct.insert(index, adt, -1);
}
else {
struct.replace(index, adt, adt.getLength());
struct.replace(index, adt, -1);
}
}
catch(Exception e) {
msg = e.getMessage();
catch (RuntimeException e) {
msg = "Unexpected error: " + e.toString();
Msg.error(this, msg, e);
return false;
}
return true;
@@ -129,6 +125,7 @@ public class CreateArrayInStructureCmd implements Command {
/**
* @see ghidra.framework.cmd.Command#getStatusMsg()
*/
@Override
public String getStatusMsg() {
return msg;
}
@@ -136,6 +133,7 @@ public class CreateArrayInStructureCmd implements Command {
/**
* @see ghidra.framework.cmd.Command#getName()
*/
@Override
public String getName() {
return "Create Array";
}
@@ -1094,62 +1094,6 @@ public class DataTypeMergeManager implements MergeResolver {
}
}
private void updateFlexArray(long sourceDtID, Structure sourceDt, Structure destStruct,
Map<Long, DataType> resolvedDataTypes) {
DataTypeComponent flexDtc = sourceDt.getFlexibleArrayComponent();
if (flexDtc == null) {
return;
}
DataTypeManager sourceDTM = sourceDt.getDataTypeManager();
DataType sourceCompDt = flexDtc.getDataType();
String comment = flexDtc.getComment();
long sourceComponentID = sourceDTM.getID(sourceCompDt);
// Try to get a mapping of the source data type to a result data type.
DataType resultCompDt = getResolvedComponent(sourceComponentID, resolvedDataTypes);
if (resultCompDt == null) {
// We didn't have a map entry for the data type.
if (!myDtAddedList.contains(Long.valueOf(sourceComponentID))) {
// Not added so should be in result if it wasn't deleted there.
DataType rDt = dtms[RESULT].getDataType(sourceComponentID);
if (rDt != null) {
resultCompDt = rDt;
}
}
if (resultCompDt == null) {
// Not added/resolved yet
// put an entry in the fixup list
fixUpList.add(new FixUpInfo(sourceDtID, sourceComponentID, Integer.MAX_VALUE,
resolvedDataTypes));
fixUpIDSet.add(sourceDtID);
// substitute datatype to preserve component name for subsequent fixup
resultCompDt = Undefined1DataType.dataType;
}
}
try {
// Apply resultCompDt as flex array
try {
destStruct.setFlexibleArrayComponent(resultCompDt, flexDtc.getFieldName(), comment);
}
catch (IllegalArgumentException e) {
displayError(destStruct, e);
DataType badDt = Undefined1DataType.dataType;
comment = "Couldn't add " + resultCompDt.getDisplayName() + " here. " +
e.getMessage() + " " + ((comment != null) ? (" " + comment) : "");
destStruct.setFlexibleArrayComponent(badDt, flexDtc.getFieldName(), comment);
}
}
catch (IllegalArgumentException e) {
displayError(destStruct, e);
}
}
private void updateStructure(long sourceDtID, Structure sourceDt, Structure destStruct,
Map<Long, DataType> resolvedDataTypes) {
@@ -1332,8 +1276,6 @@ public class DataTypeMergeManager implements MergeResolver {
if (!aligned) {
adjustStructureSize(destStruct, sourceDt.getLength());
}
updateFlexArray(sourceDtID, sourceDt, destStruct, resolvedDataTypes);
}
/**
@@ -1343,7 +1285,7 @@ public class DataTypeMergeManager implements MergeResolver {
*/
private static void adjustStructureSize(Structure struct, int preferredSize) {
DataTypeComponent dtc = struct.getComponentAt(preferredSize);
DataTypeComponent dtc = struct.getComponentContaining(preferredSize);
if (dtc == null) {
struct.growStructure(preferredSize - struct.getLength());
return;
@@ -1895,16 +1837,6 @@ public class DataTypeMergeManager implements MergeResolver {
}
checkOffsets = true;
}
DataTypeComponent flexDtc1 = ((Structure) c1).getFlexibleArrayComponent();
DataTypeComponent flexDtc2 = ((Structure) c2).getFlexibleArrayComponent();
if (flexDtc1 != null && flexDtc2 != null) {
if (isChangedComponent(flexDtc1, flexDtc2, dtm1, dtm2, false)) {
return true;
}
}
else if (flexDtc1 != null || flexDtc2 != null) {
return true;
}
}
DataTypeComponent[] c1Components = c1.getDefinedComponents();
@@ -2384,7 +2316,7 @@ public class DataTypeMergeManager implements MergeResolver {
}
/**
* Process fixup for aligned structure component or trailing flexible array
* Process fixup for aligned structure component
* @param info fixup info
* @param struct result structure
* @param dt component datatype
@@ -2392,35 +2324,15 @@ public class DataTypeMergeManager implements MergeResolver {
*/
private boolean fixUpAlignedStructureComponent(FixUpInfo info, Structure struct, DataType dt) {
int ordinal = info.index;
boolean isFlexArrayFixup = (info.index == Integer.MAX_VALUE);
DataTypeComponent dtc = null;
if (isFlexArrayFixup) {
dtc = struct.getFlexibleArrayComponent();
}
else {
if (ordinal >= 0 || ordinal < struct.getNumComponents()) {
dtc = struct.getComponent(ordinal);
}
if (ordinal >= 0 || ordinal < struct.getNumComponents()) {
dtc = struct.getComponent(ordinal);
}
if (dtc == null) {
return false;
}
if (isFlexArrayFixup) {
try {
struct.setFlexibleArrayComponent(dt, dtc.getFieldName(), dtc.getComment());
}
catch (IllegalArgumentException e) {
displayError(struct, e);
DataType badDt = Undefined1DataType.dataType;
String comment = dtc.getComment();
comment = "Couldn't add " + dt.getDisplayName() + "[ ] here. " + e.getMessage() +
" " + ((comment != null) ? (" " + comment) : "");
struct.replace(ordinal, badDt, dtc.getLength(), dtc.getFieldName(), comment);
struct.setFlexibleArrayComponent(badDt, dtc.getFieldName(), comment);
}
}
else if (dtc.isBitFieldComponent()) {
if (dtc.isBitFieldComponent()) {
if (BitFieldDataType.isValidBaseDataType(dt)) {
// replace bitfield base datatype - silent if updated type is not a valid base type
BitFieldDataType bfDt = (BitFieldDataType) dtc.getDataType();
@@ -2542,13 +2454,10 @@ public class DataTypeMergeManager implements MergeResolver {
DataType compDt = resolve(info.compID, info.getDataTypeManager(), info.ht);
boolean isFlexArrayFixup = (info.index == Integer.MAX_VALUE);
if (compDt != null) {
if (struct.isPackingEnabled() || isFlexArrayFixup) {
if (struct.isPackingEnabled()) {
if (!fixUpAlignedStructureComponent(info, struct, compDt)) {
String msg =
isFlexArrayFixup ? "flex-array component" : ("component " + info.index);
String msg = "component " + info.index;
Msg.warn(this, "Structure Merge: Couldn't get " + msg + " in " +
struct.getPathName() + " data type during fix up.");
return false; // Don't remove this FixUpInfo from the fixupList so the user will get notified.
@@ -2565,9 +2474,6 @@ public class DataTypeMergeManager implements MergeResolver {
}
// Datatype failed to resolved - check to see if we have a placeholder
else if (isFlexArrayFixup) {
struct.clearFlexibleArrayComponent();
}
else if (struct.isPackingEnabled()) {
int ordinal = info.index;
int numComponents = struct.getNumComponents();
@@ -3291,7 +3197,7 @@ public class DataTypeMergeManager implements MergeResolver {
if (composite.isPackingEnabled() || (composite instanceof Union)) {
return dtc.getOrdinal();
}
return dtc.getOffset();
return dtc.getOffset(); // TODO: use of offset could be problematic with shared offset
}
/**
@@ -3301,7 +3207,7 @@ public class DataTypeMergeManager implements MergeResolver {
private class FixUpInfo {
long id;
long compID;
int index;
int index; // TODO: index as offset could be problematic with shared offset
Map<Long, DataType> ht;
// bitfield info
@@ -3315,7 +3221,6 @@ public class DataTypeMergeManager implements MergeResolver {
* @param compID id of either component or base type
* @param index offset into non-packed structure, or ordinal into union or packed
* structure; or parameter/return ordinal; for other data types index is not used (specify -1).
* For structure trailing flex-array specify {@link Integer#MAX_VALUE}.
* @param resolvedDataTypes hashtable used for resolving the data type
*/
FixUpInfo(long id, long compID, int index,
@@ -87,44 +87,44 @@ class DataTypePanel extends JPanel {
pathAttrSet = new SimpleAttributeSet();
pathAttrSet.addAttribute(StyleConstants.FontFamily, "Tahoma");
pathAttrSet.addAttribute(StyleConstants.FontSize, new Integer(11));
pathAttrSet.addAttribute(StyleConstants.FontSize, Integer.valueOf(11));
pathAttrSet.addAttribute(StyleConstants.Bold, Boolean.TRUE);
pathAttrSet.addAttribute(StyleConstants.Foreground, MergeConstants.CONFLICT_COLOR);
nameAttrSet = new SimpleAttributeSet();
nameAttrSet.addAttribute(StyleConstants.FontFamily, "Tahoma");
nameAttrSet.addAttribute(StyleConstants.FontSize, new Integer(11));
nameAttrSet.addAttribute(StyleConstants.FontSize, Integer.valueOf(11));
nameAttrSet.addAttribute(StyleConstants.Bold, Boolean.TRUE);
sourceAttrSet = new SimpleAttributeSet();
sourceAttrSet.addAttribute(StyleConstants.FontFamily, "Tahoma");
sourceAttrSet.addAttribute(StyleConstants.FontSize, new Integer(11));
sourceAttrSet.addAttribute(StyleConstants.FontSize, Integer.valueOf(11));
sourceAttrSet.addAttribute(StyleConstants.Bold, Boolean.TRUE);
sourceAttrSet.addAttribute(StyleConstants.Foreground, SOURCE_COLOR);
offsetAttrSet = new SimpleAttributeSet();
offsetAttrSet.addAttribute(StyleConstants.FontFamily, "Monospaced");
offsetAttrSet.addAttribute(StyleConstants.FontSize, new Integer(12));
offsetAttrSet.addAttribute(StyleConstants.FontSize, Integer.valueOf(12));
offsetAttrSet.addAttribute(StyleConstants.Foreground, Color.BLACK);
contentAttrSet = new SimpleAttributeSet();
contentAttrSet.addAttribute(StyleConstants.FontFamily, "Monospaced");
contentAttrSet.addAttribute(StyleConstants.FontSize, new Integer(12));
contentAttrSet.addAttribute(StyleConstants.FontSize, Integer.valueOf(12));
contentAttrSet.addAttribute(StyleConstants.Foreground, Color.BLUE);
fieldNameAttrSet = new SimpleAttributeSet();
fieldNameAttrSet.addAttribute(StyleConstants.FontFamily, "Monospaced");
fieldNameAttrSet.addAttribute(StyleConstants.FontSize, new Integer(12));
fieldNameAttrSet.addAttribute(StyleConstants.FontSize, Integer.valueOf(12));
fieldNameAttrSet.addAttribute(StyleConstants.Foreground, new Color(204, 0, 204));
commentAttrSet = new SimpleAttributeSet();
commentAttrSet.addAttribute(StyleConstants.FontFamily, "Monospaced");
commentAttrSet.addAttribute(StyleConstants.FontSize, new Integer(12));
commentAttrSet.addAttribute(StyleConstants.FontSize, Integer.valueOf(12));
commentAttrSet.addAttribute(StyleConstants.Foreground, new Color(0, 204, 51));
deletedAttrSet = new SimpleAttributeSet();
deletedAttrSet.addAttribute(StyleConstants.FontFamily, "Tahoma");
deletedAttrSet.addAttribute(StyleConstants.FontSize, new Integer(12));
deletedAttrSet.addAttribute(StyleConstants.FontSize, Integer.valueOf(12));
deletedAttrSet.addAttribute(StyleConstants.Bold, Boolean.TRUE);
deletedAttrSet.addAttribute(StyleConstants.Foreground, Color.RED);
@@ -149,7 +149,7 @@ class DataTypePanel extends JPanel {
}
private void formatAlignment(Composite composite) {
String str = CompositeDataTypeImpl.getAlignmentAndPackingString(composite);
String str = CompositeInternal.getAlignmentAndPackingString(composite);
insertString(str + "\n\n", sourceAttrSet);
}
@@ -178,10 +178,7 @@ class DataTypePanel extends JPanel {
DataType dt = dtc.getDataType();
StringBuilder buffer = new StringBuilder();
buffer.append(dt.getName());
if (dtc.isFlexibleArrayComponent()) {
buffer.append("[0]");
}
else if (dt instanceof BitFieldDataType &&
if (dt instanceof BitFieldDataType &&
!((Composite) dtc.getParent()).isPackingEnabled()) {
BitFieldDataType bfDt = (BitFieldDataType) dt;
buffer.append("(");
@@ -204,14 +201,9 @@ class DataTypePanel extends JPanel {
offsetWidth += 2; // factor in 0x prefix
String offsetStr = "";
if (offsetWidth > 0) {
if (!dtc.isFlexibleArrayComponent()) {
offsetStr = "0x" + Integer.toHexString(dtc.getOffset());
offsetStr = StringUtilities.pad(offsetStr, ' ', offsetWidth - offsetStr.length());
offsetStr += ": ";
}
else {
offsetStr = StringUtilities.pad(offsetStr, ' ', offsetWidth + 2);
}
offsetStr = "0x" + Integer.toHexString(dtc.getOffset());
offsetStr = StringUtilities.pad(offsetStr, ' ', offsetWidth - offsetStr.length());
offsetStr += ": ";
insertString(" " + offsetStr + " ", offsetAttrSet);
}
fieldName = pad(fieldName, fieldNameWidth);
@@ -233,10 +225,8 @@ class DataTypePanel extends JPanel {
boolean showComponentOffset = false;
DataTypeComponent[] components = comp.getDefinedComponents();
DataTypeComponent flexDtc = null;
if (comp instanceof Structure) {
showComponentOffset = !comp.isPackingEnabled();
flexDtc = ((Structure) comp).getFlexibleArrayComponent();
}
int offsetLength = showComponentOffset ? Integer.toHexString(comp.getLength()).length() : 0;
@@ -246,17 +236,10 @@ class DataTypePanel extends JPanel {
maxDtNameLength = max(getDataTypeName(component), maxDtNameLength);
maxFieldNameLength = max(component.getFieldName(), maxFieldNameLength);
}
if (flexDtc != null) {
maxDtNameLength = max(getDataTypeName(flexDtc), maxDtNameLength);
maxFieldNameLength = max(flexDtc.getFieldName(), maxFieldNameLength);
}
for (DataTypeComponent component : components) {
renderComponent(component, maxDtNameLength, maxFieldNameLength, offsetLength);
}
if (flexDtc != null) {
renderComponent(flexDtc, maxDtNameLength, maxFieldNameLength, offsetLength);
}
insertString("}\n\n", contentAttrSet);
insertAlignment(comp);
@@ -47,7 +47,7 @@ public class AddBitFieldAction extends CompositeEditorTableAction {
public void actionPerformed(ActionContext context) {
CompEditorModel editorModel = (CompEditorModel) model;
if (editorModel.getNumSelectedRows() != 1 || editorModel.isFlexibleArraySelection()) {
if (editorModel.getNumSelectedRows() != 1) {
return;
}
int rowIndex = model.getSelectedRows()[0];
@@ -71,7 +71,7 @@ public class AddBitFieldAction extends CompositeEditorTableAction {
CompEditorModel editorModel = (CompEditorModel) model;
// Union do not support non-packed placement of bitfields
if (!(editorModel.viewComposite instanceof Structure) || editorModel.isPackingEnabled() ||
editorModel.getNumSelectedRows() != 1 || editorModel.isFlexibleArraySelection()) {
editorModel.getNumSelectedRows() != 1) {
enabled = false;
}
setEnabled(enabled);
@@ -370,7 +370,7 @@ public class BitFieldPlacementComponent extends JPanel implements Scrollable {
void init(DataTypeComponent editDtc) {
if (editDtc == null || editDtc.isFlexibleArrayComponent()) {
if (editDtc == null) {
editMode = EditMode.NONE;
editOrdinal = -1;
this.editComponent = null;
@@ -401,6 +401,12 @@ public class BitFieldPlacementComponent extends JPanel implements Scrollable {
return false;
}
return bitFieldAllocation.hasConflict;
// TODO: Improve conflict detection with zero-length components.
// Zero-length components can share common offset, although
// zero-length components should have a lower ordinal than a
// sized component at the same offset.
}
/**
@@ -603,7 +609,7 @@ public class BitFieldPlacementComponent extends JPanel implements Scrollable {
String conflictTip = "'" + conflict.getDataType().getDisplayName() +
(conflictName != null ? (" " + conflictName) : "") + "' at offset " +
conflict.getOffset();
conflictMsg += "<div style=\"color: red;font-style: italic\">conflict with " +
conflictMsg += "<div style=\"color: red;font-style: italic\">overlaps " +
HTMLUtilities.escapeHTML(conflictTip) + "</div>";
}
return "<HTML><div style=\"text-align:center\">" + HTMLUtilities.escapeHTML(tip) +
@@ -842,12 +848,22 @@ public class BitFieldPlacementComponent extends JPanel implements Scrollable {
BitFieldPlacement(DataTypeComponent component) {
int startOffset = component.getOffset();
int componentLength = component.getLength();
int offsetAdjBytes = startOffset - allocationByteOffset;
if (!bigEndian) {
offsetAdjBytes = allocationByteSize - offsetAdjBytes - component.getLength();
offsetAdjBytes = allocationByteSize - offsetAdjBytes - componentLength;
}
int leftAdj = 8 * offsetAdjBytes;
if (component.isBitFieldComponent()) {
if (componentLength == 0) {
// treat all zero-length fields the same
zeroBitField = true;
rightBit = leftAdj - 8;
if (!isBigEndian()) {
rightBit += 7;
}
leftBit = rightBit;
}
else if (component.isBitFieldComponent()) {
BitFieldDataType bitfield = (BitFieldDataType) component.getDataType();
int storageSize = 8 * bitfield.getStorageSize();
rightBit = leftAdj + storageSize - bitfield.getBitOffset() - 1;
@@ -855,13 +871,7 @@ public class BitFieldPlacementComponent extends JPanel implements Scrollable {
// bits stored (NOTE: this may cause a transition from declared to effective
// bit-size when editing a bitfield where the these bit-sizes differ).
int bitSize = bitfield.getBitSize();
if (bitSize == 0) {
zeroBitField = true;
leftBit = rightBit;
}
else {
leftBit = rightBit - bitSize + 1;
}
leftBit = rightBit - bitSize + 1;
}
else {
int componentSize = 8 * component.getLength();
@@ -1075,7 +1085,7 @@ public class BitFieldPlacementComponent extends JPanel implements Scrollable {
int allocationEndOffset = offset + allocationBytes - 1;
int numComponents = struct.getNumComponents();
DataTypeComponent component = struct.getComponentAt(offset);
DataTypeComponent component = struct.getDefinedComponentAtOrAfterOffset(offset);
while (component != null) {
if (component.getOffset() > allocationEndOffset) {
break;
@@ -1149,7 +1159,7 @@ public class BitFieldPlacementComponent extends JPanel implements Scrollable {
// determine placement attribute index within allocationBytes which
// may have been reduced from allocationByteSize based upon visibility.
int index = bitIndex - (8 * rightChopBytes);
int index = bitIndex - (8 * leftChopBytes);
if (index >= 0 && index < bitAttributes.length) {
bitAttributes[index] = new BitAttributes(dtc, bitAttributes[index]);
}
@@ -1245,11 +1255,11 @@ public class BitFieldPlacementComponent extends JPanel implements Scrollable {
private DataTypeComponent getConflict() {
BitAttributes c = conflict;
while (c != null && c.dtc.isZeroBitFieldComponent()) {
while (c != null && c.dtc.getLength() == 0 && c.conflict != null) {
// TODO: improve conflict detection
// Zero-length bitfield could be conflict if placement is
// Zero-length components could be conflict if placement is
// offcut with another component (currently ignored)
c = conflict.conflict;
c = c.conflict;
}
// NOTE: DEFAULT undefined datatype can be ignored as conflict
return c != null && c.dtc.getDataType() != DataType.DEFAULT ? c.dtc : null;
@@ -1301,7 +1311,7 @@ public class BitFieldPlacementComponent extends JPanel implements Scrollable {
}
else {
g.fillRect(rectangle.x, rectangle.y, bitWidth, CELL_HEIGHT);
if (conflict != null && conflict.dtc.isZeroBitFieldComponent()) {
if (conflict != null && conflict.dtc.getLength() == 0) {
conflict.paint(g, null, false);
}
}
@@ -536,7 +536,7 @@ public abstract class CompEditorModel extends CompositeEditorModel {
if (isEditingField()) {
endFieldEditing();
}
checkIsAllowableDataType(datatype, true);
checkIsAllowableDataType(datatype);
if (length < 1) {
DataTypeInstance dti = DataTypeHelper.getSizedDataType(getProvider(), datatype,
lastNumBytes, Integer.MAX_VALUE);
@@ -575,7 +575,7 @@ public abstract class CompEditorModel extends CompositeEditorModel {
endFieldEditing();
}
checkIsAllowableDataType(dataType, true);
checkIsAllowableDataType(dataType);
insertMultiple(rowIndex, dataType, dtLen, multiple, monitor);
fixSelection();
componentEdited();
@@ -741,29 +741,23 @@ public abstract class CompEditorModel extends CompositeEditorModel {
return null;
}
checkIsAllowableDataType(datatype, !oldDtc.isFlexibleArrayComponent());
checkIsAllowableDataType(datatype);
DataTypeComponent dtc;
if (oldDtc.isFlexibleArrayComponent()) {
// flexible array only supports fixed-length types
dtc = replace(rowIndex, datatype);
}
else {
int oldCompSize = oldDtc.getLength();
int newCompSize = length;
int sizeDiff = newCompSize - oldCompSize;
int oldCompSize = oldDtc.getLength();
int newCompSize = length;
int sizeDiff = newCompSize - oldCompSize;
// New one is larger so check to make sure it will fit.
if (sizeDiff > 0) {
if (!checkForReplace(rowIndex, datatype)) {
throw new InvalidDataTypeException(datatype.getDisplayName() + " doesn't fit.");
}
// New one is larger so check to make sure it will fit.
if (sizeDiff > 0) {
if (!checkForReplace(rowIndex, datatype)) {
throw new InvalidDataTypeException(datatype.getDisplayName() + " doesn't fit.");
}
// Replace the component at index.
dtc = replace(rowIndex, datatype, newCompSize, oldDtc.getFieldName(),
oldDtc.getComment());
}
// Replace the component at index.
DataTypeComponent dtc =
replace(rowIndex, datatype, newCompSize, oldDtc.getFieldName(), oldDtc.getComment());
fixSelection();
componentEdited();
selectionChanged();
@@ -793,11 +787,11 @@ public abstract class CompEditorModel extends CompositeEditorModel {
}
DataTypeComponent oldDtc = getComponent(startRowIndex);
if (oldDtc == null || oldDtc.isFlexibleArrayComponent()) {
if (oldDtc == null) {
throw new AssertException();
}
checkIsAllowableDataType(datatype, true);
checkIsAllowableDataType(datatype);
//
// Note: if the range being replaced is large enough, then the UI could lock-up. If we
@@ -839,7 +833,7 @@ public abstract class CompEditorModel extends CompositeEditorModel {
if (dtc == null) {
return false;
}
if (!isShowingUndefinedBytes() || dtc.isFlexibleArrayComponent()) {
if (!isShowingUndefinedBytes()) {
return true;
}
// Does the new data type fit by replacing the component at index.
@@ -869,10 +863,10 @@ public abstract class CompEditorModel extends CompositeEditorModel {
protected abstract void replaceOriginalComponents();
@Override
protected void checkIsAllowableDataType(DataType datatype, boolean dynamicSizingAllowed)
protected void checkIsAllowableDataType(DataType datatype)
throws InvalidDataTypeException {
super.checkIsAllowableDataType(datatype, dynamicSizingAllowed);
super.checkIsAllowableDataType(datatype);
// Verify that we aren't adding this structure or anything that it is
// part of to this editable structure.
@@ -1021,12 +1015,6 @@ public abstract class CompEditorModel extends CompositeEditorModel {
// Get data type to make into array.
DataType dt = comp.getDataType();
if (numElements == 0) {
// assume if 0 was permitted flexible array support has been provided
convertToFlexibleArray(rowIndex);
return;
}
ArrayDataType array = new ArrayDataType(dt, numElements, comp.getLength(), viewDTM);
if (getNumSelectedComponentRows() > 1) {
@@ -1244,17 +1232,17 @@ public abstract class CompEditorModel extends CompositeEditorModel {
}
@Override
public void setComponentDataTypeInstance(int rowIndex, DataTypeInstance dti)
public void setComponentDataTypeInstance(int rowIndex, DataType dt, int length)
throws UsrException {
if (getComponent(rowIndex) == null) {
// Replacing data type in unlocked mode replaces only
// that data type and structure size may change.
insert(rowIndex, dti.getDataType(), dti.getLength());
insert(rowIndex, dt, length);
}
else {
// Replacing data type in unlocked mode replaces only
// that data type and structure size may change.
replace(rowIndex, dti.getDataType(), dti.getLength());
replace(rowIndex, dt, length);
}
}
@@ -1268,14 +1256,11 @@ public abstract class CompEditorModel extends CompositeEditorModel {
@Override
public void setComponentName(int rowIndex, String name)
throws InvalidInputException, InvalidNameException, DuplicateNameException {
if (name.equals("")) {
name = null;
}
if (nameExistsElsewhere(name, rowIndex)) {
throw new InvalidNameException("Name \"" + name + "\" already exists.");
}
try {
getComponent(rowIndex).setFieldName(name);
getComponent(rowIndex).setFieldName(name); // setFieldName handles trimming
}
catch (DuplicateNameException exc) {
throw new InvalidNameException(exc.getMessage());
@@ -1552,9 +1537,6 @@ public abstract class CompEditorModel extends CompositeEditorModel {
if (!isContiguousSelection()) {
return 0;
}
if (isFlexibleArraySelection()) {
return Integer.MAX_VALUE;
}
int rowIndex = selection.getFieldRange(0).getStart().getIndex().intValue();
if (rowIndex < getNumComponents()) {
@@ -177,7 +177,13 @@ public class CompEditorPanel extends CompositeEditorPanel {
validate();
}
bitViewComponent.init(dtc);
if (dtc != null && dtc.getOffset() >= length) {
// likely trailing zero-length component - not in range for bitViewComponent
bitViewComponent.init(null);
}
else {
bitViewComponent.init(dtc);
}
}
});
@@ -821,7 +827,7 @@ public class CompEditorPanel extends CompositeEditorPanel {
sizeTextField.setEditable(editable);
if (editable) {
// editable - use same background as category field
sizeTextField.setBackground(categoryStatusTextField.getBackground());
sizeTextField.setBackground(descriptionTextField.getBackground());
}
else {
// not editable - use same background as panel
@@ -177,17 +177,14 @@ public abstract class CompositeEditorModel extends CompositeViewerModel implemen
rowIndex = range.getStart().getIndex().intValue();
}
boolean dynamicSizingAllowed = true;
DataType currentDt = null;
DataTypeComponent dtc = getComponent(rowIndex);
if (dtc != null) {
dynamicSizingAllowed = !dtc.isFlexibleArrayComponent();
currentDt = dtc.getDataType();
}
if (!(currentDt instanceof Pointer)) {
// stacking on pointer allows any data type
checkIsAllowableDataType(dt, dynamicSizingAllowed);
checkIsAllowableDataType(dt);
}
DataType resultDt = DataUtilities.reconcileAppliedDataType(currentDt, dt, true);
@@ -358,7 +355,7 @@ public abstract class CompositeEditorModel extends CompositeViewerModel implemen
dtName = previousDt.getDisplayName();
}
DataType newDt = null;
int newLength = 0;
int newLength = -1;
if (dataTypeObject instanceof DataTypeInstance) {
DataTypeInstance dti = (DataTypeInstance) dataTypeObject;
newDt = dti.getDataType();
@@ -381,10 +378,15 @@ public abstract class CompositeEditorModel extends CompositeViewerModel implemen
if (newDt == null) {
return; // Was nothing and is nothing.
}
if (DataTypeComponent.usesZeroLengthComponent(newDt)) {
newLength = 0;
}
checkIsAllowableDataType(newDt, element == null || !element.isFlexibleArrayComponent());
checkIsAllowableDataType(newDt);
newDt = resolveDataType(newDt, viewDTM, DataTypeConflictHandler.DEFAULT_HANDLER);
if (newLength < 0) {
// prefer previous size first
int suggestedLength = (previousLength <= 0) ? lastNumBytes : previousLength;
@@ -393,22 +395,22 @@ public abstract class CompositeEditorModel extends CompositeViewerModel implemen
if (sizedDataType == null) {
return;
}
newDt = resolveDataType(sizedDataType.getDataType(), viewDTM, DataTypeConflictHandler.DEFAULT_HANDLER);
newLength = sizedDataType.getLength();
if (newLength <= 0) {
throw new UsrException("Can't currently add this data type.");
}
}
if ((previousDt != null) && newDt.isEquivalent(previousDt) && newLength == previousLength) {
return;
}
int maxLength = getMaxReplaceLength(rowIndex);
if (newLength <= 0) {
throw new UsrException("Can't currently add this data type.");
}
if (maxLength > 0 && newLength > maxLength) {
throw new UsrException(newDt.getDisplayName() + " doesn't fit within " + maxLength +
" bytes, need " + newLength + " bytes");
}
setComponentDataTypeInstance(rowIndex,
DataTypeInstance.getDataTypeInstance(newDt, newLength));
setComponentDataTypeInstance(rowIndex, newDt, newLength);
notifyCompositeChanged();
}
@@ -458,10 +460,6 @@ public abstract class CompositeEditorModel extends CompositeViewerModel implemen
int max = getMaxElements();
if (isSingleRowSelection()) {
if (max != 0) {
int currentIndex = selection.getFieldRange(0).getStart().getIndex().intValue();
if (canConvertToFlexibleArray(currentIndex)) {
min = 0; // allow flexible array
}
int initial = getLastNumElements();
NumberInputDialog numberInputDialog =
new NumberInputDialog("elements", ((initial > 0) ? initial : 1), min, max);
@@ -492,20 +490,6 @@ public abstract class CompositeEditorModel extends CompositeViewerModel implemen
}
}
/**
* Determine if the existing composite component identified by its rowIndex can
* be converted to a flexible array (i.e., unsized array).
* @param rowIndex existing component index
* @return true if conversion to flexible array permitted.
*/
protected boolean canConvertToFlexibleArray(int rowIndex) {
return false;
}
protected void convertToFlexibleArray(int rowIndex) throws UsrException {
throw new UsrException("Flexible array not permitted");
}
protected void createArray(int numElements)
throws InvalidDataTypeException, DataTypeConflictException, UsrException {
if (selection.getNumRanges() != 1) {
@@ -777,6 +761,10 @@ public abstract class CompositeEditorModel extends CompositeViewerModel implemen
*/
protected boolean nameExistsElsewhere(String name, int rowIndex) {
if (name != null) {
name = name.trim();
if (name.length() == 0) {
return false;
}
int numComponents = getNumComponents();
for (int i = 0; i < rowIndex && i < numComponents; i++) {
if (name.equals(getComponent(i).getFieldName())) {
@@ -797,12 +785,18 @@ public abstract class CompositeEditorModel extends CompositeViewerModel implemen
* If invalid, an exception will be thrown.
*
* @param datatype the data type
* @param dynamicSizingAllowed true signals to allow dynamic types
* @throws InvalidDataTypeException if the structure being edited is part
* of the data type being inserted or doesn't have a valid size.
*/
protected void checkIsAllowableDataType(DataType datatype, boolean dynamicSizingAllowed)
protected void checkIsAllowableDataType(DataType datatype)
throws InvalidDataTypeException {
if (!allowsZeroLengthComponents() && DataTypeComponent.usesZeroLengthComponent(datatype)) {
throw new InvalidDataTypeException(
"Zero-length datatype not permitted: " + datatype.getName());
}
if (!allowsBitFields() && (datatype instanceof BitFieldDataType)) {
throw new InvalidDataTypeException("Bitfield not permitted: " + datatype.getName());
}
if (datatype instanceof TypeDef) {
datatype = ((TypeDef) datatype).getBaseDataType();
}
@@ -811,17 +805,21 @@ public abstract class CompositeEditorModel extends CompositeViewerModel implemen
"Factory data types are not " + "allowed in a composite data type.");
}
else if (datatype instanceof Dynamic) {
if (!dynamicSizingAllowed) {
throw new InvalidDataTypeException(
"Dynamic data type is not permitted in current context");
}
else if (!((Dynamic) datatype).canSpecifyLength()) {
if (!((Dynamic) datatype).canSpecifyLength()) {
throw new InvalidDataTypeException("Non-sizable Dynamic data types are not " +
"allowed in a composite data type.");
}
}
}
protected boolean allowsZeroLengthComponents() {
return true;
}
protected boolean allowsBitFields() {
return true;
}
@Override
public boolean isAddAllowed(int currentIndex, DataType datatype) {
return false;
@@ -1114,7 +1112,7 @@ public abstract class CompositeEditorModel extends CompositeViewerModel implemen
throw new AssertException("Can't set data type to null.");
}
checkIsAllowableDataType(newDt, element == null || !element.isFlexibleArrayComponent());
checkIsAllowableDataType(newDt);
newLength = newDt.getLength();
if (newLength < 0) {
@@ -32,7 +32,7 @@ public class CompositeViewerDataTypeManager extends StandAloneDataTypeManager {
* @param composite the composite data type that is being edited. (cannot be null).
*/
public CompositeViewerDataTypeManager(String rootName, Composite composite) {
super(rootName);
super(rootName, composite.getDataTypeManager().getDataOrganization());
transactionID = startTransaction("");
originalDTM = composite.getDataTypeManager();
universalID = originalDTM.getUniversalID(); // mimic original DTM
@@ -50,10 +50,4 @@ public class CompositeViewerDataTypeManager extends StandAloneDataTypeManager {
return originalDTM.getType();
}
@Override
public DataOrganization getDataOrganization() {
// get the alignment from the original data type manager.
return originalDTM.getDataOrganization();
}
}
@@ -516,10 +516,7 @@ class CompositeViewerModel extends AbstractTableModel implements DataTypeManager
* Returns the number of component rows in the viewer. There may be a
* blank row at the end for selecting. Therefore this number can be
* different than the actual number of components currently in the
* structure being viewed. In addition, if a flexible array component
* exists which is not included in {@link #getNumComponents()} it
* will be included in this count and would appear after the blank row
* (e.g., getComponent(getNumComponents()+1) ).
* structure being viewed.
*
* @return the number of rows in the model
*/
@@ -530,23 +527,17 @@ class CompositeViewerModel extends AbstractTableModel implements DataTypeManager
/**
* Returns the number of components in this structure or union.
* NOTE: This number does not include the flexible array component which may exist
* within a structure.
* @return the number of components in the model
*/
public int getNumComponents() {
if (viewComposite == null) {
return 0;
}
return viewComposite.getNumComponents();
return (viewComposite != null) ? viewComposite.getNumComponents() : 0;
}
/**
* Return the nth component for the structure being viewed. Since the number of rows
* can exceed the number of components defined within the composite
* ({@link Composite#getNumComponents()}) this method will return null for a blank
* row or a flexible array component which may appear as an additional rows for
* structures.
* row.
* @param rowIndex the index of the component to return. First component is index of 0.
* @return the component
*/
@@ -588,37 +579,34 @@ class CompositeViewerModel extends AbstractTableModel implements DataTypeManager
return "";
}
String value;
DataType dt;
int dtLen;
DataTypeComponent dtc = viewComposite.getComponent(rowIndex);
if (columnIndex == getOffsetColumn()) {
int offset = viewComposite.getComponent(rowIndex).getOffset();
int offset = dtc.getOffset();
value = showHexNumbers ? getHexString(offset, true) : Integer.toString(offset);
}
else if (columnIndex == getLengthColumn()) {
int length = viewComposite.getComponent(rowIndex).getLength();
value = showHexNumbers ? getHexString(length, true) : Integer.toString(length);
int compLen = dtc.getLength();
value = showHexNumbers ? getHexString(compLen, true) : Integer.toString(compLen);
}
else if (columnIndex == getMnemonicColumn()) {
DataTypeComponent comp = viewComposite.getComponent(rowIndex);
dt = comp.getDataType();
DataType dt = dtc.getDataType();
value = dt.getMnemonic(new SettingsImpl());
int compLen = comp.getLength();
dtLen = comp.getDataType().getLength();
int compLen = dtc.getLength();
int dtLen = dt.isZeroLength() ? 0 : dt.getLength();
if (dtLen > compLen) {
value = "TooBig: " + value + " needs " + dtLen + " has " + compLen;
}
}
else if (columnIndex == getDataTypeColumn()) {
DataTypeComponent dtc = viewComposite.getComponent(rowIndex);
dt = dtc.getDataType();
dtLen = dt.getLength();
DataType dt = dtc.getDataType();
int dtLen = dt.getLength();
return DataTypeInstance.getDataTypeInstance(dt, (dtLen > 0) ? dtLen : dtc.getLength());
}
else if (columnIndex == getNameColumn()) {
value = viewComposite.getComponent(rowIndex).getFieldName();
value = dtc.getFieldName();
}
else if (columnIndex == getCommentColumn()) {
value = viewComposite.getComponent(rowIndex).getComment();
value = dtc.getComment();
}
else {
value = "UNKNOWN";
@@ -1173,20 +1161,6 @@ class CompositeViewerModel extends AbstractTableModel implements DataTypeManager
return (selection.getNumRanges() == 1);
}
/**
* Returns true if the current single row selection corresponds to a flexible array component
* @return true if the current single row selection corresponds to a flexible array component
*/
public boolean isFlexibleArraySelection() {
if (!isSingleRowSelection()) {
return false;
}
FieldRange range = selection.getFieldRange(0);
int rowIndex = range.getStart().getIndex().intValue();
DataTypeComponent component = getComponent(rowIndex);
return component != null && component.isFlexibleArrayComponent();
}
/**
* Returns true if the component list selection is a single component
* @return true if the component list selection is a single component
@@ -102,9 +102,7 @@ public class DataTypeHelper {
if (newDt == null) {
throw new InvalidDataTypeException("valid data-type not specified");
}
DataTypeComponent element = editModel.getComponent(index);
editModel.checkIsAllowableDataType(newDt,
element == null || !element.isFlexibleArrayComponent());
editModel.checkIsAllowableDataType(newDt);
int mrl = editModel.getMaxReplaceLength(index);
if ((mrl != -1) && (newDt.getLength() > mrl)) {
throw new InvalidDataTypeException(newDt.getDisplayName() + " doesn't fit within " +
@@ -214,9 +214,11 @@ public interface EditorModel {
/**
* Sets the data type for the component at the indicated row index.
* @param rowIndex the row index of the component
* @param dataTypeInstance
* @param dt component datatype
* @param length component length
* @throws UsrException if invalid datatype or length specified
*/
public void setComponentDataTypeInstance(int rowIndex, DataTypeInstance dataTypeInstance)
public void setComponentDataTypeInstance(int rowIndex, DataType dt, int length)
throws UsrException;
/**
@@ -102,10 +102,6 @@ class StructureEditorModel extends CompEditorModel {
public int getRowCount() {
int componentCount = getNumComponents();
int rowCount = componentCount + 1; // add blank edit row
Structure viewStruct = (Structure) viewComposite;
if (viewStruct != null && viewStruct.hasFlexibleArrayComponent()) {
++rowCount;
}
return rowCount;
}
@@ -129,7 +125,6 @@ class StructureEditorModel extends CompEditorModel {
}
DataTypeComponent dtc = getComponent(rowIndex);
if (dtc == null) {
if (columnIndex == getDataTypeColumn()) {
return null;
@@ -137,42 +132,34 @@ class StructureEditorModel extends CompEditorModel {
return "";
}
boolean isFlexArrayComponent = dtc.isFlexibleArrayComponent();
String value = null;
DataType dt;
int dtLen;
if (columnIndex == getOffsetColumn()) {
int offset = dtc.getOffset();
value = showHexNumbers ? getHexString(offset, true) : Integer.toString(offset);
}
else if (columnIndex == getLengthColumn()) {
int length = dtc.getLength();
value = showHexNumbers ? getHexString(length, true) : Integer.toString(length);
int compLen = dtc.getLength();
value = showHexNumbers ? getHexString(compLen, true) : Integer.toString(compLen);
}
else if (columnIndex == getMnemonicColumn()) {
dt = dtc.getDataType();
DataType dt = dtc.getDataType();
value = dt.getMnemonic(new SettingsImpl());
if (isFlexArrayComponent) {
value += "[0]";
}
else {
int compLen = dtc.getLength();
dtLen = dtc.getDataType().getLength();
if (dtLen > compLen) {
value = "TooBig: " + value + " needs " + dtLen + " has " + compLen;
}
int compLen = dtc.getLength();
int dtLen = dt.isZeroLength() ? 0 : dt.getLength();
if (dtLen > compLen) {
value = "TooBig: " + value + " needs " + dtLen + " has " + compLen;
}
}
else if (columnIndex == getDataTypeColumn()) {
dt = dtc.getDataType();
dtLen = dt.getLength();
DataType dt = dtc.getDataType();
int dtLen = dt.getLength();
return DataTypeInstance.getDataTypeInstance(dt, (dtLen > 0) ? dtLen : dtc.getLength());
}
else if (columnIndex == getNameColumn()) {
value = getComponent(rowIndex).getFieldName();
value = dtc.getFieldName();
}
else if (columnIndex == getCommentColumn()) {
value = getComponent(rowIndex).getComment();
value = dtc.getComment();
}
return (value == null) ? "" : value;
@@ -185,9 +172,6 @@ class StructureEditorModel extends CompEditorModel {
return null;
}
Structure viewStruct = (Structure) viewComposite;
if (rowIndex == (numComponents + 1)) {
return viewStruct.getFlexibleArrayComponent();
}
if (rowIndex > numComponents) {
return null;
}
@@ -203,73 +187,48 @@ class StructureEditorModel extends CompEditorModel {
return viewComposite == null ? 0 : viewComposite.getNumComponents();
}
@Override
protected boolean canConvertToFlexibleArray(int rowIndex) {
if (!(viewComposite instanceof Structure)) {
return false;
}
if (((Structure) viewComposite).hasFlexibleArrayComponent()) {
return false;
}
if (rowIndex != (getNumComponents() - 1)) {
return false;
}
DataTypeComponent dtc = getComponent(rowIndex);
DataType dt = dtc.getDataType();
if (dt instanceof TypeDef) {
dt = ((TypeDef) dt).getBaseDataType();
}
if (dt instanceof Dynamic || dt instanceof FactoryDataType) {
return false;
}
return true;
}
@Override
protected void convertToFlexibleArray(int rowIndex) throws UsrException {
if (!canConvertToFlexibleArray(rowIndex)) {
// should be avoided by constraining minimum array size and data type
throw new UsrException("Flexible array not permitted");
}
DataTypeComponent dtc = getComponent(rowIndex);
Structure struct = (Structure) viewComposite;
struct.setFlexibleArrayComponent(dtc.getDataType(), dtc.getFieldName(), dtc.getComment());
delete(rowIndex);
selection.addRange(rowIndex + 1, rowIndex + 2); // select flex component
selectionChanged();
}
@Override
protected boolean isSizeEditable() {
return !isPackingEnabled();
}
void setStructureSize(int size) {
if (viewComposite == null) {
if (viewComposite == null || viewComposite.isPackingEnabled()) {
return;
}
int currentLength = viewComposite.isZeroLength() ? 0 : viewComposite.getLength();
int currentLength = (viewComposite.isZeroLength()) ? 0 : viewComposite.getLength();
if (currentLength == size) {
return;
}
Structure structure = (Structure) viewComposite;
if (currentLength > size) {
int numComponents = structure.getNumComponents();
DataTypeComponent dtc = structure.getComponentContaining(size);
int ordinal = dtc.getOrdinal();
// retain any zero-length components which have an offset equal the new size
while (dtc.getOffset() == size && dtc.getLength() == 0 &&
(ordinal + 1) < numComponents) {
dtc = structure.getComponent(++ordinal);
}
// remove trailing components outside of new size
for (int index = numComponents - 1; index >= ordinal; index--) {
structure.delete(index);
int bitFieldResidualBytes = structure.getNumComponents() - index;
for (int i = 0; i < bitFieldResidualBytes; i++) {
// bitfield removal may cause injection of undefined bytes - remove them
structure.delete(index);
}
}
// structure may shrink too much from component removal - may need to grow
currentLength = (viewComposite.isZeroLength()) ? 0 : viewComposite.getLength();
}
if (currentLength < size) {
// Increasing structure length.
structure.growStructure(size - currentLength);
}
else {
DataTypeComponent dtc = structure.getComponentAt(size);
int ordinal = dtc.getOrdinal();
if (dtc.getOffset() != size) {
structure.clearComponent(ordinal);
dtc = structure.getComponentAt(size);
ordinal = dtc.getOrdinal();
}
int numComponents = structure.getNumComponents();
for (int index = numComponents - 1; index >= ordinal; index--) {
structure.delete(index);
}
}
updateAndCheckChangeState();
fireTableDataChanged();
}
@@ -292,9 +251,6 @@ class StructureEditorModel extends CompEditorModel {
if (dtc == null) {
return false;
}
if (dtc.isFlexibleArrayComponent()) {
return true;
}
DataType dt = dtc.getDataType();
if (dt == DataType.DEFAULT) {
return false;
@@ -398,12 +354,12 @@ class StructureEditorModel extends CompEditorModel {
}
DataTypeComponent originalComp = getComponent(index);
if (originalComp == null || originalComp.isFlexibleArrayComponent()) {
if (originalComp == null) {
throw new IllegalArgumentException("Invalid component index specified");
}
DataType dt = originalComp.getDataType();
int dtLen = dt.getLength();
checkIsAllowableDataType(dt, true);
checkIsAllowableDataType(dt);
int startIndex = index + 1;
if (isShowingUndefinedBytes() && (dt != DataType.DEFAULT)) {
@@ -570,7 +526,7 @@ class StructureEditorModel extends CompEditorModel {
@Override
public boolean isBitFieldAllowed() {
return isSingleRowSelection() && !isFlexibleArraySelection();
return isSingleRowSelection();
}
/**
@@ -587,7 +543,7 @@ class StructureEditorModel extends CompEditorModel {
FieldRange range = selection.getFieldRange(0);
DataTypeComponent comp = getComponent(range.getStart().getIndex().intValue());
if (comp == null || comp.isFlexibleArrayComponent() || comp.isBitFieldComponent()) {
if (comp == null || comp.isBitFieldComponent()) {
return false;
}
@@ -615,29 +571,6 @@ class StructureEditorModel extends CompEditorModel {
return getComponent(rowIndex) != null;
}
@Override
public void deleteSelectedComponents() throws UsrException {
if (!isDeleteAllowed()) {
throw new UsrException("Deleting is not allowed.");
}
if (isEditingField()) {
endFieldEditing();
}
int rowIndex = selection.getFieldRange(0).getStart().getIndex().intValue();
DataTypeComponent dtc = getComponent(rowIndex);
if (dtc.isFlexibleArrayComponent()) {
// Remove flexible array component
((Structure) viewComposite).clearFlexibleArrayComponent();
componentEdited();
selection.addRange(rowIndex - 1, rowIndex);
fixSelection();
selectionChanged();
return;
}
super.deleteSelectedComponents();
}
@Override
public boolean isDuplicateAllowed() {
@@ -813,7 +746,7 @@ class StructureEditorModel extends CompEditorModel {
}
try {
checkIsAllowableDataType(dataType, !dtc.isFlexibleArrayComponent());
checkIsAllowableDataType(dataType);
}
catch (InvalidDataTypeException e) {
return false;
@@ -898,9 +831,7 @@ class StructureEditorModel extends CompEditorModel {
else if (comp == null) {
return 0; // No such component. Not at valid edit index.
}
else if (comp.isFlexibleArrayComponent()) {
return Integer.MAX_VALUE;
}
// Otherwise, get size of component and number of Undefined bytes after it.
FieldRange range = getSelectedRangeContaining(currentIndex);
if (range == null ||
@@ -936,28 +867,20 @@ class StructureEditorModel extends CompEditorModel {
@Override
protected DataTypeComponent insert(int rowIndex, DataType dataType, int length, String name,
String comment) throws InvalidDataTypeException {
checkIsAllowableDataType(dataType, true);
checkIsAllowableDataType(dataType);
try {
DataTypeComponent dtc = getComponent(rowIndex);
if (dtc != null && dtc.isFlexibleArrayComponent()) {
Structure struct = (Structure) viewComposite;
dtc = struct.setFlexibleArrayComponent(dataType, dtc.getFieldName(),
dtc.getComment());
DataTypeComponent dtc;
if (isPackingEnabled() || !(dataType instanceof BitFieldDataType)) {
dtc = ((Structure) viewComposite).insert(rowIndex, dataType, length, name, comment);
}
else {
if (isPackingEnabled() || !(dataType instanceof BitFieldDataType)) {
dtc = ((Structure) viewComposite).insert(rowIndex, dataType, length, name,
comment);
}
else {
BitFieldDataType bitfield = (BitFieldDataType) dataType;
dtc = ((Structure) viewComposite).insertBitField(rowIndex, length,
bitfield.getBitOffset(), bitfield.getBaseDataType(),
bitfield.getDeclaredBitSize(), name, comment);
}
if (rowIndex <= row) {
row++;
}
BitFieldDataType bitfield = (BitFieldDataType) dataType;
dtc = ((Structure) viewComposite).insertBitField(rowIndex, length,
bitfield.getBitOffset(), bitfield.getBaseDataType(),
bitfield.getDeclaredBitSize(), name, comment);
}
if (rowIndex <= row) {
row++;
}
adjustSelection(rowIndex, 1);
// Consume undefined bytes that may have been added, if needed.
@@ -973,7 +896,7 @@ class StructureEditorModel extends CompEditorModel {
protected void insert(int rowIndex, DataType dataType, int length, int numCopies,
TaskMonitor monitor) throws InvalidDataTypeException, CancelledException {
checkIsAllowableDataType(dataType, true);
checkIsAllowableDataType(dataType);
int componentOrdinal = convertRowToOrdinal(rowIndex);
monitor.initialize(numCopies);
try {
@@ -997,21 +920,10 @@ class StructureEditorModel extends CompEditorModel {
}
}
@Override
public DataTypeComponent replace(int rowIndex, DataType dt) throws UsrException {
DataTypeComponent dtc = getComponent(rowIndex);
if (dtc == null || !dtc.isFlexibleArrayComponent()) {
return super.replace(rowIndex, dt);
}
Structure struct = (Structure) viewComposite;
return struct.setFlexibleArrayComponent(dt, dtc.getFieldName(), dtc.getComment());
}
@Override
protected DataTypeComponent replace(int rowIndex, DataType dataType, int length, String name,
String comment) throws InvalidDataTypeException {
// It is assumed that the replaced component is not a flexible array
checkIsAllowableDataType(dataType, true);
checkIsAllowableDataType(dataType);
try {
DataTypeComponent dtc = null;
boolean isSelected = selection.containsEntirely(BigInteger.valueOf(rowIndex));
@@ -294,7 +294,7 @@ class UnionEditorModel extends CompEditorModel {
if (currentIndex < 0 || currentIndex > getNumComponents()) {
return false;
}
checkIsAllowableDataType(dataType, true);
checkIsAllowableDataType(dataType);
}
catch (InvalidDataTypeException e) {
return false;
@@ -378,7 +378,7 @@ class UnionEditorModel extends CompEditorModel {
@Override
public DataTypeComponent insert(int rowIndex, DataType dataType, int length, String name,
String comment) throws InvalidDataTypeException {
checkIsAllowableDataType(dataType, true);
checkIsAllowableDataType(dataType);
try {
DataTypeComponent dtc =
((Union) viewComposite).insert(rowIndex, dataType, length, name, comment);
@@ -409,7 +409,7 @@ class UnionEditorModel extends CompEditorModel {
@Override
public DataTypeComponent replace(int rowIndex, DataType dataType, int length, String name,
String comment) throws InvalidDataTypeException {
checkIsAllowableDataType(dataType, true);
checkIsAllowableDataType(dataType);
try {
boolean isSelected = selection.containsEntirely(BigInteger.valueOf(rowIndex));
((Union) viewComposite).delete(rowIndex);
@@ -63,6 +63,8 @@ import util.CollectionUtils;
//@formatter:on
public class DataTypePreviewPlugin extends ProgramPlugin {
private static final String ROOT_NAME = "DataTypePreviewer";
private DTPPComponentProvider provider;
private DTPPTableModel model;
private DTPPTable table;
@@ -71,7 +73,7 @@ public class DataTypePreviewPlugin extends ProgramPlugin {
private GoToService goToService;
private DockingAction addAction;
private DockingAction deleteAction;
private LayeredDataTypeManager dataTypeManager;
private DataTypeManager dataTypeManager;
private Program activeProgram;
private SwingUpdateManager updateManager = new SwingUpdateManager(650, () -> updatePreview());
@@ -101,7 +103,7 @@ public class DataTypePreviewPlugin extends ProgramPlugin {
model = new DTPPTableModel();
table = new DTPPTable(model);
component = new DTPPScrollPane(table);
dataTypeManager = new LayeredDataTypeManager(activeProgram);
dataTypeManager = createLayeredDataTypeManager();
addDataType(new ByteDataType());
addDataType(new WordDataType());
@@ -177,7 +179,7 @@ public class DataTypePreviewPlugin extends ProgramPlugin {
private void updateModel() {
LayeredDataTypeManager newDtm = new LayeredDataTypeManager(activeProgram);
DataTypeManager newDtm = createLayeredDataTypeManager();
int transactionId = newDtm.startTransaction("add datatypes");
try {
@@ -197,7 +199,7 @@ public class DataTypePreviewPlugin extends ProgramPlugin {
List<DataTypePath> dtPaths = getModelDataTypePaths();
model.removeAll();
LayeredDataTypeManager oldDtm = dataTypeManager;
DataTypeManager oldDtm = dataTypeManager;
dataTypeManager = newDtm;
oldDtm.close();
@@ -711,24 +713,11 @@ public class DataTypePreviewPlugin extends ProgramPlugin {
}
}
private class LayeredDataTypeManager extends StandAloneDataTypeManager {
DataOrganization layeredDataOrganization1;
public LayeredDataTypeManager(Program program) {
super("DataTypePreviewer");
this.layeredDataOrganization1 =
program != null ? program.getDataTypeManager().getDataOrganization() : null;
}
@Override
public DataOrganization getDataOrganization() {
if (layeredDataOrganization1 == null) {
return super.getDataOrganization();
}
return layeredDataOrganization1;
}
private DataTypeManager createLayeredDataTypeManager() {
DataOrganization dataOrg =
(activeProgram != null) ? activeProgram.getCompilerSpec().getDataOrganization()
: DataOrganizationImpl.getDefaultOrganization();
return new StandAloneDataTypeManager(ROOT_NAME, dataOrg);
}
}
@@ -1,62 +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.app.plugin.core.function.editor;
import ghidra.program.model.data.*;
class DataTypeManagerStub extends StandAloneDataTypeManager {
protected DataTypeManagerStub(String name) {
super(name);
populate();
}
/**
* Add the built in data types to the default built in folder if they
* were not found in any other category.
*/
protected void populate() {
int id = super.startTransaction("Populate");
try {
resolve(new ByteDataType(), null);
resolve(new CharDataType(), null);
resolve(new BooleanDataType(), null);
resolve(new DoubleDataType(), null);
resolve(new StringDataType(), null);
resolve(new Undefined1DataType(), null);
resolve(new Undefined2DataType(), null);
resolve(new Undefined4DataType(), null);
resolve(new Undefined8DataType(), null);
resolve(new UnicodeDataType(), null);
resolve(new VoidDataType(), null);
resolve(new IntegerDataType(), null);
resolve(new ShortDataType(), null);
StructureDataType struct1 = new StructureDataType("abc", 4);
struct1.setCategoryPath(new CategoryPath("/foo"));
resolve(struct1, null);
StructureDataType struct2 = new StructureDataType("abc", 4);
struct2.setCategoryPath(new CategoryPath("/bar"));
resolve(struct2, null);
}
finally {
super.endTransaction(id, true);
}
}
}
@@ -55,6 +55,18 @@ public abstract class BiDirectionDataType extends StructureDataType
this.splitOffset = splitOffset;
}
@Override
protected DataType validateDataType(DataType dataType) {
if (DataTypeComponent.usesZeroLengthComponent(dataType)) {
throw new IllegalArgumentException(
"Zero-length datatype not permitted: " + dataType.getName());
}
if (dataType instanceof BitFieldDataType) {
throw new IllegalArgumentException("Bitfield not permitted: " + dataType.getName());
}
return super.validateDataType(dataType);
}
@Override
public int getAlignment() {
throw new UnsupportedOperationException(
@@ -91,18 +103,11 @@ public abstract class BiDirectionDataType extends StructureDataType
// ignore
}
@Override
public DataTypeComponent setFlexibleArrayComponent(DataType flexType, String name,
String comment) {
throw new UnsupportedOperationException(
"BiDirectionDataType.setFlexibleArrayComponent() not implemented.");
}
protected DataTypeComponent getDefinedComponentAt(int offset) {
if (offset < splitOffset - negativeLength || offset >= splitOffset + positiveLength) {
return null;
}
int index = Collections.binarySearch(components, new Integer(offset), offsetComparator);
int index = Collections.binarySearch(components, Integer.valueOf(offset), offsetComparator);
if (index >= 0) {
return components.get(index);
}
@@ -114,7 +119,7 @@ public abstract class BiDirectionDataType extends StructureDataType
if (offset < splitOffset - negativeLength || offset >= splitOffset + positiveLength) {
return null;
}
int index = Collections.binarySearch(components, new Integer(offset), offsetComparator);
int index = Collections.binarySearch(components, Integer.valueOf(offset), offsetComparator);
if (index >= 0) {
return components.get(index);
}
@@ -240,7 +245,7 @@ public abstract class BiDirectionDataType extends StructureDataType
if (ordinal < 0 || ordinal >= numComponents) {
throw new IndexOutOfBoundsException(ordinal);
}
int idx = Collections.binarySearch(components, new Integer(ordinal), ordinalComparator);
int idx = Collections.binarySearch(components, Integer.valueOf(ordinal), ordinalComparator);
if (idx >= 0) {
return components.get(idx);
}
@@ -248,11 +253,11 @@ public abstract class BiDirectionDataType extends StructureDataType
}
@Override
public DataTypeComponent getComponent(int ordinal) {
public DataTypeComponentImpl getComponent(int ordinal) {
if (ordinal < 0 || ordinal >= numComponents) {
throw new IndexOutOfBoundsException(ordinal);
}
int idx = Collections.binarySearch(components, new Integer(ordinal), ordinalComparator);
int idx = Collections.binarySearch(components, Integer.valueOf(ordinal), ordinalComparator);
if (idx >= 0) {
return components.get(idx);
}
@@ -307,7 +312,7 @@ public abstract class BiDirectionDataType extends StructureDataType
checkAncestry(dataType);
dataType = dataType.clone(getDataTypeManager());
int index = Collections.binarySearch(components, new Integer(offset), offsetComparator);
int index = Collections.binarySearch(components, Integer.valueOf(offset), offsetComparator);
int additionalShift = 0;
if (index >= 0) {
@@ -443,7 +448,7 @@ public abstract class BiDirectionDataType extends StructureDataType
" within a defined component in " + getDisplayName() + ".");
}
else {
definedIndex = Collections.binarySearch(components, new Integer(dtc.getOrdinal()),
definedIndex = Collections.binarySearch(components, Integer.valueOf(dtc.getOrdinal()),
ordinalComparator);
if (definedIndex < 0) {
definedIndex = -definedIndex - 1;
@@ -470,7 +475,7 @@ public abstract class BiDirectionDataType extends StructureDataType
throw new IllegalArgumentException(
"Offset " + offset + " is not in " + getDisplayName() + ".");
}
int index = Collections.binarySearch(components, new Integer(offset), offsetComparator);
int index = Collections.binarySearch(components, Integer.valueOf(offset), offsetComparator);
int length = 1;
if (index < 0) {
@@ -485,6 +490,25 @@ public abstract class BiDirectionDataType extends StructureDataType
numComponents--;
}
@Override
public void clearAtOffset(int offset) {
if (offset < splitOffset - negativeLength || offset >= splitOffset + positiveLength) {
throw new IllegalArgumentException(
"Offset " + offset + " is not in " + getDisplayName() + ".");
}
int index = Collections.binarySearch(components, Integer.valueOf(offset), offsetComparator);
if (index >= 0) {
DataTypeComponent dtc = components.remove(index);
dtc.getDataType().removeParent(this);
int len = dtc.getLength();
if (len > 1) {
int deltaLength = len - 1;
shiftOffsets(index, deltaLength, 0);
numComponents += deltaLength;
}
}
}
@Override
public boolean isEquivalent(DataType dataType) {
if (dataType == this) {
@@ -531,19 +555,19 @@ public abstract class BiDirectionDataType extends StructureDataType
public abstract BiDirectionDataType clone(DataTypeManager dtm);
@Override
public void clearComponent(int index) {
if (index < 0 || index >= numComponents) {
throw new IndexOutOfBoundsException(index);
public void clearComponent(int ordinal) {
if (ordinal < 0 || ordinal >= numComponents) {
throw new IndexOutOfBoundsException(ordinal);
}
int idx = Collections.binarySearch(components, new Integer(index), ordinalComparator);
if (idx >= 0) {
DataTypeComponent dtc = components.remove(idx);
int index =
Collections.binarySearch(components, Integer.valueOf(ordinal), ordinalComparator);
if (index >= 0) {
DataTypeComponent dtc = components.remove(index);
dtc.getDataType().removeParent(this);
int len = dtc.getLength();
int deltaLength = len - 1;
// int offset = dtc.getOffset();
if (len > 1) {
shiftOffsets(idx, deltaLength, 0);
int deltaLength = len - 1;
shiftOffsets(index, deltaLength, 0);
numComponents += deltaLength;
}
}
@@ -644,7 +668,8 @@ public abstract class BiDirectionDataType extends StructureDataType
DataTypeComponentImpl newDtc =
new DataTypeComponentImpl(dataType, this, length, ordinal, newOffset, newName, comment);
dataType.addParent(this);
int index = Collections.binarySearch(components, new Integer(ordinal), ordinalComparator);
int index =
Collections.binarySearch(components, Integer.valueOf(ordinal), ordinalComparator);
if (index < 0) {
index = -index - 1;
}
@@ -79,6 +79,16 @@ class StackEditorModel extends CompositeEditorModel {
}
}
@Override
protected boolean allowsZeroLengthComponents() {
return false;
}
@Override
protected boolean allowsBitFields() {
return false;
}
void stackChangedExcternally(boolean changed) {
stackChangedExternally = changed;
}
@@ -612,7 +622,7 @@ class StackEditorModel extends CompositeEditorModel {
if (currentIndex < 0 || currentIndex >= getRowCount()) {
return false;
}
checkIsAllowableDataType(dataType, true);
checkIsAllowableDataType(dataType);
}
catch (InvalidDataTypeException e) {
return false;
@@ -720,7 +730,7 @@ class StackEditorModel extends CompositeEditorModel {
if (currentIndex < 0 || currentIndex >= getRowCount()) {
return false;
}
checkIsAllowableDataType(dataType, true);
checkIsAllowableDataType(dataType);
}
catch (InvalidDataTypeException e) {
return false;
@@ -788,10 +798,9 @@ class StackEditorModel extends CompositeEditorModel {
}
@Override
public void setComponentDataTypeInstance(int index, DataTypeInstance dti) throws UsrException {
DataType dt = dti.getDataType();
checkIsAllowableDataType(dt, true);
((StackFrameDataType) viewComposite).setDataType(index, dt, dti.getLength());
public void setComponentDataTypeInstance(int index, DataType dt, int length) throws UsrException {
checkIsAllowableDataType(dt);
((StackFrameDataType) viewComposite).setDataType(index, dt, length);
}
@Override
@@ -806,7 +815,7 @@ class StackEditorModel extends CompositeEditorModel {
public void setComponentName(int rowIndex, String newName)
throws InvalidInputException, InvalidNameException, DuplicateNameException {
if (newName.equals("")) {
if (newName.trim().length() == 0) {
newName = null;
}
// if (nameExistsElsewhere(newName, currentIndex)) {
@@ -1330,7 +1339,7 @@ class StackEditorModel extends CompositeEditorModel {
int newLength = newDt.getLength();
checkIsAllowableDataType(newDt, true);
checkIsAllowableDataType(newDt);
newDt = DataTypeHelper.resolveDataType(newDt, viewDTM, null);
int maxLength = getMaxReplaceLength(index);
if (newLength <= 0) {
@@ -25,6 +25,7 @@ import ghidra.program.model.mem.MemBuffer;
import ghidra.program.model.pcode.Varnode;
import ghidra.program.model.symbol.SymbolUtilities;
import ghidra.util.InvalidNameException;
import ghidra.util.SystemUtilities;
import ghidra.util.exception.AssertException;
import ghidra.util.exception.InvalidInputException;
@@ -410,22 +411,22 @@ public class StackFrameDataType extends BiDirectionDataType {
*
* @param ordinal the ordinal
* @param name the new name. Null indicates the default name.
* @return true if name change was successful, else false
*/
public boolean setName(int ordinal, String name) {
validateName(ordinal, name);
DataTypeComponent comp = getComponent(ordinal);
String fieldName = comp.getFieldName();
if ((name != null) && ((name.length() == 0) || (isDefaultName(name)))) {
name = null;
}
if (name == null) {
if (fieldName == null) {
return false;
if (name != null) {
name = name.trim();
if (name.length() == 0 || isDefaultName(name)) {
name = null;
}
}
else if (name.equals(fieldName)) {
if (SystemUtilities.isEqual(name, fieldName)) {
return false;
}
DataType dt = comp.getDataType();
int length = comp.getLength();
String comment = comp.getComment();
@@ -163,10 +163,16 @@ class DWARFDataTypeConflictHandler extends DataTypeConflictHandler {
// isEquiv().
// Ensure that two components in the partial struct don't map to the same
// component in the full structure.
for (DataTypeComponent partDTC : partComps) {
DataType partDT = partDTC.getDataType();
if (partDT.isZeroLength()) {
// don't try to match zero length fields, so skip
continue;
}
DataTypeComponent fullDTCAt = (partDTC.getDataType() instanceof BitFieldDataType)
? getBitfieldByOffsets(full, partDTC)
: full.getComponentAt(partDTC.getOffset());
: getBestMatchingDTC(full, partDTC);
if (fullDTCAt == null || fullDTCAt.getOffset() != partDTC.getOffset() ||
!SystemUtilities.isEqual(fullDTCAt.getFieldName(), partDTC.getFieldName())) {
return false;
@@ -175,15 +181,20 @@ class DWARFDataTypeConflictHandler extends DataTypeConflictHandler {
return false;
}
}
if ( part.getFlexibleArrayComponent() != null ) {
return full.getFlexibleArrayComponent() != null &&
isMemberFieldPartiallyCompatible(full.getFlexibleArrayComponent(),
part.getFlexibleArrayComponent(), visitedDataTypes);
}
return true;
}
DataTypeComponent getBestMatchingDTC(Structure struct, DataTypeComponent matchCriteria) {
for (DataTypeComponent dtc : struct.getComponentsContaining(matchCriteria.getOffset())) {
DataType dt = dtc.getDataType();
if (dtc.getOffset() == matchCriteria.getOffset() && !dt.isZeroLength()) {
return dtc;
}
}
return null;
}
boolean isMemberFieldPartiallyCompatible(DataTypeComponent fullDTC, DataTypeComponent partDTC,
Set<Long> visitedDataTypes) {
DataType partDT = partDTC.getDataType();
@@ -216,7 +227,7 @@ class DWARFDataTypeConflictHandler extends DataTypeConflictHandler {
private DataTypeComponent getBitfieldByOffsets(Structure full, DataTypeComponent partDTC) {
BitFieldDataType partBF = (BitFieldDataType) partDTC.getDataType();
DataTypeComponent fullDTC = full.getComponentAt(partDTC.getOffset());
DataTypeComponent fullDTC = full.getComponentContaining(partDTC.getOffset());
if (fullDTC == null) {
return null;
}
@@ -223,11 +223,6 @@ public class DWARFDataTypeImporter {
/**
* Returns true if the previously imported data type should be reused.
* <p>
* Don't re-use previously imported single-element
* Ghidra array datatypes because they may have actually been an empty array
* definition and we need the special meta-data flag DWARFDataType.isEmptyArrayType
* which is only available in a freshly created DWARFDataType.
* <p>
* Don't re-use empty structs (isNotYetDefined) to ensure that newer
* definitions of the same struct are given a chance to be resolved()
* into the DTM.
@@ -236,10 +231,7 @@ public class DWARFDataTypeImporter {
* @return boolean true if its okay to reuse the data type
*/
private boolean shouldReuseAlreadyImportedDT(DataType alreadyImportedDT) {
return alreadyImportedDT != null &&
!alreadyImportedDT.isNotYetDefined() &&
!(alreadyImportedDT instanceof Array &&
((Array) alreadyImportedDT).getNumElements() == 1);
return alreadyImportedDT != null && !alreadyImportedDT.isNotYetDefined();
}
/*
@@ -552,12 +544,19 @@ public class DWARFDataTypeImporter {
structSize = 0;
}
boolean isUnion = diea.getTag() == DWARFTag.DW_TAG_union_type;
boolean isDecl = diea.getBool(DWARFAttribute.DW_AT_declaration, false);
DataType struct =
isUnion ? new UnionDataType(dni.getParentCP(), dni.getName(), dataTypeManager)
: new StructureDataType(dni.getParentCP(), dni.getName(), (int) structSize,
dataTypeManager);
if (!isDecl && origStructSize == 0) {
// Enable packing on 0-byte composites so they are treated as defined
// and will not take space if used in a field in another composite.
((Composite) struct).setToDefaultPacking();
}
DWARFDataType result = new DWARFDataType(struct, dni, diea.getOffset());
result.dsi = DWARFSourceInfo.create(diea);
@@ -719,6 +718,9 @@ public class DWARFDataTypeImporter {
}
if (union.getLength() < unionSize) {
// NOTE: this is likely due incorrect alignment for union or one or more of its components.
// Default alignment is 1 for non-packed unions and structures.
// if the Ghidra union data type is smaller than the DWARF union, pad it out
DataType padding = Undefined.getUndefinedDataType((int) unionSize);
try {
@@ -773,11 +775,14 @@ public class DWARFDataTypeImporter {
DataTypeComponent[] definedComponents = structure.getDefinedComponents();
for (int i = 0; i < definedComponents.length; i++) {
DataTypeComponent dtc = definedComponents[i];
DataType dtcDT = dtc.getDataType();
if (dtcDT.isZeroLength()) {
continue;
}
int nextDTCOffset =
(i < definedComponents.length - 1) ? definedComponents[i + 1].getOffset()
: structure.getLength();
int emptySpaceBetween = nextDTCOffset - dtc.getEndOffset();
DataType dtcDT = dtc.getDataType();
int emptySpaceBetween = nextDTCOffset - (dtc.getEndOffset() + 1);
if (dtc.getLength() < dtcDT.getLength() && emptySpaceBetween > 0) {
DataTypeComponent newDTC = structure.replaceAtOffset(dtc.getOffset(), dtcDT,
Math.min(nextDTCOffset - dtc.getOffset(), dtc.getDataType().getLength()),
@@ -802,17 +807,15 @@ public class DWARFDataTypeImporter {
DataTypeComponent[] definedComponents = structure.getDefinedComponents();
if (definedComponents.length > 0) {
DataTypeComponent lastDTC = definedComponents[definedComponents.length - 1];
return lastDTC.getOffset() + getUnpaddedDataTypeLength(lastDTC.getDataType());
return lastDTC.getOffset() + lastDTC.getLength();
}
}
return dt.getLength();
return dt.isZeroLength() ? 0 : dt.getLength();
}
private void populateStubStruct_worker(DWARFDataType ddt, StructureDataType structure,
DIEAggregate diea, int childTagType) throws IOException, DWARFExpressionException {
Set<Long> conflictingZeroLenFields = getConflictingZeroLenFields(diea, childTagType);
for (DebugInfoEntry childEntry : diea.getHeadFragment().getChildren(childTagType)) {
DIEAggregate childDIEA = prog.getAggregate(childEntry);
@@ -870,19 +873,6 @@ public class DWARFDataTypeImporter {
}
}
if (conflictingZeroLenFields.contains(childEntry.getOffset())) {
// Skip adding this member because it is a problematic zero-length
// field
DWARFUtil.appendDescription(structure,
memberDesc("Missing member", "zero-length member", memberName, childDT,
memberOffset, -1, -1),
"\n");
continue;
}
boolean isDynamicSizedType = (childDT.dataType instanceof Dynamic ||
childDT.dataType instanceof FactoryDataType);
//if (childDT.getPathName().equals(structure.getPathName()) && childDT != structure) {
// The child we are adding has the exact same fullpath as us.
// This can happen when DWARF namespace info gets squished and two types
@@ -892,33 +882,7 @@ public class DWARFDataTypeImporter {
// TODO: rename parent struct here. use .conflict or _basetype?
//}
if (childDT.isEmptyArrayType && childDT.dataType instanceof Array) {
if (memberOffset == structure.getLength() &&
structure.getFlexibleArrayComponent() == null) {
DataType arrayElementType = ((Array) childDT.dataType).getDataType();
structure.setFlexibleArrayComponent(arrayElementType, memberName, null);
}
else {
DWARFUtil.appendDescription(structure,
memberDesc("Missing member",
"Unsupported interior flex array: " + childDT.dataType.getName(),
memberName, childDT, memberOffset, -1, -1),
"\n");
}
// skip the rest of this loop as it deals with adding component children members.
continue;
}
if (isBitField) {
if (isDynamicSizedType) {
DWARFUtil.appendDescription(structure, memberDesc("Missing member",
"dynamic length type", memberName, childDT, memberOffset, bitSize, -1),
"\n");
continue;
}
if (!BitFieldDataType.isValidBaseDataType(childDT.dataType)) {
DWARFUtil.appendDescription(structure,
memberDesc("Missing member",
@@ -982,16 +946,14 @@ public class DWARFDataTypeImporter {
}
else {
String memberComment = null;
boolean isDynamicSizedType = (childDT.dataType instanceof Dynamic ||
childDT.dataType instanceof FactoryDataType);
if (isDynamicSizedType) {
memberComment = "Unsupported dynamic size data type: " + childDT.dataType;
childDT.dataType = Undefined.getUndefinedDataType(1);
}
int childLength = getUnpaddedDataTypeLength(childDT.dataType);
if (structure.isNotYetDefined() ||
(memberOffset + childLength > structure.getLength())) {
// zero len struct can't have members added, even if they are zero len, or
// member is longer than struct has storage for
if (memberOffset + childLength > structure.getLength()) {
DWARFUtil.appendDescription(structure, memberDesc("Missing member",
"exceeds parent struct len", memberName, childDT, memberOffset, -1, -1),
"\n");
@@ -999,21 +961,39 @@ public class DWARFDataTypeImporter {
continue;
}
DataTypeComponent existingDTC = structure.getComponentAt(memberOffset);
if (existingDTC != null &&
!(existingDTC.getDataType() instanceof DefaultDataType)) {
DWARFUtil.appendDescription(structure,
memberDesc("Missing member", "conflict with " + existingDTC.getFieldName(),
memberName, childDT, memberOffset, -1, -1),
"\n");
continue;
}
try {
DataTypeComponent dtc = structure.replaceAtOffset(memberOffset,
childDT.dataType, childLength, memberName, memberComment);
// struct.replaceAtOffset() clones the childDT, which will mess up our
DataTypeComponent dtc;
if (DataTypeComponent.usesZeroLengthComponent(childDT.dataType)) {
if (!isUndefinedOrZeroLenAtOffset(structure, memberOffset)) {
DWARFUtil.appendDescription(structure, memberDesc("Missing member",
"conflicting member at same offset", memberName, childDT,
memberOffset, -1, -1), "\n");
continue;
}
// use insertAt for zero len members to allow multiple at same offset
dtc =
structure.insertAtOffset(memberOffset, childDT.dataType, 0, memberName,
memberComment);
}
else {
int ordinalToReplace = getUndefinedOrdinalAt(structure, memberOffset);
if (ordinalToReplace == -1) {
DataTypeComponent existingDTC =
structure.getComponentContaining(memberOffset);
if (existingDTC != null) {
DWARFUtil.appendDescription(structure,
memberDesc("Missing member",
"conflict with " + existingDTC.getFieldName(),
memberName, childDT, memberOffset, -1, -1),
"\n");
}
continue;
}
dtc = structure.replace(ordinalToReplace, childDT.dataType, childLength,
memberName, memberComment);
}
// struct.replaceAtOffset() and insertAtOffset() clones the childDT, which will mess up our
// identity based mapping in currentImplDataTypeToDDT.
// Update the mapping to prevent that.
updateMapping(childDT.dataType, dtc.getDataType());
@@ -1030,72 +1010,29 @@ public class DWARFDataTypeImporter {
}
}
private Set<Long> getConflictingZeroLenFields(DIEAggregate diea, int childTagType)
throws IOException, DWARFExpressionException {
// Returns a set of DIE offsets of zero len fields that are fighting for
// the same offset in the parent struct
Map<Integer, Set<Long>> zeroLenMembers = new HashMap<>();
for (DebugInfoEntry childEntry : diea.getHeadFragment().getChildren(childTagType)) {
DIEAggregate childDIEA = prog.getAggregate(childEntry);
if (childDIEA.hasAttribute(DWARFAttribute.DW_AT_external)) {
continue;
}
int bitSize = childDIEA.parseInt(DWARFAttribute.DW_AT_bit_size, -1);
boolean isBitField = bitSize != -1;
if (isBitField) {
continue;
}
DWARFDataType childDT = getDataType(childDIEA.getTypeRef(), null);
if (childDT == null) {
continue;
}
if (childDT.isZeroLenDT()) {
try {
int memberOffset =
childDIEA.parseDataMemberOffset(DWARFAttribute.DW_AT_data_member_location,
0);
zeroLenMembers.computeIfAbsent(memberOffset, k -> new HashSet<>())
.add(childEntry.getOffset());
}
catch (DWARFExpressionException e) {
continue;
}
}
private boolean isUndefinedOrZeroLenAtOffset(Structure struct, int offset) {
List<DataTypeComponent> compsAt = struct.getComponentsContaining(offset);
DataTypeComponent lastComp = !compsAt.isEmpty() ? compsAt.get(compsAt.size() - 1) : null;
if (lastComp == null) {
// only triggered if offset == length of struct, which is okay since we are adding
// a zero-length component to the struct
return true;
}
Set<Long> conflictingZeroLenFields = new HashSet<>();
for (DebugInfoEntry childEntry : diea.getHeadFragment().getChildren(childTagType)) {
DIEAggregate childDIEA = prog.getAggregate(childEntry);
if (childDIEA.hasAttribute(DWARFAttribute.DW_AT_external)) {
continue;
}
int bitSize = childDIEA.parseInt(DWARFAttribute.DW_AT_bit_size, -1);
boolean isBitField = bitSize != -1;
if (isBitField) {
continue;
}
DWARFDataType childDT = getDataType(childDIEA.getTypeRef(), null);
if (childDT == null) {
continue;
}
int memberOffset = 0;
try {
memberOffset =
childDIEA.parseDataMemberOffset(DWARFAttribute.DW_AT_data_member_location, 0);
}
catch (DWARFExpressionException e) {
continue;
}
if (!childDT.isZeroLenDT() && zeroLenMembers.containsKey(memberOffset)) {
conflictingZeroLenFields.addAll(zeroLenMembers.get(memberOffset));
}
if (lastComp.getOffset() != offset) {
return false;
}
return conflictingZeroLenFields;
DataType dt = lastComp.getDataType();
return dt.isZeroLength() || dt instanceof DefaultDataType;
}
private int getUndefinedOrdinalAt(Structure struct, int offset) {
List<DataTypeComponent> compsAt = struct.getComponentsContaining(offset);
DataTypeComponent lastComp = !compsAt.isEmpty() ? compsAt.get(compsAt.size() - 1) : null;
if (lastComp == null || lastComp.getOffset() != offset ||
!(lastComp.getDataType() instanceof DefaultDataType)) {
return -1;
}
return lastComp.getOrdinal();
}
private static String memberDesc(String prefix, String errorStr, String memberName,
@@ -1120,7 +1057,6 @@ public class DWARFDataTypeImporter {
throws IOException, DWARFExpressionException {
DWARFDataType elementType = getDataType(diea.getTypeRef(), voidDDT);
// do a second query to see if there was a recursive loop in the call above back
// to this datatype that resulted in this datatype being created.
// Use that instance if possible.
@@ -1132,7 +1068,6 @@ public class DWARFDataTypeImporter {
// Build a list of the defined dimensions for this array type.
// The first element in the DWARF dimension list would be where a wild-card (-1 length)
// dimension would be defined.
boolean isEmptyArray = false;
List<Integer> dimensions = new ArrayList<>();
List<DebugInfoEntry> subrangeDIEs =
diea.getHeadFragment().getChildren(DWARFTag.DW_TAG_subrange_type);
@@ -1146,17 +1081,14 @@ public class DWARFDataTypeImporter {
}
// Otherwise check for an upper bound
else if (subrangeAggr.hasAttribute(DWARFAttribute.DW_AT_upper_bound)) {
// TODO: Check lower bound or get the difference based on
// the language (See DWARF4 Section 5.11)
// TODO: upperbound == -1 seems to indicate zero length array
long upperBound =
subrangeAggr.parseUnsignedLong(DWARFAttribute.DW_AT_upper_bound, 0xbadbeef);
// fix special flag values used by DWARF to indicate that the array dimension
// is unknown. 64bit 0xffffff...s will already be -1, and 32bit 0xffff..s will
// be forced to -1.
// is unknown. 64bit 0xffffff...s and 32bit 0xffff..s will
// be forced to 0.
if (upperBound == 0xFF_FF_FF_FFL /* ie. max uint32 */ || upperBound == -1) {
upperBound = -1;
upperBound = 0;
}
else {
numElements = upperBound + 1;
@@ -1169,28 +1101,7 @@ public class DWARFDataTypeImporter {
}
if (numElements == -1) {
// if numElements is the DWARF special flag value for unknown, set flag
// and force the value back to something that Ghidra datatypes can handle.
// The consumer of the resultant data type will get back an array with
// 1 element instead of 0 elements because of Ghidra's limitations.
// They should check the DWARFDataType.isEmptyArrayType flag (I'm looking at
// you makeDataTypeForStruct()) if they can handle unknown length arrays.
if (subRangeDIEIndex == 0) {
isEmptyArray = true;
}
else {
Msg.error(this,
"Bad undefined-length array dimension for subrange " + subRangeDIEIndex +
" for array's size in DIE: " + diea.getOffset() + ", forcing to 1");
}
numElements = 1;
}
else if (numElements == 0) {
Msg.error(this,
"Unsupported value [" + numElements + "] for array's size in DIE: " +
diea.getOffset() + ", forcing to 1");
numElements = 1;
isEmptyArray = true;
numElements = 0;
}
else if (numElements > Integer.MAX_VALUE) {
Msg.error(this, "Bad value [" + numElements + "] for array's size in DIE: " +
@@ -1205,7 +1116,7 @@ public class DWARFDataTypeImporter {
for (int i = dimensions.size() - 1; i >= 0; i--) {
int numElements = dimensions.get(i);
ArrayDataType subArray =
new ArrayDataType(dt, numElements, dt.getLength(), dataTypeManager);
new ArrayDataType(dt, numElements, -1, dataTypeManager);
if (dt == elementType.dataType) {
updateMapping(dt, subArray.getDataType());
}
@@ -1213,7 +1124,6 @@ public class DWARFDataTypeImporter {
}
DWARFDataType result = new DWARFDataType(dt, null, diea.getOffset());
result.isEmptyArrayType = isEmptyArray;
return result;
}
@@ -1445,7 +1355,6 @@ public class DWARFDataTypeImporter {
static class DWARFDataType {
DataType dataType;
boolean isEmptyArrayType;
DWARFNameInfo dni;
DWARFSourceInfo dsi;
Set<Long> offsets = new HashSet<>();
@@ -1473,12 +1382,5 @@ public class DWARFDataTypeImporter {
Collectors.joining(","));
}
boolean isZeroLenDT() {
DataType tmpDt =
(dataType instanceof TypeDef) ? ((TypeDef) dataType).getBaseDataType() : dataType;
return isEmptyArrayType || tmpDt.isNotYetDefined() ||
tmpDt.getLength() == 0 /* this can't happen right now, but never know for future */;
}
}
}
@@ -24,6 +24,7 @@ import ghidra.app.cmd.label.SetLabelPrimaryCmd;
import ghidra.app.util.bin.format.dwarf4.*;
import ghidra.app.util.bin.format.dwarf4.encoding.*;
import ghidra.app.util.bin.format.dwarf4.expression.*;
import ghidra.program.database.data.DataTypeUtilities;
import ghidra.program.database.function.OverlappingFunctionException;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSet;
@@ -258,6 +259,19 @@ public class DWARFFunctionImporter {
DWARFTag.DW_TAG_formal_parameter)) {
DIEAggregate childDIEA = prog.getAggregate(childEntry);
DataType childDT = dwarfDTM.getDataType(childDIEA.getTypeRef(), null);
if (childDT == null || DataTypeComponent.usesZeroLengthComponent(childDT)) {
String paramName =
childDIEA.getString(DWARFAttribute.DW_AT_name, "param" + formalParams.size());
Msg.warn(this, "DWARF: zero-length function parameter " + paramName +
":" + childDT.getName() + ", omitting from definition of " +
dfunc.dni.getName() + "@" + dfunc.address);
// skip this parameter because its data type is a zero-width type that typically does
// not generate code. If this varies compiler-to-compiler, setting
// skipFuncSignature=true may be a better choice
continue;
}
Parameter formalParam = createFormalParameter(childDIEA);
if (formalParam == null) {
skipFuncSignature = true;
@@ -581,27 +595,7 @@ public class DWARFFunctionImporter {
}
}
else if (exprEvaluator.getLastRegister() == null) {
dvar.dni = dvar.dni.replaceType(null /*nothing matches static global var*/);
if (res != 0) {
// If the expression evaluated to a static address other than '0'
Address staticVariableAddress = toAddr(res + prog.getProgramBaseAddressFixup());
if (variablesProcesesed.contains(staticVariableAddress)) {
return null;
}
boolean external = diea.getBool(DWARFAttribute.DW_AT_external, false);
outputGlobal(staticVariableAddress, dvar.type, external,
DWARFSourceInfo.create(diea), dvar.dni);
}
else {
// If the expression evaluated to a static address of '0'.
// This case is probably caused by relocation fixups not being applied to the
// .debug_info section.
importSummary.relocationErrorVarDefs.add(
dvar.dni.getNamespacePath().asFormattedString() + " : " +
dvar.type.getPathName());
}
processStaticVar(res, dvar, diea);
return null;// Don't return the variable to be associated with the function
}
else {
@@ -615,6 +609,61 @@ public class DWARFFunctionImporter {
return dvar;
}
private void processStaticVar(long address, DWARFVariable dvar, DIEAggregate diea)
throws InvalidInputException {
dvar.dni = dvar.dni.replaceType(null /*nothing matches static global var*/);
if (address != 0) {
Address staticVariableAddress = toAddr(address + prog.getProgramBaseAddressFixup());
if (isZeroByteDataType(dvar.type)) {
processZeroByteStaticVar(staticVariableAddress, dvar);
return;
}
if (variablesProcesesed.contains(staticVariableAddress)) {
return;
}
boolean external = diea.getBool(DWARFAttribute.DW_AT_external, false);
outputGlobal(staticVariableAddress, dvar.type, external,
DWARFSourceInfo.create(diea), dvar.dni);
}
else {
// If the expression evaluated to a static address of '0'.
// This case is probably caused by relocation fixups not being applied to the
// .debug_info section.
importSummary.relocationErrorVarDefs.add(
dvar.dni.getNamespacePath().asFormattedString() + " : " +
dvar.type.getPathName());
}
}
private void processZeroByteStaticVar(Address staticVariableAddress, DWARFVariable dvar)
throws InvalidInputException {
// because this is a zero-length data type (ie. array[0]),
// don't create a variable at the location since it will prevent other elements
// from occupying the same offset
Listing listing = currentProgram.getListing();
String comment =
listing.getComment(CodeUnit.PRE_COMMENT, staticVariableAddress);
comment = (comment != null) ? comment + "\n" : "";
comment += String.format("Zero length variable: %s: %s", dvar.dni.getOriginalName(),
dvar.type.getDisplayName());
listing.setComment(staticVariableAddress, CodeUnit.PRE_COMMENT, comment);
SymbolTable symbolTable = currentProgram.getSymbolTable();
symbolTable.createLabel(staticVariableAddress, dvar.dni.getName(),
dvar.dni.getParentNamespace(currentProgram),
SourceType.IMPORTED);
}
private boolean isZeroByteDataType(DataType dt) {
if (!dt.isZeroLength() && dt instanceof Array) {
dt = DataTypeUtilities.getArrayBaseDataType((Array) dt);
}
return dt.isZeroLength();
}
/**
* Process lexical block entries.
*
@@ -108,9 +108,8 @@ public class PEx64UnwindInfoDataType extends DynamicDataType {
if (hasExceptionHandler(flags) || hasUnwindHandler(flags)) {
struct.add(IBO32, "ExceptionHandler", null);
if (hasUnwindHandler(flags)) {
// NOTE: Dynamic structure does not reflect flex-array
struct.setFlexibleArrayComponent(UnsignedLongDataType.dataType, "ExceptionData",
null);
struct.add(new ArrayDataType(UnsignedLongDataType.dataType, 0, -1),
"ExceptionData", null);
}
}
else if (hasChainedUnwindInfo(flags)) {
@@ -132,14 +131,7 @@ public class PEx64UnwindInfoDataType extends DynamicDataType {
if (struct == null) {
return null;
}
DataTypeComponent[] components = struct.getComponents();
if (struct.hasFlexibleArrayComponent()) {
DataTypeComponent[] newArray = new DataTypeComponent[components.length + 1];
System.arraycopy(components, 0, newArray, 0, components.length);
newArray[components.length] = struct.getFlexibleArrayComponent();
components = newArray;
}
return components;
return struct.getComponents();
}
private boolean hasExceptionHandler(int flags) {
@@ -43,17 +43,8 @@ public class CompositeHandler {
if (dec == null || dec.getDataType() == null) {
return;
}
if (parent instanceof Structure) {
// ensure that only the last component establishes a structure's flex array
((Structure) parent).clearFlexibleArrayComponent();
}
// not a bitfield, just add the data type to composite
if (!dec.isBitField()) {
if (dec.isFlexArray() && parent instanceof Structure) {
((Structure) parent).setFlexibleArrayComponent(dec.getDataType(), dec.getName(),
dec.getComment());
return;
}
parent.add(dec.getDataType(), dec.getName(), dec.getComment());
return;
}
@@ -27,7 +27,6 @@ public class Declaration {
private String name;
private String comment;
private int bitSize = -1;
private boolean flexArray = false; // true if this is a zero size flex array component
public Declaration() {
super();
@@ -155,11 +154,4 @@ public class Declaration {
bitSize = bits;
}
public void setFlexArray(boolean b) {
flexArray = b;
}
public boolean isFlexArray() {
return flexArray;
}
}
@@ -110,7 +110,11 @@ public class ArrayDataTypeHTMLRepresentation extends HTMLDataTypeRepresentation
}
private ValidatableLine buildFooterContent() {
return new TextLine("Size: " + array.getLength());
int len = array.getLength();
if (array.isZeroLength()) {
return new TextLine("Size: 0 (reported size is " + len + ")");
}
return new TextLine("Size: " + len);
}
private String buildHTMLText(ValidatableLine header, String body, ValidatableLine info,
@@ -100,11 +100,11 @@ public class CompositeDataTypeHTMLRepresentation extends HTMLDataTypeRepresentat
protected List<ValidatableLine> buildAlignmentText(Composite dataType) {
List<ValidatableLine> list = new ArrayList<>();
String alignStr = CompositeDataTypeImpl.getMinAlignmentString(dataType);
String alignStr = CompositeInternal.getMinAlignmentString(dataType);
if (alignStr != null && alignStr.length() != 0) {
list.add(new TextLine(alignStr));
}
String packStr = CompositeDataTypeImpl.getPackingString(dataType);
String packStr = CompositeInternal.getPackingString(dataType);
if (packStr != null && packStr.length() != 0) {
list.add(new TextLine(packStr));
}
@@ -117,10 +117,6 @@ public class CompositeDataTypeHTMLRepresentation extends HTMLDataTypeRepresentat
private List<ValidatableLine> buildContent(Composite comp) {
List<ValidatableLine> list = new ArrayList<>();
if (comp.isZeroLength()) {
return list;
}
int count = 0;
DataTypeComponent[] components = comp.getComponents();
for (DataTypeComponent dataTypeComponent : components) {
@@ -135,27 +131,14 @@ public class CompositeDataTypeHTMLRepresentation extends HTMLDataTypeRepresentat
locatableType = getLocatableDataType(dataType);
}
list.add(new DataTypeLine(fieldName, type, comment, locatableType, false));
list.add(new DataTypeLine(fieldName, type, comment, locatableType));
if (count++ >= MAX_COMPONENT_COUNT) {
// Prevent a ridiculous number of components from consuming all memory.
list.add(new DataTypeLine("", "Warning: Too many components to display...", "",
null, false));
list.add(
new DataTypeLine("", "Warning: Too many components to display...", "", null));
break;
}
}
if (comp instanceof Structure) {
Structure struct = (Structure) comp;
DataTypeComponent flexibleArrayComponent = struct.getFlexibleArrayComponent();
if (count < MAX_COMPONENT_COUNT && flexibleArrayComponent != null) {
String fieldName = flexibleArrayComponent.getFieldName();
String comment = flexibleArrayComponent.getComment();
DataType dataType = flexibleArrayComponent.getDataType();
String type = dataType.getDisplayName();
DataType locatableType = getLocatableDataType(dataType);
list.add(new DataTypeLine(fieldName, type, comment, locatableType, true));
}
}
return list;
}
@@ -239,9 +222,6 @@ public class CompositeDataTypeHTMLRepresentation extends HTMLDataTypeRepresentat
StringBuilder lineBuffer = new StringBuilder();
DataTypeLine line = (DataTypeLine) iterator.next();
String typeName = generateTypeName(line, trim);
if (line.isFlexibleArray()) {
typeName += "[0]";
}
int fieldLength = ToolTipUtils.LINE_LENGTH / 2;
String fieldName = line.getName();
@@ -29,7 +29,6 @@ public class DataTypeLine implements ValidatableLine {
private String name;
private String comment;
private DataType dataType;
private boolean isFlexibleArray;
private Color typeColor;
private Color nameColor;
@@ -37,9 +36,8 @@ public class DataTypeLine implements ValidatableLine {
private ValidatableLine validationLine;
DataTypeLine(String name, String type, String comment, DataType dt, boolean isFlexibleArray) {
DataTypeLine(String name, String type, String comment, DataType dt) {
this.dataType = dt;
this.isFlexibleArray = isFlexibleArray;
if (name == null) {
name = "";
}
@@ -49,17 +47,9 @@ public class DataTypeLine implements ValidatableLine {
this.comment = comment == null ? "" : comment;
}
/**
* Determine if data type should be treated as flexible array
* @return true if data type should be treated as flexible array
*/
public boolean isFlexibleArray() {
return isFlexibleArray;
}
@Override
public ValidatableLine copy() {
return new DataTypeLine(name, type, comment, dataType, isFlexibleArray);
return new DataTypeLine(name, type, comment, dataType);
}
@Override
@@ -21,7 +21,7 @@ import ghidra.util.exception.AssertException;
public class EmptyDataTypeLine extends DataTypeLine implements PlaceHolderLine {
public EmptyDataTypeLine() {
super("", "", "", null, false);
super("", "", "", null);
}
@Override
@@ -20,6 +20,8 @@ import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import docking.widgets.fieldpanel.field.*;
import docking.widgets.fieldpanel.support.FieldLocation;
import docking.widgets.fieldpanel.support.FieldUtils;
@@ -245,19 +247,32 @@ public class PreCommentFieldFactory extends FieldFactory {
}
private String[] getDataAutoComments(Data data) {
// Build flexible array comment
Address addr = data.getMinAddress().previous();
if (addr != null) {
return getFlexArrayComment(data, addr);
}
return null;
return getPreceedingComponentAutoComment(data);
}
private String[] getFlexArrayComment(Data data, Address addr) {
/**
* A composite which immediately preceeds the current address may contain trailing zero-length
* components which implicitly refer to this address and are not rendered by the opened composite.
* This comment is intended to convey the existence of such hidden components which correspond
* to addr.
* <br>
* NOTE: Implementation only provides comment for one trailing zero-length component. This could
* be improved to return a comment for all applicable trailing zero-length components.
* @param data data location whose pre-comment is currently be generated
* @return auto-comment or null
*/
private String[] getPreceedingComponentAutoComment(Data data) {
// NOTE: A zero-length composite has a length of 1 which may cause it to improperly consume
// the address location which actually corresponds to a trailing zero-length
// component.
int levelsToIgnore = 0;
String label = null;
Address prevDataAddr = data.getMinAddress().previous();
if (prevDataAddr == null) {
return null;
}
int[] cpath = data.getComponentPath();
if (cpath != null && cpath.length > 0) {
@@ -273,46 +288,60 @@ public class PreCommentFieldFactory extends FieldFactory {
}
else {
Program p = data.getProgram();
data = p.getListing().getDefinedDataContaining(addr);
if (data == null || !(data.isStructure() || data.isDynamic())) {
data = p.getListing().getDefinedDataContaining(prevDataAddr);
if (data == null || !(data.isStructure() || data.isDynamic())) { // FIXME!! refer to DynamicDataType which has components - Union?
return null;
}
Symbol s = p.getSymbolTable().getPrimarySymbol(data.getAddress());
label = s != null ? s.getName(true) : data.getDataType().getName();
}
// locate deepest structure containing addr which will be checked for flex array
DataTypeComponent lastDtc = null;
while (true) {
int offset = (int) addr.subtract(data.getMinAddress());
Data component = data.getComponentAt(offset);
if (component == null || !component.isStructure()) {
DataType dt = data.getDataType();
if (dt instanceof Structure) {
Structure struct = (Structure) dt;
lastDtc = struct.getComponentContaining(struct.getLength());
int lastDtcOrdinal = struct.getNumComponents() - 1;
while (lastDtc != null && lastDtc.isBitFieldComponent() &&
lastDtc.getOrdinal() < lastDtcOrdinal) {
lastDtc = struct.getComponent(lastDtc.getOrdinal() + 1);
}
}
else if (dt instanceof DynamicDataType) {
DynamicDataType ddt = (DynamicDataType) dt;
lastDtc = ddt.getComponentAt(data.getLength(), data);
int lastDtcOrdinal = ddt.getNumComponents(data);
while (lastDtc != null && lastDtc.isBitFieldComponent() &&
lastDtc.getOrdinal() < lastDtcOrdinal) {
lastDtc = ddt.getComponent(lastDtc.getOrdinal() + 1, data);
}
}
if (lastDtc == null || lastDtc.getLength() == 0) {
break;
}
Data component = data.getComponent(lastDtc.getOrdinal());
if (component == null) {
return null;
}
data = component;
}
return buildFlexArrayComment(data, levelsToIgnore, label);
}
private String[] buildFlexArrayComment(Data data, int levelsToIgnore, String label) {
DataType dt = data.getBaseDataType();
DataTypeComponent flexComponent = null;
if (dt instanceof Structure) {
flexComponent = ((Structure) dt).getFlexibleArrayComponent();
}
else if (dt instanceof DynamicDataType) {
flexComponent = ((DynamicDataType) dt).getFlexibleArrayComponent(data);
}
if (flexComponent == null) {
if (lastDtc == null || lastDtc.isBitFieldComponent()) {
return null;
}
return buildZeroLengthComponentAutoComment(lastDtc, data, levelsToIgnore, label);
}
String fieldName = flexComponent.getFieldName();
if (fieldName == null) {
fieldName = flexComponent.getDefaultFieldName();
private String[] buildZeroLengthComponentAutoComment(DataTypeComponent lastZeroLengthComponent, Data data, int levelsToIgnore, String label) {
String fieldName = lastZeroLengthComponent.getFieldName();
if (StringUtils.isEmpty(fieldName)) {
fieldName = lastZeroLengthComponent.getDefaultFieldName();
}
StringBuilder flexName = new StringBuilder(fieldName);
@@ -331,8 +360,8 @@ public class PreCommentFieldFactory extends FieldFactory {
flexName.insert(0, label + ".");
}
return new String[] { "Flexible Array: " + flexComponent.getDataType().getName() + "[] " +
flexName.toString() };
return new String[] { "Zero-length Component: " + lastZeroLengthComponent.getDataType().getName() + " " +
flexName.toString() };
}
private ListingTextField getTextField(String[] comments, String[] autoComment,
@@ -414,11 +414,11 @@ public class ProgramBigListingModel implements ListingModel, FormatModelListener
}
}
}
else { // Structure
else { // Structure and DynamicDataType
List<Data> dataList = data.getComponentsContaining((int) addr.subtract(dataAddr));
if (dataList != null) { // nested flex-arrays can cause odd behavior
if (dataList != null) {
for (Data subData : dataList) {
// The only case where more than one subData exists is for bit-fields.
// The only case where more than one subData exists is for bit-fields and zero-length data.
// Depending upon the packing, bit-fields at different offsets may overlap
if (subData.getMinAddress().equals(addr)) {
list.add(subData);
@@ -649,7 +649,8 @@ public class DataTypesXmlMgr {
private void writerMember(XmlWriter writer, DataTypeComponent member) {
XmlAttributes attrs = new XmlAttributes();
// TODO: how should we output bitfields (packed/non-packed) and flex array
// TODO: how should we output bitfields (packed/non-packed)
// TODO: multiple components at same offset (e.g., zero-length arrays) could throw-off IDA XML import
attrs.addAttribute("OFFSET", member.getOffset(), true);
attrs.addAttribute("DATATYPE", member.getDataType().getDisplayName());
attrs.addAttribute("DATATYPE_NAMESPACE", member.getDataType().getCategoryPath().getPath());
@@ -1032,7 +1032,7 @@ public class CodeUnitFormat {
DataType dataType = data.getDataType();
int length = data.getLength();
if (length < dataType.getLength()) {
if ((length != 0 || !dataType.isZeroLength()) && dataType.getLength() > length) {
representationList.add("Data type \"" + dataType.getDisplayName() +
"\" is too big for available space. Size = " + dataType.getLength() +
" bytes, available = " + length + " bytes");
@@ -882,22 +882,6 @@ public class ProgramDiffDetails {
for (int index2 = i; index2 < compDt2.length; index2++) {
getComponentInfo(compDt2[index2], buf2, newIndent);
}
if (dt1 instanceof Structure) {
// dt2 is also Structure - check for flex array component
DataTypeComponent flexDtc1 = ((Structure) dt1).getFlexibleArrayComponent();
DataTypeComponent flexDtc2 = ((Structure) dt2).getFlexibleArrayComponent();
if (flexDtc1 != null) {
getComponentInfo(flexDtc1, buf1, newIndent);
}
if (flexDtc2 != null) {
getComponentInfo(flexDtc2, buf2, newIndent);
}
if (flexDtc1 != null && flexDtc2 != null) {
compareSubDataTypes(flexDtc1.getDataType(), flexDtc2.getDataType(), buf1, buf2,
newIndent);
}
}
}
private void compareDataCUs(Data d1, Data d2, StringBuffer buf1, StringBuffer buf2,
@@ -926,22 +910,13 @@ public class ProgramDiffDetails {
if (fieldName == null) {
fieldName = dtc.getDefaultFieldName();
}
if (dtc.isFlexibleArrayComponent()) {
buf.append(indent + "Offset=" + DiffUtility.toSignedHexString(offset) + " " +
"Ordinal=" + ordinal + " " + fieldName + " " +
actualDt.getMnemonic(actualDt.getDefaultSettings()) + "[]" + " " +
getCategoryName(actualDt) + " " + "DataTypeSize=" + actualDt.getLength() +
" (flexible array) " + ((comment != null) ? comment : "") + " " + newLine);
}
else {
// TODO: how should we display bitfields?
buf.append(indent + "Offset=" + DiffUtility.toSignedHexString(offset) + " " +
"Ordinal=" + ordinal + " " + fieldName + " " +
actualDt.getMnemonic(actualDt.getDefaultSettings()) + " " +
getCategoryName(actualDt) + " " + "DataTypeSize=" + actualDt.getLength() + " " +
"ComponentSize=" + dtc.getLength() + " " + ((comment != null) ? comment : "") +
" " + newLine);
}
// TODO: how should we display bitfields?
buf.append(indent + "Offset=" + DiffUtility.toSignedHexString(offset) + " " + "Ordinal=" +
ordinal + " " + fieldName + " " + actualDt.getMnemonic(actualDt.getDefaultSettings()) +
" " + getCategoryName(actualDt) + " " + "DataTypeSize=" +
(actualDt.isZeroLength() ? 0 : actualDt.getLength()) + " " + "ComponentSize=" +
dtc.getLength() + " " + ((comment != null) ? comment : "") +
" " + newLine);
return actualDt;
}
@@ -983,18 +958,17 @@ public class ProgramDiffDetails {
Data data = (Data) cu;
DataType dt = data.getDataType();
if (dt instanceof Composite) {
DataTypeComponent[] compDt = ((Composite) dt).getComponents();
for (DataTypeComponent element : compDt) {
int offset = element.getOffset();
String comment = element.getComment();
String fieldName = element.getFieldName();
DataTypeComponent[] components = ((Composite) dt).getComponents();
for (DataTypeComponent dtc : components) {
int offset = dtc.getOffset();
String comment = dtc.getComment();
String fieldName = dtc.getFieldName();
if (fieldName == null) {
fieldName = "field" + offset;
}
buf.append(newIndent + min.add(offset) + " " + element.getFieldName() +
" " + element.getDataType().getName() + " " + "length=" +
element.getLength() + " " +
buf.append(newIndent + min.add(offset) + " " + dtc.getFieldName() + " " +
dtc.getDataType().getName() + " " + "length=" +
dtc.getLength() + " " +
((comment != null) ? comment : "") + " " + newLine);
}
}
@@ -573,9 +573,16 @@ public class DataTypeParser {
ArraySpecPiece(String piece) throws InvalidDataTypeException {
if (piece.startsWith("[") && piece.endsWith("]")) {
String elementCountStr = piece.substring(1, piece.length() - 1);
try {
elementCount = parseSize(elementCountStr);
String elementCountStr = piece.substring(1, piece.length() - 1);
if (elementCountStr.length() == 0) {
// treat empty array spec same as 0
// consumer may need to handle resulting array as a pointer (e.g., parameter)
elementCount = 0;
}
else {
elementCount = parseSize(elementCountStr);
}
return;
}
catch (NumberFormatException e) {
@@ -1968,14 +1968,7 @@ Declaration DirectDeclarator(Declaration dt, DataType container) : {
for (Iterator iterator = list.iterator(); iterator.hasNext();) {
Integer iSize = (Integer) iterator.next();
DataType decDt = dec.getDataType();
if (iSize == 0 && container != null) {
dec.setFlexArray(true);
break;
} else if (iSize == 0) {
dec.setDataType(dtMgr.getPointer(decDt));
} else {
dec.setDataType(new ArrayDataType(decDt, iSize, decDt.getLength()));
}
dec.setDataType(new ArrayDataType(decDt, iSize, decDt.getLength()));
}
//System.out.println("Array expr: for " + dec.getName() + " make an array " + dt.getName() + "["+size+"]");
}
@@ -27,7 +27,7 @@ import ghidra.program.database.ProgramModifierListener;
import ghidra.program.model.data.*;
import ghidra.util.InvalidNameException;
import ghidra.util.exception.DuplicateNameException;
import ghidra.util.task.TaskMonitorAdapter;
import ghidra.util.task.TaskMonitor;
/**
* Tests for merging data types.
@@ -66,12 +66,11 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
struct.insertBitFieldAt(3, 2, 6, td, 2, "bf1", null);
struct.insertBitFieldAt(3, 2, 4, td, 2, "bf2", null);
struct.add(new QWordDataType());
struct.setFlexibleArrayComponent(td, "flex", "my flex");
struct.add(new ArrayDataType(td, 0, -1), 0, "flex", "my flex");
structRef.set(struct);
c.removeCategory("Category5", TaskMonitorAdapter.DUMMY);
c.removeCategory("Category5", TaskMonitor.DUMMY);
Category c5 = c.createCategory("Category5");
c5.addDataType(struct, DataTypeConflictHandler.DEFAULT_HANDLER);
commit = true;
@@ -187,7 +186,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
Category c = dtm.getCategory(new CategoryPath("/Category1/Category2/Category3"));
try {
Structure s = (Structure) c.getDataType("IntStruct");
c.remove(s, TaskMonitorAdapter.DUMMY);
c.remove(s, TaskMonitor.DUMMY);
s = new StructureDataType(c.getCategoryPath(), "IntStruct", 0, dtm);
s.add(new QWordDataType(), "f1", "my f1");
s.add(new FloatDataType());
@@ -220,7 +219,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
Structure s = (Structure) dt;
assertEquals("my f1", s.getComponent(0).getComment());
DataTypeComponent dtc = s.getComponentAt(17);
DataTypeComponent dtc = s.getComponentContaining(17);
assertEquals(7, dtc.getOrdinal());
assertEquals("my bf1", dtc.getComment());
}
@@ -243,7 +242,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
Category c = dtm.getCategory(new CategoryPath("/Category1/Category2/Category3"));
try {
Structure s = (Structure) c.getDataType("IntStruct");
c.remove(s, TaskMonitorAdapter.DUMMY);
c.remove(s, TaskMonitor.DUMMY);
s = new StructureDataType(c.getCategoryPath(), "IntStruct", 0);
s.add(new QWordDataType());
s.add(new FloatDataType());
@@ -440,7 +439,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
"IntStruct");
try {
dtm.remove(dt, TaskMonitorAdapter.DUMMY);
dtm.remove(dt, TaskMonitor.DUMMY);
commit = true;
}
finally {
@@ -479,7 +478,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
try {
DataType dt = dtm.addDataType(s, DataTypeConflictHandler.DEFAULT_HANDLER);
dtm.remove(dt, TaskMonitorAdapter.DUMMY);
dtm.remove(dt, TaskMonitor.DUMMY);
commit = true;
}
finally {
@@ -530,7 +529,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
"IntStruct");
try {
dtm.remove(dt, TaskMonitorAdapter.DUMMY);
dtm.remove(dt, TaskMonitor.DUMMY);
commit = true;
}
finally {
@@ -581,7 +580,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
"FloatStruct");
try {
dtm.remove(dt, TaskMonitorAdapter.DUMMY);
dtm.remove(dt, TaskMonitor.DUMMY);
commit = true;
}
finally {
@@ -611,7 +610,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
"IntStruct");
try {
dtm.remove(dt, TaskMonitorAdapter.DUMMY);
dtm.remove(dt, TaskMonitor.DUMMY);
commit = true;
}
finally {
@@ -659,7 +658,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion");
try {
dtm.remove(dt, TaskMonitorAdapter.DUMMY);
dtm.remove(dt, TaskMonitor.DUMMY);
commit = true;
}
finally {
@@ -715,7 +714,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
"IntStruct");
try {
dtm.remove(dt, TaskMonitorAdapter.DUMMY);
dtm.remove(dt, TaskMonitor.DUMMY);
commit = true;
}
finally {
@@ -734,7 +733,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
"IntStruct");
try {
dtm.remove(dt, TaskMonitorAdapter.DUMMY);
dtm.remove(dt, TaskMonitor.DUMMY);
commit = true;
}
finally {
@@ -963,7 +962,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
"IntStruct");
try {
dtm.remove(dt, TaskMonitorAdapter.DUMMY);
dtm.remove(dt, TaskMonitor.DUMMY);
commit = true;
}
finally {
@@ -992,7 +991,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
"IntStruct");
try {
dtm.remove(dt, TaskMonitorAdapter.DUMMY);
dtm.remove(dt, TaskMonitor.DUMMY);
commit = true;
}
finally {
@@ -1050,7 +1049,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
Structure s = (Structure) dt;
s.add(new ByteDataType());
Category parent = dtm.getCategory(new CategoryPath("/Category1/Category2"));
parent.removeCategory("Category3", TaskMonitorAdapter.DUMMY);
parent.removeCategory("Category3", TaskMonitor.DUMMY);
commit = true;
}
finally {
@@ -1116,7 +1115,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
Structure s = (Structure) dt;
s.add(new ByteDataType());
Category parent = dtm.getCategory(new CategoryPath("/Category1/Category2"));
parent.removeCategory("Category3", TaskMonitorAdapter.DUMMY);
parent.removeCategory("Category3", TaskMonitor.DUMMY);
commit = true;
}
finally {

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