mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 10:19:23 +02:00
BitFields - corrected bitfield transitions between different data
organizations and packing for unions.
This commit is contained in:
parent
486ce82586
commit
f54f68c66e
22 changed files with 352 additions and 315 deletions
|
@ -18,7 +18,6 @@ package ghidra.app.plugin.core.compositeeditor;
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
import java.awt.Window;
|
import java.awt.Window;
|
||||||
|
|
||||||
import javax.swing.JTable;
|
|
||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
|
|
||||||
import docking.ActionContext;
|
import docking.ActionContext;
|
||||||
|
@ -67,10 +66,7 @@ public class AddBitFieldAction extends CompositeEditorTableAction {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void refreshTableAndSelection(CompEditorModel editorModel, int ordinal) {
|
private void refreshTableAndSelection(CompEditorModel editorModel, int ordinal) {
|
||||||
editorModel.fireTableDataChanged();
|
editorModel.notifyCompositeChanged();
|
||||||
editorModel.compositeInfoChanged();
|
|
||||||
JTable editorTable = provider.getTable();
|
|
||||||
editorTable.getSelectionModel().setSelectionInterval(ordinal, ordinal);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -20,6 +20,7 @@ import java.awt.event.*;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
|
||||||
|
import javax.help.UnsupportedOperationException;
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
|
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.*;
|
||||||
|
@ -382,16 +383,17 @@ public class BitFieldPlacementComponent extends JPanel {
|
||||||
String name = (fieldName != null && fieldName.length() != 0) ? fieldName : null;
|
String name = (fieldName != null && fieldName.length() != 0) ? fieldName : null;
|
||||||
DataTypeComponent dtc;
|
DataTypeComponent dtc;
|
||||||
if (composite instanceof Union) {
|
if (composite instanceof Union) {
|
||||||
dtc = composite.insertBitField(ordinal, allocationByteSize,
|
throw new UnsupportedOperationException(
|
||||||
bitFieldAllocation.bitOffset, baseDataType, bitFieldAllocation.bitSize, name,
|
"Union modification not currently supported");
|
||||||
null);
|
// dtc = composite.insertBitField(ordinal, allocationByteSize,
|
||||||
}
|
// bitFieldAllocation.bitOffset, baseDataType, bitFieldAllocation.bitSize, name,
|
||||||
else {
|
// null);
|
||||||
Structure struct = (Structure) composite;
|
|
||||||
dtc = struct.insertBitFieldAt(allocationByteOffset, allocationByteSize,
|
|
||||||
bitFieldAllocation.bitOffset, baseDataType, bitFieldAllocation.bitSize, name,
|
|
||||||
null);
|
|
||||||
}
|
}
|
||||||
|
// else {
|
||||||
|
Structure struct = (Structure) composite;
|
||||||
|
dtc = struct.insertBitFieldAt(allocationByteOffset, allocationByteSize,
|
||||||
|
bitFieldAllocation.bitOffset, baseDataType, bitFieldAllocation.bitSize, name, null);
|
||||||
|
// }
|
||||||
if (listener != null) {
|
if (listener != null) {
|
||||||
listener.componentChanged(dtc.getOrdinal());
|
listener.componentChanged(dtc.getOrdinal());
|
||||||
}
|
}
|
||||||
|
@ -484,9 +486,22 @@ public class BitFieldPlacementComponent extends JPanel {
|
||||||
if (tip == null) {
|
if (tip == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
String conflictMsg = "";
|
||||||
|
DataTypeComponent conflict = attrs.getConflict();
|
||||||
|
if (conflict != null) {
|
||||||
|
if (tip.length() != 0) {
|
||||||
|
conflictMsg = "<br>";
|
||||||
|
}
|
||||||
|
String conflictName = conflict.getFieldName();
|
||||||
|
String conflictTip = "'" + conflict.getDataType().getDisplayName() +
|
||||||
|
(conflictName != null ? (" " + conflictName) : "") + "' at offset " +
|
||||||
|
conflict.getOffset();
|
||||||
|
conflictMsg += "<div style=\"color: red;font-style: italic\">conflict with " +
|
||||||
|
HTMLUtilities.escapeHTML(conflictTip) + "</div>";
|
||||||
|
}
|
||||||
return "<HTML><div style=\"text-align:center\">" + HTMLUtilities.escapeHTML(tip) +
|
return "<HTML><div style=\"text-align:center\">" + HTMLUtilities.escapeHTML(tip) +
|
||||||
|
conflictMsg +
|
||||||
"<div style=\"color: gray;font-style: italic\">(Shift-wheel to zoom)</div></div></HTML>";
|
"<div style=\"color: gray;font-style: italic\">(Shift-wheel to zoom)</div></div></HTML>";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1050,8 +1065,7 @@ public class BitFieldPlacementComponent extends JPanel {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
String name = dtc.getFieldName();
|
String name = dtc.getFieldName();
|
||||||
return dtc.getDataType().getDisplayName() +
|
return dtc.getDataType().getDisplayName() + (name != null ? (" " + name) : "");
|
||||||
(name != null ? (" " + dtc.getFieldName()) : "");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DataTypeComponent getDataTypeComponent(boolean ignoreActiveComponent) {
|
DataTypeComponent getDataTypeComponent(boolean ignoreActiveComponent) {
|
||||||
|
|
|
@ -147,7 +147,7 @@ public class UnionDataTypeTest extends AbstractGTest {
|
||||||
union.delete(0);
|
union.delete(0);
|
||||||
}
|
}
|
||||||
// NOTE: bitOffset ignored for union
|
// NOTE: bitOffset ignored for union
|
||||||
union.insertBitField(0, 4, 12, IntegerDataType.dataType, 2, "bf1", "bf1Comment");
|
union.insertBitField(0, IntegerDataType.dataType, 2, "bf1", "bf1Comment");
|
||||||
union.insert(0, ShortDataType.dataType);
|
union.insert(0, ShortDataType.dataType);
|
||||||
|
|
||||||
//@formatter:off
|
//@formatter:off
|
||||||
|
@ -168,7 +168,7 @@ public class UnionDataTypeTest extends AbstractGTest {
|
||||||
for (int i = 0; i < cnt; i++) {
|
for (int i = 0; i < cnt; i++) {
|
||||||
union.delete(0);
|
union.delete(0);
|
||||||
}
|
}
|
||||||
union.insertBitField(0, 4, 12, IntegerDataType.dataType, 2, "bf1", "bf1Comment");
|
union.insertBitField(0, IntegerDataType.dataType, 2, "bf1", "bf1Comment");
|
||||||
union.insert(0, ShortDataType.dataType);
|
union.insert(0, ShortDataType.dataType);
|
||||||
union.setInternallyAligned(true);
|
union.setInternallyAligned(true);
|
||||||
|
|
||||||
|
@ -186,8 +186,8 @@ public class UnionDataTypeTest extends AbstractGTest {
|
||||||
@Test
|
@Test
|
||||||
public void testInsertBitFieldLittleEndian() throws Exception {
|
public void testInsertBitFieldLittleEndian() throws Exception {
|
||||||
|
|
||||||
union.insertBitField(2, 4, 0, IntegerDataType.dataType, 4, "bf1", "bf1Comment");
|
union.insertBitField(2, IntegerDataType.dataType, 4, "bf1", "bf1Comment");
|
||||||
union.insertBitField(3, 1, 0, ByteDataType.dataType, 4, "bf2", "bf2Comment");
|
union.insertBitField(3, ByteDataType.dataType, 4, "bf2", "bf2Comment");
|
||||||
|
|
||||||
//@formatter:off
|
//@formatter:off
|
||||||
CompositeTestUtils.assertExpectedComposite(this, "/TestUnion\n" +
|
CompositeTestUtils.assertExpectedComposite(this, "/TestUnion\n" +
|
||||||
|
@ -209,8 +209,8 @@ public class UnionDataTypeTest extends AbstractGTest {
|
||||||
|
|
||||||
transitionToBigEndian();
|
transitionToBigEndian();
|
||||||
|
|
||||||
union.insertBitField(2, 4, 0, IntegerDataType.dataType, 4, "bf1", "bf1Comment");
|
union.insertBitField(2, IntegerDataType.dataType, 4, "bf1", "bf1Comment");
|
||||||
union.insertBitField(3, 1, 0, ByteDataType.dataType, 4, "bf2", "bf2Comment");
|
union.insertBitField(3, ByteDataType.dataType, 4, "bf2", "bf2Comment");
|
||||||
|
|
||||||
//@formatter:off
|
//@formatter:off
|
||||||
CompositeTestUtils.assertExpectedComposite(this, "/TestUnion\n" +
|
CompositeTestUtils.assertExpectedComposite(this, "/TestUnion\n" +
|
||||||
|
|
|
@ -42,8 +42,8 @@ public class UnionImplBigEndianBitFieldTest extends AbstractCompositeImplBitFiel
|
||||||
CompositeTestUtils.assertExpectedComposite(this, "/U1\n" +
|
CompositeTestUtils.assertExpectedComposite(this, "/U1\n" +
|
||||||
"Aligned\n" +
|
"Aligned\n" +
|
||||||
"Union U1 {\n" +
|
"Union U1 {\n" +
|
||||||
" 0 int:4(0) 1 a \"\"\n" +
|
" 0 int:4(4) 1 a \"\"\n" +
|
||||||
" 0 int:2(0) 1 b \"\"\n" +
|
" 0 int:2(6) 1 b \"\"\n" +
|
||||||
"}\n" +
|
"}\n" +
|
||||||
"Size = 4 Actual Alignment = 4", struct);
|
"Size = 4 Actual Alignment = 4", struct);
|
||||||
//@formatter:on
|
//@formatter:on
|
||||||
|
@ -56,9 +56,9 @@ public class UnionImplBigEndianBitFieldTest extends AbstractCompositeImplBitFiel
|
||||||
CompositeTestUtils.assertExpectedComposite(this, "/U1z\n" +
|
CompositeTestUtils.assertExpectedComposite(this, "/U1z\n" +
|
||||||
"Aligned\n" +
|
"Aligned\n" +
|
||||||
"Union U1z {\n" +
|
"Union U1z {\n" +
|
||||||
" 0 int:4(0) 1 a \"\"\n" +
|
" 0 int:4(4) 1 a \"\"\n" +
|
||||||
" 0 longlong:0(0) 1 \"\"\n" + // has no impact
|
" 0 longlong:0(7) 1 \"\"\n" + // has no impact
|
||||||
" 0 int:2(0) 1 b \"\"\n" +
|
" 0 int:2(6) 1 b \"\"\n" +
|
||||||
"}\n" +
|
"}\n" +
|
||||||
"Size = 4 Actual Alignment = 4", struct);
|
"Size = 4 Actual Alignment = 4", struct);
|
||||||
//@formatter:on
|
//@formatter:on
|
||||||
|
@ -71,8 +71,8 @@ public class UnionImplBigEndianBitFieldTest extends AbstractCompositeImplBitFiel
|
||||||
CompositeTestUtils.assertExpectedComposite(this, "/U1p1\n" +
|
CompositeTestUtils.assertExpectedComposite(this, "/U1p1\n" +
|
||||||
"Aligned pack(1)\n" +
|
"Aligned pack(1)\n" +
|
||||||
"Union U1p1 {\n" +
|
"Union U1p1 {\n" +
|
||||||
" 0 int:4(0) 1 a \"\"\n" +
|
" 0 int:4(4) 1 a \"\"\n" +
|
||||||
" 0 int:2(0) 1 b \"\"\n" +
|
" 0 int:2(6) 1 b \"\"\n" +
|
||||||
"}\n" +
|
"}\n" +
|
||||||
"Size = 1 Actual Alignment = 1", struct);
|
"Size = 1 Actual Alignment = 1", struct);
|
||||||
//@formatter:on
|
//@formatter:on
|
||||||
|
@ -85,9 +85,9 @@ public class UnionImplBigEndianBitFieldTest extends AbstractCompositeImplBitFiel
|
||||||
CompositeTestUtils.assertExpectedComposite(this, "/U1p1z\n" +
|
CompositeTestUtils.assertExpectedComposite(this, "/U1p1z\n" +
|
||||||
"Aligned pack(1)\n" +
|
"Aligned pack(1)\n" +
|
||||||
"Union U1p1z {\n" +
|
"Union U1p1z {\n" +
|
||||||
" 0 int:4(0) 1 a \"\"\n" +
|
" 0 int:4(4) 1 a \"\"\n" +
|
||||||
" 0 longlong:0(0) 1 \"\"\n" + // has no impact
|
" 0 longlong:0(7) 1 \"\"\n" + // has no impact
|
||||||
" 0 int:2(0) 1 b \"\"\n" +
|
" 0 int:2(6) 1 b \"\"\n" +
|
||||||
"}\n" +
|
"}\n" +
|
||||||
"Size = 1 Actual Alignment = 1", struct);
|
"Size = 1 Actual Alignment = 1", struct);
|
||||||
//@formatter:on
|
//@formatter:on
|
||||||
|
@ -100,8 +100,8 @@ public class UnionImplBigEndianBitFieldTest extends AbstractCompositeImplBitFiel
|
||||||
CompositeTestUtils.assertExpectedComposite(this, "/U1p2\n" +
|
CompositeTestUtils.assertExpectedComposite(this, "/U1p2\n" +
|
||||||
"Aligned pack(2)\n" +
|
"Aligned pack(2)\n" +
|
||||||
"Union U1p2 {\n" +
|
"Union U1p2 {\n" +
|
||||||
" 0 int:4(0) 1 a \"\"\n" +
|
" 0 int:4(4) 1 a \"\"\n" +
|
||||||
" 0 int:2(0) 1 b \"\"\n" +
|
" 0 int:2(6) 1 b \"\"\n" +
|
||||||
"}\n" +
|
"}\n" +
|
||||||
"Size = 2 Actual Alignment = 2", struct);
|
"Size = 2 Actual Alignment = 2", struct);
|
||||||
//@formatter:on
|
//@formatter:on
|
||||||
|
|
|
@ -38,7 +38,7 @@ class PdbBitField extends BitFieldDataType {
|
||||||
protected PdbBitField(DataType baseDataType, int bitSize, int bitOffsetWithinBaseType)
|
protected PdbBitField(DataType baseDataType, int bitSize, int bitOffsetWithinBaseType)
|
||||||
throws InvalidDataTypeException {
|
throws InvalidDataTypeException {
|
||||||
super(baseDataType, bitSize,
|
super(baseDataType, bitSize,
|
||||||
getMinimalBitOffset(baseDataType, bitSize, bitOffsetWithinBaseType), 0);
|
getMinimalBitOffset(baseDataType, bitSize, bitOffsetWithinBaseType));
|
||||||
if (bitSize < 1) {
|
if (bitSize < 1) {
|
||||||
throw new InvalidDataTypeException("invalid PDB bit size: " + bitSize);
|
throw new InvalidDataTypeException("invalid PDB bit size: " + bitSize);
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ class BitFieldDBDataType extends BitFieldDataType {
|
||||||
// BB - Encoded base type (8-bits, consists of the following bit fields: xttsbbbb)
|
// BB - Encoded base type (8-bits, consists of the following bit fields: xttsbbbb)
|
||||||
// x - 1-bit, unused
|
// x - 1-bit, unused
|
||||||
// t - 2-bit, =0: base type only, =1:TypeDef used, =2: enum used, =3: abstract-int
|
// t - 2-bit, =0: base type only, =1:TypeDef used, =2: enum used, =3: abstract-int
|
||||||
// s - 1-bit, storage +1
|
// s - 1-bit, storage +1 (NOT-USED! - may be re-purposed by future schema change)
|
||||||
// xxxx - 4-bits, unused
|
// xxxx - 4-bits, unused
|
||||||
// OO - bit offset (i.e., right-shift factor, relative to packing base type)
|
// OO - bit offset (i.e., right-shift factor, relative to packing base type)
|
||||||
// SS - bit field size in bits
|
// SS - bit field size in bits
|
||||||
|
@ -47,10 +47,21 @@ class BitFieldDBDataType extends BitFieldDataType {
|
||||||
|
|
||||||
private static final long ID_TO_INDEX_MASK = ~-(1L << DataTypeManagerDB.DATA_TYPE_KIND_SHIFT);
|
private static final long ID_TO_INDEX_MASK = ~-(1L << DataTypeManagerDB.DATA_TYPE_KIND_SHIFT);
|
||||||
|
|
||||||
BitFieldDBDataType(DataType baseDataType, int bitSize, int bitOffset, int storageSize,
|
/**
|
||||||
DataTypeManager dtm) throws InvalidDataTypeException {
|
* Construct DB resident bitfield. Minimal storage size and effective bit size will
|
||||||
// avoid clone of baseDataType during construction
|
* be computed based upon specified parameters.
|
||||||
super(baseDataType, bitSize, bitOffset, storageSize);
|
* @param baseDataType base data type (integer/enum type or typedef to same). This
|
||||||
|
* bitfield will adopt the same datatype manager as this base type.
|
||||||
|
* @param bitSize size of bit-field expressed as number of bits (0..255). The effective
|
||||||
|
* bit size may be reduced based upon the specified base datatype size.
|
||||||
|
* @param bitOffset right shift factor within storage unit when viewed as a big-endian dd
|
||||||
|
* scalar value. Based upon minimal storage bitOffset should be in the range 0 to 7.
|
||||||
|
* @throws InvalidDataTypeException
|
||||||
|
*/
|
||||||
|
BitFieldDBDataType(DataType baseDataType, int bitSize, int bitOffset)
|
||||||
|
throws InvalidDataTypeException {
|
||||||
|
// must avoid cloning of baseDataType during construction!
|
||||||
|
super(baseDataType, bitSize, bitOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static enum BaseDatatypeKind {
|
private static enum BaseDatatypeKind {
|
||||||
|
@ -137,14 +148,14 @@ class BitFieldDBDataType extends BitFieldDataType {
|
||||||
* @param dtm data type manager
|
* @param dtm data type manager
|
||||||
* @return bit-field data type
|
* @return bit-field data type
|
||||||
*/
|
*/
|
||||||
static final BitFieldDataType getBitFieldDataType(long id, DataTypeManager dtm) {
|
static final BitFieldDataType getBitFieldDataType(long id, DataTypeManagerDB dtm) {
|
||||||
|
|
||||||
int bitSize = (int) (id & 0xff); // 8-bits
|
int bitSize = (int) (id & 0xff); // 8-bits
|
||||||
int bitOffset = (int) ((id >> BIT_OFFSET_SHIFT) & 0xff); // 8-bits
|
int bitOffset = (int) ((id >> BIT_OFFSET_SHIFT) & 0xff); // 8-bits
|
||||||
int baseTypeInfo = (int) ((id >> BASE_TYPE_SHIFT) & 0xff); // 8-bit encoded field
|
int baseTypeInfo = (int) ((id >> BASE_TYPE_SHIFT) & 0xff); // 8-bit encoded field
|
||||||
|
|
||||||
BaseDatatypeKind baseDataTypeKind = BaseDatatypeKind.getKind((baseTypeInfo >> 5) & 3);
|
BaseDatatypeKind baseDataTypeKind = BaseDatatypeKind.getKind((baseTypeInfo >> 5) & 3);
|
||||||
boolean extraStorageUsed = (baseTypeInfo & 0x10) != 0;
|
// boolean extraStorageUsed = (baseTypeInfo & 0x10) != 0;
|
||||||
|
|
||||||
DataType baseDataType = null;
|
DataType baseDataType = null;
|
||||||
long dataTypeIndex = (id >> DATATYPE_INDEX_SHIFT) & MAX_DATATYPE_INDEX; // 32-bits
|
long dataTypeIndex = (id >> DATATYPE_INDEX_SHIFT) & MAX_DATATYPE_INDEX; // 32-bits
|
||||||
|
@ -164,12 +175,12 @@ class BitFieldDBDataType extends BitFieldDataType {
|
||||||
// use integer datatype on failure
|
// use integer datatype on failure
|
||||||
baseDataType = IntegerDataType.dataType.clone(dtm);
|
baseDataType = IntegerDataType.dataType.clone(dtm);
|
||||||
}
|
}
|
||||||
int effectiveBitSize = getEffectiveBitSize(bitSize, baseDataType.getLength());
|
// int effectiveBitSize = getEffectiveBitSize(bitSize, baseDataType.getLength());
|
||||||
int storageSize = getMinimumStorageSize(effectiveBitSize);
|
// int storageSize = getMinimumStorageSize(effectiveBitSize);
|
||||||
if (extraStorageUsed) {
|
// if (extraStorageUsed) {
|
||||||
++storageSize;
|
// ++storageSize;
|
||||||
}
|
// }
|
||||||
return new BitFieldDBDataType(baseDataType, bitSize, bitOffset, storageSize, dtm);
|
return new BitFieldDBDataType(baseDataType, bitSize, bitOffset);
|
||||||
}
|
}
|
||||||
catch (InvalidDataTypeException e) {
|
catch (InvalidDataTypeException e) {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -104,13 +104,6 @@ abstract class CompositeDB extends DataTypeDB implements Composite {
|
||||||
return record.getLongValue(CompositeDBAdapter.COMPOSITE_CAT_COL);
|
return record.getLongValue(CompositeDBAdapter.COMPOSITE_CAT_COL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public DataTypeComponent addBitField(DataType baseDataType, int bitSize, String componentName,
|
|
||||||
String comment) throws InvalidDataTypeException {
|
|
||||||
BitFieldDataType bitFieldDt = new BitFieldDBDataType(baseDataType, bitSize, 0, 0, dataMgr);
|
|
||||||
return add(bitFieldDt, bitFieldDt.getStorageSize(), componentName, comment);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle replacement of datatype which may impact bitfield datatype.
|
* Handle replacement of datatype which may impact bitfield datatype.
|
||||||
* @param bitfieldComponent bitfield component
|
* @param bitfieldComponent bitfield component
|
||||||
|
@ -140,9 +133,8 @@ abstract class CompositeDB extends DataTypeDB implements Composite {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
BitFieldDBDataType newBitfieldDt =
|
BitFieldDBDataType newBitfieldDt = new BitFieldDBDataType(newDt,
|
||||||
new BitFieldDBDataType(newDt, bitfieldDt.getDeclaredBitSize(),
|
bitfieldDt.getDeclaredBitSize(), bitfieldDt.getBitOffset());
|
||||||
bitfieldDt.getBitOffset(), bitfieldDt.getStorageSize(), dataMgr);
|
|
||||||
bitfieldComponent.setDataType(newBitfieldDt);
|
bitfieldComponent.setDataType(newBitfieldDt);
|
||||||
oldDt.removeParent(this);
|
oldDt.removeParent(this);
|
||||||
newDt.addParent(this);
|
newDt.addParent(this);
|
||||||
|
|
|
@ -790,7 +790,7 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
||||||
storageSize = baseLength;
|
storageSize = baseLength;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
return new BitFieldDBDataType(resolvedBaseDt, bitSize, bitOffset, storageSize, this);
|
return new BitFieldDBDataType(resolvedBaseDt, bitSize, bitOffset);
|
||||||
}
|
}
|
||||||
catch (InvalidDataTypeException e) {
|
catch (InvalidDataTypeException e) {
|
||||||
throw new AssertException("unexpected", e);
|
throw new AssertException("unexpected", e);
|
||||||
|
|
|
@ -276,6 +276,17 @@ class StructureDB extends CompositeDB implements Structure {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataTypeComponent addBitField(DataType baseDataType, int bitSize, String componentName,
|
||||||
|
String comment) throws InvalidDataTypeException {
|
||||||
|
|
||||||
|
BitFieldDataType.checkBaseDataType(baseDataType);
|
||||||
|
baseDataType = baseDataType.clone(getDataTypeManager());
|
||||||
|
|
||||||
|
BitFieldDataType bitFieldDt = new BitFieldDBDataType(baseDataType, bitSize, 0);
|
||||||
|
return add(bitFieldDt, componentName, comment);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DataTypeComponent insertBitField(int ordinal, int byteWidth, int bitOffset,
|
public DataTypeComponent insertBitField(int ordinal, int byteWidth, int bitOffset,
|
||||||
DataType baseDataType, int bitSize, String componentName, String comment)
|
DataType baseDataType, int bitSize, String componentName, String comment)
|
||||||
|
@ -298,8 +309,7 @@ class StructureDB extends CompositeDB implements Structure {
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle aligned bitfield insertion
|
// handle aligned bitfield insertion
|
||||||
BitFieldDataType bitFieldDt =
|
BitFieldDataType bitFieldDt = new BitFieldDBDataType(baseDataType, bitSize, 0);
|
||||||
new BitFieldDBDataType(baseDataType, bitSize, 0, 0, dataMgr);
|
|
||||||
return insert(ordinal, bitFieldDt, bitFieldDt.getStorageSize(), componentName, comment);
|
return insert(ordinal, bitFieldDt, bitFieldDt.getStorageSize(), componentName, comment);
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
|
@ -315,7 +325,7 @@ class StructureDB extends CompositeDB implements Structure {
|
||||||
try {
|
try {
|
||||||
checkDeleted();
|
checkDeleted();
|
||||||
BitFieldDataType.checkBaseDataType(baseDataType);
|
BitFieldDataType.checkBaseDataType(baseDataType);
|
||||||
baseDataType = baseDataType.clone(getDataTypeManager());
|
baseDataType = baseDataType.clone(dataMgr);
|
||||||
|
|
||||||
if (byteOffset < 0 || bitSize < 0) {
|
if (byteOffset < 0 || bitSize < 0) {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
|
@ -405,11 +415,8 @@ class StructureDB extends CompositeDB implements Structure {
|
||||||
structLength = requiredLength;
|
structLength = requiredLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
// use minimal storage
|
// adjust for minimal storage use
|
||||||
int storageBitOffset = bitOffset % 8;
|
int storageBitOffset = bitOffset % 8;
|
||||||
int storageSize =
|
|
||||||
BitFieldDataType.getMinimumStorageSize(effectiveBitSize + storageBitOffset);
|
|
||||||
|
|
||||||
int revisedOffset;
|
int revisedOffset;
|
||||||
if (bigEndian) {
|
if (bigEndian) {
|
||||||
revisedOffset = byteOffset + byteWidth - ((effectiveBitSize + bitOffset + 7) / 8);
|
revisedOffset = byteOffset + byteWidth - ((effectiveBitSize + bitOffset + 7) / 8);
|
||||||
|
@ -418,11 +425,11 @@ class StructureDB extends CompositeDB implements Structure {
|
||||||
revisedOffset = byteOffset + (bitOffset / 8);
|
revisedOffset = byteOffset + (bitOffset / 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
BitFieldDataType bitfieldDt = new BitFieldDBDataType(baseDataType, bitSize,
|
BitFieldDataType bitfieldDt =
|
||||||
storageBitOffset, storageSize, getDataTypeManager());
|
new BitFieldDBDataType(baseDataType, bitSize, storageBitOffset);
|
||||||
|
|
||||||
Record rec = componentAdapter.createRecord(dataMgr.getResolvedID(bitfieldDt), key,
|
Record rec = componentAdapter.createRecord(dataMgr.getResolvedID(bitfieldDt), key,
|
||||||
storageSize, ordinal, revisedOffset, componentName, comment);
|
bitfieldDt.getStorageSize(), ordinal, revisedOffset, componentName, comment);
|
||||||
DataTypeComponentDB dtc = new DataTypeComponentDB(dataMgr, componentAdapter, this, rec);
|
DataTypeComponentDB dtc = new DataTypeComponentDB(dataMgr, componentAdapter, this, rec);
|
||||||
bitfieldDt.addParent(this); // has no affect
|
bitfieldDt.addParent(this); // has no affect
|
||||||
components.add(startIndex, dtc);
|
components.add(startIndex, dtc);
|
||||||
|
@ -1513,13 +1520,13 @@ class StructureDB extends CompositeDB implements Structure {
|
||||||
try {
|
try {
|
||||||
validateDataType(replacementDt);
|
validateDataType(replacementDt);
|
||||||
if (!(replacementDt instanceof DataTypeDB) ||
|
if (!(replacementDt instanceof DataTypeDB) ||
|
||||||
(replacementDt.getDataTypeManager() != getDataTypeManager())) {
|
(replacementDt.getDataTypeManager() != dataMgr)) {
|
||||||
replacementDt = resolve(replacementDt);
|
replacementDt = resolve(replacementDt);
|
||||||
}
|
}
|
||||||
checkAncestry(replacementDt);
|
checkAncestry(replacementDt);
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
// TODO: should we use Undefined instead to avoid cases where
|
// TODO: should we use Undefined1 instead to avoid cases where
|
||||||
// DEFAULT datatype can not be used (flex array, bitfield, aligned structure)
|
// DEFAULT datatype can not be used (flex array, bitfield, aligned structure)
|
||||||
// TODO: failing silently is rather hidden
|
// TODO: failing silently is rather hidden
|
||||||
replacementDt = DataType.DEFAULT;
|
replacementDt = DataType.DEFAULT;
|
||||||
|
|
|
@ -121,6 +121,8 @@ class UnionDB extends CompositeDB implements Union {
|
||||||
|
|
||||||
validateDataType(dataType);
|
validateDataType(dataType);
|
||||||
|
|
||||||
|
dataType = adjustBitField(dataType);
|
||||||
|
|
||||||
dataType = resolve(dataType);
|
dataType = resolve(dataType);
|
||||||
checkAncestry(dataType);
|
checkAncestry(dataType);
|
||||||
|
|
||||||
|
@ -165,6 +167,8 @@ class UnionDB extends CompositeDB implements Union {
|
||||||
checkDeleted();
|
checkDeleted();
|
||||||
validateDataType(dataType);
|
validateDataType(dataType);
|
||||||
|
|
||||||
|
dataType = adjustBitField(dataType);
|
||||||
|
|
||||||
dataType = resolve(dataType);
|
dataType = resolve(dataType);
|
||||||
checkAncestry(dataType);
|
checkAncestry(dataType);
|
||||||
|
|
||||||
|
@ -185,53 +189,22 @@ class UnionDB extends CompositeDB implements Union {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DataTypeComponent insertBitField(int ordinal, int byteWidth, int bitOffset,
|
public DataTypeComponent addBitField(DataType baseDataType, int bitSize, String componentName,
|
||||||
DataType baseDataType, int bitSize, String componentName, String comment)
|
String comment) throws InvalidDataTypeException {
|
||||||
|
return insertBitField(components.size(), baseDataType, bitSize, componentName, comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataTypeComponent insertBitField(int ordinal, DataType baseDataType, int bitSize,
|
||||||
|
String componentName, String comment)
|
||||||
throws InvalidDataTypeException, ArrayIndexOutOfBoundsException {
|
throws InvalidDataTypeException, ArrayIndexOutOfBoundsException {
|
||||||
|
|
||||||
if (ordinal < 0 || ordinal > components.size()) {
|
if (ordinal < 0 || ordinal > components.size()) {
|
||||||
throw new ArrayIndexOutOfBoundsException(ordinal);
|
throw new ArrayIndexOutOfBoundsException(ordinal);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isInternallyAligned()) {
|
BitFieldDataType bitFieldDt = new BitFieldDBDataType(baseDataType, bitSize, 0);
|
||||||
BitFieldDataType bitFieldDt =
|
return insert(ordinal, bitFieldDt, bitFieldDt.getStorageSize(), componentName, comment);
|
||||||
new BitFieldDBDataType(baseDataType, bitSize, 0, 0, dataMgr);
|
|
||||||
return insert(ordinal, bitFieldDt, bitFieldDt.getStorageSize(), componentName, comment);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (byteWidth <= 0) {
|
|
||||||
throw new IllegalArgumentException("Invalid byteWidth");
|
|
||||||
}
|
|
||||||
|
|
||||||
// handle unaligned case - use minimal storage
|
|
||||||
// bitfield value will be forced based upon byteWidth, bitSize and endianess
|
|
||||||
boolean bigEndian = getDataOrganization().isBigEndian();
|
|
||||||
int effectiveBitSize =
|
|
||||||
BitFieldDataType.getEffectiveBitSize(bitSize, baseDataType.getLength());
|
|
||||||
int storageSize = BitFieldDataType.getMinimumStorageSize(effectiveBitSize);
|
|
||||||
if (byteWidth < storageSize) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"Bitfield does not fit within specified constraints");
|
|
||||||
}
|
|
||||||
int storageBitOffset = 0;
|
|
||||||
if (bigEndian) {
|
|
||||||
storageBitOffset = (8 * storageSize) - effectiveBitSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
BitFieldDataType bitfieldDt = new BitFieldDBDataType(baseDataType, bitSize,
|
|
||||||
storageBitOffset, storageSize, getDataTypeManager());
|
|
||||||
|
|
||||||
DataTypeComponentDB dtc = createComponent(dataMgr.getResolvedID(bitfieldDt), storageSize,
|
|
||||||
ordinal, 0, componentName, comment);
|
|
||||||
|
|
||||||
bitfieldDt.addParent(this); // currently has no affect
|
|
||||||
|
|
||||||
shiftOrdinals(ordinal, 1);
|
|
||||||
components.add(ordinal, dtc);
|
|
||||||
|
|
||||||
adjustLength(true, true);
|
|
||||||
|
|
||||||
return dtc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -434,6 +407,51 @@ class UnionDB extends CompositeDB implements Union {
|
||||||
adjustInternalAlignment(true);
|
adjustInternalAlignment(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private DataType adjustBitField(DataType dataType) {
|
||||||
|
|
||||||
|
if (!(dataType instanceof BitFieldDataType)) {
|
||||||
|
return dataType;
|
||||||
|
}
|
||||||
|
|
||||||
|
BitFieldDataType bitfieldDt = (BitFieldDataType) dataType;
|
||||||
|
|
||||||
|
DataType baseDataType = bitfieldDt.getBaseDataType();
|
||||||
|
baseDataType = resolve(baseDataType);
|
||||||
|
|
||||||
|
// Both aligned and unaligned bitfields use same adjustment
|
||||||
|
// unaligned must force bitfield placement at byte offset 0
|
||||||
|
int bitSize = bitfieldDt.getDeclaredBitSize();
|
||||||
|
int effectiveBitSize =
|
||||||
|
BitFieldDataType.getEffectiveBitSize(bitSize, baseDataType.getLength());
|
||||||
|
|
||||||
|
// little-endian always uses bit offset of 0 while
|
||||||
|
// big-endian offset must be computed
|
||||||
|
boolean bigEndian = getDataOrganization().isBigEndian();
|
||||||
|
int storageBitOffset = 0;
|
||||||
|
if (bigEndian) {
|
||||||
|
if (bitSize == 0) {
|
||||||
|
storageBitOffset = 7;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
int storageSize = BitFieldDataType.getMinimumStorageSize(effectiveBitSize);
|
||||||
|
storageBitOffset = (8 * storageSize) - effectiveBitSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (effectiveBitSize != bitfieldDt.getBitSize() ||
|
||||||
|
storageBitOffset != bitfieldDt.getBitOffset()) {
|
||||||
|
try {
|
||||||
|
bitfieldDt =
|
||||||
|
new BitFieldDBDataType(baseDataType, effectiveBitSize, storageBitOffset);
|
||||||
|
}
|
||||||
|
catch (InvalidDataTypeException e) {
|
||||||
|
// unexpected since deriving from existing bitfield,
|
||||||
|
// ignore and use existing bitfield
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bitfieldDt;
|
||||||
|
}
|
||||||
|
|
||||||
private void adjustLength(boolean notify, boolean setLastChangeTime) {
|
private void adjustLength(boolean notify, boolean setLastChangeTime) {
|
||||||
lock.acquire();
|
lock.acquire();
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -202,7 +202,7 @@ public class AlignedStructurePacker {
|
||||||
zeroBitFieldDt.getStorageSize() != 1) {
|
zeroBitFieldDt.getStorageSize() != 1) {
|
||||||
try {
|
try {
|
||||||
BitFieldDataType packedBitFieldDt = new BitFieldDataType(
|
BitFieldDataType packedBitFieldDt = new BitFieldDataType(
|
||||||
zeroBitFieldDt.getBaseDataType(), 0, zeroBitOffset, 1);
|
zeroBitFieldDt.getBaseDataType(), 0, zeroBitOffset);
|
||||||
dataTypeComponent.setDataType(packedBitFieldDt);
|
dataTypeComponent.setDataType(packedBitFieldDt);
|
||||||
}
|
}
|
||||||
catch (InvalidDataTypeException e) {
|
catch (InvalidDataTypeException e) {
|
||||||
|
@ -451,12 +451,11 @@ public class AlignedStructurePacker {
|
||||||
bitOffset = bitsConsumed;
|
bitOffset = bitsConsumed;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bitOffset != currentBitFieldDt.getBitOffset() ||
|
if (bitOffset != currentBitFieldDt.getBitOffset()) {
|
||||||
byteSize != currentBitFieldDt.getStorageSize()) {
|
|
||||||
try {
|
try {
|
||||||
BitFieldDataType packedBitFieldDt =
|
BitFieldDataType packedBitFieldDt =
|
||||||
new BitFieldDataType(currentBitFieldDt.getBaseDataType(),
|
new BitFieldDataType(currentBitFieldDt.getBaseDataType(),
|
||||||
currentBitFieldDt.getDeclaredBitSize(), bitOffset, byteSize);
|
currentBitFieldDt.getDeclaredBitSize(), bitOffset);
|
||||||
dataTypeComponent.setDataType(packedBitFieldDt);
|
dataTypeComponent.setDataType(packedBitFieldDt);
|
||||||
}
|
}
|
||||||
catch (InvalidDataTypeException e) {
|
catch (InvalidDataTypeException e) {
|
||||||
|
|
|
@ -44,24 +44,23 @@ public class BitFieldDataType extends AbstractDataType {
|
||||||
// The bitOffset is established during packing and reflects the right-shift amount within the
|
// The bitOffset is established during packing and reflects the right-shift amount within the
|
||||||
// normalized big-endian view of the allocated byte storage as defined by the corresponding
|
// normalized big-endian view of the allocated byte storage as defined by the corresponding
|
||||||
// composite DataTypeComponent.
|
// composite DataTypeComponent.
|
||||||
private final int bitOffset; // indicates right-shift within big-endian view of component storage
|
private final int bitOffset; // indicates right-shift within big-endian view of component storage (range: 0..7)
|
||||||
private final int storageSize; // component storage size to which bitOffset applies
|
private final int storageSize; // minimal component storage size to which bitOffset applies
|
||||||
|
|
||||||
protected Settings defaultSettings;
|
protected Settings defaultSettings;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a bit-field type based upon a specified base type. The baseDataType will
|
* Construct a bit-field type based upon a specified base type. The baseDataType will
|
||||||
* take precedence if specified. Either baseType or baseDatatype must be specified.
|
* take precedence if specified. Either baseType or baseDatatype must be specified.
|
||||||
* @param baseDataType base data type (integer/enum type or typedef to same)
|
* @param baseDataType base data type (integer/enum type or typedef to same). This
|
||||||
* @param bitSize size of bit-field expressed as number of bits
|
* bitfield will adopt the same datatype manager as this base type.
|
||||||
|
* @param bitSize size of bit-field expressed as number of bits (0..255). The effective
|
||||||
|
* bit size may be reduced based upon the specified base datatype size.
|
||||||
* @param bitOffset right shift factor within storage unit when viewed as a big-endian dd
|
* @param bitOffset right shift factor within storage unit when viewed as a big-endian dd
|
||||||
* scalar value. Based upon minimal storage bitOffset should be in the range 0 to 7.
|
* scalar value. Based upon minimal storage bitOffset should be in the range 0 to 7.
|
||||||
* @param storageSize minimal storage allocation to which bitOffset is applied or 0 to use
|
|
||||||
* minimum storage size.
|
|
||||||
* @throws InvalidDataTypeException
|
* @throws InvalidDataTypeException
|
||||||
*/
|
*/
|
||||||
// FIXME: Remove storage parameter (compute based upon bitSize and bitOffset)
|
protected BitFieldDataType(DataType baseDataType, int bitSize, int bitOffset)
|
||||||
protected BitFieldDataType(DataType baseDataType, int bitSize, int bitOffset, int storageSize)
|
|
||||||
throws InvalidDataTypeException {
|
throws InvalidDataTypeException {
|
||||||
super(CategoryPath.ROOT, baseDataType.getName() + ":" + bitSize,
|
super(CategoryPath.ROOT, baseDataType.getName() + ":" + bitSize,
|
||||||
baseDataType.getDataTypeManager());
|
baseDataType.getDataTypeManager());
|
||||||
|
@ -76,14 +75,7 @@ public class BitFieldDataType extends AbstractDataType {
|
||||||
this.bitSize = bitSize;
|
this.bitSize = bitSize;
|
||||||
this.bitOffset = bitOffset;
|
this.bitOffset = bitOffset;
|
||||||
effectiveBitSize = getEffectiveBitSize(bitSize, this.baseDataType.getLength());
|
effectiveBitSize = getEffectiveBitSize(bitSize, this.baseDataType.getLength());
|
||||||
if (storageSize == 0) {
|
storageSize = getMinimumStorageSize(effectiveBitSize, bitOffset);
|
||||||
storageSize = getMinimumStorageSize(effectiveBitSize, bitOffset);
|
|
||||||
}
|
|
||||||
this.storageSize = storageSize;
|
|
||||||
checkStorage();
|
|
||||||
if (bitOffset < 0 || bitOffset > ((8 * storageSize) - effectiveBitSize)) {
|
|
||||||
throw new InvalidDataTypeException("invalid bit offset: " + bitOffset);
|
|
||||||
}
|
|
||||||
this.defaultSettings = this.baseDataType.getDefaultSettings();
|
this.defaultSettings = this.baseDataType.getDefaultSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,14 +87,7 @@ public class BitFieldDataType extends AbstractDataType {
|
||||||
* @throws InvalidDataTypeException if specified baseDataType is not permitted
|
* @throws InvalidDataTypeException if specified baseDataType is not permitted
|
||||||
*/
|
*/
|
||||||
protected BitFieldDataType(DataType baseDataType, int bitSize) throws InvalidDataTypeException {
|
protected BitFieldDataType(DataType baseDataType, int bitSize) throws InvalidDataTypeException {
|
||||||
this(baseDataType, bitSize, 0, 0);
|
this(baseDataType, bitSize, 0);
|
||||||
}
|
|
||||||
|
|
||||||
private void checkStorage() throws IllegalArgumentException {
|
|
||||||
int minimumStorageSize = getMinimumStorageSize(effectiveBitSize);
|
|
||||||
if (storageSize != minimumStorageSize && storageSize != ++minimumStorageSize) {
|
|
||||||
throw new IllegalArgumentException("minimal storage size required");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -197,6 +182,7 @@ public class BitFieldDataType extends AbstractDataType {
|
||||||
/**
|
/**
|
||||||
* Get the packing storage size in bytes associated with this bit-field which may be
|
* Get the packing storage size in bytes associated with this bit-field which may be
|
||||||
* larger than the base type associated with the fields original definition.
|
* larger than the base type associated with the fields original definition.
|
||||||
|
* Returned value is the same as {@link #getLength()}.
|
||||||
* @return packing storage size in bytes
|
* @return packing storage size in bytes
|
||||||
*/
|
*/
|
||||||
public int getStorageSize() {
|
public int getStorageSize() {
|
||||||
|
@ -320,13 +306,20 @@ public class BitFieldDataType extends AbstractDataType {
|
||||||
return clone(dtm);
|
return clone(dtm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clone this bitfield to a new datatype manager. This may change the effective bit
|
||||||
|
* size and storage size of the resulting datatype based upon the data organization
|
||||||
|
* of the specified dtm.
|
||||||
|
* @param dtm target datatype manager
|
||||||
|
* @return new instance or same instance of dtm is unchanged.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public BitFieldDataType clone(DataTypeManager dtm) {
|
public BitFieldDataType clone(DataTypeManager dtm) {
|
||||||
if (dtm == dataMgr) {
|
if (dtm == dataMgr) {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
return new BitFieldDataType(baseDataType.clone(dtm), bitSize, bitOffset, storageSize);
|
return new BitFieldDataType(baseDataType.clone(dtm), bitSize, bitOffset);
|
||||||
}
|
}
|
||||||
catch (InvalidDataTypeException e) {
|
catch (InvalidDataTypeException e) {
|
||||||
throw new AssertException("unexpected", e);
|
throw new AssertException("unexpected", e);
|
||||||
|
|
|
@ -201,44 +201,6 @@ public interface Composite extends DataType {
|
||||||
*/
|
*/
|
||||||
public DataTypeComponent insert(int ordinal, DataType dataType, int length);
|
public DataTypeComponent insert(int ordinal, DataType dataType, int length);
|
||||||
|
|
||||||
/**
|
|
||||||
* Inserts a new bitfield at the specified ordinal position in this composite.
|
|
||||||
* Within aligned composites and unions the specified byteWidth and bitOffset will be
|
|
||||||
* ignored.
|
|
||||||
* The component length will be computed based upon the specified parameters and will
|
|
||||||
* be reduced from byteWidth to its minimal size for the new component.
|
|
||||||
* <p>
|
|
||||||
* For unaligned structures, a component shift will only occur if the bitfield placement
|
|
||||||
* conflicts with another component. If no conflict occurs, the bitfield will be placed
|
|
||||||
* at the specified location consuming any DEFAULT components as needed. When a conflict
|
|
||||||
* does occur a shift will be performed at the ordinal position based upon the specified
|
|
||||||
* byteWidth. When located onto existing bitfields they will be packed together
|
|
||||||
* provided they do not conflict, otherwise the conflict rule above applies.
|
|
||||||
* <p>
|
|
||||||
* Supported packing for little-endian fills lsb first, whereas big-endian fills msb first.
|
|
||||||
* Insertion behavior may not work as expected if packing rules differ from this.
|
|
||||||
* @param ordinal the ordinal where the new datatype is to be inserted.
|
|
||||||
* @param byteWidth the storage unit width which contains the bitfield. Must be large
|
|
||||||
* enough to contain the specified bitSize and corresponding bitOffset. The actual
|
|
||||||
* component size used will be recomputed during insertion.
|
|
||||||
* @param bitOffset corresponds to the bitfield left-shift amount with the storage
|
|
||||||
* unit when viewed as big-endian. The final offset may be reduced based upon
|
|
||||||
* the minimal storage size determined during insertion.
|
|
||||||
* @param baseDataType the bitfield base datatype (certain restrictions apply).
|
|
||||||
* @param bitSize the bitfield size in bits
|
|
||||||
* @param componentName the field name to associate with this component.
|
|
||||||
* @param comment the comment to associate with this component.
|
|
||||||
* @return the componentDataType created whose associated data type will
|
|
||||||
* be BitFieldDataType.
|
|
||||||
* @throws InvalidDataTypeException if the specified data type is
|
|
||||||
* not a valid base type for bitfields.
|
|
||||||
* @throws ArrayIndexOutOfBoundsException if ordinal is less than 0 or greater than the
|
|
||||||
* current number of components.
|
|
||||||
*/
|
|
||||||
public DataTypeComponent insertBitField(int ordinal, int byteWidth, int bitOffset,
|
|
||||||
DataType baseDataType, int bitSize, String componentName, String comment)
|
|
||||||
throws InvalidDataTypeException, ArrayIndexOutOfBoundsException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inserts a new datatype at the specified ordinal position in this composite.
|
* Inserts a new datatype at the specified ordinal position in this composite.
|
||||||
* <BR>Note: For an aligned structure the ordinal position will get adjusted
|
* <BR>Note: For an aligned structure the ordinal position will get adjusted
|
||||||
|
|
|
@ -17,34 +17,6 @@ package ghidra.program.model.data;
|
||||||
|
|
||||||
public class CompositeAlignmentHelper {
|
public class CompositeAlignmentHelper {
|
||||||
|
|
||||||
private static int getImpartedAlignment(DataOrganization dataOrganization, int packingAlignment,
|
|
||||||
DataTypeComponent dataTypeComponent) {
|
|
||||||
|
|
||||||
// FIXME: try to eliminate this method.
|
|
||||||
|
|
||||||
// DataType componentDt = dataTypeComponent.getDataType();
|
|
||||||
//
|
|
||||||
// if (componentDt instanceof BitFieldDataType) {
|
|
||||||
// BitFieldPacking bitFieldPacking = dataOrganization.getBitFieldPacking();
|
|
||||||
// if (!bitFieldPacking.isTypeAlignmentEnabled() ||
|
|
||||||
// isBitFieldPackingEnabled(dataOrganization, packingAlignment)) {
|
|
||||||
// return 0;
|
|
||||||
// }
|
|
||||||
// BitFieldDataType bitFieldDt = (BitFieldDataType) componentDt;
|
|
||||||
// // zero-length bitfield assumed not to influence composite alignment, only component alignment
|
|
||||||
// if (!bitFieldPacking.zeroLengthAffectsContainerAlignment() &&
|
|
||||||
// bitFieldDt.getBitSize() == 0) {
|
|
||||||
// return 0;
|
|
||||||
// }
|
|
||||||
// // largest bit-field base-type will provide composite alignment constraint
|
|
||||||
// return getPackedAlignment(dataOrganization, packingAlignment,
|
|
||||||
// bitFieldDt.getBaseDataType(), bitFieldDt.getBaseTypeSize());
|
|
||||||
// }
|
|
||||||
|
|
||||||
return CompositeAlignmentHelper.getPackedAlignment(dataOrganization, packingAlignment,
|
|
||||||
dataTypeComponent);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int getCompositeAlignmentMultiple(DataOrganization dataOrganization,
|
private static int getCompositeAlignmentMultiple(DataOrganization dataOrganization,
|
||||||
Composite composite) {
|
Composite composite) {
|
||||||
int allComponentsLCM = 1;
|
int allComponentsLCM = 1;
|
||||||
|
@ -140,4 +112,5 @@ public class CompositeAlignmentHelper {
|
||||||
return ((absoluteMaxAlignment == 0) || (lcm < absoluteMaxAlignment)) ? lcm
|
return ((absoluteMaxAlignment == 0) || (lcm < absoluteMaxAlignment)) ? lcm
|
||||||
: absoluteMaxAlignment;
|
: absoluteMaxAlignment;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -141,17 +141,6 @@ public abstract class CompositeDataTypeImpl extends GenericDataType implements C
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public DataTypeComponent addBitField(DataType baseDataType, int bitSize, String componentName,
|
|
||||||
String comment) throws InvalidDataTypeException {
|
|
||||||
|
|
||||||
BitFieldDataType.checkBaseDataType(baseDataType);
|
|
||||||
baseDataType = baseDataType.clone(getDataTypeManager());
|
|
||||||
|
|
||||||
BitFieldDataType bitFieldDt = new BitFieldDataType(baseDataType, bitSize);
|
|
||||||
return add(bitFieldDt, bitFieldDt.getStorageSize(), componentName, comment);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle replacement of datatype which may impact bitfield datatype.
|
* Handle replacement of datatype which may impact bitfield datatype.
|
||||||
* @param bitfieldComponent bitfield component
|
* @param bitfieldComponent bitfield component
|
||||||
|
@ -180,9 +169,8 @@ public abstract class CompositeDataTypeImpl extends GenericDataType implements C
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
BitFieldDataType newBitfieldDt =
|
BitFieldDataType newBitfieldDt = new BitFieldDataType(newDt,
|
||||||
new BitFieldDataType(newDt, bitfieldDt.getDeclaredBitSize(),
|
bitfieldDt.getDeclaredBitSize(), bitfieldDt.getBitOffset());
|
||||||
bitfieldDt.getBitOffset(), bitfieldDt.getStorageSize());
|
|
||||||
bitfieldComponent.setDataType(newBitfieldDt);
|
bitfieldComponent.setDataType(newBitfieldDt);
|
||||||
oldDt.removeParent(this);
|
oldDt.removeParent(this);
|
||||||
newDt.addParent(this);
|
newDt.addParent(this);
|
||||||
|
|
|
@ -66,6 +66,46 @@ public interface Structure extends Composite {
|
||||||
*/
|
*/
|
||||||
public abstract DataTypeComponent getDataTypeAt(int offset);
|
public abstract DataTypeComponent getDataTypeAt(int offset);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inserts a new bitfield at the specified ordinal position in this structure.
|
||||||
|
* Within aligned structures the specified byteWidth and bitOffset will be
|
||||||
|
* ignored since packing will occur at the specified ordinal position.
|
||||||
|
* The resulting component length and bitfield details will reflect the use
|
||||||
|
* of minimal storage sizing.
|
||||||
|
* <p>
|
||||||
|
* For unaligned structures, a component shift will only occur if the bitfield placement
|
||||||
|
* conflicts with another component. If no conflict occurs, the bitfield will be placed
|
||||||
|
* at the specified location consuming any DEFAULT components as needed. When a conflict
|
||||||
|
* does occur a shift will be performed at the ordinal position based upon the specified
|
||||||
|
* byteWidth. When located onto existing bitfields they will be packed together
|
||||||
|
* provided they do not conflict, otherwise the conflict rule above applies.
|
||||||
|
* <p>
|
||||||
|
* Supported aligned packing starts with bit-0 (lsb) of the first byte for little-endian, and
|
||||||
|
* with bit-7 (msb) of the first byte for big-endian. This is the default behavior for most
|
||||||
|
* compilers. Insertion behavior may not work as expected if packing rules differ from this.
|
||||||
|
* @param ordinal the ordinal where the new datatype is to be inserted.
|
||||||
|
* @param byteWidth the storage allocation unit width which contains the bitfield. Must be large
|
||||||
|
* enough to contain the "effective bit size" and corresponding bitOffset. The actual
|
||||||
|
* component size used will be recomputed during insertion.
|
||||||
|
* @param bitOffset corresponds to the bitfield left-shift amount with the storage
|
||||||
|
* unit when viewed as big-endian. The final offset may be reduced based upon
|
||||||
|
* the minimal storage size determined during insertion.
|
||||||
|
* @param baseDataType the bitfield base datatype (certain restrictions apply).
|
||||||
|
* @param bitSize the declared bitfield size in bits. The effective bit size may be
|
||||||
|
* adjusted based upon the specified baseDataType.
|
||||||
|
* @param componentName the field name to associate with this component.
|
||||||
|
* @param comment the comment to associate with this component.
|
||||||
|
* @return the bitfield component created whose associated data type will
|
||||||
|
* be BitFieldDataType.
|
||||||
|
* @throws InvalidDataTypeException if the specified baseDataType is
|
||||||
|
* not a valid base type for bitfields.
|
||||||
|
* @throws ArrayIndexOutOfBoundsException if ordinal is less than 0 or greater than the
|
||||||
|
* current number of components.
|
||||||
|
*/
|
||||||
|
public DataTypeComponent insertBitField(int ordinal, int byteWidth, int bitOffset,
|
||||||
|
DataType baseDataType, int bitSize, String componentName, String comment)
|
||||||
|
throws InvalidDataTypeException, ArrayIndexOutOfBoundsException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inserts a new bitfield at the specified location in this composite.
|
* Inserts a new bitfield at the specified location in this composite.
|
||||||
* This method is intended to be used with unaligned structures where
|
* This method is intended to be used with unaligned structures where
|
||||||
|
|
|
@ -297,7 +297,7 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur
|
||||||
}
|
}
|
||||||
validateDataType(dataType);
|
validateDataType(dataType);
|
||||||
|
|
||||||
dataType = dataType.clone(getDataTypeManager());
|
dataType = dataType.clone(dataMgr);
|
||||||
checkAncestry(dataType);
|
checkAncestry(dataType);
|
||||||
|
|
||||||
if ((offset > structLength) && !isInternallyAligned()) {
|
if ((offset > structLength) && !isInternallyAligned()) {
|
||||||
|
@ -369,7 +369,7 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur
|
||||||
|
|
||||||
validateDataType(dataType);
|
validateDataType(dataType);
|
||||||
|
|
||||||
dataType = dataType.clone(getDataTypeManager());
|
dataType = dataType.clone(dataMgr);
|
||||||
checkAncestry(dataType);
|
checkAncestry(dataType);
|
||||||
|
|
||||||
DataTypeComponentImpl dtc;
|
DataTypeComponentImpl dtc;
|
||||||
|
@ -437,7 +437,7 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur
|
||||||
}
|
}
|
||||||
validateDataType(dataType);
|
validateDataType(dataType);
|
||||||
|
|
||||||
dataType = dataType.clone(getDataTypeManager());
|
dataType = dataType.clone(dataMgr);
|
||||||
checkAncestry(dataType);
|
checkAncestry(dataType);
|
||||||
|
|
||||||
int idx;
|
int idx;
|
||||||
|
@ -481,6 +481,17 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur
|
||||||
return dtc;
|
return dtc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataTypeComponent addBitField(DataType baseDataType, int bitSize, String componentName,
|
||||||
|
String comment) throws InvalidDataTypeException {
|
||||||
|
|
||||||
|
BitFieldDataType.checkBaseDataType(baseDataType);
|
||||||
|
baseDataType = baseDataType.clone(dataMgr);
|
||||||
|
|
||||||
|
BitFieldDataType bitFieldDt = new BitFieldDataType(baseDataType, bitSize);
|
||||||
|
return add(bitFieldDt, bitFieldDt.getStorageSize(), componentName, comment);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DataTypeComponent insertBitField(int ordinal, int byteWidth, int bitOffset,
|
public DataTypeComponent insertBitField(int ordinal, int byteWidth, int bitOffset,
|
||||||
DataType baseDataType, int bitSize, String componentName, String comment)
|
DataType baseDataType, int bitSize, String componentName, String comment)
|
||||||
|
@ -491,7 +502,7 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur
|
||||||
}
|
}
|
||||||
|
|
||||||
BitFieldDataType.checkBaseDataType(baseDataType);
|
BitFieldDataType.checkBaseDataType(baseDataType);
|
||||||
baseDataType = baseDataType.clone(getDataTypeManager());
|
baseDataType = baseDataType.clone(dataMgr);
|
||||||
|
|
||||||
if (!isInternallyAligned()) {
|
if (!isInternallyAligned()) {
|
||||||
int offset = structLength;
|
int offset = structLength;
|
||||||
|
@ -521,7 +532,7 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur
|
||||||
}
|
}
|
||||||
|
|
||||||
BitFieldDataType.checkBaseDataType(baseDataType);
|
BitFieldDataType.checkBaseDataType(baseDataType);
|
||||||
baseDataType = baseDataType.clone(getDataTypeManager());
|
baseDataType = baseDataType.clone(dataMgr);
|
||||||
|
|
||||||
int effectiveBitSize =
|
int effectiveBitSize =
|
||||||
BitFieldDataType.getEffectiveBitSize(bitSize, baseDataType.getLength());
|
BitFieldDataType.getEffectiveBitSize(bitSize, baseDataType.getLength());
|
||||||
|
@ -602,11 +613,8 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur
|
||||||
structLength = requiredLength;
|
structLength = requiredLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
// use minimal storage
|
// adjust for minimal storage use
|
||||||
int storageBitOffset = bitOffset % 8;
|
int storageBitOffset = bitOffset % 8;
|
||||||
int storageSize =
|
|
||||||
BitFieldDataType.getMinimumStorageSize(effectiveBitSize + storageBitOffset);
|
|
||||||
|
|
||||||
int revisedOffset;
|
int revisedOffset;
|
||||||
if (bigEndian) {
|
if (bigEndian) {
|
||||||
revisedOffset = byteOffset + byteWidth - ((effectiveBitSize + bitOffset + 7) / 8);
|
revisedOffset = byteOffset + byteWidth - ((effectiveBitSize + bitOffset + 7) / 8);
|
||||||
|
@ -615,11 +623,10 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur
|
||||||
revisedOffset = byteOffset + (bitOffset / 8);
|
revisedOffset = byteOffset + (bitOffset / 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
BitFieldDataType bitfieldDt =
|
BitFieldDataType bitfieldDt = new BitFieldDataType(baseDataType, bitSize, storageBitOffset);
|
||||||
new BitFieldDataType(baseDataType, bitSize, storageBitOffset, storageSize);
|
|
||||||
|
|
||||||
DataTypeComponentImpl dtc = new DataTypeComponentImpl(bitfieldDt, this, storageSize,
|
DataTypeComponentImpl dtc = new DataTypeComponentImpl(bitfieldDt, this,
|
||||||
ordinal, revisedOffset, componentName, comment);
|
bitfieldDt.getStorageSize(), ordinal, revisedOffset, componentName, comment);
|
||||||
bitfieldDt.addParent(this); // currently has no affect
|
bitfieldDt.addParent(this); // currently has no affect
|
||||||
|
|
||||||
components.add(startIndex, dtc);
|
components.add(startIndex, dtc);
|
||||||
|
@ -845,7 +852,7 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DataType clone(DataTypeManager dtm) {
|
public DataType clone(DataTypeManager dtm) {
|
||||||
if (getDataTypeManager() == dtm) {
|
if (dataMgr == dtm) {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
StructureDataType struct =
|
StructureDataType struct =
|
||||||
|
@ -991,13 +998,13 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur
|
||||||
DataType newDt = replacementDt;
|
DataType newDt = replacementDt;
|
||||||
try {
|
try {
|
||||||
validateDataType(replacementDt);
|
validateDataType(replacementDt);
|
||||||
if (replacementDt.getDataTypeManager() != getDataTypeManager()) {
|
if (replacementDt.getDataTypeManager() != dataMgr) {
|
||||||
replacementDt = replacementDt.clone(dataMgr);
|
replacementDt = replacementDt.clone(dataMgr);
|
||||||
}
|
}
|
||||||
checkAncestry(replacementDt);
|
checkAncestry(replacementDt);
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
// TODO: should we use Undefined instead to avoid cases where
|
// TODO: should we use Undefined1 instead to avoid cases where
|
||||||
// DEFAULT datatype can not be used (flex array, bitfield, aligned structure)
|
// DEFAULT datatype can not be used (flex array, bitfield, aligned structure)
|
||||||
// TODO: failing silently is rather hidden
|
// TODO: failing silently is rather hidden
|
||||||
replacementDt = DataType.DEFAULT;
|
replacementDt = DataType.DEFAULT;
|
||||||
|
@ -1130,7 +1137,7 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur
|
||||||
return getComponent(index);
|
return getComponent(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
dataType = dataType.clone(getDataTypeManager());
|
dataType = dataType.clone(dataMgr);
|
||||||
checkAncestry(dataType);
|
checkAncestry(dataType);
|
||||||
|
|
||||||
length = getPreferredComponentLength(dataType, length);
|
length = getPreferredComponentLength(dataType, length);
|
||||||
|
@ -1173,7 +1180,7 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur
|
||||||
return getComponent(ordinal);
|
return getComponent(ordinal);
|
||||||
}
|
}
|
||||||
|
|
||||||
dataType = dataType.clone(getDataTypeManager());
|
dataType = dataType.clone(dataMgr);
|
||||||
checkAncestry(dataType);
|
checkAncestry(dataType);
|
||||||
|
|
||||||
length = getPreferredComponentLength(dataType, length);
|
length = getPreferredComponentLength(dataType, length);
|
||||||
|
|
|
@ -20,4 +20,26 @@ package ghidra.program.model.data;
|
||||||
*/
|
*/
|
||||||
public interface Union extends Composite {
|
public interface Union extends Composite {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inserts a new bitfield at the specified ordinal position in this union.
|
||||||
|
* For both aligned and unaligned unions the bitfield starts with bit-0 (lsb) of the first byte
|
||||||
|
* for little-endian, and with bit-7 (msb) of the first byte for big-endian. This is the
|
||||||
|
* default behavior for most compilers. Insertion behavior may not work as expected if
|
||||||
|
* packing rules differ from this.
|
||||||
|
* @param ordinal the ordinal where the new datatype is to be inserted.
|
||||||
|
* @param baseDataType the bitfield base datatype (certain restrictions apply).
|
||||||
|
* @param bitSize the declared bitfield size in bits. The effective bit size may be
|
||||||
|
* adjusted based upon the specified baseDataType.
|
||||||
|
* @param componentName the field name to associate with this component.
|
||||||
|
* @param comment the comment to associate with this component.
|
||||||
|
* @return the bitfield component created whose associated data type will
|
||||||
|
* be BitFieldDataType.
|
||||||
|
* @throws InvalidDataTypeException if the specified baseDataType is
|
||||||
|
* not a valid base type for bitfields.
|
||||||
|
* @throws ArrayIndexOutOfBoundsException if ordinal is less than 0 or greater than the
|
||||||
|
* current number of components.
|
||||||
|
*/
|
||||||
|
public DataTypeComponent insertBitField(int ordinal, DataType baseDataType, int bitSize,
|
||||||
|
String componentName, String comment)
|
||||||
|
throws InvalidDataTypeException, ArrayIndexOutOfBoundsException;
|
||||||
}
|
}
|
||||||
|
|
|
@ -129,7 +129,9 @@ public class UnionDataType extends CompositeDataTypeImpl implements Union {
|
||||||
|
|
||||||
validateDataType(dataType);
|
validateDataType(dataType);
|
||||||
|
|
||||||
dataType = dataType.clone(getDataTypeManager());
|
dataType = adjustBitField(dataType);
|
||||||
|
|
||||||
|
dataType = dataType.clone(dataMgr);
|
||||||
checkAncestry(dataType);
|
checkAncestry(dataType);
|
||||||
|
|
||||||
length = getPreferredComponentLength(dataType, length);
|
length = getPreferredComponentLength(dataType, length);
|
||||||
|
@ -148,7 +150,9 @@ public class UnionDataType extends CompositeDataTypeImpl implements Union {
|
||||||
|
|
||||||
validateDataType(dataType);
|
validateDataType(dataType);
|
||||||
|
|
||||||
dataType = dataType.clone(getDataTypeManager());
|
dataType = adjustBitField(dataType);
|
||||||
|
|
||||||
|
dataType = dataType.clone(dataMgr);
|
||||||
checkAncestry(dataType);
|
checkAncestry(dataType);
|
||||||
|
|
||||||
length = getPreferredComponentLength(dataType, length);
|
length = getPreferredComponentLength(dataType, length);
|
||||||
|
@ -164,8 +168,14 @@ public class UnionDataType extends CompositeDataTypeImpl implements Union {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DataTypeComponent insertBitField(int ordinal, int byteWidth, int bitOffset,
|
public DataTypeComponent addBitField(DataType baseDataType, int bitSize, String componentName,
|
||||||
DataType baseDataType, int bitSize, String componentName, String comment)
|
String comment) throws InvalidDataTypeException {
|
||||||
|
return insertBitField(components.size(), baseDataType, bitSize, componentName, comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataTypeComponent insertBitField(int ordinal, DataType baseDataType, int bitSize,
|
||||||
|
String componentName, String comment)
|
||||||
throws InvalidDataTypeException, ArrayIndexOutOfBoundsException {
|
throws InvalidDataTypeException, ArrayIndexOutOfBoundsException {
|
||||||
|
|
||||||
if (ordinal < 0 || ordinal > components.size()) {
|
if (ordinal < 0 || ordinal > components.size()) {
|
||||||
|
@ -173,48 +183,10 @@ public class UnionDataType extends CompositeDataTypeImpl implements Union {
|
||||||
}
|
}
|
||||||
|
|
||||||
BitFieldDataType.checkBaseDataType(baseDataType);
|
BitFieldDataType.checkBaseDataType(baseDataType);
|
||||||
baseDataType = baseDataType.clone(getDataTypeManager());
|
baseDataType = baseDataType.clone(dataMgr);
|
||||||
|
|
||||||
if (isInternallyAligned()) {
|
BitFieldDataType bitFieldDt = new BitFieldDataType(baseDataType, bitSize);
|
||||||
BitFieldDataType bitFieldDt = new BitFieldDataType(baseDataType, bitSize);
|
return insert(ordinal, bitFieldDt, bitFieldDt.getStorageSize(), componentName, comment);
|
||||||
return insert(ordinal, bitFieldDt, bitFieldDt.getStorageSize(), componentName, comment);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (byteWidth <= 0) {
|
|
||||||
throw new IllegalArgumentException("Invalid byteWidth");
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: How should zero-length bitfields be handled ?
|
|
||||||
|
|
||||||
// handle unaligned case - use minimal storage
|
|
||||||
// bitfield value will be forced based upon byteWidth, bitSize and endianess
|
|
||||||
boolean bigEndian = getDataOrganization().isBigEndian();
|
|
||||||
int effectiveBitSize =
|
|
||||||
BitFieldDataType.getEffectiveBitSize(bitSize, baseDataType.getLength());
|
|
||||||
int storageSize = BitFieldDataType.getMinimumStorageSize(effectiveBitSize);
|
|
||||||
if (byteWidth < storageSize) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"Bitfield does not fit within specified constraints");
|
|
||||||
}
|
|
||||||
int storageBitOffset = 0;
|
|
||||||
if (bigEndian) {
|
|
||||||
storageBitOffset = (8 * storageSize) - effectiveBitSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
BitFieldDataType bitfieldDt =
|
|
||||||
new BitFieldDataType(baseDataType, bitSize, storageBitOffset, storageSize);
|
|
||||||
|
|
||||||
DataTypeComponentImpl dtc = new DataTypeComponentImpl(bitfieldDt, this, storageSize,
|
|
||||||
ordinal, 0, componentName, comment);
|
|
||||||
|
|
||||||
bitfieldDt.addParent(this); // currently has no affect
|
|
||||||
|
|
||||||
shiftOrdinals(ordinal, 1);
|
|
||||||
components.add(ordinal, dtc);
|
|
||||||
|
|
||||||
adjustLength(true);
|
|
||||||
|
|
||||||
return dtc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -227,7 +199,7 @@ public class UnionDataType extends CompositeDataTypeImpl implements Union {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DataType clone(DataTypeManager dtm) {
|
public DataType clone(DataTypeManager dtm) {
|
||||||
if (getDataTypeManager() == dtm) {
|
if (dataMgr == dtm) {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
UnionDataType union = new UnionDataType(getCategoryPath(), getName(), getUniversalID(),
|
UnionDataType union = new UnionDataType(getCategoryPath(), getName(), getUniversalID(),
|
||||||
|
@ -260,6 +232,50 @@ public class UnionDataType extends CompositeDataTypeImpl implements Union {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private DataType adjustBitField(DataType dataType) {
|
||||||
|
|
||||||
|
if (!(dataType instanceof BitFieldDataType)) {
|
||||||
|
return dataType;
|
||||||
|
}
|
||||||
|
|
||||||
|
BitFieldDataType bitfieldDt = (BitFieldDataType) dataType;
|
||||||
|
|
||||||
|
DataType baseDataType = bitfieldDt.getBaseDataType();
|
||||||
|
baseDataType = baseDataType.clone(dataMgr);
|
||||||
|
|
||||||
|
// Both aligned and unaligned bitfields use same adjustment
|
||||||
|
// unaligned must force bitfield placement at byte offset 0
|
||||||
|
int bitSize = bitfieldDt.getDeclaredBitSize();
|
||||||
|
int effectiveBitSize =
|
||||||
|
BitFieldDataType.getEffectiveBitSize(bitSize, baseDataType.getLength());
|
||||||
|
|
||||||
|
// little-endian always uses bit offset of 0 while
|
||||||
|
// big-endian offset must be computed
|
||||||
|
boolean bigEndian = getDataOrganization().isBigEndian();
|
||||||
|
int storageBitOffset = 0;
|
||||||
|
if (bigEndian) {
|
||||||
|
if (bitSize == 0) {
|
||||||
|
storageBitOffset = 7;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
int storageSize = BitFieldDataType.getMinimumStorageSize(effectiveBitSize);
|
||||||
|
storageBitOffset = (8 * storageSize) - effectiveBitSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (effectiveBitSize != bitfieldDt.getBitSize() ||
|
||||||
|
storageBitOffset != bitfieldDt.getBitOffset()) {
|
||||||
|
try {
|
||||||
|
bitfieldDt = new BitFieldDataType(baseDataType, effectiveBitSize, storageBitOffset);
|
||||||
|
}
|
||||||
|
catch (InvalidDataTypeException e) {
|
||||||
|
// unexpected since deriving from existing bitfield,
|
||||||
|
// ignore and use existing bitfield
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bitfieldDt;
|
||||||
|
}
|
||||||
|
|
||||||
private void adjustLength(boolean notify) {
|
private void adjustLength(boolean notify) {
|
||||||
int oldLength = unionLength;
|
int oldLength = unionLength;
|
||||||
unionLength = 0;
|
unionLength = 0;
|
||||||
|
@ -496,4 +512,5 @@ public class UnionDataType extends CompositeDataTypeImpl implements Union {
|
||||||
public void adjustInternalAlignment() {
|
public void adjustInternalAlignment() {
|
||||||
adjustLength(true);
|
adjustLength(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ import ghidra.program.model.data.*;
|
||||||
|
|
||||||
public class BitFieldDBDataTypeTest extends AbstractGTest {
|
public class BitFieldDBDataTypeTest extends AbstractGTest {
|
||||||
|
|
||||||
private DataTypeManager dataMgr;
|
private DataTypeManagerDB dataMgr;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() throws Exception {
|
public void setup() throws Exception {
|
||||||
|
@ -36,29 +36,29 @@ public class BitFieldDBDataTypeTest extends AbstractGTest {
|
||||||
@Test
|
@Test
|
||||||
public void testGetIdAndGetDataTypeFromId() throws Exception {
|
public void testGetIdAndGetDataTypeFromId() throws Exception {
|
||||||
|
|
||||||
testRoundTrip(new BitFieldDBDataType(CharDataType.dataType, 1, 4, 1, dataMgr));
|
testRoundTrip(new BitFieldDBDataType(CharDataType.dataType, 1, 4));
|
||||||
testRoundTrip(new BitFieldDBDataType(CharDataType.dataType, 2, 6, 1, dataMgr));
|
testRoundTrip(new BitFieldDBDataType(CharDataType.dataType, 2, 6));
|
||||||
testRoundTrip(new BitFieldDBDataType(ShortDataType.dataType, 3, 2, 2, dataMgr));
|
testRoundTrip(new BitFieldDBDataType(ShortDataType.dataType, 3, 2));
|
||||||
testRoundTrip(new BitFieldDBDataType(UnsignedShortDataType.dataType, 4, 4, 1, dataMgr));
|
testRoundTrip(new BitFieldDBDataType(UnsignedShortDataType.dataType, 4, 4));
|
||||||
testRoundTrip(new BitFieldDBDataType(IntegerDataType.dataType, 5, 7, 2, dataMgr));
|
testRoundTrip(new BitFieldDBDataType(IntegerDataType.dataType, 5, 7));
|
||||||
testRoundTrip(new BitFieldDBDataType(UnsignedIntegerDataType.dataType, 14, 2, 3, dataMgr));
|
testRoundTrip(new BitFieldDBDataType(UnsignedIntegerDataType.dataType, 14, 2));
|
||||||
testRoundTrip(new BitFieldDBDataType(LongDataType.dataType, 27, 2, 5, dataMgr));
|
testRoundTrip(new BitFieldDBDataType(LongDataType.dataType, 27, 2));
|
||||||
testRoundTrip(new BitFieldDBDataType(UnsignedLongDataType.dataType, 6, 0, 1, dataMgr));
|
testRoundTrip(new BitFieldDBDataType(UnsignedLongDataType.dataType, 6, 0));
|
||||||
testRoundTrip(new BitFieldDBDataType(LongLongDataType.dataType, 6, 2, 2, dataMgr));
|
testRoundTrip(new BitFieldDBDataType(LongLongDataType.dataType, 6, 2));
|
||||||
testRoundTrip(new BitFieldDBDataType(UnsignedLongLongDataType.dataType, 6, 2, 1, dataMgr));
|
testRoundTrip(new BitFieldDBDataType(UnsignedLongLongDataType.dataType, 6, 2));
|
||||||
|
|
||||||
// non-standard integer base types
|
// non-standard integer base types
|
||||||
testRoundTrip(new BitFieldDBDataType(ByteDataType.dataType, 6, 2, 1, dataMgr));
|
testRoundTrip(new BitFieldDBDataType(ByteDataType.dataType, 6, 2));
|
||||||
testRoundTrip(new BitFieldDBDataType(QWordDataType.dataType, 6, 2, 1, dataMgr));
|
testRoundTrip(new BitFieldDBDataType(QWordDataType.dataType, 6, 2));
|
||||||
|
|
||||||
// TypeDef base types
|
// TypeDef base types
|
||||||
TypeDef foo = new TypedefDataType("foo", IntegerDataType.dataType);
|
TypeDef foo = new TypedefDataType("foo", IntegerDataType.dataType);
|
||||||
testRoundTrip(new BitFieldDBDataType(foo, 6, 3, 2, dataMgr));
|
testRoundTrip(new BitFieldDBDataType(foo, 6, 3));
|
||||||
|
|
||||||
// Enum base types
|
// Enum base types
|
||||||
EnumDataType fum = new EnumDataType("fum", 4);
|
EnumDataType fum = new EnumDataType("fum", 4);
|
||||||
fum.add("A", 1);
|
fum.add("A", 1);
|
||||||
testRoundTrip(new BitFieldDBDataType(fum, 6, 2, 1, dataMgr));
|
testRoundTrip(new BitFieldDBDataType(fum, 6, 2));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -164,7 +164,7 @@ public class UnionDBTest extends AbstractGTest {
|
||||||
union.delete(0);
|
union.delete(0);
|
||||||
}
|
}
|
||||||
// NOTE: bitOffset ignored for union
|
// NOTE: bitOffset ignored for union
|
||||||
union.insertBitField(0, 4, 12, IntegerDataType.dataType, 2, "bf1", "bf1Comment");
|
union.insertBitField(0, IntegerDataType.dataType, 2, "bf1", "bf1Comment");
|
||||||
union.insert(0, ShortDataType.dataType);
|
union.insert(0, ShortDataType.dataType);
|
||||||
|
|
||||||
//@formatter:off
|
//@formatter:off
|
||||||
|
@ -185,7 +185,7 @@ public class UnionDBTest extends AbstractGTest {
|
||||||
for (int i = 0; i < cnt; i++) {
|
for (int i = 0; i < cnt; i++) {
|
||||||
union.delete(0);
|
union.delete(0);
|
||||||
}
|
}
|
||||||
union.insertBitField(0, 4, 12, IntegerDataType.dataType, 2, "bf1", "bf1Comment");
|
union.insertBitField(0, IntegerDataType.dataType, 2, "bf1", "bf1Comment");
|
||||||
union.insert(0, ShortDataType.dataType);
|
union.insert(0, ShortDataType.dataType);
|
||||||
union.setInternallyAligned(true);
|
union.setInternallyAligned(true);
|
||||||
|
|
||||||
|
@ -203,8 +203,8 @@ public class UnionDBTest extends AbstractGTest {
|
||||||
@Test
|
@Test
|
||||||
public void testInsertBitFieldLittleEndian() throws Exception {
|
public void testInsertBitFieldLittleEndian() throws Exception {
|
||||||
|
|
||||||
union.insertBitField(2, 4, 0, IntegerDataType.dataType, 4, "bf1", "bf1Comment");
|
union.insertBitField(2, IntegerDataType.dataType, 4, "bf1", "bf1Comment");
|
||||||
union.insertBitField(3, 1, 0, ByteDataType.dataType, 4, "bf2", "bf2Comment");
|
union.insertBitField(3, ByteDataType.dataType, 4, "bf2", "bf2Comment");
|
||||||
|
|
||||||
//@formatter:off
|
//@formatter:off
|
||||||
CompositeTestUtils.assertExpectedComposite(this, "/TestUnion\n" +
|
CompositeTestUtils.assertExpectedComposite(this, "/TestUnion\n" +
|
||||||
|
@ -226,8 +226,8 @@ public class UnionDBTest extends AbstractGTest {
|
||||||
|
|
||||||
transitionToBigEndian();
|
transitionToBigEndian();
|
||||||
|
|
||||||
union.insertBitField(2, 4, 0, IntegerDataType.dataType, 4, "bf1", "bf1Comment");
|
union.insertBitField(2, IntegerDataType.dataType, 4, "bf1", "bf1Comment");
|
||||||
union.insertBitField(3, 1, 0, ByteDataType.dataType, 4, "bf2", "bf2Comment");
|
union.insertBitField(3, ByteDataType.dataType, 4, "bf2", "bf2Comment");
|
||||||
|
|
||||||
//@formatter:off
|
//@formatter:off
|
||||||
CompositeTestUtils.assertExpectedComposite(this, "/TestUnion\n" +
|
CompositeTestUtils.assertExpectedComposite(this, "/TestUnion\n" +
|
||||||
|
@ -250,8 +250,8 @@ public class UnionDBTest extends AbstractGTest {
|
||||||
TypeDef td = new TypedefDataType("Foo", IntegerDataType.dataType);
|
TypeDef td = new TypedefDataType("Foo", IntegerDataType.dataType);
|
||||||
td = (TypeDef) dataMgr.resolve(td, null);
|
td = (TypeDef) dataMgr.resolve(td, null);
|
||||||
|
|
||||||
union.insertBitField(2, 4, 0, td, 4, "bf1", "bf1Comment");
|
union.insertBitField(2, td, 4, "bf1", "bf1Comment");
|
||||||
union.insertBitField(3, 1, 0, td, 4, "bf2", "bf2Comment");
|
union.insertBitField(3, td, 4, "bf2", "bf2Comment");
|
||||||
|
|
||||||
//@formatter:off
|
//@formatter:off
|
||||||
CompositeTestUtils.assertExpectedComposite(this, "/TestUnion\n" +
|
CompositeTestUtils.assertExpectedComposite(this, "/TestUnion\n" +
|
||||||
|
@ -289,8 +289,8 @@ public class UnionDBTest extends AbstractGTest {
|
||||||
TypeDef td = new TypedefDataType("Foo", IntegerDataType.dataType);
|
TypeDef td = new TypedefDataType("Foo", IntegerDataType.dataType);
|
||||||
td = (TypeDef) dataMgr.resolve(td, null);
|
td = (TypeDef) dataMgr.resolve(td, null);
|
||||||
|
|
||||||
union.insertBitField(2, 4, 0, td, 4, "bf1", "bf1Comment");
|
union.insertBitField(2, td, 4, "bf1", "bf1Comment");
|
||||||
union.insertBitField(3, 1, 0, td, 4, "bf2", "bf2Comment");
|
union.insertBitField(3, td, 4, "bf2", "bf2Comment");
|
||||||
|
|
||||||
//@formatter:off
|
//@formatter:off
|
||||||
CompositeTestUtils.assertExpectedComposite(this, "/TestUnion\n" +
|
CompositeTestUtils.assertExpectedComposite(this, "/TestUnion\n" +
|
||||||
|
|
|
@ -177,13 +177,11 @@ public class BitFieldDataTypeTest extends AbstractGTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
private BitFieldDataType bitField(int size, int offset) throws Exception {
|
private BitFieldDataType bitField(int size, int offset) throws Exception {
|
||||||
int storageSize = BitFieldDataType.getMinimumStorageSize(size);
|
return new BitFieldDataType(IntegerDataType.dataType, size, offset);
|
||||||
return new BitFieldDataType(IntegerDataType.dataType, size, offset, storageSize);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private BitFieldDataType unsignedBitField(int size, int offset) throws Exception {
|
private BitFieldDataType unsignedBitField(int size, int offset) throws Exception {
|
||||||
int storageSize = BitFieldDataType.getMinimumStorageSize(size);
|
return new BitFieldDataType(UnsignedIntegerDataType.dataType, size, offset);
|
||||||
return new BitFieldDataType(UnsignedIntegerDataType.dataType, size, offset, storageSize);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private MemBuffer membuf(int... bytes) throws Exception {
|
private MemBuffer membuf(int... bytes) throws Exception {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue