mirror of
https://github.com/NationalSecurityAgency/ghidra
synced 2024-10-13 13:43:00 +00:00
BitFields - added preliminary support for composite bitfields
This commit is contained in:
parent
c23ae691e2
commit
a7345527c9
|
@ -921,11 +921,13 @@ src/main/resources/images/L.gif||GHIDRA||||END|
|
|||
src/main/resources/images/LocalVariable.gif||GHIDRA||||END|
|
||||
src/main/resources/images/M.gif||GHIDRA||||END|
|
||||
src/main/resources/images/Merge.png||GHIDRA||||END|
|
||||
src/main/resources/images/Minus.png||GHIDRA||||END|
|
||||
src/main/resources/images/MultiDuplicateData.png||GHIDRA||||END|
|
||||
src/main/resources/images/Namespace.gif||GHIDRA||||END|
|
||||
src/main/resources/images/NextHighlightBlock16.gif||GHIDRA||||END|
|
||||
src/main/resources/images/NextSelectionBlock16.gif||GHIDRA||||END|
|
||||
src/main/resources/images/Parameter.gif||GHIDRA||||END|
|
||||
src/main/resources/images/Plus.png||GHIDRA||||END|
|
||||
src/main/resources/images/PreviousHighlightBlock16.gif||GHIDRA||||END|
|
||||
src/main/resources/images/PreviousSelectionBlock16.gif||GHIDRA||||END|
|
||||
src/main/resources/images/Program.gif||GHIDRA||||END|
|
||||
|
|
|
@ -164,6 +164,8 @@
|
|||
</P>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
|
||||
<H3>Unaligned Structures</H3>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
|
@ -300,6 +302,8 @@
|
|||
<DIV style="text-align: center; margin-top: 10px;">
|
||||
<IMG alt="" src="images/UnionEditorAligned.png">
|
||||
</DIV>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<H2><A name="Structure_Editor_Flex_Array"></A>Flexible Array Component</H2>
|
||||
|
@ -321,6 +325,16 @@
|
|||
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>
|
||||
|
||||
<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>
|
||||
|
@ -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>
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
|
@ -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,13 +15,13 @@
|
|||
*/
|
||||
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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 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";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
@ -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 +
|
||||
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
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);
|
||||
}
|
||||
if (tmpData.getNumComponents() > 0) {
|
||||
addOpenData(list, tmpData, addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -187,7 +187,8 @@ public class OutgoingFunctionCallNodeTest extends AbstractGenericTest {
|
|||
// 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());
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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();
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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();
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
|
@ -443,6 +751,16 @@ public class StructureImplTest extends AbstractGenericTest {
|
|||
assertNull(dtc);
|
||||
}
|
||||
|
||||
@Test
|
||||
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());
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
||||
// }
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
}
|
|
@ -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()
|
||||
|
||||
|
||||
|
|
@ -15,6 +15,12 @@ dependencies {
|
|||
compile project(":Base")
|
||||
|
||||
testCompile "org.jmockit:jmockit:1.44"
|
||||
|
||||
// Demangler Analyzer needs to find MicrosoftDemangler
|
||||
compile project(":MicrosoftDemangler")
|
||||
|
||||
testCompile project(path: ':Base', configuration: 'testArtifacts')
|
||||
testCompile project(path: ':SoftwareModeling', configuration: 'testArtifacts')
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -130,14 +130,14 @@ public class PdbAnalyzer extends AbstractAnalyzer {
|
|||
boolean parsePdb(File pdb, Program program, AutoAnalysisManager mgr, TaskMonitor monitor,
|
||||
MessageLog log) {
|
||||
DataTypeManagerService dataTypeManagerService = mgr.getDataTypeManagerService();
|
||||
PdbParserNEW parser = new PdbParserNEW(pdb, program, dataTypeManagerService, true);
|
||||
PdbParserNEW parser = new PdbParserNEW(pdb, program, dataTypeManagerService, true, monitor);
|
||||
|
||||
String message;
|
||||
|
||||
try {
|
||||
parser.parse();
|
||||
parser.openDataTypeArchives();
|
||||
parser.applyTo(monitor, log);
|
||||
parser.applyTo(log);
|
||||
return true;
|
||||
}
|
||||
catch (PdbException e) {
|
||||
|
@ -150,7 +150,11 @@ public class PdbAnalyzer extends AbstractAnalyzer {
|
|||
return false;
|
||||
}
|
||||
catch (Exception e) {
|
||||
Msg.showError(this, null, ERROR_TITLE, e.getMessage(), e);
|
||||
String msg = e.getMessage();
|
||||
if (msg == null) {
|
||||
msg = e.toString();
|
||||
}
|
||||
Msg.showError(this, null, ERROR_TITLE, msg, e);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,46 +19,76 @@ import java.util.*;
|
|||
|
||||
import org.xml.sax.SAXParseException;
|
||||
|
||||
import ghidra.app.util.bin.format.pdb.PdbParserNEW.PdbXmlMember;
|
||||
import ghidra.app.util.importer.MessageLog;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.graph.*;
|
||||
import ghidra.graph.algo.GraphNavigator;
|
||||
import ghidra.graph.jung.JungDirectedGraph;
|
||||
import ghidra.program.model.data.Composite;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.symbol.SymbolUtilities;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.SystemUtilities;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
import ghidra.util.xml.XmlUtilities;
|
||||
import ghidra.xml.*;
|
||||
import ghidra.xml.XmlElement;
|
||||
import ghidra.xml.XmlPullParser;
|
||||
|
||||
public class ApplyDataTypes {
|
||||
|
||||
private PdbParserNEW pdbParser;
|
||||
private boolean isClasses;
|
||||
private MessageLog log;
|
||||
private List<XmlTreeNode> todo = new ArrayList<>();
|
||||
private HashMap<String, CompositeDefinition> compositeQueue = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Construct a PDB XML datatype or class parser. This will pre-process each datatype element and cache
|
||||
* a properly sized composite for subsequent type reference. The full parse will not be completed
|
||||
* until the {@link #applyTo(TaskMonitor)} method is invoked after all types and classes have been
|
||||
* pre-processed or applied.
|
||||
* Construct a PDB XML datatype or class parser. The {@link #preProcessDataTypeList(XmlPullParser, boolean, TaskMonitor)}
|
||||
* method must be used to injest member elements from the pull parser to populate the set of type to be parsed.
|
||||
* The full parse will not be completed until the {@link #applyTo(TaskMonitor)} method is invoked after all types
|
||||
* and classes have been pre-processed or applied.
|
||||
* @param pdbParser PDB parser object
|
||||
* @param xmlParser XML parser positioned immediately after datatypes or classes element
|
||||
* @param isClasses true if processing classes, false if composite datatypes
|
||||
* @param monitor task progress monitor
|
||||
* @param log message log used during construction and subsequent method invocations
|
||||
* @throws CancelledException if monitor is cancelled
|
||||
* @throws SAXParseException PDB XML parse failure
|
||||
*/
|
||||
ApplyDataTypes(PdbParserNEW pdbParser, XmlPullParser xmlParser, boolean isClasses,
|
||||
TaskMonitor monitor, MessageLog log) throws CancelledException, SAXParseException {
|
||||
ApplyDataTypes(PdbParserNEW pdbParser, MessageLog log)
|
||||
throws CancelledException, SAXParseException {
|
||||
this.pdbParser = pdbParser;
|
||||
this.isClasses = isClasses;
|
||||
this.log = log;
|
||||
|
||||
// Build todo list and cache preliminary composite definitions
|
||||
preProcessDataTypeList(xmlParser, monitor);
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
todo.clear();
|
||||
compositeQueue.clear();
|
||||
}
|
||||
|
||||
private List<CompositeDefinition> getCompositeDefinitionsInpostDependencyOrder(
|
||||
TaskMonitor monitor) {
|
||||
|
||||
JungDirectedGraph<CompositeDefinition, GEdge<CompositeDefinition>> graph =
|
||||
new JungDirectedGraph<>();
|
||||
for (CompositeDefinition compositeDefinition : compositeQueue.values()) {
|
||||
graph.addVertex(compositeDefinition);
|
||||
for (PdbMember m : compositeDefinition.memberList) {
|
||||
String name = m.memberDataTypeName;
|
||||
int index = name.indexOf('[');
|
||||
if (index > 0) {
|
||||
name = name.substring(0, index).trim();
|
||||
}
|
||||
CompositeDefinition child = compositeQueue.get(name);
|
||||
if (child != null) {
|
||||
graph.addEdge(new DefaultGEdge<>(compositeDefinition, child));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: GraphAlgorithms.findCircuits(graph, monitor);
|
||||
|
||||
List<CompositeDefinition> verticesInPostOrder =
|
||||
GraphAlgorithms.getVerticesInPostOrder(graph, GraphNavigator.topDownNavigator());
|
||||
|
||||
return verticesInPostOrder;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -68,75 +98,67 @@ public class ApplyDataTypes {
|
|||
*/
|
||||
void buildDataTypes(TaskMonitor monitor) throws CancelledException {
|
||||
|
||||
monitor.setMessage("Order PDB datatypes... ");
|
||||
|
||||
List<CompositeDefinition> verticesInPostOrder =
|
||||
getCompositeDefinitionsInpostDependencyOrder(monitor);
|
||||
|
||||
monitor.setMessage("Building PDB datatypes... ");
|
||||
|
||||
for (XmlTreeNode node : todo) {
|
||||
for (CompositeDefinition compositeDefinition : verticesInPostOrder) {
|
||||
monitor.checkCanceled();
|
||||
|
||||
XmlElement elem = node.getStartElement();
|
||||
String name = SymbolUtilities.replaceInvalidChars(elem.getAttribute("name"), false);
|
||||
|
||||
String kind = isClasses ? PdbParserNEW.STRUCTURE_KIND : elem.getAttribute("kind");
|
||||
int length = XmlUtilities.parseInt(elem.getAttribute("length"));
|
||||
|
||||
// namespace qualified name used for cache lookups
|
||||
DataType cachedDataType = pdbParser.getCachedDataType(name);
|
||||
DataType cachedDataType = pdbParser.getCachedDataType(compositeDefinition.name);
|
||||
if (!(cachedDataType instanceof Composite) ||
|
||||
!cachedDataType.getCategoryPath().equals(pdbParser.getCategory(name, true)) ||
|
||||
!pdbParser.isCorrectKind(cachedDataType, kind)) {
|
||||
log.appendMsg("Error: Conflicting data type name: " + name);
|
||||
!cachedDataType.getCategoryPath().equals(
|
||||
pdbParser.getCategory(compositeDefinition.name, true)) ||
|
||||
!pdbParser.isCorrectKind(cachedDataType, compositeDefinition.kind)) {
|
||||
log.appendMsg("Error: Conflicting data type name: " + compositeDefinition.name);
|
||||
continue;
|
||||
}
|
||||
Composite composite = (Composite) cachedDataType;
|
||||
PdbUtil.clearComponents(composite);
|
||||
|
||||
if (!CompositeMember.applyDataTypeMembers(pdbParser, composite, length, node,
|
||||
monitor)) {
|
||||
if (!DefaultCompositeMember.applyDataTypeMembers(composite, compositeDefinition.isClass,
|
||||
compositeDefinition.length, getNormalMembersOnly(compositeDefinition),
|
||||
msg -> Msg.warn(this, msg), monitor)) {
|
||||
PdbUtil.clearComponents(composite);
|
||||
}
|
||||
|
||||
// Do not adjust size of defined structure contains flex array at specified offset
|
||||
boolean hasFlexibleArray = false;
|
||||
if (composite instanceof Structure) {
|
||||
hasFlexibleArray = ((Structure) composite).hasFlexibleArrayComponent();
|
||||
}
|
||||
// // Do not adjust size of defined structure contains flex array at specified offset
|
||||
// boolean hasFlexibleArray = false;
|
||||
// if (composite instanceof Structure) {
|
||||
// hasFlexibleArray = ((Structure) composite).hasFlexibleArrayComponent();
|
||||
// }
|
||||
|
||||
if (!isClasses && !hasFlexibleArray) {
|
||||
PdbUtil.ensureSize(length, composite, log);
|
||||
}
|
||||
// FIXME: This should be handled during finalization of composite layout
|
||||
// if (!isClass && !hasFlexibleArray) {
|
||||
// PdbUtil.ensureSize(length, composite, log);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* check to see if this data type is actually a class
|
||||
*/
|
||||
private boolean isDataTypeClass(XmlTreeNode node, TaskMonitor monitor)
|
||||
throws CancelledException {
|
||||
if (!node.getStartElement().getName().equals("datatype")) {
|
||||
return false;
|
||||
private List<PdbXmlMember> getNormalMembersOnly(CompositeDefinition compositeDefinition) {
|
||||
if (compositeDefinition.hasNormalMembersOnly) {
|
||||
return compositeDefinition.memberList;
|
||||
}
|
||||
for (int i = 0; i < node.getChildCount(); ++i) {
|
||||
if (monitor.isCancelled()) {
|
||||
throw new CancelledException();
|
||||
}
|
||||
XmlTreeNode childNode = node.getChildAt(i);
|
||||
XmlElement child = childNode.getStartElement();
|
||||
String datatype = child.getAttribute("datatype");
|
||||
if ("Function".equals(datatype)) {
|
||||
return true;
|
||||
ArrayList<PdbXmlMember> list = new ArrayList<>();
|
||||
for (PdbXmlMember m : compositeDefinition.memberList) {
|
||||
if (m.kind == PdbXmlKind.MEMBER) {
|
||||
list.add(m);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return list;
|
||||
}
|
||||
|
||||
private void preProcessDataTypeList(XmlPullParser xmlParser, TaskMonitor monitor)
|
||||
void preProcessDataTypeList(XmlPullParser xmlParser, boolean isClasses, TaskMonitor monitor)
|
||||
throws SAXParseException, CancelledException {
|
||||
|
||||
monitor.setMessage("Pre-processing PDB datatypes...");
|
||||
|
||||
String elementType = isClasses ? "classes" : "datatypes";
|
||||
|
||||
Map<String, XmlTreeNode> todoNames = new HashMap<>();
|
||||
while (xmlParser.hasNext()) {
|
||||
monitor.checkCanceled();
|
||||
XmlElement elem = xmlParser.peek();
|
||||
|
@ -144,50 +166,106 @@ public class ApplyDataTypes {
|
|||
xmlParser.next();
|
||||
break;
|
||||
}
|
||||
String name = SymbolUtilities.replaceInvalidChars(elem.getAttribute("name"), false);
|
||||
XmlTreeNode node = new XmlTreeNode(xmlParser);
|
||||
if (todoNames.containsKey(name)) {
|
||||
XmlTreeNode todoNode = todoNames.get(name);
|
||||
if (elem.toString().equals(todoNode.getStartElement().toString())) {
|
||||
//TODO log.appendMsg("Duplicate data type defined in PDB: "+name);
|
||||
}
|
||||
else {
|
||||
//TODO log.appendMsg("Data type re-definition ignored: "+name);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (isClasses || isDataTypeClass(node, monitor)) {
|
||||
pdbParser.predefineClass(name);
|
||||
}
|
||||
todoNames.put(name, node);
|
||||
|
||||
String kind = isClasses ? PdbParserNEW.STRUCTURE_KIND : elem.getAttribute("kind");
|
||||
CompositeDefinition compositeDefinition = new CompositeDefinition(xmlParser);
|
||||
|
||||
if (pdbParser.getCachedDataType(name) != null) {
|
||||
log.appendMsg(
|
||||
"Error: Data type name collision - unable to define " + kind + ": " + name);
|
||||
if (!compositeQueue.containsKey(compositeDefinition.name)) {
|
||||
// could be problematic if duplicate names represent two different composites
|
||||
if (compositeDefinition.isClass) {
|
||||
pdbParser.predefineClass(compositeDefinition.name);
|
||||
}
|
||||
compositeQueue.put(compositeDefinition.name, compositeDefinition);
|
||||
|
||||
if (pdbParser.getCachedDataType(compositeDefinition.name) != null) {
|
||||
log.appendMsg("Error: Data type name collision - unable to define " +
|
||||
compositeDefinition.kind.getCamelName() + ": " + compositeDefinition.name);
|
||||
continue;
|
||||
}
|
||||
|
||||
todo.add(node);
|
||||
|
||||
// /** Can this be avoided if using dependency ordering ??
|
||||
// NOTE: currently composite may grow if zero-length array used
|
||||
// since we must currently allocate one element since 0-length array
|
||||
// not yet supported.
|
||||
Composite composite = pdbParser.createComposite(kind, name);
|
||||
Composite composite =
|
||||
pdbParser.createComposite(compositeDefinition.kind, compositeDefinition.name);
|
||||
if (composite == null) {
|
||||
log.appendMsg("Unsupported datatype kind (" + kind + "): " + name);
|
||||
log.appendMsg("Unsupported datatype kind (" + compositeDefinition.kind + "): " +
|
||||
compositeDefinition.name);
|
||||
continue;
|
||||
}
|
||||
if (!isClasses) {
|
||||
int length = XmlUtilities.parseInt(elem.getAttribute("length"));
|
||||
PdbUtil.ensureSize(length, composite, log);
|
||||
}
|
||||
pdbParser.cacheDataType(name, composite);
|
||||
// if (!isClasses) {
|
||||
// int length = XmlUtilities.parseInt(elem.getAttribute("length"));
|
||||
// PdbUtil.ensureSize(length, composite, log);
|
||||
// }
|
||||
pdbParser.cacheDataType(compositeDefinition.name, composite);
|
||||
// **/
|
||||
}
|
||||
}
|
||||
todoNames.clear();//release memory...
|
||||
todoNames = null;
|
||||
}
|
||||
|
||||
private class CompositeDefinition {
|
||||
final boolean isClass;
|
||||
final PdbXmlKind kind;
|
||||
final String name;
|
||||
final int length;
|
||||
final List<PdbXmlMember> memberList = new ArrayList<>();
|
||||
final boolean hasNormalMembersOnly;
|
||||
|
||||
CompositeDefinition(XmlPullParser parser) {
|
||||
XmlElement startElement = parser.start();
|
||||
name = SymbolUtilities.replaceInvalidChars(startElement.getAttribute("name"), false);
|
||||
length = XmlUtilities.parseInt(startElement.getAttribute("length"));
|
||||
String kindStr = startElement.getAttribute("kind");
|
||||
boolean membersOnly = true;
|
||||
XmlElement element = parser.peek();
|
||||
while (element != null && element.isStart()) {
|
||||
element = parser.start("member");
|
||||
PdbXmlMember pdbXmlMember = pdbParser.getPdbXmlMember(element);
|
||||
memberList.add(pdbXmlMember);
|
||||
membersOnly &= (pdbXmlMember.kind == PdbXmlKind.MEMBER);
|
||||
parser.end(element);
|
||||
element = parser.peek();
|
||||
}
|
||||
parser.end(startElement);
|
||||
this.hasNormalMembersOnly = membersOnly;
|
||||
this.isClass = "class".equals(startElement.getName()) || isInferredClass(kindStr);
|
||||
this.kind = isClass ? PdbXmlKind.STRUCTURE : PdbXmlKind.parse(kindStr);
|
||||
}
|
||||
|
||||
private boolean isInferredClass(String kindStr) {
|
||||
|
||||
for (PdbXmlMember m : memberList) {
|
||||
if (m.kind == PdbXmlKind.MEMBER) {
|
||||
continue;
|
||||
}
|
||||
if ("void *".equals(m.memberDataTypeName)) {
|
||||
return true;
|
||||
}
|
||||
if ("Function".equals(m.memberDataTypeName)) { // ??
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return name.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
CompositeDefinition other = (CompositeDefinition) obj;
|
||||
return isClass == other.isClass && kind == other.kind && length == other.length &&
|
||||
SystemUtilities.isEqual(name, other.name);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
package ghidra.app.util.bin.format.pdb;
|
||||
|
||||
import ghidra.app.cmd.function.CallDepthChangeInfo;
|
||||
import ghidra.app.util.bin.format.pdb.PdbParserNEW.WrappedDataType;
|
||||
import ghidra.app.util.bin.format.pdb.PdbParserNEW.PdbXmlMember;
|
||||
import ghidra.app.util.importer.MessageLog;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSet;
|
||||
|
@ -56,25 +56,25 @@ class ApplyStackVariables {
|
|||
}
|
||||
elem = xmlParser.next();//stack variable number start tag
|
||||
|
||||
PdbMember member = new PdbMember(elem, monitor);
|
||||
PdbXmlMember member = pdbParser.getPdbXmlMember(elem);
|
||||
|
||||
if ("StaticLocal".equals(member.memberKind)) {
|
||||
if (PdbXmlKind.STATIC_LOCAL == member.kind) {
|
||||
xmlParser.next();//stack variable number end tag
|
||||
continue;
|
||||
}
|
||||
|
||||
DataType dt = getDataType(member, log, monitor);
|
||||
DataType dt = getDataType(member, log);
|
||||
if (dt == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ("ObjectPointer".equals(member.memberKind)) {
|
||||
if (PdbXmlKind.OBJECT_POINTER == member.kind) {
|
||||
createRegisterParameter(member.memberName, dt, log);
|
||||
}
|
||||
else if ("Parameter".equals(member.memberKind)) {
|
||||
else if (PdbXmlKind.PARAMETER == member.kind) {
|
||||
createStackVariable(member.memberName, frameBase + member.memberOffset, dt, log);
|
||||
}
|
||||
else if ("Local".equals(member.memberKind)) {
|
||||
else if (PdbXmlKind.LOCAL == member.kind) {
|
||||
createStackVariable(member.memberName, frameBase + member.memberOffset, dt, log);
|
||||
}
|
||||
|
||||
|
@ -188,20 +188,19 @@ class ApplyStackVariables {
|
|||
return variable;
|
||||
}
|
||||
|
||||
private DataType getDataType(PdbMember member, MessageLog log, TaskMonitor monitor)
|
||||
throws CancelledException {
|
||||
WrappedDataType wrappedDataType =
|
||||
pdbParser.findDataType(member.memberDataTypeName, monitor);
|
||||
private DataType getDataType(PdbXmlMember member, MessageLog log) throws CancelledException {
|
||||
WrappedDataType wrappedDataType = pdbParser.findDataType(member.memberDataTypeName);
|
||||
if (wrappedDataType == null) {
|
||||
log.appendMsg("Error: failed to resolve data type for " + member.memberKind + ": " +
|
||||
log.appendMsg("Error: failed to resolve data type for " + member.kind + ": " +
|
||||
member.memberDataTypeName);
|
||||
return null;
|
||||
}
|
||||
if (wrappedDataType.isZeroLengthArray) {
|
||||
log.appendMsg("Error: zero length array not supported for for " + member.memberKind +
|
||||
": " + member.memberDataTypeName);
|
||||
if (wrappedDataType.isZeroLengthArray()) {
|
||||
log.appendMsg("Error: zero length array not supported for for " + member.kind + ": " +
|
||||
member.memberDataTypeName);
|
||||
return null;
|
||||
}
|
||||
return wrappedDataType.dataType;
|
||||
return wrappedDataType.getDataType();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -20,7 +20,6 @@ import java.util.List;
|
|||
|
||||
import org.xml.sax.SAXParseException;
|
||||
|
||||
import ghidra.app.util.bin.format.pdb.PdbParserNEW.WrappedDataType;
|
||||
import ghidra.app.util.importer.MessageLog;
|
||||
import ghidra.program.model.data.TypedefDataType;
|
||||
import ghidra.program.model.symbol.SymbolUtilities;
|
||||
|
@ -98,19 +97,20 @@ class ApplyTypeDefs {
|
|||
continue;//TODO is this actually a global function
|
||||
}
|
||||
|
||||
WrappedDataType baseDataType = pdbParser.findDataType(baseDatatypeName, monitor);
|
||||
WrappedDataType baseDataType = pdbParser.findDataType(baseDatatypeName);
|
||||
if (baseDataType == null) {
|
||||
log.appendMsg("Error: failed to resolve typedef: " + datatypeName + " -> " +
|
||||
baseDatatypeName);
|
||||
continue;
|
||||
}
|
||||
if (baseDataType.isZeroLengthArray) {
|
||||
if (baseDataType.isZeroLengthArray()) {
|
||||
log.appendMsg(
|
||||
"Error: zero length array not supported for typedef: " + datatypeName);
|
||||
continue;
|
||||
}
|
||||
|
||||
TypedefDataType typedef = pdbParser.createTypeDef(datatypeName, baseDataType.dataType);
|
||||
TypedefDataType typedef =
|
||||
pdbParser.createTypeDef(datatypeName, baseDataType.getDataType());
|
||||
pdbParser.cacheDataType(datatypeName, typedef); // cache with namespace-based name
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,160 @@
|
|||
/* ###
|
||||
* 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.util.bin.format.pdb;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.program.model.data.BitFieldDataType;
|
||||
import ghidra.program.model.data.DataType;
|
||||
|
||||
/**
|
||||
* <code>BitFieldGroupCompositeMember</code> provides the ability to collect related
|
||||
* {@link DefaultCompositeMember} members within a group during the composite reconstruction
|
||||
* process.
|
||||
*/
|
||||
public class BitFieldGroupCompositeMember extends CompositeMember {
|
||||
|
||||
private List<DefaultCompositeMember> list = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
boolean isBitFieldMember() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isSingleBitFieldMember() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isContainer() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isStructureContainer() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isUnionContainer() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
int getOffset() {
|
||||
if (list.isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
return list.get(0).getOffset();
|
||||
}
|
||||
|
||||
int getConsumedBits() {
|
||||
// TODO: this could be maintained as a field
|
||||
int consumed = 0;
|
||||
for (DefaultCompositeMember m : list) {
|
||||
consumed += ((BitFieldDataType) m.getDataType()).getBitSize();
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
@Override
|
||||
void setOffset(int offset) {
|
||||
for (DefaultCompositeMember m : list) {
|
||||
m.setOffset(offset);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
int getLength() {
|
||||
if (list.isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
return list.get(0).getLength();
|
||||
}
|
||||
|
||||
@Override
|
||||
DefaultCompositeMember getParent() {
|
||||
if (list.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return list.get(0).getParent();
|
||||
}
|
||||
|
||||
@Override
|
||||
void setParent(DefaultCompositeMember newParent) {
|
||||
for (DefaultCompositeMember m : list) {
|
||||
m.setParent(newParent);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean addMember(DefaultCompositeMember member) {
|
||||
|
||||
DataType dt = member.getDataType();
|
||||
if (dt == null || dt.getLength() <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// trigger structure/union transformation
|
||||
DefaultCompositeMember bf0 = list.remove(0);
|
||||
|
||||
return bf0.addMember(member);
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean addToStructure(DefaultCompositeMember structure) {
|
||||
// add all bit-fields to structure and allow them to regroup
|
||||
boolean success = true;
|
||||
for (DefaultCompositeMember m : list) {
|
||||
m.setBitFieldGroup(null);
|
||||
success &= m.addToStructure(structure);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
@Override
|
||||
void finalizeDataType(int preferredSize) {
|
||||
return; // nothing to do
|
||||
}
|
||||
|
||||
private DefaultCompositeMember validateNewMember(CompositeMember member) {
|
||||
if (!member.isSingleBitFieldMember()) {
|
||||
throw new IllegalArgumentException("expected single bit-field member");
|
||||
}
|
||||
if (!list.isEmpty() &&
|
||||
(member.getOffset() != getOffset() || member.getLength() != getLength())) {
|
||||
throw new IllegalArgumentException(
|
||||
"expected bit-field member with same offset and length");
|
||||
}
|
||||
DefaultCompositeMember m = (DefaultCompositeMember) member;
|
||||
m.setBitFieldGroup(this);
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new member to the end of this bit-field group. The caller should ensure that the
|
||||
* specified member is a suitable addition to this group (must be single bit field whose
|
||||
* member offset and length match this group's).
|
||||
* @param member bit-field member (must have data type of BitFieldDataType).
|
||||
* @throws IllegalArgumentException if specified member is not suitable for this group.
|
||||
*/
|
||||
void addToGroup(CompositeMember member) {
|
||||
list.add(validateNewMember(member));
|
||||
}
|
||||
|
||||
}
|
|
@ -15,180 +15,13 @@
|
|||
*/
|
||||
package ghidra.app.util.bin.format.pdb;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import ghidra.app.util.bin.format.pdb.PdbParserNEW.WrappedDataType;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.*;
|
||||
import ghidra.util.datastruct.RangeMap;
|
||||
import ghidra.util.exception.*;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
import ghidra.util.xml.XmlUtilities;
|
||||
import ghidra.xml.XmlTreeNode;
|
||||
import ghidra.program.model.data.BitFieldDataType;
|
||||
|
||||
/**
|
||||
* <code>CompositeMember</code> provides the ability to process PDB data-type records and
|
||||
* incrementally build-up composite structure and union data-types from a flattened offset-based
|
||||
* list of members which may include embedded anonymous composite members. Composite members
|
||||
* correspond to either hard predefined data-types, or structure/union containers whose members
|
||||
* are added and refined incrementally.
|
||||
* <p>
|
||||
* Container members are characterized by a null data-type name, zero length, and will be
|
||||
* identified as either a structure or union.
|
||||
* <code>CompositeMember</code> provides a composite construction member interface for use
|
||||
* by the PDB parser.
|
||||
*/
|
||||
class CompositeMember {
|
||||
|
||||
private static int MAX_CONSTRUCTION_DEPTH = 20;
|
||||
|
||||
private DataTypeManager dataTypeManager;
|
||||
|
||||
private CompositeMember parent; // parent container (null if this is root container)
|
||||
|
||||
private String memberName; // null if this is a root container
|
||||
private String memberDataTypeName; // null if this is a container
|
||||
private int memberOffset; // member offset relative to start of parent container
|
||||
private String memberKind; // PDB defined kind of data type (e.g., Structure, Union)
|
||||
private int memberLength; // container members have 0 length (rely on memberDataType)
|
||||
|
||||
private DataType memberDataType;
|
||||
private boolean memberIsZeroLengthArray;
|
||||
|
||||
private DataTypeResolver memberDataTypeResolver;
|
||||
|
||||
// Structure container data
|
||||
private Map<Integer, CompositeMember> structureMemberOffsetMap;
|
||||
private RangeMap structureMemberRangeMap;
|
||||
|
||||
// Union container data
|
||||
private List<CompositeMember> unionMemberList;
|
||||
private boolean isBitFieldUnion;
|
||||
private int bitFieldUnionLength;
|
||||
|
||||
private static long nextTemporaryValue;
|
||||
|
||||
private static synchronized String allocateTemporaryContainerName() {
|
||||
return "_tmp_" + nextTemporaryValue++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct the outermost root container member for a new composite data-type.
|
||||
* @param dataTypeResolver data-type resolver
|
||||
* @param monitor task monitor
|
||||
* @throws CancelledException if task is cancelled
|
||||
*/
|
||||
CompositeMember(DataTypeResolver dataTypeResolver, DataTypeManager dataTypeManager)
|
||||
throws CancelledException {
|
||||
memberOffset = -1;
|
||||
memberDataTypeResolver = dataTypeResolver;
|
||||
this.dataTypeManager = dataTypeManager;
|
||||
resolve();
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new composite member from a PDB data-type member record.
|
||||
* @param member PDB member record
|
||||
* @param dataTypeResolver data-type resolver
|
||||
* @param monitor task monitor
|
||||
* @throws CancelledException if task is cancelled
|
||||
*/
|
||||
private CompositeMember(PdbMember member, DataTypeResolver dataTypeResolver,
|
||||
DataTypeManager dataTypeManager, TaskMonitor monitor) throws CancelledException {
|
||||
memberName = member.memberName;
|
||||
memberDataTypeName = member.memberDataTypeName;
|
||||
memberOffset = member.memberOffset;
|
||||
memberKind = member.memberKind;
|
||||
memberLength = member.memberLength;
|
||||
memberDataTypeResolver = dataTypeResolver;
|
||||
this.dataTypeManager = dataTypeManager;
|
||||
resolve();
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new composite member by cloning an existing member.
|
||||
* @param member composite member to be cloned
|
||||
*/
|
||||
private CompositeMember(CompositeMember member) {
|
||||
memberName = member.memberName;
|
||||
memberDataTypeName = member.memberDataTypeName;
|
||||
memberDataType = member.memberDataType;
|
||||
memberIsZeroLengthArray = member.memberIsZeroLengthArray;
|
||||
memberOffset = member.memberOffset;
|
||||
memberKind = member.memberKind;
|
||||
memberLength = member.memberLength;
|
||||
memberDataTypeResolver = member.memberDataTypeResolver;
|
||||
dataTypeManager = member.dataTypeManager;
|
||||
structureMemberOffsetMap = member.structureMemberOffsetMap;
|
||||
structureMemberRangeMap = member.structureMemberRangeMap;
|
||||
unionMemberList = member.unionMemberList;
|
||||
isBitFieldUnion = member.isBitFieldUnion;
|
||||
bitFieldUnionLength = member.bitFieldUnionLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get member name to be used within parent composite definition
|
||||
* @return member name or null if this is root container
|
||||
*/
|
||||
String getName() {
|
||||
return memberName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the PDB defined KIND designator for this member (e.g., Structure, Union)
|
||||
* @return PDB defined KIND of member
|
||||
*/
|
||||
String getKind() {
|
||||
return memberKind;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the data type name associated with this member. Anonymous inner composite
|
||||
* types will utilize a generated named based upon its parent type name and the
|
||||
* offset at which it occurs within its parent.
|
||||
* @return data type name associated with this member
|
||||
*/
|
||||
String getDataTypeName() {
|
||||
return memberDataType != null ? memberDataType.getName() : memberDataTypeName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the data type associated with this member. Container members data-type
|
||||
* may continue to transform as additional members are added.
|
||||
* @return data type associated with this member.
|
||||
*/
|
||||
DataType getDataType() {
|
||||
return memberDataType;
|
||||
}
|
||||
|
||||
private void updateContainerNameAndCategoryPath(String typeMnemonic) {
|
||||
if (parent == null || !isContainer()) {
|
||||
return; // only non-root container may be renamed
|
||||
}
|
||||
String baseName = parent.getDataTypeName();
|
||||
String oldMemberName = memberName;
|
||||
String name = "_" + typeMnemonic + "_";
|
||||
if (parent.isUnionContainer()) {
|
||||
try {
|
||||
name += parent.getOrdinal(oldMemberName);
|
||||
}
|
||||
catch (NotFoundException e) {
|
||||
Msg.error(this, "Failed to rename anonymous compsite: " + getDataTypeName());
|
||||
}
|
||||
}
|
||||
else {
|
||||
name += memberOffset;
|
||||
}
|
||||
try {
|
||||
memberDataType.setName(baseName + name);
|
||||
memberDataType.setCategoryPath(parent.getChildCategoryPath());
|
||||
|
||||
memberName = name;
|
||||
parent.memberNameChanged(oldMemberName, memberName);
|
||||
}
|
||||
catch (InvalidNameException | DuplicateNameException e) {
|
||||
// exceptions are unexpected
|
||||
throw new AssertException(e);
|
||||
}
|
||||
}
|
||||
abstract class CompositeMember {
|
||||
|
||||
/**
|
||||
* Due to the dynamic restructuring of data type containers, this method should be invoked
|
||||
|
@ -197,624 +30,82 @@ class CompositeMember {
|
|||
* unions to reflect the final organization and check if internal alignment should be enabled.
|
||||
* @param preferredSize preferred size of composite if known, else <= 0 if unknown
|
||||
*/
|
||||
void finalizeDataType(int preferredSize) {
|
||||
if (!isContainer()) {
|
||||
return;
|
||||
}
|
||||
if (isStructureContainer()) {
|
||||
updateContainerNameAndCategoryPath("s");
|
||||
CompositeMember lastMember = null;
|
||||
for (CompositeMember member : structureMemberOffsetMap.values()) {
|
||||
member.finalizeDataType(0);
|
||||
lastMember = member;
|
||||
}
|
||||
if (lastMember != null && lastMember.memberIsZeroLengthArray) {
|
||||
// transform last member into flexible array
|
||||
Structure struct = (Structure) memberDataType;
|
||||
Array array = (Array) lastMember.getDataType();
|
||||
struct.setFlexibleArrayComponent(array.getDataType(), lastMember.getName(), null);
|
||||
struct.delete(struct.getNumComponents() - 1);
|
||||
}
|
||||
}
|
||||
else if (isUnionContainer()) {
|
||||
if (isBitFieldUnionContainer()) {
|
||||
updateContainerNameAndCategoryPath("bitfield");
|
||||
}
|
||||
else {
|
||||
updateContainerNameAndCategoryPath("u");
|
||||
for (CompositeMember member : unionMemberList) {
|
||||
member.finalizeDataType(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (testContainerAlignment(preferredSize)) {
|
||||
((Composite) memberDataType).setInternallyAligned(true);
|
||||
}
|
||||
}
|
||||
abstract void finalizeDataType(int preferredSize);
|
||||
|
||||
/**
|
||||
* Determine is a container type should enable alignment.
|
||||
* @param preferredSize preferred size of composite if known, else <= 0 if unknown
|
||||
* @return true if internal structure alignment should be enabled, else false
|
||||
* Determine if this member is a container
|
||||
* @return true if container, else false
|
||||
*/
|
||||
private boolean testContainerAlignment(int preferredSize) {
|
||||
Composite copy = (Composite) memberDataType.copy(dataTypeManager);
|
||||
copy.setInternallyAligned(true);
|
||||
if (preferredSize <= 0) {
|
||||
// assume anonymous composites are aligned if size does not change
|
||||
return copy.getLength() == memberDataType.getLength();
|
||||
}
|
||||
// use alignment if length matches preferredSize
|
||||
return copy.getLength() == preferredSize;
|
||||
}
|
||||
abstract boolean isContainer();
|
||||
|
||||
/**
|
||||
* Determine if this member is a union container
|
||||
* @return true if union container, else false
|
||||
*/
|
||||
abstract boolean isUnionContainer();
|
||||
|
||||
/**
|
||||
* Determine if this member is a structure container
|
||||
* @return true if structure container, else false
|
||||
*/
|
||||
abstract boolean isStructureContainer();
|
||||
|
||||
/**
|
||||
* Determine if this member is a bit-field member or group.
|
||||
* @return true if bit-field member, else false
|
||||
*/
|
||||
abstract boolean isBitFieldMember();
|
||||
|
||||
/**
|
||||
* Determine if this member is a bit-field member not yet contained within a group.
|
||||
* If true is returned this instance is ensured to be a {@link DefaultCompositeMember} instance
|
||||
* whose data type is {@link BitFieldDataType}.
|
||||
* @return true if bit-field member not yet contained within a group
|
||||
*/
|
||||
abstract boolean isSingleBitFieldMember();
|
||||
|
||||
/**
|
||||
* Get the offset of this member relative to the start of its parent container.
|
||||
* @return relative member offset or -1 for root container
|
||||
*/
|
||||
int getOffset() {
|
||||
return memberOffset;
|
||||
}
|
||||
abstract int getOffset();
|
||||
|
||||
/**
|
||||
* Set the offset of this member relative to the start of its parent container.
|
||||
* @param offset relative member offset
|
||||
*/
|
||||
abstract void setOffset(int offset);
|
||||
|
||||
/**
|
||||
* Get the data type length associated with this member. Container members data-type
|
||||
* length may continue to grow as additional members are added.
|
||||
* @return data type associated with this member.
|
||||
*/
|
||||
int getLength() {
|
||||
return memberDataType != null ? memberDataType.getLength() : memberLength;
|
||||
}
|
||||
|
||||
private void resolve() throws CancelledException {
|
||||
WrappedDataType wrappedDataType = memberDataTypeResolver.resolveDataType(this);
|
||||
if (wrappedDataType != null) {
|
||||
memberDataType = wrappedDataType.dataType.clone(dataTypeManager);
|
||||
memberIsZeroLengthArray = wrappedDataType.isZeroLengthArray;
|
||||
}
|
||||
if (isContainer()) {
|
||||
initializeContainer();
|
||||
}
|
||||
}
|
||||
|
||||
private void initializeContainer() {
|
||||
if (!(memberDataType instanceof Composite)) {
|
||||
throw new AssertException("Root must resolve to a composite type");
|
||||
}
|
||||
if (memberDataType instanceof Structure) {
|
||||
memberKind = PdbParserNEW.STRUCTURE_KIND;
|
||||
structureMemberOffsetMap = new TreeMap<>();
|
||||
structureMemberRangeMap = new RangeMap(-1);
|
||||
unionMemberList = null;
|
||||
}
|
||||
else {
|
||||
memberKind = PdbParserNEW.UNION_KIND;
|
||||
unionMemberList = new ArrayList<>();
|
||||
structureMemberOffsetMap = null;
|
||||
structureMemberRangeMap = null;
|
||||
}
|
||||
isBitFieldUnion = false;
|
||||
bitFieldUnionLength = 0;
|
||||
memberLength = 0; // compositeMemberLength is preserved
|
||||
}
|
||||
abstract int getLength();
|
||||
|
||||
/**
|
||||
* Determine if this member is a container
|
||||
* @return true if container, else false
|
||||
* Get the parent which corresponds to this member
|
||||
* @return parent
|
||||
*/
|
||||
boolean isContainer() {
|
||||
return memberDataTypeName == null;
|
||||
}
|
||||
abstract DefaultCompositeMember getParent();
|
||||
|
||||
/**
|
||||
* Determine if this member is a union container
|
||||
* @return true if union container, else false
|
||||
* Set the composite parent which contains this member
|
||||
* @param parent new parent
|
||||
*/
|
||||
boolean isUnionContainer() {
|
||||
return unionMemberList != null;
|
||||
}
|
||||
abstract void setParent(DefaultCompositeMember parent);
|
||||
|
||||
/**
|
||||
* Determine if this member is a structure container
|
||||
* @return true if structure container, else false
|
||||
* Add specified member to this member. If this member is not a composite
|
||||
* it will trigger the creation
|
||||
* @param member
|
||||
* @return
|
||||
*/
|
||||
boolean isStructureContainer() {
|
||||
return structureMemberOffsetMap != null;
|
||||
}
|
||||
abstract boolean addMember(DefaultCompositeMember member);
|
||||
|
||||
/**
|
||||
* Determine if this member is a bit-field member
|
||||
* @return true if bit-field member, else false
|
||||
* Instructs this member to add itself to the specified structure
|
||||
* @param structure composite structure
|
||||
*/
|
||||
boolean isBitFieldMember() {
|
||||
if (memberName == null || memberLength == 0) {
|
||||
return false;
|
||||
}
|
||||
int colonPos = memberName.indexOf(':');
|
||||
if (colonPos == -1) {
|
||||
return false;
|
||||
}
|
||||
int nextColonPos = memberName.indexOf(':', colonPos + 1);
|
||||
if (nextColonPos != -1) {
|
||||
return false;
|
||||
}
|
||||
String[] split = memberName.split(":");
|
||||
try {
|
||||
int bitIndex = XmlUtilities.parseInt(split[1]);
|
||||
if (bitIndex < 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean isBitFieldUnionContainer() {
|
||||
if (!isUnionContainer() || unionMemberList.size() < 2) {
|
||||
return false;
|
||||
}
|
||||
CompositeMember member0 = unionMemberList.get(0);
|
||||
CompositeMember member1 = unionMemberList.get(1);
|
||||
return member0.isBitFieldMember() && member0.isCompanionBitField(member1);
|
||||
}
|
||||
|
||||
private int getDepth() {
|
||||
int depth = 0;
|
||||
CompositeMember p = parent;
|
||||
while (p != null) {
|
||||
p = p.parent;
|
||||
++depth;
|
||||
}
|
||||
return depth;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String type;
|
||||
if (isUnionContainer()) {
|
||||
type = PdbParserNEW.UNION_KIND;
|
||||
}
|
||||
else if (isStructureContainer()) {
|
||||
type = PdbParserNEW.STRUCTURE_KIND;
|
||||
}
|
||||
else {
|
||||
type = memberDataTypeName;
|
||||
}
|
||||
return "[CompositeMember: " + memberOffset + " " + memberName + " " + type + "]";
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>DataTypeResolver</code> provides the ability to resolve a member's data-type
|
||||
* at the time of construction.
|
||||
*/
|
||||
interface DataTypeResolver {
|
||||
/**
|
||||
* Find the specified member's data type based upon its' data-type name
|
||||
* @param member composite member to be resolved
|
||||
* @return data-type which corresponds to the specified member's data-type name or null
|
||||
* if unable to resolve.
|
||||
* @throws CancelledException if operation cancelled
|
||||
*/
|
||||
WrappedDataType resolveDataType(CompositeMember member) throws CancelledException;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to add a child member to this composite hierarchy
|
||||
* @param child PDB data-type member record
|
||||
* @param monitor task monitor
|
||||
* @return true if child data type resolved and it was successfully added to composite hierarchy,
|
||||
* false if unable to resolve member's data-type or other error occurred.
|
||||
* NOTE: there may be complex hierarchies not yet handled.
|
||||
* @throws CancelledException if operation cancelled
|
||||
*/
|
||||
boolean addMember(PdbMember child, TaskMonitor monitor) throws CancelledException {
|
||||
|
||||
if (!isContainer()) {
|
||||
throw new AssertException("addMember only permitted on root members");
|
||||
}
|
||||
if (!(memberDataType instanceof Composite)) {
|
||||
throw new AssertException();
|
||||
}
|
||||
|
||||
if (!child.memberKind.equals("Member")) {
|
||||
throw new AssertException();
|
||||
}
|
||||
|
||||
return addMember(
|
||||
new CompositeMember(child, memberDataTypeResolver, dataTypeManager, monitor));
|
||||
}
|
||||
|
||||
private CategoryPath getChildCategoryPath() {
|
||||
return new CategoryPath(memberDataType.getCategoryPath(), getDataTypeName());
|
||||
}
|
||||
|
||||
private String getOutermostDataTypeName() {
|
||||
if (parent != null) {
|
||||
return parent.getOutermostDataTypeName();
|
||||
}
|
||||
return getDataTypeName();
|
||||
}
|
||||
|
||||
private boolean transformIntoUnionContainer() {
|
||||
|
||||
if (parent == null) {
|
||||
throw new AssertException();
|
||||
}
|
||||
|
||||
if (getDepth() >= MAX_CONSTRUCTION_DEPTH) {
|
||||
Msg.error(this, "PDB composite reconstruction exceeded maximum allowed depth: " +
|
||||
getOutermostDataTypeName());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Remove siblings from parent whose offsets are greater
|
||||
List<CompositeMember> elderSiblings = kidnapElderSiblingsFromParentStructure();
|
||||
|
||||
CompositeMember memberCopy = new CompositeMember(this);
|
||||
memberCopy.memberOffset = 0;
|
||||
|
||||
CategoryPath tempCategoryPath = parent.getDataType().getCategoryPath();
|
||||
String tempName = allocateTemporaryContainerName();
|
||||
|
||||
Union nestedUnion = new UnionDataType(tempCategoryPath, tempName, dataTypeManager);
|
||||
|
||||
nestedUnion.add(memberDataType, memberName, null);
|
||||
|
||||
String oldName = memberName;
|
||||
memberName = tempName;
|
||||
memberDataType = nestedUnion;
|
||||
memberIsZeroLengthArray = false;
|
||||
memberDataTypeName = null; // signifies a container
|
||||
initializeContainer();
|
||||
|
||||
unionMemberList.add(memberCopy);
|
||||
memberCopy.parent = this;
|
||||
|
||||
if (!elderSiblings.isEmpty()) {
|
||||
memberCopy.transformIntoStructureContainer();
|
||||
for (CompositeMember sibling : elderSiblings) {
|
||||
sibling.memberOffset -= memberOffset;
|
||||
if (!memberCopy.addStructureMember(sibling)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
isBitFieldUnion = memberCopy.isBitFieldMember();
|
||||
if (isBitFieldUnion) {
|
||||
bitFieldUnionLength = memberCopy.memberLength; // bit field length is bit-length
|
||||
}
|
||||
|
||||
if (parent != null) {
|
||||
parent.memberChanged(oldName, this);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean transformIntoStructureContainer() {
|
||||
|
||||
if (parent == null) {
|
||||
throw new AssertException();
|
||||
}
|
||||
|
||||
if (getDepth() >= MAX_CONSTRUCTION_DEPTH) {
|
||||
Msg.error(this, "PDB composite reconstruction exceeded maximum allowed depth: " +
|
||||
getOutermostDataTypeName());
|
||||
return false;
|
||||
}
|
||||
|
||||
CompositeMember memberCopy = new CompositeMember(this);
|
||||
memberCopy.memberOffset = 0;
|
||||
|
||||
CategoryPath tempCategoryPath = parent.getDataType().getCategoryPath();
|
||||
String tempName = allocateTemporaryContainerName();
|
||||
|
||||
Structure nestedStructure =
|
||||
new StructureDataType(tempCategoryPath, tempName, 0, dataTypeManager);
|
||||
|
||||
nestedStructure.insertAtOffset(0, memberDataType, memberDataType.getLength(), memberName,
|
||||
getStructureMemberComment());
|
||||
|
||||
String oldName = memberName;
|
||||
memberName = tempName;
|
||||
memberDataType = nestedStructure;
|
||||
memberIsZeroLengthArray = false;
|
||||
memberDataTypeName = null; // signifies a container
|
||||
initializeContainer();
|
||||
|
||||
structureMemberRangeMap.paintRange(0, memberCopy.getLength() - 1, 0);
|
||||
structureMemberOffsetMap.put(0, memberCopy);
|
||||
memberCopy.parent = this;
|
||||
|
||||
if (parent != null) {
|
||||
parent.memberChanged(oldName, this);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private String getStructureMemberComment() {
|
||||
if (memberIsZeroLengthArray) {
|
||||
return "warning: zero length array forced to have one element";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean addStructureMember(CompositeMember member) {
|
||||
|
||||
// check for conflict within structure container
|
||||
int conflictOffset = structureMemberRangeMap.getValue(member.memberOffset);
|
||||
if (conflictOffset < 0) {
|
||||
structureMemberOffsetMap.put(member.memberOffset, member);
|
||||
structureMemberRangeMap.paintRange(member.memberOffset,
|
||||
member.memberOffset + member.getLength() - 1, member.memberOffset);
|
||||
member.parent = this;
|
||||
((Structure) memberDataType).insertAtOffset(member.memberOffset, member.memberDataType,
|
||||
member.getLength(), member.memberName, member.getStructureMemberComment());
|
||||
if (parent != null) {
|
||||
parent.sizeChanged(this);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
CompositeMember conflictMember = structureMemberOffsetMap.get(conflictOffset);
|
||||
|
||||
// adjust this member for addition to container
|
||||
member.memberOffset -= conflictMember.memberOffset;
|
||||
|
||||
return conflictMember.addMember(member);
|
||||
}
|
||||
|
||||
private boolean addUnionMember(CompositeMember member) {
|
||||
|
||||
if (member.memberOffset == 0) {
|
||||
if (isBitFieldUnion && !isCompanionBitField(member)) {
|
||||
// push this union into a new union
|
||||
transformIntoUnionContainer();
|
||||
return addUnionMember(member); // try again
|
||||
}
|
||||
|
||||
if (!isBitFieldUnion && unionMemberList.size() != 0 && member.isBitFieldMember()) {
|
||||
CompositeMember lastUnionMember = unionMemberList.get(unionMemberList.size() - 1);
|
||||
if (lastUnionMember.isCompanionBitField(member)) {
|
||||
return lastUnionMember.addMember(member);
|
||||
}
|
||||
}
|
||||
|
||||
unionMemberList.add(member);
|
||||
member.parent = this;
|
||||
((Union) memberDataType).add(member.memberDataType, member.memberName, null);
|
||||
if (isBitFieldUnion) {
|
||||
bitFieldUnionLength += member.memberLength;
|
||||
}
|
||||
if (parent != null) {
|
||||
parent.sizeChanged(this);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// find relevant union member for structure conversion
|
||||
for (CompositeMember unionMember : unionMemberList) {
|
||||
if ((member.isBitFieldMember() && unionMember.isCompanionBitField(member)) ||
|
||||
(!member.isBitFieldMember() &&
|
||||
member.memberOffset >= (unionMember.memberOffset + unionMember.getLength()))) {
|
||||
// NOTE: Placement is rather speculative - assume structure is required
|
||||
// TODO: watch out for nested union
|
||||
member.memberOffset -= unionMember.memberOffset;
|
||||
return unionMember.addMember(member);
|
||||
}
|
||||
}
|
||||
|
||||
CompositeMember lastUnionMember = unionMemberList.get(unionMemberList.size() - 1);
|
||||
// NOTE: union must be forced into structure transformation
|
||||
if (lastUnionMember.isUnionContainer()) {
|
||||
if (!lastUnionMember.transformIntoStructureContainer()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return lastUnionMember.addMember(member);
|
||||
}
|
||||
|
||||
private boolean isCompanionBitField(CompositeMember member) {
|
||||
if (!member.isBitFieldMember()) {
|
||||
return false;
|
||||
}
|
||||
if (isContainer()) {
|
||||
if (isBitFieldUnion) {
|
||||
if (unionMemberList.size() == 0 || member.memberOffset != 0) {
|
||||
return false;
|
||||
}
|
||||
if (!SystemUtilities.isEqual(unionMemberList.get(0).memberDataTypeName,
|
||||
member.memberDataTypeName)) {
|
||||
return false;
|
||||
}
|
||||
int combinedBitfieldLength = bitFieldUnionLength + member.memberLength;
|
||||
if (combinedBitfieldLength > (member.getDataType().getLength() * 8)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//return member.memberOffset < getLength();
|
||||
return false;
|
||||
}
|
||||
if (!isBitFieldMember()) {
|
||||
return false;
|
||||
}
|
||||
if (memberOffset != member.memberOffset) {
|
||||
return false;
|
||||
}
|
||||
return SystemUtilities.isEqual(memberDataTypeName, member.memberDataTypeName);
|
||||
}
|
||||
|
||||
private void sizeChanged(CompositeMember pdbMember) {
|
||||
if (structureMemberRangeMap != null) {
|
||||
structureMemberRangeMap.paintRange(pdbMember.memberOffset,
|
||||
pdbMember.memberOffset + pdbMember.getLength() - 1, pdbMember.memberOffset);
|
||||
}
|
||||
if (parent != null) {
|
||||
parent.sizeChanged(this);
|
||||
}
|
||||
}
|
||||
|
||||
private void memberChanged(String fieldName, CompositeMember newMember) {
|
||||
if (isUnionContainer()) {
|
||||
Union union = (Union) memberDataType;
|
||||
int count = union.getNumComponents();
|
||||
for (int i = 0; i < count; i++) {
|
||||
DataTypeComponent component = union.getComponent(i);
|
||||
if (fieldName.equals(component.getFieldName())) {
|
||||
union.delete(i);
|
||||
union.insert(i, newMember.getDataType(), newMember.getLength(),
|
||||
newMember.memberName, null);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (isStructureContainer()) {
|
||||
Structure struct = (Structure) memberDataType;
|
||||
struct.replaceAtOffset(newMember.getOffset(), newMember.getDataType(),
|
||||
newMember.getLength(), newMember.getName(), null);
|
||||
}
|
||||
}
|
||||
|
||||
private void memberNameChanged(String oldFieldName, String newFieldName) {
|
||||
if (isContainer()) {
|
||||
Composite composite = (Composite) memberDataType;
|
||||
int count = composite.getNumComponents();
|
||||
for (int i = 0; i < count; i++) {
|
||||
DataTypeComponent component = composite.getComponent(i);
|
||||
if (oldFieldName.equals(component.getFieldName())) {
|
||||
try {
|
||||
component.setFieldName(newFieldName);
|
||||
}
|
||||
catch (DuplicateNameException e) {
|
||||
Msg.error(this, "Failed to rename temporary component name: " +
|
||||
getDataTypeName() + "." + oldFieldName + " -> " + newFieldName);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int getOrdinal(String fieldName) throws NotFoundException {
|
||||
if (!isContainer()) {
|
||||
throw new AssertException();
|
||||
}
|
||||
Composite composite = (Composite) memberDataType;
|
||||
int count = composite.getNumComponents();
|
||||
for (int i = 0; i < count; i++) {
|
||||
DataTypeComponent component = composite.getComponent(i);
|
||||
if (fieldName.equals(component.getFieldName())) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
private boolean addMember(CompositeMember member) {
|
||||
|
||||
if (member.memberDataType == null || member.memberDataType.getLength() <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isContainer()) {
|
||||
if (member.memberOffset != 0) {
|
||||
if (!transformIntoStructureContainer()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!transformIntoUnionContainer()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isUnionContainer()) {
|
||||
return addUnionMember(member);
|
||||
}
|
||||
return addStructureMember(member);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method facilitates the removal and collection of all siblings of this
|
||||
* member from its parent container. Only those siblings whose offset is greater
|
||||
* than this member's offset will be included. The use of this method is necessary when
|
||||
* a member sequence has been added to a structure container and it is later decided to
|
||||
* push this member and its siblings into a new sub-composite. Before they can be
|
||||
* added to the new container they must be removed from their current container
|
||||
* using this method.
|
||||
* @return list of sibling structure members removed from parent
|
||||
*/
|
||||
private List<CompositeMember> kidnapElderSiblingsFromParentStructure() {
|
||||
|
||||
List<CompositeMember> list = new ArrayList<>();
|
||||
if (parent == null || !parent.isStructureContainer()) {
|
||||
return list;
|
||||
}
|
||||
|
||||
Structure parentStruct = (Structure) parent.memberDataType;
|
||||
|
||||
for (DataTypeComponent component : parentStruct.getComponents()) {
|
||||
if (component.getOffset() > memberOffset) {
|
||||
parentStruct.clearComponent(component.getOrdinal());
|
||||
CompositeMember member =
|
||||
parent.structureMemberOffsetMap.remove(component.getOffset());
|
||||
// could be a padding undefined that was never added to the structureMemberOffsetMap
|
||||
if (member != null) {
|
||||
list.add(member);
|
||||
}
|
||||
else if (component.getDataType() != DataType.DEFAULT) {
|
||||
// exceptions are unexpected
|
||||
throw new AssertException("Data Type component parsing issues " +
|
||||
parentStruct.getName() + " kidnapping " + component.getFieldName());
|
||||
}
|
||||
}
|
||||
}
|
||||
parent.structureMemberRangeMap.paintRange(memberOffset + getLength(), parent.getLength(),
|
||||
-1);
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Buildup an empty composite by applying datatype composite members defined as
|
||||
* children of an PDB XML class or datatype node. Only those children with a kind of
|
||||
* "Member" will be processed.
|
||||
* @param pdbParser PDB parser object
|
||||
* @param composite empty composite to which members will be added
|
||||
* @param preferredCompositeSize preferred size of composite, <= 0 indicates unknown
|
||||
* @param compositeNode PDB XML class or datatype node whose children will be processed
|
||||
* @param monitor task monitor
|
||||
* @return true if members successfully added to composite
|
||||
* @throws CancelledException if monitor is cancelled
|
||||
*/
|
||||
static boolean applyDataTypeMembers(PdbParserNEW pdbParser, Composite composite,
|
||||
int preferredCompositeSize, XmlTreeNode compositeNode, TaskMonitor monitor)
|
||||
throws CancelledException {
|
||||
|
||||
Composite editComposite = composite;
|
||||
|
||||
CompositeMember rootMember = new CompositeMember(
|
||||
member -> member.isContainer() ? new WrappedDataType(editComposite, false)
|
||||
: pdbParser.findDataType(member.getDataTypeName(), monitor),
|
||||
pdbParser.getProgramDataTypeManager());
|
||||
|
||||
Iterator<XmlTreeNode> children = compositeNode.getChildren();
|
||||
while (children.hasNext()) {
|
||||
monitor.checkCanceled();
|
||||
XmlTreeNode child = children.next();
|
||||
PdbMember member = new PdbMember(child, monitor);
|
||||
if (member.memberKind.equals("Member")) {
|
||||
if (!rootMember.addMember(member, monitor)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rootMember.finalizeDataType(preferredCompositeSize);
|
||||
return true;
|
||||
}
|
||||
|
||||
abstract boolean addToStructure(DefaultCompositeMember structure);
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,111 @@
|
|||
/* ###
|
||||
* 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.util.bin.format.pdb;
|
||||
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.InvalidDataTypeException;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.NumericUtilities;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
|
||||
/**
|
||||
* <code>PdbMember</code> convey PDB member information used for datatype
|
||||
* reconstruction. The <i>memberDataTypeName</i> is expected to include
|
||||
* namespace prefixes when relevant. When representing bitfields the
|
||||
* <i>memberName</i> is used to convey bit-size and bit-offset information
|
||||
* (e.g., fieldname:SSSS[:XXXX] where SSSS corresponds to the bit-size
|
||||
* and XXXX corresponds to an optional bit-offset).
|
||||
*/
|
||||
public class DefaultPdbMember extends PdbMember {
|
||||
|
||||
private final String name;
|
||||
|
||||
private boolean isBitField;
|
||||
private int bitFieldSize = -1;
|
||||
private int bitFieldOffset = -1;
|
||||
|
||||
private final PdbDataTypeParser dataTypeParser;
|
||||
|
||||
/**
|
||||
* Default PDB member construction
|
||||
* @param name member field name. For bitfields this also conveys the bit-size
|
||||
* and optionally the bit-offset.
|
||||
* @param dataTypeName field datatype or the base datatype associated with a bitfield
|
||||
* @param offset
|
||||
* @param dataTypeParser
|
||||
*/
|
||||
DefaultPdbMember(String name, String dataTypeName, int offset,
|
||||
PdbDataTypeParser dataTypeParser) {
|
||||
super(getMemberName(name), dataTypeName, offset);
|
||||
this.name = name;
|
||||
parseBitField();
|
||||
this.dataTypeParser = dataTypeParser;
|
||||
}
|
||||
|
||||
private static String getMemberName(String name) {
|
||||
int bitFieldColonIndex = name != null ? name.indexOf(':') : -1;
|
||||
if (bitFieldColonIndex >= 0) {
|
||||
return name.substring(0, bitFieldColonIndex);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected WrappedDataType getDataType() throws CancelledException {
|
||||
WrappedDataType wrappedDt = dataTypeParser.findDataType(getDataTypeName());
|
||||
if (wrappedDt != null && isBitField) {
|
||||
if (wrappedDt.isZeroLengthArray()) {
|
||||
return null;
|
||||
}
|
||||
PdbBitField bitFieldDt;
|
||||
try {
|
||||
DataType baseDataType =
|
||||
wrappedDt.getDataType().clone(dataTypeParser.getProgramDataTypeManager());
|
||||
bitFieldDt = new PdbBitField(baseDataType, bitFieldSize, bitFieldOffset);
|
||||
}
|
||||
catch (InvalidDataTypeException e) {
|
||||
Msg.error(this, "PDB parse error: " + e.getMessage());
|
||||
return null;
|
||||
}
|
||||
wrappedDt = new WrappedDataType(bitFieldDt, false);
|
||||
}
|
||||
return wrappedDt;
|
||||
}
|
||||
|
||||
private void parseBitField() {
|
||||
int bitFieldColonIndex = name != null ? name.indexOf(':') : -1;
|
||||
if (bitFieldColonIndex >= 0) {
|
||||
|
||||
isBitField = true;
|
||||
|
||||
String bitSizeOffsetStr = name.substring(bitFieldColonIndex + 1);
|
||||
|
||||
try {
|
||||
int colonIndex = bitSizeOffsetStr.indexOf(':');
|
||||
if (colonIndex > 0) {
|
||||
bitFieldOffset = (int) NumericUtilities.parseNumber(
|
||||
bitSizeOffsetStr.substring(colonIndex + 1));
|
||||
bitSizeOffsetStr = bitSizeOffsetStr.substring(0, colonIndex);
|
||||
}
|
||||
bitFieldSize = (int) NumericUtilities.parseNumber(bitSizeOffsetStr);
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
/* ###
|
||||
* 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.util.bin.format.pdb;
|
||||
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.exception.AssertException;
|
||||
|
||||
/**
|
||||
* <code>PdbBitField</code> provides ability to hang onto bitfield as a datatype.
|
||||
* This will be transformed to a normal BitFieldDataType when cloned.
|
||||
*/
|
||||
class PdbBitField extends BitFieldDataType {
|
||||
|
||||
private int bitOffsetWithinBaseType;
|
||||
|
||||
// TODO: add support for big-endian
|
||||
|
||||
/**
|
||||
* Construct a PDB bitfield (not intended for direct use by DataTypeManager)
|
||||
* @param baseDataType fielfield base datatype cloned for target datatype manager
|
||||
* @param bitSize bitfield size in bits
|
||||
* @param bitOffsetWithinBaseType bit offset within baseDataType or -1 if unknown
|
||||
* @throws InvalidDataTypeException if invalid bitfield parameters are specified
|
||||
*/
|
||||
protected PdbBitField(DataType baseDataType, int bitSize, int bitOffsetWithinBaseType)
|
||||
throws InvalidDataTypeException {
|
||||
super(baseDataType, bitSize,
|
||||
getMinimalBitOffset(baseDataType, bitSize, bitOffsetWithinBaseType), 0);
|
||||
if (bitSize < 1) {
|
||||
throw new InvalidDataTypeException("invalid PDB bit size: " + bitSize);
|
||||
}
|
||||
if (bitOffsetWithinBaseType < -1) {
|
||||
throw new InvalidDataTypeException(
|
||||
"invalid PDB bit offset: " + bitOffsetWithinBaseType);
|
||||
}
|
||||
this.bitOffsetWithinBaseType = bitOffsetWithinBaseType;
|
||||
}
|
||||
|
||||
private static int getMinimalBitOffset(DataType baseDataType, int bitSize,
|
||||
int bitOffsetWithinBaseType) {
|
||||
if (bitOffsetWithinBaseType < 0) {
|
||||
return 0;
|
||||
}
|
||||
// assumes little endian packing (lsb first)
|
||||
return bitOffsetWithinBaseType % 8;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the bit offset within the full base type
|
||||
* @return base type bit offset or -1 if unknown
|
||||
*/
|
||||
public int getBitOffsetWithinBase() {
|
||||
return bitOffsetWithinBaseType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BitFieldDataType clone(DataTypeManager dtm) {
|
||||
if (dtm != getDataTypeManager()) {
|
||||
throw new AssertException("unsupported clone operation");
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getDisplayName() + "(baseSize:" + getBaseTypeSize() + ",bitOffsetInBase:" +
|
||||
bitOffsetWithinBaseType + ")";
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,321 @@
|
|||
/* ###
|
||||
* 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.util.bin.format.pdb;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import ghidra.app.services.DataTypeManagerService;
|
||||
import ghidra.program.database.data.DataTypeUtilities;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
class PdbDataTypeParser {
|
||||
|
||||
private final static String NO_TYPE = "NoType";
|
||||
|
||||
private DataTypeManager programDataTypeMgr;
|
||||
private DataTypeManagerService service;
|
||||
private TaskMonitor monitor;
|
||||
|
||||
private Map<String, DataType> dataTypeCache = new HashMap<>();
|
||||
|
||||
PdbDataTypeParser(DataTypeManager programDataTypeMgr, DataTypeManagerService service,
|
||||
TaskMonitor monitor) {
|
||||
this.programDataTypeMgr = programDataTypeMgr;
|
||||
this.service = service;
|
||||
this.monitor = monitor;
|
||||
createMandatoryDataTypes();
|
||||
}
|
||||
|
||||
private void createMandatoryDataTypes() {
|
||||
|
||||
addDataType(new TypedefDataType("wchar", WideCharDataType.dataType));
|
||||
|
||||
addDataType(new TypedefDataType("__int8",
|
||||
AbstractIntegerDataType.getSignedDataType(1, programDataTypeMgr)));
|
||||
addDataType(new TypedefDataType("__uint8",
|
||||
AbstractIntegerDataType.getUnsignedDataType(1, programDataTypeMgr)));
|
||||
|
||||
addDataType(new TypedefDataType("__int16",
|
||||
AbstractIntegerDataType.getSignedDataType(2, programDataTypeMgr)));
|
||||
addDataType(new TypedefDataType("__uint16",
|
||||
AbstractIntegerDataType.getUnsignedDataType(2, programDataTypeMgr)));
|
||||
|
||||
addDataType(new TypedefDataType("__int32",
|
||||
AbstractIntegerDataType.getSignedDataType(4, programDataTypeMgr)));
|
||||
addDataType(new TypedefDataType("__uint32",
|
||||
AbstractIntegerDataType.getUnsignedDataType(2, programDataTypeMgr)));
|
||||
|
||||
addDataType(new TypedefDataType("__int64",
|
||||
AbstractIntegerDataType.getSignedDataType(8, programDataTypeMgr)));
|
||||
addDataType(new TypedefDataType("__uint64",
|
||||
AbstractIntegerDataType.getUnsignedDataType(8, programDataTypeMgr)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the target program's datatype manager
|
||||
* @return program's datatype manager
|
||||
*/
|
||||
public DataTypeManager getProgramDataTypeManager() {
|
||||
return programDataTypeMgr;
|
||||
}
|
||||
|
||||
void flushDataTypeCache() {
|
||||
for (DataType dt : dataTypeCache.values()) {
|
||||
programDataTypeMgr.resolve(dt,
|
||||
DataTypeConflictHandler.REPLACE_EMPTY_STRUCTS_OR_RENAME_AND_ADD_HANDLER);
|
||||
}
|
||||
dataTypeCache.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the data type managers are used in a particular order.
|
||||
* The order is as follows:
|
||||
* 1) the program's data type manager
|
||||
* 2) the built-in data type manager
|
||||
* 3) the open data type archives
|
||||
*/
|
||||
private class PdbDataTypeManagerComparator implements Comparator<DataTypeManager> {
|
||||
@Override
|
||||
public int compare(DataTypeManager dtm1, DataTypeManager dtm2) {
|
||||
if (dtm1 == programDataTypeMgr) {
|
||||
return -1;
|
||||
}
|
||||
if (dtm2 == programDataTypeMgr) {
|
||||
return 1;
|
||||
}
|
||||
if (dtm1 instanceof BuiltInDataTypeManager) {
|
||||
return -1;
|
||||
}
|
||||
if (dtm2 instanceof BuiltInDataTypeManager) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void clear() {
|
||||
dataTypeCache.clear();
|
||||
}
|
||||
|
||||
DataType getCachedDataType(String key) {
|
||||
return dataTypeCache.get(key);
|
||||
}
|
||||
|
||||
void cacheDataType(String key, DataType dataType) {
|
||||
dataTypeCache.put(key, dataType);
|
||||
}
|
||||
|
||||
void addDataType(DataType dataType) {
|
||||
|
||||
if (dataType instanceof Composite) {
|
||||
DataTypeComponent[] components = ((Composite) dataType).getComponents();
|
||||
for (DataTypeComponent component : components) {
|
||||
addDataType(component.getDataType());
|
||||
}
|
||||
}
|
||||
|
||||
ArrayList<DataType> oldDataTypeList = new ArrayList<>();
|
||||
programDataTypeMgr.findDataTypes(dataType.getName(), oldDataTypeList);
|
||||
dataType = programDataTypeMgr.addDataType(dataType,
|
||||
DataTypeConflictHandler.REPLACE_EMPTY_STRUCTS_OR_RENAME_AND_ADD_HANDLER);
|
||||
|
||||
cacheDataType(dataType.getName(), dataType);
|
||||
|
||||
for (DataType oldDataType : oldDataTypeList) {
|
||||
if (oldDataType.getLength() == 0 &&
|
||||
oldDataType.getClass().equals(dataType.getClass())) {
|
||||
try {
|
||||
programDataTypeMgr.replaceDataType(oldDataType, dataType, false);
|
||||
}
|
||||
catch (DataTypeDependencyException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private DataType findDataTypeInArchives(String datatype, TaskMonitor monitor)
|
||||
throws CancelledException {
|
||||
|
||||
DataTypeManager[] managers = service.getDataTypeManagers();
|
||||
Arrays.sort(managers, new PdbDataTypeManagerComparator());
|
||||
for (DataTypeManager manager : managers) {
|
||||
if (monitor.isCancelled()) {
|
||||
throw new CancelledException();
|
||||
}
|
||||
DataType dt = DataTypeUtilities.findNamespaceQualifiedDataType(manager, datatype, null);
|
||||
if (dt != null) {
|
||||
cacheDataType(datatype, dt);
|
||||
return dt;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private DataType findBaseDataType(String dataTypeName, TaskMonitor monitor)
|
||||
throws CancelledException {
|
||||
DataType dt = getCachedDataType(dataTypeName);
|
||||
if (dt != null) {
|
||||
return dt;
|
||||
}
|
||||
|
||||
// PDP category does not apply to built-ins which always live at the root
|
||||
|
||||
BuiltInDataTypeManager builtInDTM = BuiltInDataTypeManager.getDataTypeManager();
|
||||
dt = builtInDTM.getDataType(new DataTypePath(CategoryPath.ROOT, dataTypeName));
|
||||
if (dt == null) {
|
||||
dt = findDataTypeInArchives(dataTypeName, monitor);
|
||||
}
|
||||
return dt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a data-type by name in a case-sensitive manner.
|
||||
* @param monitor task monitor
|
||||
* @param dataTypeName data-type name (may be qualified by its namespace)
|
||||
* @return wrapped data-type or null if not found.
|
||||
* @throws CancelledException if operation is cancelled
|
||||
*/
|
||||
public WrappedDataType findDataType(String datatype) throws CancelledException {
|
||||
|
||||
// NOTE: previous case-insensitive search was removed since type names
|
||||
// should be case-sensitive
|
||||
datatype = datatype.trim();
|
||||
|
||||
if (datatype == null || datatype.length() == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (NO_TYPE.equals(datatype)) {
|
||||
return new WrappedDataType(VoidDataType.dataType, false); //TODO make it void?
|
||||
}
|
||||
|
||||
String dataTypeName = datatype;
|
||||
|
||||
// Example type representations:
|
||||
// char *[2][3] pointer(array(array(char,3),2))
|
||||
// char *[2][3] * pointer(array(array(pointer(char),3),2))
|
||||
// char [0][2][3] * array(array(array(pointer(char),3),2),0)
|
||||
// char [2][3] * array(array(pointer(char),3),2)
|
||||
|
||||
int basePointerDepth = 0;
|
||||
while (dataTypeName.endsWith("*")) {
|
||||
++basePointerDepth;
|
||||
dataTypeName = dataTypeName.substring(0, dataTypeName.length() - 1).trim();
|
||||
}
|
||||
|
||||
boolean isZeroLengthArray = false;
|
||||
List<Integer> arrayDimensions = null;
|
||||
if (dataTypeName.endsWith("]")) {
|
||||
arrayDimensions = new ArrayList<>();
|
||||
dataTypeName = parseArrayDimensions(dataTypeName, arrayDimensions);
|
||||
if (dataTypeName == null) {
|
||||
Msg.error(this, "Failed to parse array dimensions: " + datatype);
|
||||
return null;
|
||||
}
|
||||
isZeroLengthArray = (arrayDimensions.get(arrayDimensions.size() - 1) == 0);
|
||||
}
|
||||
|
||||
int pointerDepth = 0;
|
||||
if (arrayDimensions != null) {
|
||||
while (dataTypeName.endsWith("*")) {
|
||||
++pointerDepth;
|
||||
dataTypeName = dataTypeName.substring(0, dataTypeName.length() - 1).trim();
|
||||
}
|
||||
if (pointerDepth != 0 && isZeroLengthArray) {
|
||||
Msg.error(this, "Unsupported pointer to zero-length array: " + datatype);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Find base data-type (name may include namespace, e.g., Foo::MyType)
|
||||
// Primary cache (dataTypeCache) may contain namespace qualified data type
|
||||
|
||||
DataType dt = findBaseDataType(dataTypeName, monitor);
|
||||
if (dt == null) {
|
||||
return null; // base type not found
|
||||
}
|
||||
|
||||
while (basePointerDepth-- != 0) {
|
||||
dt = createPointer(dt);
|
||||
}
|
||||
|
||||
if (arrayDimensions != null) {
|
||||
dt = createArray(dt, arrayDimensions);
|
||||
}
|
||||
|
||||
while (pointerDepth-- != 0) {
|
||||
dt = createPointer(dt);
|
||||
}
|
||||
|
||||
return new WrappedDataType(dt, isZeroLengthArray);
|
||||
}
|
||||
|
||||
private String parseArrayDimensions(String datatype, List<Integer> arrayDimensions) {
|
||||
String dataTypeName = datatype;
|
||||
boolean zeroLengthArray = false;
|
||||
while (dataTypeName.endsWith("]")) {
|
||||
if (zeroLengthArray) {
|
||||
return null; // only last dimension may be 0
|
||||
}
|
||||
int rBracketPos = dataTypeName.lastIndexOf(']');
|
||||
int lBracketPos = dataTypeName.lastIndexOf('[');
|
||||
if (lBracketPos < 0) {
|
||||
return null;
|
||||
}
|
||||
int dimension;
|
||||
try {
|
||||
dimension = Integer.parseInt(dataTypeName.substring(lBracketPos + 1, rBracketPos));
|
||||
if (dimension < 0) {
|
||||
return null; // invalid dimension
|
||||
}
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
return null;
|
||||
}
|
||||
dataTypeName = dataTypeName.substring(0, lBracketPos).trim();
|
||||
arrayDimensions.add(dimension);
|
||||
}
|
||||
return dataTypeName;
|
||||
}
|
||||
|
||||
DataType createPointer(DataType dt) {
|
||||
return PointerDataType.getPointer(dt, programDataTypeMgr);
|
||||
}
|
||||
|
||||
private DataType createArray(DataType dt, List<Integer> arrayDimensions) {
|
||||
int dimensionCount = arrayDimensions.size();
|
||||
boolean zeroLengthArray = arrayDimensions.get(arrayDimensions.size() - 1) == 0;
|
||||
if (zeroLengthArray) {
|
||||
--dimensionCount;
|
||||
}
|
||||
for (int i = 0; i < dimensionCount; i++) {
|
||||
int dimension = arrayDimensions.get(i);
|
||||
dt = new ArrayDataType(dt, dimension, dt.getLength(), programDataTypeMgr);
|
||||
}
|
||||
if (zeroLengthArray) {
|
||||
// This should be temporary for supported flex-array cases,
|
||||
// although we do not really support flex-arrays within unions
|
||||
// or in the middle of structures.
|
||||
dt = new ArrayDataType(dt, 1, dt.getLength(), programDataTypeMgr);
|
||||
}
|
||||
return dt;
|
||||
}
|
||||
|
||||
}
|
|
@ -15,31 +15,59 @@
|
|||
*/
|
||||
package ghidra.app.util.bin.format.pdb;
|
||||
|
||||
import ghidra.program.model.symbol.SymbolUtilities;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
import ghidra.util.xml.XmlUtilities;
|
||||
import ghidra.xml.XmlElement;
|
||||
import ghidra.xml.XmlTreeNode;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
|
||||
/**
|
||||
* <code>PdbMember</code> convey PDB member information used for datatype
|
||||
* reconstruction.
|
||||
*/
|
||||
abstract class PdbMember {
|
||||
|
||||
final class PdbMember {
|
||||
final String memberName;
|
||||
final String memberDataTypeName;
|
||||
final int memberOffset;
|
||||
final String memberKind;
|
||||
final int memberLength;
|
||||
|
||||
PdbMember(XmlTreeNode node, TaskMonitor monitor) {
|
||||
this(node.getStartElement(), monitor);
|
||||
protected PdbMember(String memberName, String memberDataTypeName, int memberOffset) {
|
||||
this.memberName = memberName;
|
||||
this.memberDataTypeName = memberDataTypeName;
|
||||
this.memberOffset = memberOffset;
|
||||
}
|
||||
|
||||
PdbMember(XmlElement element, TaskMonitor monitor) {
|
||||
// TODO: Need to examine consistency of renaming names/data types for space removal across
|
||||
// all of PDB.
|
||||
memberName = SymbolUtilities.replaceInvalidChars(element.getAttribute("name"), false);
|
||||
memberDataTypeName = element.getAttribute("datatype");
|
||||
memberOffset = XmlUtilities.parseInt(element.getAttribute("offset"));
|
||||
memberKind = element.getAttribute("kind");
|
||||
memberLength = XmlUtilities.parseInt(element.getAttribute("length"));
|
||||
/**
|
||||
* Get the member's name which will correspond to the field name.
|
||||
* @return member field name
|
||||
*/
|
||||
public String getName() {
|
||||
return memberName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the member's datatype name (may be namespace qualified)
|
||||
* @return member's datatype name
|
||||
*/
|
||||
public String getDataTypeName() {
|
||||
return memberDataTypeName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the member's byte offset within the root composite.
|
||||
* @return member's byte offset
|
||||
*/
|
||||
public int getOffset() {
|
||||
return memberOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this member's associated data type which has already been cloned for the
|
||||
* target program's data type manager. This indicates a dependency callback
|
||||
* and may be used to trigger resolution for composites. When resolving dependencies
|
||||
* care must be take to avoid circular dependencies which could occur under certain
|
||||
* error conditions.
|
||||
* @param member composite member to be resolved
|
||||
* @return data-type which corresponds to the specified member's data-type name or null
|
||||
* if unable to resolve.
|
||||
* @throws CancelledException if operation cancelled
|
||||
*/
|
||||
protected abstract WrappedDataType getDataType() throws CancelledException;
|
||||
|
||||
}
|
||||
|
|
|
@ -30,7 +30,6 @@ import ghidra.app.util.importer.LibrarySearchPathManager;
|
|||
import ghidra.app.util.importer.MessageLog;
|
||||
import ghidra.framework.*;
|
||||
import ghidra.framework.options.Options;
|
||||
import ghidra.program.database.data.DataTypeUtilities;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.listing.*;
|
||||
|
@ -38,9 +37,9 @@ import ghidra.program.model.mem.DumbMemBufferImpl;
|
|||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.SystemUtilities;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.exception.InvalidInputException;
|
||||
import ghidra.util.exception.*;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
import ghidra.util.xml.XmlUtilities;
|
||||
import ghidra.xml.*;
|
||||
|
||||
/**
|
||||
|
@ -55,8 +54,6 @@ public class PdbParserNEW {
|
|||
public final static File SPECIAL_PDB_LOCATION = new File("C:/WINDOWS/Symbols");
|
||||
public final static String PDB_STORAGE_PROPERTY = "PDB Storage Directory";
|
||||
|
||||
private final static String NO_TYPE = "NoType";
|
||||
|
||||
static final String STRUCTURE_KIND = "Structure";
|
||||
static final String UNION_KIND = "Union";
|
||||
|
||||
|
@ -72,13 +69,15 @@ public class PdbParserNEW {
|
|||
}
|
||||
}
|
||||
|
||||
private TaskMonitor monitor;
|
||||
|
||||
private final boolean forceAnalysis;
|
||||
private final File pdbFile;
|
||||
private final boolean isXML;
|
||||
private final Program program;
|
||||
private DataTypeManager dataMgr;
|
||||
private final DataTypeManagerService service;
|
||||
private final PdbProgramAttributes programAttributes;
|
||||
|
||||
private Process process;
|
||||
private XmlPullParser parser;
|
||||
private PdbErrorHandler errHandler;
|
||||
|
@ -93,23 +92,24 @@ public class PdbParserNEW {
|
|||
* by the PDB to be available within the dataTypeCache using namespace-based type
|
||||
* names.
|
||||
*/
|
||||
private Map<String, DataType> dataTypeCache = new HashMap<>();
|
||||
private PdbDataTypeParser dataTypeParser;
|
||||
private Map<SymbolPath, Boolean> namespaceMap = new TreeMap<>(); // false: simple namespace, true: class namespace
|
||||
|
||||
public PdbParserNEW(File pdbFile, Program program, DataTypeManagerService service,
|
||||
boolean forceAnalysis) {
|
||||
this(pdbFile, program, service, getPdbAttributes(program), forceAnalysis);
|
||||
boolean forceAnalysis, TaskMonitor monitor) {
|
||||
this(pdbFile, program, service, getPdbAttributes(program), forceAnalysis, monitor);
|
||||
}
|
||||
|
||||
public PdbParserNEW(File pdbFile, Program program, DataTypeManagerService service,
|
||||
PdbProgramAttributes programAttributes, boolean forceAnalysis) {
|
||||
PdbProgramAttributes programAttributes, boolean forceAnalysis, TaskMonitor monitor) {
|
||||
this.pdbFile = pdbFile;
|
||||
this.categoryPrefix = "/" + pdbFile.getName();
|
||||
this.pdbCategory = new CategoryPath(categoryPrefix);
|
||||
this.program = program;
|
||||
this.dataMgr = program.getDataTypeManager();
|
||||
this.service = service;
|
||||
this.forceAnalysis = forceAnalysis;
|
||||
|
||||
this.monitor = monitor != null ? monitor : TaskMonitor.DUMMY;
|
||||
this.isXML = pdbFile.getAbsolutePath().endsWith(PdbFileType.XML.toString());
|
||||
this.programAttributes = programAttributes;
|
||||
}
|
||||
|
@ -119,7 +119,7 @@ public class PdbParserNEW {
|
|||
* @return data type manager
|
||||
*/
|
||||
DataTypeManager getProgramDataTypeManager() {
|
||||
return program.getDataTypeManager();
|
||||
return dataMgr;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -273,36 +273,33 @@ public class PdbParserNEW {
|
|||
}
|
||||
|
||||
private void completeDefferedTypeParsing(ApplyDataTypes applyDataTypes,
|
||||
ApplyDataTypes applyClasses, ApplyTypeDefs applyTypeDefs, TaskMonitor monitor,
|
||||
MessageLog log) throws CancelledException {
|
||||
ApplyTypeDefs applyTypeDefs, MessageLog log) throws CancelledException {
|
||||
|
||||
defineClasses(monitor, log);
|
||||
|
||||
if (applyDataTypes != null) {
|
||||
applyDataTypes.buildDataTypes(monitor);
|
||||
}
|
||||
if (applyClasses != null) {
|
||||
applyClasses.buildDataTypes(monitor);
|
||||
}
|
||||
|
||||
if (applyTypeDefs != null) {
|
||||
applyTypeDefs.buildTypeDefs(monitor);
|
||||
applyTypeDefs.buildTypeDefs(monitor); // TODO: no dependencies exit on TypeDefs (use single pass)
|
||||
}
|
||||
|
||||
// Ensure that all data types are resolved
|
||||
flushDataTypeCache();
|
||||
if (dataTypeParser != null) {
|
||||
dataTypeParser.flushDataTypeCache();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply PDB debug information to the current program
|
||||
*
|
||||
* @param monitor Monitor used to cancel processing
|
||||
* @param log MessageLog used to record errors
|
||||
* @throws IOException if an error occurs during parsing
|
||||
* @throws PdbException if PDB file has already been loaded
|
||||
* @throws CancelledException if user cancels the current action
|
||||
*/
|
||||
public void applyTo(TaskMonitor monitor, MessageLog log)
|
||||
throws IOException, PdbException, CancelledException {
|
||||
public void applyTo(MessageLog log) throws IOException, PdbException, CancelledException {
|
||||
if (!parsed) {
|
||||
throw new IOException("PDB: parse() must be called before applyTo()");
|
||||
}
|
||||
|
@ -316,10 +313,7 @@ public class PdbParserNEW {
|
|||
Msg.debug(this, "Found PDB for " + program.getName());
|
||||
try {
|
||||
|
||||
PdbUtil.createMandatoryDataTypes(this, monitor);
|
||||
|
||||
ApplyDataTypes applyDataTypes = null;
|
||||
ApplyDataTypes applyClasses = null;
|
||||
ApplyTypeDefs applyTypeDefs = null;
|
||||
|
||||
boolean typesFlushed = false;
|
||||
|
@ -351,10 +345,16 @@ public class PdbParserNEW {
|
|||
ApplyEnums.applyTo(parser, this, monitor, log);
|
||||
}
|
||||
else if (element.getName().equals("datatypes")) {
|
||||
applyDataTypes = new ApplyDataTypes(this, parser, false, monitor, log);
|
||||
if (applyDataTypes == null) {
|
||||
applyDataTypes = new ApplyDataTypes(this, log);
|
||||
}
|
||||
applyDataTypes.preProcessDataTypeList(parser, false, monitor);
|
||||
}
|
||||
else if (element.getName().equals("classes")) {
|
||||
applyClasses = new ApplyDataTypes(this, parser, true, monitor, log);
|
||||
if (applyDataTypes == null) {
|
||||
applyDataTypes = new ApplyDataTypes(this, log);
|
||||
}
|
||||
applyDataTypes.preProcessDataTypeList(parser, true, monitor);
|
||||
}
|
||||
else if (element.getName().equals("typedefs")) {
|
||||
applyTypeDefs = new ApplyTypeDefs(this, parser, monitor, log);
|
||||
|
@ -362,8 +362,7 @@ public class PdbParserNEW {
|
|||
else if (element.getName().equals("functions")) {
|
||||
// apply functions (must occur within XML after all type sections)
|
||||
if (!typesFlushed) {
|
||||
completeDefferedTypeParsing(applyDataTypes, applyClasses, applyTypeDefs,
|
||||
monitor, log);
|
||||
completeDefferedTypeParsing(applyDataTypes, applyTypeDefs, log);
|
||||
typesFlushed = true;
|
||||
}
|
||||
ApplyFunctions.applyTo(this, parser, monitor, log);
|
||||
|
@ -371,8 +370,7 @@ public class PdbParserNEW {
|
|||
else if (element.getName().equals("tables")) {
|
||||
// apply tables (must occur within XML after all other sections)
|
||||
if (!typesFlushed) {
|
||||
completeDefferedTypeParsing(applyDataTypes, applyClasses, applyTypeDefs,
|
||||
monitor, log);
|
||||
completeDefferedTypeParsing(applyDataTypes, applyTypeDefs, log);
|
||||
typesFlushed = true;
|
||||
}
|
||||
ApplyTables.applyTo(this, parser, monitor, log);
|
||||
|
@ -383,8 +381,7 @@ public class PdbParserNEW {
|
|||
}
|
||||
|
||||
if (!typesFlushed) {
|
||||
completeDefferedTypeParsing(applyDataTypes, applyClasses, applyTypeDefs, monitor,
|
||||
log);
|
||||
completeDefferedTypeParsing(applyDataTypes, applyTypeDefs, log);
|
||||
}
|
||||
|
||||
Options options = program.getOptions(Program.PROGRAM_INFO);
|
||||
|
@ -413,15 +410,6 @@ public class PdbParserNEW {
|
|||
}
|
||||
}
|
||||
|
||||
private void flushDataTypeCache() {
|
||||
DataTypeManager dtm = program.getDataTypeManager();
|
||||
for (DataType dt : dataTypeCache.values()) {
|
||||
dtm.resolve(dt,
|
||||
DataTypeConflictHandler.REPLACE_EMPTY_STRUCTS_OR_RENAME_AND_ADD_HANDLER);
|
||||
}
|
||||
dataTypeCache.clear();
|
||||
}
|
||||
|
||||
void predefineClass(String classname) {
|
||||
SymbolPath classPath = new SymbolPath(classname);
|
||||
namespaceMap.put(classPath, true);
|
||||
|
@ -701,47 +689,47 @@ public class PdbParserNEW {
|
|||
}
|
||||
//errHandler = null;
|
||||
//thread = null;
|
||||
dataTypeCache.clear();
|
||||
if (dataTypeParser != null) {
|
||||
dataTypeParser.clear();
|
||||
}
|
||||
}
|
||||
|
||||
boolean isCorrectKind(DataType dt, String kind) {
|
||||
if (STRUCTURE_KIND.equals(kind)) {
|
||||
boolean isCorrectKind(DataType dt, PdbXmlKind kind) {
|
||||
if (kind == PdbXmlKind.STRUCTURE) {
|
||||
return (dt instanceof Structure);
|
||||
}
|
||||
else if (UNION_KIND.equals(kind)) {
|
||||
else if (kind == PdbXmlKind.UNION) {
|
||||
return (dt instanceof Union);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Composite createComposite(String kind, String name) {
|
||||
if (STRUCTURE_KIND.equals(kind)) {
|
||||
Composite createComposite(PdbXmlKind kind, String name) {
|
||||
if (kind == PdbXmlKind.STRUCTURE) {
|
||||
return createStructure(name, 0);
|
||||
}
|
||||
else if (UNION_KIND.equals(kind)) {
|
||||
else if (kind == PdbXmlKind.UNION) {
|
||||
return createUnion(name);
|
||||
}
|
||||
return null;
|
||||
throw new IllegalArgumentException("unsupported kind: " + kind);
|
||||
}
|
||||
|
||||
Structure createStructure(String name, int length) {
|
||||
return new StructureDataType(getCategory(name, true), stripNamespace(name), length,
|
||||
program.getDataTypeManager());
|
||||
dataMgr);
|
||||
}
|
||||
|
||||
Union createUnion(String name) {
|
||||
return new UnionDataType(getCategory(name, true), stripNamespace(name),
|
||||
program.getDataTypeManager());
|
||||
return new UnionDataType(getCategory(name, true), stripNamespace(name), dataMgr);
|
||||
}
|
||||
|
||||
TypedefDataType createTypeDef(String name, DataType baseDataType) {
|
||||
return new TypedefDataType(getCategory(name, true), stripNamespace(name), baseDataType,
|
||||
program.getDataTypeManager());
|
||||
dataMgr);
|
||||
}
|
||||
|
||||
EnumDataType createEnum(String name, int length) {
|
||||
return new EnumDataType(getCategory(name, true), stripNamespace(name), length,
|
||||
program.getDataTypeManager());
|
||||
return new EnumDataType(getCategory(name, true), stripNamespace(name), length, dataMgr);
|
||||
}
|
||||
|
||||
void createString(boolean isUnicode, Address address, MessageLog log, TaskMonitor monitor) {
|
||||
|
@ -751,15 +739,15 @@ public class PdbParserNEW {
|
|||
|
||||
void createData(Address address, String datatype, MessageLog log, TaskMonitor monitor)
|
||||
throws CancelledException {
|
||||
WrappedDataType wrappedDt = findDataType(datatype, monitor);
|
||||
WrappedDataType wrappedDt = getDataTypeParser().findDataType(datatype);
|
||||
if (wrappedDt == null) {
|
||||
log.appendMsg("Error: Failed to resolve datatype " + datatype + " at " + address);
|
||||
}
|
||||
else if (wrappedDt.isZeroLengthArray) {
|
||||
else if (wrappedDt.isZeroLengthArray()) {
|
||||
Msg.debug(this, "Did not apply zero length array data " + datatype + " at " + address);
|
||||
}
|
||||
else {
|
||||
createData(address, wrappedDt.dataType, log, monitor);
|
||||
createData(address, wrappedDt.getDataType(), log, monitor);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -818,15 +806,15 @@ public class PdbParserNEW {
|
|||
return;
|
||||
}
|
||||
}
|
||||
Listing listing = program.getListing();
|
||||
if (existingData == null) {
|
||||
try {
|
||||
program.getListing().clearCodeUnits(address, address.add(dataTypeLength - 1),
|
||||
false);
|
||||
listing.clearCodeUnits(address, address.add(dataTypeLength - 1), false);
|
||||
if (dataType.getLength() == -1) {
|
||||
program.getListing().createData(address, dataType, dataTypeLength);
|
||||
listing.createData(address, dataType, dataTypeLength);
|
||||
}
|
||||
else {
|
||||
program.getListing().createData(address, dataType);
|
||||
listing.createData(address, dataType);
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
|
@ -836,9 +824,8 @@ public class PdbParserNEW {
|
|||
}
|
||||
else if (isDataReplaceable(existingData)) {
|
||||
try {
|
||||
program.getListing().clearCodeUnits(address, address.add(dataTypeLength - 1),
|
||||
false);
|
||||
program.getListing().createData(address, dataType, dataTypeLength);
|
||||
listing.clearCodeUnits(address, address.add(dataTypeLength - 1), false);
|
||||
listing.createData(address, dataType, dataTypeLength);
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.appendMsg("Unable to replace " + dataType.getDisplayName() + " at 0x" +
|
||||
|
@ -960,245 +947,17 @@ public class PdbParserNEW {
|
|||
return false;
|
||||
}
|
||||
|
||||
DataType createPointer(DataType dt) {
|
||||
return PointerDataType.getPointer(dt, program.getDataTypeManager());
|
||||
}
|
||||
// DataType createPointer(DataType dt) {
|
||||
// return PointerDataType.getPointer(dt, program.getDataTypeManager());
|
||||
// }
|
||||
|
||||
/**
|
||||
* Find a data-type by name in a case-sensitive manner.
|
||||
* @param monitor task monitor
|
||||
* @param dataTypeName data-type name (may be qualified by its namespace)
|
||||
* @return wrapped data-type or null if not found.
|
||||
* @throws CancelledException if operation is cancelled
|
||||
*/
|
||||
WrappedDataType findDataType(String datatype, TaskMonitor monitor) throws CancelledException {
|
||||
|
||||
// NOTE: previous case-insensitive search was removed since type names
|
||||
// should be case-sensitive
|
||||
datatype = datatype.trim();
|
||||
|
||||
if (datatype == null || datatype.length() == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (NO_TYPE.equals(datatype)) {
|
||||
return new WrappedDataType(VoidDataType.dataType, false); //TODO make it void?
|
||||
}
|
||||
|
||||
String dataTypeName = datatype;
|
||||
|
||||
// Example type representations:
|
||||
// char *[2][3] pointer(array(array(char,3),2))
|
||||
// char *[2][3] * pointer(array(array(pointer(char),3),2))
|
||||
// char [0][2][3] * array(array(array(pointer(char),3),2),0)
|
||||
// char [2][3] * array(array(pointer(char),3),2)
|
||||
|
||||
int basePointerDepth = 0;
|
||||
while (dataTypeName.endsWith("*")) {
|
||||
++basePointerDepth;
|
||||
dataTypeName = dataTypeName.substring(0, dataTypeName.length() - 1).trim();
|
||||
}
|
||||
|
||||
boolean isZeroLengthArray = false;
|
||||
List<Integer> arrayDimensions = null;
|
||||
if (dataTypeName.endsWith("]")) {
|
||||
arrayDimensions = new ArrayList<>();
|
||||
dataTypeName = parseArrayDimensions(dataTypeName, arrayDimensions);
|
||||
if (dataTypeName == null) {
|
||||
Msg.error(this, "Failed to parse array dimensions: " + datatype);
|
||||
return null;
|
||||
}
|
||||
isZeroLengthArray = (arrayDimensions.get(arrayDimensions.size() - 1) == 0);
|
||||
}
|
||||
|
||||
int pointerDepth = 0;
|
||||
if (arrayDimensions != null) {
|
||||
while (dataTypeName.endsWith("*")) {
|
||||
++pointerDepth;
|
||||
dataTypeName = dataTypeName.substring(0, dataTypeName.length() - 1).trim();
|
||||
}
|
||||
if (pointerDepth != 0 && isZeroLengthArray) {
|
||||
Msg.error(this, "Unsupported pointer to zero-length array: " + datatype);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Find base data-type (name may include namespace, e.g., Foo::MyType)
|
||||
// Primary cache (dataTypeCache) may contain namespace qualified data type
|
||||
|
||||
DataType dt = findBaseDataType(dataTypeName, monitor);
|
||||
if (dt == null) {
|
||||
return null; // base type not found
|
||||
}
|
||||
|
||||
while (basePointerDepth-- != 0) {
|
||||
dt = createPointer(dt);
|
||||
}
|
||||
|
||||
if (arrayDimensions != null) {
|
||||
dt = createArray(dt, arrayDimensions);
|
||||
}
|
||||
|
||||
while (pointerDepth-- != 0) {
|
||||
dt = createPointer(dt);
|
||||
}
|
||||
|
||||
return new WrappedDataType(dt, isZeroLengthArray);
|
||||
}
|
||||
|
||||
private DataType findBaseDataType(String dataTypeName, TaskMonitor monitor)
|
||||
throws CancelledException {
|
||||
DataType dt = getCachedDataType(dataTypeName);
|
||||
if (dt != null) {
|
||||
return dt;
|
||||
}
|
||||
|
||||
// PDP category does not apply to built-ins which always live at the root
|
||||
|
||||
BuiltInDataTypeManager builtInDTM = BuiltInDataTypeManager.getDataTypeManager();
|
||||
dt = builtInDTM.getDataType(new DataTypePath(CategoryPath.ROOT, dataTypeName));
|
||||
if (dt == null) {
|
||||
dt = findDataTypeInArchives(dataTypeName, monitor);
|
||||
}
|
||||
return dt;
|
||||
}
|
||||
|
||||
static class WrappedDataType {
|
||||
final boolean isZeroLengthArray;
|
||||
final DataType dataType;
|
||||
|
||||
WrappedDataType(DataType dataType, boolean isZeroLengthArray) {
|
||||
this.dataType = dataType;
|
||||
this.isZeroLengthArray = isZeroLengthArray;
|
||||
}
|
||||
}
|
||||
|
||||
private DataType createArray(DataType dt, List<Integer> arrayDimensions) {
|
||||
int dimensionCount = arrayDimensions.size();
|
||||
boolean zeroLengthArray = arrayDimensions.get(arrayDimensions.size() - 1) == 0;
|
||||
if (zeroLengthArray) {
|
||||
--dimensionCount;
|
||||
}
|
||||
for (int i = 0; i < dimensionCount; i++) {
|
||||
int dimension = arrayDimensions.get(i);
|
||||
dt = new ArrayDataType(dt, dimension, dt.getLength(), program.getDataTypeManager());
|
||||
}
|
||||
if (zeroLengthArray) {
|
||||
// TODO: improve support for representing zero-length arrays
|
||||
dt = new ArrayDataType(dt, 1, dt.getLength(), program.getDataTypeManager());
|
||||
}
|
||||
return dt;
|
||||
}
|
||||
|
||||
private String parseArrayDimensions(String datatype, List<Integer> arrayDimensions) {
|
||||
String dataTypeName = datatype;
|
||||
boolean zeroLengthArray = false;
|
||||
while (dataTypeName.endsWith("]")) {
|
||||
if (zeroLengthArray) {
|
||||
return null; // only last dimension may be 0
|
||||
}
|
||||
int rBracketPos = dataTypeName.lastIndexOf(']');
|
||||
int lBracketPos = dataTypeName.lastIndexOf('[');
|
||||
if (lBracketPos < 0) {
|
||||
return null;
|
||||
}
|
||||
int dimension;
|
||||
try {
|
||||
dimension = Integer.parseInt(dataTypeName.substring(lBracketPos + 1, rBracketPos));
|
||||
if (dimension < 0) {
|
||||
return null; // invalid dimension
|
||||
}
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
return null;
|
||||
}
|
||||
dataTypeName = dataTypeName.substring(0, lBracketPos).trim();
|
||||
arrayDimensions.add(dimension);
|
||||
}
|
||||
return dataTypeName;
|
||||
}
|
||||
|
||||
private DataType findDataTypeInArchives(String datatype, TaskMonitor monitor)
|
||||
throws CancelledException {
|
||||
|
||||
DataTypeManager[] managers = service.getDataTypeManagers();
|
||||
Arrays.sort(managers, new PdbDataTypeManagerComparator());
|
||||
for (DataTypeManager manager : managers) {
|
||||
if (monitor.isCancelled()) {
|
||||
throw new CancelledException();
|
||||
}
|
||||
DataType dt = DataTypeUtilities.findNamespaceQualifiedDataType(manager, datatype, null);
|
||||
if (dt != null) {
|
||||
cacheDataType(datatype, dt);
|
||||
return dt;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the data type managers are used in a particular order.
|
||||
* The order is as follows:
|
||||
* 1) the program's data type manager
|
||||
* 2) the built-in data type manager
|
||||
* 3) the open data type archives
|
||||
*/
|
||||
private class PdbDataTypeManagerComparator implements Comparator<DataTypeManager> {
|
||||
@Override
|
||||
public int compare(DataTypeManager dtm1, DataTypeManager dtm2) {
|
||||
if (dtm1 == program.getDataTypeManager()) {
|
||||
return -1;
|
||||
}
|
||||
if (dtm2 == program.getDataTypeManager()) {
|
||||
return 1;
|
||||
}
|
||||
if (dtm1 instanceof BuiltInDataTypeManager) {
|
||||
return -1;
|
||||
}
|
||||
if (dtm2 instanceof BuiltInDataTypeManager) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
DataType getCachedDataType(String key) {
|
||||
return dataTypeCache.get(key);
|
||||
}
|
||||
|
||||
void cacheDataType(String key, DataType dataType) {
|
||||
dataTypeCache.put(key, dataType);
|
||||
}
|
||||
|
||||
void addDataType(DataType dataType) {
|
||||
|
||||
if (dataType instanceof Composite) {
|
||||
DataTypeComponent[] components = ((Composite) dataType).getComponents();
|
||||
for (DataTypeComponent component : components) {
|
||||
addDataType(component.getDataType());
|
||||
}
|
||||
}
|
||||
|
||||
DataTypeManager dataTypeMgr = program.getDataTypeManager();
|
||||
ArrayList<DataType> oldDataTypeList = new ArrayList<>();
|
||||
dataTypeMgr.findDataTypes(dataType.getName(), oldDataTypeList);
|
||||
dataType = dataTypeMgr.addDataType(dataType,
|
||||
DataTypeConflictHandler.REPLACE_EMPTY_STRUCTS_OR_RENAME_AND_ADD_HANDLER);
|
||||
|
||||
cacheDataType(dataType.getName(), dataType);
|
||||
|
||||
for (DataType oldDataType : oldDataTypeList) {
|
||||
if (oldDataType.getLength() == 0 &&
|
||||
oldDataType.getClass().equals(dataType.getClass())) {
|
||||
try {
|
||||
dataTypeMgr.replaceDataType(oldDataType, dataType, false);
|
||||
}
|
||||
catch (DataTypeDependencyException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// DataType getCachedDataType(String key) {
|
||||
// return dataTypeCache.get(key);
|
||||
// }
|
||||
//
|
||||
// void cacheDataType(String key, DataType dataType) {
|
||||
// dataTypeCache.put(key, dataType);
|
||||
// }
|
||||
|
||||
/**
|
||||
* Get the PDB root category path
|
||||
|
@ -1540,4 +1299,64 @@ public class PdbParserNEW {
|
|||
return null;
|
||||
}
|
||||
|
||||
PdbDataTypeParser getDataTypeParser() {
|
||||
if (program == null) {
|
||||
throw new AssertException("Parser was not constructed with program");
|
||||
}
|
||||
if (dataTypeParser == null) {
|
||||
dataTypeParser = new PdbDataTypeParser(program.getDataTypeManager(), service, monitor);
|
||||
}
|
||||
return dataTypeParser;
|
||||
}
|
||||
|
||||
void cacheDataType(String name, DataType dataType) {
|
||||
getDataTypeParser().cacheDataType(name, dataType);
|
||||
}
|
||||
|
||||
DataType getCachedDataType(String name) {
|
||||
return getDataTypeParser().getCachedDataType(name);
|
||||
}
|
||||
|
||||
void addDataType(DataType dataType) {
|
||||
getDataTypeParser().addDataType(dataType);
|
||||
}
|
||||
|
||||
WrappedDataType findDataType(String dataTypeName) throws CancelledException {
|
||||
return getDataTypeParser().findDataType(dataTypeName);
|
||||
}
|
||||
|
||||
public PdbMember getPdbXmlMember(XmlTreeNode node) {
|
||||
return new PdbXmlMember(node);
|
||||
}
|
||||
|
||||
public PdbXmlMember getPdbXmlMember(XmlElement element) {
|
||||
return new PdbXmlMember(element);
|
||||
}
|
||||
|
||||
class PdbXmlMember extends DefaultPdbMember {
|
||||
|
||||
final PdbXmlKind kind;
|
||||
|
||||
PdbXmlMember(XmlTreeNode node) {
|
||||
this(node.getStartElement());
|
||||
}
|
||||
|
||||
PdbXmlMember(XmlElement element) {
|
||||
super(SymbolUtilities.replaceInvalidChars(element.getAttribute("name"), false),
|
||||
element.getAttribute("datatype"),
|
||||
XmlUtilities.parseInt(element.getAttribute("offset")), dataTypeParser);
|
||||
kind = PdbXmlKind.parse(element.getAttribute("kind"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Kind of member record. Only those records with a Member kind
|
||||
* are currently considered for inclusion within a composite.
|
||||
* @return PDB kind
|
||||
*/
|
||||
public PdbXmlKind getKind() {
|
||||
return kind;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,13 +18,12 @@ package ghidra.app.util.bin.format.pdb;
|
|||
import ghidra.app.cmd.comments.SetCommentsCmd;
|
||||
import ghidra.app.util.PseudoDisassembler;
|
||||
import ghidra.app.util.PseudoInstruction;
|
||||
import ghidra.app.util.importer.MessageLog;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.data.Composite;
|
||||
import ghidra.program.model.data.Structure;
|
||||
import ghidra.program.model.listing.CodeUnit;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.util.Conv;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
final class PdbUtil {
|
||||
|
||||
|
@ -95,31 +94,31 @@ final class PdbUtil {
|
|||
return false;
|
||||
}
|
||||
|
||||
final static void ensureSize(int expectedLength, Composite composite, MessageLog log) {
|
||||
int actualLength = composite.getLength();
|
||||
if (actualLength < expectedLength) {
|
||||
|
||||
composite.setInternallyAligned(false);
|
||||
if (composite instanceof Structure) {
|
||||
Structure struct = (Structure) composite;
|
||||
// if this is an empty structure, the structure will lie to us
|
||||
// and say it has one element so add 1 to growth factor
|
||||
struct.growStructure(
|
||||
expectedLength - actualLength + (struct.isNotYetDefined() ? 1 : 0));
|
||||
}
|
||||
// must be a union data type
|
||||
else {
|
||||
DataType datatype = new ArrayDataType(DataType.DEFAULT, expectedLength,
|
||||
DataType.DEFAULT.getLength());
|
||||
composite.add(datatype);
|
||||
}
|
||||
}
|
||||
else if (actualLength > expectedLength) {
|
||||
log.appendMsg("Warning: Composite data type generated from PDB has size mismatch. " +
|
||||
composite.getName() + ": expected 0x" + Integer.toHexString(expectedLength) +
|
||||
", but was 0x" + Integer.toHexString(actualLength));
|
||||
}
|
||||
}
|
||||
// final static void ensureSize(int expectedLength, Composite composite, MessageLog log) {
|
||||
// int actualLength = composite.getLength();
|
||||
// if (actualLength < expectedLength) {
|
||||
//
|
||||
// composite.setInternallyAligned(false);
|
||||
// if (composite instanceof Structure) {
|
||||
// Structure struct = (Structure) composite;
|
||||
// // if this is an empty structure, the structure will lie to us
|
||||
// // and say it has one element so add 1 to growth factor
|
||||
// struct.growStructure(
|
||||
// expectedLength - actualLength + (struct.isNotYetDefined() ? 1 : 0));
|
||||
// }
|
||||
// // must be a union data type
|
||||
// else {
|
||||
// DataType datatype = new ArrayDataType(DataType.DEFAULT, expectedLength,
|
||||
// DataType.DEFAULT.getLength());
|
||||
// composite.add(datatype);
|
||||
// }
|
||||
// }
|
||||
// else if (actualLength > expectedLength) {
|
||||
// log.appendMsg("Warning: Composite data type generated from PDB has size mismatch. " +
|
||||
// composite.getName() + ": expected 0x" + Integer.toHexString(expectedLength) +
|
||||
// ", but was 0x" + Integer.toHexString(actualLength));
|
||||
// }
|
||||
// }
|
||||
|
||||
final static void clearComponents(Composite composite) {
|
||||
if (composite instanceof Structure) {
|
||||
|
@ -160,31 +159,4 @@ final class PdbUtil {
|
|||
return pass + "th pass";
|
||||
}
|
||||
|
||||
final static void createMandatoryDataTypes(PdbParserNEW parser, TaskMonitor monitor) {
|
||||
|
||||
DataTypeManager dtm = parser.getProgramDataTypeManager();
|
||||
|
||||
parser.addDataType(new TypedefDataType("wchar", WideCharDataType.dataType));
|
||||
|
||||
parser.addDataType(
|
||||
new TypedefDataType("__int8", AbstractIntegerDataType.getSignedDataType(1, dtm)));
|
||||
parser.addDataType(
|
||||
new TypedefDataType("__uint8", AbstractIntegerDataType.getUnsignedDataType(1, dtm)));
|
||||
|
||||
parser.addDataType(
|
||||
new TypedefDataType("__int16", AbstractIntegerDataType.getSignedDataType(2, dtm)));
|
||||
parser.addDataType(
|
||||
new TypedefDataType("__uint16", AbstractIntegerDataType.getUnsignedDataType(2, dtm)));
|
||||
|
||||
parser.addDataType(
|
||||
new TypedefDataType("__int32", AbstractIntegerDataType.getSignedDataType(4, dtm)));
|
||||
parser.addDataType(
|
||||
new TypedefDataType("__uint32", AbstractIntegerDataType.getUnsignedDataType(2, dtm)));
|
||||
|
||||
parser.addDataType(
|
||||
new TypedefDataType("__int64", AbstractIntegerDataType.getSignedDataType(8, dtm)));
|
||||
parser.addDataType(
|
||||
new TypedefDataType("__uint64", AbstractIntegerDataType.getUnsignedDataType(8, dtm)));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
/* ###
|
||||
* 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.util.bin.format.pdb;
|
||||
|
||||
public enum PdbXmlKind {
|
||||
|
||||
//@formatter:off
|
||||
STRUCTURE,
|
||||
UNION,
|
||||
MEMBER,
|
||||
STATIC_LOCAL,
|
||||
OBJECT_POINTER,
|
||||
PARAMETER,
|
||||
LOCAL,
|
||||
UNKNOWN;
|
||||
//@formatter:on
|
||||
|
||||
private final String camelName;
|
||||
|
||||
private PdbXmlKind() {
|
||||
camelName = toCamel(name());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name in camel form
|
||||
* @return name in camel form
|
||||
*/
|
||||
public String getCamelName() {
|
||||
return camelName;
|
||||
}
|
||||
|
||||
private static String toCamel(String name) {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
boolean makeUpper = true;
|
||||
for (char c : name.toCharArray()) {
|
||||
if (c == '_') {
|
||||
makeUpper = true;
|
||||
continue;
|
||||
}
|
||||
if (makeUpper) {
|
||||
c = Character.toUpperCase(c);
|
||||
}
|
||||
buf.append(c);
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse case-insensitive kind string and return corresponding PdbKind.
|
||||
* It is expected that kind strings will be camel notation (e.g., OBJECT_POINTER
|
||||
* kind string would be ObjectPointer).
|
||||
* If not identified UNKNOWN will be returned.
|
||||
* @param kind kind string (underscores not permitted)
|
||||
* @return PdbKind
|
||||
*/
|
||||
public static PdbXmlKind parse(String kind) {
|
||||
for (PdbXmlKind pdbKind : values()) {
|
||||
if (pdbKind.camelName.equalsIgnoreCase(kind)) {
|
||||
return pdbKind;
|
||||
}
|
||||
}
|
||||
return UNKNOWN;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
/* ###
|
||||
* 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.util.bin.format.pdb;
|
||||
|
||||
import ghidra.program.model.data.DataType;
|
||||
|
||||
/**
|
||||
* <code>WrappedDataType</code> provide the ability to wrap
|
||||
* a {@link DataType} with additional information not conveyed
|
||||
* by the datatype on its' own.
|
||||
* <P>
|
||||
* Note that a BitFieldDataType instance may be specified as the datatype
|
||||
* in order to convey bitfield related information.
|
||||
*/
|
||||
public class WrappedDataType {
|
||||
|
||||
private final boolean isZeroLengthArray;
|
||||
private final DataType dataType;
|
||||
|
||||
/**
|
||||
* Constructed wrapped datatype
|
||||
* @param dataType datatype
|
||||
* @param isZeroLengthArray true if datatype corresponds to a zero-length
|
||||
* array which can not directly be represented as an Array datatype,
|
||||
* else false for all other cases.
|
||||
*/
|
||||
protected WrappedDataType(DataType dataType, boolean isZeroLengthArray) {
|
||||
this.dataType = dataType;
|
||||
this.isZeroLengthArray = isZeroLengthArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return datatype
|
||||
*/
|
||||
public DataType getDataType() {
|
||||
return dataType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if datatype corresponds to a zero-length array
|
||||
* which can not directly be represented as an Array datatype,
|
||||
* else false for all other cases.
|
||||
*/
|
||||
public boolean isZeroLengthArray() {
|
||||
return isZeroLengthArray;
|
||||
}
|
||||
}
|
|
@ -15,11 +15,13 @@
|
|||
*/
|
||||
package pdb;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
import docking.DockingWindowManager;
|
||||
import docking.widgets.dialogs.MultiLineMessageDialog;
|
||||
import ghidra.app.plugin.core.analysis.*;
|
||||
import ghidra.app.services.DataTypeManagerService;
|
||||
import ghidra.app.util.bin.format.pdb.PdbException;
|
||||
import ghidra.app.util.bin.format.pdb.PdbParserNEW;
|
||||
import ghidra.app.util.importer.MessageLog;
|
||||
|
@ -32,13 +34,15 @@ import ghidra.util.task.Task;
|
|||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
class LoadPdbTask extends Task {
|
||||
private PdbParserNEW parser;
|
||||
private File pdbFile;
|
||||
private DataTypeManagerService service;
|
||||
private final Program program;
|
||||
|
||||
LoadPdbTask(Program program, PdbParserNEW parser) {
|
||||
LoadPdbTask(Program program, File pdbFile, DataTypeManagerService service) {
|
||||
super("Loading PDB...", true, false, false);
|
||||
this.program = program;
|
||||
this.parser = parser;
|
||||
this.pdbFile = pdbFile;
|
||||
this.service = service;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -56,9 +60,12 @@ class LoadPdbTask extends Task {
|
|||
public boolean analysisWorkerCallback(Program currentProgram, Object workerContext,
|
||||
TaskMonitor currentMonitor) throws Exception, CancelledException, PdbException {
|
||||
|
||||
PdbParserNEW parser =
|
||||
new PdbParserNEW(pdbFile, program, service, true, currentMonitor);
|
||||
|
||||
parser.parse();
|
||||
parser.openDataTypeArchives();
|
||||
parser.applyTo(currentMonitor, log);
|
||||
parser.applyTo(log);
|
||||
|
||||
analyzeSymbols(currentMonitor, log);
|
||||
return !monitor.isCancelled();
|
||||
|
|
|
@ -103,10 +103,7 @@ public class PdbPlugin extends Plugin {
|
|||
return;
|
||||
}
|
||||
|
||||
// Note: use other constructor if we want to enforce Auto-Analysis before
|
||||
// applying PDB.
|
||||
final PdbParserNEW parser = new PdbParserNEW(pdb, program, service, true);
|
||||
TaskLauncher.launch(new LoadPdbTask(program, parser));
|
||||
TaskLauncher.launch(new LoadPdbTask(program, pdb, service));
|
||||
}
|
||||
catch (Exception pe) {
|
||||
Msg.showError(getClass(), null, "Error", pe.getMessage());
|
||||
|
|
|
@ -773,11 +773,7 @@ public class PdbSymbolServerPlugin extends Plugin {
|
|||
return;
|
||||
}
|
||||
|
||||
// Note: use other constructor if we want to enforce Auto-Analysis before
|
||||
// applying PDB.
|
||||
final PdbParserNEW parser =
|
||||
new PdbParserNEW(downloadedPdb, currentProgram, service, true);
|
||||
TaskLauncher.launch(new LoadPdbTask(currentProgram, parser));
|
||||
TaskLauncher.launch(new LoadPdbTask(currentProgram, downloadedPdb, service));
|
||||
}
|
||||
catch (Exception pe) {
|
||||
Msg.showError(getClass(), null, "Error", pe.getMessage());
|
||||
|
|
|
@ -195,12 +195,15 @@ std::wstring getName(IDiaSymbol& symbol) {
|
|||
|
||||
DWORD locType = 0;
|
||||
ULONGLONG len = 0;
|
||||
DWORD bitPos = 0;
|
||||
if (symbol.get_locationType(&locType) == S_OK &&
|
||||
locType == LocIsBitField &&
|
||||
symbol.get_length(&len) == S_OK) {
|
||||
const size_t length = wstrName.length() + 4 + 32; // length of: name + ":0x\0" + wag_hex_numeric_str_len
|
||||
symbol.get_length(&len) == S_OK &&
|
||||
symbol.get_bitPosition(&bitPos) == S_OK) {
|
||||
// allocate length of: name + ":0x" + len + ":0x" + bitPos + "\0"
|
||||
const size_t length = wstrName.length() + 70;
|
||||
std::vector<wchar_t> str(length);
|
||||
swprintf_s(str.data(), length, L"%ws:0x%I64x", wstrName.c_str(), len);
|
||||
swprintf_s(str.data(), length, L"%ws:0x%I64x:0x%x", wstrName.c_str(), len, bitPos);
|
||||
return escapeXmlEntities(str.data());
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,783 @@
|
|||
/* ###
|
||||
* 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.util.bin.format.pdb;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.test.AbstractGhidraHeadlessIntegrationTest;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
import util.CollectionUtils;
|
||||
|
||||
public class CompositeMemberTest extends AbstractGhidraHeadlessIntegrationTest
|
||||
implements Consumer<String> {
|
||||
|
||||
DataTypeManager dataMgr;
|
||||
PdbDataTypeParser dataTypeParser;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
// DataOrganization based on x86-64.cspec
|
||||
DataOrganizationImpl dataOrg = DataOrganizationImpl.getDefaultOrganization(null);
|
||||
dataOrg.setBigEndian(false);
|
||||
dataOrg.setAbsoluteMaxAlignment(0);
|
||||
dataOrg.setMachineAlignment(2);
|
||||
dataOrg.setDefaultPointerAlignment(8);
|
||||
dataOrg.setPointerSize(8);
|
||||
|
||||
dataOrg.setSizeAlignment(8, 8);
|
||||
|
||||
BitFieldPackingImpl bitFieldPacking = new BitFieldPackingImpl();
|
||||
bitFieldPacking.setUseMSConvention(true);
|
||||
dataOrg.setBitFieldPacking(bitFieldPacking);
|
||||
|
||||
dataMgr = new TestDummyDataTypeManager() {
|
||||
HashMap<String, DataType> dataTypeMap = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public DataOrganization getDataOrganization() {
|
||||
return dataOrg;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType addDataType(DataType dataType, DataTypeConflictHandler handler) {
|
||||
// handler ignored - tests should not induce conflicts
|
||||
String pathname = dataType.getPathName();
|
||||
DataType myDt = dataTypeMap.get(pathname);
|
||||
if (myDt != null) {
|
||||
return myDt;
|
||||
}
|
||||
DataType dt = dataType.clone(this);
|
||||
dataTypeMap.put(pathname, dt);
|
||||
return dt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType findDataType(String dataTypePath) {
|
||||
return dataTypeMap.get(dataTypePath);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType getDataType(CategoryPath path, String name) {
|
||||
return super.getDataType(new DataTypePath(path, name).getPath());
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType getDataType(String dataTypePath) {
|
||||
return dataTypeMap.get(dataTypePath);
|
||||
}
|
||||
};
|
||||
|
||||
dataTypeParser = new PdbDataTypeParser(dataMgr, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(String message) {
|
||||
Msg.info(this, message + " (Test: " + getName() + ")");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleStructureWithBitFields() throws Exception {
|
||||
|
||||
StructureDataType struct = new StructureDataType("struct", 0, dataMgr);
|
||||
|
||||
//@formatter:off
|
||||
List<MyPdbMember> members =
|
||||
CollectionUtils.asList(new MyPdbMember("a", "uchar", 0),
|
||||
new MyPdbMember("b:0x4", "uchar", 1),
|
||||
new MyPdbMember("c:0x4", "uchar", 1),
|
||||
new MyPdbMember("d:0x4", "uchar", 2),
|
||||
new MyPdbMember("e:0x4", "uint", 4),
|
||||
new MyPdbMember("f", "ushort", 8));
|
||||
//@formatter:on
|
||||
|
||||
assertTrue(DefaultCompositeMember.applyDataTypeMembers(struct, false, 12, members, this,
|
||||
TaskMonitor.DUMMY));
|
||||
|
||||
//@formatter:off
|
||||
CompositeTestUtils.assertExpectedComposite(this,
|
||||
"/struct\n" +
|
||||
"Aligned\n" +
|
||||
"Structure struct {\n" +
|
||||
" 0 uchar 1 a \"\"\n" +
|
||||
" 1 uchar:4(0) 1 b \"\"\n" +
|
||||
" 1 uchar:4(4) 1 c \"\"\n" +
|
||||
" 2 uchar:4(0) 1 d \"\"\n" +
|
||||
" 4 uint:4(0) 1 e \"\"\n" +
|
||||
" 8 ushort 2 f \"\"\n" +
|
||||
"}\n" +
|
||||
"Size = 12 Actual Alignment = 4", struct);
|
||||
//@formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleStructureWithFillerBitFields() throws Exception {
|
||||
|
||||
StructureDataType struct = new StructureDataType("struct", 0, dataMgr);
|
||||
|
||||
//@formatter:off
|
||||
List<MyPdbMember> members =
|
||||
CollectionUtils.asList(new MyPdbMember("a", "uchar", 0),
|
||||
new MyPdbMember("b:0x2:0x2", "uchar", 1),
|
||||
new MyPdbMember("c1:0x1:0x4", "uchar", 1),
|
||||
new MyPdbMember("c2:0x1:0x6", "uchar", 1),
|
||||
new MyPdbMember("d:0x7:0x0", "uchar", 2),
|
||||
new MyPdbMember("e:0x4:0x0", "uint", 4),
|
||||
new MyPdbMember("f", "ushort", 8));
|
||||
//@formatter:on
|
||||
|
||||
assertTrue(DefaultCompositeMember.applyDataTypeMembers(struct, false, 12, members, this,
|
||||
TaskMonitor.DUMMY));
|
||||
|
||||
//@formatter:off
|
||||
CompositeTestUtils.assertExpectedComposite(this,
|
||||
"/struct\n" +
|
||||
"Aligned\n" +
|
||||
"Structure struct {\n" +
|
||||
" 0 uchar 1 a \"\"\n" +
|
||||
" 1 uchar:2(0) 1 padding \"\"\n" +
|
||||
" 1 uchar:2(2) 1 b \"\"\n" +
|
||||
" 1 uchar:1(4) 1 c1 \"\"\n" +
|
||||
" 1 uchar:1(5) 1 padding \"\"\n" +
|
||||
" 1 uchar:1(6) 1 c2 \"\"\n" +
|
||||
" 2 uchar:7(0) 1 d \"\"\n" +
|
||||
" 4 uint:4(0) 1 e \"\"\n" +
|
||||
" 8 ushort 2 f \"\"\n" +
|
||||
"}\n" +
|
||||
"Size = 12 Actual Alignment = 4", struct, true);
|
||||
//@formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnionedStructuresWithFillerBitFields() throws Exception {
|
||||
|
||||
/*** Structure Source ***
|
||||
|
||||
struct BitFieldUnionAlternatingPadded_s {
|
||||
union {
|
||||
struct {
|
||||
char a0:1;
|
||||
char :1;
|
||||
char a2:1;
|
||||
char :1;
|
||||
char a4:1;
|
||||
char :1;
|
||||
};
|
||||
struct {
|
||||
char :1;
|
||||
char a1:1;
|
||||
char :1;
|
||||
char a3:1;
|
||||
char :1;
|
||||
char a5:1;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
*/
|
||||
|
||||
StructureDataType struct = new StructureDataType("struct", 0, dataMgr);
|
||||
|
||||
//@formatter:off
|
||||
List<MyPdbMember> members =
|
||||
CollectionUtils.asList(
|
||||
new MyPdbMember("a0:0x1:0x0", "char", 0),
|
||||
new MyPdbMember("a2:0x1:0x2", "char", 0),
|
||||
new MyPdbMember("a4:0x1:0x4", "char", 0),
|
||||
new MyPdbMember("a1:0x1:0x1", "char", 0),
|
||||
new MyPdbMember("a3:0x1:0x3", "char", 0),
|
||||
new MyPdbMember("a5:0x1:0x5", "char", 0));
|
||||
//@formatter:on
|
||||
|
||||
assertTrue(DefaultCompositeMember.applyDataTypeMembers(struct, false, 1, members, this,
|
||||
TaskMonitor.DUMMY));
|
||||
|
||||
//@formatter:off
|
||||
CompositeTestUtils.assertExpectedComposite(this,
|
||||
"/struct\n" +
|
||||
"Aligned\n" +
|
||||
"Structure struct {\n" +
|
||||
" 0 struct_u_0 1 null \"\"\n" +
|
||||
"}\n" +
|
||||
"Size = 1 Actual Alignment = 1\n" +
|
||||
"/struct/struct_u_0\n" +
|
||||
"Aligned\n" +
|
||||
"Union struct_u_0 {\n" +
|
||||
" 0 struct_u_0_s_0 1 _s_0 \"\"\n" +
|
||||
" 0 struct_u_0_s_1 1 _s_1 \"\"\n" +
|
||||
"}\n" +
|
||||
"Size = 1 Actual Alignment = 1\n" +
|
||||
"/struct/struct_u_0/struct_u_0_s_0\n" +
|
||||
"Aligned\n" +
|
||||
"Structure struct_u_0_s_0 {\n" +
|
||||
" 0 char:1(0) 1 a0 \"\"\n" +
|
||||
" 0 char:1(1) 1 padding \"\"\n" +
|
||||
" 0 char:1(2) 1 a2 \"\"\n" +
|
||||
" 0 char:1(3) 1 padding \"\"\n" +
|
||||
" 0 char:1(4) 1 a4 \"\"\n" +
|
||||
"}\n" +
|
||||
"Size = 1 Actual Alignment = 1\n" +
|
||||
"/struct/struct_u_0/struct_u_0_s_1\n" +
|
||||
"Aligned\n" +
|
||||
"Structure struct_u_0_s_1 {\n" +
|
||||
" 0 char:1(0) 1 padding \"\"\n" +
|
||||
" 0 char:1(1) 1 a1 \"\"\n" +
|
||||
" 0 char:1(2) 1 padding \"\"\n" +
|
||||
" 0 char:1(3) 1 a3 \"\"\n" +
|
||||
" 0 char:1(4) 1 padding \"\"\n" +
|
||||
" 0 char:1(5) 1 a5 \"\"\n" +
|
||||
"}\n" +
|
||||
"Size = 1 Actual Alignment = 1", struct, true);
|
||||
//@formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleUnion() throws Exception {
|
||||
|
||||
UnionDataType union = new UnionDataType(CategoryPath.ROOT, "union", dataMgr);
|
||||
|
||||
// NOTE: preference will be given to packing compatible bitfields at same byte
|
||||
// offset into structures (currently ambiguous data in PDB xml)
|
||||
|
||||
//@formatter:off
|
||||
List<MyPdbMember> members =
|
||||
CollectionUtils.asList(new MyPdbMember("a", "uchar", 0),
|
||||
new MyPdbMember("b:0x4", "uchar", 0),
|
||||
new MyPdbMember("c:0x4", "uchar", 0),
|
||||
new MyPdbMember("d:0x4", "uchar", 0),
|
||||
new MyPdbMember("e:0x4", "uchar", 0),
|
||||
new MyPdbMember("f", "ushort", 0));
|
||||
//@formatter:on
|
||||
|
||||
assertTrue(DefaultCompositeMember.applyDataTypeMembers(union, false, 2, members, this,
|
||||
TaskMonitor.DUMMY));
|
||||
|
||||
// NOTE: handling of bit-fields within union is rather ambiguous within
|
||||
// PDB data
|
||||
|
||||
//@formatter:off
|
||||
CompositeTestUtils.assertExpectedComposite(this,
|
||||
"/union\n" +
|
||||
"Aligned\n" +
|
||||
"Union union {\n" +
|
||||
" 0 uchar 1 a \"\"\n" +
|
||||
" 0 union_s_1 1 _s_1 \"\"\n" +
|
||||
" 0 union_s_2 1 _s_2 \"\"\n" +
|
||||
" 0 ushort 2 f \"\"\n" +
|
||||
"}\n" +
|
||||
"Size = 2 Actual Alignment = 2\n" +
|
||||
"/union/union_s_1\n" +
|
||||
"Aligned\n" +
|
||||
"Structure union_s_1 {\n" +
|
||||
" 0 uchar:4(0) 1 b \"\"\n" +
|
||||
" 0 uchar:4(4) 1 c \"\"\n" +
|
||||
"}\n" +
|
||||
"Size = 1 Actual Alignment = 1\n" +
|
||||
"/union/union_s_2\n" +
|
||||
"Aligned\n" +
|
||||
"Structure union_s_2 {\n" +
|
||||
" 0 uchar:4(0) 1 d \"\"\n" +
|
||||
" 0 uchar:4(4) 1 e \"\"\n" +
|
||||
"}\n" +
|
||||
"Size = 1 Actual Alignment = 1", union, true);
|
||||
//@formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testComplexStructureWithFlexArray() throws Exception {
|
||||
|
||||
UnionDataType struct = new UnionDataType(CategoryPath.ROOT, "union", dataMgr);
|
||||
|
||||
//@formatter:off
|
||||
List<MyPdbMember> members =
|
||||
CollectionUtils.asList(
|
||||
new MyPdbMember("a", "int", 0),
|
||||
new MyPdbMember("b", "int", 4),
|
||||
new MyPdbMember("c", "int", 8),
|
||||
new MyPdbMember("d", "char[0]", 12),
|
||||
new MyPdbMember("e", "longlong", 0),
|
||||
new MyPdbMember("f", "char[0]", 8));
|
||||
//@formatter:on
|
||||
|
||||
assertTrue(DefaultCompositeMember.applyDataTypeMembers(struct, false, 12, members, this,
|
||||
TaskMonitor.DUMMY));
|
||||
|
||||
//@formatter:off
|
||||
CompositeTestUtils.assertExpectedComposite(this,
|
||||
"/union\n" +
|
||||
"Aligned\n" +
|
||||
"Union union {\n" +
|
||||
" 0 union_s_0 12 _s_0 \"\"\n" +
|
||||
" 0 union_s_1 8 _s_1 \"\"\n" +
|
||||
"}\n" +
|
||||
"Size = 12 Actual Alignment = 8\n" +
|
||||
"/union/union_s_0\n" +
|
||||
"Aligned\n" +
|
||||
"Structure union_s_0 {\n" +
|
||||
" 0 int 4 a \"\"\n" +
|
||||
" 4 int 4 b \"\"\n" +
|
||||
" 8 int 4 c \"\"\n" +
|
||||
" char[0] 0 d \"\"\n" +
|
||||
"}\n" +
|
||||
"Size = 12 Actual Alignment = 4\n" +
|
||||
"/union/union_s_1\n" +
|
||||
"Aligned\n" +
|
||||
"Structure union_s_1 {\n" +
|
||||
" 0 longlong 8 e \"\"\n" +
|
||||
" char[0] 0 f \"\"\n" +
|
||||
"}\n" +
|
||||
"Size = 8 Actual Alignment = 8\n", struct, true);
|
||||
//@formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testComplexStructureWithFlexArray2() throws Exception {
|
||||
|
||||
UnionDataType struct = new UnionDataType(CategoryPath.ROOT, "union", dataMgr);
|
||||
|
||||
//@formatter:off
|
||||
List<MyPdbMember> members =
|
||||
CollectionUtils.asList(
|
||||
new MyPdbMember("a", "int", 0),
|
||||
new MyPdbMember("b", "int", 4),
|
||||
new MyPdbMember("c", "int", 8),
|
||||
new MyPdbMember("d", "char[0]", 12),
|
||||
new MyPdbMember("f", "char[0]", 0));
|
||||
//@formatter:on
|
||||
|
||||
assertTrue(DefaultCompositeMember.applyDataTypeMembers(struct, false, 12, members, this,
|
||||
TaskMonitor.DUMMY));
|
||||
|
||||
//@formatter:off
|
||||
CompositeTestUtils.assertExpectedComposite(this,
|
||||
"/union\n" +
|
||||
"Aligned\n" +
|
||||
"Union union {\n" +
|
||||
" 0 union_s_0 12 _s_0 \"\"\n" +
|
||||
" 0 union_s_1 1 _s_1 \"\"\n" +
|
||||
"}\n" +
|
||||
"Size = 12 Actual Alignment = 4\n" +
|
||||
"/union/union_s_0\n" +
|
||||
"Aligned\n" +
|
||||
"Structure union_s_0 {\n" +
|
||||
" 0 int 4 a \"\"\n" +
|
||||
" 4 int 4 b \"\"\n" +
|
||||
" 8 int 4 c \"\"\n" +
|
||||
" char[0] 0 d \"\"\n" +
|
||||
"}\n" +
|
||||
"Size = 12 Actual Alignment = 4\n" +
|
||||
"/union/union_s_1\n" +
|
||||
"Aligned\n" +
|
||||
"Structure union_s_1 {\n" +
|
||||
" char[0] 0 f \"\"\n" +
|
||||
"}\n" +
|
||||
"Size = 1 Actual Alignment = 1\n", struct, true);
|
||||
//@formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testComplexStructureWithBitFields() throws Exception {
|
||||
|
||||
StructureDataType struct = new StructureDataType("struct", 0, dataMgr);
|
||||
|
||||
//@formatter:off
|
||||
List<MyPdbMember> members =
|
||||
CollectionUtils.asList(
|
||||
new MyPdbMember("s0:0x1", "char", 0),
|
||||
new MyPdbMember("s1:0x1", "char", 0),
|
||||
new MyPdbMember("s2:0x1", "char", 0),
|
||||
new MyPdbMember("s3:0x1", "char", 0),
|
||||
new MyPdbMember("s4:0x1", "char", 0),
|
||||
new MyPdbMember("s5:0x1", "char", 0),
|
||||
new MyPdbMember("s6:0x1", "char", 0),
|
||||
new MyPdbMember("s7:0x1", "char", 0),
|
||||
new MyPdbMember("u0:0x1", "uchar", 0),
|
||||
new MyPdbMember("u1:0x1", "uchar", 0),
|
||||
new MyPdbMember("u2:0x1", "uchar", 0),
|
||||
new MyPdbMember("u3:0x1", "uchar", 0),
|
||||
new MyPdbMember("u4:0x1", "uchar", 0),
|
||||
new MyPdbMember("u5:0x1", "uchar", 0),
|
||||
new MyPdbMember("u6:0x1", "uchar", 0),
|
||||
new MyPdbMember("u7:0x1", "uchar", 0),
|
||||
new MyPdbMember("a", "ulong", 8),
|
||||
new MyPdbMember("b", "longlong", 8));
|
||||
//@formatter:on
|
||||
|
||||
assertTrue(DefaultCompositeMember.applyDataTypeMembers(struct, false, 16, members, this,
|
||||
TaskMonitor.DUMMY));
|
||||
|
||||
//@formatter:off
|
||||
CompositeTestUtils.assertExpectedComposite(this,
|
||||
"/struct\n" +
|
||||
"Aligned\n" +
|
||||
"Structure struct {\n" +
|
||||
" 0 struct_u_0 1 null \"\"\n" +
|
||||
" 8 struct_u_8 8 null \"\"\n" +
|
||||
"}\n" +
|
||||
"Size = 16 Actual Alignment = 8\n" +
|
||||
"/struct/struct_u_0\n" +
|
||||
"Aligned\n" +
|
||||
"Union struct_u_0 {\n" +
|
||||
" 0 struct_u_0_s_0 1 _s_0 \"\"\n" +
|
||||
" 0 struct_u_0_s_1 1 _s_1 \"\"\n" +
|
||||
"}\n" +
|
||||
"Size = 1 Actual Alignment = 1\n" +
|
||||
"/struct/struct_u_0/struct_u_0_s_0\n" +
|
||||
"Aligned\n" +
|
||||
"Structure struct_u_0_s_0 {\n" +
|
||||
" 0 char:1(0) 1 s0 \"\"\n" +
|
||||
" 0 char:1(1) 1 s1 \"\"\n" +
|
||||
" 0 char:1(2) 1 s2 \"\"\n" +
|
||||
" 0 char:1(3) 1 s3 \"\"\n" +
|
||||
" 0 char:1(4) 1 s4 \"\"\n" +
|
||||
" 0 char:1(5) 1 s5 \"\"\n" +
|
||||
" 0 char:1(6) 1 s6 \"\"\n" +
|
||||
" 0 char:1(7) 1 s7 \"\"\n" +
|
||||
"}\n" +
|
||||
"Size = 1 Actual Alignment = 1\n" +
|
||||
"/struct/struct_u_0/struct_u_0_s_1\n" +
|
||||
"Aligned\n" +
|
||||
"Structure struct_u_0_s_1 {\n" +
|
||||
" 0 uchar:1(0) 1 u0 \"\"\n" +
|
||||
" 0 uchar:1(1) 1 u1 \"\"\n" +
|
||||
" 0 uchar:1(2) 1 u2 \"\"\n" +
|
||||
" 0 uchar:1(3) 1 u3 \"\"\n" +
|
||||
" 0 uchar:1(4) 1 u4 \"\"\n" +
|
||||
" 0 uchar:1(5) 1 u5 \"\"\n" +
|
||||
" 0 uchar:1(6) 1 u6 \"\"\n" +
|
||||
" 0 uchar:1(7) 1 u7 \"\"\n" +
|
||||
"}\n" +
|
||||
"Size = 1 Actual Alignment = 1\n" +
|
||||
"/struct/struct_u_8\n" +
|
||||
"Aligned\n" +
|
||||
"Union struct_u_8 {\n" +
|
||||
" 0 ulong 4 a \"\"\n" +
|
||||
" 0 longlong 8 b \"\"\n" +
|
||||
"}\n" +
|
||||
"Size = 8 Actual Alignment = 8\n", struct, true);
|
||||
//@formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testComplexStructureWithBitFields2() throws Exception {
|
||||
|
||||
UnionDataType struct = new UnionDataType(CategoryPath.ROOT, "union", dataMgr);
|
||||
|
||||
//@formatter:off
|
||||
List<MyPdbMember> members =
|
||||
CollectionUtils.asList(
|
||||
new MyPdbMember("a", "ulong", 0),
|
||||
new MyPdbMember("b", "longlong", 0),
|
||||
new MyPdbMember("s0:0x1", "char", 0),
|
||||
new MyPdbMember("s1:0x1", "char", 0),
|
||||
new MyPdbMember("s2:0x1", "char", 0),
|
||||
new MyPdbMember("s3:0x1", "char", 0),
|
||||
new MyPdbMember("s4:0x1", "char", 0),
|
||||
new MyPdbMember("s5:0x1", "char", 0),
|
||||
new MyPdbMember("s6:0x1", "char", 0),
|
||||
new MyPdbMember("s7:0x1", "char", 0),
|
||||
new MyPdbMember("u0:0x1", "uchar", 1),
|
||||
new MyPdbMember("u1:0x1", "uchar", 1),
|
||||
new MyPdbMember("u2:0x1", "uchar", 1),
|
||||
new MyPdbMember("u3:0x1", "uchar", 1),
|
||||
new MyPdbMember("u4:0x1", "uchar", 1),
|
||||
new MyPdbMember("u5:0x1", "uchar", 1),
|
||||
new MyPdbMember("u6:0x1", "uchar", 1),
|
||||
new MyPdbMember("u7:0x1", "uchar", 1));
|
||||
|
||||
//@formatter:on
|
||||
|
||||
assertTrue(DefaultCompositeMember.applyDataTypeMembers(struct, false, 12, members, this,
|
||||
TaskMonitor.DUMMY));
|
||||
|
||||
//@formatter:off
|
||||
CompositeTestUtils.assertExpectedComposite(this,
|
||||
"/union\n" +
|
||||
"Unaligned\n" +
|
||||
"Union union {\n" +
|
||||
" 0 ulong 4 a \"\"\n" +
|
||||
" 0 longlong 8 b \"\"\n" +
|
||||
" 0 union_s_2 2 _s_2 \"\"\n" +
|
||||
"}\n" +
|
||||
"Size = 8 Actual Alignment = 1\n" +
|
||||
"/union/union_s_2\n" +
|
||||
"Aligned\n" +
|
||||
"Structure union_s_2 {\n" +
|
||||
" 0 char:1(0) 1 s0 \"\"\n" +
|
||||
" 0 char:1(1) 1 s1 \"\"\n" +
|
||||
" 0 char:1(2) 1 s2 \"\"\n" +
|
||||
" 0 char:1(3) 1 s3 \"\"\n" +
|
||||
" 0 char:1(4) 1 s4 \"\"\n" +
|
||||
" 0 char:1(5) 1 s5 \"\"\n" +
|
||||
" 0 char:1(6) 1 s6 \"\"\n" +
|
||||
" 0 char:1(7) 1 s7 \"\"\n" +
|
||||
" 1 uchar:1(0) 1 u0 \"\"\n" +
|
||||
" 1 uchar:1(1) 1 u1 \"\"\n" +
|
||||
" 1 uchar:1(2) 1 u2 \"\"\n" +
|
||||
" 1 uchar:1(3) 1 u3 \"\"\n" +
|
||||
" 1 uchar:1(4) 1 u4 \"\"\n" +
|
||||
" 1 uchar:1(5) 1 u5 \"\"\n" +
|
||||
" 1 uchar:1(6) 1 u6 \"\"\n" +
|
||||
" 1 uchar:1(7) 1 u7 \"\"\n" +
|
||||
"}\n" +
|
||||
"Size = 2 Actual Alignment = 1", struct, true);
|
||||
//@formatter:on
|
||||
}
|
||||
|
||||
// @Ignore defined structure is too ambiguous
|
||||
@Test
|
||||
public void testMoreComplicatedStructure() throws Exception {
|
||||
|
||||
StructureDataType struct = new StructureDataType("MoreComplicated_s", 0, dataMgr);
|
||||
|
||||
//@formatter:off
|
||||
List<MyPdbMember> members =
|
||||
CollectionUtils.asList(new MyPdbMember("s0:0x1", "char", 0x0),
|
||||
new MyPdbMember("s1:0x1", "char", 0x0),
|
||||
new MyPdbMember("s2:0x1", "char", 0x0),
|
||||
new MyPdbMember("s3:0x1", "char", 0x0),
|
||||
new MyPdbMember("s4:0x1", "char", 0x0),
|
||||
new MyPdbMember("s5:0x1", "char", 0x0),
|
||||
new MyPdbMember("s6:0x1", "char", 0x0),
|
||||
new MyPdbMember("s7:0x1", "char", 0x0),
|
||||
new MyPdbMember("u0:0x1", "uchar", 0x0),
|
||||
new MyPdbMember("u1:0x1", "uchar", 0x0),
|
||||
new MyPdbMember("u2:0x1", "uchar", 0x0),
|
||||
new MyPdbMember("u3:0x1", "uchar", 0x0),
|
||||
new MyPdbMember("u4:0x1", "uchar", 0x0),
|
||||
new MyPdbMember("u5:0x1", "uchar", 0x0),
|
||||
new MyPdbMember("u6:0x1", "uchar", 0x0),
|
||||
new MyPdbMember("u7:0x1", "uchar", 0x0),
|
||||
new MyPdbMember("val", "ulong", 0x8),
|
||||
new MyPdbMember("d", "double", 0x8),
|
||||
new MyPdbMember("n0:0x4", "ulong", 0x8),
|
||||
new MyPdbMember("n1:0x4", "ulong", 0x8),
|
||||
new MyPdbMember("n2:0x4", "ulong", 0x8),
|
||||
new MyPdbMember("n3:0x4", "ulong", 0x8),
|
||||
new MyPdbMember("n4:0x4", "ulong", 0x8),
|
||||
new MyPdbMember("n5:0x4", "ulong", 0x8),
|
||||
new MyPdbMember("n6:0x4", "ulong", 0x8),
|
||||
new MyPdbMember("n7:0x4", "ulong", 0x8),
|
||||
new MyPdbMember("n8:0x4", "ulong", 0xc),
|
||||
new MyPdbMember("n9:0x4", "ulong", 0xc),
|
||||
new MyPdbMember("n10:0x4", "ulong", 0xc),
|
||||
new MyPdbMember("n11:0x4", "ulong", 0xc),
|
||||
new MyPdbMember("n12:0x4", "ulong", 0xc),
|
||||
new MyPdbMember("n13:0x4", "ulong", 0xc),
|
||||
new MyPdbMember("n14:0x4", "ulong", 0xc),
|
||||
new MyPdbMember("n15:0x4", "ulong", 0xc),
|
||||
new MyPdbMember("x1:0x1", "ulong", 0x8),
|
||||
new MyPdbMember("x2:0x2", "ulong", 0x8),
|
||||
new MyPdbMember("x3:0x3", "ulong", 0x8),
|
||||
new MyPdbMember("x4:0x4", "ulong", 0x8),
|
||||
new MyPdbMember("x5:0x5", "ulong", 0x8),
|
||||
new MyPdbMember("x6:0x6", "ulong", 0x8),
|
||||
new MyPdbMember("x7:0x7", "ulong", 0x8),
|
||||
new MyPdbMember("x8:0x8", "ulong", 0xc),
|
||||
new MyPdbMember("x9:0x9", "ulong", 0xc),
|
||||
new MyPdbMember("x10:0xa", "ulong", 0xc),
|
||||
new MyPdbMember("y1:0x1", "uchar", 0x8),
|
||||
new MyPdbMember("y2:0x2", "uchar", 0x8),
|
||||
new MyPdbMember("y3:0x3", "uchar", 0x8),
|
||||
new MyPdbMember("y4:0x4", "uchar", 0x9),
|
||||
new MyPdbMember("y5:0x5", "uchar", 0xa),
|
||||
new MyPdbMember("y6:0x6", "uchar", 0xb),
|
||||
new MyPdbMember("y7:0x7", "uchar", 0xc),
|
||||
new MyPdbMember("y8:0x8", "uchar", 0xd),
|
||||
new MyPdbMember("y9:0x9", "ushort", 0xe),
|
||||
new MyPdbMember("da", "double", 0x10),
|
||||
new MyPdbMember("ca", "char[8]", 0x18),
|
||||
new MyPdbMember("cb", "char[8]", 0x10),
|
||||
new MyPdbMember("db", "double", 0x18),
|
||||
new MyPdbMember("beef", "char[10]", 0x20),
|
||||
new MyPdbMember("fromAddress", "int", 0x2c),
|
||||
new MyPdbMember("toAddress", "int", 0x30),
|
||||
new MyPdbMember("seqNum", "int", 0x34),
|
||||
new MyPdbMember("data", "char[0]", 0x38),
|
||||
new MyPdbMember("buf", "char[0]", 0x2c));
|
||||
//@formatter:on
|
||||
|
||||
assertTrue(DefaultCompositeMember.applyDataTypeMembers(struct, false, 0x38, members, this,
|
||||
TaskMonitor.DUMMY));
|
||||
|
||||
//@formatter:off
|
||||
CompositeTestUtils.assertExpectedComposite(this,
|
||||
"/MoreComplicated_s\n" +
|
||||
"Aligned\n" +
|
||||
"Structure MoreComplicated_s {\n" +
|
||||
" 0 MoreComplicated_s_u_0 1 null \"\"\n" +
|
||||
" 8 MoreComplicated_s_u_8 8 null \"\"\n" +
|
||||
" 16 MoreComplicated_s_u_16 16 null \"\"\n" +
|
||||
" 32 char[10] 10 beef \"\"\n" +
|
||||
" 44 MoreComplicated_s_u_44 12 null \"\"\n" +
|
||||
"}\n" +
|
||||
"Size = 56 Actual Alignment = 8\n" +
|
||||
"/MoreComplicated_s/MoreComplicated_s_u_0\n" +
|
||||
"Aligned\n" +
|
||||
"Union MoreComplicated_s_u_0 {\n" +
|
||||
" 0 MoreComplicated_s_u_0_s_0 1 _s_0 \"\"\n" +
|
||||
" 0 MoreComplicated_s_u_0_s_1 1 _s_1 \"\"\n" +
|
||||
"}\n" +
|
||||
"Size = 1 Actual Alignment = 1\n" +
|
||||
"/MoreComplicated_s/MoreComplicated_s_u_0/MoreComplicated_s_u_0_s_0\n" +
|
||||
"Aligned\n" +
|
||||
"Structure MoreComplicated_s_u_0_s_0 {\n" +
|
||||
" 0 char:1(0) 1 s0 \"\"\n" +
|
||||
" 0 char:1(1) 1 s1 \"\"\n" +
|
||||
" 0 char:1(2) 1 s2 \"\"\n" +
|
||||
" 0 char:1(3) 1 s3 \"\"\n" +
|
||||
" 0 char:1(4) 1 s4 \"\"\n" +
|
||||
" 0 char:1(5) 1 s5 \"\"\n" +
|
||||
" 0 char:1(6) 1 s6 \"\"\n" +
|
||||
" 0 char:1(7) 1 s7 \"\"\n" +
|
||||
"}\n" +
|
||||
"Size = 1 Actual Alignment = 1\n" +
|
||||
"/MoreComplicated_s/MoreComplicated_s_u_0/MoreComplicated_s_u_0_s_1\n" +
|
||||
"Aligned\n" +
|
||||
"Structure MoreComplicated_s_u_0_s_1 {\n" +
|
||||
" 0 uchar:1(0) 1 u0 \"\"\n" +
|
||||
" 0 uchar:1(1) 1 u1 \"\"\n" +
|
||||
" 0 uchar:1(2) 1 u2 \"\"\n" +
|
||||
" 0 uchar:1(3) 1 u3 \"\"\n" +
|
||||
" 0 uchar:1(4) 1 u4 \"\"\n" +
|
||||
" 0 uchar:1(5) 1 u5 \"\"\n" +
|
||||
" 0 uchar:1(6) 1 u6 \"\"\n" +
|
||||
" 0 uchar:1(7) 1 u7 \"\"\n" +
|
||||
"}\n" +
|
||||
"Size = 1 Actual Alignment = 1\n" +
|
||||
"/MoreComplicated_s/MoreComplicated_s_u_16\n" +
|
||||
"Aligned\n" +
|
||||
"Union MoreComplicated_s_u_16 {\n" +
|
||||
" 0 MoreComplicated_s_u_16_s_0 16 _s_0 \"\"\n" +
|
||||
" 0 MoreComplicated_s_u_16_s_1 16 _s_1 \"\"\n" +
|
||||
"}\n" +
|
||||
"Size = 16 Actual Alignment = 8\n" +
|
||||
"/MoreComplicated_s/MoreComplicated_s_u_16/MoreComplicated_s_u_16_s_0\n" +
|
||||
"Aligned\n" +
|
||||
"Structure MoreComplicated_s_u_16_s_0 {\n" +
|
||||
" 0 double 8 da \"\"\n" +
|
||||
" 8 char[8] 8 ca \"\"\n" +
|
||||
"}\n" +
|
||||
"Size = 16 Actual Alignment = 8\n" +
|
||||
"/MoreComplicated_s/MoreComplicated_s_u_16/MoreComplicated_s_u_16_s_1\n" +
|
||||
"Aligned\n" +
|
||||
"Structure MoreComplicated_s_u_16_s_1 {\n" +
|
||||
" 0 char[8] 8 cb \"\"\n" +
|
||||
" 8 double 8 db \"\"\n" +
|
||||
"}\n" +
|
||||
"Size = 16 Actual Alignment = 8\n" +
|
||||
"/MoreComplicated_s/MoreComplicated_s_u_44\n" +
|
||||
"Aligned\n" +
|
||||
"Union MoreComplicated_s_u_44 {\n" +
|
||||
" 0 MoreComplicated_s_u_44_s_0 12 _s_0 \"\"\n" +
|
||||
" 0 MoreComplicated_s_u_44_s_1 1 _s_1 \"\"\n" +
|
||||
"}\n" +
|
||||
"Size = 12 Actual Alignment = 4\n" +
|
||||
"/MoreComplicated_s/MoreComplicated_s_u_44/MoreComplicated_s_u_44_s_0\n" +
|
||||
"Aligned\n" +
|
||||
"Structure MoreComplicated_s_u_44_s_0 {\n" +
|
||||
" 0 int 4 fromAddress \"\"\n" +
|
||||
" 4 int 4 toAddress \"\"\n" +
|
||||
" 8 int 4 seqNum \"\"\n" +
|
||||
" char[0] 0 data \"\"\n" +
|
||||
"}\n" +
|
||||
"Size = 12 Actual Alignment = 4\n" +
|
||||
"/MoreComplicated_s/MoreComplicated_s_u_44/MoreComplicated_s_u_44_s_1\n" +
|
||||
"Aligned\n" +
|
||||
"Structure MoreComplicated_s_u_44_s_1 {\n" +
|
||||
" char[0] 0 buf \"\"\n" +
|
||||
"}\n" +
|
||||
"Size = 1 Actual Alignment = 1\n" +
|
||||
"/MoreComplicated_s/MoreComplicated_s_u_8\n" +
|
||||
"Aligned\n" +
|
||||
"Union MoreComplicated_s_u_8 {\n" +
|
||||
" 0 ulong 4 val \"\"\n" +
|
||||
" 0 double 8 d \"\"\n" +
|
||||
" 0 MoreComplicated_s_u_8_s_2 8 _s_2 \"\"\n" +
|
||||
" 0 MoreComplicated_s_u_8_s_3 8 _s_3 \"\"\n" +
|
||||
" 0 MoreComplicated_s_u_8_s_4 8 _s_4 \"\"\n" +
|
||||
"}\n" +
|
||||
"Size = 8 Actual Alignment = 8\n" +
|
||||
"/MoreComplicated_s/MoreComplicated_s_u_8/MoreComplicated_s_u_8_s_2\n" +
|
||||
"Aligned\n" +
|
||||
"Structure MoreComplicated_s_u_8_s_2 {\n" +
|
||||
" 0 ulong:4(0) 1 n0 \"\"\n" +
|
||||
" 0 ulong:4(4) 1 n1 \"\"\n" +
|
||||
" 1 ulong:4(0) 1 n2 \"\"\n" +
|
||||
" 1 ulong:4(4) 1 n3 \"\"\n" +
|
||||
" 2 ulong:4(0) 1 n4 \"\"\n" +
|
||||
" 2 ulong:4(4) 1 n5 \"\"\n" +
|
||||
" 3 ulong:4(0) 1 n6 \"\"\n" +
|
||||
" 3 ulong:4(4) 1 n7 \"\"\n" +
|
||||
" 4 ulong:4(0) 1 n8 \"\"\n" +
|
||||
" 4 ulong:4(4) 1 n9 \"\"\n" +
|
||||
" 5 ulong:4(0) 1 n10 \"\"\n" +
|
||||
" 5 ulong:4(4) 1 n11 \"\"\n" +
|
||||
" 6 ulong:4(0) 1 n12 \"\"\n" +
|
||||
" 6 ulong:4(4) 1 n13 \"\"\n" +
|
||||
" 7 ulong:4(0) 1 n14 \"\"\n" +
|
||||
" 7 ulong:4(4) 1 n15 \"\"\n" +
|
||||
"}\n" +
|
||||
"Size = 8 Actual Alignment = 4\n" +
|
||||
"/MoreComplicated_s/MoreComplicated_s_u_8/MoreComplicated_s_u_8_s_3\n" +
|
||||
"Aligned\n" +
|
||||
"Structure MoreComplicated_s_u_8_s_3 {\n" +
|
||||
" 0 ulong:1(0) 1 x1 \"\"\n" +
|
||||
" 0 ulong:2(1) 1 x2 \"\"\n" +
|
||||
" 0 ulong:3(3) 1 x3 \"\"\n" +
|
||||
" 0 ulong:4(6) 2 x4 \"\"\n" +
|
||||
" 1 ulong:5(2) 1 x5 \"\"\n" +
|
||||
" 1 ulong:6(7) 2 x6 \"\"\n" +
|
||||
" 2 ulong:7(5) 2 x7 \"\"\n" +
|
||||
" 4 ulong:8(0) 1 x8 \"\"\n" +
|
||||
" 5 ulong:9(0) 2 x9 \"\"\n" +
|
||||
" 6 ulong:10(1) 2 x10 \"\"\n" +
|
||||
"}\n" +
|
||||
"Size = 8 Actual Alignment = 4\n" +
|
||||
"/MoreComplicated_s/MoreComplicated_s_u_8/MoreComplicated_s_u_8_s_4\n" +
|
||||
"Aligned\n" +
|
||||
"Structure MoreComplicated_s_u_8_s_4 {\n" +
|
||||
" 0 uchar:1(0) 1 y1 \"\"\n" +
|
||||
" 0 uchar:2(1) 1 y2 \"\"\n" +
|
||||
" 0 uchar:3(3) 1 y3 \"\"\n" +
|
||||
" 1 uchar:4(0) 1 y4 \"\"\n" +
|
||||
" 2 uchar:5(0) 1 y5 \"\"\n" +
|
||||
" 3 uchar:6(0) 1 y6 \"\"\n" +
|
||||
" 4 uchar:7(0) 1 y7 \"\"\n" +
|
||||
" 5 uchar:8(0) 1 y8 \"\"\n" +
|
||||
" 6 ushort:9(0) 2 y9 \"\"\n" +
|
||||
"}\n" +
|
||||
"Size = 8 Actual Alignment = 2", struct, true);
|
||||
//@formatter:on
|
||||
}
|
||||
|
||||
class MyPdbMember extends DefaultPdbMember {
|
||||
|
||||
protected MyPdbMember(String memberName, String memberDataTypeName, int memberOffset) {
|
||||
super(memberName, memberDataTypeName, memberOffset, dataTypeParser);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -23,7 +23,6 @@ import java.util.List;
|
|||
|
||||
import org.junit.*;
|
||||
|
||||
import generic.test.AbstractGenericTest;
|
||||
import ghidra.app.plugin.core.analysis.AutoAnalysisManager;
|
||||
import ghidra.app.services.DataTypeManagerService;
|
||||
import ghidra.app.util.bin.format.pdb.PdbParserNEW.PdbFileType;
|
||||
|
@ -35,7 +34,8 @@ import ghidra.program.model.address.AddressFactory;
|
|||
import ghidra.program.model.listing.FunctionManager;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.test.AbstractGhidraHeadlessIntegrationTest;
|
||||
import ghidra.util.task.TaskMonitorAdapter;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
import utilities.util.FileUtilities;
|
||||
|
||||
public class PdbParserTest extends AbstractGhidraHeadlessIntegrationTest {
|
||||
|
||||
|
@ -84,7 +84,7 @@ public class PdbParserTest extends AbstractGhidraHeadlessIntegrationTest {
|
|||
public void setUp() throws Exception {
|
||||
|
||||
// Get temp directory in which to store files
|
||||
String tempDirPath = AbstractGenericTest.getTestDirectoryPath();
|
||||
String tempDirPath = getTestDirectoryPath();
|
||||
tempDir = new File(tempDirPath);
|
||||
|
||||
fileLocation = new File(tempDir, exeFolderName);
|
||||
|
@ -100,6 +100,9 @@ public class PdbParserTest extends AbstractGhidraHeadlessIntegrationTest {
|
|||
@After
|
||||
public void tearDown() throws Exception {
|
||||
|
||||
if (fileLocation != null) {
|
||||
FileUtilities.deleteDir(fileLocation);
|
||||
}
|
||||
if (createdFiles != null) {
|
||||
deleteCreatedFiles(createdFiles);
|
||||
}
|
||||
|
@ -991,9 +994,8 @@ public class PdbParserTest extends AbstractGhidraHeadlessIntegrationTest {
|
|||
}
|
||||
|
||||
private void createDirectory(File directory) {
|
||||
boolean createSuccess = directory.mkdir();
|
||||
|
||||
if (!createSuccess) {
|
||||
directory.mkdir();
|
||||
if (!directory.isDirectory()) {
|
||||
fail("Should have created directory: " + directory.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
|
@ -1063,11 +1065,12 @@ public class PdbParserTest extends AbstractGhidraHeadlessIntegrationTest {
|
|||
|
||||
AutoAnalysisManager mgr = AutoAnalysisManager.getAnalysisManager(testProgram);
|
||||
DataTypeManagerService dataTypeManagerService = mgr.getDataTypeManagerService();
|
||||
PdbParserNEW parser = new PdbParserNEW(pdb, testProgram, dataTypeManagerService, false);
|
||||
PdbParserNEW parser =
|
||||
new PdbParserNEW(pdb, testProgram, dataTypeManagerService, false, TaskMonitor.DUMMY);
|
||||
|
||||
parser.openDataTypeArchives();
|
||||
parser.parse();
|
||||
parser.applyTo(TaskMonitorAdapter.DUMMY_MONITOR, new MessageLog());
|
||||
parser.applyTo(new MessageLog());
|
||||
|
||||
// Now check program to see if the function has been successfully applied
|
||||
AddressFactory addressFactory = testProgram.getAddressFactory();
|
||||
|
|
|
@ -34,7 +34,7 @@ public abstract class AbstractFunctionParameterMarkupItemTest extends AbstractVT
|
|||
//==================================================================================================
|
||||
|
||||
protected DataType createByteDataType(ProgramDB program) {
|
||||
DataTypeManagerDB dataTypeManager = program.getDataManager();
|
||||
DataTypeManagerDB dataTypeManager = program.getDataTypeManager();
|
||||
DataType dataType = new ByteDataType(dataTypeManager);
|
||||
return dataTypeManager.addDataType(dataType, DataTypeConflictHandler.DEFAULT_HANDLER);
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ public abstract class AbstractFunctionParameterMarkupItemTest extends AbstractVT
|
|||
int transaction = -1;
|
||||
try {
|
||||
transaction = program.startTransaction("Test - Create Data Type");
|
||||
DataTypeManagerDB dataTypeManager = program.getDataManager();
|
||||
DataTypeManagerDB dataTypeManager = program.getDataTypeManager();
|
||||
DataType dataType = new IntegerDataType(dataTypeManager);
|
||||
return dataTypeManager.addDataType(dataType, DataTypeConflictHandler.DEFAULT_HANDLER);
|
||||
}
|
||||
|
|
|
@ -390,7 +390,7 @@ public class DBHandle {
|
|||
/**
|
||||
* Returns true if transaction is currently active
|
||||
*/
|
||||
protected boolean isTransactionActive() {
|
||||
public boolean isTransactionActive() {
|
||||
return txStarted;
|
||||
}
|
||||
|
||||
|
|
|
@ -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,11 +15,7 @@
|
|||
*/
|
||||
package ghidra.util.layout;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Container;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Insets;
|
||||
import java.awt.LayoutManager;
|
||||
import java.awt.*;
|
||||
|
||||
/**
|
||||
* LayoutManger for arranging components into exactly two columns.
|
||||
|
@ -30,6 +25,7 @@ public class TwoColumnPairLayout implements LayoutManager {
|
|||
private int columnGap;
|
||||
private int pairGap;
|
||||
private int preferredColumnWidth;
|
||||
|
||||
/**
|
||||
* Constructor for PairLayout.
|
||||
*/
|
||||
|
@ -37,7 +33,8 @@ public class TwoColumnPairLayout implements LayoutManager {
|
|||
this(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
public TwoColumnPairLayout(int verticalGap, int columnGap, int pairGap, int preferredValueColumnWidth) {
|
||||
public TwoColumnPairLayout(int verticalGap, int columnGap, int pairGap,
|
||||
int preferredValueColumnWidth) {
|
||||
super();
|
||||
this.verticalGap = verticalGap;
|
||||
this.columnGap = columnGap;
|
||||
|
@ -45,21 +42,24 @@ public class TwoColumnPairLayout implements LayoutManager {
|
|||
this.preferredColumnWidth = preferredValueColumnWidth;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @see LayoutManager#addLayoutComponent(String, Component)
|
||||
*/
|
||||
public void addLayoutComponent(String name, Component comp) {}
|
||||
@Override
|
||||
public void addLayoutComponent(String name, Component comp) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @see LayoutManager#removeLayoutComponent(Component)
|
||||
*/
|
||||
public void removeLayoutComponent(Component comp) {}
|
||||
@Override
|
||||
public void removeLayoutComponent(Component comp) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @see LayoutManager#preferredLayoutSize(Container)
|
||||
*/
|
||||
@Override
|
||||
public Dimension preferredLayoutSize(Container parent) {
|
||||
int rowHeight = getPreferredRowHeight(parent);
|
||||
int[] widths = getPreferredWidths(parent);
|
||||
|
@ -67,10 +67,13 @@ public class TwoColumnPairLayout implements LayoutManager {
|
|||
int nRows = (parent.getComponentCount() + 3) / 4;
|
||||
Insets insets = parent.getInsets();
|
||||
Dimension d = new Dimension(0, 0);
|
||||
int labelWidth = widths[0];
|
||||
int valueWidth = preferredColumnWidth == 0 ? widths[1] : preferredColumnWidth;
|
||||
|
||||
d.width = 2*labelWidth + 2*valueWidth + columnGap + 2*pairGap + insets.left + insets.right;
|
||||
if (preferredColumnWidth > 0) {
|
||||
widths[1] = widths[3] = preferredColumnWidth;
|
||||
}
|
||||
|
||||
d.width = widths[0] + widths[1] + widths[2] + widths[3] + columnGap + 2 * pairGap +
|
||||
insets.left + insets.right;
|
||||
d.height = rowHeight * nRows + verticalGap * (nRows - 1) + insets.top + insets.bottom;
|
||||
return d;
|
||||
}
|
||||
|
@ -78,6 +81,7 @@ public class TwoColumnPairLayout implements LayoutManager {
|
|||
/**
|
||||
* @see LayoutManager#minimumLayoutSize(Container)
|
||||
*/
|
||||
@Override
|
||||
public Dimension minimumLayoutSize(Container parent) {
|
||||
return preferredLayoutSize(parent);
|
||||
}
|
||||
|
@ -85,6 +89,7 @@ public class TwoColumnPairLayout implements LayoutManager {
|
|||
/**
|
||||
* @see LayoutManager#layoutContainer(Container)
|
||||
*/
|
||||
@Override
|
||||
public void layoutContainer(Container parent) {
|
||||
int rowHeight = getPreferredRowHeight(parent);
|
||||
int[] widths = getPreferredWidths(parent);
|
||||
|
@ -95,15 +100,20 @@ public class TwoColumnPairLayout implements LayoutManager {
|
|||
int x = insets.left;
|
||||
int y = insets.top;
|
||||
|
||||
widths[1] = (width - 2*widths[0] - 2*pairGap - columnGap)/2;
|
||||
int totalLabelWidth = widths[0] + widths[2];
|
||||
int padding = 2 * pairGap + columnGap;
|
||||
int totalValueWidth = (width - totalLabelWidth - padding);
|
||||
|
||||
widths[1] = (totalValueWidth * widths[1]) / (widths[1] + widths[3]);
|
||||
widths[3] = totalValueWidth - widths[1];
|
||||
|
||||
int n = parent.getComponentCount();
|
||||
for (int i = 0; i < n; i++) {
|
||||
int index = i % 2;
|
||||
int index = i % 4;
|
||||
Component c = parent.getComponent(i);
|
||||
c.setBounds(x, y, widths[index], rowHeight);
|
||||
x += widths[index];
|
||||
x += (index == 0) ? pairGap : columnGap;
|
||||
x += (index == 1) ? columnGap : pairGap;
|
||||
if (i % 4 == 3) {
|
||||
y += rowHeight + verticalGap;
|
||||
x = insets.left;
|
||||
|
@ -121,18 +131,17 @@ public class TwoColumnPairLayout implements LayoutManager {
|
|||
}
|
||||
return height;
|
||||
}
|
||||
int[] getPreferredWidths(Container parent) {
|
||||
int[] widths = new int[2];
|
||||
|
||||
int[] getPreferredWidths(Container parent) {
|
||||
int[] widths = new int[4];
|
||||
int n = parent.getComponentCount();
|
||||
for (int i = 0; i < n; i++) {
|
||||
Component c = parent.getComponent(i);
|
||||
Dimension d = c.getPreferredSize();
|
||||
int index = i % 2;
|
||||
int index = i % 4;
|
||||
widths[index] = Math.max(widths[index], d.width);
|
||||
}
|
||||
return widths;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -1273,7 +1273,7 @@ public class GraphAlgorithmsTest extends AbstractGraphAlgorithmsTest {
|
|||
edge(v5, v6);
|
||||
edge(v7, v3);
|
||||
|
||||
List<List<TestV>> circuits = GraphAlgorithms.findCircuits(g, TaskMonitor.DUMMY);
|
||||
List<List<TestV>> circuits = GraphAlgorithms.findCircuits(g, false, TaskMonitor.DUMMY);
|
||||
assertEquals(3, circuits.size());
|
||||
}
|
||||
|
||||
|
|
|
@ -71,7 +71,6 @@
|
|||
<optional>
|
||||
<element name="long_double_size"><ref name="value_type"/></element>
|
||||
</optional>
|
||||
|
||||
<optional>
|
||||
<element name="size_alignment_map">
|
||||
<zeroOrMore>
|
||||
|
@ -82,6 +81,24 @@
|
|||
</zeroOrMore>
|
||||
</element>
|
||||
</optional>
|
||||
<optional>
|
||||
<element name="bitfield_packing">
|
||||
<interleave>
|
||||
<optional>
|
||||
<!-- boolean value, default: false (MSVC should be true) -->
|
||||
<element name="use_MS_convention"><ref name="value_type"/></element>
|
||||
</optional>
|
||||
<optional>
|
||||
<!-- boolean value, default: true -->
|
||||
<element name="type_alignment_enabled"><ref name="value_type"/></element>
|
||||
</optional>
|
||||
<optional>
|
||||
<!-- int value: number of bytes -->
|
||||
<element name="zero_length_boundary"><ref name="value_type"/></element>
|
||||
</optional>
|
||||
</interleave>
|
||||
</element>
|
||||
</optional>
|
||||
</interleave>
|
||||
</element>
|
||||
</optional>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
*/
|
||||
package ghidra.app.util;
|
||||
|
||||
import java.util.ConcurrentModificationException;
|
||||
import java.util.*;
|
||||
|
||||
import ghidra.docking.settings.Settings;
|
||||
import ghidra.program.database.ProgramDB;
|
||||
|
@ -53,7 +53,7 @@ public class PseudoData extends PseudoCodeUnit implements Data {
|
|||
this.dataType = dataType;
|
||||
baseDataType = getBaseDataType(dataType);
|
||||
if (program instanceof ProgramDB) {
|
||||
dataMgr = ((ProgramDB) program).getDataManager();
|
||||
dataMgr = ((ProgramDB) program).getDataTypeManager();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -384,6 +384,46 @@ public class PseudoData extends PseudoCodeUnit implements Data {
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Data> getComponentsContaining(int offset) {
|
||||
List<Data> list = new ArrayList<>();
|
||||
if (offset < 0 || offset >= length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (baseDataType instanceof Array) {
|
||||
Array array = (Array) baseDataType;
|
||||
int elementLength = array.getElementLength();
|
||||
int index = offset / elementLength;
|
||||
list.add(getComponent(index));
|
||||
}
|
||||
else if (baseDataType instanceof Structure) {
|
||||
Structure struct = (Structure) baseDataType;
|
||||
DataTypeComponent dtc = struct.getComponentAt(offset);
|
||||
// Logic handles overlapping bit-fields
|
||||
while (dtc != null && offset <= (dtc.getOffset() + dtc.getLength() - 1)) {
|
||||
int ordinal = dtc.getOrdinal();
|
||||
list.add(getComponent(ordinal++));
|
||||
dtc = ordinal < struct.getNumComponents() ? struct.getComponent(ordinal) : null;
|
||||
}
|
||||
}
|
||||
else if (baseDataType instanceof DynamicDataType) {
|
||||
DynamicDataType ddt = (DynamicDataType) baseDataType;
|
||||
DataTypeComponent dtc = ddt.getComponentAt(offset, this);
|
||||
if (dtc != null) {
|
||||
list.add(getComponent(dtc.getOrdinal()));
|
||||
}
|
||||
}
|
||||
else if (baseDataType instanceof Union) {
|
||||
if (offset == 0) {
|
||||
for (int i = 0; i < getNumComponents(); i++) {
|
||||
list.add(getComponent(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.listing.Data#getComponentIndex()
|
||||
*/
|
||||
|
|
|
@ -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,6 +15,10 @@
|
|||
*/
|
||||
package ghidra.program.database;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
import db.*;
|
||||
import ghidra.framework.Application;
|
||||
import ghidra.framework.data.DomainObjectAdapterDB;
|
||||
import ghidra.framework.model.*;
|
||||
|
@ -31,16 +34,11 @@ import ghidra.util.exception.*;
|
|||
import ghidra.util.task.TaskMonitor;
|
||||
import ghidra.util.task.TaskMonitorAdapter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
import db.*;
|
||||
|
||||
/**
|
||||
* Database implementation for Data Type Archive.
|
||||
*/
|
||||
public class DataTypeArchiveDB extends DomainObjectAdapterDB implements DataTypeArchive,
|
||||
DataTypeArchiveChangeManager {
|
||||
public class DataTypeArchiveDB extends DomainObjectAdapterDB
|
||||
implements DataTypeArchive, DataTypeArchiveChangeManager {
|
||||
|
||||
/**
|
||||
* DB_VERSION should be incremented any time a change is made to the overall
|
||||
|
@ -80,8 +78,8 @@ public class DataTypeArchiveDB extends DomainObjectAdapterDB implements DataType
|
|||
|
||||
private final static Class<?>[] COL_CLASS = new Class[] { StringField.class };
|
||||
private final static String[] COL_TYPES = new String[] { "Value" };
|
||||
private final static Schema SCHEMA = new Schema(0, StringField.class, "Key", COL_CLASS,
|
||||
COL_TYPES);
|
||||
private final static Schema SCHEMA =
|
||||
new Schema(0, StringField.class, "Key", COL_CLASS, COL_TYPES);
|
||||
|
||||
private ProjectDataTypeManager dataTypeManager;
|
||||
|
||||
|
@ -98,8 +96,8 @@ public class DataTypeArchiveDB extends DomainObjectAdapterDB implements DataType
|
|||
* @throws InvalidNameException
|
||||
* @throws DuplicateNameException
|
||||
*/
|
||||
public DataTypeArchiveDB(DomainFolder folder, String name, Object consumer) throws IOException,
|
||||
DuplicateNameException, InvalidNameException {
|
||||
public DataTypeArchiveDB(DomainFolder folder, String name, Object consumer)
|
||||
throws IOException, DuplicateNameException, InvalidNameException {
|
||||
super(new DBHandle(), name, 500, 1000, consumer);
|
||||
this.name = name;
|
||||
|
||||
|
@ -118,7 +116,9 @@ public class DataTypeArchiveDB extends DomainObjectAdapterDB implements DataType
|
|||
endTransaction(id, true);
|
||||
clearUndo(false);
|
||||
|
||||
if (folder != null) {
|
||||
folder.createFile(name, this, TaskMonitorAdapter.DUMMY_MONITOR);
|
||||
}
|
||||
|
||||
success = true;
|
||||
}
|
||||
|
@ -136,7 +136,7 @@ public class DataTypeArchiveDB extends DomainObjectAdapterDB implements DataType
|
|||
}
|
||||
|
||||
/**
|
||||
* Constructs a new DataTypeArchivemDB
|
||||
* Constructs a new DataTypeArchiveDB
|
||||
* @param dbh a handle to an open data type archive database.
|
||||
* @param openMode one of:
|
||||
* READ_ONLY: the original database will not be modified
|
||||
|
@ -207,8 +207,8 @@ public class DataTypeArchiveDB extends DomainObjectAdapterDB implements DataType
|
|||
private void propertiesRestore() {
|
||||
Options pl = getOptions(ARCHIVE_INFO);
|
||||
boolean origChangeState = changed;
|
||||
pl.registerOption(CREATED_WITH_GHIDRA_VERSION, "4.3",
|
||||
null, "Version of Ghidra used to create this program.");
|
||||
pl.registerOption(CREATED_WITH_GHIDRA_VERSION, "4.3", null,
|
||||
"Version of Ghidra used to create this program.");
|
||||
pl.registerOption(DATE_CREATED, JANUARY_1_1970, null, "Date this program was created");
|
||||
// registerDefaultPointerSize();
|
||||
changed = origChangeState;
|
||||
|
|
|
@ -156,14 +156,15 @@ abstract public class DatabaseObject {
|
|||
* This method provides a cheap (lock free) way to test if an object is valid. If
|
||||
* this object is invalid, then the lock will be used to refresh as needed.
|
||||
* @param lock the lock that will be used if the object needs to be refreshed.
|
||||
* @return true if object is valid, else false
|
||||
*/
|
||||
public void validate(Lock lock) {
|
||||
public boolean validate(Lock lock) {
|
||||
if (!deleted && !isInvalid()) {
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
lock.acquire();
|
||||
try {
|
||||
checkIsValid();
|
||||
return checkIsValid();
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
|
|
|
@ -595,7 +595,7 @@ class ListingDB implements Listing {
|
|||
*/
|
||||
@Override
|
||||
public DataTypeManager getDataTypeManager() {
|
||||
return program.getDataManager();
|
||||
return program.getDataTypeManager();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
|
|
|
@ -30,7 +30,6 @@ import ghidra.framework.store.LockException;
|
|||
import ghidra.program.database.bookmark.BookmarkDBManager;
|
||||
import ghidra.program.database.code.CodeManager;
|
||||
import ghidra.program.database.code.InstructionDB;
|
||||
import ghidra.program.database.data.DataTypeManagerDB;
|
||||
import ghidra.program.database.data.ProgramDataTypeManager;
|
||||
import ghidra.program.database.external.ExternalManagerDB;
|
||||
import ghidra.program.database.function.FunctionManagerDB;
|
||||
|
@ -623,13 +622,6 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM
|
|||
return (TreeManager) managers[TREE_MGR];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the DataManager
|
||||
*/
|
||||
public DataTypeManagerDB getDataManager() {
|
||||
return (DataTypeManagerDB) managers[DATA_MGR];
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.listing.Program#getDataTypeManager()
|
||||
*/
|
||||
|
@ -2657,7 +2649,7 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM
|
|||
metadata.put("# of Defined Data", "" + listing.getNumDefinedData());
|
||||
metadata.put("# of Functions", "" + getFunctionManager().getFunctionCount());
|
||||
metadata.put("# of Symbols", "" + getSymbolTable().getNumSymbols());
|
||||
metadata.put("# of Data Types", "" + getDataManager().getDataTypeCount(true));
|
||||
metadata.put("# of Data Types", "" + getDataTypeManager().getDataTypeCount(true));
|
||||
metadata.put("# of Data Type Categories", "" + getDataTypeManager().getCategoryCount());
|
||||
|
||||
Options propList = getOptions(Program.PROGRAM_INFO);
|
||||
|
|
|
@ -227,7 +227,7 @@ public class CodeManager implements ErrorHandler, ManagerDB {
|
|||
contextMgr = program.getProgramContext();
|
||||
refManager = program.getReferenceManager();
|
||||
propertyMapMgr = program.getUsrPropertyManager();
|
||||
dataManager = program.getDataManager();
|
||||
dataManager = program.getDataTypeManager();
|
||||
protoMgr.setProgram(program);
|
||||
}
|
||||
|
||||
|
@ -1976,6 +1976,10 @@ public class CodeManager implements ErrorHandler, ManagerDB {
|
|||
DataDB data = null;
|
||||
try {
|
||||
|
||||
if (dataType instanceof BitFieldDataType) {
|
||||
throw new CodeUnitInsertionException("Bitfields not supported for Data");
|
||||
}
|
||||
|
||||
DataType originalDataType = dataType;
|
||||
if (dataType instanceof FactoryDataType) {
|
||||
MemBuffer memBuffer = new MemoryBufferImpl(program.getMemory(), addr);
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
package ghidra.program.database.code;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import db.Record;
|
||||
import ghidra.docking.settings.Settings;
|
||||
|
@ -66,7 +67,7 @@ class DataDB extends CodeUnitDB implements Data {
|
|||
dataType = DataType.DEFAULT;
|
||||
}
|
||||
this.dataType = dataType;
|
||||
dataMgr = program.getDataManager();
|
||||
dataMgr = program.getDataTypeManager();
|
||||
|
||||
baseDataType = getBaseDataType(dataType);
|
||||
|
||||
|
@ -554,9 +555,6 @@ class DataDB extends CodeUnitDB implements Data {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.listing.Data#getComponentAt(int)
|
||||
*/
|
||||
@Override
|
||||
public Data getComponentAt(int offset) {
|
||||
lock.acquire();
|
||||
|
@ -594,6 +592,56 @@ class DataDB extends CodeUnitDB implements Data {
|
|||
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Data> getComponentsContaining(int offset) {
|
||||
List<Data> list = new ArrayList<>();
|
||||
lock.acquire();
|
||||
try {
|
||||
checkIsValid();
|
||||
if (offset < 0 || offset >= length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (baseDataType instanceof Array) {
|
||||
Array array = (Array) baseDataType;
|
||||
int elementLength = array.getElementLength();
|
||||
int index = offset / elementLength;
|
||||
list.add(getComponent(index));
|
||||
}
|
||||
else if (baseDataType instanceof Structure) {
|
||||
Structure struct = (Structure) baseDataType;
|
||||
DataTypeComponent dtc = struct.getComponentAt(offset);
|
||||
// Logic handles overlapping bit-fields
|
||||
// Include if offset is contains within bounds of component
|
||||
while (dtc != null && (offset >= dtc.getOffset()) &&
|
||||
(offset <= (dtc.getOffset() + dtc.getLength() - 1))) {
|
||||
int ordinal = dtc.getOrdinal();
|
||||
list.add(getComponent(ordinal++));
|
||||
dtc = ordinal < struct.getNumComponents() ? struct.getComponent(ordinal) : null;
|
||||
}
|
||||
}
|
||||
else if (baseDataType instanceof DynamicDataType) {
|
||||
DynamicDataType ddt = (DynamicDataType) baseDataType;
|
||||
DataTypeComponent dtc = ddt.getComponentAt(offset, this);
|
||||
if (dtc != null) {
|
||||
list.add(getComponent(dtc.getOrdinal()));
|
||||
}
|
||||
}
|
||||
else if (baseDataType instanceof Union) {
|
||||
if (offset == 0) {
|
||||
for (int i = 0; i < getNumComponents(); i++) {
|
||||
list.add(getComponent(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.listing.Data#getComponentIndex()
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,251 @@
|
|||
/* ###
|
||||
* 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.*;
|
||||
import ghidra.program.model.data.Enum;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.exception.AssertException;
|
||||
|
||||
/**
|
||||
* <code>BitFieldDBDataType</code> extends BitFieldDataType for DataTypeManagerDB use.
|
||||
* This class provides the ability to generate a datatype ID and reconstruct a bit-field
|
||||
* datatype from an ID.
|
||||
*/
|
||||
class BitFieldDBDataType extends BitFieldDataType {
|
||||
|
||||
// Bit Field ID Encoding (expressed as the following 4-bit nibble fields): XXTTTTTTTTBBOOSS
|
||||
//
|
||||
// XX - reserved for datatype manager table ID
|
||||
// TTTTTTTT - TypeDef/Enum ID (32-bits, excludes table ID, applies to resolved TypeDef/Enum only)
|
||||
// BB - Encoded base type (8-bits, consists of the following bit fields: xttsbbbb)
|
||||
// x - 1-bit, unused
|
||||
// t - 2-bit, =0: base type only, =1:TypeDef used, =2: enum used, =3: abstract-int
|
||||
// s - 1-bit, storage +1
|
||||
// xxxx - 4-bits, unused
|
||||
// OO - bit offset (i.e., right-shift factor, relative to packing base type)
|
||||
// SS - bit field size in bits
|
||||
|
||||
private static final int BIT_OFFSET_SHIFT = 8;
|
||||
private static final int BASE_TYPE_SHIFT = 16;
|
||||
private static final int DATATYPE_INDEX_SHIFT = 24;
|
||||
|
||||
public static final long MAX_DATATYPE_INDEX = 0xffffffffL; // 32-bits
|
||||
|
||||
private static final long ID_TO_INDEX_MASK = ~-(1L << DataTypeManagerDB.DATA_TYPE_KIND_SHIFT);
|
||||
|
||||
BitFieldDBDataType(DataType baseDataType, int bitSize, int bitOffset, int storageSize,
|
||||
DataTypeManager dtm) throws InvalidDataTypeException {
|
||||
// avoid clone of baseDataType during construction
|
||||
super(baseDataType, bitSize, bitOffset, storageSize);
|
||||
}
|
||||
|
||||
private static enum BaseDatatypeKind {
|
||||
NONE(0), TYPEDEF(1), ENUM(2), INTEGER(3);
|
||||
final int id;
|
||||
|
||||
BaseDatatypeKind(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
static BaseDatatypeKind getKind(int value) {
|
||||
for (BaseDatatypeKind kind : values()) {
|
||||
if (kind.id == value) {
|
||||
return kind;
|
||||
}
|
||||
}
|
||||
return NONE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a generated ID for this bit-field which is suitable for reconstruction
|
||||
* via the {@link #getBitFieldDataType(long)} method. This ID encodes the base
|
||||
* datatype (including typedef/enum and packing data),
|
||||
* bit-size and bit-offset. The upper byte of the ID will always be zero and
|
||||
* is reserved for use by the DataTypeManager.
|
||||
* <p>
|
||||
* The ability to reference base datatypes (e.g., TypeDef, Enum) is currently limited
|
||||
* (i.e. 32-bit base datatype ID).
|
||||
* @param bitfieldDt the resolved bitfield datatype whose ID is needed. This must first be
|
||||
* resolved by a DataTypeManagerDB.
|
||||
* @return bit-field ID
|
||||
*/
|
||||
static final long getId(BitFieldDataType bitfieldDt) {
|
||||
DataTypeManager dtm = bitfieldDt.getDataTypeManager();
|
||||
if (!(dtm instanceof DataTypeManagerDB)) {
|
||||
throw new AssertException("bitfieldDt must first be resolved");
|
||||
}
|
||||
|
||||
BaseDatatypeKind dataTypeKind = BaseDatatypeKind.NONE;
|
||||
long dataTypeIndex = 0;
|
||||
DataType baseDataType = bitfieldDt.getBaseDataType();
|
||||
if (baseDataType instanceof TypeDef) {
|
||||
dataTypeKind = BaseDatatypeKind.TYPEDEF;
|
||||
}
|
||||
else if (baseDataType instanceof Enum) {
|
||||
dataTypeKind = BaseDatatypeKind.ENUM;
|
||||
}
|
||||
else if (baseDataType instanceof AbstractIntegerDataType) {
|
||||
dataTypeKind = BaseDatatypeKind.INTEGER;
|
||||
}
|
||||
if (dataTypeKind != BaseDatatypeKind.NONE) {
|
||||
dataTypeIndex = getResolvedDataTypeIndex(baseDataType, (DataTypeManagerDB) dtm);
|
||||
if (dataTypeIndex == DataTypeManager.NULL_DATATYPE_ID) {
|
||||
Msg.debug(BitFieldDBDataType.class,
|
||||
"Bit-Field data type not resolved: " + baseDataType.getName());
|
||||
dataTypeIndex = MAX_DATATYPE_INDEX;
|
||||
dataTypeKind = BaseDatatypeKind.NONE;
|
||||
}
|
||||
else if (dataTypeIndex >= MAX_DATATYPE_INDEX) {
|
||||
// TypeDef index exceeds 32-bit limit
|
||||
Msg.debug(BitFieldDBDataType.class,
|
||||
"Bit-Field data type index out of range: " + baseDataType.getName());
|
||||
dataTypeIndex = MAX_DATATYPE_INDEX;
|
||||
dataTypeKind = BaseDatatypeKind.NONE;
|
||||
}
|
||||
}
|
||||
long id = (dataTypeIndex << DATATYPE_INDEX_SHIFT) |
|
||||
(getBaseTypeEncodedField(bitfieldDt, dataTypeKind) << BASE_TYPE_SHIFT) |
|
||||
(bitfieldDt.getBitOffset() << BIT_OFFSET_SHIFT) | bitfieldDt.getDeclaredBitSize();
|
||||
return id;
|
||||
}
|
||||
|
||||
private static final long getBaseTypeEncodedField(BitFieldDataType bitFieldDt,
|
||||
BaseDatatypeKind dataTypeKind) {
|
||||
int nominalStorageSize = BitFieldDataType.getMinimumStorageSize(bitFieldDt.getBitSize());
|
||||
boolean extraStorageUsed = bitFieldDt.getStorageSize() > nominalStorageSize;
|
||||
return (dataTypeKind.id << 5) | (extraStorageUsed ? 0x10L : 0L);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a bit-field datatype instance for a given ID. The upper byte of the ID will be ignored.
|
||||
* @param id bit-field datatype ID
|
||||
* @param dtm data type manager
|
||||
* @return bit-field data type
|
||||
*/
|
||||
static final BitFieldDataType getBitFieldDataType(long id, DataTypeManager dtm) {
|
||||
|
||||
int bitSize = (int) (id & 0xff); // 8-bits
|
||||
int bitOffset = (int) ((id >> BIT_OFFSET_SHIFT) & 0xff); // 8-bits
|
||||
int baseTypeInfo = (int) ((id >> BASE_TYPE_SHIFT) & 0xff); // 8-bit encoded field
|
||||
|
||||
BaseDatatypeKind baseDataTypeKind = BaseDatatypeKind.getKind((baseTypeInfo >> 5) & 3);
|
||||
boolean extraStorageUsed = (baseTypeInfo & 0x10) != 0;
|
||||
|
||||
DataType baseDataType = null;
|
||||
long dataTypeIndex = (id >> DATATYPE_INDEX_SHIFT) & MAX_DATATYPE_INDEX; // 32-bits
|
||||
if (baseDataTypeKind != BaseDatatypeKind.NONE && dataTypeIndex != MAX_DATATYPE_INDEX) {
|
||||
if (baseDataTypeKind == BaseDatatypeKind.TYPEDEF) {
|
||||
baseDataType = getTypeDef(dataTypeIndex, dtm);
|
||||
}
|
||||
else if (baseDataTypeKind == BaseDatatypeKind.ENUM) {
|
||||
baseDataType = getEnum(dataTypeIndex, dtm);
|
||||
}
|
||||
else {
|
||||
baseDataType = getIntegerType(dataTypeIndex, dtm);
|
||||
}
|
||||
}
|
||||
try {
|
||||
if (baseDataType == null) {
|
||||
// use integer datatype on failure
|
||||
baseDataType = IntegerDataType.dataType.clone(dtm);
|
||||
}
|
||||
int effectiveBitSize = getEffectiveBitSize(bitSize, baseDataType.getLength());
|
||||
int storageSize = getMinimumStorageSize(effectiveBitSize);
|
||||
if (extraStorageUsed) {
|
||||
++storageSize;
|
||||
}
|
||||
return new BitFieldDBDataType(baseDataType, bitSize, bitOffset, storageSize, dtm);
|
||||
}
|
||||
catch (InvalidDataTypeException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static final long getResolvedDataTypeIndex(DataType dataType, DataTypeManagerDB dtm) {
|
||||
|
||||
long dataTypeId = dtm.getID(dataType);
|
||||
if (dataTypeId == DataTypeManager.NULL_DATATYPE_ID) {
|
||||
return DataTypeManager.NULL_DATATYPE_ID;
|
||||
}
|
||||
return dataTypeId & ID_TO_INDEX_MASK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the TypeDef which corresponds to the specified typeDefIndex and the
|
||||
* specified data type manager.
|
||||
* @param typeDefIndex base data type index used by bit-field
|
||||
* @param primitiveBaseDataType expected primitive base datatype
|
||||
* @param dtm data type manager
|
||||
* @return TypeDef data type or null if not found
|
||||
*/
|
||||
private static final TypeDef getTypeDef(long typeDefIndex, DataTypeManager dtm) {
|
||||
long dataTypeId =
|
||||
((long) DataTypeManagerDB.TYPEDEF << DataTypeManagerDB.DATA_TYPE_KIND_SHIFT) |
|
||||
typeDefIndex;
|
||||
DataType dataType = dtm.getDataType(dataTypeId);
|
||||
if (!(dataType instanceof TypeDef)) {
|
||||
return null;
|
||||
}
|
||||
TypeDef typeDefDt = (TypeDef) dataType;
|
||||
DataType dt = typeDefDt.getBaseDataType();
|
||||
if (dt instanceof Enum) {
|
||||
// TODO: how restrictive should we be on matching enum size?
|
||||
return typeDefDt;
|
||||
}
|
||||
if (dt instanceof AbstractIntegerDataType) {
|
||||
return typeDefDt;
|
||||
}
|
||||
return null; // unsupported typedef
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Enum which corresponds to the specified enumIndex and the
|
||||
* specified data type manager.
|
||||
* @param enumIndex enum data type index used by bit-field
|
||||
* @param dtm data type manager
|
||||
* @return Enum data type or null if not found
|
||||
*/
|
||||
private static final Enum getEnum(long enumIndex, DataTypeManager dtm) {
|
||||
long dataTypeId =
|
||||
((long) DataTypeManagerDB.ENUM << DataTypeManagerDB.DATA_TYPE_KIND_SHIFT) | enumIndex;
|
||||
DataType dataType = dtm.getDataType(dataTypeId);
|
||||
if (!(dataType instanceof Enum)) {
|
||||
return null;
|
||||
}
|
||||
return (Enum) dataType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the integer base type which corresponds to the specified intTypeIndex and the
|
||||
* specified data type manager.
|
||||
* @param intTypeIndex base data type index used by bit-field
|
||||
* @param dtm data type manager
|
||||
* @return integer data type or null if not found
|
||||
*/
|
||||
private static final AbstractIntegerDataType getIntegerType(long intTypeIndex,
|
||||
DataTypeManager dtm) {
|
||||
long dataTypeId =
|
||||
((long) DataTypeManagerDB.BUILT_IN << DataTypeManagerDB.DATA_TYPE_KIND_SHIFT) |
|
||||
intTypeIndex;
|
||||
DataType dataType = dtm.getDataType(dataTypeId);
|
||||
if (!(dataType instanceof AbstractIntegerDataType)) {
|
||||
return null;
|
||||
}
|
||||
return (AbstractIntegerDataType) dataType;
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue