From 1fcad78bc49ae356d5fba4c939eba5af38b81301 Mon Sep 17 00:00:00 2001 From: ghidra1 Date: Tue, 14 May 2019 14:30:41 -0400 Subject: [PATCH] BitFields - added direct parse support of bitfield entry within composite. Restrict use of bitfield datatype. --- .../compositeeditor/BitFieldEditorDialog.java | 2 +- .../compositeeditor/BitFieldEditorPanel.java | 14 +-- .../compositeeditor/CompositeEditorPanel.java | 6 +- .../core/compositeeditor/EditorModel.java | 5 + .../compositeeditor/StructureEditorModel.java | 8 +- .../compositeeditor/UnionEditorModel.java | 7 +- .../core/stackeditor/StackEditorModel.java | 13 ++- .../datatype/DataTypeSelectionEditor.java | 32 ++----- .../java/ghidra/util/data/DataTypeParser.java | 94 +++++++++++++++++-- .../program/model/data/ArrayDataType.java | 4 + .../program/model/data/BitFieldDataType.java | 2 +- .../program/model/data/PointerDataType.java | 5 + .../program/model/data/TypedefDataType.java | 4 + 13 files changed, 153 insertions(+), 43 deletions(-) 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());