Bitfields - added simple bitfield viewer and corrected missing support

for bitfields and flex arrays
This commit is contained in:
ghidra1 2019-06-05 18:26:57 -04:00
parent 52f6bfc127
commit 31163bca26
26 changed files with 747 additions and 233 deletions

View file

@ -23,6 +23,7 @@ import javax.swing.SwingUtilities;
import docking.ActionContext;
import docking.DockingWindowManager;
import ghidra.program.model.data.Structure;
import ghidra.util.exception.AssertException;
/**
@ -76,7 +77,8 @@ public class AddBitFieldAction extends CompositeEditorTableAction {
public void adjustEnablement() {
boolean enabled = true;
CompEditorModel editorModel = (CompEditorModel) model;
if (editorModel.viewComposite == null || editorModel.isAligned() ||
// Union do not support unaligned placement of bitfields
if (!(editorModel.viewComposite instanceof Structure) || editorModel.isAligned() ||
editorModel.getNumSelectedRows() != 1 || editorModel.isFlexibleArraySelection()) {
enabled = false;
}

View file

@ -20,15 +20,12 @@ import java.awt.event.MouseEvent;
import javax.swing.Icon;
import javax.swing.JComponent;
import docking.*;
import docking.ActionContext;
import docking.DialogComponentProvider;
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 {
@ -93,7 +90,7 @@ public class BitFieldEditorDialog extends DialogComponentProvider {
if (bitfieldDtc == null || !bitFieldEditorPanel.endCurrentEdit()) {
return;
}
initEdit(bitfieldDtc.getOrdinal());
initEdit(bitfieldDtc.getOrdinal(), true);
}
@Override
@ -200,7 +197,7 @@ public class BitFieldEditorDialog extends DialogComponentProvider {
initAdd(-editOrdinal - 1);
}
else {
initEdit(editOrdinal);
initEdit(editOrdinal, false);
}
return bitFieldEditorPanel;
}
@ -234,16 +231,19 @@ public class BitFieldEditorDialog extends DialogComponentProvider {
setApplyEnabled(true);
}
private void initEdit(int editOrdinal) throws ArrayIndexOutOfBoundsException {
private void initEdit(int editOrdinal, boolean useExistingAllocationSize)
throws ArrayIndexOutOfBoundsException {
DataTypeComponent dtc = composite.getComponent(editOrdinal);
if (!dtc.isBitFieldComponent()) {
throw new IllegalArgumentException("editOrdinal does not correspond to bitfield");
}
bitFieldEditorPanel.initEdit(dtc, getPreferredAllocationOffset(dtc));
bitFieldEditorPanel.initEdit(dtc, getPreferredAllocationOffset(dtc),
useExistingAllocationSize);
setApplyEnabled(true);
}
private int getPreferredAllocationOffset(DataTypeComponent bitfieldDtc) {
static int getPreferredAllocationOffset(DataTypeComponent bitfieldDtc) {
Composite composite = (Composite) bitfieldDtc.getParent();
if (composite instanceof Union) {
return 0;
}
@ -270,34 +270,4 @@ public class BitFieldEditorDialog extends DialogComponentProvider {
return offset;
}
public static void main(String[] args) throws Exception {
//UniversalIdGenerator.initialize();
ApplicationConfiguration configuration = new HeadlessGhidraApplicationConfiguration();
configuration.setInitializeLogging(false);
Application.initializeApplication(new GhidraApplicationLayout(), configuration);
Structure s = new StructureDataType("Foo", 0);
DataTypeComponent dtcA =
s.insertBitFieldAt(0, 4, 16, IntegerDataType.dataType, 4, "BitA", null);
DataTypeComponent dtcZ =
s.insertBitFieldAt(0, 4, 16, IntegerDataType.dataType, 0, "BitZ", null);
DataTypeComponent dtcB =
s.insertBitFieldAt(0, 4, 12, IntegerDataType.dataType, 4, "BitB", null);
DataTypeComponent dtcC =
s.insertBitFieldAt(0, 4, 4, IntegerDataType.dataType, 4, "BitC", null);
DockingWindowManager winMgr = new DockingWindowManager("TEST", null, null);
BitFieldEditorDialog dlg =
new BitFieldEditorDialog(s, new DefaultDataTypeManagerService(), -1, null);
SystemUtilities.runSwingNow(() -> {
winMgr.setVisible(true);
DockingWindowManager.showDialog(null, dlg);
});
}
}

View file

@ -39,8 +39,8 @@ import ghidra.util.layout.*;
import resources.ResourceManager;
/**
* <code>BitFieldEditorPanel</code> provides the ability to place bitfields
* within unaligned structures and unions.
* <code>BitFieldEditorPanel</code> provides the ability to add or modify bitfields
* within unaligned structures.
*/
public class BitFieldEditorPanel extends JPanel {
@ -100,7 +100,7 @@ public class BitFieldEditorPanel extends JPanel {
private JPanel createLegendPanel() {
JPanel legendPanel = new JPanel(new BorderLayout());
legendPanel.add(new BitFieldPlacementComponent.BitFieldLegend(), BorderLayout.WEST);
legendPanel.add(new BitFieldPlacementComponent.BitFieldLegend(null), BorderLayout.WEST);
return legendPanel;
}
@ -390,15 +390,19 @@ public class BitFieldEditorPanel extends JPanel {
* If null an allocation size of 4-bytes will be used but may be adjusted.
* @param bitfieldDtc bitfield component or null
* @param allocationOffset allocation offset to be used
* @param useExistingAllocationSize if true attempt to use existing allocation size
*/
void initEdit(DataTypeComponent bitfieldDtc, int allocationOffset) {
void initEdit(DataTypeComponent bitfieldDtc, int allocationOffset,
boolean useExistingAllocationSize) {
String initialFieldName = null;
DataType initialBaseDataType = null;
int allocationSize = -1;
if (useExistingAllocationSize) {
BitFieldAllocation bitFieldAllocation = placementComponent.getBitFieldAllocation();
if (bitFieldAllocation != null) {
allocationSize = bitFieldAllocation.getAllocationByteSize();
}
}
if (bitfieldDtc != null) {
if (!bitfieldDtc.isBitFieldComponent()) {
throw new IllegalArgumentException("unsupport data type component");
@ -420,7 +424,7 @@ public class BitFieldEditorPanel extends JPanel {
// TODO: adjust offset and allocationSize if needed
placementComponent.setAllocationOffset(allocationOffset);
placementComponent.init(allocationSize, bitfieldDtc);
bitFieldAllocation = placementComponent.getBitFieldAllocation(); // get updated instance
BitFieldAllocation bitFieldAllocation = placementComponent.getBitFieldAllocation(); // get updated instance
initControls(initialFieldName, initialBaseDataType, bitFieldAllocation.getBitSize());
enableControls(bitfieldDtc != null);
}

View file

@ -26,6 +26,7 @@ import ghidra.program.model.data.*;
import ghidra.program.model.data.Composite;
import ghidra.util.Msg;
import ghidra.util.exception.AssertException;
import ghidra.util.layout.VerticalLayout;
import resources.icons.ColorIcon;
public class BitFieldPlacementComponent extends JPanel {
@ -59,28 +60,51 @@ public class BitFieldPlacementComponent extends JPanel {
private EditMode editMode = EditMode.NONE;
private int editOrdinal = -1; // FIXME: improve insert use
private DataTypeComponent editComponent;
public static class BitFieldLegend extends JPanel {
BitFieldLegend() {
setLayout(new GridLayout(2, 3, 5, 5));
//setLayout(new RowColumnLayout(10, 10, RowColumnLayout.ROW, 0));
add(new JLabel("Undefined bits",
new ColorIcon(UNDEFINED_BIT_COLOR, INTERIOR_LINE_COLOR, LENEND_BOX_SIZE),
SwingConstants.LEFT));
add(new JLabel("Defined bitfield",
new ColorIcon(BITFIELD_COMPONENT_COLOR, INTERIOR_LINE_COLOR, LENEND_BOX_SIZE),
SwingConstants.LEFT));
add(new JLabel("Defined non-bitfield",
new ColorIcon(NON_BITFIELD_COMPONENT_COLOR, INTERIOR_LINE_COLOR, LENEND_BOX_SIZE),
SwingConstants.LEFT));
add(new JLabel("Edit bitfield bits",
BitFieldLegend(DataTypeComponent viewedBitfield) {
JPanel legendPanel;
if (viewedBitfield != null) {
setLayout(new VerticalLayout(10));
legendPanel = new JPanel(new GridLayout(1, 3, 5, 5));
String viewComponentText =
"Selected bitfield { " + viewedBitfield.getDataType().getDisplayName();
String viewComponentName = viewedBitfield.getFieldName();
if (viewComponentName != null) {
viewComponentText += " " + viewComponentName;
}
viewComponentText += " }";
add(new JLabel(viewComponentText,
new ColorIcon(BITFIELD_BITS_COLOR, INTERIOR_LINE_COLOR, LENEND_BOX_SIZE),
SwingConstants.LEFT));
add(new JLabel("Conflict bits",
add(legendPanel);
}
else {
setLayout(new GridLayout(2, 3, 5, 5));
legendPanel = this;
}
legendPanel.add(new JLabel("Defined bitfield",
new ColorIcon(BITFIELD_COMPONENT_COLOR, INTERIOR_LINE_COLOR, LENEND_BOX_SIZE),
SwingConstants.LEFT));
legendPanel.add(new JLabel("Defined non-bitfield ",
new ColorIcon(NON_BITFIELD_COMPONENT_COLOR, INTERIOR_LINE_COLOR, LENEND_BOX_SIZE),
SwingConstants.LEFT));
legendPanel.add(new JLabel("Undefined bits",
new ColorIcon(UNDEFINED_BIT_COLOR, INTERIOR_LINE_COLOR, LENEND_BOX_SIZE),
SwingConstants.LEFT));
if (viewedBitfield == null) {
legendPanel.add(new JLabel("Edit bitfield bits",
new ColorIcon(BITFIELD_BITS_COLOR, INTERIOR_LINE_COLOR, LENEND_BOX_SIZE),
SwingConstants.LEFT));
legendPanel.add(new JLabel("Conflict bits",
new ColorIcon(CONFLICT_BITS_COLOR, INTERIOR_LINE_COLOR, LENEND_BOX_SIZE),
SwingConstants.LEFT));
}
}
}
@ -127,7 +151,8 @@ public class BitFieldPlacementComponent extends JPanel {
}
void refresh(int allocationByteSize, int bitSize, int bitOffset) {
bitFieldAllocation = new BitFieldAllocation(allocationByteSize, bitSize, bitOffset);
bitFieldAllocation =
new BitFieldAllocation(allocationByteSize, bitSize, bitOffset, editComponent);
updatePreferredSize();
repaint();
}
@ -147,14 +172,16 @@ public class BitFieldPlacementComponent extends JPanel {
void initAdd(int allocationByteSize, int bitSize, int bitOffset) {
editMode = EditMode.ADD;
editOrdinal = -1;
editComponent = null;
refresh(allocationByteSize, bitSize, bitOffset);
}
void init(int allocationByteSize, DataTypeComponent editComponent) {
void init(int allocationByteSize, DataTypeComponent editDtc) {
if (editComponent == null) {
if (editDtc == null) {
editMode = EditMode.NONE;
editOrdinal = -1;
this.editComponent = null;
refresh(allocationByteSize, 0, 0);
return;
}
@ -163,12 +190,13 @@ public class BitFieldPlacementComponent extends JPanel {
// of the component being modified
editMode = EditMode.EDIT;
editOrdinal = editComponent.getOrdinal();
editOrdinal = editDtc.getOrdinal();
this.editComponent = editDtc;
BitFieldPlacement placement = new BitFieldPlacement(editComponent, allocationByteSize);
BitFieldPlacement placement = new BitFieldPlacement(editDtc, allocationByteSize);
bitFieldAllocation =
new BitFieldAllocation(allocationByteSize, placement.rightBit - placement.leftBit + 1,
(8 * allocationByteSize) - placement.rightBit - 1);
(8 * allocationByteSize) - placement.rightBit - 1, editDtc);
updatePreferredSize();
repaint();
}
@ -213,6 +241,7 @@ public class BitFieldPlacementComponent extends JPanel {
// unexpected removal
editMode = EditMode.ADD;
editOrdinal = -1;
editComponent = null;
}
else if (ordinal < editOrdinal) {
--editOrdinal;
@ -268,6 +297,7 @@ public class BitFieldPlacementComponent extends JPanel {
finally {
editMode = EditMode.NONE;
editOrdinal = -1;
editComponent = null;
bitFieldAllocation.refresh();
repaint();
}
@ -475,18 +505,21 @@ public class BitFieldPlacementComponent extends JPanel {
private final int bitSize;
private final int bitOffset;
private boolean hasConflict;
private DataTypeComponent editComponent;
// 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) {
BitFieldAllocation(int allocationByteSize, int bitSize, int bitOffset,
DataTypeComponent editComponent) {
if (allocationByteSize <= 0 || (bitSize + bitOffset) > (8 * allocationByteSize)) {
throw new IllegalArgumentException("allocation size too small");
}
this.allocationByteSize = allocationByteSize;
this.bitSize = bitSize;
this.bitOffset = bitOffset;
this.editComponent = editComponent;
refresh();
}
@ -505,11 +538,11 @@ public class BitFieldPlacementComponent extends JPanel {
if (editMode != EditMode.NONE) {
int rightMostBit = bitAttributes.length - bitOffset - 1;
if (bitSize == 0) {
allocateZeroBitField(null, rightMostBit);
allocateZeroBitField(editComponent, rightMostBit);
}
else {
int leftMostBit = rightMostBit - bitSize + 1;
allocateBits(null, leftMostBit, rightMostBit, false, false);
allocateBits(editComponent, leftMostBit, rightMostBit, false, false);
}
}
@ -741,7 +774,7 @@ public class BitFieldPlacementComponent extends JPanel {
if (zeroBitfield) {
return UNDEFINED_BIT_COLOR;
}
if (dtc == null) {
if (dtc == editComponent) {
return BITFIELD_BITS_COLOR; // edit field
}
return dtc.isBitFieldComponent() ? BITFIELD_COMPONENT_COLOR

View file

@ -0,0 +1,56 @@
/* ###
* 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 javax.swing.JComponent;
import docking.DialogComponentProvider;
import ghidra.program.model.data.*;
public class BitFieldViewerDialog extends DialogComponentProvider {
BitFieldViewerDialog(Composite composite, int editOrdinal) {
super("View " + getCompositeType(composite) + " Bitfield");
addButtons();
addWorkPanel(buildWorkPanel(composite, editOrdinal));
setRememberLocation(false);
setRememberSize(false);
}
private void addButtons() {
addCancelButton();
setCancelButtonText("Close");
}
private JComponent buildWorkPanel(Composite composite, int viewOrdinal) {
if (viewOrdinal < 0 || viewOrdinal >= composite.getNumComponents()) {
throw new IllegalArgumentException("invalid composite ordinal");
}
DataTypeComponent dtc = composite.getComponent(viewOrdinal);
if (!dtc.isBitFieldComponent()) {
throw new IllegalArgumentException("editOrdinal does not correspond to bitfield");
}
return new BitFieldViewerPanel(dtc, BitFieldEditorDialog.getPreferredAllocationOffset(dtc));
}
private static String getCompositeType(Composite composite) {
// currently supports unaligned case only!
String alignmentMode = composite.isInternallyAligned() ? "Aligned" : "Unaligned";
String type = (composite instanceof Union) ? "Union" : "Structure";
return alignmentMode + " " + type;
}
}

View file

@ -0,0 +1,143 @@
/* ###
* 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.BorderLayout;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import ghidra.program.model.data.*;
import ghidra.util.layout.*;
/**
* <code>BitFieldViewerPanel</code> provides the ability to examine bitfield placement
* within structures.
* TODO: consider using as a hover panel
*/
public class BitFieldViewerPanel extends JPanel {
private Composite composite;
private DataTypeComponent bitfieldDtc;
private JLabel allocationOffsetLabel;
private BitFieldPlacementComponent placementComponent;
BitFieldViewerPanel(DataTypeComponent bitfieldDtc, int allocationOffset) {
super();
this.bitfieldDtc = bitfieldDtc;
this.composite = (Composite) bitfieldDtc.getParent();
setLayout(new VerticalLayout(5));
setFocusTraversalKeysEnabled(true);
setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
if (composite instanceof Structure) {
add(createAllocationOffsetPanel());
}
add(createPlacementPanel());
add(createLegendPanel());
initView(allocationOffset);
}
private JPanel createLegendPanel() {
JPanel legendPanel = new JPanel(new BorderLayout());
legendPanel.add(new BitFieldPlacementComponent.BitFieldLegend(bitfieldDtc),
BorderLayout.WEST);
return legendPanel;
}
private JPanel createAllocationOffsetPanel() {
JPanel panel = new JPanel(new HorizontalLayout(5));
allocationOffsetLabel = new JLabel();
allocationOffsetLabel.setHorizontalTextPosition(SwingConstants.LEFT);
panel.add(allocationOffsetLabel);
return panel;
}
private void updateAllocationOffsetLabel() {
if (composite instanceof Structure) {
String text =
"Structure Offset of Allocation Unit: " + placementComponent.getAllocationOffset();
allocationOffsetLabel.setText(text);
}
}
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"));
JPanel p = new JPanel(new BorderLayout());
p.add(placementComponent, BorderLayout.WEST);
p.setBorder(new EmptyBorder(0, 0, 5, 0));
JScrollPane scrollPane = new JScrollPane(p, ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER,
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
scrollPane.getViewport().setBackground(getBackground());
scrollPane.setBorder(null);
midPanel.add(scrollPane);
return midPanel;
}
/**
* 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 allocationOffset allocation offset to be used
* @param useExistingAllocationSize if true attempt to use existing allocation size
*/
private void initView(int allocationOffset) {
DataType initialBaseDataType = null;
int allocationSize = -1;
if (bitfieldDtc != null) {
if (!bitfieldDtc.isBitFieldComponent()) {
throw new IllegalArgumentException("unsupport data type component");
}
BitFieldDataType bitfieldDt = (BitFieldDataType) bitfieldDtc.getDataType();
initialBaseDataType = bitfieldDt.getBaseDataType();
if (allocationSize < 1) {
allocationSize = initialBaseDataType.getLength();
}
int allocationAdjust = composite.getLength() - allocationOffset - allocationSize;
if (allocationAdjust < 0) {
allocationSize += allocationAdjust;
}
}
if (allocationSize < 1) {
allocationSize = 4;
}
placementComponent.setAllocationOffset(allocationOffset);
placementComponent.init(allocationSize, bitfieldDtc);
updateAllocationOffsetLabel();
}
}

View file

@ -1231,4 +1231,11 @@ public abstract class CompositeEditorModel extends CompositeViewerModel implemen
throw new DuplicateNameException("Data type named " + name + " already exists");
}
}
/**
* @return true if presence of bitfields is supported, else false
*/
protected boolean bitfieldsSupported() {
return (viewComposite instanceof Structure) || (viewComposite instanceof Union);
}
}

View file

@ -45,10 +45,7 @@ import docking.widgets.label.GLabel;
import docking.widgets.table.GTable;
import docking.widgets.table.GTableCellRenderer;
import docking.widgets.textfield.GValidatedTextField;
import ghidra.app.plugin.core.data.DataTypeCellRenderer;
import ghidra.app.plugin.core.datamgr.archive.SourceArchive;
import ghidra.app.services.DataTypeManagerService;
import ghidra.app.util.ToolTipUtils;
import ghidra.app.util.datatype.DataTypeSelectionEditor;
import ghidra.app.util.datatype.NavigationDirection;
import ghidra.framework.plugintool.Plugin;
@ -144,7 +141,8 @@ public abstract class CompositeEditorPanel extends JPanel
private void setupTableCellRenderer() {
GTableCellRenderer cellRenderer = new GTableCellRenderer();
DataTypeCellRenderer dtiCellRenderer = new DataTypeCellRenderer();
DataTypeCellRenderer dtiCellRenderer = new DataTypeCellRenderer(
model.getOriginalDataTypeManager(), model.bitfieldsSupported());
table.setDefaultRenderer(String.class, cellRenderer);
table.setDefaultRenderer(DataTypeInstance.class, dtiCellRenderer);
}
@ -558,6 +556,12 @@ public abstract class CompositeEditorPanel extends JPanel
table = new CompositeTable(model);
table.putClientProperty("JTable.autoStartsEdit", Boolean.FALSE);
table.addMouseListener(new CompositeTableMouseListener());
if (model.bitfieldsSupported()) {
CompositeTableCellMouseListener cellMouseListener =
new CompositeTableCellMouseListener();
table.addMouseListener(cellMouseListener);
table.addMouseMotionListener(cellMouseListener);
}
CompositeEditorTableAction action = provider.actionMgr.getNamedAction(
CompositeEditorTableAction.EDIT_ACTION_PREFIX + EditFieldAction.ACTION_NAME);
@ -1402,6 +1406,85 @@ public abstract class CompositeEditorPanel extends JPanel
}
}
private class CompositeTableCellMouseListener extends MouseAdapter {
private boolean trackMovement;
private Cursor originalCursor;
private boolean pointerCursorActive;
@Override
public void mouseExited(MouseEvent e) {
trackMovement = false;
table.setCursor(originalCursor);
}
@Override
public void mouseEntered(MouseEvent e) {
trackMovement = true;
originalCursor = table.getCursor();
}
@Override
public void mouseClicked(MouseEvent e) {
if (!pointerCursorActive || e.getClickCount() != 1) {
return;
}
Point p = e.getPoint();
int columnIndex = table.columnAtPoint(p);
int rowIndex = table.rowAtPoint(p);
if ((columnIndex == -1) || (rowIndex == -1)) {
return;
}
DataTypeComponent dtc = model.getComponent(rowIndex);
if (dtc != null && dtc.isBitFieldComponent()) {
e.consume();
BitFieldViewerDialog dlg =
new BitFieldViewerDialog(model.viewComposite, dtc.getOrdinal());
Rectangle cellRect = table.getCellRect(rowIndex, columnIndex, false);
Point xyPoint = new Point(cellRect.x + DataTypeCellRenderer.ICON_WIDTH,
cellRect.y + cellRect.height);
SwingUtilities.convertPointToScreen(xyPoint, table);
dlg.setInitialLocation(xyPoint.x, xyPoint.y);
Window w = SwingUtilities.windowForComponent(table);
DockingWindowManager.showDialog(w, dlg, table);
}
}
@Override
public void mouseMoved(MouseEvent e) {
if (!trackMovement) {
return;
}
Point p = e.getPoint();
// Locate the renderer under the event location
int columnIndex = table.columnAtPoint(p);
int rowIndex = table.rowAtPoint(p);
if ((columnIndex != -1) && (rowIndex != -1) &&
DataTypeInstance.class.equals(table.getColumnClass(columnIndex))) {
DataTypeComponent dtc = model.getComponent(rowIndex);
// ignore non-bitfield rows
if (dtc != null && dtc.isBitFieldComponent()) {
Rectangle cellRect = table.getCellRect(rowIndex, columnIndex, false);
p.translate(-cellRect.x, -cellRect.y);
if (p.x <= (DataTypeCellRenderer.ICON_WIDTH + 2)) {
if (!pointerCursorActive) {
pointerCursorActive = true;
table.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
}
return; // view bitfield cursor active
}
}
}
if (pointerCursorActive) {
table.setCursor(originalCursor);
pointerCursorActive = false;
}
}
}
private class CompositeTableMouseListener extends MouseAdapter {
@Override
public void mouseReleased(MouseEvent e) {
@ -1473,69 +1556,6 @@ public abstract class CompositeEditorPanel extends JPanel
super(dm);
}
// Use the contains method to set the tooltip text depending
// on the table cell the mouse is over.
@Override
public boolean contains(int x, int y) {
if (!super.contains(x, y)) {
return false;
}
Point p = new Point(x, y);
int columnIndex = columnAtPoint(p);
int rowIndex = rowAtPoint(p);
String toolTipText = null;
Object value = model.getValueAt(rowIndex, columnIndex);
if (columnIndex == model.getDataTypeColumn()) {
if (value instanceof DataTypeInstance) {
DataTypeInstance dataTypeInstance = (DataTypeInstance) value;
toolTipText = getDataTypeToolTip(dataTypeInstance.getDataType());
}
}
else if (value instanceof String) {
String string = (String) value;
if (string.length() == 0) {
string = null;
}
toolTipText = string;
}
String currentToolTipText = getToolTipText();
if (!SystemUtilities.isEqual(toolTipText, currentToolTipText)) {
setToolTipText(toolTipText);
}
return true;
}
private String getDataTypeToolTip(DataType dataType) {
DataTypeManager dataTypeManager = dataType.getDataTypeManager();
// This checks for null dataTypeManager below since BadDataType won't have one.
SourceArchive sourceArchive = dataType.getSourceArchive();
DataTypeManager originalDTM = model.getOriginalDataTypeManager();
boolean localSource =
(sourceArchive == null) || ((dataTypeManager != null) && SystemUtilities.isEqual(
dataTypeManager.getUniversalID(), sourceArchive.getSourceArchiveID()));
if (localSource) {
sourceArchive = originalDTM.getSourceArchive(originalDTM.getUniversalID());
}
DataType foundDataType = originalDTM.getDataType(dataType.getDataTypePath());
String displayName = "";
if (foundDataType != null && (dataTypeManager != null)) {
displayName = dataTypeManager.getName();
}
displayName += dataType.getPathName();
if (!localSource) {
displayName += " (" + sourceArchive.getName() + ")";
}
displayName = HTMLUtilities.friendlyEncodeHTML(displayName);
String toolTipText = ToolTipUtils.getToolTipText(dataType);
String headerText = "<HTML><b>" + displayName + "</b><BR>";
toolTipText = toolTipText.replace("<HTML>", headerText);
return toolTipText;
}
@Override
// overridden because the editor component was not being given focus
public Component prepareEditor(TableCellEditor editor, int row, int column) {

View file

@ -0,0 +1,129 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.plugin.core.compositeeditor;
import java.awt.Color;
import java.awt.Component;
import javax.swing.*;
import docking.widgets.table.GTableCellRenderer;
import docking.widgets.table.GTableCellRenderingData;
import ghidra.app.plugin.core.datamgr.archive.SourceArchive;
import ghidra.app.util.ToolTipUtils;
import ghidra.program.model.data.*;
import ghidra.util.HTMLUtilities;
import ghidra.util.SystemUtilities;
import resources.ResourceManager;
import resources.icons.IconWrapper;
import resources.icons.ScaledImageIconWrapper;
public class DataTypeCellRenderer extends GTableCellRenderer {
private static final long serialVersionUID = 1L;
static final int ICON_WIDTH = 12;
static final int ICON_HEIGHT = 12;
public static final Icon MAGNIFIER_ICON = new IconWrapper() {
@Override
protected Icon createIcon() {
ImageIcon viewBitfieldIcon = ResourceManager.loadImage("images/magnifier.png");
ScaledImageIconWrapper scaledViewBitfieldIcon =
new ScaledImageIconWrapper(viewBitfieldIcon, ICON_WIDTH, ICON_HEIGHT);
return scaledViewBitfieldIcon;
}
};
private DataTypeManager originalDTM;
private boolean includeViewBitfieldIcon;
public DataTypeCellRenderer(DataTypeManager originalDataTypeManager,
boolean includeViewBitfieldIcon) {
this.originalDTM = originalDataTypeManager;
this.includeViewBitfieldIcon = includeViewBitfieldIcon;
}
@Override
public Component getTableCellRendererComponent(GTableCellRenderingData data) {
Object value = data.getValue();
String dtString = "";
String tooltipText = null;
boolean useRed = false;
DataType dt = null;
if (value instanceof DataTypeInstance) {
dt = ((DataTypeInstance) value).getDataType();
tooltipText = getDataTypeToolTip(dt);
dtString = dt.getDisplayName();
if (dt.isNotYetDefined()) {
useRed = true;
}
}
GTableCellRenderingData renderData = data.copyWithNewValue(dtString);
JLabel c = (JLabel) super.getTableCellRendererComponent(renderData);
c.setToolTipText(tooltipText);
if (useRed) {
c.setForeground(Color.RED);
}
c.setHorizontalTextPosition(RIGHT);
c.setIcon(null);
if (includeViewBitfieldIcon && (dt instanceof BitFieldDataType)) {
// add inspect icon and action listener
c.setIcon(MAGNIFIER_ICON);
}
return c;
}
private String getDataTypeToolTip(DataType dataType) {
DataTypeManager dataTypeManager = dataType.getDataTypeManager();
// This checks for null dataTypeManager below since BadDataType won't have one.
SourceArchive sourceArchive = dataType.getSourceArchive();
boolean localSource = (sourceArchive == null) ||
((dataTypeManager != null) && SystemUtilities.isEqual(dataTypeManager.getUniversalID(),
sourceArchive.getSourceArchiveID()));
if (localSource) {
sourceArchive = originalDTM.getSourceArchive(originalDTM.getUniversalID());
}
DataType foundDataType = originalDTM.getDataType(dataType.getDataTypePath());
String displayName = "";
if (foundDataType != null && (dataTypeManager != null)) {
displayName = dataTypeManager.getName();
}
displayName += dataType.getPathName();
if (!localSource) {
displayName += " (" + sourceArchive.getName() + ")";
}
displayName = HTMLUtilities.friendlyEncodeHTML(displayName);
String toolTipText = ToolTipUtils.getToolTipText(dataType);
String headerText = "<HTML><b>" + displayName + "</b><BR>";
toolTipText = toolTipText.replace("<HTML>", headerText);
return toolTipText;
}
}

View file

@ -71,7 +71,8 @@ public class StructureEditorProvider extends CompositeEditorProvider {
new HexNumbersAction(this),
new CreateInternalStructureAction(this),
new AddBitFieldAction(this),
new EditBitFieldAction(this)
new EditBitFieldAction(this),
// new ViewBitFieldAction(this)
};
//@formatter:on
}

View file

@ -0,0 +1,87 @@
/* ###
* 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.SwingUtilities;
import docking.ActionContext;
import docking.DockingWindowManager;
import ghidra.program.model.data.DataTypeComponent;
import ghidra.program.model.data.Structure;
import ghidra.util.exception.AssertException;
/**
* Action for use in the composite data type editor.
* This action has help associated with it.
*/
public class ViewBitFieldAction extends CompositeEditorTableAction {
private final static String ACTION_NAME = "View Bitfield";
private final static String GROUP_NAME = BITFIELD_ACTION_GROUP;
private final static String DESCRIPTION = "View an existing bitfield";
private static String[] popupPath = new String[] { ACTION_NAME };
public ViewBitFieldAction(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();
}
private DataTypeComponent getBitFieldComponent() {
CompEditorModel editorModel = (CompEditorModel) model;
if ((editorModel.viewComposite instanceof Structure) &&
editorModel.getNumSelectedRows() == 1) {
int rowIndex = model.getSelectedRows()[0];
if (rowIndex < model.getNumComponents()) {
DataTypeComponent dtComponent = model.getComponent(rowIndex);
if (dtComponent.isBitFieldComponent()) {
return dtComponent;
}
}
}
return null;
}
@Override
public void actionPerformed(ActionContext context) {
CompEditorModel editorModel = (CompEditorModel) model;
DataTypeComponent dtComponent = getBitFieldComponent();
if (dtComponent == null) {
return;
}
BitFieldViewerDialog dlg =
new BitFieldViewerDialog(editorModel.viewComposite, dtComponent.getOrdinal());
Component c = provider.getComponent();
Window w = SwingUtilities.windowForComponent(c);
DockingWindowManager.showDialog(w, dlg, c);
requestTableFocus();
}
@Override
public void adjustEnablement() {
setEnabled(getBitFieldComponent() != null);
}
}

View file

@ -1,55 +0,0 @@
/* ###
* 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.data;
import java.awt.Color;
import java.awt.Component;
import docking.widgets.table.GTableCellRenderer;
import docking.widgets.table.GTableCellRenderingData;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.DataTypeInstance;
public class DataTypeCellRenderer extends GTableCellRenderer {
private static final long serialVersionUID = 1L;
@Override
public Component getTableCellRendererComponent(GTableCellRenderingData data) {
Object value = data.getValue();
String dtString = "";
boolean useRed = false;
if (value instanceof DataTypeInstance) {
DataType dt = ((DataTypeInstance) value).getDataType();
dtString = dt.getDisplayName();
if (dt.isNotYetDefined()) {
useRed = true;
}
}
GTableCellRenderingData renderData = data.copyWithNewValue(dtString);
Component c =
super.getTableCellRendererComponent(renderData);
if (useRed) {
c.setForeground(Color.RED);
}
return c;
}
}

View file

@ -95,6 +95,9 @@ public class FindReferencesToFieldAction extends DockingAction {
DataTypeComponent[] components = composite.getComponents();
List<String> names = new ArrayList<>();
for (DataTypeComponent dataTypeComponent : components) {
if (dataTypeComponent.isBitFieldComponent()) {
continue;
}
String fieldName = dataTypeComponent.getFieldName();
if (StringUtils.isBlank(fieldName)) {
continue;

View file

@ -92,6 +92,9 @@ public class ToolTipUtils {
else if (dataType instanceof Array) {
return new ArrayDataTypeHTMLRepresentation((Array) dataType);
}
else if (dataType instanceof BitFieldDataType) {
return new BitFieldDataTypeHTMLRepresentation((BitFieldDataType) dataType);
}
else {
return new DefaultDataTypeHTMLRepresentation(dataType);
}
@ -203,8 +206,9 @@ public class ToolTipUtils {
buf.append("<td width=\"1%\">");
buf.append(colorString(Color.BLACK, friendlyEncodeHTML(param.getDataType().getName())));
buf.append("</td><td width=\"1%\">");
Color paramColor = param.getFunction().hasCustomVariableStorage()
? PARAM_CUSTOM_STORAGE_COLOR : PARAM_DYNAMIC_STORAGE_COLOR;
Color paramColor =
param.getFunction().hasCustomVariableStorage() ? PARAM_CUSTOM_STORAGE_COLOR
: PARAM_DYNAMIC_STORAGE_COLOR;
buf.append(
colorString(paramColor, friendlyEncodeHTML(param.getVariableStorage().toString())));
buf.append("</td><td width=\"1%\">");

View file

@ -0,0 +1,63 @@
/* ###
* 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.html;
import ghidra.app.util.ToolTipUtils;
import ghidra.program.model.data.BitFieldDataType;
import ghidra.program.model.data.DataType;
import ghidra.util.HTMLUtilities;
import ghidra.util.exception.AssertException;
public class BitFieldDataTypeHTMLRepresentation extends HTMLDataTypeRepresentation {
public BitFieldDataTypeHTMLRepresentation(BitFieldDataType bitFieldDt) {
super(buildHTMLText(bitFieldDt));
}
private static String buildHTMLText(BitFieldDataType bitFieldDt) {
StringBuffer buffer = new StringBuffer();
String description = bitFieldDt.getDescription();
if (description == null || description.length() == 0) {
description = bitFieldDt.getDisplayName();
}
description = HTMLUtilities.friendlyEncodeHTML(description);
buffer.append(description);
DataType baseDataType = bitFieldDt.getBaseDataType();
buffer.append(BR).append(BR);
buffer.append("Bitfield Base Data Type: ").append(BR);
buffer.append(INDENT_OPEN);
HTMLDataTypeRepresentation representation =
ToolTipUtils.getHTMLRepresentation(baseDataType);
String baseHTML = representation.getHTMLContentString();
buffer.append(baseHTML);
if (baseHTML.indexOf(LENGTH_PREFIX) < 0) {
addDataTypeLength(baseDataType, buffer);
}
buffer.append(INDENT_CLOSE);
return buffer.toString();
}
@Override
public HTMLDataTypeRepresentation[] diff(HTMLDataTypeRepresentation otherRepresentation) {
throw new AssertException("Bitfield types are not diffable at this time");
}
}

View file

@ -138,7 +138,7 @@ public class TypeDefDataTypeHTMLRepresentation extends HTMLDataTypeRepresentatio
// body
buffy.append(BR);
buffy.append("TypeDef Base Data Type: ").append(BR).append(BR);
buffy.append("TypeDef Base Data Type: ").append(BR);
iterator = bodyLines.iterator();
for (; iterator.hasNext();) {

View file

@ -648,6 +648,7 @@ public class DataTypesXmlMgr {
private void writerMember(XmlWriter writer, DataTypeComponent member) {
XmlAttributes attrs = new XmlAttributes();
// TODO: how should we output bitfields (aligned/unaligned) and flex array
attrs.addAttribute("OFFSET", member.getOffset(), true);
attrs.addAttribute("DATATYPE", member.getDataType().getDisplayName());
attrs.addAttribute("DATATYPE_NAMESPACE", member.getDataType().getCategoryPath().getPath());

View file

@ -935,6 +935,7 @@ public class ProgramDiffDetails {
" (flexible array) " + ((comment != null) ? comment : "") + " " + newLine);
}
else {
// TODO: how should we display bitfields?
buf.append(indent + "Offset=" + DiffUtility.toSignedHexString(offset) + " " +
"Ordinal=" + ordinal + " " + fieldName + " " +
actualDt.getMnemonic(actualDt.getDefaultSettings()) + " " +
@ -1505,8 +1506,8 @@ public class ProgramDiffDetails {
private boolean addSpecificCommentDetails(int commentType, String commentName) {
boolean hasCommentDiff = false;
try {
for (Address p1Address = minP1Address; p1Address
.compareTo(maxP1Address) <= 0; p1Address = p1Address.add(1L)) {
for (Address p1Address = minP1Address; p1Address.compareTo(
maxP1Address) <= 0; p1Address = p1Address.add(1L)) {
Address p2Address = SimpleDiffUtility.getCompatibleAddress(p1, p1Address, p2);
String noComment = "No " + commentName + ".";
String cmt1 = l1.getComment(commentType, p1Address);
@ -2209,9 +2210,8 @@ public class ProgramDiffDetails {
for (String propertyName : names1) {
if (cu.hasProperty(propertyName)) {
// Handle case where the class for a Saveable property is missing (unsupported).
if (cu.getProgram()
.getListing()
.getPropertyMap(propertyName) instanceof UnsupportedMapDB) {
if (cu.getProgram().getListing().getPropertyMap(
propertyName) instanceof UnsupportedMapDB) {
buf.append(
indent2 + propertyName + " is an unsupported property." + newLine);
continue;
@ -2282,8 +2282,8 @@ public class ProgramDiffDetails {
BookmarkManager bmm1 = p1.getBookmarkManager();
BookmarkManager bmm2 = p2.getBookmarkManager();
try {
for (Address p1Address = minP1Address; p1Address
.compareTo(maxP1Address) <= 0; p1Address = p1Address.add(1)) {
for (Address p1Address = minP1Address; p1Address.compareTo(
maxP1Address) <= 0; p1Address = p1Address.add(1)) {
Address p2Address = SimpleDiffUtility.getCompatibleAddress(p1, p1Address, p2);
Bookmark[] marks1 = bmm1.getBookmarks(p1Address);
Arrays.sort(marks1, BOOKMARK_COMPARATOR);

View file

@ -46,16 +46,16 @@ public class DataTypeDependencyOrderer {
private DataTypeManager dtManager;
// A HashSet is chosen so that we have no duplicates.
private HashSet<Entry> inputSet = new HashSet<Entry>();
private HashSet<Entry> inputSet = new HashSet<>();
private HashSet<Entry> procSet = new HashSet<Entry>();
private HashSet<Entry> doneSet = new HashSet<Entry>();
private ArrayList<DataType> structList = new ArrayList<DataType>();
private ArrayList<DataType> orderedDependentsList = new ArrayList<DataType>();
private HashSet<Entry> procSet = new HashSet<>();
private HashSet<Entry> doneSet = new HashSet<>();
private ArrayList<DataType> structList = new ArrayList<>();
private ArrayList<DataType> orderedDependentsList = new ArrayList<>();
private HashMap<Entry, Set<Entry>> whoIDependOn = new HashMap<Entry, Set<Entry>>();
private HashMap<Entry, Set<Entry>> whoDependsOnMe = new HashMap<Entry, Set<Entry>>();
private LinkedList<Entry> noDependentsQueue = new LinkedList<Entry>();
private HashMap<Entry, Set<Entry>> whoIDependOn = new HashMap<>();
private HashMap<Entry, Set<Entry>> whoDependsOnMe = new HashMap<>();
private LinkedList<Entry> noDependentsQueue = new LinkedList<>();
/**
* Associate a DataType with its ID (relative to the DataTypeManager) in an Entry
@ -152,7 +152,7 @@ public class DataTypeDependencyOrderer {
if (processed == false) {
processDependencyLists();
}
return new Pair<ArrayList<DataType>, ArrayList<DataType>>(structList, orderedDependentsList);
return new Pair<>(structList, orderedDependentsList);
}
/**
@ -189,8 +189,8 @@ public class DataTypeDependencyOrderer {
whoDependsOnMe.size() + "\n\n");
if (!orderedDependentsList.isEmpty()) {
for (DataType dt : orderedDependentsList) {
res.append("Ordered Dependents: " + dt.getName() + " " + dt.getClass().getName() +
"\n");
res.append(
"Ordered Dependents: " + dt.getName() + " " + dt.getClass().getName() + "\n");
}
}
res.append("\n");
@ -260,10 +260,14 @@ public class DataTypeDependencyOrderer {
addDependent(entry, ((TypeDef) dataType).getDataType());
}
else if (dataType instanceof Structure) {
DataTypeComponent dtcomps[] = ((Structure) dataType).getComponents();
Structure struct = (Structure) dataType;
DataTypeComponent dtcomps[] = struct.getComponents();
for (DataTypeComponent dtcomp : dtcomps) {
addDependent(entry, dtcomp.getDataType());
}
if (struct.hasFlexibleArrayComponent()) {
addDependent(entry, struct.getFlexibleArrayComponent().getDataType());
}
}
else if (dataType instanceof Composite) {
DataTypeComponent dtcomps[] = ((Composite) dataType).getComponents();
@ -331,6 +335,9 @@ public class DataTypeDependencyOrderer {
if ((entry == null) || (subType == null)) {
return;
}
if (subType instanceof BitFieldDataType) {
subType = ((BitFieldDataType) subType).getBaseDataType();
}
Entry subEntry = createEntry(subType);
if (!doneSet.contains(subEntry)) {
procSet.add(subEntry);
@ -343,13 +350,13 @@ public class DataTypeDependencyOrderer {
}
Set<Entry> dependents = whoDependsOnMe.get(subEntry);
if (dependents == null) {
dependents = new HashSet<Entry>();
dependents = new HashSet<>();
whoDependsOnMe.put(subEntry, dependents);
}
dependents.add(entry); //ignores duplicates
Set<Entry> support = whoIDependOn.get(entry);
if (support == null) {
support = new HashSet<Entry>();
support = new HashSet<>();
whoIDependOn.put(entry, support);
}
support.add(subEntry); //ignores duplicates
@ -361,10 +368,10 @@ public class DataTypeDependencyOrderer {
}
Set<Entry> dependents = whoDependsOnMe.get(entry);
if (dependents == null) {
dependents = new HashSet<Entry>();
dependents = new HashSet<>();
whoDependsOnMe.put(entry, dependents);
}
Set<Entry> support = new HashSet<Entry>();
Set<Entry> support = new HashSet<>();
whoIDependOn.put(entry, support);
}

View file

@ -2151,7 +2151,7 @@ public class CodeManager implements ErrorHandler, ManagerDB {
}
private void createReference(Data data, Address toAddr, List<Address> longSegmentAddressList) {
if (toAddr == null) {
if (toAddr == null || !toAddr.isLoadedMemoryAddress()) {
return;
}

View file

@ -421,6 +421,12 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
for (DataTypeComponent comp : comps) {
comp.getDataType().addParent(dt);
}
if (dt instanceof Structure) {
Structure struct = (Structure) dt;
if (struct.hasFlexibleArrayComponent()) {
struct.getFlexibleArrayComponent().getDataType().addParent(dt);
}
}
}
else if (dt instanceof FunctionDefinition) {
FunctionDefinition funDef = (FunctionDefinition) dt;

View file

@ -649,6 +649,7 @@ class StructureDB extends CompositeDB implements Structure {
return 1; // Unaligned
}
if (alignment <= 0) {
// just in case - alignment should have been previously determined and stored
StructurePackResult packResult = AlignedStructureInspector.packComponents(this);
alignment = packResult.alignment;
}

View file

@ -23,6 +23,11 @@ import javax.help.UnsupportedOperationException;
import ghidra.docking.settings.Settings;
import ghidra.util.exception.DuplicateNameException;
/**
* <code>AlignedStructureInspector</code> provides a simple instance of a structure
* member container used to perform alignment operations without forcing modification
* of the actual structure.
*/
public class AlignedStructureInspector extends AlignedStructurePacker {
private AlignedStructureInspector(Structure structure) {
@ -34,6 +39,9 @@ public class AlignedStructureInspector extends AlignedStructurePacker {
for (DataTypeComponent c : structure.getComponents()) {
list.add(new ReadOnlyComponentWrapper(c));
}
if (structure.hasFlexibleArrayComponent()) {
list.add(new ReadOnlyComponentWrapper(structure.getFlexibleArrayComponent()));
}
return list;
}
@ -55,10 +63,10 @@ public class AlignedStructureInspector extends AlignedStructurePacker {
}
@Override
public void update(int ordinal, int offset, int length) {
this.ordinal = ordinal;
this.offset = offset;
this.length = length;
public void update(int ord, int off, int len) {
this.ordinal = ord;
this.offset = off;
this.length = len;
}
@Override
@ -73,7 +81,7 @@ public class AlignedStructureInspector extends AlignedStructurePacker {
@Override
public boolean isFlexibleArrayComponent() {
return false;
return component.isFlexibleArrayComponent();
}
@Override

View file

@ -340,7 +340,18 @@ public class BitFieldDataType extends AbstractDataType {
@Override
public String getDescription() {
return getName() + " BitField";
StringBuffer sbuf = new StringBuffer();
sbuf.append(Integer.toString(effectiveBitSize));
sbuf.append("-bit ");
DataType dt = getBaseDataType();
sbuf.append(dt.getDisplayName());
sbuf.append(" bitfield");
if (effectiveBitSize != bitSize) {
sbuf.append(" (declared as ");
sbuf.append(Integer.toString(bitSize));
sbuf.append("-bits)");
}
return sbuf.toString();
}
@Override

View file

@ -242,7 +242,7 @@ public class DataTypeWriter {
}
Msg.error(this, "Factory data types may not be written - type: " + dt, iae);
}
if (dt instanceof Pointer || dt instanceof Array) {
if (dt instanceof Pointer || dt instanceof Array || dt instanceof BitFieldDataType) {
write(getBaseDataType(dt), monitor);
return;
}
@ -308,6 +308,9 @@ public class DataTypeWriter {
else if (dt instanceof BuiltInDataType) {
writeBuiltIn((BuiltInDataType) dt, monitor);
}
else if (dt instanceof BitFieldDataType) {
// skip
}
else {
writer.write(EOL);
writer.write(EOL);
@ -540,7 +543,12 @@ public class DataTypeWriter {
if (componentString == null) {
if (dataType instanceof Array) {
if (dataType instanceof BitFieldDataType) {
BitFieldDataType bfDt = (BitFieldDataType) dataType;
name += ":" + bfDt.getDeclaredBitSize();
dataType = bfDt.getBaseDataType();
}
else if (dataType instanceof Array) {
Array array = (Array) dataType;
name += getArrayDimensions(array);
dataType = getArrayBaseType(array);
@ -637,6 +645,7 @@ public class DataTypeWriter {
return;
}
}
// TODO: A comment explaining the special 'P' case would be helpful!! Smells like fish.
else if (baseType instanceof Pointer && typedefName.startsWith("P")) {
DataType dt = ((Pointer) baseType).getDataType();
if (dt instanceof TypeDef) {
@ -765,6 +774,10 @@ public class DataTypeWriter {
Pointer pointer = (Pointer) dt;
dt = pointer.getDataType();
}
else if (dt instanceof BitFieldDataType) {
BitFieldDataType bitfieldDt = (BitFieldDataType) dt;
dt = bitfieldDt.getBaseDataType();
}
else {
break;
}

View file

@ -25,9 +25,9 @@ public interface InternalDataTypeComponent extends DataTypeComponent {
/**
* Update component ordinal, offset and length during alignment
* @param ordinal
* @param offset
* @param length
* @param ordinal updated ordinal
* @param offset updated offset
* @param length updated byte length
*/
void update(int ordinal, int offset, int length);