BitFields - added preliminary support for composite bitfields

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

View file

@ -163,6 +163,8 @@
be specified.<BR>
</P>
</BLOCKQUOTE>
<BLOCKQUOTE>
<H3>Unaligned Structures</H3>
@ -301,7 +303,9 @@
<IMG alt="" src="images/UnionEditorAligned.png">
</DIV>
</BLOCKQUOTE>
</BLOCKQUOTE>
<H2><A name="Structure_Editor_Flex_Array"></A>Flexible Array Component</H2>
<P>A structure may be defined with a trailing flexible array component which corresponds to
@ -321,7 +325,17 @@
be reflected in decompilation results. Its primary purpose if to reflect the C source definition
of a structure with correct alignment and structure sizing.</P>
<DIV style="text-align: center;">
<P><IMG alt="Note:" src="../../shared/note.png"> The equivalent of having <SPAN style=
"font-style: italic;">no C #pragma pack attribute</SPAN> on the structure or union is to
choose <SPAN style="font-weight: bold;">none</SPAN>. The equivalent for a C code attribute of
<SPAN style="font-style: italic;">#pragma pack()</SPAN> without a value is to specify a <SPAN
style="font-weight: bold;">pack value</SPAN> of <SPAN style="font-weight: bold;">1</SPAN>.
The equivalent of <SPAN style="font-style: italic;"># pragma</SPAN> <SPAN style=
"font-style: italic;">pack(4)</SPAN> is to specify a <SPAN style="font-weight: bold;">pack
value</SPAN> of 4.<BR>
</P>
<DIV style="text-align: center;">
<IMG alt="" src="images/StructureEditorWithFlexArray.png"><BR>
<BR>
</DIV>
@ -334,6 +348,8 @@
table. There are also short-cut keys associated with each of the edit actions.</P>
</BLOCKQUOTE>
<BLOCKQUOTE>
<H3><A name="Structure_Editor_Insert_Undefined_Byte"></A> <IMG src="images/Plus.png" alt="">
Insert Undefined Byte</H3>
@ -557,6 +573,7 @@
is created and a component containing it replaces the selected components.</P>
</BLOCKQUOTE><BR>
</BLOCKQUOTE>
<H2><A name="Structure_Editor_Component_Fields"></A>Component Fields</H2>

View file

@ -23,16 +23,17 @@ import java.util.Map.Entry;
import javax.swing.tree.TreePath;
import generic.jar.ResourceFile;
import ghidra.app.plugin.core.datamgr.archive.Archive;
import ghidra.app.plugin.core.datamgr.archive.DuplicateIdException;
import ghidra.app.plugin.core.datamgr.archive.*;
import ghidra.app.plugin.core.datamgr.util.DataTypeArchiveUtility;
import ghidra.app.plugin.core.datamgr.util.DataTypeComparator;
import ghidra.app.services.DataTypeManagerService;
import ghidra.program.model.data.*;
import ghidra.program.model.listing.DataTypeArchive;
import ghidra.util.HelpLocation;
import ghidra.util.UniversalID;
class DefaultDataTypeManagerService implements DataTypeManagerService {
// FIXME!! TESTING
public class DefaultDataTypeManagerService implements DataTypeManagerService {
private Map<String, FileDataTypeManager> archiveMap = new HashMap<>();
private DataTypeManager builtInDataTypesManager = BuiltInDataTypeManager.getDataTypeManager();
@ -156,6 +157,9 @@ class DefaultDataTypeManagerService implements DataTypeManagerService {
@Override
public DataType getDataType(TreePath selectedTreeNode) {
if (selectedTreeNode == null) {
return null;
}
throw new UnsupportedOperationException();
}
@ -171,7 +175,11 @@ class DefaultDataTypeManagerService implements DataTypeManagerService {
@Override
public List<DataType> getSortedDataTypeList() {
throw new UnsupportedOperationException();
List<DataType> dataTypes =
builtInDataTypesManager.getDataTypes(BuiltInSourceArchive.INSTANCE);
dataTypes.sort(new DataTypeComparator());
return dataTypes;
// throw new UnsupportedOperationException();
}
@Override

View file

@ -0,0 +1,112 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.plugin.core.compositeeditor;
import java.awt.Component;
import java.awt.Window;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import docking.ActionContext;
import docking.DockingWindowManager;
import ghidra.program.model.data.*;
import ghidra.util.exception.AssertException;
/**
* Action for use in the composite data type editor.
* This action has help associated with it.
*/
public class AddBitFieldAction extends CompositeEditorTableAction {
private final static String ACTION_NAME = "Add Bitfield";
private final static String GROUP_NAME = BITFIELD_ACTION_GROUP;
private final static String DESCRIPTION =
"Add a bitfield at the position of a selected component";
private static String[] popupPath = new String[] { ACTION_NAME };
public AddBitFieldAction(CompositeEditorProvider provider) {
super(provider, EDIT_ACTION_PREFIX + ACTION_NAME, GROUP_NAME, popupPath, null, null);
setDescription(DESCRIPTION);
if (!(model instanceof CompEditorModel)) {
throw new AssertException("unsupported use");
}
adjustEnablement();
}
@Override
public void actionPerformed(ActionContext context) {
CompEditorModel editorModel = (CompEditorModel) model;
if (editorModel.getNumSelectedRows() != 1 || editorModel.isFlexibleArraySelection()) {
return;
}
int rowIndex = model.getSelectedRows()[0];
if (editorModel.isAligned()) {
// Insert before selected component
// ordinal based, user input needed:
// 1. bitfield base datatype
// 2. bitfield size
// 3. bitfield name (can be renamed later)
int ordinal = -1;
DataType baseDataType = null;
if (!editorModel.isAtEnd(rowIndex)) {
DataTypeComponent component = editorModel.getComponent(rowIndex);
ordinal = component.getOrdinal();
if (component.isBitFieldComponent()) {
BitFieldDataType currentBitfield = (BitFieldDataType) component.getDataType();
baseDataType = currentBitfield.getBaseDataType();
}
}
insertBitField(ordinal, baseDataType);
}
else {
BitFieldEditorDialog dlg =
new BitFieldEditorDialog(editorModel.viewComposite, provider.dtmService,
-(rowIndex + 1), ordinal -> refreshTableAndSelection(editorModel, ordinal));
Component c = provider.getComponent();
Window w = SwingUtilities.windowForComponent(c);
DockingWindowManager.showDialog(w, dlg, c);
}
requestTableFocus();
}
private void refreshTableAndSelection(CompEditorModel editorModel, int ordinal) {
editorModel.fireTableDataChanged();
editorModel.compositeInfoChanged();
JTable editorTable = provider.getTable();
editorTable.getSelectionModel().setSelectionInterval(ordinal, ordinal);
}
private void insertBitField(int ordinal, DataType baseDataType) {
// TODO Auto-generated method stub
}
@Override
public void adjustEnablement() {
boolean enabled = true;
CompEditorModel editorModel = (CompEditorModel) model;
if (editorModel.viewComposite == null || editorModel.getNumSelectedRows() != 1 ||
editorModel.isFlexibleArraySelection()) {
enabled = false;
}
setEnabled(enabled);
}
}

View file

@ -0,0 +1,302 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.plugin.core.compositeeditor;
import java.awt.event.MouseEvent;
import javax.swing.Icon;
import javax.swing.JComponent;
import docking.*;
import docking.action.DockingAction;
import docking.action.MenuData;
import ghidra.GhidraApplicationLayout;
import ghidra.app.plugin.core.analysis.DefaultDataTypeManagerService;
import ghidra.app.services.DataTypeManagerService;
import ghidra.framework.*;
import ghidra.program.model.data.*;
import ghidra.util.SystemUtilities;
import resources.ResourceManager;
public class BitFieldEditorDialog extends DialogComponentProvider {
private static final Icon ADD_ICON = ResourceManager.loadImage("images/Plus.png");
private static final Icon EDIT_ICON = ResourceManager.loadImage("images/move.png");
private static final Icon DELETE_ICON = ResourceManager.loadImage("images/edit-delete.png");
private DataTypeManagerService dtmService;
private Composite composite;
private CompositeChangeListener listener;
private BitFieldEditorPanel bitFieldEditorPanel; // for unaligned use case
BitFieldEditorDialog(Composite composite, DataTypeManagerService dtmService, int editOrdinal,
CompositeChangeListener listener) {
super("Edit " + getCompositeType(composite) + " Bitfield");
this.composite = composite;
this.listener = listener;
this.dtmService = dtmService;
addButtons();
addWorkPanel(buildWorkPanel(editOrdinal));
setRememberLocation(false);
setRememberSize(false);
addActions();
}
private void addButtons() {
addOKButton();
addCancelButton();
if (composite instanceof Structure) {
addApplyButton();
setApplyEnabled(false);
}
}
private static DataTypeComponent getEditComponent(ActionContext context, boolean bitFieldOnly) {
if (!(context instanceof BitFieldEditorPanel.BitFieldEditorContext)) {
return null;
}
BitFieldEditorPanel.BitFieldEditorContext editorContext =
(BitFieldEditorPanel.BitFieldEditorContext) context;
DataTypeComponent dtc = editorContext.getSelectedComponent();
if (dtc != null && (!bitFieldOnly || dtc.isBitFieldComponent())) {
return dtc;
}
return null;
}
private class EditBitFieldAction extends DockingAction {
EditBitFieldAction() {
super("Edit Bitfield", "BitFieldEditorDialog");
setPopupMenuData(new MenuData(new String[] { getName() }, EDIT_ICON));
}
@Override
public void actionPerformed(ActionContext context) {
DataTypeComponent bitfieldDtc = getEditComponent(context, true);
if (bitfieldDtc == null || !bitFieldEditorPanel.endCurrentEdit()) {
return;
}
initEdit(bitfieldDtc.getOrdinal());
}
@Override
public boolean isEnabledForContext(ActionContext context) {
return getEditComponent(context, true) != null;
}
}
private class AddBitFieldAction extends DockingAction {
AddBitFieldAction() {
super("Add Bitfield", "BitFieldEditorDialog");
setPopupMenuData(new MenuData(new String[] { getName() }, ADD_ICON));
}
@Override
public void actionPerformed(ActionContext context) {
if (!bitFieldEditorPanel.endCurrentEdit()) {
return;
}
BitFieldEditorPanel.BitFieldEditorContext editorContext =
(BitFieldEditorPanel.BitFieldEditorContext) context;
bitFieldEditorPanel.initAdd(null, editorContext.getAllocationOffset(),
editorContext.getSelectedBitOffset(), true);
setApplyEnabled(true);
}
@Override
public boolean isEnabledForContext(ActionContext context) {
return (context instanceof BitFieldEditorPanel.BitFieldEditorContext) &&
!bitFieldEditorPanel.isAdding();
}
}
private class DeleteComponentAction extends DockingAction {
DeleteComponentAction() {
super("Delete Component", "BitFieldEditorDialog");
setPopupMenuData(new MenuData(new String[] { getName() }, DELETE_ICON));
}
@Override
public void actionPerformed(ActionContext context) {
DataTypeComponent bitfieldDtc = getEditComponent(context, false);
if (bitfieldDtc == null) {
return;
}
int ordinal = bitfieldDtc.getOrdinal();
composite.delete(ordinal);
bitFieldEditorPanel.componentDeleted(ordinal);
if (listener != null) {
listener.componentChanged(ordinal);
}
}
@Override
public boolean isEnabledForContext(ActionContext context) {
return getEditComponent(context, false) != null;
}
}
private void addActions() {
addAction(new AddBitFieldAction());
addAction(new EditBitFieldAction());
addAction(new DeleteComponentAction());
}
@Override
protected void applyCallback() {
if (bitFieldEditorPanel.isEditing() && bitFieldEditorPanel.apply(listener)) {
setApplyEnabled(false);
}
}
@Override
protected void okCallback() {
applyCallback();
close();
}
@Override
public ActionContext getActionContext(MouseEvent event) {
ActionContext context = bitFieldEditorPanel.getActionContext(event);
if (context != null) {
return context;
}
return super.getActionContext(event);
}
@Override
protected void cancelCallback() {
// TODO: Should we cancel without asking?
if (!bitFieldEditorPanel.endCurrentEdit()) {
return;
}
super.cancelCallback();
}
private JComponent buildWorkPanel(int editOrdinal) {
bitFieldEditorPanel = new BitFieldEditorPanel(composite, dtmService);
if (editOrdinal < 0) {
initAdd(-editOrdinal - 1);
}
else {
initEdit(editOrdinal);
}
return bitFieldEditorPanel;
}
private static String getCompositeType(Composite composite) {
// currently supports unaligned case only!
if (composite.isInternallyAligned()) {
throw new IllegalArgumentException("Aligned use not supported");
}
String alignmentMode = composite.isInternallyAligned() ? "Aligned" : "Unaligned";
String type = (composite instanceof Union) ? "Union" : "Structure";
return alignmentMode + " " + type;
}
private void initAdd(int ordinal) {
DataType baseDataType = null;
int offset = 0;
if (ordinal < composite.getNumComponents()) {
DataTypeComponent dtc = composite.getComponent(ordinal);
offset = dtc.getOffset();
if (dtc.isBitFieldComponent()) {
baseDataType = ((BitFieldDataType) dtc.getDataType()).getBaseDataType();
}
}
else if (!composite.isNotYetDefined()) {
offset = composite.getLength();
}
// use previous or default base datatype
bitFieldEditorPanel.initAdd(baseDataType, offset, 0, false);
setApplyEnabled(true);
}
private void initEdit(int editOrdinal) throws ArrayIndexOutOfBoundsException {
DataTypeComponent dtc = composite.getComponent(editOrdinal);
if (!dtc.isBitFieldComponent()) {
throw new IllegalArgumentException("editOrdinal does not correspond to bitfield");
}
bitFieldEditorPanel.initEdit(dtc, getPreferredAllocationOffset(dtc), false);
setApplyEnabled(true);
}
private int getPreferredAllocationOffset(DataTypeComponent bitfieldDtc) {
if (composite instanceof Union) {
return 0;
}
BitFieldDataType bitfieldDt = (BitFieldDataType) bitfieldDtc.getDataType();
int offset = bitfieldDtc.getOffset();
int baseTypeSize = bitfieldDt.getBaseTypeSize();
if (bitfieldDtc.getLength() >= baseTypeSize) {
return offset; // do not adjust
}
DataOrganization dataOrganization = composite.getDataOrganization();
// Assume a reasonable alignment in identifying aligned offset
int alignment = CompositeAlignmentHelper.getPackedAlignment(dataOrganization,
Composite.NOT_PACKING, bitfieldDt.getBaseDataType(), bitfieldDt.getBaseTypeSize());
int adjustedOffset = offset - (offset % alignment);
// only adjust if bitfield fits within aligned offset
if (bitfieldDtc.getEndOffset() <= (adjustedOffset + baseTypeSize - 1)) {
return adjustedOffset;
}
return offset;
}
public static void main(String[] args) throws Exception {
//UniversalIdGenerator.initialize();
ApplicationConfiguration configuration = new HeadlessGhidraApplicationConfiguration();
configuration.setInitializeLogging(false);
Application.initializeApplication(new GhidraApplicationLayout(), configuration);
Structure s = new StructureDataType("Foo", 0);
DataTypeComponent dtcA =
s.insertBitFieldAt(0, 4, 16, IntegerDataType.dataType, 4, "BitA", null);
DataTypeComponent dtcZ =
s.insertBitFieldAt(0, 4, 16, IntegerDataType.dataType, 0, "BitZ", null);
DataTypeComponent dtcB =
s.insertBitFieldAt(0, 4, 12, IntegerDataType.dataType, 4, "BitB", null);
DataTypeComponent dtcC =
s.insertBitFieldAt(0, 4, 4, IntegerDataType.dataType, 4, "BitC", null);
DockingWindowManager winMgr = new DockingWindowManager("TEST", null, null);
BitFieldEditorDialog dlg =
new BitFieldEditorDialog(s, new DefaultDataTypeManagerService(), -1, null);
SystemUtilities.runSwingNow(() -> {
winMgr.setVisible(true);
DockingWindowManager.showDialog(null, dlg);
});
}
}

View file

@ -0,0 +1,581 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.plugin.core.compositeeditor;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.CellEditorListener;
import javax.swing.event.ChangeEvent;
import docking.ActionContext;
import docking.widgets.DropDownSelectionTextField;
import docking.widgets.OptionDialog;
import ghidra.app.plugin.core.compositeeditor.BitFieldPlacementComponent.BitAttributes;
import ghidra.app.plugin.core.compositeeditor.BitFieldPlacementComponent.BitFieldAllocation;
import ghidra.app.services.DataTypeManagerService;
import ghidra.app.util.datatype.DataTypeSelectionEditor;
import ghidra.app.util.datatype.NavigationDirection;
import ghidra.program.model.data.*;
import ghidra.util.Msg;
import ghidra.util.data.DataTypeParser.AllowedDataTypes;
import ghidra.util.layout.*;
import resources.ResourceManager;
/**
* <code>BitFieldEditorPanel</code> provides the ability to place bitfields
* within unaligned structures and unions.
*/
public class BitFieldEditorPanel extends JPanel {
private static final Icon DECREMENT_ICON = ResourceManager.loadImage("images/Minus.png");
private static final Icon INCREMENT_ICON = ResourceManager.loadImage("images/Plus.png");
private static final String ENTRY_ERROR_DIALOG_TITLE = "Bitfield Entry Error";
private DataTypeManagerService dtmService;
private Composite composite;
private JLabel allocationOffsetLabel;
JButton decrementButton;
JButton incrementButton;
private BitFieldPlacementComponent placementComponent;
private DataType baseDataType;
private DataTypeSelectionEditor dtChoiceEditor;
private JTextField fieldNameTextField;
private SpinnerNumberModel allocSizeModel;
private JSpinnerWithMouseWheel allocSizeInput;
private SpinnerNumberModel bitOffsetModel;
private JSpinnerWithMouseWheel bitOffsetInput;
private SpinnerNumberModel bitSizeModel;
private JSpinnerWithMouseWheel bitSizeInput;
private boolean updating = false;
BitFieldEditorPanel(Composite composite, DataTypeManagerService dtmService) {
super();
this.composite = composite;
if (composite.isInternallyAligned()) {
// A different bitfield editor should be used for aligned composites
throw new IllegalArgumentException("composite must be unaligned");
}
setLayout(new VerticalLayout(5));
setFocusTraversalKeysEnabled(true);
this.dtmService = dtmService;
setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
createPlacementPanel();
if (composite instanceof Structure) {
add(createAllocationOffsetPanel());
}
add(placementComponent);
add(createEntryPanel());
enableControls(false);
}
private JPanel createAllocationOffsetPanel() {
JPanel panel = new JPanel(new HorizontalLayout(5));
decrementButton = new JButton(DECREMENT_ICON);
decrementButton.setFocusable(false);
decrementButton.setToolTipText("Decrement allocation unit offset");
decrementButton.addActionListener(e -> adjustAllocationOffset(-1));
panel.add(decrementButton);
incrementButton = new JButton(INCREMENT_ICON);
incrementButton.setFocusable(false);
incrementButton.setToolTipText("Increment allocation unit offset");
incrementButton.addActionListener(e -> adjustAllocationOffset(1));
panel.add(incrementButton);
allocationOffsetLabel = new JLabel();
allocationOffsetLabel.setHorizontalTextPosition(SwingConstants.LEFT);
panel.add(allocationOffsetLabel);
return panel;
}
private void adjustAllocationOffset(int delta) {
int adjustedOffset = placementComponent.getAllocationOffset() + delta;
if (adjustedOffset < 0 || adjustedOffset > composite.getLength()) {
return;
}
placementComponent.setAllocationOffset(adjustedOffset);
updateAllocationOffsetLabel();
}
private void updateAllocationOffsetLabel() {
if (composite instanceof Structure) {
String text =
"Structure Offset of Allocation Unit: " + placementComponent.getAllocationOffset();
allocationOffsetLabel.setText(text);
int offset = placementComponent.getAllocationOffset();
decrementButton.setEnabled(offset > 0);
int length = composite.isNotYetDefined() ? 0 : composite.getLength();
incrementButton.setEnabled(offset < length);
}
}
private JPanel createEntryPanel() {
JComponent baseDataTypeEditor = createDataTypeChoiceEditor();
fieldNameTextField = new JTextField(20);
fieldNameTextField.setFocusable(true);
allocSizeModel = new SpinnerNumberModel(Long.valueOf(4), Long.valueOf(1), Long.valueOf(16),
Long.valueOf(1));
allocSizeInput = new JSpinnerWithMouseWheel(allocSizeModel);
bitOffsetModel = new SpinnerNumberModel(Long.valueOf(0), Long.valueOf(0), Long.valueOf(31),
Long.valueOf(1));
bitOffsetInput = new JSpinnerWithMouseWheel(bitOffsetModel);
bitSizeModel = new SpinnerNumberModel(Long.valueOf(4), Long.valueOf(0), Long.valueOf(4 * 8),
Long.valueOf(1));
bitSizeInput = new JSpinnerWithMouseWheel(bitSizeModel);
allocSizeModel.addChangeListener(e -> update());
bitSizeModel.addChangeListener(e -> update());
bitOffsetModel.addChangeListener(e -> update());
JPanel entryPanel = new JPanel(new TwoColumnPairLayout(5, 15, 5, 0));
entryPanel.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEtchedBorder(),
BorderFactory.createEmptyBorder(5, 5, 5, 5)));
entryPanel.setFocusCycleRoot(true);
entryPanel.add(new JLabel("Base Datatype:"));
entryPanel.add(baseDataTypeEditor);
entryPanel.add(new JLabel("Allocation Bytes:"));
entryPanel.add(allocSizeInput);
entryPanel.add(new JLabel("Field Name:"));
entryPanel.add(fieldNameTextField);
entryPanel.add(new JLabel("Bit Size:"));
entryPanel.add(bitSizeInput);
entryPanel.add(new JPanel());
entryPanel.add(new JPanel());
entryPanel.add(new JLabel("Bit Offset:"));
entryPanel.add(bitOffsetInput);
return entryPanel;
}
private JComponent createDataTypeChoiceEditor() {
dtChoiceEditor = new DataTypeSelectionEditor(dtmService, -1, AllowedDataTypes.BITFIELD_USE);
dtChoiceEditor.setConsumeEnterKeyPress(false);
dtChoiceEditor.setTabCommitsEdit(true);
//dtChoiceEditor.setPreferredDataTypeManager(composite.getDataTypeManager());
final DropDownSelectionTextField<DataType> dtChoiceTextField =
dtChoiceEditor.getDropDownTextField();
dtChoiceTextField.setBorder(UIManager.getBorder("TextField.border"));
dtChoiceEditor.addCellEditorListener(new CellEditorListener() {
@Override
public void editingCanceled(ChangeEvent e) {
dtChoiceEditor.setCellEditorValue(baseDataType); // restore
}
@Override
public void editingStopped(ChangeEvent e) {
if (!checkValidBaseDataType()) {
dtChoiceTextField.selectAll();
}
else {
baseDataType = dtChoiceEditor.getCellEditorValueAsDataType();
if (baseDataType != null) {
baseDataType = baseDataType.clone(composite.getDataTypeManager());
}
updateBitSizeModel();
NavigationDirection direction = dtChoiceEditor.getNavigationDirection();
if (direction == NavigationDirection.FORWARD) {
allocSizeInput.requestFocus();
}
else if (direction == NavigationDirection.BACKWARD) {
bitOffsetInput.requestFocus();
}
}
}
});
dtChoiceEditor.getBrowseButton().setFocusable(false);
JComponent editorComponent = dtChoiceEditor.getEditorComponent();
Dimension preferredSize = editorComponent.getPreferredSize();
editorComponent.setPreferredSize(new Dimension(200, preferredSize.height));
return editorComponent;
}
private JPanel createPlacementPanel() {
JPanel midPanel = new JPanel(new PairLayout(5, 5));
JPanel leftMidPanel = new JPanel(new VerticalLayout(13));
leftMidPanel.setBorder(BorderFactory.createEmptyBorder(12, 8, 12, 0));
JLabel byteOffsetLabel = new JLabel("Byte Offset:", SwingConstants.RIGHT);
byteOffsetLabel.setToolTipText("Byte Offset is relative to start of allocation unit");
leftMidPanel.add(byteOffsetLabel);
leftMidPanel.add(new JLabel("Bits:", SwingConstants.RIGHT));
midPanel.add(leftMidPanel);
placementComponent = new BitFieldPlacementComponent(composite);
placementComponent.setFont(UIManager.getFont("TextField.font"));
placementComponent.addMouseWheelListener(e -> bitSizeInput.mouseWheelMoved(e));
placementComponent.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() == 1 && e.getButton() == MouseEvent.BUTTON1 &&
bitOffsetInput.isEnabled()) {
setBitFieldOffset(e.getPoint());
}
// if (e.getClickCount() == 2 && endCurrentEdit() &&
// editBitFieldComponent(e.getPoint())) {
// enableControls(true);
// }
}
// public void mousePressed(MouseEvent e) {
// if (e.isPopupTrigger()) {
// setBitFieldPopupContext(e.getPoint());
// }
// };
});
JScrollPane scrollPane =
new JScrollPane(placementComponent, ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER,
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
scrollPane.getViewport().setBackground(getBackground());
midPanel.add(scrollPane);
return midPanel;
}
private boolean checkValidBaseDataType() {
DropDownSelectionTextField<DataType> textField = dtChoiceEditor.getDropDownTextField();
String dtName = textField.getText().trim();
try {
if (dtName.length() == 0 || !dtChoiceEditor.validateUserSelection()) {
Msg.showError(BitFieldEditorPanel.class, textField, ENTRY_ERROR_DIALOG_TITLE,
"Valid bitfield base datatype entry required");
return false;
}
}
catch (InvalidDataTypeException e) {
Msg.showError(BitFieldEditorPanel.class, textField, ENTRY_ERROR_DIALOG_TITLE,
"Invalid bitfield base datatype: " + e.getMessage());
return false;
}
return true;
}
void initAdd(DataType initialBaseDataType, int allocationOffset, int bitOffset,
boolean useCurrentAllocation) {
if (initialBaseDataType == null) {
initialBaseDataType = baseDataType;
}
if (!BitFieldDataType.isValidBaseDataType(initialBaseDataType)) {
initialBaseDataType = IntegerDataType.dataType.clone(composite.getDataTypeManager());
}
placementComponent.setAllocationOffset(allocationOffset);
long allocationSize = useCurrentAllocation ? (Long) allocSizeModel.getValue()
: initialBaseDataType.getLength();
placementComponent.initAdd((int) allocationSize, 1, bitOffset);
initControls(null, initialBaseDataType);
enableControls(true);
}
/**
* Initialize for edit of existing component or no component if bitfieldDtc is null.
* 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) {
String initialFieldName = null;
DataType initialBaseDataType = null;
int allocationSize = -1;
BitFieldAllocation bitFieldAllocation = placementComponent.getBitFieldAllocation();
if (bitFieldAllocation != null) {
allocationSize = bitFieldAllocation.getAllocationByteSize();
}
if (bitfieldDtc != null) {
if (!bitfieldDtc.isBitFieldComponent()) {
throw new IllegalArgumentException("unsupport data type component");
}
initialFieldName = bitfieldDtc.getFieldName();
BitFieldDataType bitfieldDt = (BitFieldDataType) bitfieldDtc.getDataType();
initialBaseDataType = bitfieldDt.getBaseDataType();
if (!useCurrentAllocation || allocationSize < 1) {
allocationSize = initialBaseDataType.getLength();
}
}
if (allocationSize < 1) {
allocationSize = 4;
}
// TODO: adjust offset and allocationSize if needed
placementComponent.setAllocationOffset(allocationOffset);
placementComponent.init(allocationSize, bitfieldDtc);
initControls(initialFieldName, initialBaseDataType);
enableControls(bitfieldDtc != null);
}
void componentDeleted(int ordinal) {
placementComponent.componentDeleted(ordinal);
}
private void initControls(String initialFieldName, DataType initialBaseDataType) {
updating = true;
try {
baseDataType = initialBaseDataType;
dtChoiceEditor.setCellEditorValue(initialBaseDataType);
fieldNameTextField.setText(initialFieldName);
// Use current placementComponent to obtain initial values
BitFieldAllocation bitFieldAllocation = placementComponent.getBitFieldAllocation();
allocSizeModel.setValue((long) bitFieldAllocation.getAllocationByteSize());
int allocBits = 8 * bitFieldAllocation.getAllocationByteSize();
bitSizeModel.setValue(1L);
bitOffsetModel.setMaximum((long) allocBits - 1);
bitOffsetModel.setValue((long) bitFieldAllocation.getBitOffset());
updateBitSizeModel();
updateAllocationOffsetLabel();
}
finally {
updating = false;
}
}
/**
* @return true if actively editing or adding a bitfield
*/
boolean isEditing() {
return placementComponent.isEditing();
}
/**
* @return true if actively adding a bitfield
*/
boolean isAdding() {
return placementComponent.isAdding();
}
boolean endCurrentEdit() {
if (placementComponent.isEditing()) {
String currentOp = placementComponent.isAdding() ? "add" : "edit";
int option = OptionDialog.showYesNoDialog(this, "Confirm Edit Action",
"Cancel current bitfield " + currentOp + " operation?");
if (option != OptionDialog.YES_OPTION) {
return false;
}
placementComponent.cancelEdit();
enableControls(false);
}
return true;
}
boolean apply(CompositeChangeListener listener) {
boolean deleteConflicts = false;
if (placementComponent.hasApplyConflict()) {
long allocationSize = (Long) allocSizeModel.getValue();
int option = OptionDialog.showOptionDialog(this, "Bitfield Conflict(s)",
"Bitfield placement conflicts with one or more components.\n" +
"Would you like to delete conflicts or move conflicts by " + allocationSize +
" bytes?",
"Delete Conflicts", "Move Conflicts", OptionDialog.WARNING_MESSAGE);
if (option == OptionDialog.CANCEL_OPTION) {
return false;
}
deleteConflicts = (option == OptionDialog.OPTION_ONE);
}
placementComponent.applyBitField(baseDataType, fieldNameTextField.getText().trim(),
deleteConflicts, listener);
enableControls(false);
return true;
}
private void enableControls(boolean enable) {
allocSizeInput.setEnabled(enable);
bitSizeInput.setEnabled(enable);
bitOffsetInput.setEnabled(enable);
if (!enable) {
// TODO: set placementComponent mode to NONE
bitOffsetModel.setValue(0L);
bitSizeModel.setValue(1L);
fieldNameTextField.setText(null);
}
}
private void setBitFieldOffset(Point point) {
int bitOffset = placementComponent.getBitOffset(point);
if (bitOffset >= 0) {
// long cast is required for auto-box to Long object
bitOffsetModel.setValue((long) bitOffset);
}
}
private DataTypeComponent getDataTypeComponent(Point p) {
BitAttributes attrs = placementComponent.getBitAttributes(p);
if (attrs != null) {
return attrs.getDataTypeComponent(true);
}
return null;
}
private void updateBitSizeModel() {
int allocSize = allocSizeModel.getNumber().intValue();
int allocBits = 8 * allocSize;
int baseTypeBits = baseDataType != null ? (8 * baseDataType.getLength()) : allocBits;
long maxBitSize = Math.min(allocBits, baseTypeBits);
bitSizeModel.setMaximum(maxBitSize);
if (maxBitSize < (Long) bitSizeModel.getValue()) {
bitSizeModel.setValue(maxBitSize);
}
}
private void update() {
if (updating) {
return;
}
updating = true;
try {
int allocSize = allocSizeModel.getNumber().intValue();
int allocBits = 8 * allocSize;
updateBitSizeModel();
bitOffsetModel.setMaximum(Long.valueOf(allocBits - 1));
int bitSize = bitSizeModel.getNumber().intValue();
int boff = bitOffsetModel.getNumber().intValue();
int total = bitSize + boff;
if (total > allocBits) {
boff -= total - allocBits;
if (boff < 0) {
boff = 0;
}
}
if (bitSize == 0) {
// force preferred placement of zero-length bit-field
// little-endian: lsb of byte
// big-endian: msb of byte
boff = 8 * (boff / 8);
if (placementComponent.isBigEndian()) {
boff += 7;
}
bitOffsetModel.setStepSize((long) 8);
}
else {
bitOffsetModel.setStepSize((long) 1);
}
bitOffsetModel.setValue(Long.valueOf(boff));
if (bitSize > allocBits) {
bitSize = allocBits;
bitSizeModel.setValue(Long.valueOf(bitSize));
}
placementComponent.refresh(allocSize, bitSize, boff);
}
finally {
updating = false;
}
}
ActionContext getActionContext(MouseEvent event) {
if (placementComponent == event.getSource()) {
Point p = event.getPoint();
return new BitFieldEditorContext(getDataTypeComponent(p),
placementComponent.getBitOffset(p));
}
return null;
}
class BitFieldEditorContext extends ActionContext {
private int selectedBitOffset;
private DataTypeComponent selectedDtc;
private BitFieldEditorContext(DataTypeComponent selectedDtc, int selectedBitOffset) {
this.selectedDtc = selectedDtc;
this.selectedBitOffset = selectedBitOffset;
}
DataTypeComponent getSelectedComponent() {
return selectedDtc;
}
public int getAllocationOffset() {
return placementComponent.getAllocationOffset();
}
public int getSelectedBitOffset() {
return selectedBitOffset;
}
}
private static class JSpinnerWithMouseWheel extends JSpinner implements MouseWheelListener {
JSpinnerWithMouseWheel(SpinnerNumberModel model) {
super(model);
addMouseWheelListener(this);
}
@Override
public void requestFocus() {
DefaultEditor editor = (DefaultEditor) getEditor();
editor.getTextField().requestFocus();
}
@Override
public void mouseWheelMoved(MouseWheelEvent mwe) {
if (!isEnabled()) {
return;
}
if (mwe.getScrollType() != MouseWheelEvent.WHEEL_UNIT_SCROLL) {
return;
}
SpinnerNumberModel m = (SpinnerNumberModel) getModel();
if (mwe.getScrollType() != MouseWheelEvent.WHEEL_UNIT_SCROLL) {
// TODO: Handle other mouse wheel modes
return;
}
Long value =
mwe.getUnitsToScroll() > 0 ? (Long) m.getPreviousValue() : (Long) m.getNextValue();
if (value != null) {
setValue(value);
mwe.consume();
}
}
}
}

View file

@ -0,0 +1,746 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.plugin.core.compositeeditor;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.util.Arrays;
import java.util.HashSet;
import javax.swing.JPanel;
import javax.swing.ToolTipManager;
import ghidra.program.model.data.*;
import ghidra.program.model.data.Composite;
import ghidra.util.Msg;
import ghidra.util.exception.AssertException;
public class BitFieldPlacementComponent extends JPanel {
private static final int CELL_HEIGHT = 30;
private static final int BIT_WIDTH = 10;
private static final int ZERO_BIT_WIDTH = 3;
private static final int BIT_SEPARATOR_THICKNESS = 1;
private static final int BYTE_SEPARATOR_THICKNESS = 2;
private static final int BYTE_WIDTH = 8 * (BIT_WIDTH + BIT_SEPARATOR_THICKNESS);
private static final int SCROLLBAR_THICKNESS = 10;
private static final int MY_HEIGHT = (2 * CELL_HEIGHT) + (3 * BYTE_SEPARATOR_THICKNESS);
private static final Color TEXT_COLOR = Color.black;
private static final Color LINE_COLOR = Color.black;
private static final Color BYTE_HEADER_COLOR = new Color(0xdfdfdf);
private static final Color UNDEFINED_BIT_COLOR = new Color(0xe8e8e8);
private static final Color BITFIELD_BITS_COLOR = Color.green;
private static final Color CONFLICT_BITS_COLOR = Color.yellow;
private static final Color BITFIELD_COMPONENT_COLOR = new Color(0xcfcfff);
private static final Color NON_BITFIELD_COMPONENT_COLOR = new Color(0xafafff);
private static final Color INTERIOR_LINE_COLOR = new Color(0xbfbfbf);
private final Composite composite;
private final boolean bigEndian;
private int allocationOffset;
private BitFieldAllocation bitFieldAllocation;
private EditMode editMode = EditMode.NONE;
private int editOrdinal = -1; // FIXME: improve insert use
BitFieldPlacementComponent(Composite composite) {
this.composite = composite;
bigEndian = composite.getDataOrganization().isBigEndian();
updatePreferredSize();
setSize(getPreferredSize());
setMinimumSize(getPreferredSize());
ToolTipManager.sharedInstance().registerComponent(this);
}
private int getPreferredHeight() {
return MY_HEIGHT + SCROLLBAR_THICKNESS;
}
private int getPreferredWidth() {
if (bitFieldAllocation == null) {
return 10;
}
int extraLineSpace = BYTE_SEPARATOR_THICKNESS - BIT_SEPARATOR_THICKNESS;
return (bitFieldAllocation.allocationByteSize * BYTE_WIDTH) + BYTE_SEPARATOR_THICKNESS +
extraLineSpace;
}
public boolean isBigEndian() {
return bigEndian;
}
public BitFieldAllocation getBitFieldAllocation() {
return bitFieldAllocation;
}
int getBitOffset(Point point) {
int bitWidthWithLine = BIT_WIDTH + BIT_SEPARATOR_THICKNESS;
int cellIndex = (point.x - BYTE_SEPARATOR_THICKNESS) / bitWidthWithLine;
return (8 * bitFieldAllocation.allocationByteSize) - cellIndex - 1;
}
private void updatePreferredSize() {
setPreferredSize(new Dimension(getPreferredWidth(), getPreferredHeight()));
revalidate();
}
void refresh(int allocationByteSize, int bitSize, int bitOffset) {
bitFieldAllocation = new BitFieldAllocation(allocationByteSize, bitSize, bitOffset);
updatePreferredSize();
repaint();
}
void setAllocationOffset(int allocationOffset) {
this.allocationOffset = allocationOffset;
if (bitFieldAllocation != null) {
bitFieldAllocation.refresh();
repaint();
}
}
int getAllocationOffset() {
return allocationOffset;
}
void initAdd(int allocationByteSize, int bitSize, int bitOffset) {
editMode = EditMode.ADD;
editOrdinal = -1;
refresh(allocationByteSize, bitSize, bitOffset);
}
void init(int allocationByteSize, DataTypeComponent editComponent) {
if (editComponent == null) {
editMode = EditMode.NONE;
editOrdinal = -1;
refresh(allocationByteSize, 0, 0);
return;
}
// TODO: consider showing a animated hashed-box around original bit boundary
// of the component being modified
editMode = EditMode.EDIT;
editOrdinal = editComponent.getOrdinal();
BitFieldPlacement placement = new BitFieldPlacement(editComponent, allocationByteSize);
bitFieldAllocation =
new BitFieldAllocation(allocationByteSize, placement.rightBit - placement.leftBit + 1,
(8 * allocationByteSize) - placement.rightBit - 1);
updatePreferredSize();
repaint();
}
boolean hasApplyConflict() {
if (composite instanceof Union) {
return false;
}
for (BitAttributes attrs : bitFieldAllocation.bitAttributes) {
if (attrs.hasConflict() && (attrs.isAddBitField() || attrs.isEditField())) {
return true;
}
}
return false;
}
/**
* @return true if editing or adding a bitfield
*/
boolean isEditing() {
return editMode != EditMode.NONE;
}
/**
* @return true if adding a bitfield
*/
boolean isAdding() {
return editMode == EditMode.ADD;
}
void cancelEdit() {
if (editMode != EditMode.NONE) {
editMode = EditMode.NONE;
editOrdinal = -1;
refresh(bitFieldAllocation.allocationByteSize, 0, 0);
}
}
void componentDeleted(int ordinal) {
if (editMode == EditMode.EDIT) {
if (ordinal == editOrdinal) {
// unexpected removal
editMode = EditMode.ADD;
editOrdinal = -1;
}
else if (ordinal < editOrdinal) {
--editOrdinal;
}
}
bitFieldAllocation.refresh();
repaint();
}
void applyBitField(DataType baseDataType, String fieldName, boolean deleteConflicts,
CompositeChangeListener listener) {
HashSet<Integer> ordinalDeleteSet = new HashSet<>();
if (editOrdinal >= 0) {
composite.delete(editOrdinal);
}
if (deleteConflicts) {
for (BitAttributes attrs : bitFieldAllocation.bitAttributes) {
if (attrs.hasConflict() && (attrs.isAddBitField() || attrs.isEditField())) {
// Edit component will always be on top of conflict
ordinalDeleteSet.add(attrs.getConflict().getOrdinal());
}
}
}
Integer[] ordinalsToDelete = ordinalDeleteSet.toArray(new Integer[ordinalDeleteSet.size()]);
Arrays.sort(ordinalsToDelete); // delete from end first
int ordinal = composite.getNumComponents();
for (int i = ordinalsToDelete.length - 1; i >= 0; i--) {
ordinal = ordinalsToDelete[i];
composite.delete(ordinal);
}
try {
String name = (fieldName != null && fieldName.length() != 0) ? fieldName : null;
DataTypeComponent dtc;
if (composite instanceof Union) {
dtc = composite.insertBitField(ordinal, bitFieldAllocation.allocationByteSize,
bitFieldAllocation.bitOffset, baseDataType, bitFieldAllocation.bitSize, name,
null);
}
else {
Structure struct = (Structure) composite;
dtc = struct.insertBitFieldAt(allocationOffset,
bitFieldAllocation.allocationByteSize, bitFieldAllocation.bitOffset,
baseDataType, bitFieldAllocation.bitSize, name, null);
}
if (listener != null) {
listener.componentChanged(dtc.getOrdinal());
}
}
catch (ArrayIndexOutOfBoundsException | InvalidDataTypeException e) {
Msg.error(this, "Unexpected bitfield apply error", e);
}
finally {
editMode = EditMode.NONE;
editOrdinal = -1;
bitFieldAllocation.refresh();
repaint();
}
}
BitAttributes getBitAttributes(Point p) {
if (bitFieldAllocation == null) {
return null;
}
for (BitAttributes attrs : bitFieldAllocation.bitAttributes) {
if (attrs.rectangle != null && attrs.rectangle.contains(p)) {
return attrs;
}
}
return null;
}
@Override
public String getToolTipText(MouseEvent e) {
BitAttributes attrs = getBitAttributes(e.getPoint());
return attrs != null ? attrs.getTip() : null;
}
@Override
public void paintComponent(Graphics g) {
//super.paintComponent(g);
int height = getHeight();
int width = getWidth();
g.setColor(getBackground());
g.fillRect(0, 0, width, height);
if (bitFieldAllocation == null) {
return;
}
width = getPreferredWidth();
height = MY_HEIGHT;
g.setColor(LINE_COLOR);
g.fillRect(0, 0, width, BYTE_SEPARATOR_THICKNESS); // top line
g.fillRect(0, 0, BYTE_SEPARATOR_THICKNESS, height); // left line (full height)
g.fillRect(width - BYTE_SEPARATOR_THICKNESS, 0, BYTE_SEPARATOR_THICKNESS, height); // right line (full height)
int y = CELL_HEIGHT + BYTE_SEPARATOR_THICKNESS;
g.fillRect(0, y, width, BYTE_SEPARATOR_THICKNESS); // next horizontal line
y += CELL_HEIGHT + BYTE_SEPARATOR_THICKNESS;
g.fillRect(0, y, width, BYTE_SEPARATOR_THICKNESS); // bottom line
paintByteHeader(g, BYTE_SEPARATOR_THICKNESS, allocationOffset);
paintBits((Graphics2D) g, (2 * BYTE_SEPARATOR_THICKNESS) + CELL_HEIGHT);
}
private void paintByteHeader(Graphics g, int y, int baseOffset) {
int byteSize = bitFieldAllocation.allocationByteSize;
int x = BYTE_SEPARATOR_THICKNESS;
for (int i = 0; i < byteSize; i++) {
// last byte header needs to slightly wider
int w = BYTE_WIDTH;
if (i == (byteSize - 1)) {
w += BYTE_SEPARATOR_THICKNESS - BIT_SEPARATOR_THICKNESS;
}
paintByte(g, x, y, w, i, baseOffset);
x += w;
g.fillRect(x - BYTE_SEPARATOR_THICKNESS, y, BYTE_SEPARATOR_THICKNESS, CELL_HEIGHT); // line after each byte
}
}
private void paintByte(Graphics g, int x, int y, int width, int byteIndex, int baseOffset) {
Color curColor = g.getColor();
Font curFont = g.getFont();
int offset = byteIndex;
if (!bigEndian) {
offset = bitFieldAllocation.allocationByteSize - byteIndex - 1;
}
offset += baseOffset;
g.setColor(BYTE_HEADER_COLOR);
g.fillRect(x, y, width - BYTE_SEPARATOR_THICKNESS, CELL_HEIGHT); // byte fill
g.setColor(TEXT_COLOR);
Font textFont = getFont().deriveFont(Font.BOLD);
g.setFont(textFont);
String offsetStr = Integer.toString(offset);
FontMetrics fontMetrics = g.getFontMetrics();
int textY = y + (CELL_HEIGHT + fontMetrics.getMaxAscent()) / 2;
int textX = x + (width - BYTE_SEPARATOR_THICKNESS - fontMetrics.stringWidth(offsetStr)) / 2;
g.drawString(offsetStr, textX, textY);
g.setColor(curColor);
g.setFont(curFont);
}
private void paintBits(Graphics2D g, int y) {
Color curColor = g.getColor();
BitAttributes[] bitAttributes = bitFieldAllocation.bitAttributes;
int x = BYTE_SEPARATOR_THICKNESS;
if (bitAttributes[0] != null && bitAttributes[0].leftEndType == EndBitType.TRUNCATED_END) {
// adjust left-most line to reflect truncated component
x -= BIT_SEPARATOR_THICKNESS; // backup to left line location
drawTruncationLine(g, x, y, CELL_HEIGHT);
x += BIT_SEPARATOR_THICKNESS;
}
BitAttributes prevAttrs = null;
for (int n = 0; n < bitAttributes.length; n++) {
BitAttributes attrs = bitAttributes[n];
boolean paintRightLine = n != (bitAttributes.length - 1);
attrs.paint(g, prevAttrs, paintRightLine);
x += attrs.rectangle.width;
prevAttrs = attrs;
}
if (prevAttrs != null && prevAttrs.rightEndType == EndBitType.TRUNCATED_END) {
x -= BIT_SEPARATOR_THICKNESS; // backup to right line location
drawTruncationLine(g, x, y, CELL_HEIGHT);
}
g.setColor(curColor);
}
private static final Stroke DASH = new BasicStroke(1, BasicStroke.CAP_SQUARE,
BasicStroke.JOIN_MITER, 2, new float[] { 3, 3 }, 0);
private void drawTruncationLine(Graphics2D g, int x, int y, int height) {
Color c = g.getColor();
Stroke s = g.getStroke();
g.setColor(getBackground()); // draw over black line
g.setStroke(DASH);
g.drawLine(x, y, x, y + height - 1);
g.setColor(c);
g.setStroke(s);
}
private class BitFieldPlacement {
int leftBit;
int rightBit;
boolean truncateLeft;
boolean truncateRight;
boolean zeroBitField;
BitFieldPlacement(DataTypeComponent component, int allocationByteSize) {
int startOffset = component.getOffset();
int offsetAdjBytes = startOffset - allocationOffset;
if (!bigEndian) {
offsetAdjBytes = allocationByteSize - offsetAdjBytes - component.getLength();
}
int leftAdj = 8 * offsetAdjBytes;
if (component.isBitFieldComponent()) {
BitFieldDataType bitfield = (BitFieldDataType) component.getDataType();
int storageSize = 8 * bitfield.getStorageSize();
rightBit = leftAdj + storageSize - bitfield.getBitOffset() - 1;
// Use effective bit-size since unaligned uses are only concerned with actual
// bits stored (NOTE: this may cause a transition from declared to effective
// bit-size when editing a bitfield where the these bit-sizes differ).
int bitSize = bitfield.getBitSize();
if (bitSize == 0) {
zeroBitField = true;
leftBit = rightBit;
}
else {
leftBit = rightBit - bitSize + 1;
}
}
else {
int componentSize = 8 * component.getLength();
rightBit = leftAdj + componentSize - 1;
leftBit = leftAdj;
}
// System.out.println(component.toString() + " >>> " + leftBit + " - " + rightBit +
// " oa: " + offsetAdjBytes);
// clip to allocation region
int allocBitSize = 8 * allocationByteSize;
truncateRight = false;
if (rightBit >= allocBitSize) {
truncateRight = true;
rightBit = allocBitSize - 1;
}
truncateLeft = false;
if (leftBit < 0) {
truncateLeft = true;
leftBit = 0;
}
}
}
class BitFieldAllocation {
private final int allocationByteSize;
private int bitSize;
private int bitOffset;
private boolean hasConflict;
// bit layout normalized to big-endian layout
// left-most allocation msb has array index of 0
private BitAttributes[] bitAttributes;
BitFieldAllocation(int allocationByteSize, int bitSize, int bitOffset) {
if (allocationByteSize <= 0 || (bitSize + bitOffset) > (8 * allocationByteSize)) {
throw new IllegalArgumentException("allocation size too small");
}
this.allocationByteSize = allocationByteSize;
this.bitSize = bitSize;
this.bitOffset = bitOffset;
refresh();
}
private void refresh() {
allocateBits();
layoutBits();
}
private void allocateBits() {
bitAttributes = new BitAttributes[8 * allocationByteSize];
if (composite instanceof Structure) {
allocateStructureMembers((Structure) composite);
}
if (editMode != EditMode.NONE) {
int rightMostBit = bitAttributes.length - bitOffset - 1;
if (bitSize == 0) {
allocateZeroBitField(null, rightMostBit);
}
else {
int leftMostBit = rightMostBit - bitSize + 1;
allocateBits(null, leftMostBit, rightMostBit, false, false);
}
}
// fill-in unallocated bits
for (int i = 0; i < bitAttributes.length; i++) {
if (bitAttributes[i] == null) {
bitAttributes[i] = new BitAttributes();
}
}
}
private void layoutBits() {
int x = BYTE_SEPARATOR_THICKNESS;
int y = (2 * BYTE_SEPARATOR_THICKNESS) + CELL_HEIGHT;
int width = BIT_WIDTH + BIT_SEPARATOR_THICKNESS;
for (BitAttributes attrs : bitAttributes) {
attrs.layout(x, y, width, CELL_HEIGHT);
x += width;
}
}
private void allocateStructureMembers(Structure struct) {
int allocationEndOffset = allocationOffset + allocationByteSize - 1;
for (DataTypeComponent component : struct.getDefinedComponents()) {
if (component.getOrdinal() == editOrdinal) {
continue;
}
int startOffset = component.getOffset();
int endOffset = component.getEndOffset();
if (endOffset < allocationOffset) {
continue;
}
if (startOffset > allocationEndOffset) {
continue;
}
BitFieldPlacement placement = new BitFieldPlacement(component, allocationByteSize);
if (placement.zeroBitField) {
allocateZeroBitField(component, placement.rightBit);
}
else {
allocateBits(component, placement.leftBit, placement.rightBit,
placement.truncateLeft, placement.truncateRight);
}
}
}
private void allocateBits(DataTypeComponent dtc, int leftBit, int rightBit,
boolean truncatedLeft, boolean truncatedRight) {
if (truncatedLeft && truncatedRight && leftBit == rightBit) {
throw new AssertException();
}
int startIndex = Math.max(0, leftBit);
int endIndex = Math.min(bitAttributes.length - 1, rightBit);
for (int i = startIndex; i <= endIndex; i++) {
EndBitType leftEndType = EndBitType.NOT_END;
EndBitType rightEndType = EndBitType.NOT_END;
if (dtc != null) {
if (i == leftBit) {
leftEndType = truncatedLeft ? EndBitType.TRUNCATED_END : EndBitType.END;
}
if (i == rightBit) {
rightEndType = truncatedLeft ? EndBitType.TRUNCATED_END : EndBitType.END;
}
}
bitAttributes[i] =
new BitAttributes(dtc, leftEndType, rightEndType, bitAttributes[i]);
hasConflict |= bitAttributes[i].hasConflict();
}
}
private void allocateZeroBitField(DataTypeComponent dtc, int bitIndex) {
bitAttributes[bitIndex] = new BitAttributes(dtc, bitAttributes[bitIndex]);
}
public int getAllocationByteSize() {
return allocationByteSize;
}
public int getBitOffset() {
return bitOffset;
}
public int getBitSize() {
return bitSize;
}
}
static enum EditMode {
NONE, ADD, EDIT;
}
static enum EndBitType {
NOT_END, END, TRUNCATED_END;
}
class BitAttributes {
private final DataTypeComponent dtc;
private final EndBitType leftEndType;
private final EndBitType rightEndType;
private final BitAttributes conflict;
private boolean zeroBitfield;
private boolean unallocated;
Rectangle rectangle;
/**
* Unallocated bitfield
* @param dtc
* @param conflict
*/
BitAttributes() {
dtc = null;
leftEndType = EndBitType.NOT_END;
rightEndType = EndBitType.NOT_END;
conflict = null;
unallocated = true;
}
/**
* Zero-length bitfield
* @param dtc
* @param conflict
*/
BitAttributes(DataTypeComponent dtc, BitAttributes conflict) {
this(dtc, dtc != null ? EndBitType.END : EndBitType.NOT_END,
dtc != null ? EndBitType.END : EndBitType.NOT_END, conflict);
zeroBitfield = true;
}
BitAttributes(DataTypeComponent dtc, EndBitType leftEndType, EndBitType rightEndType,
BitAttributes conflict) {
this.dtc = dtc;
this.leftEndType = leftEndType;
this.rightEndType = rightEndType;
this.conflict = conflict;
if (conflict != null) {
leftEndType = conflict.leftEndType;
rightEndType = conflict.rightEndType;
}
}
boolean isAddBitField() {
return !unallocated && dtc == null;
}
boolean isEditField() {
return dtc != null && dtc.getOrdinal() == editOrdinal;
}
boolean hasConflict() {
return getConflict() != null;
}
public DataTypeComponent getConflict() {
BitAttributes c = conflict;
while (c != null && c.dtc.isZeroBitFieldComponent()) {
c = conflict.conflict;
}
return c != null ? c.dtc : null;
}
void layout(int x, int y, int width, int height) {
rectangle = new Rectangle(x, y, width, height);
}
void paint(Graphics g, BitAttributes bitAttrsToLeft, boolean paintRightLine) {
// bit box
Color c = getColor();
g.setColor(c);
g.fillRect(rectangle.x, rectangle.y, BIT_WIDTH, CELL_HEIGHT);
if (zeroBitfield ||
(dtc != null && conflict != null && conflict.dtc.isZeroBitFieldComponent())) {
c = BITFIELD_BITS_COLOR;
Color lineColor = INTERIOR_LINE_COLOR;
if (dtc != null) {
c = BITFIELD_COMPONENT_COLOR;
lineColor = LINE_COLOR;
}
// little-endian: place strip on right-side of bit
// big-endian: place strip on left-side of bit
int xStrip = bigEndian ? rectangle.x : (rectangle.x + BIT_WIDTH - ZERO_BIT_WIDTH);
int xLine =
bigEndian ? (xStrip + ZERO_BIT_WIDTH) : (xStrip - BIT_SEPARATOR_THICKNESS);
g.setColor(c);
g.fillRect(xStrip, rectangle.y, ZERO_BIT_WIDTH, CELL_HEIGHT);
g.setColor(lineColor);
g.fillRect(xLine, rectangle.y, BIT_SEPARATOR_THICKNESS, CELL_HEIGHT);
}
if (bitAttrsToLeft != null && dtc != null && bitAttrsToLeft.unallocated) {
// draw left bit line if we know better than the undefined to our left
g.setColor(LINE_COLOR);
g.fillRect(rectangle.x - BIT_SEPARATOR_THICKNESS, rectangle.y,
BIT_SEPARATOR_THICKNESS, CELL_HEIGHT);
}
if (paintRightLine) {
// draw right bit line
Color lineColor = LINE_COLOR;
if (rightEndType == EndBitType.NOT_END) {
lineColor = INTERIOR_LINE_COLOR;
}
g.setColor(lineColor);
g.fillRect(rectangle.x + BIT_WIDTH, rectangle.y, BIT_SEPARATOR_THICKNESS,
CELL_HEIGHT);
}
}
Color getColor() {
// zero-length stripe will be added later and
// should treated as a conflict
if (unallocated) {
return UNDEFINED_BIT_COLOR;
}
if (conflict != null && !conflict.unallocated) {
if (zeroBitfield) {
return conflict.getColor();
}
if (!conflict.dtc.isZeroBitFieldComponent()) {
return CONFLICT_BITS_COLOR;
}
}
if (zeroBitfield) {
return UNDEFINED_BIT_COLOR;
}
if (dtc == null) {
return BITFIELD_BITS_COLOR; // edit field
}
return dtc.isBitFieldComponent() ? BITFIELD_COMPONENT_COLOR
: NON_BITFIELD_COMPONENT_COLOR;
}
String getTip() {
if (dtc == null) {
return null;
}
String name = dtc.getFieldName();
return dtc.getDataType().getDisplayName() +
(name != null ? (" " + dtc.getFieldName()) : "");
}
DataTypeComponent getDataTypeComponent(boolean ignoreEditComponent) {
if (dtc != null && (dtc.getOrdinal() != editOrdinal || !ignoreEditComponent)) {
return dtc;
}
if (conflict != null) {
return conflict.dtc;
}
return null;
}
}
}

View file

@ -457,8 +457,7 @@ public abstract class CompEditorModel extends CompositeEditorModel {
protected abstract DataTypeComponent insert(int rowIndex, DataType dataType, int length,
String name, String comment) throws InvalidDataTypeException;
protected abstract void insert(int rowIndex, DataType dataType, int length, String name,
String comment, int numCopies) throws InvalidDataTypeException;
protected abstract void insert(int rowIndex, DataType dataType, int length, int numCopies) throws InvalidDataTypeException;
/**
* Add a DataType component into to an editable structure
@ -479,7 +478,7 @@ public abstract class CompEditorModel extends CompositeEditorModel {
return;
}
insert(rowIndex, dataType, dtLen, null, null, multiple);
insert(rowIndex, dataType, dtLen, multiple);
}
/* (non-Javadoc)

View file

@ -0,0 +1,26 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.plugin.core.compositeeditor;
public interface CompositeChangeListener {
/**
* Indicates the ordinal of the component which has been added, updated or cleared.
* @param ordinal component ordinal
*/
void componentChanged(int ordinal);
}

View file

@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,18 +15,18 @@
*/
package ghidra.app.plugin.core.compositeeditor;
public interface EditorAction extends CompositeEditorModelListener {
static final String BASIC_ACTION_GROUP = "1_BASIC_EDITOR_ACTION";
static final String FAVORITES_ACTION_GROUP = "2_FAVORITE_DT_EDITOR_ACTION";
static final String CYCLE_ACTION_GROUP = "3_CYCLE_DT_EDITOR_ACTION";
static final String COMPONENT_ACTION_GROUP = "4_COMPONENT_EDITOR_ACTION";
static final String BITFIELD_ACTION_GROUP = "5_COMPONENT_EDITOR_ACTION";
/**
* Method to set the action's enablement based on the associated editor
* model's current state.
*/
public void adjustEnablement();
}

View file

@ -997,13 +997,14 @@ class StructureEditorModel extends CompEditorModel {
}
@Override
protected void insert(int rowIndex, DataType dataType, int length, String name, String comment,
int numCopies) throws InvalidDataTypeException {
protected void insert(int rowIndex, DataType dataType, int length, int numCopies)
throws InvalidDataTypeException {
checkIsAllowableDataType(dataType, true);
int componentOrdinal = convertRowToOrdinal(rowIndex);
try {
((Structure) viewComposite).insert(componentOrdinal, dataType, length, name, comment,
numCopies);
for (int i = 0; i < numCopies; i++) {
viewComposite.insert(componentOrdinal, dataType, length);
}
if (rowIndex <= row) {
row += numCopies;
}
@ -1026,9 +1027,6 @@ class StructureEditorModel extends CompEditorModel {
return struct.setFlexibleArrayComponent(dt, dtc.getFieldName(), dtc.getComment());
}
/* (non-Javadoc)
* @see ghidra.app.plugin.datamanager.editor.CompositeEditorModel#replace(int, ghidra.program.model.data.DataType, int, java.lang.String, java.lang.String)
*/
@Override
protected DataTypeComponent replace(int rowIndex, DataType dataType, int length, String name,
String comment) throws InvalidDataTypeException {

View file

@ -15,11 +15,10 @@
*/
package ghidra.app.plugin.core.compositeeditor;
import ghidra.framework.plugintool.Plugin;
import ghidra.program.model.data.Structure;
import javax.swing.ImageIcon;
import ghidra.framework.plugintool.Plugin;
import ghidra.program.model.data.Structure;
import resources.ResourceManager;
/**
@ -45,44 +44,44 @@ public class StructureEditorProvider extends CompositeEditorProvider {
editorModel.selectionChanged();
}
/* (non-Javadoc)
* @see ghidra.app.plugin.datamanager.editor.EditorProvider#getName()
*/
@Override
public String getName() {
return "Structure Editor";
}
/* (non-Javadoc)
* @see ghidra.app.plugin.compositeeditor.CompositeEditorProvider#createActions()
*/
@Override
protected CompositeEditorTableAction[] createActions() {
//@formatter:off
return new CompositeEditorTableAction[] {
new ApplyAction(this),
// new ToggleLockAction(this),
new InsertUndefinedAction(this), new MoveUpAction(this), new MoveDownAction(this),
new ClearAction(this), new DuplicateAction(this), new DuplicateMultipleAction(this),
new DeleteAction(this), new PointerAction(this), new ArrayAction(this),
new ShowComponentPathAction(this), new UnpackageAction(this),
new EditComponentAction(this), new EditFieldAction(this), new HexNumbersAction(this),
new CreateInternalStructureAction(this) };
// new ToggleLockAction(this),
new InsertUndefinedAction(this),
new MoveUpAction(this),
new MoveDownAction(this),
new ClearAction(this),
new DuplicateAction(this),
new DuplicateMultipleAction(this),
new DeleteAction(this),
new PointerAction(this),
new ArrayAction(this),
new ShowComponentPathAction(this),
new UnpackageAction(this),
new EditComponentAction(this),
new EditFieldAction(this),
new HexNumbersAction(this),
new CreateInternalStructureAction(this),
new AddBitFieldAction(this)
};
//@formatter:on
}
/* (non-Javadoc)
* @see ghidra.app.plugin.compositeeditor.CompositeEditorProvider#getHelpName()
*/
@Override
public String getHelpName() {
return "Structure_Editor";
}
/* (non-Javadoc)
* @see ghidra.app.plugin.compositeeditor.CompositeEditorProvider#getHelpTopic()
*/
@Override
public String getHelpTopic() {
return "DataTypeEditors";
}
}

View file

@ -410,10 +410,10 @@ class UnionEditorModel extends CompEditorModel {
}
@Override
public void insert(int rowIndex, DataType dataType, int length, String name, String comment,
int numCopies) throws InvalidDataTypeException {
public void insert(int rowIndex, DataType dataType, int length, int numCopies)
throws InvalidDataTypeException {
for (int ii = 0; ii < numCopies; ++ii) {
insert(rowIndex + ii, dataType, length, name, comment);
insert(rowIndex + ii, dataType, length, null, null);
}
}

View file

@ -15,11 +15,10 @@
*/
package ghidra.app.plugin.core.compositeeditor;
import ghidra.framework.plugintool.Plugin;
import ghidra.program.model.data.Union;
import javax.swing.ImageIcon;
import ghidra.framework.plugintool.Plugin;
import ghidra.program.model.data.Union;
import resources.ResourceManager;
/**
@ -49,32 +48,34 @@ public class UnionEditorProvider extends CompositeEditorProvider {
return "Union Editor";
}
/* (non-Javadoc)
* @see ghidra.app.plugin.compositeeditor.CompositeEditorProvider#createActions()
*/
@Override
protected CompositeEditorTableAction[] createActions() {
return new CompositeEditorTableAction[] { new ApplyAction(this), new MoveUpAction(this),
new MoveDownAction(this), new DuplicateAction(this), new DuplicateMultipleAction(this),
new DeleteAction(this), new PointerAction(this), new ArrayAction(this),
new ShowComponentPathAction(this), new EditComponentAction(this),
new EditFieldAction(this), new HexNumbersAction(this) };
//@formatter:off
return new CompositeEditorTableAction[] {
new ApplyAction(this),
new MoveUpAction(this),
new MoveDownAction(this),
new DuplicateAction(this),
new DuplicateMultipleAction(this),
new DeleteAction(this),
new PointerAction(this),
new ArrayAction(this),
new ShowComponentPathAction(this),
new EditComponentAction(this),
new EditFieldAction(this),
new HexNumbersAction(this),
new AddBitFieldAction(this)
};
//@formatter:on
}
/* (non-Javadoc)
* @see ghidra.app.plugin.compositeeditor.CompositeEditorProvider#getHelpName()
*/
@Override
public String getHelpName() {
return "Structure_Editor";
}
/* (non-Javadoc)
* @see ghidra.app.plugin.compositeeditor.CompositeEditorProvider#getHelpTopic()
*/
@Override
public String getHelpTopic() {
return "DataTypeEditors";
}
}

View file

@ -71,7 +71,7 @@ public class DataTypePreviewPlugin extends ProgramPlugin {
private GoToService goToService;
private DockingAction addAction;
private DockingAction deleteAction;
private DataTypeManager dataTypeManager;
private LayeredDataTypeManager dataTypeManager;
private Program activeProgram;
private SwingUpdateManager updateManager = new SwingUpdateManager(650, () -> updatePreview());
@ -156,7 +156,33 @@ public class DataTypePreviewPlugin extends ProgramPlugin {
updateModel();
}
void updateModel() {
private List<DataTypePath> getModelDataTypePaths() {
// retain order as they currently exist within model
List<DataTypePath> list = new ArrayList<>();
for (Preview preview : model.getModelData()) {
if (preview instanceof DataTypePreview) {
list.add(preview.getDataType().getDataTypePath());
}
else if (preview instanceof DataTypeComponentPreview) {
DataTypeComponentPreview componentPreview = (DataTypeComponentPreview) preview;
if (componentPreview.getParent() == null) {
list.add(preview.getDataType().getDataTypePath());
}
}
}
return list;
}
private void updateModel() {
// NOTE: data types do not respond to switching the data organization object
// since this is cached internal to the data type at time of construction.
// We must purge old datatypes and have them re-instantiated by the
// datatype manager
List<DataTypePath> dtPaths = getModelDataTypePaths();
model.removeAll();
dataTypeManager.invalidate();
int transactionId = dataTypeManager.startTransaction("realign");
try {
Iterator<Composite> allComposites = dataTypeManager.getAllComposites();
@ -164,14 +190,19 @@ public class DataTypePreviewPlugin extends ProgramPlugin {
Composite composite = allComposites.next();
if (composite.isInternallyAligned()) {
composite.realign();
model.removeAll(composite);
model.add(composite);
}
}
}
finally {
dataTypeManager.endTransaction(transactionId, true);
}
for (DataTypePath dtPath : dtPaths) {
DataType dataType = dataTypeManager.getDataType(dtPath);
if (dataType != null) {
model.add(dataType);
}
}
}
@Override
@ -693,5 +724,9 @@ public class DataTypePreviewPlugin extends ProgramPlugin {
return super.getDataOrganization();
}
void invalidate() {
invalidateCache();
}
}
}

View file

@ -192,7 +192,7 @@ public abstract class BiDirectionDataType extends StructureDataType
protected void shiftOffsets(int startIndex, int endIndex, int deltaOrdinal, int deltaOffset) {
for (int i = startIndex; i <= endIndex && i < components.size(); i++) {
DataTypeComponentImpl dtc = components.get(i);
shiftOffsets(dtc, deltaOrdinal, deltaOffset);
shiftOffset(dtc, deltaOrdinal, deltaOffset);
}
}
@ -242,7 +242,7 @@ public abstract class BiDirectionDataType extends StructureDataType
}
@Override
public DataTypeComponent insertAtOffset(int offset, DataType dataType, int length,
public DataTypeComponentImpl insertAtOffset(int offset, DataType dataType, int length,
String newName, String comment) {
if (offset < splitOffset - negativeLength || offset >= splitOffset + positiveLength) {
throw new IllegalArgumentException(
@ -297,11 +297,6 @@ public abstract class BiDirectionDataType extends StructureDataType
return dtc;
}
@Override
public DataTypeComponent insertAtOffset(int offset, DataType dataType, int length) {
return insertAtOffset(offset, dataType, length, null, null);
}
@Override
public DataTypeComponent add(DataType dataType, int length, String newName, String comment) {
return addPositive(dataType, length, newName, comment);
@ -374,7 +369,7 @@ public abstract class BiDirectionDataType extends StructureDataType
structLength += absAmount;
notifySizeChanged();
}
@Override
public DataTypeComponent insert(int index, DataType dataType, int length, String newName,
String comment) {
@ -407,12 +402,6 @@ public abstract class BiDirectionDataType extends StructureDataType
// return dtc;
}
@Override
public void insert(int ordinal, DataType dataType, int length, String name, String comment,
int numCopies) {
throw new AssertException("BiDirectionDataType.insert() not implemented.");
}
protected void insertAtOffset(int offset, int numBytes) {
if (offset < splitOffset - negativeLength || offset > splitOffset + positiveLength) {
throw new IllegalArgumentException("Offset " + offset +
@ -676,7 +665,7 @@ public abstract class BiDirectionDataType extends StructureDataType
// dtMgr.dataTypeChanged(this);
// }
}
@Override
public DataTypeComponent[] getDefinedComponents() {
return components.toArray(new DataTypeComponent[components.size()]);
@ -704,12 +693,6 @@ public abstract class BiDirectionDataType extends StructureDataType
return replace(origDtc, dataType, length, newName, comment);
}
@Override
public DataTypeComponent replace(int index, DataType dataType, int length) {
validateDataType(dataType);
return replace(index, dataType, length, null, null);
}
@Override
public DataTypeComponent replaceAtOffset(int offset, DataType dataType, int length,
String newName, String comment) {

View file

@ -24,8 +24,6 @@ import ghidra.program.model.pcode.Varnode;
import ghidra.util.InvalidNameException;
import ghidra.util.exception.DuplicateNameException;
import java.lang.UnsupportedOperationException;
public class StackPieceDataType extends DataTypeImpl {
private final Variable variable;
@ -66,13 +64,13 @@ public class StackPieceDataType extends DataTypeImpl {
}
@Override
public void setName(String name) throws InvalidNameException, DuplicateNameException {
public void setName(String name) throws InvalidNameException {
throw new UnsupportedOperationException();
}
@Override
public void setNameAndCategory(CategoryPath path, String name) throws InvalidNameException,
DuplicateNameException {
public void setNameAndCategory(CategoryPath path, String name)
throws InvalidNameException, DuplicateNameException {
throw new UnsupportedOperationException();
}

View file

@ -22,7 +22,7 @@ import ghidra.util.InvalidNameException;
import ghidra.util.exception.DuplicateNameException;
class MSRichProductBuildNumberDataType extends DataTypeImpl {
private final CompId compid;
public MSRichProductBuildNumberDataType(CompId compid) {
@ -58,7 +58,7 @@ class MSRichProductBuildNumberDataType extends DataTypeImpl {
}
@Override
public void setName(String name) throws InvalidNameException, DuplicateNameException {
public void setName(String name) throws InvalidNameException {
// ignored
}

View file

@ -58,7 +58,7 @@ class MSRichProductIDDataType extends DataTypeImpl {
}
@Override
public void setName(String name) throws InvalidNameException, DuplicateNameException {
public void setName(String name) throws InvalidNameException {
// ignored
}
@ -92,7 +92,7 @@ class MSRichProductIDDataType extends DataTypeImpl {
public String getRepresentation(MemBuffer buf, Settings settings, int length) {
return compid.getProductDescription();
}
@Override

View file

@ -58,7 +58,7 @@ class RichObjectCountDataType extends DataTypeImpl {
}
@Override
public void setName(String name) throws InvalidNameException, DuplicateNameException {
public void setName(String name) throws InvalidNameException {
// ignored
}

View file

@ -27,11 +27,8 @@ import ghidra.program.model.data.*;
*/
public class CompositeHandler {
private DataType lastBitFieldType = null; // type that has a bitfield
private int bitLength = 0; // how many bits have been used
private int anonCnt = 0; // count of anonymous unions created
private Composite parent; // parent container for bitfields
private Composite bitFieldUnion; // artificial union to contain subfields
public CompositeHandler(Composite parent) {
super();
@ -42,7 +39,7 @@ public class CompositeHandler {
return parent;
}
public void add(Declaration dec) {
public void add(Declaration dec) throws IllegalArgumentException {
if (dec == null || dec.getDataType() == null) {
return;
}
@ -52,7 +49,6 @@ public class CompositeHandler {
}
// not a bitfield, just add the data type to composite
if (!dec.isBitField()) {
initialize();
if (dec.isFlexArray() && parent instanceof Structure) {
((Structure) parent).setFlexibleArrayComponent(dec.getDataType(), dec.getName(),
dec.getComment());
@ -62,72 +58,16 @@ public class CompositeHandler {
return;
}
// add bit-field component
DataType dataType = dec.getDataType();
int bitSize = dec.getBitFieldSize();
// if data type different, start new subfield
handleFullBitfieldUnion(dataType, bitSize);
// add the bitfield to the continer union
String bitoff =
(bitSize == 1 ? "" + bitLength : bitLength + "-" + (bitLength + bitSize - 1));
bitFieldUnion.add(dataType, dec.getName(), ": bits " + bitoff);
lastBitFieldType = dataType;
bitLength += bitSize;
try {
parent.addBitField(dataType, dec.getBitFieldSize(), dec.getName(), dec.getComment());
}
catch (InvalidDataTypeException e) {
// TODO Auto-generated catch block
throw new IllegalArgumentException(
"Invalid bitfield " + dec.getName() + " : " + dec.getBitFieldSize());
}
}
/**
* Creates a new bitfield union container if one not created yet or the current
* is full.
*
* @param dataType - type that is about to be added to container
* @param bitSize
*/
private void handleFullBitfieldUnion(DataType dataType, int bitSize) {
if (!bitfieldFull(dataType, bitSize)) {
return;
}
// create an anonymous union to hold sub bitfields
bitFieldUnion = new UnionDataType(parent.getCategoryPath(),
"anon_" + parent.getName() + "_bitfield_" + ++anonCnt);
bitFieldUnion = (Composite) parent.add(bitFieldUnion).getDataType();
bitLength = 0;
}
/**
* Check if a new union needs to be created
*
* @param dataType type that will be added to the union
* @param bitSize size of the bitfield to be added
*
* @return true if a new bitfied union needs to be added
*/
private boolean bitfieldFull(DataType dataType, int bitSize) {
if (parent instanceof Union) {
bitFieldUnion = parent;
return false;
}
// no union yet
if (bitFieldUnion == null) {
return true;
}
// datatype has changed
if (!dataType.equals(lastBitFieldType)) {
return true;
}
// union has overflowed
return (bitLength + bitSize) > (dataType.getLength() * 8);
}
/**
* Clears any residual bitfield info so a new bitfield container will
* be created when necessary.
*/
private void initialize() {
lastBitFieldType = null;
bitLength = 0;
bitFieldUnion = null;
}
}

View file

@ -26,7 +26,7 @@ public class Declaration {
private DataType dt;
private String name;
private String comment;
private int bitSize = 0;
private int bitSize = -1;
private boolean flexArray = false; // true if this is a zero size flex array component
public Declaration() {
@ -97,9 +97,6 @@ public class Declaration {
if (name == null) {
return "";
}
if (isBitField()) {
return name + ":" + bitSize;
}
return name;
}
@ -133,7 +130,7 @@ public class Declaration {
* @return true if a bitfield size has been set
*/
boolean isBitField() {
return bitSize != 0;
return bitSize >= 0;
}
/**

View file

@ -15,14 +15,6 @@
*/
package ghidra.app.util.datatype;
import ghidra.app.plugin.core.datamgr.util.DataTypeChooserDialog;
import ghidra.app.plugin.core.datamgr.util.DataTypeUtils;
import ghidra.app.services.DataTypeManagerService;
import ghidra.framework.plugintool.ServiceProvider;
import ghidra.program.model.data.*;
import ghidra.util.data.DataTypeParser;
import java.awt.Component;
import java.awt.event.*;
import javax.swing.*;
@ -31,6 +23,12 @@ import javax.swing.tree.TreePath;
import docking.options.editor.ButtonPanelFactory;
import docking.widgets.DropDownSelectionTextField;
import ghidra.app.plugin.core.datamgr.util.DataTypeChooserDialog;
import ghidra.app.plugin.core.datamgr.util.DataTypeUtils;
import ghidra.app.services.DataTypeManagerService;
import ghidra.framework.plugintool.ServiceProvider;
import ghidra.program.model.data.*;
import ghidra.util.data.DataTypeParser;
/**
* An editor that is used to show the {@link DropDownSelectionTextField} for the entering of
@ -58,6 +56,7 @@ public class DataTypeSelectionEditor extends AbstractCellEditor {
private JPanel editorPanel;
private DropDownSelectionTextField<DataType> selectionField;
private JButton browseButton;
private DataTypeManagerService dataTypeManagerService;
private int maxSize = -1;
private DataTypeManager dataTypeManager;
@ -109,9 +108,8 @@ public class DataTypeSelectionEditor extends AbstractCellEditor {
}
private void init() {
selectionField =
new DropDownSelectionTextField<DataType>(new DataTypeDropDownSelectionDataModel(
dataTypeManagerService));
selectionField = new DropDownSelectionTextField<>(
new DataTypeDropDownSelectionDataModel(dataTypeManagerService));
selectionField.addCellEditorListener(new CellEditorListener() {
@Override
public void editingCanceled(ChangeEvent e) {
@ -128,15 +126,9 @@ public class DataTypeSelectionEditor extends AbstractCellEditor {
selectionField.setBorder(UIManager.getBorder("Table.focusCellHighlightBorder"));
JButton browseButton = ButtonPanelFactory.createButton(ButtonPanelFactory.BROWSE_TYPE);
browseButton = ButtonPanelFactory.createButton(ButtonPanelFactory.BROWSE_TYPE);
browseButton.setToolTipText("Browse the Data Manager");
browseButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// show the data type manager
showDataTypeBrowser();
}
});
browseButton.addActionListener(e -> showDataTypeBrowser());
editorPanel = new JPanel();
editorPanel.setLayout(new BoxLayout(editorPanel, BoxLayout.X_AXIS));
@ -196,7 +188,7 @@ public class DataTypeSelectionEditor extends AbstractCellEditor {
* Returns the component that allows the user to edit.
* @return the component that allows the user to edit.
*/
public Component getEditorComponent() {
public JComponent getEditorComponent() {
return editorPanel;
}
@ -204,6 +196,10 @@ public class DataTypeSelectionEditor extends AbstractCellEditor {
return selectionField;
}
public JButton getBrowseButton() {
return browseButton;
}
/**
* Sets the initially selected node in the data type tree that the user can choose to
* show.
@ -321,11 +317,11 @@ public class DataTypeSelectionEditor extends AbstractCellEditor {
// look for the case where the user made a selection from the matching window, but
// then changed the text field text.
DataType selectedDataType = selectionField.getSelectedValue();
if (selectedDataType != null && selectionField.getText().equals(selectedDataType.getName())) {
if (selectedDataType != null &&
selectionField.getText().equals(selectedDataType.getName())) {
DataTypeParser.ensureIsAllowableType(selectedDataType, allowedDataTypes);
return true;
}
return false;
}
@ -346,6 +342,11 @@ public class DataTypeSelectionEditor extends AbstractCellEditor {
// TODO: implement in the future to allow the user to create data types
private boolean promptUserToCreateDataType() throws InvalidDataTypeException {
if (selectionField.getText().trim().length() == 0) {
// no need to invoke parser on empty string
return false;
}
// we will create new pointer and array types by default
DataType newDataType = null;
// try {

View file

@ -81,10 +81,10 @@ public class MUIResourceDataType extends DynamicDataType {
if (checkMagic(memBuffer)) {
StructureDataType sdt = MUIStructureHeader();
tempOffset = addComp(sdt, sdt.getLength(), "muiResourceHeader",
memBuffer.getAddress().add(tempOffset), comps, tempOffset);
memBuffer.getAddress().add(tempOffset), comps, tempOffset);
sdt = MUIStructureData(tempOffset, memBuffer, offsets, sizes);
tempOffset = addComp(sdt, sdt.getLength(), "muiResourceData",
memBuffer.getAddress().add(tempOffset), comps, tempOffset);
memBuffer.getAddress().add(tempOffset), comps, tempOffset);
}
else {
Msg.debug(this, "Not an MUI resource data type at " + mbIn.getAddress());
@ -107,7 +107,7 @@ public class MUIResourceDataType extends DynamicDataType {
"0x01 = internal, 0x02 = external");
ArrayDataType adt16 = new ArrayDataType(ByteDataType.dataType, 16, 1);
ArrayDataType adt24 = new ArrayDataType(ByteDataType.dataType, 16, 1);
ArrayDataType adt24 = new ArrayDataType(ByteDataType.dataType, 24, 1);
struct.add(adt16, 16, "serviceChecksum", "");
struct.add(adt16, 16, "checksum", "");
@ -195,9 +195,8 @@ public class MUIResourceDataType extends DynamicDataType {
private int addComp(DataType dataType, int length, String fieldName, Address address,
List<DataTypeComponent> comps, int currentOffset) {
if (length > 0) {
ReadOnlyDataTypeComponent readOnlyDataTypeComponent =
new ReadOnlyDataTypeComponent(dataType, this, length, comps.size(), currentOffset,
fieldName, null);
ReadOnlyDataTypeComponent readOnlyDataTypeComponent = new ReadOnlyDataTypeComponent(
dataType, this, length, comps.size(), currentOffset, fieldName, null);
comps.add(readOnlyDataTypeComponent);
currentOffset += length;
}

View file

@ -308,7 +308,7 @@ public class BytesFieldFactory extends FieldFactory {
}
alignSize = (int) (nextComponent.getMinAddress().subtract(data.getMaxAddress())) - 1;
}
if (alignSize == 0) {
if (alignSize <= 0) {
return null;
}
int alignmentOffset = data.getParentOffset() + data.getLength();

View file

@ -271,8 +271,8 @@ public class ProgramBigListingModel implements ListingModel, FormatModelListener
int offset = (int) address.subtract(parent.getMinAddress());
data = parent.getComponentAt(offset);
// Need to handle filler in aligned structures in a special way.
if (data == null && ((Structure) dt).isInternallyAligned()) {
// Need to handle filler in a special way.
if (data == null) {
// So look for next non-filler address.
offset++;
int length = dt.getLength();
@ -280,7 +280,7 @@ public class ProgramBigListingModel implements ListingModel, FormatModelListener
// If not beyond structure's end, check for non-filler.
data = parent.getComponentAt(offset);
if (data != null) { // Found non filler address so return it.
return parent.getMinAddress().add(offset);
return data.getMinAddress();
}
}
}
@ -315,9 +315,12 @@ public class ProgramBigListingModel implements ListingModel, FormatModelListener
}
}
else {
// otherwise just return the next dataComponent after this one
if (index < parent.getNumComponents() - 1) {
return parent.getComponent(index + 1).getMinAddress();
while (index < parent.getNumComponents() - 1) {
index++;
Data component = parent.getComponent(index);
if (address.compareTo(component.getMinAddress()) < 0) {
return component.getAddress();
}
}
}
return null;
@ -369,7 +372,9 @@ public class ProgramBigListingModel implements ListingModel, FormatModelListener
}
else {
int offset = (int) addr.subtract(parent.getMinAddress());
data = parent.getComponentAt(offset - 1);
List<Data> componentsContaining = parent.getComponentsContaining(offset - 1);
data = componentsContaining.isEmpty() ? null
: componentsContaining.get(componentsContaining.size() - 1);
}
if (data == null) {
return addr.previous();
@ -415,14 +420,18 @@ public class ProgramBigListingModel implements ListingModel, FormatModelListener
}
}
}
else {
Data tmpData = data.getComponentAt((int) addr.subtract(dataAddr));
if (tmpData != null) {
if (tmpData.getMinAddress().equals(addr)) {
list.add(tmpData);
}
if (tmpData.getNumComponents() > 0) {
addOpenData(list, tmpData, addr);
else { // Structure
List<Data> dataList = data.getComponentsContaining((int) addr.subtract(dataAddr));
if (dataList != null) { // nested flex-arrays can cause odd behavior
for (Data subData : dataList) {
// The only case where more than one subData exists is for bit-fields.
// Depending upon the packing, bit-fields at different offsets may overlap
if (subData.getMinAddress().equals(addr)) {
list.add(subData);
}
if (subData.getNumComponents() > 0) {
addOpenData(list, subData, addr);
}
}
}
}

View file

@ -15,7 +15,8 @@
*/
package ghidra.util.data;
import java.util.*;
import java.util.ArrayList;
import java.util.List;
import ghidra.app.plugin.core.datamgr.util.DataTypeUtils;
import ghidra.app.services.DataTypeManagerService;
@ -45,7 +46,12 @@ public class DataTypeParser {
/**
* Only Fixed-length data types and string data types
*/
STRINGS_AND_FIXED_LENGTH
STRINGS_AND_FIXED_LENGTH,
/**
* Only Enums, Integer types and those Typedefs based on them
* for use as a bitfield base datatype
*/
BITFIELD_USE
}
private DataTypeManager sourceDataTypeManager; // may be null
@ -57,7 +63,7 @@ public class DataTypeParser {
* A constructor that does not use the source or destination data type managers. In terms of
* the source data type manager, this means that all data type managers will be used when
* resolving data types.
*
*
* @param dataTypeManagerService
* @param allowedTypes
*/
@ -73,7 +79,7 @@ public class DataTypeParser {
* @param destinationDataTypeManager target data-type manager, or null
* @param dataTypeManagerService data-type manager tool service, or null
* @param allowedTypes constrains which data-types may be parsed
*
*
* @see #DataTypeParser(DataTypeManagerService, AllowedDataTypes)
*/
public DataTypeParser(DataTypeManager sourceDataTypeManager,
@ -118,7 +124,7 @@ public class DataTypeParser {
* Parse a data-type string specification using the specified baseDatatype.
* @param suggestedBaseDataType base data-type (may be null), this will be used as the base data-type if
* its name matches the base name in the specified dataTypeString.
* @param dataTypeString a base data-type followed by a sequence of zero or more pointer/array decorations to be applied.
* @param dataTypeString a base data-type followed by a sequence of zero or more pointer/array decorations to be applied.
* The string may start with the baseDataType's name.
* @return parsed data-type or null if not found
* @throws InvalidDataTypeException if data-type string is invalid or length exceeds specified maxSize
@ -180,6 +186,12 @@ public class DataTypeParser {
throw new InvalidDataTypeException("fixed-length or string data-type required");
}
break;
case BITFIELD_USE:
if (!BitFieldDataType.isValidBaseDataType(dt)) {
throw new InvalidDataTypeException(
"enum or integer derived data-type required");
}
break;
case ALL:
// do nothing
break;
@ -334,8 +346,7 @@ public class DataTypeParser {
// see if one of the data types belongs to the program or the built in types, where the
// program is more important than the builtin
for (Iterator<DataType> iter = dtList.iterator(); iter.hasNext();) {
DataType dataType = iter.next();
for (DataType dataType : dtList) {
DataTypeManager manager = dataType.getDataTypeManager();
if (manager instanceof BuiltInDataTypeManager) {
programDataType = dataType;
@ -350,8 +361,7 @@ public class DataTypeParser {
return null;
}
for (Iterator<DataType> iter = dtList.iterator(); iter.hasNext();) {
DataType dataType = iter.next();
for (DataType dataType : dtList) {
// just one non-matching case means that we can't use the program's data type
if (!programDataType.isEquivalent(dataType)) {
return null;

View file

@ -1674,17 +1674,19 @@ Composite StructOrUnion() : {Composite comp;}
{
(
<STRUCT> ( DeclSpec() )* { comp = new StructureDataType(ANONYMOUS_STRUCT_PREFIX + cnt++, 0);
try {
// always set the packing, because by default structures should be aligned
// Always set the packing, because by default structures should be aligned
// setting 0 turns off packing, but sets structures to be aligned
// TODO: is this correct, should this be changed and controlled by the
// compiler spec.
comp.setPackingValue(this.packSize);
} catch (InvalidInputException e1) {
e1.printStackTrace(); }
}
|
<UNION> ( DeclSpec() )* { comp = new UnionDataType(ANONYMOUS_UNION_PREFIX + cnt++); }
<UNION> ( DeclSpec() )* { comp = new UnionDataType(ANONYMOUS_UNION_PREFIX + cnt++);
// Always set the packing, because by default structures should be aligned
// setting 0 turns off packing, but sets structures to be aligned.
comp.setPackingValue(this.packSize);
}
)
{
try {
@ -1813,7 +1815,14 @@ void StructDeclarator(Declaration dt, Composite comp, CompositeHandler composite
}
}]
|
":" ConstantExpression()
":" bitSizeObj = ConstantExpression() {
Integer bitSize = getConstantValue(bitSizeObj,0);
if (bitSize != 0) {
throw new ParseException("invalid bit-field declaration: ':" + bitSize);
}
dec = new Declaration(dt);
dec.setBitFieldSize(0);
}
)
{
try {

View file

@ -51,8 +51,8 @@ public class OutgoingFunctionCallNodeTest extends AbstractGenericTest {
super();
}
@Before
public void setUp() throws Exception {
@Before
public void setUp() throws Exception {
builder = new ToyProgramBuilder("Call Node Test", true);
builder.createMemory(".text", "0x0", 0x3000);
@ -64,8 +64,8 @@ public class OutgoingFunctionCallNodeTest extends AbstractGenericTest {
node = new OutgoingFunctionCallNode(program, function, source, true, new AtomicInteger(5));
}
@Test
public void testGenerateChildren_SelfRecursiveCall() throws Exception {
@Test
public void testGenerateChildren_SelfRecursiveCall() throws Exception {
builder.createMemoryCallReference(nodeAddress, nodeAddress);
@ -73,8 +73,8 @@ public class OutgoingFunctionCallNodeTest extends AbstractGenericTest {
assertTrue(children.isEmpty());
}
@Test
public void testGenerateChildren_CalledFunctionExists() throws Exception {
@Test
public void testGenerateChildren_CalledFunctionExists() throws Exception {
String otherAddress = "0x1000";
builder.createEmptyFunction("Function_2", otherAddress, 10, DataType.DEFAULT);
builder.createMemoryCallReference(nodeAddress, otherAddress);
@ -84,8 +84,8 @@ public class OutgoingFunctionCallNodeTest extends AbstractGenericTest {
assertEquals("Function_2", children.get(0).getName());
}
@Test
public void testGenerateChildren_CalledFunctionExists_ExternalCall() throws Exception {
@Test
public void testGenerateChildren_CalledFunctionExists_ExternalCall() throws Exception {
String otherAddress = "0x1000";
String externalFunctionName = "External_Function";
@ -100,8 +100,8 @@ public class OutgoingFunctionCallNodeTest extends AbstractGenericTest {
assertEquals(externalFunctionName, children.get(0).getName());
}
@Test
public void testGenerateChildren_CallReference_ExternalFunction_NoFunctionInMemory()
@Test
public void testGenerateChildren_CallReference_ExternalFunction_NoFunctionInMemory()
throws Exception {
builder.createMemoryCallReference(nodeAddress, "EXTERNAL:00000001");
@ -111,8 +111,8 @@ public class OutgoingFunctionCallNodeTest extends AbstractGenericTest {
assertEquals("EXTERNAL:00000001", children.get(0).getName());
}
@Test
public void testGenerateChildren_CallReference_ToPointer_ToExternalFunction() throws Exception {
@Test
public void testGenerateChildren_CallReference_ToPointer_ToExternalFunction() throws Exception {
//
// Function A
@ -137,8 +137,8 @@ public class OutgoingFunctionCallNodeTest extends AbstractGenericTest {
assertEquals(externalFunctionName, children.get(0).getName());
}
@Test
public void testGenerateChildren_CallReference_ToPointer_ToNonExternalFunction()
@Test
public void testGenerateChildren_CallReference_ToPointer_ToNonExternalFunction()
throws Exception {
//
@ -162,8 +162,8 @@ public class OutgoingFunctionCallNodeTest extends AbstractGenericTest {
assertTrue(children.get(0) instanceof DeadEndNode);
}
@Test
public void testGenerateChildren_CallReference_ToPointer_Offcut() throws Exception {
@Test
public void testGenerateChildren_CallReference_ToPointer_Offcut() throws Exception {
//
// Bad code case; expected reference to pointer, but no data there
@ -179,21 +179,22 @@ public class OutgoingFunctionCallNodeTest extends AbstractGenericTest {
assertTrue(children.get(0) instanceof DeadEndNode);
}
@Test
public void testGenerateChildren_WriteReference() throws Exception {
@Test
public void testGenerateChildren_WriteReference() throws Exception {
//
// Have a reference in the function to a place that is not another function, and the
// reference is a write reference. No call node is created.
//
builder.createMemoryReference(nodeAddress, "0x1000", RefType.WRITE, SourceType.USER_DEFINED);
builder.createMemoryReference(nodeAddress, "0x1000", RefType.WRITE,
SourceType.USER_DEFINED);
List<GTreeNode> children = node.generateChildren(TaskMonitor.DUMMY);
assertTrue(children.isEmpty());
}
@Test
public void testGenerateChildren_ReadReference_NullInstruction() throws Exception {
@Test
public void testGenerateChildren_ReadReference_NullInstruction() throws Exception {
//
// Have a reference in the function to a place that is not another function, and the
@ -208,8 +209,8 @@ public class OutgoingFunctionCallNodeTest extends AbstractGenericTest {
}
@Test
public void testGenerateChildren_ReadReference_NotCallInstruction() throws Exception {
@Test
public void testGenerateChildren_ReadReference_NotCallInstruction() throws Exception {
//
// Read reference to an instruction with a flow type that is not a call
@ -223,8 +224,8 @@ public class OutgoingFunctionCallNodeTest extends AbstractGenericTest {
assertTrue(children.isEmpty());
}
@Test
public void testGenerateChildren_ReadReference_CallInstruction_InstructionAtToAddress()
@Test
public void testGenerateChildren_ReadReference_CallInstruction_InstructionAtToAddress()
throws Exception {
//
@ -243,8 +244,8 @@ public class OutgoingFunctionCallNodeTest extends AbstractGenericTest {
assertTrue(children.isEmpty());
}
@Test
public void testGenerateChildren_ReadReference_CallInstruction_ToData_NoReference()
@Test
public void testGenerateChildren_ReadReference_CallInstruction_ToData_NoReference()
throws Exception {
//
@ -258,8 +259,8 @@ public class OutgoingFunctionCallNodeTest extends AbstractGenericTest {
assertTrue(children.isEmpty());
}
@Test
public void testGenerateChildren_ReadReference_CallInstruction_ToData_NonExternalReference()
@Test
public void testGenerateChildren_ReadReference_CallInstruction_ToData_NonExternalReference()
throws Exception {
//
@ -277,8 +278,8 @@ public class OutgoingFunctionCallNodeTest extends AbstractGenericTest {
assertTrue(children.isEmpty());
}
@Test
public void testGenerateChildren_ReadReference_CallInstruction_ToData_ExternalReference_NonFunctionSymbol()
@Test
public void testGenerateChildren_ReadReference_CallInstruction_ToData_ExternalReference_NonFunctionSymbol()
throws Exception {
//
@ -296,8 +297,8 @@ public class OutgoingFunctionCallNodeTest extends AbstractGenericTest {
assertTrue(children.isEmpty());
}
@Test
public void testGenerateChildren_ReadReference_CallInstruction_ToData_ExternalReference_FunctionSymbol()
@Test
public void testGenerateChildren_ReadReference_CallInstruction_ToData_ExternalReference_FunctionSymbol()
throws Exception {
//

View file

@ -28,6 +28,7 @@ import ghidra.program.model.data.*;
import ghidra.program.model.data.Composite.AlignmentType;
import ghidra.util.exception.DuplicateNameException;
import ghidra.util.exception.UsrException;
import ghidra.util.task.TaskMonitor;
import ghidra.util.task.TaskMonitorAdapter;
public class UnionEditorNotifiedTest extends AbstractUnionEditorTest {
@ -118,11 +119,16 @@ public class UnionEditorNotifiedTest extends AbstractUnionEditorTest {
@Test
public void testEditedDtCategoryRemoved() throws Exception {
DataTypeManager dtm = complexUnion.getDataTypeManager();
Union refUnion = (Union) dtm.getDataType("/testCat/refUnion");
assertNotNull(refUnion);
Category tempCat;
try {
startTransaction("Modify Program");
tempCat = pgmRootCat.createCategory("Temp");
tempCat.moveDataType(complexUnion, DataTypeConflictHandler.DEFAULT_HANDLER);
tempCat.moveDataType(refUnion, DataTypeConflictHandler.DEFAULT_HANDLER);
}
finally {
endTransaction(true);
@ -142,7 +148,7 @@ public class UnionEditorNotifiedTest extends AbstractUnionEditorTest {
});
waitForSwing();
// refUnion* gets removed since it has only a complexUnion* that was removed.
// refUnion* gets removed
assertEquals(num - 1, model.getNumComponents());
assertTrue(dt18.isEquivalent(getDataType(18)));
assertTrue(dt20.isEquivalent(getDataType(19)));
@ -409,16 +415,31 @@ public class UnionEditorNotifiedTest extends AbstractUnionEditorTest {
init(complexUnion, pgmTestCat, false);
int num = model.getNumComponents();
// Clone the data types we want to hold onto for comparison later, since reload can close the viewDTM.
DataType dt18 = getDataType(18).clone(programDTM);
DataType dt20 = getDataType(20).clone(programDTM);
SwingUtilities.invokeLater(() -> complexUnion.getDataTypeManager().remove(complexUnion,
TaskMonitorAdapter.DUMMY_MONITOR));
DataTypeManager dtm = complexUnion.getDataTypeManager();
Union refUnion = (Union) dtm.getDataType("/testCat/refUnion");
assertNotNull(refUnion);
SwingUtilities.invokeLater(() -> dtm.remove(refUnion, TaskMonitor.DUMMY)); // remove refUnion
waitForSwing();
// refUnion* gets removed since it has only a complexUnion* that was removed.
assertEquals(num - 1, model.getNumComponents());
// refUnion* gets removed (1 component)
num -= 1;
assertEquals(num, model.getNumComponents());
assertTrue(dt18.isEquivalent(getDataType(18)));
assertTrue(dt20.isEquivalent(getDataType(19)));
SwingUtilities.invokeLater(
() -> simpleUnion.getDataTypeManager().remove(simpleUnion, TaskMonitor.DUMMY));
waitForSwing();
// All components (3 total) which were dependent upon simpleUnion are removed
num -= 3;
assertEquals(num, model.getNumComponents());
}
finally {
cleanup();

View file

@ -22,6 +22,7 @@ import static org.junit.Assert.assertEquals;
import org.junit.*;
import ghidra.app.events.ProgramActivatedPluginEvent;
import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin;
import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin;
import ghidra.app.plugin.core.datapreview.DataTypePreviewPlugin.DTPPTableModel;
@ -209,12 +210,19 @@ public class DataTypePreviewPluginTest extends AbstractGhidraHeadedIntegrationTe
assertEquals("61004D00200065h", model.getValueAt(4, DTPPTableModel.PREVIEW_COL));// 8-byte long at offset 4
assertEquals("72h", model.getValueAt(5, DTPPTableModel.PREVIEW_COL));// 2-byte short at offset 12
// deactivate program
plugin.getTool().firePluginEvent(new ProgramActivatedPluginEvent("Test", null));
waitForPostedSwingRunnables();
// NOTE: Altering data organization on-the-fly is not supported
dataOrganization.setDefaultAlignment(2);
dataOrganization.setShortSize(3);
dataOrganization.setIntegerSize(3);
dataOrganization.setLongSize(6);
plugin.updateModel();
// activate program
plugin.getTool().firePluginEvent(new ProgramActivatedPluginEvent("Test", program));
waitForPostedSwingRunnables();
gotoService.goTo(addr(program, 0x100df26));

View file

@ -22,7 +22,6 @@ import org.junit.*;
import ghidra.app.cmd.memory.MoveBlockListener;
import ghidra.app.cmd.memory.MoveBlockTask;
import ghidra.program.database.ProgramBuilder;
import ghidra.program.database.ProgramDB;
import ghidra.program.database.data.DataTypeManagerDB;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSpace;
@ -81,7 +80,7 @@ public class MoveBlockModelTest extends AbstractGhidraHeadedIntegrationTest
model.initialize(block);
int transactionID = x8051.startTransaction("Set settings");
DataTypeManagerDB dtm = ((ProgramDB) x8051).getDataManager();
DataTypeManagerDB dtm = (DataTypeManagerDB) x8051.getDataTypeManager();
for (int i = 0; i < 10; i++) {
Address a = getAddr(x8051, "BITS", i);
dtm.setStringSettingsValue(a, "color", "red" + i);
@ -197,8 +196,7 @@ public class MoveBlockModelTest extends AbstractGhidraHeadedIntegrationTest
waitForCondition(() -> moveCompleted && x8051.canLock());
// make sure settings on data got moved
DataTypeManagerDB dtm = ((ProgramDB) x8051).getDataManager();
DataTypeManagerDB dtm = (DataTypeManagerDB) x8051.getDataTypeManager();
for (int i = 0; i < 10; i++) {
Address a = getAddr(x8051, "CODE", 0x2000 + i);

View file

@ -439,7 +439,7 @@ public class FollowFlowProgramBuilder extends ProgramBuilder {
startTransaction();
ProgramDB program = getProgram();
Listing listing = program.getListing();
Structure struct = new StructureDataType(name, thisStructureSize, program.getDataManager());
Structure struct = new StructureDataType(name, thisStructureSize, program.getDataTypeManager());
struct.replaceAtOffset(0, new FloatDataType(), 4, null, null);
struct.replaceAtOffset(pointerOffset, new Pointer32DataType(), 4, null, null);
listing.createData(addr(startOfStruct), struct);
@ -473,7 +473,7 @@ public class FollowFlowProgramBuilder extends ProgramBuilder {
startTransaction();
ProgramDB program = getProgram();
Listing listing = program.getListing();
Structure struct = new StructureDataType(name, thisStructureSize, program.getDataManager());
Structure struct = new StructureDataType(name, thisStructureSize, program.getDataTypeManager());
struct.replaceAtOffset(0, new FloatDataType(), 4, null, null);
struct.replaceAtOffset(pointerOffset, new Pointer32DataType(), 4, null, null);
struct.replaceAtOffset(pointerOffset + pointerSize, new Pointer32DataType(), 4, null, null);

View file

@ -441,13 +441,8 @@ public class DataTypeSelectionDialogTest extends AbstractGhidraHeadedIntegration
// Check that more than 2 non-equivalent data types trigger the dialog to appear.
//
Category secondCategory = rootCategory.createCategory("testCategory2");
dataType = new CustomDataType(secondCategory.getCategoryPath(), crazyName, 2) {
@Override
public DataTypeManager getDataTypeManager() {
return getProgramDataTypeManager(dataTypeManagers);
}
};
dataType = new CustomDataType(secondCategory.getCategoryPath(), crazyName, 2,
getProgramDataTypeManager(dataTypeManagers));
addDataType(secondCategory, dataType);
showDialogWithoutBlocking(tool, dialog);
@ -1099,6 +1094,10 @@ public class DataTypeSelectionDialogTest extends AbstractGhidraHeadedIntegration
}
private class CustomDataType extends StructureDataType {
public CustomDataType(CategoryPath path, String name, int length, DataTypeManager dtm) {
super(path, name, length, dtm);
}
public CustomDataType(CategoryPath path, String name, int length) {
super(path, name, length);
}

View file

@ -55,7 +55,7 @@ public class ArrayTest extends AbstractGhidraHeadedIntegrationTest {
public void setUp() throws Exception {
program = createDefaultProgram(testName.getMethodName(), ProgramBuilder._TOY, this);
dataMgr = program.getDataManager();
dataMgr = program.getDataTypeManager();
listing = program.getListing();
space = program.getAddressFactory().getDefaultAddressSpace();
transactionID = program.startTransaction("Test");

View file

@ -0,0 +1,129 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.program.database.data;
import static org.junit.Assert.assertEquals;
import org.junit.*;
import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin;
import ghidra.framework.plugintool.PluginTool;
import ghidra.program.database.ProgramBuilder;
import ghidra.program.database.ProgramDB;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSpace;
import ghidra.program.model.data.*;
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
import ghidra.test.TestEnv;
import ghidra.util.task.TaskMonitor;
public class BitFieldListingDisplayTest extends AbstractGhidraHeadedIntegrationTest {
private ProgramDB program;
private int transactionID;
private Structure struct;
private AddressSpace space;
private TestEnv env;
private CodeBrowserPlugin plugin;
@Before
public void setUp() throws Exception {
program = createDefaultProgram("Test", ProgramBuilder._TOY, this); // big-endian
startTransaction();
space = program.getAddressFactory().getDefaultAddressSpace();
program.getMemory().createInitializedBlock("m", addr(0x1000), 0x100, (byte) 0,
TaskMonitor.DUMMY, false);
struct = createStructure("Test", 0);
struct.setInternallyAligned(true);
struct.addBitField(IntegerDataType.dataType, 3, "bf1", "Nuts");
struct.addBitField(IntegerDataType.dataType, 24, "bf2", null);
struct.addBitField(IntegerDataType.dataType, 4, "bf3", null);
struct.addBitField(IntegerDataType.dataType, 12, "bf4", null);
struct.addBitField(IntegerDataType.dataType, 3, "bf4a", null);
struct.addBitField(IntegerDataType.dataType, 3, "bf5", null);
struct.addBitField(IntegerDataType.dataType, 3, "b6", null);
struct.add(new ByteDataType(), "field0", "Comment1");
struct.add(new WordDataType(), null, "Comment2");
struct.add(new DWordDataType(), "field3", null);
struct.add(new ByteDataType(), "field4", "Comment4");
program.getListing().createData(addr(0x1010), struct);
env = new TestEnv();
PluginTool tool = env.launchDefaultTool(program);
plugin = getPlugin(tool, CodeBrowserPlugin.class);
}
private Address addr(long value) {
return space.getAddress(value);
}
@After
public void tearDown() throws Exception {
endTransaction();
env.dispose();
}
protected Structure createStructure(String name, int length) {
return (Structure) getDataTypeManager().resolve(new StructureDataType(name, length), null);
}
protected DataTypeManager getDataTypeManager() {
return program.getDataTypeManager();
}
private void startTransaction() {
transactionID = program.startTransaction("Test");
}
private void endTransaction() {
program.endTransaction(transactionID, true);
}
@Test
public void testBitField() throws Exception {
openStructure(addr(0x1010));
assertMnemonic("Test", addr(0x1010), 0);
assertMnemonic("int:3", addr(0x1010), 1);
assertMnemonic("int:24", addr(0x1010), 2);
assertMnemonic("int:4", addr(0x1013), 0);
assertMnemonic("int:12", addr(0x1014), 0);
assertMnemonic("int:3", addr(0x1015), 0);
assertMnemonic("int:3", addr(0x1015), 1);
assertMnemonic("int:3", addr(0x1016), 0);
assertMnemonic("db", addr(0x1017), 0);
assertMnemonic("dw", addr(0x1018), 0);
System.out.println("wait");
}
private void assertMnemonic(String expectedValue, Address addr, int occurrence) {
plugin.goToField(addr, "Mnemonic", occurrence, 0, 0);
assertEquals(expectedValue, plugin.getCurrentFieldText());
}
private void openStructure(Address address) {
// open the structure
plugin.goToField(address, "+", 0, 0);
click(plugin, 1);
waitForSwing();
}
}

View file

@ -73,7 +73,7 @@ public class CategoryTest extends AbstractGhidraHeadedIntegrationTest {
public void setUp() throws Exception {
program = createDefaultProgram(testName.getMethodName(), ProgramBuilder._TOY, this);
dataMgr = program.getDataManager();
dataMgr = program.getDataTypeManager();
eventRecordingListener = new CategoryTestListener();
dataMgr.addDataTypeManagerListener(eventRecordingListener);
root = dataMgr.getRootCategory();

View file

@ -59,7 +59,7 @@ public class ConflictHandlerTest extends AbstractGhidraHeadedIntegrationTest {
@Before
public void setUp() throws Exception {
program = createDefaultProgram(testName.getMethodName(), ProgramBuilder._TOY, this);
dataMgr = program.getDataManager();
dataMgr = program.getDataTypeManager();
startTransaction();
}

View file

@ -37,7 +37,7 @@ public class DataManagerTest extends AbstractGhidraHeadedIntegrationTest {
@Before
public void setUp() throws Exception {
program = createDefaultProgram(testName.getMethodName(), ProgramBuilder._TOY, this);
dataMgr = program.getDataManager();
dataMgr = program.getDataTypeManager();
startTransaction();
}

View file

@ -48,7 +48,7 @@ public class EnumTest extends AbstractGhidraHeadedIntegrationTest {
public void setUp() throws Exception {
program = createDefaultProgram("Test", ProgramBuilder._TOY, this);
dataMgr = program.getDataManager();
dataMgr = program.getDataTypeManager();
transactionID = program.startTransaction("Test");
}

View file

@ -46,7 +46,7 @@ public class FunctionDefinitionDBTest extends AbstractGhidraHeadedIntegrationTes
@Before
public void setUp() throws Exception {
program = createDefaultProgram(testName.getMethodName(), ProgramBuilder._TOY, this);
dtm = program.getDataManager();
dtm = program.getDataTypeManager();
startTransaction();
FunctionDefinitionDataType fdt = new FunctionDefinitionDataType("test");
fdt.setComment("My comments");

View file

@ -55,7 +55,7 @@ public class SettingsTest extends AbstractGhidraHeadedIntegrationTest {
public void setUp() throws Exception {
program = createDefaultProgram(testName.getMethodName(), ProgramBuilder._TOY, this);
space = program.getAddressFactory().getDefaultAddressSpace();
dataMgr = program.getDataManager();
dataMgr = program.getDataTypeManager();
listing = program.getListing();
transactionID = program.startTransaction("Test");
addBlock();

View file

@ -629,7 +629,7 @@ public class FunctionDBTest extends AbstractGhidraHeadedIntegrationTest implemen
int initialParamCnt = f.getParameterCount();
Structure bar = new StructureDataType("bar", 20);
Pointer barPtr = program.getDataManager().getPointer(bar);
Pointer barPtr = program.getDataTypeManager().getPointer(bar);
Parameter returnVar = f.getReturn();
Parameter p1 = f.getParameter(0);
@ -697,7 +697,7 @@ public class FunctionDBTest extends AbstractGhidraHeadedIntegrationTest implemen
int initialParamCnt = f.getParameterCount();
Structure bar = new StructureDataType("bar", 20);
Pointer barPtr = program.getDataManager().getPointer(bar);
Pointer barPtr = program.getDataTypeManager().getPointer(bar);
Parameter returnVar = f.getReturn();
Parameter p1 = f.getParameter(0);

View file

@ -114,6 +114,7 @@ public class DataTypeUtilsTest {
}
private class DataTypeDummy implements DataType {
String wrappedString;
UniversalID id;
@ -132,6 +133,11 @@ public class DataTypeUtilsTest {
return null;
}
@Override
public DataOrganization getDataOrganization() {
throw new UnsupportedOperationException();
}
@Override
public String getDisplayName() {
return "This is a wrapper for: " + wrappedString;

View file

@ -22,6 +22,7 @@ import java.util.List;
import org.junit.*;
import generic.test.AbstractGenericTest;
import ghidra.app.services.DataTypeManagerService;
import ghidra.app.util.cparser.C.ParseException;
import ghidra.program.database.ProgramBuilder;
import ghidra.program.database.ProgramDB;
@ -39,6 +40,7 @@ public class FunctionEditorModelTest extends AbstractGenericTest {
private volatile boolean dataChangeCalled;
private Structure bigStruct;
private ProgramDB program;
private DataTypeManagerService service;
private volatile boolean tableRowsChanged;
class MyModelChangeListener implements ModelChangeListener {
@ -61,7 +63,6 @@ public class FunctionEditorModelTest extends AbstractGenericTest {
program = builder.getProgram();
bigStruct = new StructureDataType("bigStruct", 20);
resolveBigStruct();
model = new FunctionEditorModel(null /* use default parser*/, fun);
model.setModelChangeListener(new MyModelChangeListener());
}
@ -73,7 +74,6 @@ public class FunctionEditorModelTest extends AbstractGenericTest {
Function fun = builder.createEmptyFunction("bob", "1000", 20, new VoidDataType());
program = builder.getProgram();
resolveBigStruct();
model = new FunctionEditorModel(null /* use default parser*/, fun);
model.setModelChangeListener(new MyModelChangeListener());
}
@ -81,7 +81,7 @@ public class FunctionEditorModelTest extends AbstractGenericTest {
private void resolveBigStruct() {
int txId = program.startTransaction("Resolve bigStruct");
try {
program.getDataManager().resolve(bigStruct, null);
program.getDataTypeManager().resolve(bigStruct, null);
}
finally {
program.endTransaction(txId, true);
@ -972,9 +972,9 @@ public class FunctionEditorModelTest extends AbstractGenericTest {
assertEquals("Stack[0x4]:1", param.getStorage().toString());
DataType struct = new StructureDataType("bigStruct", 100);
DataType structPtr = PointerDataType.getPointer(struct, program.getDataManager());
DataType structPtr = PointerDataType.getPointer(struct, program.getDataTypeManager());
DataType voidPtr =
PointerDataType.getPointer(VoidDataType.dataType, program.getDataManager());
PointerDataType.getPointer(VoidDataType.dataType, program.getDataTypeManager());
model.setCallingConventionName(CompilerSpec.CALLING_CONVENTION_thiscall);
@ -1081,9 +1081,10 @@ public class FunctionEditorModelTest extends AbstractGenericTest {
assertEquals("CL:1", param.getStorage().toString());
DataType struct = new StructureDataType("bigStruct", 100);
DataType structPtr = PointerDataType.getPointer(struct, program.getDataManager());
DataType structPtr = PointerDataType.getPointer(struct, program.getDataTypeManager());
DataType voidPtr =
PointerDataType.getPointer(VoidDataType.dataType, program.getDataManager());
PointerDataType.getPointer(VoidDataType.dataType, program.getDataTypeManager());
model.setCallingConventionName(CompilerSpec.CALLING_CONVENTION_thiscall);
@ -1722,7 +1723,7 @@ public class FunctionEditorModelTest extends AbstractGenericTest {
int txId = program.startTransaction("Add TypeDef jjjjjj");
try {
DataType dt = new TypedefDataType("jjjjjj", ByteDataType.dataType);
program.getDataManager().resolve(dt, null);
program.getDataTypeManager().resolve(dt, null);
}
finally {
program.endTransaction(txId, true);
@ -1919,4 +1920,5 @@ public class FunctionEditorModelTest extends AbstractGenericTest {
private String getSignatureText() {
return model.getFunctionSignatureTextFromModel();
}
}

View file

@ -63,7 +63,7 @@ public class DWARFTestBase extends AbstractGhidraHeadedIntegrationTest {
@Before
public void setUp() throws Exception {
program = createDefaultProgram(testName.getMethodName(), ProgramBuilder._TOY, this);
dataMgr = program.getDataManager();
dataMgr = program.getDataTypeManager();
startTransaction();
AutoAnalysisManager mgr = AutoAnalysisManager.getAnalysisManager(program);

View file

@ -1407,11 +1407,11 @@ public class HTMLDataTypeRepresentationTest extends AbstractGenericTest {
String name = componentAtIndex.getFieldName();
if (optionalName != null) {
destinationComposite.insert(insertIndex, componentCopy, componentCopy.getLength(),
destinationComposite.insert(insertIndex, componentCopy, componentAtIndex.getLength(),
optionalName, null);
}
else {
destinationComposite.insert(insertIndex, componentCopy, componentCopy.getLength(),
destinationComposite.insert(insertIndex, componentCopy, componentAtIndex.getLength(),
name + " Copy", null);
}
}

View file

@ -0,0 +1,45 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
*
*/
package ghidra.program.database.data;
import ghidra.program.model.data.*;
public class MSVCStructureDBBitFieldTest extends MSVCStructureImplBitFieldTest {
private static DataTypeManager dataMgr;
@Override
public void setUp() throws Exception {
getDataTypeManager().startTransaction("Test");
super.setUp();
}
@Override
protected DataTypeManager getDataTypeManager() {
synchronized (MSVCStructureDBBitFieldTest.class) {
if (dataMgr == null) {
dataMgr = new StandAloneDataTypeManager("Test");
DataOrganizationImpl dataOrg = (DataOrganizationImpl) dataMgr.getDataOrganization();
DataOrganizationTestUtils.initDataOrganizationWindows64BitX86(dataOrg);
}
return dataMgr;
}
}
}

View file

@ -0,0 +1,45 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
*
*/
package ghidra.program.database.data;
import ghidra.program.model.data.*;
public class MSVCUnionDBBitFieldTest extends MSVCUnionImplBitFieldTest {
private static DataTypeManager dataMgr;
@Override
public void setUp() throws Exception {
getDataTypeManager().startTransaction("Test");
super.setUp();
}
@Override
protected DataTypeManager getDataTypeManager() {
synchronized (MSVCUnionDBBitFieldTest.class) {
if (dataMgr == null) {
dataMgr = new StandAloneDataTypeManager("Test");
DataOrganizationImpl dataOrg = (DataOrganizationImpl) dataMgr.getDataOrganization();
DataOrganizationTestUtils.initDataOrganizationWindows64BitX86(dataOrg);
}
return dataMgr;
}
}
}

View file

@ -0,0 +1,45 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
*
*/
package ghidra.program.database.data;
import ghidra.program.model.data.*;
public class StructureDBBigEndianBitFieldTest extends StructureImplBigEndianBitFieldTest {
private static DataTypeManager dataMgr;
@Override
public void setUp() throws Exception {
getDataTypeManager().startTransaction("Test");
super.setUp();
}
@Override
protected DataTypeManager getDataTypeManager() {
synchronized (MSVCStructureDBBitFieldTest.class) {
if (dataMgr == null) {
dataMgr = new StandAloneDataTypeManager("Test");
DataOrganizationImpl dataOrg = (DataOrganizationImpl) dataMgr.getDataOrganization();
DataOrganizationTestUtils.initDataOrganization32BitMips(dataOrg);
}
return dataMgr;
}
}
}

View file

@ -0,0 +1,45 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
*
*/
package ghidra.program.database.data;
import ghidra.program.model.data.*;
public class StructureDBLittleEndianBitFieldTest extends StructureImplLittleEndianBitFieldTest {
private static DataTypeManager dataMgr;
@Override
public void setUp() throws Exception {
getDataTypeManager().startTransaction("Test");
super.setUp();
}
@Override
protected DataTypeManager getDataTypeManager() {
synchronized (MSVCStructureDBBitFieldTest.class) {
if (dataMgr == null) {
dataMgr = new StandAloneDataTypeManager("Test");
DataOrganizationImpl dataOrg = (DataOrganizationImpl) dataMgr.getDataOrganization();
DataOrganizationTestUtils.initDataOrganizationGcc64BitX86(dataOrg);
}
return dataMgr;
}
}
}

View file

@ -22,21 +22,30 @@ import static org.junit.Assert.*;
import org.junit.*;
import generic.test.AbstractGenericTest;
import generic.test.AbstractGTest;
import ghidra.program.model.data.*;
/**
*
*/
public class StructureImplTest extends AbstractGenericTest {
public class StructureDataTypeTest extends AbstractGTest {
private Structure struct;
/**
* @param arg0
*/
public StructureImplTest() {
super();
@Before
public void setUp() throws Exception {
struct = createStructure("TestStruct", 0);
struct.add(new ByteDataType(), "field1", "Comment1");
struct.add(new WordDataType(), null, "Comment2");
struct.add(new DWordDataType(), "field3", null);
struct.add(new ByteDataType(), "field4", "Comment4");
}
private void transitionToBigEndian() {
// transition default little-endian structure to big-endian
DataTypeManager beDtm = new MyBigEndianDataTypeManager();
struct = (Structure) struct.clone(beDtm);
}
private Structure createStructure(String name, int length) {
@ -56,21 +65,7 @@ public class StructureImplTest extends AbstractGenericTest {
}
private Pointer createPointer(DataType dataType, int length) {
return new Pointer32DataType(dataType);
}
@Before
public void setUp() throws Exception {
struct = createStructure("Test", 0);
struct.add(new ByteDataType(), "field0", "Comment1");
struct.add(new WordDataType(), null, "Comment2");
struct.add(new DWordDataType(), "field3", null);
struct.add(new ByteDataType(), "field4", "Comment4");
}
@After
public void tearDown() throws Exception {
return new PointerDataType(dataType, length);
}
@Test
@ -81,14 +76,15 @@ public class StructureImplTest extends AbstractGenericTest {
DataTypeComponent dtc = struct.getComponent(0);
assertEquals(0, dtc.getOffset());
assertEquals(0, dtc.getOrdinal());
assertEquals("field0", dtc.getFieldName());
assertEquals("field1", dtc.getFieldName());
assertEquals("Comment1", dtc.getComment());
assertEquals(ByteDataType.class, dtc.getDataType().getClass());
dtc = struct.getComponent(1);
assertEquals(1, dtc.getOffset());
assertEquals(1, dtc.getOrdinal());
assertNull(dtc.getFieldName());
assertEquals("field_0x1", dtc.getDefaultFieldName());
assertEquals(null, dtc.getFieldName());
assertEquals("Comment2", dtc.getComment());
assertEquals(WordDataType.class, dtc.getDataType().getClass());
@ -115,8 +111,8 @@ public class StructureImplTest extends AbstractGenericTest {
assertEquals(10, struct.getLength());
assertEquals(10, struct.getNumComponents());
struct.add(new ByteDataType(), "field0", "Comment1");
struct.add(new WordDataType(), "field1", "Comment2");
struct.add(new ByteDataType(), "field1", "Comment1");
struct.add(new WordDataType(), null, "Comment2");
struct.add(new DWordDataType(), "field3", null);
struct.add(new ByteDataType(), "field4", "Comment4");
@ -126,28 +122,33 @@ public class StructureImplTest extends AbstractGenericTest {
DataTypeComponent dtc = struct.getComponent(0);
assertEquals(0, dtc.getOffset());
assertEquals(0, dtc.getOrdinal());
assertEquals("field_0x0", dtc.getDefaultFieldName());
assertNull(dtc.getFieldName());
assertEquals(null, dtc.getComment());
assertNull(dtc.getComment());
assertEquals(DataType.DEFAULT, dtc.getDataType());
dtc = struct.getComponent(1);
assertEquals(1, dtc.getOffset());
assertEquals(1, dtc.getOrdinal());
assertEquals("field_0x1", dtc.getDefaultFieldName());
assertNull(dtc.getFieldName());
assertEquals(null, dtc.getComment());
assertEquals(DataType.DEFAULT, dtc.getDataType());
dtc = struct.getComponent(10);
assertEquals(10, dtc.getOffset());
assertEquals(10, dtc.getOrdinal());
assertEquals("field0", dtc.getFieldName());
assertEquals("field1", dtc.getFieldName());
assertEquals("Comment1", dtc.getComment());
assertEquals(ByteDataType.class, dtc.getDataType().getClass());
dtc = struct.getComponent(11);
assertEquals(11, dtc.getOffset());
assertEquals(11, dtc.getOrdinal());
assertEquals("field1", dtc.getFieldName());
assertEquals("field_0xb", dtc.getDefaultFieldName());
assertNull(dtc.getFieldName());
assertEquals("Comment2", dtc.getComment());
assertEquals(WordDataType.class, dtc.getDataType().getClass());
@ -168,20 +169,22 @@ public class StructureImplTest extends AbstractGenericTest {
DataTypeComponent dtc = struct.getComponent(0);
assertEquals(0, dtc.getOffset());
assertEquals(0, dtc.getOrdinal());
assertEquals(null, dtc.getFieldName());
assertEquals(null, dtc.getComment());
assertEquals("field_0x0", dtc.getDefaultFieldName());
assertNull(dtc.getFieldName());
assertNull(dtc.getComment());
assertEquals(FloatDataType.class, dtc.getDataType().getClass());
dtc = struct.getComponent(1);
assertEquals(4, dtc.getOffset());
assertEquals(1, dtc.getOrdinal());
assertEquals("field0", dtc.getFieldName());
assertEquals("field1", dtc.getFieldName());
assertEquals("Comment1", dtc.getComment());
assertEquals(ByteDataType.class, dtc.getDataType().getClass());
dtc = struct.getComponent(2);
assertEquals(5, dtc.getOffset());
assertEquals(2, dtc.getOrdinal());
assertEquals("field_0x5", dtc.getDefaultFieldName());
assertNull(dtc.getFieldName());
assertEquals("Comment2", dtc.getComment());
assertEquals(WordDataType.class, dtc.getDataType().getClass());
@ -204,6 +207,7 @@ public class StructureImplTest extends AbstractGenericTest {
@Test
public void testInsert_end() {
struct.insert(4, new FloatDataType());
assertEquals(12, struct.getLength());
assertEquals(5, struct.getNumComponents());
@ -211,14 +215,15 @@ public class StructureImplTest extends AbstractGenericTest {
DataTypeComponent dtc = struct.getComponent(0);
assertEquals(0, dtc.getOffset());
assertEquals(0, dtc.getOrdinal());
assertEquals("field0", dtc.getFieldName());
assertEquals("field1", dtc.getFieldName());
assertEquals("Comment1", dtc.getComment());
assertEquals(ByteDataType.class, dtc.getDataType().getClass());
dtc = struct.getComponent(1);
assertEquals(1, dtc.getOffset());
assertEquals(1, dtc.getOrdinal());
assertEquals(null, dtc.getFieldName());
assertEquals("field_0x1", dtc.getDefaultFieldName());
assertNull(dtc.getFieldName());
assertEquals("Comment2", dtc.getComment());
assertEquals(WordDataType.class, dtc.getDataType().getClass());
@ -239,6 +244,7 @@ public class StructureImplTest extends AbstractGenericTest {
dtc = struct.getComponent(4);
assertEquals(8, dtc.getOffset());
assertEquals(4, dtc.getOrdinal());
assertEquals("field_0x8", dtc.getDefaultFieldName());
assertNull(dtc.getFieldName());
assertEquals(null, dtc.getComment());
assertEquals(FloatDataType.class, dtc.getDataType().getClass());
@ -247,6 +253,7 @@ public class StructureImplTest extends AbstractGenericTest {
@Test
public void testInsert_middle() {
struct.insert(2, new FloatDataType());
assertEquals(12, struct.getLength());
assertEquals(5, struct.getNumComponents());
@ -254,13 +261,14 @@ public class StructureImplTest extends AbstractGenericTest {
DataTypeComponent dtc = struct.getComponent(0);
assertEquals(0, dtc.getOffset());
assertEquals(0, dtc.getOrdinal());
assertEquals("field0", dtc.getFieldName());
assertEquals("field1", dtc.getFieldName());
assertEquals("Comment1", dtc.getComment());
assertEquals(ByteDataType.class, dtc.getDataType().getClass());
dtc = struct.getComponent(1);
assertEquals(1, dtc.getOffset());
assertEquals(1, dtc.getOrdinal());
assertEquals("field_0x1", dtc.getDefaultFieldName());
assertNull(dtc.getFieldName());
assertEquals("Comment2", dtc.getComment());
assertEquals(WordDataType.class, dtc.getDataType().getClass());
@ -268,8 +276,9 @@ public class StructureImplTest extends AbstractGenericTest {
dtc = struct.getComponent(2);
assertEquals(3, dtc.getOffset());
assertEquals(2, dtc.getOrdinal());
assertEquals("field_0x3", dtc.getDefaultFieldName());
assertNull(dtc.getFieldName());
assertEquals(null, dtc.getComment());
assertNull(dtc.getComment());
assertEquals(FloatDataType.class, dtc.getDataType().getClass());
dtc = struct.getComponent(3);
@ -285,6 +294,7 @@ public class StructureImplTest extends AbstractGenericTest {
assertEquals("field4", dtc.getFieldName());
assertEquals("Comment4", dtc.getComment());
assertEquals(ByteDataType.class, dtc.getDataType().getClass());
}
@Test
@ -403,6 +413,304 @@ public class StructureImplTest extends AbstractGenericTest {
assertEquals(104, struct.getLength());
}
@Test
public void testInsertBitFieldLittleEndianAppend() throws Exception {
struct.insertBitField(4, 4, 0, IntegerDataType.dataType, 3, "bf1", "bf1Comment");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/TestStruct\n" +
"Unaligned\n" +
"Structure TestStruct {\n" +
" 0 byte 1 field1 \"Comment1\"\n" +
" 1 word 2 null \"Comment2\"\n" +
" 3 dword 4 field3 \"\"\n" +
" 7 byte 1 field4 \"Comment4\"\n" +
" 8 int:3(0) 1 bf1 \"bf1Comment\"\n" +
" 9 undefined 1 null \"\"\n" +
" 10 undefined 1 null \"\"\n" +
" 11 undefined 1 null \"\"\n" +
"}\n" +
"Size = 12 Actual Alignment = 1", struct);
//@formatter:on
struct.insertBitField(4, 4, 3, IntegerDataType.dataType, 3, "bf2", "bf2Comment");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/TestStruct\n" +
"Unaligned\n" +
"Structure TestStruct {\n" +
" 0 byte 1 field1 \"Comment1\"\n" +
" 1 word 2 null \"Comment2\"\n" +
" 3 dword 4 field3 \"\"\n" +
" 7 byte 1 field4 \"Comment4\"\n" +
" 8 int:3(0) 1 bf1 \"bf1Comment\"\n" +
" 8 int:3(3) 1 bf2 \"bf2Comment\"\n" +
" 9 undefined 1 null \"\"\n" +
" 10 undefined 1 null \"\"\n" +
" 11 undefined 1 null \"\"\n" +
"}\n" +
"Size = 12 Actual Alignment = 1", struct);
//@formatter:on
}
@Test
public void testInsertBitFieldAtLittleEndianAppend() throws Exception {
struct.insertBitFieldAt(10, 4, 0, IntegerDataType.dataType, 3, "bf1", "bf1Comment");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/TestStruct\n" +
"Unaligned\n" +
"Structure TestStruct {\n" +
" 0 byte 1 field1 \"Comment1\"\n" +
" 1 word 2 null \"Comment2\"\n" +
" 3 dword 4 field3 \"\"\n" +
" 7 byte 1 field4 \"Comment4\"\n" +
" 8 undefined 1 null \"\"\n" +
" 9 undefined 1 null \"\"\n" +
" 10 int:3(0) 1 bf1 \"bf1Comment\"\n" +
" 11 undefined 1 null \"\"\n" +
" 12 undefined 1 null \"\"\n" +
" 13 undefined 1 null \"\"\n" +
"}\n" +
"Size = 14 Actual Alignment = 1", struct);
//@formatter:on
struct.insertBitFieldAt(10, 4, 3, IntegerDataType.dataType, 3, "bf2", "bf2Comment");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/TestStruct\n" +
"Unaligned\n" +
"Structure TestStruct {\n" +
" 0 byte 1 field1 \"Comment1\"\n" +
" 1 word 2 null \"Comment2\"\n" +
" 3 dword 4 field3 \"\"\n" +
" 7 byte 1 field4 \"Comment4\"\n" +
" 8 undefined 1 null \"\"\n" +
" 9 undefined 1 null \"\"\n" +
" 10 int:3(0) 1 bf1 \"bf1Comment\"\n" +
" 10 int:3(3) 1 bf2 \"bf2Comment\"\n" +
" 11 undefined 1 null \"\"\n" +
" 12 undefined 1 null \"\"\n" +
" 13 undefined 1 null \"\"\n" +
"}\n" +
"Size = 14 Actual Alignment = 1", struct);
//@formatter:on
}
@Test
public void testInsertBitFieldAtLittleEndian() throws Exception {
struct.insertBitFieldAt(2, 4, 0, IntegerDataType.dataType, 3, "bf1", "bf1Comment");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/TestStruct\n" +
"Unaligned\n" +
"Structure TestStruct {\n" +
" 0 byte 1 field1 \"Comment1\"\n" +
" 1 undefined 1 null \"\"\n" +
" 2 int:3(0) 1 bf1 \"bf1Comment\"\n" +
" 3 undefined 1 null \"\"\n" +
" 4 undefined 1 null \"\"\n" +
" 5 undefined 1 null \"\"\n" +
" 6 word 2 null \"Comment2\"\n" +
" 8 dword 4 field3 \"\"\n" +
" 12 byte 1 field4 \"Comment4\"\n" +
"}\n" +
"Size = 13 Actual Alignment = 1", struct);
//@formatter:on
struct.insertBitFieldAt(2, 4, 3, IntegerDataType.dataType, 3, "bf2", "bf2Comment");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/TestStruct\n" +
"Unaligned\n" +
"Structure TestStruct {\n" +
" 0 byte 1 field1 \"Comment1\"\n" +
" 1 undefined 1 null \"\"\n" +
" 2 int:3(0) 1 bf1 \"bf1Comment\"\n" +
" 2 int:3(3) 1 bf2 \"bf2Comment\"\n" +
" 3 undefined 1 null \"\"\n" +
" 4 undefined 1 null \"\"\n" +
" 5 undefined 1 null \"\"\n" +
" 6 word 2 null \"Comment2\"\n" +
" 8 dword 4 field3 \"\"\n" +
" 12 byte 1 field4 \"Comment4\"\n" +
"}\n" +
"Size = 13 Actual Alignment = 1", struct);
//@formatter:on
struct.insertBitFieldAt(2, 4, 6, IntegerDataType.dataType, 15, "bf3", "bf3Comment");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/TestStruct\n" +
"Unaligned\n" +
"Structure TestStruct {\n" +
" 0 byte 1 field1 \"Comment1\"\n" +
" 1 undefined 1 null \"\"\n" +
" 2 int:3(0) 1 bf1 \"bf1Comment\"\n" +
" 2 int:3(3) 1 bf2 \"bf2Comment\"\n" +
" 2 int:15(6) 3 bf3 \"bf3Comment\"\n" +
" 5 undefined 1 null \"\"\n" +
" 6 word 2 null \"Comment2\"\n" +
" 8 dword 4 field3 \"\"\n" +
" 12 byte 1 field4 \"Comment4\"\n" +
"}\n" +
"Size = 13 Actual Alignment = 1", struct);
//@formatter:on
try {
struct.insertBitFieldAt(2, 4, 21, IntegerDataType.dataType, 12, "bf4", "bf4Comment");
fail(
"expected - IllegalArgumentException: Bitfield does not fit within specified constraints");
}
catch (IllegalArgumentException e) {
// expected
}
struct.insertBitFieldAt(2, 4, 21, IntegerDataType.dataType, 11, "bf4", "bf4Comment");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/TestStruct\n" +
"Unaligned\n" +
"Structure TestStruct {\n" +
" 0 byte 1 field1 \"Comment1\"\n" +
" 1 undefined 1 null \"\"\n" +
" 2 int:3(0) 1 bf1 \"bf1Comment\"\n" +
" 2 int:3(3) 1 bf2 \"bf2Comment\"\n" +
" 2 int:15(6) 3 bf3 \"bf3Comment\"\n" +
" 4 int:11(5) 2 bf4 \"bf4Comment\"\n" +
" 6 word 2 null \"Comment2\"\n" +
" 8 dword 4 field3 \"\"\n" +
" 12 byte 1 field4 \"Comment4\"\n" +
"}\n" +
"Size = 13 Actual Alignment = 1", struct);
//@formatter:on
}
@Test
public void testInsertBitFieldAtBigEndian() throws Exception {
transitionToBigEndian();
try {
struct.insertBitFieldAt(2, 4, 30, IntegerDataType.dataType, 3, "bf1", "bf1Comment");
fail(
"expected - IllegalArgumentException: Bitfield does not fit within specified constraints");
}
catch (IllegalArgumentException e) {
// expected
}
struct.insertBitFieldAt(2, 4, 29, IntegerDataType.dataType, 3, "bf1", "bf1Comment");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/TestStruct\n" +
"Unaligned\n" +
"Structure TestStruct {\n" +
" 0 byte 1 field1 \"Comment1\"\n" +
" 1 undefined 1 null \"\"\n" +
" 2 int:3(5) 1 bf1 \"bf1Comment\"\n" +
" 3 undefined 1 null \"\"\n" +
" 4 undefined 1 null \"\"\n" +
" 5 undefined 1 null \"\"\n" +
" 6 word 2 null \"Comment2\"\n" +
" 8 dword 4 field3 \"\"\n" +
" 12 byte 1 field4 \"Comment4\"\n" +
"}\n" +
"Size = 13 Actual Alignment = 1", struct);
//@formatter:on
struct.insertBitFieldAt(2, 4, 26, IntegerDataType.dataType, 3, "bf2", "bf2Comment");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/TestStruct\n" +
"Unaligned\n" +
"Structure TestStruct {\n" +
" 0 byte 1 field1 \"Comment1\"\n" +
" 1 undefined 1 null \"\"\n" +
" 2 int:3(5) 1 bf1 \"bf1Comment\"\n" +
" 2 int:3(2) 1 bf2 \"bf2Comment\"\n" +
" 3 undefined 1 null \"\"\n" +
" 4 undefined 1 null \"\"\n" +
" 5 undefined 1 null \"\"\n" +
" 6 word 2 null \"Comment2\"\n" +
" 8 dword 4 field3 \"\"\n" +
" 12 byte 1 field4 \"Comment4\"\n" +
"}\n" +
"Size = 13 Actual Alignment = 1", struct);
//@formatter:on
struct.insertBitFieldAt(2, 4, 11, IntegerDataType.dataType, 15, "bf3", "bf3Comment");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/TestStruct\n" +
"Unaligned\n" +
"Structure TestStruct {\n" +
" 0 byte 1 field1 \"Comment1\"\n" +
" 1 undefined 1 null \"\"\n" +
" 2 int:3(5) 1 bf1 \"bf1Comment\"\n" +
" 2 int:3(2) 1 bf2 \"bf2Comment\"\n" +
" 2 int:15(3) 3 bf3 \"bf3Comment\"\n" +
" 5 undefined 1 null \"\"\n" +
" 6 word 2 null \"Comment2\"\n" +
" 8 dword 4 field3 \"\"\n" +
" 12 byte 1 field4 \"Comment4\"\n" +
"}\n" +
"Size = 13 Actual Alignment = 1", struct);
//@formatter:on
struct.insertBitFieldAt(2, 4, 0, IntegerDataType.dataType, 11, "bf4", "bf4Comment");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/TestStruct\n" +
"Unaligned\n" +
"Structure TestStruct {\n" +
" 0 byte 1 field1 \"Comment1\"\n" +
" 1 undefined 1 null \"\"\n" +
" 2 int:3(5) 1 bf1 \"bf1Comment\"\n" +
" 2 int:3(2) 1 bf2 \"bf2Comment\"\n" +
" 2 int:15(3) 3 bf3 \"bf3Comment\"\n" +
" 4 int:11(0) 2 bf4 \"bf4Comment\"\n" +
" 6 word 2 null \"Comment2\"\n" +
" 8 dword 4 field3 \"\"\n" +
" 12 byte 1 field4 \"Comment4\"\n" +
"}\n" +
"Size = 13 Actual Alignment = 1", struct);
//@formatter:on
}
@Test
public void testInsertAtOffsetAfterBeforeBitField() throws Exception {
struct.insertBitFieldAt(2, 4, 0, IntegerDataType.dataType, 3, "bf1", "bf1Comment");
struct.insertBitFieldAt(2, 4, 3, IntegerDataType.dataType, 3, "bf2", "bf2Comment");
struct.insertBitFieldAt(2, 4, 6, IntegerDataType.dataType, 15, "bf3", "bf3Comment");
struct.insertBitFieldAt(2, 4, 21, IntegerDataType.dataType, 11, "bf4", "bf4Comment");
struct.insertAtOffset(2, FloatDataType.dataType, 4);
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/TestStruct\n" +
"Unaligned\n" +
"Structure TestStruct {\n" +
" 0 byte 1 field1 \"Comment1\"\n" +
" 1 undefined 1 null \"\"\n" +
" 2 float 4 null \"\"\n" +
" 6 int:3(0) 1 bf1 \"bf1Comment\"\n" +
" 6 int:3(3) 1 bf2 \"bf2Comment\"\n" +
" 6 int:15(6) 3 bf3 \"bf3Comment\"\n" +
" 8 int:11(5) 2 bf4 \"bf4Comment\"\n" +
" 10 word 2 null \"Comment2\"\n" +
" 12 dword 4 field3 \"\"\n" +
" 16 byte 1 field4 \"Comment4\"\n" +
"}\n" +
"Size = 17 Actual Alignment = 1", struct);
//@formatter:on
}
@Test
public void testClearComponent() {
struct.clearComponent(0);
@ -444,7 +752,17 @@ public class StructureImplTest extends AbstractGenericTest {
}
@Test
public void testReplace1() {// bigger, space below
public void testReplace() { // bigger, no space below
try {
struct.replace(0, new QWordDataType(), 8);
Assert.fail();
}
catch (Exception e) {
}
}
@Test
public void testReplace1() { // bigger, space below
struct.insert(1, new QWordDataType());
struct.clearComponent(1);
assertEquals(16, struct.getLength());
@ -459,7 +777,7 @@ public class StructureImplTest extends AbstractGenericTest {
}
@Test
public void testReplace2() {// same size
public void testReplace2() { // same size
struct.replace(0, new CharDataType(), 1);
assertEquals(8, struct.getLength());
assertEquals(4, struct.getNumComponents());
@ -470,7 +788,7 @@ public class StructureImplTest extends AbstractGenericTest {
}
@Test
public void testReplace3() {// smaller
public void testReplace3() { // smaller
struct.replace(1, new CharDataType(), 1);
assertEquals(8, struct.getLength());
assertEquals(5, struct.getNumComponents());
@ -623,13 +941,66 @@ public class StructureImplTest extends AbstractGenericTest {
s.add(new FloatDataType());
struct.add(s);
s.deleteAll();
assertEquals(1, s.getLength());
assertTrue(s.isNotYetDefined());
assertEquals(0, s.getNumComponents());
}
@Test
public void testGetComponents() {
struct = createStructure("Test", 8);
struct.insert(2, new ByteDataType(), 1, "field3", "Comment1");
struct.insert(5, new WordDataType(), 2, null, "Comment2");
struct.insert(7, new DWordDataType(), 4, "field8", null);
assertEquals(15, struct.getLength());
assertEquals(11, struct.getNumComponents());
DataTypeComponent[] dtcs = struct.getComponents();
assertEquals(11, dtcs.length);
int offset = 0;
for (int i = 0; i < 11; i++) {
assertEquals(i, dtcs[i].getOrdinal());
assertEquals(offset, dtcs[i].getOffset());
offset += dtcs[i].getLength();
}
assertEquals(DataType.DEFAULT, dtcs[0].getDataType());
assertEquals(DataType.DEFAULT, dtcs[1].getDataType());
assertEquals(ByteDataType.class, dtcs[2].getDataType().getClass());
assertEquals(DataType.DEFAULT, dtcs[3].getDataType());
assertEquals(DataType.DEFAULT, dtcs[4].getDataType());
assertEquals(WordDataType.class, dtcs[5].getDataType().getClass());
assertEquals(DataType.DEFAULT, dtcs[6].getDataType());
assertEquals(DWordDataType.class, dtcs[7].getDataType().getClass());
assertEquals(DataType.DEFAULT, dtcs[8].getDataType());
assertEquals(DataType.DEFAULT, dtcs[9].getDataType());
assertEquals(DataType.DEFAULT, dtcs[10].getDataType());
}
@Test
public void testGetDefinedComponents() {
struct = createStructure("Test", 8);
struct.insert(2, new ByteDataType(), 1, "field3", "Comment1");
struct.insert(5, new WordDataType(), 2, null, "Comment2");
struct.insert(7, new DWordDataType(), 4, "field8", null);
assertEquals(15, struct.getLength());
assertEquals(11, struct.getNumComponents());
DataTypeComponent[] dtcs = struct.getDefinedComponents();
assertEquals(3, dtcs.length);
assertEquals(ByteDataType.class, dtcs[0].getDataType().getClass());
assertEquals(2, dtcs[0].getOrdinal());
assertEquals(2, dtcs[0].getOffset());
assertEquals(WordDataType.class, dtcs[1].getDataType().getClass());
assertEquals(5, dtcs[1].getOrdinal());
assertEquals(5, dtcs[1].getOffset());
assertEquals(DWordDataType.class, dtcs[2].getDataType().getClass());
assertEquals(7, dtcs[2].getOrdinal());
assertEquals(8, dtcs[2].getOffset());
}
@Test
public void testGetComponentAt() {
DataTypeComponent dtc = struct.getComponentAt(4);
@ -638,19 +1009,6 @@ public class StructureImplTest extends AbstractGenericTest {
assertEquals(3, dtc.getOffset());
}
@Test
public void testGetDataTypeAt() {
Structure s1 = createStructure("Test1", 0);
s1.add(new WordDataType());
s1.add(struct);
s1.add(new ByteDataType());
DataTypeComponent dtc = s1.getComponentAt(7);
assertEquals(struct, dtc.getDataType());
dtc = s1.getDataTypeAt(7);
assertEquals(DWordDataType.class, dtc.getDataType().getClass());
}
@Test
public void testAddVarLengthDataTypes() {
Structure s1 = createStructure("Test1", 0);
@ -732,6 +1090,134 @@ public class StructureImplTest extends AbstractGenericTest {
assertEquals("NewTypedef", typdef.getName());
}
@Test
public void testGetDataTypeAt() {
Structure s1 = createStructure("Test1", 0);
s1.add(new WordDataType());
s1.add(struct);
s1.add(new ByteDataType());
DataTypeComponent dtc = s1.getComponentAt(7);
assertEquals(struct, dtc.getDataType());
dtc = s1.getDataTypeAt(7);
assertEquals(DWordDataType.class, dtc.getDataType().getClass());
}
@Test
public void testReplaceWith() {
assertEquals(8, struct.getLength());
assertEquals(4, struct.getNumComponents());
Structure newStruct = createStructure("Replaced", 8);
newStruct.setDescription("testReplaceWith()");
DataTypeComponent dtc0 = newStruct.insert(2, new ByteDataType(), 1, "field3", "Comment1");
DataTypeComponent dtc1 = newStruct.insert(5, new WordDataType(), 2, null, "Comment2");
DataTypeComponent dtc2 = newStruct.insert(7, new DWordDataType(), 4, "field8", null);
struct.replaceWith(newStruct);
assertEquals(15, struct.getLength());
assertEquals(11, struct.getNumComponents());
DataTypeComponent[] dtcs = struct.getDefinedComponents();
assertEquals(3, dtcs.length);
assertEquals(dtc0, dtcs[0]);
assertEquals(dtc1, dtcs[1]);
assertEquals(dtc2, dtcs[2]);
assertEquals("TestStruct", struct.getName());
assertEquals("", struct.getDescription());
}
@Test
public void testReplaceWith2() throws InvalidDataTypeException {
// NOTE: unaligned bitfields should remain unchanged when
// transitioning endianess even though it makes little sense.
// Unaligned structures are not intended to be portable!
TypeDef td = new TypedefDataType("Foo", IntegerDataType.dataType);
struct.insertBitFieldAt(9, 1, 0, td, 4, "MyBit1", "bitComment1");
struct.insertBitFieldAt(9, 1, 4, td, 3, "MyBit2", "bitComment2");
struct.insertBitFieldAt(9, 2, 7, td, 2, "MyBit3", "bitComment3");
struct.growStructure(1);
struct.setFlexibleArrayComponent(td, "myFlex", "flexComment");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/TestStruct\n" +
"Unaligned\n" +
"Structure TestStruct {\n" +
" 0 byte 1 field1 \"Comment1\"\n" +
" 1 word 2 null \"Comment2\"\n" +
" 3 dword 4 field3 \"\"\n" +
" 7 byte 1 field4 \"Comment4\"\n" +
" 8 undefined 1 null \"\"\n" +
" 9 Foo:4(0) 1 MyBit1 \"bitComment1\"\n" +
" 9 Foo:3(4) 1 MyBit2 \"bitComment2\"\n" +
" 9 Foo:2(7) 2 MyBit3 \"bitComment3\"\n" +
" 11 undefined 1 null \"\"\n" +
" Foo[0] 0 myFlex \"flexComment\"\n" +
"}\n" +
"Size = 12 Actual Alignment = 1", struct);
//@formatter:on
DataTypeManager beDtm = new MyBigEndianDataTypeManager();
Structure newStruct = new StructureDataType("bigStruct", 0, beDtm);
newStruct.replaceWith(struct);
assertTrue(newStruct.getDataOrganization().isBigEndian());
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/bigStruct\n" +
"Unaligned\n" +
"Structure bigStruct {\n" +
" 0 byte 1 field1 \"Comment1\"\n" +
" 1 word 2 null \"Comment2\"\n" +
" 3 dword 4 field3 \"\"\n" +
" 7 byte 1 field4 \"Comment4\"\n" +
" 8 undefined 1 null \"\"\n" +
" 9 Foo:4(0) 1 MyBit1 \"bitComment1\"\n" +
" 9 Foo:3(4) 1 MyBit2 \"bitComment2\"\n" +
" 9 Foo:2(7) 2 MyBit3 \"bitComment3\"\n" +
" 11 undefined 1 null \"\"\n" +
" Foo[0] 0 myFlex \"flexComment\"\n" +
"}\n" +
"Size = 12 Actual Alignment = 1", newStruct);
//@formatter:on
}
/**
* Test that a structure can't ... ???
*/
@Test
public void testCyclingProblem() {
Structure newStruct = createStructure("TestStruct", 80);
newStruct.setDescription("testReplaceWith()");
newStruct.add(new ByteDataType(), "field0", "Comment1");
newStruct.add(struct, "field1", null);
newStruct.add(new WordDataType(), null, "Comment2");
newStruct.add(new DWordDataType(), "field3", null);
try {
struct.add(newStruct);
Assert.fail();
}
catch (IllegalArgumentException e) {
}
try {
struct.insert(0, newStruct);
Assert.fail();
}
catch (IllegalArgumentException e) {
}
try {
struct.replace(0, newStruct, newStruct.getLength());
Assert.fail();
}
catch (IllegalArgumentException e) {
}
}
/**
* Test that a structure can't be added to itself.
*/
@ -1049,4 +1535,13 @@ public class StructureImplTest extends AbstractGenericTest {
}
}
protected class MyBigEndianDataTypeManager extends StandAloneDataTypeManager {
MyBigEndianDataTypeManager() {
super("BEdtm");
DataOrganizationImpl dataOrg = DataOrganizationImpl.getDefaultOrganization(null);
dataOrg.setBigEndian(true);
this.dataOrganization = dataOrg;
}
}
}

View file

@ -0,0 +1,45 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
*
*/
package ghidra.program.database.data;
import ghidra.program.model.data.*;
public class UnionDBBigEndianBitFieldTest extends UnionImplBigEndianBitFieldTest {
private static DataTypeManager dataMgr;
@Override
public void setUp() throws Exception {
getDataTypeManager().startTransaction("Test");
super.setUp();
}
@Override
protected DataTypeManager getDataTypeManager() {
synchronized (MSVCStructureDBBitFieldTest.class) {
if (dataMgr == null) {
dataMgr = new StandAloneDataTypeManager("Test");
DataOrganizationImpl dataOrg = (DataOrganizationImpl) dataMgr.getDataOrganization();
DataOrganizationTestUtils.initDataOrganization32BitMips(dataOrg);
}
return dataMgr;
}
}
}

View file

@ -0,0 +1,45 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
*
*/
package ghidra.program.database.data;
import ghidra.program.model.data.*;
public class UnionDBLittleEndianBitFieldTest extends UnionImplLittleEndianBitFieldTest {
private static DataTypeManager dataMgr;
@Override
public void setUp() throws Exception {
getDataTypeManager().startTransaction("Test");
super.setUp();
}
@Override
protected DataTypeManager getDataTypeManager() {
synchronized (MSVCStructureDBBitFieldTest.class) {
if (dataMgr == null) {
dataMgr = new StandAloneDataTypeManager("Test");
DataOrganizationImpl dataOrg = (DataOrganizationImpl) dataMgr.getDataOrganization();
DataOrganizationTestUtils.initDataOrganizationGcc64BitX86(dataOrg);
}
return dataMgr;
}
}
}

View file

@ -13,79 +13,59 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
*
*/
package ghidra.program.database.data;
import static org.junit.Assert.*;
import org.junit.*;
import generic.test.AbstractGenericTest;
import ghidra.program.database.ProgramBuilder;
import ghidra.program.database.ProgramDB;
import generic.test.AbstractGTest;
import ghidra.program.model.data.*;
import ghidra.test.AbstractGhidraHeadlessIntegrationTest;
/**
* Test the database implementation of Union data type.
*
*
*
*/
public class UnionTest extends AbstractGenericTest {
public class UnionDataTypeTest extends AbstractGTest {
private Union union;
private ProgramDB program;
private DataTypeManagerDB dataMgr;
private int transactionID;
/**
* Constructor for UnionTest.
* @param name
*/
public UnionTest() {
super();
}
private Structure createStructure(String name, int length) {
return (Structure) dataMgr.resolve(new StructureDataType(name, length),
DataTypeConflictHandler.DEFAULT_HANDLER);
}
private Union createUnion(String name) {
return (Union) dataMgr.resolve(new UnionDataType(name),
DataTypeConflictHandler.DEFAULT_HANDLER);
}
private TypeDef createTypeDef(DataType dataType) {
return (TypeDef) dataMgr.resolve(
new TypedefDataType(dataType.getName() + "TypeDef", dataType), null);
}
private Array createArray(DataType dataType, int numElements) {
return (Array) dataMgr.resolve(
new ArrayDataType(dataType, numElements, dataType.getLength()), null);
}
private Pointer createPointer(DataType dataType, int length) {
return (Pointer) dataMgr.resolve(new Pointer32DataType(dataType), null);
}
@Before
public void setUp() throws Exception {
program =
AbstractGhidraHeadlessIntegrationTest.createDefaultProgram("Test", ProgramBuilder._TOY, this);
dataMgr = program.getDataManager();
transactionID = program.startTransaction("Test");
union = createUnion("Test");
union = createUnion("TestUnion");
union.add(new ByteDataType(), "field1", "Comment1");
union.add(new WordDataType(), null, "Comment2");
union.add(new DWordDataType(), "field3", null);
union.add(new ByteDataType(), "field4", "Comment4");
}
@After
public void tearDown() throws Exception {
program.endTransaction(transactionID, true);
program.release(this);
private void transitionToBigEndian() {
// transition default little-endian structure to big-endian
DataTypeManager beDtm = new MyBigEndianDataTypeManager();
union = (Union) union.clone(beDtm);
}
private Union createUnion(String name) {
return new UnionDataType(name);
}
private Structure createStructure(String name, int size) {
return new StructureDataType(name, size);
}
private TypeDef createTypeDef(DataType dataType) {
return new TypedefDataType(dataType.getName() + "TypeDef", dataType);
}
private Array createArray(DataType dataType, int numElements) {
return new ArrayDataType(dataType, numElements, dataType.getLength());
}
private Pointer createPointer(DataType dataType, int length) {
return new PointerDataType(dataType, length);
}
@Test
@ -109,12 +89,11 @@ public class UnionTest extends AbstractGenericTest {
@Test
public void testAdd2() {
Structure struct = new StructureDataType("struct_1", 0);
Structure struct = createStructure("struct_1", 0);
struct.add(new ByteDataType());
struct.add(new StringDataType(), 10);
union.add(struct);
union.delete(4);
assertEquals(4, union.getNumComponents());
assertEquals(4, union.getLength());
@ -122,7 +101,7 @@ public class UnionTest extends AbstractGenericTest {
@Test
public void testGetComponent() {
Structure struct = new StructureDataType("struct_1", 0);
Structure struct = createStructure("struct_1", 0);
struct.add(new ByteDataType());
struct.add(new StringDataType(), 10);
DataTypeComponent newdtc = union.add(struct, "field5", "comments");
@ -135,7 +114,7 @@ public class UnionTest extends AbstractGenericTest {
@Test
public void testGetComponents() {
Structure struct = new StructureDataType("struct_1", 0);
Structure struct = createStructure("struct_1", 0);
struct.add(new ByteDataType());
struct.add(new StringDataType(), 10);
union.add(struct, "field5", "comments");
@ -147,7 +126,7 @@ public class UnionTest extends AbstractGenericTest {
@Test
public void testInsert() {
Structure struct = new StructureDataType("struct_1", 0);
Structure struct = createStructure("struct_1", 0);
struct.add(new ByteDataType());
struct.add(new StringDataType(), 10);
@ -161,20 +140,92 @@ public class UnionTest extends AbstractGenericTest {
}
@Test
public void testGetName() {
assertEquals("Test", union.getName());
public void testBitFieldUnionLength() throws Exception {
int cnt = union.getNumComponents();
for (int i = 0; i < cnt; i++) {
union.delete(0);
}
union.insertBitField(0, 4, 12, IntegerDataType.dataType, 2, "bf1", "bf1Comment");
union.insert(0, ShortDataType.dataType);
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/TestUnion\n" +
"Unaligned\n" +
"Union TestUnion {\n" +
" 0 short 2 null \"\"\n" +
" 1 byte:2(4) 1 bf1 \"bf1Comment\"\n" +
"}\n" +
"Size = 4 Actual Alignment = 1", union);
//@formatter:on
}
@Test
public void testClone() throws Exception {
public void testInsertBitFieldLittleEndian() throws Exception {
union.insertBitField(2, 4, 0, IntegerDataType.dataType, 4, "bf1", "bf1Comment");
union.insertBitField(3, 1, 0, ByteDataType.dataType, 4, "bf2", "bf2Comment");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/TestUnion\n" +
"Unaligned\n" +
"Union TestUnion {\n" +
" 0 byte 1 field1 \"Comment1\"\n" +
" 0 word 2 null \"Comment2\"\n" +
" 0 int:4(0) 1 bf1 \"bf1Comment\"\n" +
" 0 byte:4(0) 1 bf2 \"bf2Comment\"\n" +
" 0 dword 4 field3 \"\"\n" +
" 0 byte 1 field4 \"Comment4\"\n" +
"}\n" +
"Size = 4 Actual Alignment = 1", union);
//@formatter:on
}
@Test
public void testInsertBitFieldBigEndian() throws Exception {
transitionToBigEndian();
union.insertBitField(2, 4, 0, IntegerDataType.dataType, 4, "bf1", "bf1Comment");
union.insertBitField(3, 1, 0, ByteDataType.dataType, 4, "bf2", "bf2Comment");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/TestUnion\n" +
"Unaligned\n" +
"Union TestUnion {\n" +
" 0 byte 1 field1 \"Comment1\"\n" +
" 0 word 2 null \"Comment2\"\n" +
" 0 int:4(4) 1 bf1 \"bf1Comment\"\n" +
" 0 byte:4(4) 1 bf2 \"bf2Comment\"\n" +
" 0 dword 4 field3 \"\"\n" +
" 0 byte 1 field4 \"Comment4\"\n" +
"}\n" +
"Size = 4 Actual Alignment = 1", union);
//@formatter:on
}
@Test
public void testGetName() {
assertEquals("TestUnion", union.getName());
}
@Test
public void testCloneRetainIdentity() throws Exception {
Union unionCopy = (Union) union.clone(null);
assertNull(unionCopy.getDataTypeManager());
assertEquals(4, union.getLength());
}
@Test
public void testCopyDontRetain() throws Exception {
Union unionCopy = (Union) union.copy(null);
assertNull(unionCopy.getDataTypeManager());
assertEquals(4, union.getLength());
}
@Test
public void testDelete() throws Exception {
Structure struct = new StructureDataType("struct_1", 0);
Structure struct = createStructure("struct_1", 0);
struct.add(new ByteDataType());
struct.add(new StringDataType(), 10);
union.add(struct);
@ -189,16 +240,15 @@ public class UnionTest extends AbstractGenericTest {
@Test
public void testIsPartOf() {
Structure struct = new StructureDataType("struct_1", 0);
Structure struct = createStructure("struct_1", 0);
struct.add(new ByteDataType());
DataTypeComponent dtc = struct.add(new StringDataType(), 10);
DataTypeComponent newdtc = union.add(struct);
dtc = union.getComponent(4);
DataTypeComponent dtc = struct.add(createStructure("mystring", 10));
DataType dt = dtc.getDataType();
DataTypeComponent newdtc = union.add(struct);
assertTrue(union.isPartOf(dt));
Structure newstruct = (Structure) newdtc.getDataType();
Structure s1 = (Structure) newstruct.add(new StructureDataType("s1", 1)).getDataType();
Structure s1 = (Structure) newstruct.add(createStructure("s1", 1)).getDataType();
dt = s1.add(new QWordDataType()).getDataType();
assertTrue(union.isPartOf(dt));
@ -206,18 +256,48 @@ public class UnionTest extends AbstractGenericTest {
@Test
public void testReplaceWith() {
Structure struct = new StructureDataType("struct_1", 0);
struct.add(new ByteDataType());
struct.add(new StringDataType(), 10);
Union newunion = new UnionDataType("newunion");
newunion.add(struct);
assertEquals(4, union.getLength());
assertEquals(4, union.getNumComponents());
union.replaceWith(newunion);
assertEquals(1, newunion.getNumComponents());
DataType dt = dataMgr.getDataType("/struct_1");
assertNotNull(dt);
Union newUnion = createUnion("Replaced");
newUnion.setDescription("testReplaceWith()");
DataTypeComponent dtc2 = newUnion.insert(0, new DWordDataType(), 4, "field2", null);
DataTypeComponent dtc1 = newUnion.insert(0, new WordDataType(), 2, null, "Comment2");
DataTypeComponent dtc0 = newUnion.insert(0, new ByteDataType(), 1, "field0", "Comment1");
assertEquals(dt, union.getComponent(0).getDataType());
union.replaceWith(newUnion);
assertEquals(4, union.getLength());
assertEquals(3, union.getNumComponents());
DataTypeComponent[] dtcs = union.getComponents();
assertEquals(3, dtcs.length);
assertEquals(dtc0, dtcs[0]);
assertEquals(dtc1, dtcs[1]);
assertEquals(dtc2, dtcs[2]);
assertEquals("TestUnion", union.getName());
assertEquals("", union.getDescription()); // unchanged
}
@Test
public void testCyclingProblem() {
Union newUnion = createUnion("Test");
newUnion.setDescription("testReplaceWith()");
newUnion.add(new ByteDataType(), "field0", "Comment1");
newUnion.add(union, "field1", null);
newUnion.add(new WordDataType(), null, "Comment2");
newUnion.add(new DWordDataType(), "field3", null);
try {
union.add(newUnion);
Assert.fail();
}
catch (IllegalArgumentException e) {
}
try {
union.insert(0, newUnion);
Assert.fail();
}
catch (IllegalArgumentException e) {
}
}
/**
@ -453,4 +533,12 @@ public class UnionTest extends AbstractGenericTest {
}
}
protected class MyBigEndianDataTypeManager extends StandAloneDataTypeManager {
MyBigEndianDataTypeManager() {
super("BEdtm");
DataOrganizationImpl dataOrg = DataOrganizationImpl.getDefaultOrganization(null);
dataOrg.setBigEndian(true);
this.dataOrganization = dataOrg;
}
}
}

View file

@ -0,0 +1,77 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.program.model.data;
import static org.junit.Assert.assertTrue;
import java.io.FileNotFoundException;
import java.io.InputStream;
import org.junit.Before;
import generic.test.AbstractGTest;
import ghidra.app.util.cparser.C.CParser;
import ghidra.util.Msg;
import resources.ResourceManager;
public abstract class AbstractCompositeImplBitFieldTest extends AbstractGTest {
protected static final String C_SOURCE_FILE = "ghidra/app/util/cparser/bitfields.h";
@Before
public void setUp() throws Exception {
DataTypeManager dataMgr = getDataTypeManager();
if (dataMgr.getDataTypeCount(false) != 0) {
Msg.info(this, "Using previously parsed data types");
return; // already have types
}
Msg.info(this, "Parsing data types from " + C_SOURCE_FILE);
CParser parser = new CParser(dataMgr, true, null);
try (InputStream is = ResourceManager.getResourceAsStream(C_SOURCE_FILE)) {
if (is == null) {
throw new FileNotFoundException("Resource not found: " + C_SOURCE_FILE);
}
Msg.debug(this, "Parsing C headers from " + C_SOURCE_FILE);
parser.parse(is);
}
}
protected class MyDataTypeManager extends StandAloneDataTypeManager {
MyDataTypeManager(String name, DataOrganization dataOrg) {
super(name);
this.dataOrganization = dataOrg;
}
}
abstract DataTypeManager getDataTypeManager();
Structure getStructure(String name) {
DataType dataType = getDataTypeManager().getDataType("/" + name);
assertTrue("Data type not found: " + name, dataType instanceof Structure);
return (Structure) dataType;
}
Union getUnion(String name) {
DataType dataType = getDataTypeManager().getDataType("/" + name);
assertTrue("Data type not found: " + name, dataType instanceof Union);
return (Union) dataType;
}
}

View file

@ -0,0 +1,753 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.program.model.data;
import org.junit.Test;
public class MSVCStructureImplBitFieldTest extends AbstractCompositeImplBitFieldTest {
private static DataTypeManager dataMgr;
@Override
protected DataTypeManager getDataTypeManager() {
synchronized (MSVCStructureImplBitFieldTest.class) {
if (dataMgr == null) {
DataOrganizationImpl dataOrg = DataOrganizationImpl.getDefaultOrganization(null);
DataOrganizationTestUtils.initDataOrganizationWindows64BitX86(dataOrg);
dataMgr = new MyDataTypeManager("test", dataOrg);
}
return dataMgr;
}
}
@Test
public void testStructureBitFieldsB1() {
Structure struct = getStructure("B1");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/B1\n" +
"Aligned\n" +
"Structure B1 {\n" +
" 0 char 1 a \"\"\n" +
" 2 ushort:6(0) 1 b \"\"\n" +
" 4 int:8(0) 1 c \"\"\n" +
" 8 short:4(0) 1 d \"\"\n" +
"}\n" +
"Size = 12 Actual Alignment = 4", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsB2() {
Structure struct = getStructure("B2");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/B2\n" +
"Aligned\n" +
"Structure B2 {\n" +
" 0 char 1 a \"\"\n" +
" 2 ushort:6(0) 1 b \"\"\n" +
" 4 int:8(0) 1 c \"\"\n" +
" 5 int:4(0) 1 d \"\"\n" +
"}\n" +
"Size = 8 Actual Alignment = 4", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsB3() {
Structure struct = getStructure("B3");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/B3\n" +
"Aligned\n" +
"Structure B3 {\n" +
" 0 char 1 a \"\"\n" +
" 2 ushort:6(0) 1 b \"\"\n" +
" 4 int:8(0) 1 c \"\"\n" +
" 8 char 1 d \"\"\n" +
"}\n" +
"Size = 12 Actual Alignment = 4", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsZ1() {
Structure struct = getStructure("Z1");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/Z1\n" +
"Aligned\n" +
"Structure Z1 {\n" +
" 0 char 1 a \"\"\n" +
" 2 int:0(0) 1 \"\"\n" +
" 2 ushort:6(0) 1 b \"\"\n" +
" 4 int:8(0) 1 c \"\"\n" +
" 8 short:4(0) 1 d \"\"\n" +
"}\n" +
"Size = 12 Actual Alignment = 4", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsZ2() {
Structure struct = getStructure("Z2");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/Z2\n" +
"Aligned\n" +
"Structure Z2 {\n" +
" 0 char 1 a \"\"\n" +
" 2 ushort:6(0) 1 b \"\"\n" +
" 4 int:8(0) 1 c \"\"\n" +
" 8 int:0(0) 1 \"\"\n" +
" 8 short:4(0) 1 d \"\"\n" +
"}\n" +
"Size = 12 Actual Alignment = 4", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsZ3() {
Structure struct = getStructure("Z3");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/Z3\n" +
"Aligned\n" +
"Structure Z3 {\n" +
" 0 char 1 a \"\"\n" +
" 2 ushort:6(0) 1 b \"\"\n" +
" 4 int:8(0) 1 c \"\"\n" +
" 5 int:4(0) 1 d \"\"\n" +
" 7 longlong:0(0) 1 \"\"\n" +
"}\n" +
"Size = 8 Actual Alignment = 8", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsZ4() {
Structure struct = getStructure("Z4");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/Z4\n" +
"Aligned\n" +
"Structure Z4 {\n" +
" 0 char 1 a \"\"\n" +
" 2 ushort:6(0) 1 b \"\"\n" +
" 4 int:8(0) 1 c \"\"\n" +
" 8 longlong:0(0) 1 \"\"\n" +
" 8 char 1 d \"\"\n" +
"}\n" +
"Size = 16 Actual Alignment = 8", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsZ5() {
Structure struct = getStructure("Z5");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/Z5\n" +
"Aligned\n" +
"Structure Z5 {\n" +
" 0 char 1 a \"\"\n" +
" 8 int:0(0) 1 \"\"\n" +
" 8 longlong:6(0) 1 b \"\"\n" +
" 16 int:8(0) 1 c \"\"\n" +
" 20 char 1 d \"\"\n" +
"}\n" +
"Size = 24 Actual Alignment = 8", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsZ6() {
Structure struct = getStructure("Z6");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/Z6\n" +
"Aligned\n" +
"Structure Z6 {\n" +
" 0 char 1 a \"\"\n" +
" 8 int:0(0) 1 \"\"\n" +
" 8 longlong:6(0) 1 b \"\"\n" +
" 16 int:8(0) 1 c \"\"\n" +
" 20 char 1 d \"\"\n" +
" 24 longlong:6(0) 1 e \"\"\n" +
" 32 int:8(0) 1 f \"\"\n" +
" 36 char 1 g \"\"\n" +
"}\n" +
"Size = 40 Actual Alignment = 8", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsB1p1() {
Structure struct = getStructure("B1p1");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/B1p1\n" +
"Aligned pack(1)\n" +
"Structure B1p1 {\n" +
" 0 char 1 a \"\"\n" +
" 1 ushort:6(0) 1 b \"\"\n" +
" 3 int:8(0) 1 c \"\"\n" +
" 7 short:4(0) 1 d \"\"\n" +
"}\n" +
"Size = 9 Actual Alignment = 1", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsB2p1() {
Structure struct = getStructure("B2p1");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/B2p1\n" +
"Aligned pack(1)\n" +
"Structure B2p1 {\n" +
" 0 char 1 a \"\"\n" +
" 1 ushort:6(0) 1 b \"\"\n" +
" 3 int:8(0) 1 c \"\"\n" +
" 4 int:4(0) 1 d \"\"\n" +
"}\n" +
"Size = 7 Actual Alignment = 1", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsB3p1() {
Structure struct = getStructure("B3p1");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/B3p1\n" +
"Aligned pack(1)\n" +
"Structure B3p1 {\n" +
" 0 char 1 a \"\"\n" +
" 1 ushort:6(0) 1 b \"\"\n" +
" 3 int:8(0) 1 c \"\"\n" +
" 7 char 1 d \"\"\n" +
"}\n" +
"Size = 8 Actual Alignment = 1", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsZ1p1() {
Structure struct = getStructure("Z1p1");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/Z1p1\n" +
"Aligned pack(1)\n" +
"Structure Z1p1 {\n" +
" 0 char 1 a \"\"\n" +
" 1 int:0(0) 1 \"\"\n" +
" 1 ushort:6(0) 1 b \"\"\n" +
" 3 int:8(0) 1 c \"\"\n" +
" 7 short:4(0) 1 d \"\"\n" +
"}\n" +
"Size = 9 Actual Alignment = 1", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsZ2p1() {
Structure struct = getStructure("Z2p1");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/Z2p1\n" +
"Aligned pack(1)\n" +
"Structure Z2p1 {\n" +
" 0 char 1 a \"\"\n" +
" 1 ushort:6(0) 1 b \"\"\n" +
" 3 int:8(0) 1 c \"\"\n" +
" 7 int:0(0) 1 \"\"\n" +
" 7 short:4(0) 1 d \"\"\n" +
"}\n" +
"Size = 9 Actual Alignment = 1", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsZ3p1() {
Structure struct = getStructure("Z3p1");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/Z3p1\n" +
"Aligned pack(1)\n" +
"Structure Z3p1 {\n" +
" 0 char 1 a \"\"\n" +
" 1 ushort:6(0) 1 b \"\"\n" +
" 3 int:8(0) 1 c \"\"\n" +
" 4 int:4(0) 1 d \"\"\n" +
" 6 longlong:0(0) 1 \"\"\n" +
"}\n" +
"Size = 7 Actual Alignment = 1", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsZ3p1T() {
Structure struct = getStructure("Z3p1T");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/Z3p1T\n" +
"Aligned\n" +
"Structure Z3p1T {\n" +
" 0 char 1 a \"\"\n" +
" 1 Z3p1 7 z3p1 \"\"\n" +
"}\n" +
"Size = 8 Actual Alignment = 1", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsZ4p1() {
Structure struct = getStructure("Z4p1");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/Z4p1\n" +
"Aligned pack(1)\n" +
"Structure Z4p1 {\n" +
" 0 char 1 a \"\"\n" +
" 1 ushort:6(0) 1 b \"\"\n" +
" 3 int:8(0) 1 c \"\"\n" +
" 7 longlong:0(0) 1 \"\"\n" +
" 7 char 1 d \"\"\n" +
"}\n" +
"Size = 8 Actual Alignment = 1", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsB1p2() {
Structure struct = getStructure("B1p2");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/B1p2\n" +
"Aligned pack(2)\n" +
"Structure B1p2 {\n" +
" 0 char 1 a \"\"\n" +
" 2 ushort:6(0) 1 b \"\"\n" +
" 4 int:8(0) 1 c \"\"\n" +
" 8 short:4(0) 1 d \"\"\n" +
"}\n" +
"Size = 10 Actual Alignment = 2", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsB2p2() {
Structure struct = getStructure("B2p2");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/B2p2\n" +
"Aligned pack(2)\n" +
"Structure B2p2 {\n" +
" 0 char 1 a \"\"\n" +
" 2 ushort:6(0) 1 b \"\"\n" +
" 4 int:8(0) 1 c \"\"\n" +
" 5 int:4(0) 1 d \"\"\n" +
"}\n" +
"Size = 8 Actual Alignment = 2", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsB3p2() {
Structure struct = getStructure("B3p2");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/B3p2\n" +
"Aligned pack(2)\n" +
"Structure B3p2 {\n" +
" 0 char 1 a \"\"\n" +
" 2 ushort:6(0) 1 b \"\"\n" +
" 4 int:8(0) 1 c \"\"\n" +
" 8 char 1 d \"\"\n" +
"}\n" +
"Size = 10 Actual Alignment = 2", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsB4p2() {
Structure struct = getStructure("B4p2");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/B4p2\n" +
"Aligned pack(2)\n" +
"Structure B4p2 {\n" +
" 0 char 1 a \"\"\n" +
" 2 ushort:6(0) 1 b \"\"\n" +
" 4 int:8(0) 1 c \"\"\n" +
" 8 longlong 8 d \"\"\n" +
" 16 int:4(0) 1 e \"\"\n" +
"}\n" +
"Size = 20 Actual Alignment = 2", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsZ1p2() {
Structure struct = getStructure("Z1p2");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/Z1p2\n" +
"Aligned pack(2)\n" +
"Structure Z1p2 {\n" +
" 0 char 1 a \"\"\n" +
" 2 int:0(0) 1 \"\"\n" +
" 2 ushort:6(0) 1 b \"\"\n" +
" 4 int:8(0) 1 c \"\"\n" +
" 8 short:4(0) 1 d \"\"\n" +
"}\n" +
"Size = 10 Actual Alignment = 2", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsZ1p2x() {
Structure struct = getStructure("Z1p2x");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/Z1p2x\n" +
"Aligned pack(2)\n" +
"Structure Z1p2x {\n" +
" 0 char 1 a \"\"\n" +
" 2 int:0(0) 1 \"\"\n" +
" 2 ushort:6(0) 1 b \"\"\n" +
" 4 int:8(0) 1 c \"\"\n" +
" 8 short:4(0) 1 d \"\"\n" +
" 8 short:4(4) 1 d1 \"\"\n" +
" 9 short:4(0) 1 d2 \"\"\n" +
" 9 short:4(4) 1 d3 \"\"\n" +
" 10 short:4(0) 1 d4 \"\"\n" +
" 10 short:4(4) 1 d5 \"\"\n" +
" 11 short:4(0) 1 d6 \"\"\n" +
" 11 short:4(4) 1 d7 \"\"\n" +
" 12 short:0(0) 1 \"\"\n" +
" 12 ushort:6(0) 1 _b \"\"\n" +
" 14 int:8(0) 1 _c \"\"\n" +
" 18 short:4(0) 1 _d \"\"\n" +
" 18 short:4(4) 1 _d1 \"\"\n" +
" 19 short:4(0) 1 _d2 \"\"\n" +
" 19 short:4(4) 1 _d3 \"\"\n" +
" 20 short:4(0) 1 _d4 \"\"\n" +
" 20 short:4(4) 1 _d5 \"\"\n" +
" 21 short:4(0) 1 _d6 \"\"\n" +
" 21 short:4(4) 1 _d7 \"\"\n" +
"}\n" +
"Size = 22 Actual Alignment = 2", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsZ2p2() {
Structure struct = getStructure("Z2p2");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/Z2p2\n" +
"Aligned pack(2)\n" +
"Structure Z2p2 {\n" +
" 0 char 1 a \"\"\n" +
" 2 ushort:6(0) 1 b \"\"\n" +
" 4 int:8(0) 1 c \"\"\n" +
" 8 int:0(0) 1 \"\"\n" +
" 8 short:4(0) 1 d \"\"\n" +
"}\n" +
"Size = 10 Actual Alignment = 2", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsZ3p2() {
Structure struct = getStructure("Z3p2");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/Z3p2\n" +
"Aligned pack(2)\n" +
"Structure Z3p2 {\n" +
" 0 char 1 a \"\"\n" +
" 2 ushort:6(0) 1 b \"\"\n" +
" 4 int:8(0) 1 c \"\"\n" +
" 5 int:4(0) 1 d \"\"\n" +
" 7 longlong:0(0) 1 \"\"\n" +
"}\n" +
"Size = 8 Actual Alignment = 2", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsZ4p2() {
Structure struct = getStructure("Z4p2");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/Z4p2\n" +
"Aligned pack(2)\n" +
"Structure Z4p2 {\n" +
" 0 char 1 a \"\"\n" +
" 2 ushort:6(0) 1 b \"\"\n" +
" 4 int:8(0) 1 c \"\"\n" +
" 8 longlong:0(0) 1 \"\"\n" +
" 8 char 1 d \"\"\n" +
"}\n" +
"Size = 10 Actual Alignment = 2", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsZ5p2() {
Structure struct = getStructure("Z5p2");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/Z5p2\n" +
"Aligned pack(2)\n" +
"Structure Z5p2 {\n" +
" 0 char 1 a \"\"\n" +
" 2 ushort:12(0) 2 b \"\"\n" +
" 4 int:8(0) 1 c \"\"\n" +
" 8 longlong:0(0) 1 \"\"\n" +
" 8 char 1 d \"\"\n" +
"}\n" +
"Size = 10 Actual Alignment = 2", struct);
//@formatter:on
}
@Test
public void testStructureBitFields_x1p2() {
Structure struct = getStructure("x1p2");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/x1p2\n" +
"Aligned pack(2)\n" +
"Structure x1p2 {\n" +
" 0 char 1 a \"\"\n" +
"}\n" +
"Size = 1 Actual Alignment = 1", struct);
//@formatter:on
}
@Test
public void testStructureBitFields_x2p2() {
Structure struct = getStructure("x2p2");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/x2p2\n" +
"Aligned pack(2)\n" +
"Structure x2p2 {\n" +
" 0 char 1 a \"\"\n" +
" 2 int:27(0) 4 b \"\"\n" +
"}\n" +
"Size = 6 Actual Alignment = 2", struct);
//@formatter:on
}
@Test
public void testStructureBitFields_x3p2() {
Structure struct = getStructure("x3p2");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/x3p2\n" +
"Aligned pack(2)\n" +
"Structure x3p2 {\n" +
" 0 char 1 a \"\"\n" +
" 2 short:0(0) 1 \"\"\n" +
" 2 int:27(0) 4 b \"\"\n" +
"}\n" +
"Size = 6 Actual Alignment = 2", struct);
//@formatter:on
}
@Test
public void testStructureBitFields_x4p2() {
Structure struct = getStructure("x4p2");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/x4p2\n" +
"Aligned pack(2)\n" +
"Structure x4p2 {\n" +
" 0 char 1 a \"\"\n" +
" 2 int:27(0) 4 b \"\"\n" +
" 5 longlong:0(0) 1 \"\"\n" +
"}\n" +
"Size = 6 Actual Alignment = 2", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsZ5p4() {
Structure struct = getStructure("Z5p4");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/Z5p4\n" +
"Aligned pack(4)\n" +
"Structure Z5p4 {\n" +
" 0 char 1 a \"\"\n" +
" 2 ushort:12(0) 2 b \"\"\n" +
" 4 int:8(0) 1 c \"\"\n" +
" 8 longlong:0(0) 1 \"\"\n" +
" 8 char 1 d \"\"\n" +
"}\n" +
"Size = 12 Actual Alignment = 4", struct);
//@formatter:on
}
@Test
public void testStructureBitFields_x1p4() {
Structure struct = getStructure("x1p4");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/x1p4\n" +
"Aligned pack(4)\n" +
"Structure x1p4 {\n" +
" 0 char 1 a \"\"\n" +
"}\n" +
"Size = 1 Actual Alignment = 1", struct);
//@formatter:on
}
@Test
public void testStructureBitFields_x2p4() {
Structure struct = getStructure("x2p4");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/x2p4\n" +
"Aligned pack(4)\n" +
"Structure x2p4 {\n" +
" 0 char 1 a \"\"\n" +
" 4 int:27(0) 4 b \"\"\n" +
"}\n" +
"Size = 8 Actual Alignment = 4", struct);
//@formatter:on
}
@Test
public void testStructureBitFields_x3p4() {
Structure struct = getStructure("x3p4");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/x3p4\n" +
"Aligned pack(4)\n" +
"Structure x3p4 {\n" +
" 0 char 1 a \"\"\n" +
" 4 short:0(0) 1 \"\"\n" +
" 4 int:27(0) 4 b \"\"\n" +
"}\n" +
"Size = 8 Actual Alignment = 4", struct);
//@formatter:on
}
@Test
public void testStructureBitFields_x4p4() {
Structure struct = getStructure("x4p4");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/x4p4\n" +
"Aligned pack(4)\n" +
"Structure x4p4 {\n" +
" 0 char 1 a \"\"\n" +
" 4 int:27(0) 4 b \"\"\n" +
" 7 longlong:0(0) 1 \"\"\n" +
"}\n" +
"Size = 8 Actual Alignment = 4", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsT1() {
Structure struct = getStructure("T1");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/T1\n" +
"Aligned\n" +
"Structure T1 {\n" +
" 0 charTypedef 1 a \"\"\n" +
" 4 myEnum:3(0) 1 b \"\"\n" +
" 4 enumTypedef:3(3) 1 c \"\"\n" +
" 8 charTypedef:7(0) 1 d \"\"\n" +
"}\n" +
"Size = 12 Actual Alignment = 4", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsT2() {
Structure struct = getStructure("T2");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/T2\n" +
"Aligned\n" +
"Structure T2 {\n" +
" 0 charTypedef 1 a \"\"\n" +
" 4 intTypedef:17(0) 3 b \"\"\n" +
" 6 enumTypedef:3(1) 1 c \"\"\n" +
" 8 charTypedef:3(0) 1 d \"\"\n" +
"}\n" +
"Size = 12 Actual Alignment = 4", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsS1() {
Structure struct = getStructure("S1");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/S1\n" +
"Aligned\n" +
"Structure S1 {\n" +
" 0 B1 12 b1 \"\"\n" +
" 12 B2 8 b2 \"\"\n" +
" 20 Z1 12 z1 \"\"\n" +
" 32 Z2 12 z2 \"\"\n" +
" 48 Z3 8 z3 \"\"\n" +
"}\n" +
"Size = 56 Actual Alignment = 8", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsS1p1() {
Structure struct = getStructure("S1p1");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/S1p1\n" +
"Aligned pack(1)\n" +
"Structure S1p1 {\n" +
" 0 B1 12 b1 \"\"\n" +
" 12 B2 8 b2 \"\"\n" +
" 20 Z1 12 z1 \"\"\n" +
" 32 Z2 12 z2 \"\"\n" +
" 44 Z3 8 z3 \"\"\n" +
"}\n" +
"Size = 52 Actual Alignment = 1", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsS2p1() {
Structure struct = getStructure("S2p1");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/S2p1\n" +
"Aligned pack(1)\n" +
"Structure S2p1 {\n" +
" 0 B1p1 9 b1p1 \"\"\n" +
" 9 B2p1 7 b2p1 \"\"\n" +
" 16 Z1p1 9 z1p1 \"\"\n" +
" 25 Z2p1 9 z2p1 \"\"\n" +
" 34 Z3p1 7 z3p1 \"\"\n" +
"}\n" +
"Size = 41 Actual Alignment = 1", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsS1p2() {
Structure struct = getStructure("S1p2");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/S1p2\n" +
"Aligned pack(2)\n" +
"Structure S1p2 {\n" +
" 0 B1 12 b1 \"\"\n" +
" 12 B2 8 b2 \"\"\n" +
" 20 Z1 12 z1 \"\"\n" +
" 32 Z2 12 z2 \"\"\n" +
" 44 Z3 8 z3 \"\"\n" +
"}\n" +
"Size = 52 Actual Alignment = 2", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsS2p2() {
Structure struct = getStructure("S2p2");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/S2p2\n" +
"Aligned pack(2)\n" +
"Structure S2p2 {\n" +
" 0 B1p2 10 b1p2 \"\"\n" +
" 10 B2p2 8 b2p2 \"\"\n" +
" 18 Z1p2 10 z1p2 \"\"\n" +
" 28 Z2p2 10 z2p2 \"\"\n" +
" 38 Z3p2 8 z3p2 \"\"\n" +
"}\n" +
"Size = 46 Actual Alignment = 2", struct);
//@formatter:on
}
}

View file

@ -0,0 +1,108 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.program.model.data;
import org.junit.Test;
public class MSVCUnionImplBitFieldTest extends AbstractCompositeImplBitFieldTest {
private static DataTypeManager dataMgr;
@Override
protected DataTypeManager getDataTypeManager() {
synchronized (MSVCUnionImplBitFieldTest.class) {
if (dataMgr == null) {
DataOrganizationImpl dataOrg = DataOrganizationImpl.getDefaultOrganization(null);
DataOrganizationTestUtils.initDataOrganizationWindows64BitX86(dataOrg);
dataMgr = new MyDataTypeManager("test", dataOrg);
}
return dataMgr;
}
}
@Test
public void testUnionBitFieldsU1() {
Union struct = getUnion("U1");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/U1\n" +
"Aligned\n" +
"Union U1 {\n" +
" 0 int:4(0) 1 a \"\"\n" +
" 0 int:2(0) 1 b \"\"\n" +
"}\n" +
"Size = 4 Actual Alignment = 4", struct);
//@formatter:on
}
@Test
public void testUnionBitFieldsU1z() {
Union struct = getUnion("U1z");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/U1z\n" +
"Aligned\n" +
"Union U1z {\n" +
" 0 int:4(0) 1 a \"\"\n" +
" 0 longlong:0(0) 1 \"\"\n" +
" 0 int:2(0) 1 b \"\"\n" +
"}\n" +
"Size = 8 Actual Alignment = 8", struct);
//@formatter:on
}
@Test
public void testUnionBitFieldsU1p1() {
Union struct = getUnion("U1p1");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/U1p1\n" +
"Aligned pack(1)\n" +
"Union U1p1 {\n" +
" 0 int:4(0) 1 a \"\"\n" +
" 0 int:2(0) 1 b \"\"\n" +
"}\n" +
"Size = 4 Actual Alignment = 1", struct);
//@formatter:on
}
@Test
public void testUnionBitFieldsU1p1z() {
Union struct = getUnion("U1p1z");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/U1p1z\n" +
"Aligned pack(1)\n" +
"Union U1p1z {\n" +
" 0 int:4(0) 1 a \"\"\n" +
" 0 longlong:0(0) 1 \"\"\n" +
" 0 int:2(0) 1 b \"\"\n" +
"}\n" +
"Size = 8 Actual Alignment = 1", struct);
//@formatter:on
}
@Test
public void testUnionBitFieldsU1p2() {
Union struct = getUnion("U1p2");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/U1p2\n" +
"Aligned pack(2)\n" +
"Union U1p2 {\n" +
" 0 int:4(0) 1 a \"\"\n" +
" 0 int:2(0) 1 b \"\"\n" +
"}\n" +
"Size = 4 Actual Alignment = 2", struct);
//@formatter:on
}
}

View file

@ -0,0 +1,755 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.program.model.data;
import org.junit.Test;
public class StructureImplBigEndianBitFieldTest extends AbstractCompositeImplBitFieldTest {
// NOTE: verified bitfields sample built with mips-elf-gcc (GCC) 4.9.2
private static DataTypeManager dataMgr;
@Override
protected DataTypeManager getDataTypeManager() {
synchronized (StructureImplBigEndianBitFieldTest.class) {
if (dataMgr == null) {
DataOrganizationImpl dataOrg = DataOrganizationImpl.getDefaultOrganization(null);
DataOrganizationTestUtils.initDataOrganization32BitMips(dataOrg);
dataMgr = new MyDataTypeManager("test", dataOrg);
}
return dataMgr;
}
}
@Test
public void testStructureBitFieldsB1() {
Structure struct = getStructure("B1");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/B1\n" +
"Aligned\n" +
"Structure B1 {\n" +
" 0 char 1 a \"\"\n" +
" 1 ushort:6(2) 1 b \"\"\n" +
" 1 int:8(2) 2 c \"\"\n" +
" 2 short:4(6) 2 d \"\"\n" +
"}\n" +
"Size = 4 Actual Alignment = 4", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsB2() {
Structure struct = getStructure("B2");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/B2\n" +
"Aligned\n" +
"Structure B2 {\n" +
" 0 char 1 a \"\"\n" +
" 1 ushort:6(2) 1 b \"\"\n" +
" 1 int:8(2) 2 c \"\"\n" +
" 2 int:4(6) 2 d \"\"\n" +
"}\n" +
"Size = 4 Actual Alignment = 4", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsB3() {
Structure struct = getStructure("B3");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/B3\n" +
"Aligned\n" +
"Structure B3 {\n" +
" 0 char 1 a \"\"\n" +
" 1 ushort:6(2) 1 b \"\"\n" +
" 1 int:8(2) 2 c \"\"\n" +
" 3 char 1 d \"\"\n" +
"}\n" +
"Size = 4 Actual Alignment = 4", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsZ1() {
Structure struct = getStructure("Z1");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/Z1\n" +
"Aligned\n" +
"Structure Z1 {\n" +
" 0 char 1 a \"\"\n" +
" 4 int:0(7) 1 \"\"\n" +
" 4 ushort:6(2) 1 b \"\"\n" +
" 4 int:8(2) 2 c \"\"\n" +
" 6 short:4(4) 1 d \"\"\n" +
"}\n" +
"Size = 8 Actual Alignment = 4", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsZ2() {
Structure struct = getStructure("Z2");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/Z2\n" +
"Aligned\n" +
"Structure Z2 {\n" +
" 0 char 1 a \"\"\n" +
" 1 ushort:6(2) 1 b \"\"\n" +
" 1 int:8(2) 2 c \"\"\n" +
" 4 int:0(7) 1 \"\"\n" +
" 4 short:4(4) 1 d \"\"\n" +
"}\n" +
"Size = 8 Actual Alignment = 4", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsZ3() {
Structure struct = getStructure("Z3");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/Z3\n" +
"Aligned\n" +
"Structure Z3 {\n" +
" 0 char 1 a \"\"\n" +
" 1 ushort:6(2) 1 b \"\"\n" +
" 1 int:8(2) 2 c \"\"\n" +
" 2 int:4(6) 2 d \"\"\n" +
" 3 longlong:0(7) 1 \"\"\n" +
"}\n" +
"Size = 8 Actual Alignment = 8", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsZ4() {
Structure struct = getStructure("Z4");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/Z4\n" +
"Aligned\n" +
"Structure Z4 {\n" +
" 0 char 1 a \"\"\n" +
" 1 ushort:6(2) 1 b \"\"\n" +
" 1 int:8(2) 2 c \"\"\n" +
" 8 longlong:0(7) 1 \"\"\n" +
" 8 char 1 d \"\"\n" +
"}\n" +
"Size = 12 Actual Alignment = 4", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsZ5() {
Structure struct = getStructure("Z5");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/Z5\n" +
"Aligned\n" +
"Structure Z5 {\n" +
" 0 char 1 a \"\"\n" +
" 4 int:0(7) 1 \"\"\n" +
" 4 longlong:6(2) 1 b \"\"\n" +
" 4 int:8(2) 2 c \"\"\n" +
" 6 char 1 d \"\"\n" +
"}\n" +
"Size = 8 Actual Alignment = 8", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsZ6() {
Structure struct = getStructure("Z6");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/Z6\n" +
"Aligned\n" +
"Structure Z6 {\n" +
" 0 char 1 a \"\"\n" +
" 4 int:0(7) 1 \"\"\n" +
" 4 longlong:6(2) 1 b \"\"\n" +
" 4 int:8(2) 2 c \"\"\n" +
" 6 char 1 d \"\"\n" +
" 7 longlong:6(2) 1 e \"\"\n" +
" 8 int:8(0) 1 f \"\"\n" +
" 9 char 1 g \"\"\n" +
"}\n" +
"Size = 16 Actual Alignment = 8", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsB1p1() {
Structure struct = getStructure("B1p1");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/B1p1\n" +
"Aligned pack(1)\n" +
"Structure B1p1 {\n" +
" 0 char 1 a \"\"\n" +
" 1 ushort:6(2) 1 b \"\"\n" +
" 1 int:8(2) 2 c \"\"\n" +
" 2 short:4(6) 2 d \"\"\n" +
"}\n" +
"Size = 4 Actual Alignment = 1", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsB2p1() {
Structure struct = getStructure("B2p1");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/B2p1\n" +
"Aligned pack(1)\n" +
"Structure B2p1 {\n" +
" 0 char 1 a \"\"\n" +
" 1 ushort:6(2) 1 b \"\"\n" +
" 1 int:8(2) 2 c \"\"\n" +
" 2 int:4(6) 2 d \"\"\n" +
"}\n" +
"Size = 4 Actual Alignment = 1", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsB3p1() {
Structure struct = getStructure("B3p1");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/B3p1\n" +
"Aligned pack(1)\n" +
"Structure B3p1 {\n" +
" 0 char 1 a \"\"\n" +
" 1 ushort:6(2) 1 b \"\"\n" +
" 1 int:8(2) 2 c \"\"\n" +
" 3 char 1 d \"\"\n" +
"}\n" +
"Size = 4 Actual Alignment = 1", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsZ1p1() {
Structure struct = getStructure("Z1p1");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/Z1p1\n" +
"Aligned pack(1)\n" +
"Structure Z1p1 {\n" +
" 0 char 1 a \"\"\n" +
" 4 int:0(7) 1 \"\"\n" +
" 4 ushort:6(2) 1 b \"\"\n" +
" 4 int:8(2) 2 c \"\"\n" +
" 5 short:4(6) 2 d \"\"\n" +
"}\n" +
"Size = 7 Actual Alignment = 1", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsZ2p1() {
Structure struct = getStructure("Z2p1");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/Z2p1\n" +
"Aligned pack(1)\n" +
"Structure Z2p1 {\n" +
" 0 char 1 a \"\"\n" +
" 1 ushort:6(2) 1 b \"\"\n" +
" 1 int:8(2) 2 c \"\"\n" +
" 4 int:0(7) 1 \"\"\n" +
" 4 short:4(4) 1 d \"\"\n" +
"}\n" +
"Size = 5 Actual Alignment = 1", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsZ3p1() {
Structure struct = getStructure("Z3p1");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/Z3p1\n" +
"Aligned pack(1)\n" +
"Structure Z3p1 {\n" +
" 0 char 1 a \"\"\n" +
" 1 ushort:6(2) 1 b \"\"\n" +
" 1 int:8(2) 2 c \"\"\n" +
" 2 int:4(6) 2 d \"\"\n" +
" 3 longlong:0(7) 1 \"\"\n" +
"}\n" +
"Size = 8 Actual Alignment = 1", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsZ3p1T() {
Structure struct = getStructure("Z3p1T");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/Z3p1T\n" +
"Aligned\n" +
"Structure Z3p1T {\n" +
" 0 char 1 a \"\"\n" +
" 1 Z3p1 8 z3p1 \"\"\n" +
"}\n" +
"Size = 9 Actual Alignment = 1", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsZ4p1() {
Structure struct = getStructure("Z4p1");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/Z4p1\n" +
"Aligned pack(1)\n" +
"Structure Z4p1 {\n" +
" 0 char 1 a \"\"\n" +
" 1 ushort:6(2) 1 b \"\"\n" +
" 1 int:8(2) 2 c \"\"\n" +
" 8 longlong:0(7) 1 \"\"\n" +
" 8 char 1 d \"\"\n" +
"}\n" +
"Size = 9 Actual Alignment = 1", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsB1p2() {
Structure struct = getStructure("B1p2");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/B1p2\n" +
"Aligned pack(2)\n" +
"Structure B1p2 {\n" +
" 0 char 1 a \"\"\n" +
" 1 ushort:6(2) 1 b \"\"\n" +
" 1 int:8(2) 2 c \"\"\n" +
" 2 short:4(6) 2 d \"\"\n" +
"}\n" +
"Size = 4 Actual Alignment = 2", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsB2p2() {
Structure struct = getStructure("B2p2");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/B2p2\n" +
"Aligned pack(2)\n" +
"Structure B2p2 {\n" +
" 0 char 1 a \"\"\n" +
" 1 ushort:6(2) 1 b \"\"\n" +
" 1 int:8(2) 2 c \"\"\n" +
" 2 int:4(6) 2 d \"\"\n" +
"}\n" +
"Size = 4 Actual Alignment = 2", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsB3p2() {
Structure struct = getStructure("B3p2");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/B3p2\n" +
"Aligned pack(2)\n" +
"Structure B3p2 {\n" +
" 0 char 1 a \"\"\n" +
" 1 ushort:6(2) 1 b \"\"\n" +
" 1 int:8(2) 2 c \"\"\n" +
" 3 char 1 d \"\"\n" +
"}\n" +
"Size = 4 Actual Alignment = 2", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsB4p2() {
Structure struct = getStructure("B4p2");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/B4p2\n" +
"Aligned pack(2)\n" +
"Structure B4p2 {\n" +
" 0 char 1 a \"\"\n" +
" 1 ushort:6(2) 1 b \"\"\n" +
" 1 int:8(2) 2 c \"\"\n" +
" 4 longlong 8 d \"\"\n" +
" 12 int:4(4) 1 e \"\"\n" +
"}\n" +
"Size = 14 Actual Alignment = 2", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsZ1p2() {
Structure struct = getStructure("Z1p2");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/Z1p2\n" +
"Aligned pack(2)\n" +
"Structure Z1p2 {\n" +
" 0 char 1 a \"\"\n" +
" 4 int:0(7) 1 \"\"\n" +
" 4 ushort:6(2) 1 b \"\"\n" +
" 4 int:8(2) 2 c \"\"\n" +
" 5 short:4(6) 2 d \"\"\n" +
"}\n" +
"Size = 8 Actual Alignment = 2", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsZ1p2x() {
Structure struct = getStructure("Z1p2x");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/Z1p2x\n" +
"Aligned pack(2)\n" +
"Structure Z1p2x {\n" +
" 0 char 1 a \"\"\n" +
" 4 int:0(7) 1 \"\"\n" +
" 4 ushort:6(2) 1 b \"\"\n" +
" 4 int:8(2) 2 c \"\"\n" +
" 5 short:4(6) 2 d \"\"\n" +
" 6 short:4(2) 1 d1 \"\"\n" +
" 6 short:4(6) 2 d2 \"\"\n" +
" 7 short:4(2) 1 d3 \"\"\n" +
" 7 short:4(6) 2 d4 \"\"\n" +
" 8 short:4(2) 1 d5 \"\"\n" +
" 8 short:4(6) 2 d6 \"\"\n" +
" 9 short:4(2) 1 d7 \"\"\n" +
" 10 short:0(7) 1 \"\"\n" +
" 10 ushort:6(2) 1 _b \"\"\n" +
" 10 int:8(2) 2 _c \"\"\n" +
" 11 short:4(6) 2 _d \"\"\n" +
" 12 short:4(2) 1 _d1 \"\"\n" +
" 12 short:4(6) 2 _d2 \"\"\n" +
" 13 short:4(2) 1 _d3 \"\"\n" +
" 13 short:4(6) 2 _d4 \"\"\n" +
" 14 short:4(2) 1 _d5 \"\"\n" +
" 14 short:4(6) 2 _d6 \"\"\n" +
" 15 short:4(2) 1 _d7 \"\"\n" +
"}\n" +
"Size = 16 Actual Alignment = 2", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsZ2p2() {
Structure struct = getStructure("Z2p2");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/Z2p2\n" +
"Aligned pack(2)\n" +
"Structure Z2p2 {\n" +
" 0 char 1 a \"\"\n" +
" 1 ushort:6(2) 1 b \"\"\n" +
" 1 int:8(2) 2 c \"\"\n" +
" 4 int:0(7) 1 \"\"\n" +
" 4 short:4(4) 1 d \"\"\n" +
"}\n" +
"Size = 6 Actual Alignment = 2", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsZ3p2() {
Structure struct = getStructure("Z3p2");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/Z3p2\n" +
"Aligned pack(2)\n" +
"Structure Z3p2 {\n" +
" 0 char 1 a \"\"\n" +
" 1 ushort:6(2) 1 b \"\"\n" +
" 1 int:8(2) 2 c \"\"\n" +
" 2 int:4(6) 2 d \"\"\n" +
" 3 longlong:0(7) 1 \"\"\n" +
"}\n" +
"Size = 8 Actual Alignment = 2", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsZ4p2() {
Structure struct = getStructure("Z4p2");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/Z4p2\n" +
"Aligned pack(2)\n" +
"Structure Z4p2 {\n" +
" 0 char 1 a \"\"\n" +
" 1 ushort:6(2) 1 b \"\"\n" +
" 1 int:8(2) 2 c \"\"\n" +
" 8 longlong:0(7) 1 \"\"\n" +
" 8 char 1 d \"\"\n" +
"}\n" +
"Size = 10 Actual Alignment = 2", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsZ5p2() {
Structure struct = getStructure("Z5p2");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/Z5p2\n" +
"Aligned pack(2)\n" +
"Structure Z5p2 {\n" +
" 0 char 1 a \"\"\n" +
" 1 ushort:12(4) 2 b \"\"\n" +
" 2 int:8(4) 2 c \"\"\n" +
" 8 longlong:0(7) 1 \"\"\n" +
" 8 char 1 d \"\"\n" +
"}\n" +
"Size = 10 Actual Alignment = 2", struct);
//@formatter:on
}
@Test
public void testStructureBitFields_x1p2() {
Structure struct = getStructure("x1p2");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/x1p2\n" +
"Aligned pack(2)\n" +
"Structure x1p2 {\n" +
" 0 char 1 a \"\"\n" +
"}\n" +
"Size = 1 Actual Alignment = 1", struct);
//@formatter:on
}
@Test
public void testStructureBitFields_x2p2() {
Structure struct = getStructure("x2p2");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/x2p2\n" +
"Aligned pack(2)\n" +
"Structure x2p2 {\n" +
" 0 char 1 a \"\"\n" +
" 1 int:27(5) 4 b \"\"\n" +
"}\n" +
"Size = 6 Actual Alignment = 2", struct);
//@formatter:on
}
@Test
public void testStructureBitFields_x3p2() {
Structure struct = getStructure("x3p2");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/x3p2\n" +
"Aligned pack(2)\n" +
"Structure x3p2 {\n" +
" 0 char 1 a \"\"\n" +
" 2 short:0(7) 1 \"\"\n" +
" 2 int:27(5) 4 b \"\"\n" +
"}\n" +
"Size = 6 Actual Alignment = 2", struct);
//@formatter:on
}
@Test
public void testStructureBitFields_x4p2() {
Structure struct = getStructure("x4p2");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/x4p2\n" +
"Aligned pack(2)\n" +
"Structure x4p2 {\n" +
" 0 char 1 a \"\"\n" +
" 1 int:27(5) 4 b \"\"\n" +
" 4 longlong:0(7) 1 \"\"\n" +
"}\n" +
"Size = 8 Actual Alignment = 2", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsZ5p4() {
Structure struct = getStructure("Z5p4");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/Z5p4\n" +
"Aligned pack(4)\n" +
"Structure Z5p4 {\n" +
" 0 char 1 a \"\"\n" +
" 1 ushort:12(4) 2 b \"\"\n" +
" 2 int:8(4) 2 c \"\"\n" +
" 8 longlong:0(7) 1 \"\"\n" +
" 8 char 1 d \"\"\n" +
"}\n" +
"Size = 12 Actual Alignment = 4", struct);
//@formatter:on
}
@Test
public void testStructureBitFields_x1p4() {
Structure struct = getStructure("x1p4");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/x1p4\n" +
"Aligned pack(4)\n" +
"Structure x1p4 {\n" +
" 0 char 1 a \"\"\n" +
"}\n" +
"Size = 1 Actual Alignment = 1", struct);
//@formatter:on
}
@Test
public void testStructureBitFields_x2p4() {
Structure struct = getStructure("x2p4");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/x2p4\n" +
"Aligned pack(4)\n" +
"Structure x2p4 {\n" +
" 0 char 1 a \"\"\n" +
" 1 int:27(5) 4 b \"\"\n" +
"}\n" +
"Size = 8 Actual Alignment = 4", struct);
//@formatter:on
}
@Test
public void testStructureBitFields_x3p4() {
Structure struct = getStructure("x3p4");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/x3p4\n" +
"Aligned pack(4)\n" +
"Structure x3p4 {\n" +
" 0 char 1 a \"\"\n" +
" 2 short:0(7) 1 \"\"\n" +
" 2 int:27(5) 4 b \"\"\n" +
"}\n" +
"Size = 8 Actual Alignment = 4", struct);
//@formatter:on
}
@Test
public void testStructureBitFields_x4p4() {
Structure struct = getStructure("x4p4");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/x4p4\n" +
"Aligned pack(4)\n" +
"Structure x4p4 {\n" +
" 0 char 1 a \"\"\n" +
" 1 int:27(5) 4 b \"\"\n" +
" 4 longlong:0(7) 1 \"\"\n" +
"}\n" +
"Size = 8 Actual Alignment = 4", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsT1() {
Structure struct = getStructure("T1");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/T1\n" +
"Aligned\n" +
"Structure T1 {\n" +
" 0 charTypedef 1 a \"\"\n" +
" 1 myEnum:3(5) 1 b \"\"\n" +
" 1 enumTypedef:3(2) 1 c \"\"\n" +
" 2 charTypedef:7(1) 1 d \"\"\n" +
"}\n" +
"Size = 4 Actual Alignment = 4", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsT2() {
Structure struct = getStructure("T2");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/T2\n" +
"Aligned\n" +
"Structure T2 {\n" +
" 0 charTypedef 1 a \"\"\n" +
" 1 intTypedef:17(7) 3 b \"\"\n" +
" 3 enumTypedef:3(4) 1 c \"\"\n" +
" 3 charTypedef:3(1) 1 d \"\"\n" +
"}\n" +
"Size = 4 Actual Alignment = 4", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsS1() {
Structure struct = getStructure("S1");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/S1\n" +
"Aligned\n" +
"Structure S1 {\n" +
" 0 B1 4 b1 \"\"\n" +
" 4 B2 4 b2 \"\"\n" +
" 8 Z1 8 z1 \"\"\n" +
" 16 Z2 8 z2 \"\"\n" +
" 24 Z3 8 z3 \"\"\n" +
"}\n" +
"Size = 32 Actual Alignment = 8", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsS1p1() {
Structure struct = getStructure("S1p1");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/S1p1\n" +
"Aligned pack(1)\n" +
"Structure S1p1 {\n" +
" 0 B1 4 b1 \"\"\n" +
" 4 B2 4 b2 \"\"\n" +
" 8 Z1 8 z1 \"\"\n" +
" 16 Z2 8 z2 \"\"\n" +
" 24 Z3 8 z3 \"\"\n" +
"}\n" +
"Size = 32 Actual Alignment = 1", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsS2p1() {
Structure struct = getStructure("S2p1");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/S2p1\n" +
"Aligned pack(1)\n" +
"Structure S2p1 {\n" +
" 0 B1p1 4 b1p1 \"\"\n" +
" 4 B2p1 4 b2p1 \"\"\n" +
" 8 Z1p1 7 z1p1 \"\"\n" +
" 15 Z2p1 5 z2p1 \"\"\n" +
" 20 Z3p1 8 z3p1 \"\"\n" +
"}\n" +
"Size = 28 Actual Alignment = 1", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsS1p2() {
Structure struct = getStructure("S1p2");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/S1p2\n" +
"Aligned pack(2)\n" +
"Structure S1p2 {\n" +
" 0 B1 4 b1 \"\"\n" +
" 4 B2 4 b2 \"\"\n" +
" 8 Z1 8 z1 \"\"\n" +
" 16 Z2 8 z2 \"\"\n" +
" 24 Z3 8 z3 \"\"\n" +
"}\n" +
"Size = 32 Actual Alignment = 2", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsS2p2() {
Structure struct = getStructure("S2p2");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/S2p2\n" +
"Aligned pack(2)\n" +
"Structure S2p2 {\n" +
" 0 B1p2 4 b1p2 \"\"\n" +
" 4 B2p2 4 b2p2 \"\"\n" +
" 8 Z1p2 8 z1p2 \"\"\n" +
" 16 Z2p2 6 z2p2 \"\"\n" +
" 22 Z3p2 8 z3p2 \"\"\n" +
"}\n" +
"Size = 30 Actual Alignment = 2", struct);
//@formatter:on
}
}

View file

@ -0,0 +1,816 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.program.model.data;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.Iterator;
import org.junit.Test;
import resources.ResourceManager;
public class StructureImplLittleEndianBitFieldTest extends AbstractCompositeImplBitFieldTest {
// NOTE: verified bitfields sample built with Apple LLVM version 9.0.0 (clang-900.0.39.2)
private static DataTypeManager dataMgr;
@Override
public void setUp() throws Exception {
super.setUp();
// uncomment to generate datatype archive
// writeArchive();
}
private void writeArchive() throws IOException {
URL resource = ResourceManager.getResource(C_SOURCE_FILE);
File f = new File(resource.getPath() + ".gdt");
if (f.exists()) {
f.delete();
}
FileDataTypeManager fileDtMgr = FileDataTypeManager.createFileArchive(f);
int txId = fileDtMgr.startTransaction("Save Datatypes");
try {
Iterator<Composite> composites = getDataTypeManager().getAllComposites();
while (composites.hasNext()) {
fileDtMgr.addDataType(composites.next(), null);
}
}
finally {
fileDtMgr.endTransaction(txId, true);
}
fileDtMgr.save();
fileDtMgr.close();
}
@Override
protected DataTypeManager getDataTypeManager() {
synchronized (StructureImplBigEndianBitFieldTest.class) {
if (dataMgr == null) {
DataOrganizationImpl dataOrg = DataOrganizationImpl.getDefaultOrganization(null);
DataOrganizationTestUtils.initDataOrganizationGcc64BitX86(dataOrg);
dataMgr = new MyDataTypeManager("test", dataOrg);
}
return dataMgr;
}
}
@Test
public void testStructureBitFieldsB1() {
Structure struct = getStructure("B1");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/B1\n" +
"Aligned\n" +
"Structure B1 {\n" +
" 0 char 1 a \"\"\n" +
" 1 ushort:6(0) 1 b \"\"\n" +
" 1 int:8(6) 2 c \"\"\n" +
" 2 short:4(6) 2 d \"\"\n" +
"}\n" +
"Size = 4 Actual Alignment = 4", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsB2() {
Structure struct = getStructure("B2");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/B2\n" +
"Aligned\n" +
"Structure B2 {\n" +
" 0 char 1 a \"\"\n" +
" 1 ushort:6(0) 1 b \"\"\n" +
" 1 int:8(6) 2 c \"\"\n" +
" 2 int:4(6) 2 d \"\"\n" +
"}\n" +
"Size = 4 Actual Alignment = 4", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsB3() {
Structure struct = getStructure("B3");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/B3\n" +
"Aligned\n" +
"Structure B3 {\n" +
" 0 char 1 a \"\"\n" +
" 1 ushort:6(0) 1 b \"\"\n" + // gcc groups with previous non-bitfield
" 1 int:8(6) 2 c \"\"\n" +
" 3 char 1 d \"\"\n" +
"}\n" +
"Size = 4 Actual Alignment = 4", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsZ1() {
Structure struct = getStructure("Z1");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/Z1\n" +
"Aligned\n" +
"Structure Z1 {\n" +
" 0 char 1 a \"\"\n" +
" 4 int:0(0) 1 \"\"\n" +
" 4 ushort:6(0) 1 b \"\"\n" +
" 4 int:8(6) 2 c \"\"\n" +
" 6 short:4(0) 1 d \"\"\n" +
"}\n" +
"Size = 8 Actual Alignment = 4", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsZ2() {
Structure struct = getStructure("Z2");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/Z2\n" +
"Aligned\n" +
"Structure Z2 {\n" +
" 0 char 1 a \"\"\n" +
" 1 ushort:6(0) 1 b \"\"\n" +
" 1 int:8(6) 2 c \"\"\n" +
" 4 int:0(0) 1 \"\"\n" +
" 4 short:4(0) 1 d \"\"\n" +
"}\n" +
"Size = 8 Actual Alignment = 4", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsZ3() {
Structure struct = getStructure("Z3");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/Z3\n" +
"Aligned\n" +
"Structure Z3 {\n" +
" 0 char 1 a \"\"\n" +
" 1 ushort:6(0) 1 b \"\"\n" +
" 1 int:8(6) 2 c \"\"\n" +
" 2 int:4(6) 2 d \"\"\n" +
" 3 longlong:0(0) 1 \"\"\n" +
"}\n" +
"Size = 8 Actual Alignment = 8", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsZ4() {
Structure struct = getStructure("Z4");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/Z4\n" +
"Aligned\n" +
"Structure Z4 {\n" +
" 0 char 1 a \"\"\n" +
" 1 ushort:6(0) 1 b \"\"\n" +
" 1 int:8(6) 2 c \"\"\n" +
" 8 longlong:0(0) 1 \"\"\n" +
" 8 char 1 d \"\"\n" +
"}\n" +
"Size = 12 Actual Alignment = 4", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsZ5() {
Structure struct = getStructure("Z5");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/Z5\n" +
"Aligned\n" +
"Structure Z5 {\n" +
" 0 char 1 a \"\"\n" +
" 4 int:0(0) 1 \"\"\n" +
" 4 longlong:6(0) 1 b \"\"\n" +
" 4 int:8(6) 2 c \"\"\n" +
" 6 char 1 d \"\"\n" +
"}\n" +
"Size = 8 Actual Alignment = 8", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsZ6() {
Structure struct = getStructure("Z6");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/Z6\n" +
"Aligned\n" +
"Structure Z6 {\n" +
" 0 char 1 a \"\"\n" +
" 4 int:0(0) 1 \"\"\n" +
" 4 longlong:6(0) 1 b \"\"\n" +
" 4 int:8(6) 2 c \"\"\n" +
" 6 char 1 d \"\"\n" +
" 7 longlong:6(0) 1 e \"\"\n" +
" 8 int:8(0) 1 f \"\"\n" +
" 9 char 1 g \"\"\n" +
"}\n" +
"Size = 16 Actual Alignment = 8", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsB1p1() {
Structure struct = getStructure("B1p1");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/B1p1\n" +
"Aligned pack(1)\n" +
"Structure B1p1 {\n" +
" 0 char 1 a \"\"\n" +
" 1 ushort:6(0) 1 b \"\"\n" +
" 1 int:8(6) 2 c \"\"\n" +
" 2 short:4(6) 2 d \"\"\n" +
"}\n" +
"Size = 4 Actual Alignment = 1", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsB2p1() {
Structure struct = getStructure("B2p1");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/B2p1\n" +
"Aligned pack(1)\n" +
"Structure B2p1 {\n" +
" 0 char 1 a \"\"\n" +
" 1 ushort:6(0) 1 b \"\"\n" +
" 1 int:8(6) 2 c \"\"\n" +
" 2 int:4(6) 2 d \"\"\n" +
"}\n" +
"Size = 4 Actual Alignment = 1", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsB3p1() {
Structure struct = getStructure("B3p1");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/B3p1\n" +
"Aligned pack(1)\n" +
"Structure B3p1 {\n" +
" 0 char 1 a \"\"\n" +
" 1 ushort:6(0) 1 b \"\"\n" +
" 1 int:8(6) 2 c \"\"\n" +
" 3 char 1 d \"\"\n" +
"}\n" +
"Size = 4 Actual Alignment = 1", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsZ1p1() {
Structure struct = getStructure("Z1p1");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/Z1p1\n" +
"Aligned pack(1)\n" +
"Structure Z1p1 {\n" +
" 0 char 1 a \"\"\n" +
" 4 int:0(0) 1 \"\"\n" +
" 4 ushort:6(0) 1 b \"\"\n" +
" 4 int:8(6) 2 c \"\"\n" +
" 5 short:4(6) 2 d \"\"\n" +
"}\n" +
"Size = 7 Actual Alignment = 1", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsZ2p1() {
Structure struct = getStructure("Z2p1");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/Z2p1\n" +
"Aligned pack(1)\n" +
"Structure Z2p1 {\n" +
" 0 char 1 a \"\"\n" +
" 1 ushort:6(0) 1 b \"\"\n" +
" 1 int:8(6) 2 c \"\"\n" +
" 4 int:0(0) 1 \"\"\n" +
" 4 short:4(0) 1 d \"\"\n" +
"}\n" +
"Size = 5 Actual Alignment = 1", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsZ3p1() {
Structure struct = getStructure("Z3p1");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/Z3p1\n" +
"Aligned pack(1)\n" +
"Structure Z3p1 {\n" +
" 0 char 1 a \"\"\n" +
" 1 ushort:6(0) 1 b \"\"\n" +
" 1 int:8(6) 2 c \"\"\n" +
" 2 int:4(6) 2 d \"\"\n" +
" 3 longlong:0(0) 1 \"\"\n" +
"}\n" +
"Size = 8 Actual Alignment = 1", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsZ3p1T() {
Structure struct = getStructure("Z3p1T");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/Z3p1T\n" +
"Aligned\n" +
"Structure Z3p1T {\n" +
" 0 char 1 a \"\"\n" +
" 1 Z3p1 8 z3p1 \"\"\n" +
"}\n" +
"Size = 9 Actual Alignment = 1", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsZ4p1() {
Structure struct = getStructure("Z4p1");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/Z4p1\n" +
"Aligned pack(1)\n" +
"Structure Z4p1 {\n" +
" 0 char 1 a \"\"\n" +
" 1 ushort:6(0) 1 b \"\"\n" +
" 1 int:8(6) 2 c \"\"\n" +
" 8 longlong:0(0) 1 \"\"\n" +
" 8 char 1 d \"\"\n" +
"}\n" +
"Size = 9 Actual Alignment = 1", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsB1p2() {
Structure struct = getStructure("B1p2");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/B1p2\n" +
"Aligned pack(2)\n" +
"Structure B1p2 {\n" +
" 0 char 1 a \"\"\n" +
" 1 ushort:6(0) 1 b \"\"\n" +
" 1 int:8(6) 2 c \"\"\n" +
" 2 short:4(6) 2 d \"\"\n" +
"}\n" +
"Size = 4 Actual Alignment = 2", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsB2p2() {
Structure struct = getStructure("B2p2");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/B2p2\n" +
"Aligned pack(2)\n" +
"Structure B2p2 {\n" +
" 0 char 1 a \"\"\n" +
" 1 ushort:6(0) 1 b \"\"\n" +
" 1 int:8(6) 2 c \"\"\n" +
" 2 int:4(6) 2 d \"\"\n" +
"}\n" +
"Size = 4 Actual Alignment = 2", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsB3p2() {
Structure struct = getStructure("B3p2");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/B3p2\n" +
"Aligned pack(2)\n" +
"Structure B3p2 {\n" +
" 0 char 1 a \"\"\n" +
" 1 ushort:6(0) 1 b \"\"\n" +
" 1 int:8(6) 2 c \"\"\n" +
" 3 char 1 d \"\"\n" +
"}\n" +
"Size = 4 Actual Alignment = 2", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsB4p2() {
Structure struct = getStructure("B4p2");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/B4p2\n" +
"Aligned pack(2)\n" +
"Structure B4p2 {\n" +
" 0 char 1 a \"\"\n" +
" 1 ushort:6(0) 1 b \"\"\n" +
" 1 int:8(6) 2 c \"\"\n" +
" 4 longlong 8 d \"\"\n" +
" 12 int:4(0) 1 e \"\"\n" +
"}\n" +
"Size = 14 Actual Alignment = 2", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsZ1p2() {
Structure struct = getStructure("Z1p2");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/Z1p2\n" +
"Aligned pack(2)\n" +
"Structure Z1p2 {\n" +
" 0 char 1 a \"\"\n" +
" 4 int:0(0) 1 \"\"\n" +
" 4 ushort:6(0) 1 b \"\"\n" +
" 4 int:8(6) 2 c \"\"\n" +
" 5 short:4(6) 2 d \"\"\n" +
"}\n" +
"Size = 8 Actual Alignment = 2", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsZ1p2x() {
Structure struct = getStructure("Z1p2x");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/Z1p2x\n" +
"Aligned pack(2)\n" +
"Structure Z1p2x {\n" +
" 0 char 1 a \"\"\n" +
" 4 int:0(0) 1 \"\"\n" +
" 4 ushort:6(0) 1 b \"\"\n" +
" 4 int:8(6) 2 c \"\"\n" +
" 5 short:4(6) 2 d \"\"\n" +
" 6 short:4(2) 1 d1 \"\"\n" +
" 6 short:4(6) 2 d2 \"\"\n" +
" 7 short:4(2) 1 d3 \"\"\n" +
" 7 short:4(6) 2 d4 \"\"\n" +
" 8 short:4(2) 1 d5 \"\"\n" +
" 8 short:4(6) 2 d6 \"\"\n" +
" 9 short:4(2) 1 d7 \"\"\n" +
" 10 short:0(0) 1 \"\"\n" +
" 10 ushort:6(0) 1 _b \"\"\n" +
" 10 int:8(6) 2 _c \"\"\n" +
" 11 short:4(6) 2 _d \"\"\n" +
" 12 short:4(2) 1 _d1 \"\"\n" +
" 12 short:4(6) 2 _d2 \"\"\n" +
" 13 short:4(2) 1 _d3 \"\"\n" +
" 13 short:4(6) 2 _d4 \"\"\n" +
" 14 short:4(2) 1 _d5 \"\"\n" +
" 14 short:4(6) 2 _d6 \"\"\n" +
" 15 short:4(2) 1 _d7 \"\"\n" +
"}\n" +
"Size = 16 Actual Alignment = 2", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsZ2p2() {
Structure struct = getStructure("Z2p2");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/Z2p2\n" +
"Aligned pack(2)\n" +
"Structure Z2p2 {\n" +
" 0 char 1 a \"\"\n" +
" 1 ushort:6(0) 1 b \"\"\n" +
" 1 int:8(6) 2 c \"\"\n" +
" 4 int:0(0) 1 \"\"\n" +
" 4 short:4(0) 1 d \"\"\n" +
"}\n" +
"Size = 6 Actual Alignment = 2", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsZ3p2() {
Structure struct = getStructure("Z3p2");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/Z3p2\n" +
"Aligned pack(2)\n" +
"Structure Z3p2 {\n" +
" 0 char 1 a \"\"\n" +
" 1 ushort:6(0) 1 b \"\"\n" +
" 1 int:8(6) 2 c \"\"\n" +
" 2 int:4(6) 2 d \"\"\n" +
" 3 longlong:0(0) 1 \"\"\n" +
"}\n" +
"Size = 8 Actual Alignment = 2", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsZ4p2() {
Structure struct = getStructure("Z4p2");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/Z4p2\n" +
"Aligned pack(2)\n" +
"Structure Z4p2 {\n" +
" 0 char 1 a \"\"\n" +
" 1 ushort:6(0) 1 b \"\"\n" +
" 1 int:8(6) 2 c \"\"\n" +
" 8 longlong:0(0) 1 \"\"\n" +
" 8 char 1 d \"\"\n" +
"}\n" +
"Size = 10 Actual Alignment = 2", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsZ5p2() {
Structure struct = getStructure("Z5p2");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/Z5p2\n" +
"Aligned pack(2)\n" +
"Structure Z5p2 {\n" +
" 0 char 1 a \"\"\n" +
" 1 ushort:12(0) 2 b \"\"\n" +
" 2 int:8(4) 2 c \"\"\n" +
" 8 longlong:0(0) 1 \"\"\n" +
" 8 char 1 d \"\"\n" +
"}\n" +
"Size = 10 Actual Alignment = 2", struct);
//@formatter:on
}
@Test
public void testStructureBitFields_x1p2() {
Structure struct = getStructure("x1p2");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/x1p2\n" +
"Aligned pack(2)\n" +
"Structure x1p2 {\n" +
" 0 char 1 a \"\"\n" +
"}\n" +
"Size = 1 Actual Alignment = 1", struct);
//@formatter:on
}
@Test
public void testStructureBitFields_x2p2() {
Structure struct = getStructure("x2p2");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/x2p2\n" +
"Aligned pack(2)\n" +
"Structure x2p2 {\n" +
" 0 char 1 a \"\"\n" +
" 1 int:27(0) 4 b \"\"\n" +
"}\n" +
"Size = 6 Actual Alignment = 2", struct);
//@formatter:on
}
@Test
public void testStructureBitFields_x3p2() {
Structure struct = getStructure("x3p2");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/x3p2\n" +
"Aligned pack(2)\n" +
"Structure x3p2 {\n" +
" 0 char 1 a \"\"\n" +
" 2 short:0(0) 1 \"\"\n" +
" 2 int:27(0) 4 b \"\"\n" +
"}\n" +
"Size = 6 Actual Alignment = 2", struct);
//@formatter:on
}
@Test
public void testStructureBitFields_x4p2() {
Structure struct = getStructure("x4p2");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/x4p2\n" +
"Aligned pack(2)\n" +
"Structure x4p2 {\n" +
" 0 char 1 a \"\"\n" +
" 1 int:27(0) 4 b \"\"\n" +
" 4 longlong:0(0) 1 \"\"\n" +
"}\n" +
"Size = 8 Actual Alignment = 2", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsZ5p4() {
Structure struct = getStructure("Z5p4");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/Z5p4\n" +
"Aligned pack(4)\n" +
"Structure Z5p4 {\n" +
" 0 char 1 a \"\"\n" +
" 1 ushort:12(0) 2 b \"\"\n" +
" 2 int:8(4) 2 c \"\"\n" +
" 8 longlong:0(0) 1 \"\"\n" +
" 8 char 1 d \"\"\n" +
"}\n" +
"Size = 12 Actual Alignment = 4", struct);
//@formatter:on
}
@Test
public void testStructureBitFields_x1p4() {
Structure struct = getStructure("x1p4");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/x1p4\n" +
"Aligned pack(4)\n" +
"Structure x1p4 {\n" +
" 0 char 1 a \"\"\n" +
"}\n" +
"Size = 1 Actual Alignment = 1", struct);
//@formatter:on
}
@Test
public void testStructureBitFields_x2p4() {
Structure struct = getStructure("x2p4");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/x2p4\n" +
"Aligned pack(4)\n" +
"Structure x2p4 {\n" +
" 0 char 1 a \"\"\n" +
" 1 int:27(0) 4 b \"\"\n" +
"}\n" +
"Size = 8 Actual Alignment = 4", struct);
//@formatter:on
}
@Test
public void testStructureBitFields_x3p4() {
Structure struct = getStructure("x3p4");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/x3p4\n" +
"Aligned pack(4)\n" +
"Structure x3p4 {\n" +
" 0 char 1 a \"\"\n" +
" 2 short:0(0) 1 \"\"\n" +
" 2 int:27(0) 4 b \"\"\n" +
"}\n" +
"Size = 8 Actual Alignment = 4", struct);
//@formatter:on
}
@Test
public void testStructureBitFields_x4p4() {
Structure struct = getStructure("x4p4");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/x4p4\n" +
"Aligned pack(4)\n" +
"Structure x4p4 {\n" +
" 0 char 1 a \"\"\n" +
" 1 int:27(0) 4 b \"\"\n" +
" 4 longlong:0(0) 1 \"\"\n" +
"}\n" +
"Size = 8 Actual Alignment = 4", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsT1() {
Structure struct = getStructure("T1");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/T1\n" +
"Aligned\n" +
"Structure T1 {\n" +
" 0 charTypedef 1 a \"\"\n" +
" 1 myEnum:3(0) 1 b \"\"\n" +
" 1 enumTypedef:3(3) 1 c \"\"\n" +
" 2 charTypedef:7(0) 1 d \"\"\n" +
"}\n" +
"Size = 4 Actual Alignment = 4", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsT2() {
Structure struct = getStructure("T2");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/T2\n" +
"Aligned\n" +
"Structure T2 {\n" +
" 0 charTypedef 1 a \"\"\n" +
" 1 intTypedef:17(0) 3 b \"\"\n" +
" 3 enumTypedef:3(1) 1 c \"\"\n" +
" 3 charTypedef:3(4) 1 d \"\"\n" +
"}\n" +
"Size = 4 Actual Alignment = 4", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsS1() {
Structure struct = getStructure("S1");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/S1\n" +
"Aligned\n" +
"Structure S1 {\n" +
" 0 B1 4 b1 \"\"\n" +
" 4 B2 4 b2 \"\"\n" +
" 8 Z1 8 z1 \"\"\n" +
" 16 Z2 8 z2 \"\"\n" +
" 24 Z3 8 z3 \"\"\n" +
"}\n" +
"Size = 32 Actual Alignment = 8", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsS1p1() {
Structure struct = getStructure("S1p1");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/S1p1\n" +
"Aligned pack(1)\n" +
"Structure S1p1 {\n" +
" 0 B1 4 b1 \"\"\n" +
" 4 B2 4 b2 \"\"\n" +
" 8 Z1 8 z1 \"\"\n" +
" 16 Z2 8 z2 \"\"\n" +
" 24 Z3 8 z3 \"\"\n" +
"}\n" +
"Size = 32 Actual Alignment = 1", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsS2p1() {
Structure struct = getStructure("S2p1");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/S2p1\n" +
"Aligned pack(1)\n" +
"Structure S2p1 {\n" +
" 0 B1p1 4 b1p1 \"\"\n" +
" 4 B2p1 4 b2p1 \"\"\n" +
" 8 Z1p1 7 z1p1 \"\"\n" +
" 15 Z2p1 5 z2p1 \"\"\n" +
" 20 Z3p1 8 z3p1 \"\"\n" +
"}\n" +
"Size = 28 Actual Alignment = 1", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsS1p2() {
Structure struct = getStructure("S1p2");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/S1p2\n" +
"Aligned pack(2)\n" +
"Structure S1p2 {\n" +
" 0 B1 4 b1 \"\"\n" +
" 4 B2 4 b2 \"\"\n" +
" 8 Z1 8 z1 \"\"\n" +
" 16 Z2 8 z2 \"\"\n" +
" 24 Z3 8 z3 \"\"\n" +
"}\n" +
"Size = 32 Actual Alignment = 2", struct);
//@formatter:on
}
@Test
public void testStructureBitFieldsS2p2() {
Structure struct = getStructure("S2p2");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/S2p2\n" +
"Aligned pack(2)\n" +
"Structure S2p2 {\n" +
" 0 B1p2 4 b1p2 \"\"\n" +
" 4 B2p2 4 b2p2 \"\"\n" +
" 8 Z1p2 8 z1p2 \"\"\n" +
" 16 Z2p2 6 z2p2 \"\"\n" +
" 22 Z3p2 8 z3p2 \"\"\n" +
"}\n" +
"Size = 30 Actual Alignment = 2", struct);
//@formatter:on
}
// @Test
// public void testStructureBitFieldsFOO() {
// Structure struct = getStructure("Z3p1T");
//
// System.out.println(struct.toString());
//
// DataTypeManager dtm = struct.getDataTypeManager();
// if (dtm instanceof StandAloneDataTypeManager) {
// ((StandAloneDataTypeManager) dtm).startTransaction("TEST");
// }
// else if (dtm instanceof ProgramDataTypeManager) {
// ((ProgramDataTypeManager) dtm).getProgram().startTransaction("TEST");
// }
//
// ArrayList<InternalDataTypeComponent> components =
// (ArrayList<InternalDataTypeComponent>) getInstanceField("components", struct);
//
// AlignedStructurePacker.packComponents(struct, components);
//
// //@formatter:off
// CompositeTestUtils.assertExpectedComposite(this, "", struct);
// //@formatter:on
// }
}

View file

@ -0,0 +1,109 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.program.model.data;
import org.junit.Test;
public class UnionImplBigEndianBitFieldTest extends AbstractCompositeImplBitFieldTest {
// NOTE: verified bitfields sample built with mips-elf-gcc (GCC) 4.9.2
private static DataTypeManager dataMgr;
@Override
protected DataTypeManager getDataTypeManager() {
synchronized (StructureImplBigEndianBitFieldTest.class) {
if (dataMgr == null) {
DataOrganizationImpl dataOrg = DataOrganizationImpl.getDefaultOrganization(null);
DataOrganizationTestUtils.initDataOrganization32BitMips(dataOrg);
dataMgr = new MyDataTypeManager("test", dataOrg);
}
return dataMgr;
}
}
@Test
public void testUnionBitFieldsU1() {
Union struct = getUnion("U1");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/U1\n" +
"Aligned\n" +
"Union U1 {\n" +
" 0 int:4(0) 1 a \"\"\n" +
" 0 int:2(0) 1 b \"\"\n" +
"}\n" +
"Size = 4 Actual Alignment = 4", struct);
//@formatter:on
}
@Test
public void testUnionBitFieldsU1z() {
Union struct = getUnion("U1z");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/U1z\n" +
"Aligned\n" +
"Union U1z {\n" +
" 0 int:4(0) 1 a \"\"\n" +
" 0 longlong:0(0) 1 \"\"\n" + // has no impact
" 0 int:2(0) 1 b \"\"\n" +
"}\n" +
"Size = 4 Actual Alignment = 4", struct);
//@formatter:on
}
@Test
public void testUnionBitFieldsU1p1() {
Union struct = getUnion("U1p1");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/U1p1\n" +
"Aligned pack(1)\n" +
"Union U1p1 {\n" +
" 0 int:4(0) 1 a \"\"\n" +
" 0 int:2(0) 1 b \"\"\n" +
"}\n" +
"Size = 1 Actual Alignment = 1", struct);
//@formatter:on
}
@Test
public void testUnionBitFieldsU1p1z() {
Union struct = getUnion("U1p1z");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/U1p1z\n" +
"Aligned pack(1)\n" +
"Union U1p1z {\n" +
" 0 int:4(0) 1 a \"\"\n" +
" 0 longlong:0(0) 1 \"\"\n" + // has no impact
" 0 int:2(0) 1 b \"\"\n" +
"}\n" +
"Size = 1 Actual Alignment = 1", struct);
//@formatter:on
}
@Test
public void testUnionBitFieldsU1p2() {
Union struct = getUnion("U1p2");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/U1p2\n" +
"Aligned pack(2)\n" +
"Union U1p2 {\n" +
" 0 int:4(0) 1 a \"\"\n" +
" 0 int:2(0) 1 b \"\"\n" +
"}\n" +
"Size = 2 Actual Alignment = 2", struct);
//@formatter:on
}
}

View file

@ -0,0 +1,109 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.program.model.data;
import org.junit.Test;
public class UnionImplLittleEndianBitFieldTest extends AbstractCompositeImplBitFieldTest {
// NOTE: verified bitfields sample built with Apple LLVM version 9.0.0 (clang-900.0.39.2)
private static DataTypeManager dataMgr;
@Override
protected DataTypeManager getDataTypeManager() {
synchronized (StructureImplBigEndianBitFieldTest.class) {
if (dataMgr == null) {
DataOrganizationImpl dataOrg = DataOrganizationImpl.getDefaultOrganization(null);
DataOrganizationTestUtils.initDataOrganizationGcc64BitX86(dataOrg);
dataMgr = new MyDataTypeManager("test", dataOrg);
}
return dataMgr;
}
}
@Test
public void testUnionBitFieldsU1() {
Union struct = getUnion("U1");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/U1\n" +
"Aligned\n" +
"Union U1 {\n" +
" 0 int:4(0) 1 a \"\"\n" +
" 0 int:2(0) 1 b \"\"\n" +
"}\n" +
"Size = 4 Actual Alignment = 4", struct);
//@formatter:on
}
@Test
public void testUnionBitFieldsU1z() {
Union struct = getUnion("U1z");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/U1z\n" +
"Aligned\n" +
"Union U1z {\n" +
" 0 int:4(0) 1 a \"\"\n" +
" 0 longlong:0(0) 1 \"\"\n" + // has no impact
" 0 int:2(0) 1 b \"\"\n" +
"}\n" +
"Size = 4 Actual Alignment = 4", struct);
//@formatter:on
}
@Test
public void testUnionBitFieldsU1p1() {
Union struct = getUnion("U1p1");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/U1p1\n" +
"Aligned pack(1)\n" +
"Union U1p1 {\n" +
" 0 int:4(0) 1 a \"\"\n" +
" 0 int:2(0) 1 b \"\"\n" +
"}\n" +
"Size = 1 Actual Alignment = 1", struct);
//@formatter:on
}
@Test
public void testUnionBitFieldsU1p1z() {
Union struct = getUnion("U1p1z");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/U1p1z\n" +
"Aligned pack(1)\n" +
"Union U1p1z {\n" +
" 0 int:4(0) 1 a \"\"\n" +
" 0 longlong:0(0) 1 \"\"\n" + // has no impact
" 0 int:2(0) 1 b \"\"\n" +
"}\n" +
"Size = 1 Actual Alignment = 1", struct);
//@formatter:on
}
@Test
public void testUnionBitFieldsU1p2() {
Union struct = getUnion("U1p2");
//@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/U1p2\n" +
"Aligned pack(2)\n" +
"Union U1p2 {\n" +
" 0 int:4(0) 1 a \"\"\n" +
" 0 int:2(0) 1 b \"\"\n" +
"}\n" +
"Size = 2 Actual Alignment = 2", struct);
//@formatter:on
}
}

View file

@ -0,0 +1,184 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include "bitfields.h"
struct B1 B1 = { 5, 0x2A, -1, 0xA };
struct B2 B2 = { 5, 0x2A, -1, 0xA };
struct B3 B3 = { 5, 0x2A, -1, 0xA };
struct Z1 Z1 = { 5, 0x2A, -1, 0xA };
struct Z2 Z2 = { 5, 0x2A, -1, 0xA };
struct Z3 Z3 = { 5, 0x2A, -1, 0xA };
struct Z4 Z4 = { 5, 0x2A, -1, 0xA };
struct Z5 Z5 = { 5, 0x2A, -1, 0xA };
struct Z6 Z6 = { 5, 0x2A, -1, 0xA, 0x2A, -1, 0xA };
struct B1p1 B1p1 = { 5, 0x2A, -1, 0xA };
struct B2p1 B2p1 = { 5, 0x2A, -1, 0xA };
struct B3p1 B3p1 = { 5, 0x2A, -1, 0xA };
struct Z1p1 Z1p1 = { 5, 0x2A, -1, 0xA };
struct Z2p1 Z2p1 = { 5, 0x2A, -1, 0xA };
struct Z3p1 Z3p1 = { 5, 0x2A, -1, 0xA };
struct Z3p1T Z3p1T = { 7, { 5, 0x2A, -1, 0xA }};
struct Z4p1 Z4p1 = { 5, 0x2A, -1, 0xA };
struct B1p2 B1p2 = { 5, 0x2A, -1, 0xA };
struct B2p2 B2p2 = { 5, 0x2A, -1, 0xA };
struct B3p2 B3p2 = { 5, 0x2A, -1, 0xA };
struct B4p2 B4p2 = { 5, 0x2A, -1, 0x5555555555555555, 0xA };
struct Z1p2 Z1p2 = { 5, 0x2A, -1, 0xA };
struct Z1p2x Z1p2x = { 5, 0x2A, -1, 0xA, -1, 0, -1, 0, -1, 0, -1, 0x2A, -1, 0xA, -1, 0, -1, 0, -1, 0, -1 };
struct Z2p2 Z2p2 = { 5, 0x2A, -1, 0xA };
struct Z3p2 Z3p2 = { 5, 0x2A, -1, 0xA };
struct Z4p2 Z4p2 = { 5, 0x2A, -1, 0xA };
struct Z5p2 Z5p2 = { 5, 0x2A, -1, 0xA };
struct x1p2 x1p2 = { 5 };
struct x2p2 x2p2 = { 5, 0x2A };
struct x3p2 x3p2 = { 5, 0x2A };
struct x4p2 x4p2 = { 5, 0x2A };
struct Z5p4 Z5p4 = { 5, 0x2A, -1, 0xA };
struct x1p4 x1p4 = { 5 };
struct x2p4 x2p4 = { 5, 0x2A };
struct x3p4 x3p4 = { 5, 0x2A };
struct x4p4 x4p4 = { 5, 0x2A };
struct S1 S1 = { { 5, 0x2A, -1, 0xA }, { 5, 0x2A, -1, 0xA }, { 5, 0x2A, -1, 0xA }, { 5, 0x2A, -1, 0xA }, { 5, 0x2A, -1, 0xA } };
struct S1p1 S1p1 = { { 5, 0x2A, -1, 0xA }, { 5, 0x2A, -1, 0xA }, { 5, 0x2A, -1, 0xA }, { 5, 0x2A, -1, 0xA }, { 5, 0x2A, -1, 0xA } };
struct S2p1 S2p1 = { { 5, 0x2A, -1, 0xA }, { 5, 0x2A, -1, 0xA }, { 5, 0x2A, -1, 0xA }, { 5, 0x2A, -1, 0xA }, { 5, 0x2A, -1, 0xA } };
struct S1p2 S1p2 = { { 5, 0x2A, -1, 0xA }, { 5, 0x2A, -1, 0xA }, { 5, 0x2A, -1, 0xA }, { 5, 0x2A, -1, 0xA }, { 5, 0x2A, -1, 0xA } };
struct S2p2 S2p2 = { { 5, 0x2A, -1, 0xA }, { 5, 0x2A, -1, 0xA }, { 5, 0x2A, -1, 0xA }, { 5, 0x2A, -1, 0xA }, { 5, 0x2A, -1, 0xA } };
struct T1 T1 = { 5, TWO, THREE, 1 };
struct T2 T2 = { 5, 0x2A, THREE, 1 };
union U1 U1;
union U1z U1z;
union U1p1 U1p1;
union U1p1z U1p1z;
union U1p2 U1p2;
struct SUp1 SUp1;
int main(int argc, char *argv[]) {
printf("len B1: %d\n", sizeof(struct B1));
printf("len B2: %d\n", sizeof(struct B2));
printf("len B3: %d\n", sizeof(struct B3));
printf("len Z1: %d\n", sizeof(struct Z1));
printf("len Z2: %d\n", sizeof(struct Z2));
printf("len Z3: %d\n", sizeof(struct Z3));
printf("len Z4: %d\n", sizeof(struct Z4));
printf("len Z5: %d\n", sizeof(struct Z5));
printf("len Z6: %d\n", sizeof(struct Z6));
printf("len B1p1: %d\n", sizeof(struct B1p1));
printf("len B2p1: %d\n", sizeof(struct B2p1));
printf("len B3p1: %d\n", sizeof(struct B3p1));
printf("len Z1p1: %d\n", sizeof(struct Z1p1));
printf("len Z2p1: %d\n", sizeof(struct Z2p1));
printf("len Z3p1: %d\n", sizeof(struct Z3p1));
printf("len Z3p1T: %d\n", sizeof(struct Z3p1T));
printf("len Z4p1: %d\n", sizeof(struct Z4p1));
printf("len B1p2: %d\n", sizeof(struct B1p2));
printf("len B2p2: %d\n", sizeof(struct B2p2));
printf("len B3p2: %d\n", sizeof(struct B3p2));
printf("len B4p2: %d\n", sizeof(struct B4p2));
printf("len Z1p2: %d\n", sizeof(struct Z1p2));
printf("len Z1p2x: %d\n", sizeof(struct Z1p2x));
printf("len Z2p2: %d\n", sizeof(struct Z2p2));
printf("len Z3p2: %d\n", sizeof(struct Z3p2));
printf("len Z4p2: %d\n", sizeof(struct Z4p2));
printf("len Z5p2: %d\n", sizeof(struct Z5p2));
printf("len x1p2: %d\n", sizeof(struct x1p2));
printf("len x2p2: %d\n", sizeof(struct x2p2));
printf("len x3p2: %d\n", sizeof(struct x3p2));
printf("len x4p2: %d\n", sizeof(struct x4p2));
printf("len Z5p4: %d\n", sizeof(struct Z5p4));
printf("len x1p4: %d\n", sizeof(struct x1p4));
printf("len x2p4: %d\n", sizeof(struct x2p4));
printf("len x3p4: %d\n", sizeof(struct x3p4));
printf("len x4p4: %d\n", sizeof(struct x4p4));
printf("len S1: %d\n", sizeof(struct S1));
printf("len S1p1: %d\n", sizeof(struct S1p1));
printf("len S2p1: %d\n", sizeof(struct S2p1));
printf("len S1p2: %d\n", sizeof(struct S1p2));
printf("len S2p2: %d\n", sizeof(struct S2p2));
printf("len T1: %d\n", sizeof(struct T1));
printf("len T2: %d\n", sizeof(struct T2));
printf("len U1: %d\n", sizeof(union U1));
printf("len U1z: %d\n", sizeof(union U1z));
printf("len U1p1: %d\n", sizeof(union U1p1));
printf("len U1p1z: %d\n", sizeof(union U1p1z));
printf("len U1p2: %d\n", sizeof(union U1p2));
printf("len SUp1: %d\n", sizeof(struct SUp1));
}

View file

@ -0,0 +1,445 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Verify bitfield grouping and alignment without zero-length bitfields
struct B1 {
char a;
unsigned short b:6; // gcc groups with previous non-bitfield
int c:8; // gcc groups with previous two fields (including non-bitfield)
short d:4;
};
struct B2 {
char a;
unsigned short b:6; // gcc groups with previous non-bitfield
int c:8;
int d:4;
};
struct B3 {
char a;
unsigned short b:6; // gcc groups with previous non-bitfield
int c:8;
char d; // gcc groups with int bit-field
};
// Verify bitfield grouping and alignment with zero-length bitfields
struct Z1 {
char a;
int :0; // MSVC ignores field, gcc forces break and does not combine with previous field
unsigned short b:6;
int c:8;
short d:4;
};
struct Z2 {
char a;
unsigned short b:6; // gcc groups with previous non-bitfield
int c:8;
int :0;
short d:4;
};
struct Z3 {
char a;
unsigned short b:6; // gcc groups with previous non-bitfield
int c:8; // gcc groups with previous two fields (including non-bitfield)
int d:4;
long long :0; // trailing :0 imposes alignment onto structure
};
struct Z4 {
char a;
unsigned short b:6; // gcc groups with previous non-bitfield
int c:8; // gcc groups with previous two fields (including non-bitfield)
long long :0; // forced alignment of non-bitfield
char d;
};
struct Z5 {
char a;
int :0;
long long b:6;
int c:8;
char d;
};
struct Z6 {
char a;
int :0;
long long b:6;
int c:8;
char d;
long long e:6;
int f:8;
char g;
};
#pragma pack(1)
// Verify bitfield grouping and alignment without zero-length bitfields
struct B1p1 {
char a;
unsigned short b:6;
int c:8;
short d:4;
};
struct B2p1 {
char a;
unsigned short b:6;
int c:8;
int d:4;
};
struct B3p1 {
char a;
unsigned short b:6;
int c:8;
char d; // gcc groups with int bit-field
};
// Verify bitfield grouping and alignment with zero-length bitfields
struct Z1p1 {
char a;
int :0; // MSVC ignores field
unsigned short b:6;
int c:8;
short d:4;
};
struct Z2p1 {
char a;
unsigned short b:6;
int c:8;
int :0;
short d:4;
};
struct Z3p1 {
char a;
unsigned short b:6;
int c:8;
int d:4;
long long :0; // trailing :0 (ignore when packing ?) - case needs more testing
};
struct Z4p1 {
char a;
unsigned short b:6;
int c:8;
long long :0; // forced alignment of non-bitfield
char d;
};
#pragma pack()
// packed structure contained within default aligned structure
struct Z3p1T {
char a;
struct Z3p1 z3p1;
};
#pragma pack(2)
// Verify bitfield grouping and alignment without zero-length bitfields
struct B1p2 {
char a;
unsigned short b:6;
int c:8;
short d:4;
};
struct B2p2 {
char a;
unsigned short b:6;
int c:8;
int d:4;
};
struct B3p2 {
char a;
unsigned short b:6;
int c:8;
char d; // gcc groups with int bit-field
};
struct B4p2 {
char a;
unsigned short b:6;
int c:8;
long long d;
int e:4;
};
// Verify bitfield grouping and alignment with zero-length bitfields
struct Z1p2 {
char a;
int :0; // MSVC ignores field
unsigned short b:6;
int c:8;
short d:4; // NOTE: gcc appears ignore short alignment constraint due to int :0 ???
};
struct Z1p2x {
char a;
int :0; // MSVC ignores field
unsigned short b:6;
int c:8;
short d:4; // NOTE: gcc appears ignore short alignment constraint due to int :0 ???
short d1:4;
short d2:4;
short d3:4;
short d4:4;
short d5:4;
short d6:4;
short d7:4;
short :0;
unsigned short _b:6;
int _c:8;
short _d:4; // NOTE: gcc appears ignore short alignment constraint due to int :0 ???
short _d1:4;
short _d2:4;
short _d3:4;
short _d4:4;
short _d5:4;
short _d6:4;
short _d7:4;
};
struct Z2p2 {
char a;
unsigned short b:6;
int c:8;
int :0;
short d:4;
};
struct Z3p2 {
char a;
unsigned short b:6;
int c:8;
int d:4;
long long :0; // trailing :0 (ignore when packing ?) - case needs more testing
};
struct Z4p2 {
char a;
unsigned short b:6;
int c:8;
long long :0; // forced alignment of non-bitfield
char d;
};
struct Z5p2 {
char a;
unsigned short b:12;
int c:8;
long long :0; // forced alignment of non-bitfield
char d;
};
struct x1p2 {
char a;
};
struct x2p2 {
char a;
int b:27;
};
struct x3p2 {
char a;
short :0;
int b:27;
};
struct x4p2 {
char a;
int b:27;
long long :0;
};
#pragma pack()
#pragma pack(4)
struct Z5p4 {
char a;
unsigned short b:12;
int c:8;
long long :0; // forced alignment of non-bitfield
char d;
};
struct x1p4 {
char a;
};
struct x2p4 {
char a;
int b:27;
};
struct x3p4 {
char a;
short :0;
int b:27;
};
struct x4p4 {
char a;
int b:27;
long long :0;
};
#pragma pack()
// Structures within structures
struct S1 {
struct B1 b1;
struct B2 b2;
struct Z1 z1;
struct Z2 z2;
struct Z3 z3;
};
#pragma pack(1)
struct S1p1 {
struct B1 b1;
struct B2 b2;
struct Z1 z1;
struct Z2 z2;
struct Z3 z3;
};
struct S2p1 {
struct B1p1 b1p1;
struct B2p1 b2p1;
struct Z1p1 z1p1;
struct Z2p1 z2p1;
struct Z3p1 z3p1;
};
#pragma pack()
#pragma pack(2)
struct S1p2 {
struct B1 b1;
struct B2 b2;
struct Z1 z1;
struct Z2 z2;
struct Z3 z3;
};
struct S2p2 {
struct B1p2 b1p2;
struct B2p2 b2p2;
struct Z1p2 z1p2;
struct Z2p2 z2p2;
struct Z3p2 z3p2;
};
#pragma pack()
enum myEnum { ONE, TWO, THREE };
typedef enum myEnum enumTypedef;
typedef int intTypedef;
typedef char charTypedef;
typedef short shortTypedef;
struct T1 {
charTypedef a;
enum myEnum b:3;
enumTypedef c:3;
charTypedef d:7;
};
struct T2 {
charTypedef a;
intTypedef b:17;
enumTypedef c:3;
charTypedef d:3;
};
// Unions
union U1 {
int a:4;
int b:2;
};
union U1z {
int a:4;
long long :0;
int b:2;
};
#pragma pack(1)
union U1p1 {
int a:4;
int b:2;
};
union U1p1z {
int a:4;
long long :0;
int b:2;
};
struct SUp1 {
char a;
union U1p1z u;
};
#pragma pack(2)
union U1p2 {
int a:4;
int b:2;
};
#pragma pack()