diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/BitFieldEditorDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/BitFieldEditorDialog.java
index 53939c0475..f896b76ece 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/BitFieldEditorDialog.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/BitFieldEditorDialog.java
@@ -239,7 +239,7 @@ public class BitFieldEditorDialog extends DialogComponentProvider {
if (!dtc.isBitFieldComponent()) {
throw new IllegalArgumentException("editOrdinal does not correspond to bitfield");
}
- bitFieldEditorPanel.initEdit(dtc, getPreferredAllocationOffset(dtc), false);
+ bitFieldEditorPanel.initEdit(dtc, getPreferredAllocationOffset(dtc));
setApplyEnabled(true);
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/BitFieldEditorPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/BitFieldEditorPanel.java
index f905a891d8..acb4dbf196 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/BitFieldEditorPanel.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/BitFieldEditorPanel.java
@@ -193,7 +193,8 @@ public class BitFieldEditorPanel extends JPanel {
private JComponent createDataTypeChoiceEditor() {
- dtChoiceEditor = new DataTypeSelectionEditor(dtmService, -1, AllowedDataTypes.BITFIELD_BASE_TYPE);
+ dtChoiceEditor =
+ new DataTypeSelectionEditor(dtmService, -1, AllowedDataTypes.BITFIELD_BASE_TYPE);
dtChoiceEditor.setConsumeEnterKeyPress(false);
dtChoiceEditor.setTabCommitsEdit(true);
//dtChoiceEditor.setPreferredDataTypeManager(composite.getDataTypeManager());
@@ -368,11 +369,8 @@ public class BitFieldEditorPanel extends JPanel {
* If null an allocation size of 4-bytes will be used but may be adjusted.
* @param bitfieldDtc bitfield component or null
* @param allocationOffset allocation offset to be used
- * @param useCurrentAllocation retain current allocation size, otherwise
- * use size of base datatype.
*/
- void initEdit(DataTypeComponent bitfieldDtc, int allocationOffset,
- boolean useCurrentAllocation) {
+ void initEdit(DataTypeComponent bitfieldDtc, int allocationOffset) {
String initialFieldName = null;
DataType initialBaseDataType = null;
int allocationSize = -1;
@@ -387,9 +385,13 @@ public class BitFieldEditorPanel extends JPanel {
initialFieldName = bitfieldDtc.getFieldName();
BitFieldDataType bitfieldDt = (BitFieldDataType) bitfieldDtc.getDataType();
initialBaseDataType = bitfieldDt.getBaseDataType();
- if (!useCurrentAllocation || allocationSize < 1) {
+ if (allocationSize < 1) {
allocationSize = initialBaseDataType.getLength();
}
+ int allocationAdjust = composite.getLength() - allocationOffset - allocationSize;
+ if (allocationAdjust < 0) {
+ allocationSize += allocationAdjust;
+ }
}
if (allocationSize < 1) {
allocationSize = 4;
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorPanel.java
index b5ad18477a..dd8b28a2d6 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorPanel.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorPanel.java
@@ -1216,6 +1216,7 @@ public abstract class CompositeEditorPanel extends JPanel
private DataTypeSelectionEditor editor;
private DataType dt;
private int maxLength;
+ private boolean bitfieldAllowed;
private JPanel editorPanel;
@@ -1224,6 +1225,7 @@ public abstract class CompositeEditorPanel extends JPanel
boolean isSelected, int row, int column) {
model.clearStatus();
maxLength = model.getMaxAddLength(row);
+ bitfieldAllowed = model.isBitFieldAllowed();
init();
DataTypeInstance dti = (DataTypeInstance) value;
@@ -1243,7 +1245,9 @@ public abstract class CompositeEditorPanel extends JPanel
Plugin plugin = provider.getPlugin();
final PluginTool tool = plugin.getTool();
- editor = new DataTypeSelectionEditor(tool, maxLength, AllowedDataTypes.SIZABLE_DYNAMIC);
+ editor = new DataTypeSelectionEditor(tool, maxLength,
+ bitfieldAllowed ? AllowedDataTypes.SIZABLE_DYNAMIC_AND_BITFIELD
+ : AllowedDataTypes.SIZABLE_DYNAMIC);
editor.setTabCommitsEdit(true);
DataTypeManager originalDataTypeManager = model.getOriginalDataTypeManager();
editor.setPreferredDataTypeManager(originalDataTypeManager);
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/EditorModel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/EditorModel.java
index d66c469447..198d0d3726 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/EditorModel.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/EditorModel.java
@@ -87,6 +87,11 @@ public interface EditorModel {
*/
public boolean isArrayAllowed();
+ /**
+ * Returns whether or not a bitfield is allowed at the current location.
+ */
+ public boolean isBitFieldAllowed();
+
/**
* Returns whether or not clearing the selected components is allowed.
*/
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/StructureEditorModel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/StructureEditorModel.java
index 4e3682e3fc..b387a3e897 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/StructureEditorModel.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/StructureEditorModel.java
@@ -181,8 +181,7 @@ class StructureEditorModel extends CompEditorModel {
@Override
public DataTypeComponent getComponent(int rowIndex) {
int numComponents = getNumComponents();
-
- if (rowIndex < 0 || rowIndex == numComponents) {
+ if (numComponents == 0 || rowIndex < 0 || rowIndex == numComponents) {
return null;
}
Structure viewStruct = (Structure) viewComposite;
@@ -571,6 +570,11 @@ class StructureEditorModel extends CompEditorModel {
// Begin methods for determining if a type of edit action is allowed.
// *************************************************************
+ @Override
+ public boolean isBitFieldAllowed() {
+ return isSingleRowSelection() && !isFlexibleArraySelection();
+ }
+
/**
* Returns whether or not the selection
* is allowed to be changed into an array.
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/UnionEditorModel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/UnionEditorModel.java
index 256087944b..1bfca3a985 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/UnionEditorModel.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/UnionEditorModel.java
@@ -213,13 +213,18 @@ class UnionEditorModel extends CompEditorModel {
// Begin methods for determining if a type of edit action is allowed.
// *************************************************************
+ @Override
+ public boolean isBitFieldAllowed() {
+ return isSingleRowSelection();
+ }
+
/**
* Returns whether or not the selection
* is allowed to be changed into an array.
*/
@Override
public boolean isArrayAllowed() {
- return (getNumSelectedComponentRows() == 1);
+ return isSingleRowSelection();
}
/**
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/StackEditorModel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/StackEditorModel.java
index 11a44cd10b..c023d2e62c 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/StackEditorModel.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/StackEditorModel.java
@@ -687,9 +687,14 @@ class StackEditorModel extends CompositeEditorModel {
return true;
}
+ @Override
+ public boolean isBitFieldAllowed() {
+ return false;
+ }
+
@Override
public boolean isArrayAllowed() {
- if (getNumSelectedRows() != 1) {
+ if (getNumSelectedRows() != 1 || viewComposite == null) {
return false;
}
int index = getMinIndexSelected();
@@ -1437,11 +1442,17 @@ class StackEditorModel extends CompositeEditorModel {
@Override
public DataTypeComponent getComponent(int rowIndex) {
+ if (viewComposite == null) {
+ return null;
+ }
return viewComposite.getComponent(rowIndex);
}
@Override
public int getNumComponents() {
+ if (viewComposite == null) {
+ return 0;
+ }
return viewComposite.getNumComponents();
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/datatype/DataTypeSelectionEditor.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/datatype/DataTypeSelectionEditor.java
index edd7e633cf..3bdf812625 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/datatype/DataTypeSelectionEditor.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/datatype/DataTypeSelectionEditor.java
@@ -298,7 +298,7 @@ public class DataTypeSelectionEditor extends AbstractCellEditor {
// if it is not a known type, the prompt user to create new one
if (!isValidDataType()) {
- return promptUserToCreateDataType();
+ return parseDataTypeTextEntry();
}
return true;
@@ -339,8 +339,12 @@ public class DataTypeSelectionEditor extends AbstractCellEditor {
return null;
}
- // TODO: implement in the future to allow the user to create data types
- private boolean promptUserToCreateDataType() throws InvalidDataTypeException {
+ /**
+ * Parse datatype text entry using {@link DataTypeParser}. Allows addition
+ * of supported modifiers (e.g., arrays, pointers, etc.).
+ * @return true if parse successful else false
+ */
+ private boolean parseDataTypeTextEntry() throws InvalidDataTypeException {
if (selectionField.getText().trim().length() == 0) {
// no need to invoke parser on empty string
@@ -349,9 +353,8 @@ public class DataTypeSelectionEditor extends AbstractCellEditor {
// we will create new pointer and array types by default
DataType newDataType = null;
-// try {
- DataTypeParser parser =
- new DataTypeParser(dataTypeManager, null, dataTypeManagerService, allowedDataTypes);
+ DataTypeParser parser = new DataTypeParser(dataTypeManager, dataTypeManager,
+ dataTypeManagerService, allowedDataTypes);
newDataType = parser.parse(selectionField.getText(), getDataTypeRootForCurrentText());
if (newDataType != null) {
if (maxSize >= 0 && newDataType.getLength() > newDataType.getLength()) {
@@ -360,23 +363,6 @@ public class DataTypeSelectionEditor extends AbstractCellEditor {
selectionField.setSelectedValue(newDataType);
return true;
}
-// }
-// // squash these exceptions, as this method returns false if we were unable to create the
-// // given data type
-// catch ( CancelledException ce ) {
-// }
-
- // prompt user
- /*
- int userChoice = JOptionPane.showOptionDialog( selectionField,
- "Data type \"" + selectionField.getText() + "\" does not exist. Would you " +
- "like to create it?", "Create New Data Type?",
- JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, null, null );
-
- if ( userChoice == JOptionPane.YES_OPTION ) {
- return createNewDataTypeForUserSelection();
- }
- */
return false;
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/util/data/DataTypeParser.java b/Ghidra/Features/Base/src/main/java/ghidra/util/data/DataTypeParser.java
index 34c6c378d0..1397e89052 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/util/data/DataTypeParser.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/util/data/DataTypeParser.java
@@ -23,6 +23,7 @@ import ghidra.app.services.DataTypeManagerService;
import ghidra.program.database.data.DataTypeUtilities;
import ghidra.program.database.data.ProgramDataTypeManager;
import ghidra.program.model.data.*;
+import ghidra.util.exception.AssertException;
public class DataTypeParser {
@@ -39,6 +40,15 @@ public class DataTypeParser {
* All fixed-length data-types and sizable Dynamic(i.e., canSpecifyLength) data-types
*/
SIZABLE_DYNAMIC,
+ /**
+ * All fixed-length data-types, sizable Dynamic data-types.
+ * In addition a bitfield specification may be specified (e.g., int:2)
+ * for use when defining structure and union components only
+ * (see {@link ProxyBitFieldDataType}). Parser must be properly constructed
+ * with the intended {@link DataTypeParser#destinationDataTypeManager}.
+ * If a bitfield is returned special handling is required.
+ */
+ SIZABLE_DYNAMIC_AND_BITFIELD,
/**
* Only Fixed-length data-types
*/
@@ -54,6 +64,26 @@ public class DataTypeParser {
BITFIELD_BASE_TYPE
}
+ /**
+ * ProxyBitFieldDataType provides acts as a proxy bitfield
+ * whose specification may be used when defining a structure or
+ * union bitfield. This datatype may not be directly applied to a program.
+ */
+ private static class ProxyBitFieldDataType extends BitFieldDataType {
+ /**
+ * Construct proxy bitfield datatype for use when defining
+ * a structure or union bitfield.
+ * @param baseDataType a supported primitive integer data type or TypeDef to such a type.
+ * A deep clone of this type will be performed using the specified dataMgr.
+ * @param bitSize size of bit-field expressed as number of bits
+ * @throws InvalidDataTypeException if specified baseDataType is not permitted
+ */
+ private ProxyBitFieldDataType(DataType baseDataType, int bitSize)
+ throws InvalidDataTypeException {
+ super(baseDataType, bitSize);
+ }
+ }
+
private DataTypeManager sourceDataTypeManager; // may be null
private DataTypeManager destinationDataTypeManager; // may be null
private DataTypeManagerService dataTypeManagerService; // may be null
@@ -162,6 +192,12 @@ public class DataTypeParser {
*/
public static void ensureIsAllowableType(DataType dt, AllowedDataTypes allowedTypes)
throws InvalidDataTypeException {
+ if (dt instanceof BitFieldDataType) {
+ if (allowedTypes != AllowedDataTypes.SIZABLE_DYNAMIC_AND_BITFIELD) {
+ throw new InvalidDataTypeException("bitfield data-type not allowed");
+ }
+ return;
+ }
switch (allowedTypes) {
case DYNAMIC:
if (dt instanceof FactoryDataType) {
@@ -169,6 +205,7 @@ public class DataTypeParser {
}
break;
case SIZABLE_DYNAMIC:
+ case SIZABLE_DYNAMIC_AND_BITFIELD:
if (dt instanceof FactoryDataType) {
throw new InvalidDataTypeException("factory data-type not allowed");
}
@@ -205,7 +242,11 @@ public class DataTypeParser {
throws InvalidDataTypeException {
int arraySequenceStartIndex = -1;
List modifiers = new ArrayList<>();
+ boolean terminalModifier = false;
for (String piece : splitDataTypeModifiers(dataTypeModifiers)) {
+ if (terminalModifier) {
+ throw new InvalidDataTypeException("Invalid data type modifier");
+ }
if (piece.startsWith("*")) {
modifiers.add(new PointerSpecPiece(piece));
arraySequenceStartIndex = -1;
@@ -221,6 +262,10 @@ public class DataTypeParser {
modifiers.add(arraySpec);
}
}
+ else if (piece.startsWith(":")) {
+ terminalModifier = true;
+ modifiers.add(new BitfieldSpecPiece(piece));
+ }
else if (piece.startsWith("{")) {
// # indicates the size of an array element when the base data type is dynamic.
modifiers.add(new ElementSizeSpecPiece(piece));
@@ -241,11 +286,22 @@ public class DataTypeParser {
elementLength = ((ElementSizeSpecPiece) modifier).getElementSize();
}
}
- else {
+ else if (modifier instanceof ArraySpecPiece) {
int elementCount = ((ArraySpecPiece) modifier).getElementCount();
dt = createArrayDataType(dt, elementLength, elementCount);
elementLength = dt.getLength();
}
+ else if (modifier instanceof BitfieldSpecPiece) {
+ if (allowedTypes != AllowedDataTypes.SIZABLE_DYNAMIC_AND_BITFIELD) {
+ throw new InvalidDataTypeException("bitfield not permitted");
+ }
+ if (destinationDataTypeManager == null) {
+ throw new AssertException(
+ "bitfields require destination datatype manager to be specified");
+ }
+ int bitSize = ((BitfieldSpecPiece) modifier).getBitSize();
+ dt = new ProxyBitFieldDataType(dt.clone(destinationDataTypeManager), bitSize);
+ }
}
}
catch (IllegalArgumentException e) {
@@ -375,7 +431,7 @@ public class DataTypeParser {
int nextIndex = 0;
while (nextIndex < dataTypeString.length()) {
char c = dataTypeString.charAt(nextIndex);
- if (c == '*' || c == '[' || c == '{') {
+ if (c == '*' || c == '[' || c == ':' || c == '{') {
return dataTypeString.substring(0, nextIndex).trim();
}
++nextIndex;
@@ -384,7 +440,7 @@ public class DataTypeParser {
}
private static String[] splitDataTypeModifiers(String dataTypeModifiers) {
- dataTypeModifiers = dataTypeModifiers.replaceAll("[ \\t]", "");
+ dataTypeModifiers = dataTypeModifiers.replaceAll(":[ \\t]", "");
if (dataTypeModifiers.length() == 0) {
return new String[0];
}
@@ -393,7 +449,7 @@ public class DataTypeParser {
int nextIndex = 1;
while (nextIndex < dataTypeModifiers.length()) {
char c = dataTypeModifiers.charAt(nextIndex);
- if (c == '*' || c == '[' || c == '{') {
+ if (c == '*' || c == '[' || c == ':' || c == '{') {
list.add(dataTypeModifiers.substring(startIndex, nextIndex));
startIndex = nextIndex;
}
@@ -420,7 +476,7 @@ public class DataTypeParser {
destinationDataTypeManager);
}
- private static int parseArraySize(String numStr) {
+ private static int parseSize(String numStr) {
numStr = (numStr == null ? "" : numStr.trim());
if (numStr.length() == 0) {
throw new NumberFormatException();
@@ -435,6 +491,30 @@ public class DataTypeParser {
// dummy interface so we don't have to use Object in the list container
}
+ private static class BitfieldSpecPiece implements DtPiece {
+ int bitSize;
+
+ BitfieldSpecPiece(String piece) throws InvalidDataTypeException {
+ if (piece.startsWith(":")) {
+ String bitSizeStr = piece.substring(1);
+ try {
+ bitSize = parseSize(bitSizeStr);
+ if (bitSize >= 0) {
+ return;
+ }
+ }
+ catch (NumberFormatException e) {
+ // handled below
+ }
+ }
+ throw new InvalidDataTypeException("invalid bitfield specification: " + piece);
+ }
+
+ int getBitSize() {
+ return bitSize;
+ }
+ }
+
private static class ArraySpecPiece implements DtPiece {
int elementCount;
@@ -442,7 +522,7 @@ public class DataTypeParser {
if (piece.startsWith("[") && piece.endsWith("]")) {
String elementCountStr = piece.substring(1, piece.length() - 1);
try {
- elementCount = parseArraySize(elementCountStr);
+ elementCount = parseSize(elementCountStr);
return;
}
catch (NumberFormatException e) {
@@ -492,7 +572,7 @@ public class DataTypeParser {
if (piece.startsWith("{") && piece.endsWith("}")) {
String elementSizeStr = piece.substring(1, piece.length() - 1);
try {
- elementSize = parseArraySize(elementSizeStr);
+ elementSize = parseSize(elementSizeStr);
return;
}
catch (NumberFormatException e) {
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/ArrayDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/ArrayDataType.java
index b0fddaf6f0..0f20ce61ab 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/ArrayDataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/ArrayDataType.java
@@ -72,6 +72,10 @@ public class ArrayDataType extends DataTypeImpl implements Array {
}
private void validate(DataType dt) {
+ if (dt instanceof BitFieldDataType) {
+ throw new IllegalArgumentException(
+ "Array data-type may not be a bitfield: " + dt.getName());
+ }
if (dt instanceof FactoryDataType) {
throw new IllegalArgumentException(
"Array data-type may not be a Factory data-type: " + dt.getName());
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/BitFieldDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/BitFieldDataType.java
index 84a7eaa6d9..cab42075a3 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/BitFieldDataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/BitFieldDataType.java
@@ -90,7 +90,7 @@ public class BitFieldDataType extends AbstractDataType {
/**
* Construct a bit-field type based upon a supported baseDataType.
* @param baseDataType a supported primitive integer data type or TypeDef to such a type.
- * A deep clone of this type will be performed using the specified dataMgr.
+ * The baseType must already be cloned to the target datatype manager.
* @param bitSize size of bit-field expressed as number of bits
* @throws InvalidDataTypeException if specified baseDataType is not permitted
*/
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/PointerDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/PointerDataType.java
index 15c8fb11d7..d873911e64 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/PointerDataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/PointerDataType.java
@@ -112,6 +112,11 @@ public class PointerDataType extends BuiltIn implements Pointer {
public PointerDataType(DataType referencedDataType, int length, DataTypeManager dtm) {
super(referencedDataType != null ? referencedDataType.getCategoryPath() : null,
constructUniqueName(referencedDataType, length), dtm);
+ if (referencedDataType instanceof BitFieldDataType) {
+ throw new IllegalArgumentException(
+ "Pointer reference data-type may not be a bitfield: " +
+ referencedDataType.getName());
+ }
this.length = length <= 0 ? -1 : length;
this.referencedDataType = referencedDataType;
if (referencedDataType != null) {
diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/TypedefDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/TypedefDataType.java
index ac998e3245..f58f734378 100644
--- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/TypedefDataType.java
+++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/TypedefDataType.java
@@ -75,6 +75,10 @@ public class TypedefDataType extends GenericDataType implements TypeDef {
}
private void validate(DataType dt) {
+ if (dt instanceof BitFieldDataType) {
+ throw new IllegalArgumentException(
+ "TypeDef data-type may not be a bitfield: " + dt.getName());
+ }
if (dt instanceof FactoryDataType) {
throw new IllegalArgumentException(
"TypeDef data-type may not be a Factory data-type: " + dt.getName());