mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 18:29:37 +02:00
Bitfields - added simple bitfield viewer and corrected missing support
for bitfields and flex arrays
This commit is contained in:
parent
52f6bfc127
commit
31163bca26
26 changed files with 747 additions and 233 deletions
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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%\">");
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
||||
}
|
|
@ -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();) {
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue