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.ActionContext;
|
||||||
import docking.DockingWindowManager;
|
import docking.DockingWindowManager;
|
||||||
|
import ghidra.program.model.data.Structure;
|
||||||
import ghidra.util.exception.AssertException;
|
import ghidra.util.exception.AssertException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -76,7 +77,8 @@ public class AddBitFieldAction extends CompositeEditorTableAction {
|
||||||
public void adjustEnablement() {
|
public void adjustEnablement() {
|
||||||
boolean enabled = true;
|
boolean enabled = true;
|
||||||
CompEditorModel editorModel = (CompEditorModel) model;
|
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()) {
|
editorModel.getNumSelectedRows() != 1 || editorModel.isFlexibleArraySelection()) {
|
||||||
enabled = false;
|
enabled = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,15 +20,12 @@ import java.awt.event.MouseEvent;
|
||||||
import javax.swing.Icon;
|
import javax.swing.Icon;
|
||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
|
|
||||||
import docking.*;
|
import docking.ActionContext;
|
||||||
|
import docking.DialogComponentProvider;
|
||||||
import docking.action.DockingAction;
|
import docking.action.DockingAction;
|
||||||
import docking.action.MenuData;
|
import docking.action.MenuData;
|
||||||
import ghidra.GhidraApplicationLayout;
|
|
||||||
import ghidra.app.plugin.core.analysis.DefaultDataTypeManagerService;
|
|
||||||
import ghidra.app.services.DataTypeManagerService;
|
import ghidra.app.services.DataTypeManagerService;
|
||||||
import ghidra.framework.*;
|
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.*;
|
||||||
import ghidra.util.SystemUtilities;
|
|
||||||
import resources.ResourceManager;
|
import resources.ResourceManager;
|
||||||
|
|
||||||
public class BitFieldEditorDialog extends DialogComponentProvider {
|
public class BitFieldEditorDialog extends DialogComponentProvider {
|
||||||
|
@ -93,7 +90,7 @@ public class BitFieldEditorDialog extends DialogComponentProvider {
|
||||||
if (bitfieldDtc == null || !bitFieldEditorPanel.endCurrentEdit()) {
|
if (bitfieldDtc == null || !bitFieldEditorPanel.endCurrentEdit()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
initEdit(bitfieldDtc.getOrdinal());
|
initEdit(bitfieldDtc.getOrdinal(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -200,7 +197,7 @@ public class BitFieldEditorDialog extends DialogComponentProvider {
|
||||||
initAdd(-editOrdinal - 1);
|
initAdd(-editOrdinal - 1);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
initEdit(editOrdinal);
|
initEdit(editOrdinal, false);
|
||||||
}
|
}
|
||||||
return bitFieldEditorPanel;
|
return bitFieldEditorPanel;
|
||||||
}
|
}
|
||||||
|
@ -234,16 +231,19 @@ public class BitFieldEditorDialog extends DialogComponentProvider {
|
||||||
setApplyEnabled(true);
|
setApplyEnabled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initEdit(int editOrdinal) throws ArrayIndexOutOfBoundsException {
|
private void initEdit(int editOrdinal, boolean useExistingAllocationSize)
|
||||||
|
throws ArrayIndexOutOfBoundsException {
|
||||||
DataTypeComponent dtc = composite.getComponent(editOrdinal);
|
DataTypeComponent dtc = composite.getComponent(editOrdinal);
|
||||||
if (!dtc.isBitFieldComponent()) {
|
if (!dtc.isBitFieldComponent()) {
|
||||||
throw new IllegalArgumentException("editOrdinal does not correspond to bitfield");
|
throw new IllegalArgumentException("editOrdinal does not correspond to bitfield");
|
||||||
}
|
}
|
||||||
bitFieldEditorPanel.initEdit(dtc, getPreferredAllocationOffset(dtc));
|
bitFieldEditorPanel.initEdit(dtc, getPreferredAllocationOffset(dtc),
|
||||||
|
useExistingAllocationSize);
|
||||||
setApplyEnabled(true);
|
setApplyEnabled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getPreferredAllocationOffset(DataTypeComponent bitfieldDtc) {
|
static int getPreferredAllocationOffset(DataTypeComponent bitfieldDtc) {
|
||||||
|
Composite composite = (Composite) bitfieldDtc.getParent();
|
||||||
if (composite instanceof Union) {
|
if (composite instanceof Union) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -270,34 +270,4 @@ public class BitFieldEditorDialog extends DialogComponentProvider {
|
||||||
|
|
||||||
return offset;
|
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;
|
import resources.ResourceManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <code>BitFieldEditorPanel</code> provides the ability to place bitfields
|
* <code>BitFieldEditorPanel</code> provides the ability to add or modify bitfields
|
||||||
* within unaligned structures and unions.
|
* within unaligned structures.
|
||||||
*/
|
*/
|
||||||
public class BitFieldEditorPanel extends JPanel {
|
public class BitFieldEditorPanel extends JPanel {
|
||||||
|
|
||||||
|
@ -100,7 +100,7 @@ public class BitFieldEditorPanel extends JPanel {
|
||||||
|
|
||||||
private JPanel createLegendPanel() {
|
private JPanel createLegendPanel() {
|
||||||
JPanel legendPanel = new JPanel(new BorderLayout());
|
JPanel legendPanel = new JPanel(new BorderLayout());
|
||||||
legendPanel.add(new BitFieldPlacementComponent.BitFieldLegend(), BorderLayout.WEST);
|
legendPanel.add(new BitFieldPlacementComponent.BitFieldLegend(null), BorderLayout.WEST);
|
||||||
return legendPanel;
|
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.
|
* If null an allocation size of 4-bytes will be used but may be adjusted.
|
||||||
* @param bitfieldDtc bitfield component or null
|
* @param bitfieldDtc bitfield component or null
|
||||||
* @param allocationOffset allocation offset to be used
|
* @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;
|
String initialFieldName = null;
|
||||||
DataType initialBaseDataType = null;
|
DataType initialBaseDataType = null;
|
||||||
int allocationSize = -1;
|
int allocationSize = -1;
|
||||||
|
if (useExistingAllocationSize) {
|
||||||
BitFieldAllocation bitFieldAllocation = placementComponent.getBitFieldAllocation();
|
BitFieldAllocation bitFieldAllocation = placementComponent.getBitFieldAllocation();
|
||||||
if (bitFieldAllocation != null) {
|
if (bitFieldAllocation != null) {
|
||||||
allocationSize = bitFieldAllocation.getAllocationByteSize();
|
allocationSize = bitFieldAllocation.getAllocationByteSize();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (bitfieldDtc != null) {
|
if (bitfieldDtc != null) {
|
||||||
if (!bitfieldDtc.isBitFieldComponent()) {
|
if (!bitfieldDtc.isBitFieldComponent()) {
|
||||||
throw new IllegalArgumentException("unsupport data type component");
|
throw new IllegalArgumentException("unsupport data type component");
|
||||||
|
@ -420,7 +424,7 @@ public class BitFieldEditorPanel extends JPanel {
|
||||||
// TODO: adjust offset and allocationSize if needed
|
// TODO: adjust offset and allocationSize if needed
|
||||||
placementComponent.setAllocationOffset(allocationOffset);
|
placementComponent.setAllocationOffset(allocationOffset);
|
||||||
placementComponent.init(allocationSize, bitfieldDtc);
|
placementComponent.init(allocationSize, bitfieldDtc);
|
||||||
bitFieldAllocation = placementComponent.getBitFieldAllocation(); // get updated instance
|
BitFieldAllocation bitFieldAllocation = placementComponent.getBitFieldAllocation(); // get updated instance
|
||||||
initControls(initialFieldName, initialBaseDataType, bitFieldAllocation.getBitSize());
|
initControls(initialFieldName, initialBaseDataType, bitFieldAllocation.getBitSize());
|
||||||
enableControls(bitfieldDtc != null);
|
enableControls(bitfieldDtc != null);
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@ import ghidra.program.model.data.*;
|
||||||
import ghidra.program.model.data.Composite;
|
import ghidra.program.model.data.Composite;
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
import ghidra.util.exception.AssertException;
|
import ghidra.util.exception.AssertException;
|
||||||
|
import ghidra.util.layout.VerticalLayout;
|
||||||
import resources.icons.ColorIcon;
|
import resources.icons.ColorIcon;
|
||||||
|
|
||||||
public class BitFieldPlacementComponent extends JPanel {
|
public class BitFieldPlacementComponent extends JPanel {
|
||||||
|
@ -59,28 +60,51 @@ public class BitFieldPlacementComponent extends JPanel {
|
||||||
|
|
||||||
private EditMode editMode = EditMode.NONE;
|
private EditMode editMode = EditMode.NONE;
|
||||||
private int editOrdinal = -1; // FIXME: improve insert use
|
private int editOrdinal = -1; // FIXME: improve insert use
|
||||||
|
private DataTypeComponent editComponent;
|
||||||
|
|
||||||
public static class BitFieldLegend extends JPanel {
|
public static class BitFieldLegend extends JPanel {
|
||||||
|
|
||||||
BitFieldLegend() {
|
BitFieldLegend(DataTypeComponent viewedBitfield) {
|
||||||
setLayout(new GridLayout(2, 3, 5, 5));
|
JPanel legendPanel;
|
||||||
//setLayout(new RowColumnLayout(10, 10, RowColumnLayout.ROW, 0));
|
if (viewedBitfield != null) {
|
||||||
add(new JLabel("Undefined bits",
|
setLayout(new VerticalLayout(10));
|
||||||
new ColorIcon(UNDEFINED_BIT_COLOR, INTERIOR_LINE_COLOR, LENEND_BOX_SIZE),
|
legendPanel = new JPanel(new GridLayout(1, 3, 5, 5));
|
||||||
SwingConstants.LEFT));
|
String viewComponentText =
|
||||||
add(new JLabel("Defined bitfield",
|
"Selected bitfield { " + viewedBitfield.getDataType().getDisplayName();
|
||||||
new ColorIcon(BITFIELD_COMPONENT_COLOR, INTERIOR_LINE_COLOR, LENEND_BOX_SIZE),
|
String viewComponentName = viewedBitfield.getFieldName();
|
||||||
SwingConstants.LEFT));
|
if (viewComponentName != null) {
|
||||||
add(new JLabel("Defined non-bitfield",
|
viewComponentText += " " + viewComponentName;
|
||||||
new ColorIcon(NON_BITFIELD_COMPONENT_COLOR, INTERIOR_LINE_COLOR, LENEND_BOX_SIZE),
|
}
|
||||||
SwingConstants.LEFT));
|
viewComponentText += " }";
|
||||||
add(new JLabel("Edit bitfield bits",
|
add(new JLabel(viewComponentText,
|
||||||
new ColorIcon(BITFIELD_BITS_COLOR, INTERIOR_LINE_COLOR, LENEND_BOX_SIZE),
|
new ColorIcon(BITFIELD_BITS_COLOR, INTERIOR_LINE_COLOR, LENEND_BOX_SIZE),
|
||||||
SwingConstants.LEFT));
|
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),
|
new ColorIcon(CONFLICT_BITS_COLOR, INTERIOR_LINE_COLOR, LENEND_BOX_SIZE),
|
||||||
SwingConstants.LEFT));
|
SwingConstants.LEFT));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,7 +151,8 @@ public class BitFieldPlacementComponent extends JPanel {
|
||||||
}
|
}
|
||||||
|
|
||||||
void refresh(int allocationByteSize, int bitSize, int bitOffset) {
|
void refresh(int allocationByteSize, int bitSize, int bitOffset) {
|
||||||
bitFieldAllocation = new BitFieldAllocation(allocationByteSize, bitSize, bitOffset);
|
bitFieldAllocation =
|
||||||
|
new BitFieldAllocation(allocationByteSize, bitSize, bitOffset, editComponent);
|
||||||
updatePreferredSize();
|
updatePreferredSize();
|
||||||
repaint();
|
repaint();
|
||||||
}
|
}
|
||||||
|
@ -147,14 +172,16 @@ public class BitFieldPlacementComponent extends JPanel {
|
||||||
void initAdd(int allocationByteSize, int bitSize, int bitOffset) {
|
void initAdd(int allocationByteSize, int bitSize, int bitOffset) {
|
||||||
editMode = EditMode.ADD;
|
editMode = EditMode.ADD;
|
||||||
editOrdinal = -1;
|
editOrdinal = -1;
|
||||||
|
editComponent = null;
|
||||||
refresh(allocationByteSize, bitSize, bitOffset);
|
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;
|
editMode = EditMode.NONE;
|
||||||
editOrdinal = -1;
|
editOrdinal = -1;
|
||||||
|
this.editComponent = null;
|
||||||
refresh(allocationByteSize, 0, 0);
|
refresh(allocationByteSize, 0, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -163,12 +190,13 @@ public class BitFieldPlacementComponent extends JPanel {
|
||||||
// of the component being modified
|
// of the component being modified
|
||||||
|
|
||||||
editMode = EditMode.EDIT;
|
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 =
|
bitFieldAllocation =
|
||||||
new BitFieldAllocation(allocationByteSize, placement.rightBit - placement.leftBit + 1,
|
new BitFieldAllocation(allocationByteSize, placement.rightBit - placement.leftBit + 1,
|
||||||
(8 * allocationByteSize) - placement.rightBit - 1);
|
(8 * allocationByteSize) - placement.rightBit - 1, editDtc);
|
||||||
updatePreferredSize();
|
updatePreferredSize();
|
||||||
repaint();
|
repaint();
|
||||||
}
|
}
|
||||||
|
@ -213,6 +241,7 @@ public class BitFieldPlacementComponent extends JPanel {
|
||||||
// unexpected removal
|
// unexpected removal
|
||||||
editMode = EditMode.ADD;
|
editMode = EditMode.ADD;
|
||||||
editOrdinal = -1;
|
editOrdinal = -1;
|
||||||
|
editComponent = null;
|
||||||
}
|
}
|
||||||
else if (ordinal < editOrdinal) {
|
else if (ordinal < editOrdinal) {
|
||||||
--editOrdinal;
|
--editOrdinal;
|
||||||
|
@ -268,6 +297,7 @@ public class BitFieldPlacementComponent extends JPanel {
|
||||||
finally {
|
finally {
|
||||||
editMode = EditMode.NONE;
|
editMode = EditMode.NONE;
|
||||||
editOrdinal = -1;
|
editOrdinal = -1;
|
||||||
|
editComponent = null;
|
||||||
bitFieldAllocation.refresh();
|
bitFieldAllocation.refresh();
|
||||||
repaint();
|
repaint();
|
||||||
}
|
}
|
||||||
|
@ -475,18 +505,21 @@ public class BitFieldPlacementComponent extends JPanel {
|
||||||
private final int bitSize;
|
private final int bitSize;
|
||||||
private final int bitOffset;
|
private final int bitOffset;
|
||||||
private boolean hasConflict;
|
private boolean hasConflict;
|
||||||
|
private DataTypeComponent editComponent;
|
||||||
|
|
||||||
// bit layout normalized to big-endian layout
|
// bit layout normalized to big-endian layout
|
||||||
// left-most allocation msb has array index of 0
|
// left-most allocation msb has array index of 0
|
||||||
private BitAttributes[] bitAttributes;
|
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)) {
|
if (allocationByteSize <= 0 || (bitSize + bitOffset) > (8 * allocationByteSize)) {
|
||||||
throw new IllegalArgumentException("allocation size too small");
|
throw new IllegalArgumentException("allocation size too small");
|
||||||
}
|
}
|
||||||
this.allocationByteSize = allocationByteSize;
|
this.allocationByteSize = allocationByteSize;
|
||||||
this.bitSize = bitSize;
|
this.bitSize = bitSize;
|
||||||
this.bitOffset = bitOffset;
|
this.bitOffset = bitOffset;
|
||||||
|
this.editComponent = editComponent;
|
||||||
refresh();
|
refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -505,11 +538,11 @@ public class BitFieldPlacementComponent extends JPanel {
|
||||||
if (editMode != EditMode.NONE) {
|
if (editMode != EditMode.NONE) {
|
||||||
int rightMostBit = bitAttributes.length - bitOffset - 1;
|
int rightMostBit = bitAttributes.length - bitOffset - 1;
|
||||||
if (bitSize == 0) {
|
if (bitSize == 0) {
|
||||||
allocateZeroBitField(null, rightMostBit);
|
allocateZeroBitField(editComponent, rightMostBit);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
int leftMostBit = rightMostBit - bitSize + 1;
|
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) {
|
if (zeroBitfield) {
|
||||||
return UNDEFINED_BIT_COLOR;
|
return UNDEFINED_BIT_COLOR;
|
||||||
}
|
}
|
||||||
if (dtc == null) {
|
if (dtc == editComponent) {
|
||||||
return BITFIELD_BITS_COLOR; // edit field
|
return BITFIELD_BITS_COLOR; // edit field
|
||||||
}
|
}
|
||||||
return dtc.isBitFieldComponent() ? BITFIELD_COMPONENT_COLOR
|
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");
|
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.GTable;
|
||||||
import docking.widgets.table.GTableCellRenderer;
|
import docking.widgets.table.GTableCellRenderer;
|
||||||
import docking.widgets.textfield.GValidatedTextField;
|
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.services.DataTypeManagerService;
|
||||||
import ghidra.app.util.ToolTipUtils;
|
|
||||||
import ghidra.app.util.datatype.DataTypeSelectionEditor;
|
import ghidra.app.util.datatype.DataTypeSelectionEditor;
|
||||||
import ghidra.app.util.datatype.NavigationDirection;
|
import ghidra.app.util.datatype.NavigationDirection;
|
||||||
import ghidra.framework.plugintool.Plugin;
|
import ghidra.framework.plugintool.Plugin;
|
||||||
|
@ -144,7 +141,8 @@ public abstract class CompositeEditorPanel extends JPanel
|
||||||
|
|
||||||
private void setupTableCellRenderer() {
|
private void setupTableCellRenderer() {
|
||||||
GTableCellRenderer cellRenderer = new GTableCellRenderer();
|
GTableCellRenderer cellRenderer = new GTableCellRenderer();
|
||||||
DataTypeCellRenderer dtiCellRenderer = new DataTypeCellRenderer();
|
DataTypeCellRenderer dtiCellRenderer = new DataTypeCellRenderer(
|
||||||
|
model.getOriginalDataTypeManager(), model.bitfieldsSupported());
|
||||||
table.setDefaultRenderer(String.class, cellRenderer);
|
table.setDefaultRenderer(String.class, cellRenderer);
|
||||||
table.setDefaultRenderer(DataTypeInstance.class, dtiCellRenderer);
|
table.setDefaultRenderer(DataTypeInstance.class, dtiCellRenderer);
|
||||||
}
|
}
|
||||||
|
@ -558,6 +556,12 @@ public abstract class CompositeEditorPanel extends JPanel
|
||||||
table = new CompositeTable(model);
|
table = new CompositeTable(model);
|
||||||
table.putClientProperty("JTable.autoStartsEdit", Boolean.FALSE);
|
table.putClientProperty("JTable.autoStartsEdit", Boolean.FALSE);
|
||||||
table.addMouseListener(new CompositeTableMouseListener());
|
table.addMouseListener(new CompositeTableMouseListener());
|
||||||
|
if (model.bitfieldsSupported()) {
|
||||||
|
CompositeTableCellMouseListener cellMouseListener =
|
||||||
|
new CompositeTableCellMouseListener();
|
||||||
|
table.addMouseListener(cellMouseListener);
|
||||||
|
table.addMouseMotionListener(cellMouseListener);
|
||||||
|
}
|
||||||
|
|
||||||
CompositeEditorTableAction action = provider.actionMgr.getNamedAction(
|
CompositeEditorTableAction action = provider.actionMgr.getNamedAction(
|
||||||
CompositeEditorTableAction.EDIT_ACTION_PREFIX + EditFieldAction.ACTION_NAME);
|
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 {
|
private class CompositeTableMouseListener extends MouseAdapter {
|
||||||
@Override
|
@Override
|
||||||
public void mouseReleased(MouseEvent e) {
|
public void mouseReleased(MouseEvent e) {
|
||||||
|
@ -1473,69 +1556,6 @@ public abstract class CompositeEditorPanel extends JPanel
|
||||||
super(dm);
|
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
|
@Override
|
||||||
// overridden because the editor component was not being given focus
|
// overridden because the editor component was not being given focus
|
||||||
public Component prepareEditor(TableCellEditor editor, int row, int column) {
|
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 HexNumbersAction(this),
|
||||||
new CreateInternalStructureAction(this),
|
new CreateInternalStructureAction(this),
|
||||||
new AddBitFieldAction(this),
|
new AddBitFieldAction(this),
|
||||||
new EditBitFieldAction(this)
|
new EditBitFieldAction(this),
|
||||||
|
// new ViewBitFieldAction(this)
|
||||||
};
|
};
|
||||||
//@formatter:on
|
//@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();
|
DataTypeComponent[] components = composite.getComponents();
|
||||||
List<String> names = new ArrayList<>();
|
List<String> names = new ArrayList<>();
|
||||||
for (DataTypeComponent dataTypeComponent : components) {
|
for (DataTypeComponent dataTypeComponent : components) {
|
||||||
|
if (dataTypeComponent.isBitFieldComponent()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
String fieldName = dataTypeComponent.getFieldName();
|
String fieldName = dataTypeComponent.getFieldName();
|
||||||
if (StringUtils.isBlank(fieldName)) {
|
if (StringUtils.isBlank(fieldName)) {
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -92,6 +92,9 @@ public class ToolTipUtils {
|
||||||
else if (dataType instanceof Array) {
|
else if (dataType instanceof Array) {
|
||||||
return new ArrayDataTypeHTMLRepresentation((Array) dataType);
|
return new ArrayDataTypeHTMLRepresentation((Array) dataType);
|
||||||
}
|
}
|
||||||
|
else if (dataType instanceof BitFieldDataType) {
|
||||||
|
return new BitFieldDataTypeHTMLRepresentation((BitFieldDataType) dataType);
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
return new DefaultDataTypeHTMLRepresentation(dataType);
|
return new DefaultDataTypeHTMLRepresentation(dataType);
|
||||||
}
|
}
|
||||||
|
@ -203,8 +206,9 @@ public class ToolTipUtils {
|
||||||
buf.append("<td width=\"1%\">");
|
buf.append("<td width=\"1%\">");
|
||||||
buf.append(colorString(Color.BLACK, friendlyEncodeHTML(param.getDataType().getName())));
|
buf.append(colorString(Color.BLACK, friendlyEncodeHTML(param.getDataType().getName())));
|
||||||
buf.append("</td><td width=\"1%\">");
|
buf.append("</td><td width=\"1%\">");
|
||||||
Color paramColor = param.getFunction().hasCustomVariableStorage()
|
Color paramColor =
|
||||||
? PARAM_CUSTOM_STORAGE_COLOR : PARAM_DYNAMIC_STORAGE_COLOR;
|
param.getFunction().hasCustomVariableStorage() ? PARAM_CUSTOM_STORAGE_COLOR
|
||||||
|
: PARAM_DYNAMIC_STORAGE_COLOR;
|
||||||
buf.append(
|
buf.append(
|
||||||
colorString(paramColor, friendlyEncodeHTML(param.getVariableStorage().toString())));
|
colorString(paramColor, friendlyEncodeHTML(param.getVariableStorage().toString())));
|
||||||
buf.append("</td><td width=\"1%\">");
|
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
|
// body
|
||||||
buffy.append(BR);
|
buffy.append(BR);
|
||||||
buffy.append("TypeDef Base Data Type: ").append(BR).append(BR);
|
buffy.append("TypeDef Base Data Type: ").append(BR);
|
||||||
|
|
||||||
iterator = bodyLines.iterator();
|
iterator = bodyLines.iterator();
|
||||||
for (; iterator.hasNext();) {
|
for (; iterator.hasNext();) {
|
||||||
|
|
|
@ -648,6 +648,7 @@ public class DataTypesXmlMgr {
|
||||||
|
|
||||||
private void writerMember(XmlWriter writer, DataTypeComponent member) {
|
private void writerMember(XmlWriter writer, DataTypeComponent member) {
|
||||||
XmlAttributes attrs = new XmlAttributes();
|
XmlAttributes attrs = new XmlAttributes();
|
||||||
|
// TODO: how should we output bitfields (aligned/unaligned) and flex array
|
||||||
attrs.addAttribute("OFFSET", member.getOffset(), true);
|
attrs.addAttribute("OFFSET", member.getOffset(), true);
|
||||||
attrs.addAttribute("DATATYPE", member.getDataType().getDisplayName());
|
attrs.addAttribute("DATATYPE", member.getDataType().getDisplayName());
|
||||||
attrs.addAttribute("DATATYPE_NAMESPACE", member.getDataType().getCategoryPath().getPath());
|
attrs.addAttribute("DATATYPE_NAMESPACE", member.getDataType().getCategoryPath().getPath());
|
||||||
|
|
|
@ -935,6 +935,7 @@ public class ProgramDiffDetails {
|
||||||
" (flexible array) " + ((comment != null) ? comment : "") + " " + newLine);
|
" (flexible array) " + ((comment != null) ? comment : "") + " " + newLine);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
// TODO: how should we display bitfields?
|
||||||
buf.append(indent + "Offset=" + DiffUtility.toSignedHexString(offset) + " " +
|
buf.append(indent + "Offset=" + DiffUtility.toSignedHexString(offset) + " " +
|
||||||
"Ordinal=" + ordinal + " " + fieldName + " " +
|
"Ordinal=" + ordinal + " " + fieldName + " " +
|
||||||
actualDt.getMnemonic(actualDt.getDefaultSettings()) + " " +
|
actualDt.getMnemonic(actualDt.getDefaultSettings()) + " " +
|
||||||
|
@ -1505,8 +1506,8 @@ public class ProgramDiffDetails {
|
||||||
private boolean addSpecificCommentDetails(int commentType, String commentName) {
|
private boolean addSpecificCommentDetails(int commentType, String commentName) {
|
||||||
boolean hasCommentDiff = false;
|
boolean hasCommentDiff = false;
|
||||||
try {
|
try {
|
||||||
for (Address p1Address = minP1Address; p1Address
|
for (Address p1Address = minP1Address; p1Address.compareTo(
|
||||||
.compareTo(maxP1Address) <= 0; p1Address = p1Address.add(1L)) {
|
maxP1Address) <= 0; p1Address = p1Address.add(1L)) {
|
||||||
Address p2Address = SimpleDiffUtility.getCompatibleAddress(p1, p1Address, p2);
|
Address p2Address = SimpleDiffUtility.getCompatibleAddress(p1, p1Address, p2);
|
||||||
String noComment = "No " + commentName + ".";
|
String noComment = "No " + commentName + ".";
|
||||||
String cmt1 = l1.getComment(commentType, p1Address);
|
String cmt1 = l1.getComment(commentType, p1Address);
|
||||||
|
@ -2209,9 +2210,8 @@ public class ProgramDiffDetails {
|
||||||
for (String propertyName : names1) {
|
for (String propertyName : names1) {
|
||||||
if (cu.hasProperty(propertyName)) {
|
if (cu.hasProperty(propertyName)) {
|
||||||
// Handle case where the class for a Saveable property is missing (unsupported).
|
// Handle case where the class for a Saveable property is missing (unsupported).
|
||||||
if (cu.getProgram()
|
if (cu.getProgram().getListing().getPropertyMap(
|
||||||
.getListing()
|
propertyName) instanceof UnsupportedMapDB) {
|
||||||
.getPropertyMap(propertyName) instanceof UnsupportedMapDB) {
|
|
||||||
buf.append(
|
buf.append(
|
||||||
indent2 + propertyName + " is an unsupported property." + newLine);
|
indent2 + propertyName + " is an unsupported property." + newLine);
|
||||||
continue;
|
continue;
|
||||||
|
@ -2282,8 +2282,8 @@ public class ProgramDiffDetails {
|
||||||
BookmarkManager bmm1 = p1.getBookmarkManager();
|
BookmarkManager bmm1 = p1.getBookmarkManager();
|
||||||
BookmarkManager bmm2 = p2.getBookmarkManager();
|
BookmarkManager bmm2 = p2.getBookmarkManager();
|
||||||
try {
|
try {
|
||||||
for (Address p1Address = minP1Address; p1Address
|
for (Address p1Address = minP1Address; p1Address.compareTo(
|
||||||
.compareTo(maxP1Address) <= 0; p1Address = p1Address.add(1)) {
|
maxP1Address) <= 0; p1Address = p1Address.add(1)) {
|
||||||
Address p2Address = SimpleDiffUtility.getCompatibleAddress(p1, p1Address, p2);
|
Address p2Address = SimpleDiffUtility.getCompatibleAddress(p1, p1Address, p2);
|
||||||
Bookmark[] marks1 = bmm1.getBookmarks(p1Address);
|
Bookmark[] marks1 = bmm1.getBookmarks(p1Address);
|
||||||
Arrays.sort(marks1, BOOKMARK_COMPARATOR);
|
Arrays.sort(marks1, BOOKMARK_COMPARATOR);
|
||||||
|
|
|
@ -46,16 +46,16 @@ public class DataTypeDependencyOrderer {
|
||||||
private DataTypeManager dtManager;
|
private DataTypeManager dtManager;
|
||||||
|
|
||||||
// A HashSet is chosen so that we have no duplicates.
|
// 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> procSet = new HashSet<>();
|
||||||
private HashSet<Entry> doneSet = new HashSet<Entry>();
|
private HashSet<Entry> doneSet = new HashSet<>();
|
||||||
private ArrayList<DataType> structList = new ArrayList<DataType>();
|
private ArrayList<DataType> structList = new ArrayList<>();
|
||||||
private ArrayList<DataType> orderedDependentsList = new ArrayList<DataType>();
|
private ArrayList<DataType> orderedDependentsList = new ArrayList<>();
|
||||||
|
|
||||||
private HashMap<Entry, Set<Entry>> whoIDependOn = new HashMap<Entry, Set<Entry>>();
|
private HashMap<Entry, Set<Entry>> whoIDependOn = new HashMap<>();
|
||||||
private HashMap<Entry, Set<Entry>> whoDependsOnMe = new HashMap<Entry, Set<Entry>>();
|
private HashMap<Entry, Set<Entry>> whoDependsOnMe = new HashMap<>();
|
||||||
private LinkedList<Entry> noDependentsQueue = new LinkedList<Entry>();
|
private LinkedList<Entry> noDependentsQueue = new LinkedList<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Associate a DataType with its ID (relative to the DataTypeManager) in an Entry
|
* Associate a DataType with its ID (relative to the DataTypeManager) in an Entry
|
||||||
|
@ -152,7 +152,7 @@ public class DataTypeDependencyOrderer {
|
||||||
if (processed == false) {
|
if (processed == false) {
|
||||||
processDependencyLists();
|
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");
|
whoDependsOnMe.size() + "\n\n");
|
||||||
if (!orderedDependentsList.isEmpty()) {
|
if (!orderedDependentsList.isEmpty()) {
|
||||||
for (DataType dt : orderedDependentsList) {
|
for (DataType dt : orderedDependentsList) {
|
||||||
res.append("Ordered Dependents: " + dt.getName() + " " + dt.getClass().getName() +
|
res.append(
|
||||||
"\n");
|
"Ordered Dependents: " + dt.getName() + " " + dt.getClass().getName() + "\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
res.append("\n");
|
res.append("\n");
|
||||||
|
@ -260,10 +260,14 @@ public class DataTypeDependencyOrderer {
|
||||||
addDependent(entry, ((TypeDef) dataType).getDataType());
|
addDependent(entry, ((TypeDef) dataType).getDataType());
|
||||||
}
|
}
|
||||||
else if (dataType instanceof Structure) {
|
else if (dataType instanceof Structure) {
|
||||||
DataTypeComponent dtcomps[] = ((Structure) dataType).getComponents();
|
Structure struct = (Structure) dataType;
|
||||||
|
DataTypeComponent dtcomps[] = struct.getComponents();
|
||||||
for (DataTypeComponent dtcomp : dtcomps) {
|
for (DataTypeComponent dtcomp : dtcomps) {
|
||||||
addDependent(entry, dtcomp.getDataType());
|
addDependent(entry, dtcomp.getDataType());
|
||||||
}
|
}
|
||||||
|
if (struct.hasFlexibleArrayComponent()) {
|
||||||
|
addDependent(entry, struct.getFlexibleArrayComponent().getDataType());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (dataType instanceof Composite) {
|
else if (dataType instanceof Composite) {
|
||||||
DataTypeComponent dtcomps[] = ((Composite) dataType).getComponents();
|
DataTypeComponent dtcomps[] = ((Composite) dataType).getComponents();
|
||||||
|
@ -331,6 +335,9 @@ public class DataTypeDependencyOrderer {
|
||||||
if ((entry == null) || (subType == null)) {
|
if ((entry == null) || (subType == null)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (subType instanceof BitFieldDataType) {
|
||||||
|
subType = ((BitFieldDataType) subType).getBaseDataType();
|
||||||
|
}
|
||||||
Entry subEntry = createEntry(subType);
|
Entry subEntry = createEntry(subType);
|
||||||
if (!doneSet.contains(subEntry)) {
|
if (!doneSet.contains(subEntry)) {
|
||||||
procSet.add(subEntry);
|
procSet.add(subEntry);
|
||||||
|
@ -343,13 +350,13 @@ public class DataTypeDependencyOrderer {
|
||||||
}
|
}
|
||||||
Set<Entry> dependents = whoDependsOnMe.get(subEntry);
|
Set<Entry> dependents = whoDependsOnMe.get(subEntry);
|
||||||
if (dependents == null) {
|
if (dependents == null) {
|
||||||
dependents = new HashSet<Entry>();
|
dependents = new HashSet<>();
|
||||||
whoDependsOnMe.put(subEntry, dependents);
|
whoDependsOnMe.put(subEntry, dependents);
|
||||||
}
|
}
|
||||||
dependents.add(entry); //ignores duplicates
|
dependents.add(entry); //ignores duplicates
|
||||||
Set<Entry> support = whoIDependOn.get(entry);
|
Set<Entry> support = whoIDependOn.get(entry);
|
||||||
if (support == null) {
|
if (support == null) {
|
||||||
support = new HashSet<Entry>();
|
support = new HashSet<>();
|
||||||
whoIDependOn.put(entry, support);
|
whoIDependOn.put(entry, support);
|
||||||
}
|
}
|
||||||
support.add(subEntry); //ignores duplicates
|
support.add(subEntry); //ignores duplicates
|
||||||
|
@ -361,10 +368,10 @@ public class DataTypeDependencyOrderer {
|
||||||
}
|
}
|
||||||
Set<Entry> dependents = whoDependsOnMe.get(entry);
|
Set<Entry> dependents = whoDependsOnMe.get(entry);
|
||||||
if (dependents == null) {
|
if (dependents == null) {
|
||||||
dependents = new HashSet<Entry>();
|
dependents = new HashSet<>();
|
||||||
whoDependsOnMe.put(entry, dependents);
|
whoDependsOnMe.put(entry, dependents);
|
||||||
}
|
}
|
||||||
Set<Entry> support = new HashSet<Entry>();
|
Set<Entry> support = new HashSet<>();
|
||||||
whoIDependOn.put(entry, support);
|
whoIDependOn.put(entry, support);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2151,7 +2151,7 @@ public class CodeManager implements ErrorHandler, ManagerDB {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createReference(Data data, Address toAddr, List<Address> longSegmentAddressList) {
|
private void createReference(Data data, Address toAddr, List<Address> longSegmentAddressList) {
|
||||||
if (toAddr == null) {
|
if (toAddr == null || !toAddr.isLoadedMemoryAddress()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -421,6 +421,12 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
||||||
for (DataTypeComponent comp : comps) {
|
for (DataTypeComponent comp : comps) {
|
||||||
comp.getDataType().addParent(dt);
|
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) {
|
else if (dt instanceof FunctionDefinition) {
|
||||||
FunctionDefinition funDef = (FunctionDefinition) dt;
|
FunctionDefinition funDef = (FunctionDefinition) dt;
|
||||||
|
|
|
@ -649,6 +649,7 @@ class StructureDB extends CompositeDB implements Structure {
|
||||||
return 1; // Unaligned
|
return 1; // Unaligned
|
||||||
}
|
}
|
||||||
if (alignment <= 0) {
|
if (alignment <= 0) {
|
||||||
|
// just in case - alignment should have been previously determined and stored
|
||||||
StructurePackResult packResult = AlignedStructureInspector.packComponents(this);
|
StructurePackResult packResult = AlignedStructureInspector.packComponents(this);
|
||||||
alignment = packResult.alignment;
|
alignment = packResult.alignment;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,11 @@ import javax.help.UnsupportedOperationException;
|
||||||
import ghidra.docking.settings.Settings;
|
import ghidra.docking.settings.Settings;
|
||||||
import ghidra.util.exception.DuplicateNameException;
|
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 {
|
public class AlignedStructureInspector extends AlignedStructurePacker {
|
||||||
|
|
||||||
private AlignedStructureInspector(Structure structure) {
|
private AlignedStructureInspector(Structure structure) {
|
||||||
|
@ -34,6 +39,9 @@ public class AlignedStructureInspector extends AlignedStructurePacker {
|
||||||
for (DataTypeComponent c : structure.getComponents()) {
|
for (DataTypeComponent c : structure.getComponents()) {
|
||||||
list.add(new ReadOnlyComponentWrapper(c));
|
list.add(new ReadOnlyComponentWrapper(c));
|
||||||
}
|
}
|
||||||
|
if (structure.hasFlexibleArrayComponent()) {
|
||||||
|
list.add(new ReadOnlyComponentWrapper(structure.getFlexibleArrayComponent()));
|
||||||
|
}
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,10 +63,10 @@ public class AlignedStructureInspector extends AlignedStructurePacker {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void update(int ordinal, int offset, int length) {
|
public void update(int ord, int off, int len) {
|
||||||
this.ordinal = ordinal;
|
this.ordinal = ord;
|
||||||
this.offset = offset;
|
this.offset = off;
|
||||||
this.length = length;
|
this.length = len;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -73,7 +81,7 @@ public class AlignedStructureInspector extends AlignedStructurePacker {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isFlexibleArrayComponent() {
|
public boolean isFlexibleArrayComponent() {
|
||||||
return false;
|
return component.isFlexibleArrayComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -340,7 +340,18 @@ public class BitFieldDataType extends AbstractDataType {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getDescription() {
|
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
|
@Override
|
||||||
|
|
|
@ -242,7 +242,7 @@ public class DataTypeWriter {
|
||||||
}
|
}
|
||||||
Msg.error(this, "Factory data types may not be written - type: " + dt, iae);
|
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);
|
write(getBaseDataType(dt), monitor);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -308,6 +308,9 @@ public class DataTypeWriter {
|
||||||
else if (dt instanceof BuiltInDataType) {
|
else if (dt instanceof BuiltInDataType) {
|
||||||
writeBuiltIn((BuiltInDataType) dt, monitor);
|
writeBuiltIn((BuiltInDataType) dt, monitor);
|
||||||
}
|
}
|
||||||
|
else if (dt instanceof BitFieldDataType) {
|
||||||
|
// skip
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
writer.write(EOL);
|
writer.write(EOL);
|
||||||
writer.write(EOL);
|
writer.write(EOL);
|
||||||
|
@ -540,7 +543,12 @@ public class DataTypeWriter {
|
||||||
|
|
||||||
if (componentString == null) {
|
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;
|
Array array = (Array) dataType;
|
||||||
name += getArrayDimensions(array);
|
name += getArrayDimensions(array);
|
||||||
dataType = getArrayBaseType(array);
|
dataType = getArrayBaseType(array);
|
||||||
|
@ -637,6 +645,7 @@ public class DataTypeWriter {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// TODO: A comment explaining the special 'P' case would be helpful!! Smells like fish.
|
||||||
else if (baseType instanceof Pointer && typedefName.startsWith("P")) {
|
else if (baseType instanceof Pointer && typedefName.startsWith("P")) {
|
||||||
DataType dt = ((Pointer) baseType).getDataType();
|
DataType dt = ((Pointer) baseType).getDataType();
|
||||||
if (dt instanceof TypeDef) {
|
if (dt instanceof TypeDef) {
|
||||||
|
@ -765,6 +774,10 @@ public class DataTypeWriter {
|
||||||
Pointer pointer = (Pointer) dt;
|
Pointer pointer = (Pointer) dt;
|
||||||
dt = pointer.getDataType();
|
dt = pointer.getDataType();
|
||||||
}
|
}
|
||||||
|
else if (dt instanceof BitFieldDataType) {
|
||||||
|
BitFieldDataType bitfieldDt = (BitFieldDataType) dt;
|
||||||
|
dt = bitfieldDt.getBaseDataType();
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,9 +25,9 @@ public interface InternalDataTypeComponent extends DataTypeComponent {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update component ordinal, offset and length during alignment
|
* Update component ordinal, offset and length during alignment
|
||||||
* @param ordinal
|
* @param ordinal updated ordinal
|
||||||
* @param offset
|
* @param offset updated offset
|
||||||
* @param length
|
* @param length updated byte length
|
||||||
*/
|
*/
|
||||||
void update(int ordinal, int offset, int length);
|
void update(int ordinal, int offset, int length);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue