Merge remote-tracking branch 'origin/patch'

This commit is contained in:
ghidra1 2021-01-11 23:06:39 -05:00
commit fb5ab7569d
20 changed files with 524 additions and 762 deletions

View file

@ -204,7 +204,7 @@ public class BitFieldEditorPanel extends JPanel {
private JComponent createDataTypeChoiceEditor() {
dtChoiceEditor =
new DataTypeSelectionEditor(dtmService, -1, AllowedDataTypes.BITFIELD_BASE_TYPE);
new DataTypeSelectionEditor(dtmService, AllowedDataTypes.BITFIELD_BASE_TYPE);
dtChoiceEditor.setConsumeEnterKeyPress(false);
dtChoiceEditor.setTabCommitsEdit(true);
//dtChoiceEditor.setPreferredDataTypeManager(composite.getDataTypeManager());
@ -539,7 +539,7 @@ public class BitFieldEditorPanel extends JPanel {
dtChoiceEditor.getDropDownTextField().setText("");
fieldNameTextField.setText(null);
fieldCommentTextField.setText(null);
;
bitOffsetModel.setValue(0L);
bitSizeModel.setValue(1L);
}

View file

@ -1255,7 +1255,7 @@ public abstract class CompositeEditorPanel extends JPanel
Plugin plugin = provider.getPlugin();
final PluginTool tool = plugin.getTool();
editor = new DataTypeSelectionEditor(tool, maxLength,
editor = new DataTypeSelectionEditor(tool,
bitfieldAllowed ? AllowedDataTypes.SIZABLE_DYNAMIC_AND_BITFIELD
: AllowedDataTypes.SIZABLE_DYNAMIC);
editor.setTabCommitsEdit(true);
@ -1287,12 +1287,7 @@ public abstract class CompositeEditorPanel extends JPanel
}
};
dataTypeChooserButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
Swing.runLater(() -> stopEdit(tool));
}
});
dataTypeChooserButton.addActionListener(e -> Swing.runLater(() -> stopEdit(tool)));
textField.addFocusListener(new FocusAdapter() {
@Override

View file

@ -24,12 +24,8 @@ import docking.action.*;
import ghidra.app.context.ListingActionContext;
import ghidra.app.util.datatype.DataTypeSelectionDialog;
import ghidra.framework.plugintool.PluginTool;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressRange;
import ghidra.program.model.data.*;
import ghidra.program.model.listing.*;
import ghidra.program.util.*;
import ghidra.util.SystemUtilities;
import ghidra.program.model.data.DataType;
import ghidra.program.model.listing.Data;
import ghidra.util.data.DataTypeParser.AllowedDataTypes;
/**
@ -58,121 +54,21 @@ public class ChooseDataTypeAction extends DockingAction {
@Override
public void actionPerformed(ActionContext context) {
ListingActionContext programActionContext =
(ListingActionContext) context.getContextObject();
int maxSize = Integer.MAX_VALUE;
Program program = programActionContext.getProgram();
ProgramLocation loc = programActionContext.getLocation();
ProgramSelection sel = programActionContext.getSelection();
if (sel != null && !sel.isEmpty()) {
InteriorSelection interiorSel = sel.getInteriorSelection();
if (interiorSel != null) {
maxSize = getSizeInsideStructure(program, interiorSel);
}
else {
maxSize = getSizeForSelection(program, sel);
}
}
else {
int[] compPath = loc.getComponentPath();
if (compPath != null && compPath.length > 0) {
maxSize = getSizeInsideStructure(program, loc);
}
else {
maxSize = getSizeForAddress(program, loc);
}
}
// unable to create data types at the current location
if (maxSize < 0) {
return;
}
Pointer pointer = program.getDataTypeManager().getPointer(null);
DataType dataType = getDataType(programActionContext, maxSize, pointer.getLength());
ListingActionContext listingContext = (ListingActionContext) context.getContextObject();
DataType dataType = getDataType(listingContext);
if (dataType != null) {
plugin.doCreateData(program, loc, sel, dataType, false);
plugin.createData(dataType, listingContext, true);
}
}
private int getSizeInsideStructure(Program program, InteriorSelection selection) {
ProgramLocation location = selection.getFrom();
Data dataComponent = getParentDataType(program, location);
if (dataComponent == null) {
return -1;
}
return selection.getByteLength();
}
private int getSizeInsideStructure(Program program, ProgramLocation location) {
Data dataComponent = getParentDataType(program, location);
if (dataComponent == null) {
return -1;
}
return getMaxSizeInStructure((Structure) dataComponent.getParent().getBaseDataType(),
dataComponent.getComponentIndex());
}
private int getSizeForAddress(Program program, ProgramLocation location) {
Address address = location.getAddress();
Data data = program.getListing().getDataAt(address);
if (data == null) {
plugin.getTool().setStatusInfo("Create Data Failed! No data at " + address);
return -1;
}
return getMaxSize(program, address);
}
private Data getParentDataType(Program program, ProgramLocation location) {
int[] path = location.getComponentPath();
Address address = location.getAddress();
Data data = program.getListing().getDataContaining(address);
Data dataComponent = null;
if (data != null) {
dataComponent = data.getComponent(path);
}
if (dataComponent == null) {
plugin.getTool().setStatusInfo("Create data type failed! No data at " + address);
return null;
}
DataType parentDataType = dataComponent.getParent().getBaseDataType();
if (!(parentDataType instanceof Structure)) {
plugin.getTool().setStatusInfo("Cannot set data type here.");
return null;
}
return dataComponent;
}
private int getSizeForSelection(Program program, ProgramSelection selection) {
PluginTool tool = plugin.getTool();
AddressRange range = selection.getFirstRange();
Address address = selection.getMinAddress();
Data data = program.getListing().getDataAt(address);
if (data == null) {
tool.setStatusInfo("Cannot set data type! No data at " + address);
return -1;
}
return (int) range.getLength();
}
private DataType getDataType(ListingActionContext context, int maxElements,
int defaultPointerSize) {
private DataType getDataType(ListingActionContext context) {
PluginTool tool = plugin.getTool();
Data data = plugin.getDataUnit(context);
int noSizeRestriction = -1;
DataTypeSelectionDialog selectionDialog = new DataTypeSelectionDialog(tool,
data.getProgram().getDataTypeManager(), maxElements, AllowedDataTypes.ALL);
DataType currentDataType = data.getBaseDataType();
selectionDialog.setInitialDataType(currentDataType);
data.getProgram().getDataTypeManager(), noSizeRestriction, AllowedDataTypes.ALL);
DataType initialType = data.getBaseDataType();
selectionDialog.setInitialDataType(initialType);
tool.showDialog(selectionDialog);
return selectionDialog.getUserChosenDataType();
}
@ -185,47 +81,4 @@ public class ChooseDataTypeAction extends DockingAction {
}
return false;
}
private int getMaxSizeInStructure(Structure struct, int index) {
int n = struct.getNumComponents();
DataTypeComponent dtc = struct.getComponent(index++);
int length = dtc.getLength();
while (index < n) {
dtc = struct.getComponent(index++);
DataType dataType = dtc.getDataType();
if (dataType != DataType.DEFAULT) {
break;
}
length += dtc.getLength();
}
return length;
}
private int getMaxSize(Program program, Address addr) {
// can't go past the end of a block to start with
Address maxAddr = program.getMemory().getBlock(addr).getEnd();
// get the next non undefined element in memory
Instruction instr = program.getListing().getInstructionAfter(addr);
if (instr != null) {
Address instrAddr = instr.getMinAddress();
if (instrAddr.compareTo(maxAddr) < 0) {
maxAddr = instrAddr.subtract(1);
}
}
Data data = DataUtilities.getNextNonUndefinedDataAfter(program, addr, maxAddr);
if (data != null) {
Address dataAddr = data.getMinAddress();
if (dataAddr.compareTo(maxAddr) < 0) {
maxAddr = dataAddr.subtract(1);
}
}
long length = maxAddr.subtract(addr) + 1;
SystemUtilities.assertTrue(length > 0,
"Subtraction an address from the max address in its block should never be negative");
return length > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) length;
}
}

View file

@ -238,31 +238,13 @@ public class DataPlugin extends Plugin implements DataService {
dtmService.addDataTypeManagerChangeListener(adapter);
}
boolean isEditDataTypeAllowed(ListingActionContext context) {
Data data = getDataUnit(context);
if (data == null || dtmService == null) {
return false;
}
if (dtmService.isEditable(data.getBaseDataType())) {
return true;
}
Data pdata = data.getParent();
if (pdata != null) {
if (dtmService.isEditable(pdata.getBaseDataType())) {
return true;
}
}
return false;
}
DataType getEditableDataTypeFromContext(ListingActionContext context) {
ProgramSelection currentSelection = context.getSelection();
Program currentProgram = context.getProgram();
DataType editableDataType = null;
ProgramSelection selection = context.getSelection();
Program program = context.getProgram();
Data data = null;
if (currentSelection != null && !currentSelection.isEmpty()) {
Listing listing = currentProgram.getListing();
boolean isDataOnly = !listing.getInstructions(currentSelection, true).hasNext();
if (selection != null && !selection.isEmpty()) {
Listing listing = program.getListing();
boolean isDataOnly = !listing.getInstructions(selection, true).hasNext();
if (isDataOnly) {
data = getDataUnit(context);
}
@ -270,30 +252,30 @@ public class DataPlugin extends Plugin implements DataService {
else {
data = getDataUnit(context);
}
if (data != null) {
if (dtmService != null) {
return getEditableDataType(data);
}
private DataType getEditableDataType(Data data) {
if (data == null || dtmService == null) {
return null;
}
DataType baseDt = data.getBaseDataType();
if (dtmService.isEditable(baseDt)) {
editableDataType = baseDt;
return baseDt;
}
else {
Data pdata = data.getParent();
if (pdata != null) {
baseDt = pdata.getBaseDataType();
if (dtmService.isEditable(baseDt)) {
editableDataType = baseDt;
return baseDt;
}
}
}
}
}
return editableDataType;
return null;
}
/**
* @see ghidra.app.services.DataService#createData(ghidra.program.model.data.DataType,
* ghidra.app.context.ListingActionContext, boolean)
*/
@Override
public boolean createData(DataType dt, ListingActionContext context,
boolean enableConflictHandling) {
@ -307,8 +289,7 @@ public class DataPlugin extends Plugin implements DataService {
}
/*
* This version uses the ProgramActionContext and does not depend on any
* plugin's currentProgram
* This version uses the ListingActionContext and does not depend on any plugin's currentProgram
*/
boolean doCreateData(ListingActionContext context, DataType dt) {
ProgramSelection selection = context.getSelection();
@ -316,7 +297,7 @@ public class DataPlugin extends Plugin implements DataService {
Program program = context.getProgram();
dt = dt.clone(program.getDataTypeManager());
boolean didCreateData = true;
boolean didCreateData = false;
if (selection != null && !selection.isEmpty()) {
didCreateData = createDataForSelection(program, dt, selection);
}
@ -375,7 +356,7 @@ public class DataPlugin extends Plugin implements DataService {
Listing listing = program.getListing();
Data data = listing.getDataAt(start);
if (data == null) {
tool.setStatusInfo("Invalid data location");
tool.setStatusInfo("Invalid data location. Cannot create data at " + start + '.');
return false;
}
@ -393,10 +374,13 @@ public class DataPlugin extends Plugin implements DataService {
end = start.addNoWrap(newSize - 1);
}
catch (AddressOverflowException e) {
tool.setStatusInfo("Invalid data location. Not enough space at " + start + " for " +
newSize + " bytes.");
return false;
}
if (intstrutionExists(listing, dataType, start, end)) {
tool.setStatusInfo("Invalid data location. Instruction exists at " + start + '.');
return false;
}
@ -415,7 +399,7 @@ public class DataPlugin extends Plugin implements DataService {
Data definedData =
DataUtilities.getNextNonUndefinedDataAfter(program, start, blockMaxAddress);
if (dataExists(program, dataType, definedData, start, end)) {
return false;
return false; // status updated in 'dataExists()' call
}
return true;
@ -516,58 +500,6 @@ public class DataPlugin extends Plugin implements DataService {
return dataTypeInstance.getLength();
}
boolean doCreateData(Program program, ProgramLocation loc, ProgramSelection sel, DataType dt) {
return doCreateData(program, loc, sel, dt, true);
}
boolean doCreateData(Program program, ProgramLocation loc, ProgramSelection sel, DataType dt,
boolean convertPointers) {
// Handle selection case
boolean rc = true;
if (sel != null && !sel.isEmpty()) {
BackgroundCommand cmd;
Address start = sel.getMinAddress();
InteriorSelection interSel = sel.getInteriorSelection();
if (interSel != null) {
int[] startPath = interSel.getFrom().getComponentPath();
int length = (int) sel.getNumAddresses(); // interior selections can't be that big
cmd = new CreateDataInStructureBackgroundCmd(start, startPath, length, dt,
convertPointers);
}
else {
cmd = new CreateDataBackgroundCmd(sel, dt, convertPointers);
}
if (sel.getNumAddresses() < DataPlugin.BACKGROUND_SELECTION_THRESHOLD) {
rc = tool.execute(cmd, program);
}
else {
getPluginTool().executeBackgroundCommand(cmd, program);
}
}
// Handle single location case
else if (loc != null) {
Address start = loc.getAddress();
int[] startPath = loc.getComponentPath();
Command cmd;
if (startPath != null && startPath.length != 0) {
cmd = new CreateDataInStructureCmd(start, startPath, dt, convertPointers);
}
else {
if (!checkEnoughSpace(program, start, dt, convertPointers)) {
return false;
}
cmd = new CreateDataCmd(start, dt, false, convertPointers);
}
rc = getPluginTool().execute(cmd, program);
}
updateRecentlyUsed(dt);
return rc;
}
PluginTool getPluginTool() {
return tool;
}
@ -741,9 +673,6 @@ public class DataPlugin extends Plugin implements DataService {
}
}
/**
* @see ghidra.framework.plugintool.Plugin#dispose()
*/
@Override
public void dispose() {
favoritesUpdateManager.dispose();
@ -756,10 +685,6 @@ public class DataPlugin extends Plugin implements DataService {
createStructureAction.dispose();
}
/**
* @see ghidra.app.plugin.ProgramPlugin#locationChanged(ghidra.program.util.ProgramLocation)
* @see ghidra.app.plugin.ProgramPlugin#selectionChanged(ghidra.program.util.ProgramSelection)
*/
Data getDataUnit(ListingActionContext context) {
ProgramLocation location = context.getLocation();
ProgramSelection selection = context.getSelection();

View file

@ -69,7 +69,7 @@ public class CreateTypeDefDialog extends DialogComponentProvider {
// data type info
dataTypeEditor =
new DataTypeSelectionEditor(plugin.getTool(), Integer.MAX_VALUE, AllowedDataTypes.ALL);
new DataTypeSelectionEditor(plugin.getTool(), AllowedDataTypes.ALL);
panel.add(new GLabel("Data type:"));
panel.add(dataTypeEditor.getEditorComponent());

View file

@ -374,6 +374,7 @@ public class FunctionPlugin extends Plugin implements DataService {
* Get an iterator over all functions overlapping the current selection.
* If there is no selection any functions overlapping the current location.
*
* @param context the context
* @return Iterator over functions
*/
public Iterator<Function> getFunctions(ListingActionContext context) {
@ -470,11 +471,10 @@ public class FunctionPlugin extends Plugin implements DataService {
* Lay down the specified dataType on a function return, parameter or local variable
* based upon the programActionContext. Pointer conversion will be handled
* by merging the existing dataType with the specified dataType.
* @param dataType The DataType to create.
* @param dt The DataType to create.
* @param programActionContext action context
* @param promptForConflictRemoval if true and specified dataType results in a storage conflict,
* @param enableConflictHandling if true and specified dataType results in a storage conflict,
* user may be prompted for removal of conflicting variables (not applicable for return type)
* @return True if the DataType could be created at the given location.
*/
@Override
public boolean createData(DataType dt, ListingActionContext programActionContext,
@ -483,11 +483,12 @@ public class FunctionPlugin extends Plugin implements DataService {
}
/**
* This method is the same as {@link #createData(DataType, ProgramLocation)}, except that this
* method will use the given value of <tt>convertPointers</tt> to determine if the new
* DataType should be made into a pointer if the existing DataType is a pointer.
* @param dataType The DataType to create.
* @param location The location at which to create the DataType.
* This method is the same as {@link #createData(DataType, ListingActionContext, boolean)},
* except that this method will use the given value of <tt>convertPointers</tt> to determine
* if the new DataType should be made into a pointer if the existing DataType is a pointer.
*
* @param dataType the DataType to create
* @param context the context containing the location at which to create the DataType
* @param convertPointers True signals to convert the given DataType to a pointer if there is
* an existing pointer at the specified location.
* @param promptForConflictRemoval if true and specified dataType results in a storage conflict,
@ -609,23 +610,12 @@ public class FunctionPlugin extends Plugin implements DataService {
return null;
}
// private boolean checkStackVarToFit(Function fun, StackVariable var, DataType dt) {
// if (var.getDataType() instanceof Pointer) {
// return true;
// }
// int startOffset = var.getLength();
// if (startOffset < 0) startOffset = 1;
// int size = getMaxStackVariableSize(fun, var);
// if (size < 0) return true;
// return size >= dt.getLength();
// }
/**
* Return the maximum data type length permitted
* for the specified local variable. A -1 returned
* value indicates no limit imposed.
* @param fun
* @param var
* Return the maximum data type length permitted for the specified local variable. A -1
* returned value indicates no limit imposed.
*
* @param fun the function
* @param var the variable
* @return maximum data type length permitted for var
*/
int getMaxStackVariableSize(Function fun, Variable var) {

View file

@ -61,7 +61,7 @@ class ParameterDataTypeCellEditor extends AbstractCellEditor implements TableCel
}
private void init() {
editor = new DataTypeSelectionEditor(service, -1, DataTypeParser.AllowedDataTypes.ALL);
editor = new DataTypeSelectionEditor(service, DataTypeParser.AllowedDataTypes.ALL);
editor.setTabCommitsEdit(true);
editor.setConsumeEnterKeyPress(false); // we want the table to handle Enter key presses
@ -88,13 +88,7 @@ class ParameterDataTypeCellEditor extends AbstractCellEditor implements TableCel
}
};
dataTypeChooserButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
dataTypeChooserButton.addActionListener(e -> SwingUtilities.invokeLater(() -> {
DataType dataType = service.getDataType((String) null);
if (dataType != null) {
editor.setCellEditorValue(dataType);
@ -103,10 +97,7 @@ class ParameterDataTypeCellEditor extends AbstractCellEditor implements TableCel
else {
editor.cancelCellEditing();
}
}
});
}
});
}));
FocusAdapter focusListener = new FocusAdapter() {
@Override

View file

@ -20,13 +20,9 @@ import ghidra.framework.plugintool.ServiceInfo;
import ghidra.program.model.data.DataType;
/**
* Data Creation service.
*
* NOTE: This version is dependant on the currentProgram of the implementing
* plugin class. If you want a version that is not dependant on it, please use
* DataCreationService
* Service for creating data
*/
@ServiceInfo(description = "Data creation service.")
@ServiceInfo(description = "Data creation service")
public interface DataService {
/**
@ -42,13 +38,12 @@ public interface DataService {
/**
* Apply the given data type at a location.
*
* @param dt
* dataType to create at the location
* @param context
* the context containing program, location, and selection information
* @param enableConflictHandling
* if true, the service may prompt the user to resolve data conflicts
* @param dt data type to create at the location
* @param context the context containing program, location, and selection information
* @param enableConflictHandling if true, the service may prompt the user to resolve data
* conflicts
* @return true if the data could be created at the current location
*/
public boolean createData(DataType dt, ListingActionContext context, boolean enableConflictHandling);
public boolean createData(DataType dt, ListingActionContext context,
boolean enableConflictHandling);
}

View file

@ -63,7 +63,7 @@ public class DataTypeSelectionDialog extends DialogComponentProvider {
private void buildEditor() {
removeWorkPanel();
editor = new DataTypeSelectionEditor(pluginTool, maxSize, allowedTypes);
editor = new DataTypeSelectionEditor(pluginTool, allowedTypes);
editor.setPreferredDataTypeManager(dtm);
editor.setConsumeEnterKeyPress(false); // we want to handle Enter key presses
editor.addCellEditorListener(new CellEditorListener() {
@ -171,6 +171,7 @@ public class DataTypeSelectionDialog extends DialogComponentProvider {
* This method is useful for widgets that have embedded editors that launch this dialog. For
* these editors, like tables, it is nice to be able to tab through various editors. This
* method allows these editors to keep this functionality, even though a new dialog was shown.
* @param doesCommit true commits edits on Tab press
*/
public void setTabCommitsEdit(boolean doesCommit) {
editor.setTabCommitsEdit(doesCommit);

View file

@ -59,7 +59,6 @@ public class DataTypeSelectionEditor extends AbstractCellEditor {
private DropDownSelectionTextField<DataType> selectionField;
private JButton browseButton;
private DataTypeManagerService dataTypeManagerService;
private int maxSize = -1;
private DataTypeManager dataTypeManager;
private DataTypeParser.AllowedDataTypes allowedDataTypes;
@ -69,12 +68,12 @@ public class DataTypeSelectionEditor extends AbstractCellEditor {
// optional path to initially select in the data type chooser tree
private TreePath initiallySelectedTreePath;
public DataTypeSelectionEditor(ServiceProvider serviceProvider, int maxSize,
public DataTypeSelectionEditor(ServiceProvider serviceProvider,
DataTypeParser.AllowedDataTypes allowedDataTypes) {
this(serviceProvider.getService(DataTypeManagerService.class), maxSize, allowedDataTypes);
this(serviceProvider.getService(DataTypeManagerService.class), allowedDataTypes);
}
public DataTypeSelectionEditor(DataTypeManagerService service, int maxSize,
public DataTypeSelectionEditor(DataTypeManagerService service,
DataTypeParser.AllowedDataTypes allowedDataTypes) {
if (service == null) {
@ -82,7 +81,6 @@ public class DataTypeSelectionEditor extends AbstractCellEditor {
}
this.dataTypeManagerService = service;
this.maxSize = maxSize;
this.allowedDataTypes = allowedDataTypes;
init();
@ -102,7 +100,10 @@ public class DataTypeSelectionEditor extends AbstractCellEditor {
}
/**
* Sets whether this editor should consumer Enter key presses
* @see DropDownSelectionTextField#setConsumeEnterKeyPress(boolean)
*
* @param consume true to consume
*/
public void setConsumeEnterKeyPress(boolean consume) {
selectionField.setConsumeEnterKeyPress(consume);
@ -276,6 +277,7 @@ public class DataTypeSelectionEditor extends AbstractCellEditor {
/**
* Returns the direction of the user triggered navigation; null if the user did not trigger
* navigation out of this component.
* @return the direction
*/
public NavigationDirection getNavigationDirection() {
return navigationDirection;
@ -362,10 +364,8 @@ public class DataTypeSelectionEditor extends AbstractCellEditor {
catch (CancelledException e) {
return false;
}
if (newDataType != null) {
if (maxSize >= 0 && newDataType.getLength() > newDataType.getLength()) {
throw new InvalidDataTypeException("data-type larger than " + maxSize + " bytes");
}
selectionField.setSelectedValue(newDataType);
return true;
}

View file

@ -95,8 +95,8 @@ public class DataTypeParser {
* the source data type manager, this means that all data type managers will be used when
* resolving data types.
*
* @param dataTypeManagerService
* @param allowedTypes
* @param dataTypeManagerService data-type manager tool service, or null
* @param allowedTypes constrains which data-types may be parsed
*/
public DataTypeParser(DataTypeQueryService dataTypeManagerService,
AllowedDataTypes allowedTypes) {

View file

@ -15,6 +15,7 @@
*/
package ghidra.app.plugin.core.data;
import static org.hamcrest.core.StringContains.*;
import static org.junit.Assert.*;
import javax.swing.*;
@ -22,9 +23,9 @@ import javax.swing.*;
import org.apache.commons.lang3.StringUtils;
import org.junit.*;
import docking.DialogComponentProvider;
import docking.DockingDialog;
import docking.*;
import docking.action.DockingActionIf;
import generic.test.TestUtils;
import ghidra.app.cmd.disassemble.DisassembleCommand;
import ghidra.app.plugin.core.codebrowser.*;
import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin;
@ -50,7 +51,6 @@ import ghidra.test.TestEnv;
public class ApplyDataTypeToBrowserTest extends AbstractGhidraHeadedIntegrationTest {
private static final String PROGRAM_FILENAME = "WallaceSrc";
private static final int TASK_TIMEOUT = 2000;
private static final String CYCLE_BYTE_WORD_DWORD_QWORD = "Cycle: byte,word,dword,qword";
private TestEnv env;
@ -63,6 +63,7 @@ public class ApplyDataTypeToBrowserTest extends AbstractGhidraHeadedIntegrationT
private DataTypeArchiveGTree tree;
private ArchiveRootNode archiveRootNode;
private ArchiveNode programNode;
private CodeViewerProvider codeViewerProvider;
@Before
public void setUp() throws Exception {
@ -94,6 +95,9 @@ public class ApplyDataTypeToBrowserTest extends AbstractGhidraHeadedIntegrationT
assertNotNull("Did not successfully wait for the program node to load", programNode);
tool.showComponentProvider(provider, true);
CodeBrowserPlugin codeBrowserPlugin = env.getPlugin(CodeBrowserPlugin.class);
codeViewerProvider = codeBrowserPlugin.getProvider();
}
private ProgramDB buildWallaceSrcProgram() throws Exception {
@ -121,24 +125,19 @@ public class ApplyDataTypeToBrowserTest extends AbstractGhidraHeadedIntegrationT
executeOnSwingWithoutBlocking(() -> {
ProgramManager pm = tool.getService(ProgramManager.class);
pm.closeProgram();
});
// this handles the save changes dialog and potential analysis dialogs
closeAllWindowsAndFrames();
closeAllWindows();
env.release(program);
env.dispose();
}
@Test
public void testChooseDataTypeOnDefaultDts() throws Exception {
CodeViewerProvider codeViewerProvider = positionListingCursorAtAddress("004027d0");
waitForSwing();
goTo("004027d0");
DockingActionIf chooseDataTypeAction = getAction(dataPlugin, "Choose Data Type");
assertNotNull(chooseDataTypeAction);
performAction(chooseDataTypeAction, codeViewerProvider, false);
showDataTypeChooser();
chooseInDialog("_person");
@ -152,12 +151,9 @@ public class ApplyDataTypeToBrowserTest extends AbstractGhidraHeadedIntegrationT
@Test
public void testChooseDataTypeOnUndefinedDts() throws Exception {
createData("004027d2", new Undefined4DataType());
CodeViewerProvider codeViewerProvider = positionListingCursorAtAddress("004027d0");
waitForSwing();
goTo("004027d0");
DockingActionIf chooseDataTypeAction = getAction(dataPlugin, "Choose Data Type");
assertNotNull(chooseDataTypeAction);
performAction(chooseDataTypeAction, codeViewerProvider, false);
showDataTypeChooser();
chooseInDialog("_person");
@ -170,80 +166,67 @@ public class ApplyDataTypeToBrowserTest extends AbstractGhidraHeadedIntegrationT
@Test
public void testChooseDataTypeOnDefinedDts() throws Exception {
//
// Test that apply data on an existing type will offer to clear that type
//
createData("004027d1", new ByteDataType());
CodeViewerProvider codeViewerProvider = positionListingCursorAtAddress("004027d0");
waitForSwing();
goTo("004027d0");
DockingActionIf chooseDataTypeAction = getAction(dataPlugin, "Choose Data Type");
assertNotNull(chooseDataTypeAction);
performAction(chooseDataTypeAction, codeViewerProvider, false);
showDataTypeChooser();
DialogComponentProvider dialog =
chooseInDialog("_person", "_person doesn't fit within 1 bytes, need 41 bytes");
chooseInDialog("_person");
pressConflictingDataDialog("Yes");
Data data = program.getListing().getDataAt(addr("004027d0"));
assertEquals(DataType.DEFAULT, data.getDataType());
assertEquals(addr("004027d0"), data.getMaxAddress());
pressButtonByText(dialog, "Cancel");
waitForSwing();
ProgramDataTypeManager dataTypeManager = program.getDataTypeManager();
DataType dataType = dataTypeManager.getDataType(new CategoryPath("/"), "_person");
assertEquals(dataType, data.getDataType());
assertEquals(addr("004027f8"), data.getMaxAddress());
}
@Test
public void testChooseDataTypeOnDefinedAndUndefinedDts() throws Exception {
createData("004027d1", new ByteDataType());
createData("004027d2", new Undefined4DataType());
CodeViewerProvider codeViewerProvider = positionListingCursorAtAddress("004027d0");
waitForSwing();
goTo("004027d0");
DockingActionIf chooseDataTypeAction = getAction(dataPlugin, "Choose Data Type");
assertNotNull(chooseDataTypeAction);
performAction(chooseDataTypeAction, codeViewerProvider, false);
DialogComponentProvider dialog =
chooseInDialog("_person", "_person doesn't fit within 1 bytes, need 41 bytes");
showDataTypeChooser();
chooseInDialog("_person");
pressConflictingDataDialog("No");
Data data = program.getListing().getDataAt(addr("004027d0"));
assertEquals(DataType.DEFAULT, data.getDataType());
assertEquals(addr("004027d0"), data.getMaxAddress());
pressButtonByText(dialog, "Cancel");
waitForSwing();
}
@Test
public void testChooseDataTypeWhereDoesNotFit() throws Exception {
CodeViewerProvider codeViewerProvider = positionListingCursorAtAddress("004027e0");
waitForSwing();
goTo("004027e0");
DockingActionIf chooseDataTypeAction = getAction(dataPlugin, "Choose Data Type");
assertNotNull(chooseDataTypeAction);
performAction(chooseDataTypeAction, codeViewerProvider, false);
showDataTypeChooser();
DialogComponentProvider dialog =
chooseInDialog("_person", "_person doesn't fit within 32 bytes, need 41 bytes");
showDataTypeChooser();
chooseInDialog("_person");
assertToolStatus("Not enough room in memory block containing address");
Data data = program.getListing().getDataAt(addr("004027d0"));
assertEquals(DataType.DEFAULT, data.getDataType());
assertEquals(addr("004027d0"), data.getMaxAddress());
pressButtonByText(dialog, "Cancel");
waitForSwing();
}
@Test
public void testCreateArrayOnDefaultDts() throws Exception {
CodeViewerProvider codeViewerProvider = positionListingCursorAtAddress("004027d0");
waitForSwing();
goTo("004027d0");
DockingActionIf chooseDataTypeAction = getAction(dataPlugin, "Define Array");
assertNotNull(chooseDataTypeAction);
performAction(chooseDataTypeAction, codeViewerProvider, false);
waitForSwing();
JDialog dialog = waitForJDialog(tool.getToolFrame(), "Create undefined[]", 2000);
assertNotNull(dialog);
JDialog dialog = waitForJDialog("Create undefined[]");
JTextField tf = findComponent(dialog, JTextField.class);
triggerText(tf, "48");
waitForSwing();
@ -261,8 +244,7 @@ public class ApplyDataTypeToBrowserTest extends AbstractGhidraHeadedIntegrationT
@Test
public void testCreateArrayOnUndefinedDts() throws Exception {
createData("004027d2", new Undefined4DataType());
CodeViewerProvider codeViewerProvider = positionListingCursorAtAddress("004027d0");
waitForSwing();
goTo("004027d0");
DockingActionIf chooseDataTypeAction = getAction(dataPlugin, "Define Array");
assertNotNull(chooseDataTypeAction);
@ -270,8 +252,8 @@ public class ApplyDataTypeToBrowserTest extends AbstractGhidraHeadedIntegrationT
waitForSwing();
JDialog dialog = waitForJDialog(tool.getToolFrame(), "Create undefined[]", 2000);
assertNotNull(dialog);
JDialog dialog = waitForJDialog("Create undefined[]");
JTextField tf = findComponent(dialog, JTextField.class);
triggerText(tf, "48");
@ -288,8 +270,7 @@ public class ApplyDataTypeToBrowserTest extends AbstractGhidraHeadedIntegrationT
@Test
public void testCreateArrayFailureOnDefinedDts() throws Exception {
createData("004027d4", new ByteDataType());
CodeViewerProvider codeViewerProvider = positionListingCursorAtAddress("004027d0");
waitForSwing();
goTo("004027d0");
DockingActionIf chooseDataTypeAction = getAction(dataPlugin, "Define Array");
assertNotNull(chooseDataTypeAction);
@ -297,8 +278,7 @@ public class ApplyDataTypeToBrowserTest extends AbstractGhidraHeadedIntegrationT
waitForSwing();
JDialog dialog = waitForJDialog(tool.getToolFrame(), "Create undefined[]", 2000);
assertNotNull(dialog);
JDialog dialog = waitForJDialog("Create undefined[]");
checkStatus((DockingDialog) dialog, "Entering more than 4 will overwrite existing data");
@ -326,8 +306,7 @@ public class ApplyDataTypeToBrowserTest extends AbstractGhidraHeadedIntegrationT
createCode("004027d4", 1);
CodeViewerProvider codeViewerProvider = positionListingCursorAtAddress("004027d0");
waitForSwing();
goTo("004027d0");
DockingActionIf chooseDataTypeAction = getAction(dataPlugin, "Define Array");
assertNotNull(chooseDataTypeAction);
@ -335,8 +314,7 @@ public class ApplyDataTypeToBrowserTest extends AbstractGhidraHeadedIntegrationT
waitForSwing();
JDialog dialog = waitForJDialog(tool.getToolFrame(), "Create undefined[]", 2000);
assertNotNull(dialog);
JDialog dialog = waitForJDialog("Create undefined[]");
checkStatus((DockingDialog) dialog, " ");
@ -364,8 +342,7 @@ public class ApplyDataTypeToBrowserTest extends AbstractGhidraHeadedIntegrationT
createCode("004027d4", 1);
CodeViewerProvider codeViewerProvider = positionListingCursorAtAddress("004027d0");
waitForSwing();
goTo("004027d0");
DockingActionIf chooseDataTypeAction = getAction(dataPlugin, "Define Array");
assertNotNull(chooseDataTypeAction);
@ -373,8 +350,7 @@ public class ApplyDataTypeToBrowserTest extends AbstractGhidraHeadedIntegrationT
waitForSwing();
JDialog dialog = waitForJDialog(tool.getToolFrame(), "Create undefined[]", 2000);
assertNotNull(dialog);
JDialog dialog = waitForJDialog("Create undefined[]");
checkStatus((DockingDialog) dialog, " ");
@ -396,8 +372,7 @@ public class ApplyDataTypeToBrowserTest extends AbstractGhidraHeadedIntegrationT
@Test
public void testCreateArrayOverwriteOnDefinedDts() throws Exception {
createData("004027d4", new ByteDataType());
CodeViewerProvider codeViewerProvider = positionListingCursorAtAddress("004027d0");
waitForSwing();
goTo("004027d0");
DockingActionIf chooseDataTypeAction = getAction(dataPlugin, "Define Array");
assertNotNull(chooseDataTypeAction);
@ -405,8 +380,8 @@ public class ApplyDataTypeToBrowserTest extends AbstractGhidraHeadedIntegrationT
waitForSwing();
JDialog dialog = waitForJDialog(tool.getToolFrame(), "Create undefined[]", 2000);
assertNotNull(dialog);
JDialog dialog = waitForJDialog("Create undefined[]");
JTextField tf = findComponent(dialog, JTextField.class);
triggerText(tf, "48");
waitForSwing();
@ -417,8 +392,7 @@ public class ApplyDataTypeToBrowserTest extends AbstractGhidraHeadedIntegrationT
pressButtonByText(dialog, "OK");
waitForSwing();
dialog = waitForJDialog(tool.getToolFrame(), "Overwrite Existing Data?", 2000);
assertNotNull(dialog);
dialog = waitForJDialog("Overwrite Existing Data?");
pressButtonByText(dialog, "Yes");
waitForSwing();
@ -434,8 +408,7 @@ public class ApplyDataTypeToBrowserTest extends AbstractGhidraHeadedIntegrationT
DataType dataType = dataTypeManager.getDataType(new CategoryPath("/"), "_person");
plugin.setRecentlyUsed(dataType);
CodeViewerProvider codeViewerProvider = positionListingCursorAtAddress("004027d0");
waitForSwing();
goTo("004027d0");
DockingActionIf chooseDataTypeAction = getAction(dataPlugin, "Recently Used");
assertNotNull(chooseDataTypeAction);
@ -455,8 +428,7 @@ public class ApplyDataTypeToBrowserTest extends AbstractGhidraHeadedIntegrationT
plugin.setRecentlyUsed(dataType);
createData("004027d2", new Undefined4DataType());
CodeViewerProvider codeViewerProvider = positionListingCursorAtAddress("004027d0");
waitForSwing();
goTo("004027d0");
DockingActionIf chooseDataTypeAction = getAction(dataPlugin, "Recently Used");
assertNotNull(chooseDataTypeAction);
@ -476,20 +448,12 @@ public class ApplyDataTypeToBrowserTest extends AbstractGhidraHeadedIntegrationT
plugin.setRecentlyUsed(dataType);
createData("004027d1", new ByteDataType());
CodeViewerProvider codeViewerProvider = positionListingCursorAtAddress("004027d0");
waitForSwing();
goTo("004027d0");
DockingActionIf chooseDataTypeAction = getAction(dataPlugin, "Recently Used");
assertNotNull(chooseDataTypeAction);
performAction(chooseDataTypeAction, codeViewerProvider, false);
waitForSwing();
JDialog dialog = waitForJDialog(tool.getToolFrame(), "Data Conflict", 2000);
assertNotNull(dialog);
pressButtonByText(dialog, "Yes");
waitForSwing();
pressConflictingDataDialog("Yes");
Data data = program.getListing().getDataAt(addr("004027d0"));
assertEquals(dataType, data.getDataType());
@ -503,20 +467,13 @@ public class ApplyDataTypeToBrowserTest extends AbstractGhidraHeadedIntegrationT
plugin.setRecentlyUsed(dataType);
createData("004027d1", new ByteDataType());
CodeViewerProvider codeViewerProvider = positionListingCursorAtAddress("004027d0");
waitForSwing();
goTo("004027d0");
DockingActionIf chooseDataTypeAction = getAction(dataPlugin, "Recently Used");
assertNotNull(chooseDataTypeAction);
performAction(chooseDataTypeAction, codeViewerProvider, false);
waitForSwing();
JDialog dialog = waitForJDialog(tool.getToolFrame(), "Data Conflict", 2000);
assertNotNull(dialog);
pressButtonByText(dialog, "No");
waitForSwing();
pressConflictingDataDialog("No");
Data data = program.getListing().getDataAt(addr("004027d0"));
assertEquals(DataType.DEFAULT, data.getDataType());
@ -525,21 +482,18 @@ public class ApplyDataTypeToBrowserTest extends AbstractGhidraHeadedIntegrationT
@Test
public void testFavoriteOnDefaultDts() throws Exception {
CodeViewerProvider codeViewerProvider = positionListingCursorAtAddress("004027d0");
goTo("004027d0");
ProgramDataTypeManager dataTypeManager = program.getDataTypeManager();
DataType dataType = dataTypeManager.getDataType(new CategoryPath("/"), "_person");
// Set _person as a favorite
runSwing(() -> dataTypeManager.setFavorite(dataType, true), false);
waitForSwing();
final ProgramDataTypeManager dataTypeManager = program.getDataTypeManager();
final DataType dataType = dataTypeManager.getDataType(new CategoryPath("/"), "_person");
// Set _person as a favorite.
executeOnSwingWithoutBlocking(() -> dataTypeManager.setFavorite(dataType, true));
waitForSwing();
// Choose favorite.
// Choose favorite
DockingActionIf favoriteAction = getAction(dataPlugin, "Define _person");
assertNotNull(favoriteAction);
performAction(favoriteAction, codeViewerProvider, true);
waitForSwing();
Data data = program.getListing().getDataAt(addr("004027d0"));
@ -550,21 +504,18 @@ public class ApplyDataTypeToBrowserTest extends AbstractGhidraHeadedIntegrationT
@Test
public void testFavoriteOnUndefinedDts() throws Exception {
createData("004027d2", new Undefined4DataType());
CodeViewerProvider codeViewerProvider = positionListingCursorAtAddress("004027d0");
waitForSwing();
goTo("004027d0");
final ProgramDataTypeManager dataTypeManager = program.getDataTypeManager();
final DataType dataType = dataTypeManager.getDataType(new CategoryPath("/"), "_person");
ProgramDataTypeManager dataTypeManager = program.getDataTypeManager();
DataType dataType = dataTypeManager.getDataType(new CategoryPath("/"), "_person");
// Set _person as a favorite.
executeOnSwingWithoutBlocking(() -> dataTypeManager.setFavorite(dataType, true));
// Set _person as a favorite
runSwing(() -> dataTypeManager.setFavorite(dataType, true), false);
waitForSwing();
// Choose favorite.
DockingActionIf favoriteAction = getAction(dataPlugin, "Define _person");
assertNotNull(favoriteAction);
performAction(favoriteAction, codeViewerProvider, true);
waitForSwing();
Data data = program.getListing().getDataAt(addr("004027d0"));
@ -575,28 +526,20 @@ public class ApplyDataTypeToBrowserTest extends AbstractGhidraHeadedIntegrationT
@Test
public void testFavoriteOnDefinedDtsAnswerYes() throws Exception {
createData("004027d1", new ByteDataType());
CodeViewerProvider codeViewerProvider = positionListingCursorAtAddress("004027d0");
goTo("004027d0");
ProgramDataTypeManager dataTypeManager = program.getDataTypeManager();
DataType dataType = dataTypeManager.getDataType(new CategoryPath("/"), "_person");
// Set _person as a favorite
runSwing(() -> dataTypeManager.setFavorite(dataType, true), false);
waitForSwing();
final ProgramDataTypeManager dataTypeManager = program.getDataTypeManager();
final DataType dataType = dataTypeManager.getDataType(new CategoryPath("/"), "_person");
// Set _person as a favorite.
executeOnSwingWithoutBlocking(() -> dataTypeManager.setFavorite(dataType, true));
waitForSwing();
// Choose favorite.
// Choose favorite
DockingActionIf favoriteAction = getAction(dataPlugin, "Define _person");
assertNotNull(favoriteAction);
performAction(favoriteAction, codeViewerProvider, false);
waitForSwing();
JDialog dialog = waitForJDialog(tool.getToolFrame(), "Data Conflict", 2000);
assertNotNull(dialog);
pressButtonByText(dialog, "Yes");
waitForSwing();
pressConflictingDataDialog("Yes");
Data data = program.getListing().getDataAt(addr("004027d0"));
assertEquals(dataType, data.getDataType());
@ -606,28 +549,20 @@ public class ApplyDataTypeToBrowserTest extends AbstractGhidraHeadedIntegrationT
@Test
public void testFavoriteOnDefinedDtsAnswerNo() throws Exception {
createData("004027d1", new ByteDataType());
CodeViewerProvider codeViewerProvider = positionListingCursorAtAddress("004027d0");
waitForSwing();
goTo("004027d0");
final ProgramDataTypeManager dataTypeManager = program.getDataTypeManager();
final DataType dataType = dataTypeManager.getDataType(new CategoryPath("/"), "_person");
ProgramDataTypeManager dataTypeManager = program.getDataTypeManager();
DataType dataType = dataTypeManager.getDataType(new CategoryPath("/"), "_person");
// Set _person as a favorite.
executeOnSwingWithoutBlocking(() -> dataTypeManager.setFavorite(dataType, true));
// Set _person as a favorite
runSwing(() -> dataTypeManager.setFavorite(dataType, true), false);
waitForSwing();
// Choose favorite.
DockingActionIf favoriteAction = getAction(dataPlugin, "Define _person");
assertNotNull(favoriteAction);
performAction(favoriteAction, codeViewerProvider, false);
waitForSwing();
JDialog dialog = waitForJDialog(tool.getToolFrame(), "Data Conflict", 2000);
assertNotNull(dialog);
pressButtonByText(dialog, "No");
waitForSwing();
pressConflictingDataDialog("No");
Data data = program.getListing().getDataAt(addr("004027d0"));
assertEquals(DataType.DEFAULT, data.getDataType());
@ -636,12 +571,9 @@ public class ApplyDataTypeToBrowserTest extends AbstractGhidraHeadedIntegrationT
@Test
public void testCycleOnDefaultDts() throws Exception {
CodeViewerProvider codeViewerProvider = positionListingCursorAtAddress("004027d0");
waitForSwing();
goTo("004027d0");
DockingActionIf chooseDataTypeAction = getAction(dataPlugin, "Choose Data Type");
assertNotNull(chooseDataTypeAction);
performAction(chooseDataTypeAction, codeViewerProvider, false);
showDataTypeChooser();
chooseInDialog("_person");
@ -655,8 +587,7 @@ public class ApplyDataTypeToBrowserTest extends AbstractGhidraHeadedIntegrationT
@Test
public void testCycleOnUndefinedDts() throws Exception {
createData("004027d2", new Undefined4DataType());
positionListingCursorAtAddress("004027d0");
waitForSwing();
goTo("004027d0");
Data data = program.getListing().getDataAt(addr("004027d0"));
ProgramDataTypeManager dataTypeManager = program.getDataTypeManager();
@ -689,8 +620,7 @@ public class ApplyDataTypeToBrowserTest extends AbstractGhidraHeadedIntegrationT
@Test
public void testCycleOnDefinedDts() throws Exception {
createData("004027d3", new ByteDataType());
positionListingCursorAtAddress("004027d0");
waitForSwing();
goTo("004027d0");
Data data = program.getListing().getDataAt(addr("004027d0"));
ProgramDataTypeManager dataTypeManager = program.getDataTypeManager();
@ -722,13 +652,12 @@ public class ApplyDataTypeToBrowserTest extends AbstractGhidraHeadedIntegrationT
@Test
public void testDragNDropOnDefaultDts() throws Exception {
CodeViewerProvider codeViewerProvider = positionListingCursorAtAddress("004027d0");
waitForSwing();
goTo("004027d0");
ProgramDataTypeManager dataTypeManager = program.getDataTypeManager();
DataType dataType = dataTypeManager.getDataType(new CategoryPath("/"), "_person");
dragNDropDataTypeToCurrentBrowserLocation(codeViewerProvider, dataType);
dragNDropDataTypeToCurrentBrowserLocation(dataType);
Data data = program.getListing().getDataAt(addr("004027d0"));
assertEquals(dataType, data.getDataType());
@ -738,13 +667,12 @@ public class ApplyDataTypeToBrowserTest extends AbstractGhidraHeadedIntegrationT
@Test
public void testDragNDropOnUndefinedDts() throws Exception {
createData("004027d2", new Undefined4DataType());
CodeViewerProvider codeViewerProvider = positionListingCursorAtAddress("004027d0");
waitForSwing();
goTo("004027d0");
ProgramDataTypeManager dataTypeManager = program.getDataTypeManager();
DataType dataType = dataTypeManager.getDataType(new CategoryPath("/"), "_person");
dragNDropDataTypeToCurrentBrowserLocation(codeViewerProvider, dataType);
dragNDropDataTypeToCurrentBrowserLocation(dataType);
Data data = program.getListing().getDataAt(addr("004027d0"));
assertEquals(dataType, data.getDataType());
@ -754,19 +682,14 @@ public class ApplyDataTypeToBrowserTest extends AbstractGhidraHeadedIntegrationT
@Test
public void testDragNDropYesOnDefinedDts() throws Exception {
createData("004027d3", new ByteDataType());
CodeViewerProvider codeViewerProvider = positionListingCursorAtAddress("004027d0");
waitForSwing();
goTo("004027d0");
ProgramDataTypeManager dataTypeManager = program.getDataTypeManager();
DataType dataType = dataTypeManager.getDataType(new CategoryPath("/"), "_person");
dragNDropDataTypeToCurrentBrowserLocation(codeViewerProvider, dataType);
dragNDropDataTypeToCurrentBrowserLocation(dataType);
JDialog dialog = waitForJDialog(tool.getToolFrame(), "Data Conflict", 2000);
assertNotNull(dialog);
pressButtonByText(dialog, "Yes");
waitForSwing();
pressConflictingDataDialog("Yes");
Data data = program.getListing().getDataAt(addr("004027d0"));
assertEquals(dataType, data.getDataType());
@ -776,19 +699,14 @@ public class ApplyDataTypeToBrowserTest extends AbstractGhidraHeadedIntegrationT
@Test
public void testDragNDropNoOnDefinedDts() throws Exception {
createData("004027d3", new ByteDataType());
CodeViewerProvider codeViewerProvider = positionListingCursorAtAddress("004027d0");
waitForSwing();
goTo("004027d0");
ProgramDataTypeManager dataTypeManager = program.getDataTypeManager();
DataType dataType = dataTypeManager.getDataType(new CategoryPath("/"), "_person");
dragNDropDataTypeToCurrentBrowserLocation(codeViewerProvider, dataType);
dragNDropDataTypeToCurrentBrowserLocation(dataType);
JDialog dialog = waitForJDialog(tool.getToolFrame(), "Data Conflict", 2000);
assertNotNull(dialog);
pressButtonByText(dialog, "No");
waitForSwing();
pressConflictingDataDialog("No");
Data data = program.getListing().getDataAt(addr("004027d0"));
assertEquals(DataType.DEFAULT, data.getDataType());
@ -797,13 +715,12 @@ public class ApplyDataTypeToBrowserTest extends AbstractGhidraHeadedIntegrationT
@Test
public void testDragNDropWhereDoesNotFit() throws Exception {
CodeViewerProvider codeViewerProvider = positionListingCursorAtAddress("004027e0");
waitForSwing();
goTo("004027e0");
ProgramDataTypeManager dataTypeManager = program.getDataTypeManager();
DataType dataType = dataTypeManager.getDataType(new CategoryPath("/"), "_person");
dragNDropDataTypeToCurrentBrowserLocation(codeViewerProvider, dataType);
dragNDropDataTypeToCurrentBrowserLocation(dataType);
Data data = program.getListing().getDataAt(addr("004027e0"));
assertEquals(DataType.DEFAULT, data.getDataType());
@ -814,24 +731,36 @@ public class ApplyDataTypeToBrowserTest extends AbstractGhidraHeadedIntegrationT
// Private Helper Methods
//==================================================================================================
private DialogComponentProvider chooseInDialog(String typeName) {
private void assertToolStatus(String expectedMessage) {
waitForSwing();
PluginTool pluginTool = plugin.getTool();
DockingWindowManager windowManager = pluginTool.getWindowManager();
Object rootNode = TestUtils.invokeInstanceMethod("getRootNode", windowManager);
StatusBar statusBar = (StatusBar) TestUtils.getInstanceField("statusBar", rootNode);
String actualMessage = runSwing(() -> statusBar.getStatusText());
assertThat("The tool's status text was not set", actualMessage,
containsString(expectedMessage));
}
private void showDataTypeChooser() {
DockingActionIf chooseDataTypeAction = getAction(dataPlugin, "Choose Data Type");
performAction(chooseDataTypeAction, codeViewerProvider, false);
}
private void pressConflictingDataDialog(String button) {
DialogComponentProvider dialog = waitForDialogComponent("Data Conflict");
pressButtonByText(dialog, button);
waitForTasks();
}
private DialogComponentProvider chooseInDialog(String typeName) {
return chooseInDialog(typeName, null);
}
/**
* Waits for the Data Type Chooser dialog to appear. Then, enters the given text to
* select that type. Finally, OK is pressed. The dialog may or may not go away,
* depending upon the state of the dialog.
*
* @param typeName the name of the dt
* @param errorStatus the expected status after pressing OK
*/
private DialogComponentProvider chooseInDialog(String typeName, String errorStatus) {
DataTypeSelectionDialog dialog = waitForDialogComponent(DataTypeSelectionDialog.class);
assertNotNull(dialog);
JTextField tf = findComponent(dialog, JTextField.class);
triggerText(tf, "_person");
waitForSwing();
@ -862,7 +791,7 @@ public class ApplyDataTypeToBrowserTest extends AbstractGhidraHeadedIntegrationT
}
private void dragNDropDataTypeToCurrentBrowserLocation(
final CodeViewerProvider codeViewerProvider, final DataType dataType) {
final DataType dataType) {
executeOnSwingWithoutBlocking(() -> {
// Simulate the drag-n-drop of the data type onto the location.
ProgramLocation programLocation = codeViewerProvider.getLocation();
@ -880,12 +809,7 @@ public class ApplyDataTypeToBrowserTest extends AbstractGhidraHeadedIntegrationT
}
private void doAction(Plugin pluginForAction, String name, boolean waitForCompletion) {
CodeBrowserPlugin codeBrowserPlugin = env.getPlugin(CodeBrowserPlugin.class);
assertNotNull(codeBrowserPlugin);
CodeViewerProvider connectedProvider =
(CodeViewerProvider) getInstanceField("connectedProvider", codeBrowserPlugin);
assertNotNull(connectedProvider);
CodeViewerActionContext codeViewerContext = new CodeViewerActionContext(connectedProvider);
CodeViewerActionContext codeViewerContext = new CodeViewerActionContext(codeViewerProvider);
DockingActionIf action = getAction(pluginForAction, name);
assertNotNull("Action was not found: " + name, action);
@ -894,28 +818,26 @@ public class ApplyDataTypeToBrowserTest extends AbstractGhidraHeadedIntegrationT
}
try {
performAction(action, connectedProvider, waitForCompletion);
performAction(action, codeViewerProvider, waitForCompletion);
}
catch (Throwable t) {
t.printStackTrace();
Assert.fail("Action '" + name + "' failed: " + t.toString());
failWithException("Action '" + name + "' failed: ", t);
}
}
private CodeViewerProvider positionListingCursorAtAddress(String addressString) {
CodeBrowserPlugin codeBrowserPlugin = env.getPlugin(CodeBrowserPlugin.class);
assertNotNull(codeBrowserPlugin);
private void goTo(String addressString) {
CodeBrowserPlugin codeBrowser = env.getPlugin(CodeBrowserPlugin.class);
Address address = program.getAddressFactory().getAddress(addressString);
codeBrowserPlugin.goToField(address, "Address", 0, 0);
assertEquals(addressString, codeBrowserPlugin.getCurrentAddress().toString());
codeBrowser.goToField(address, "Address", 0, 0);
assertEquals(addressString, codeBrowser.getCurrentAddress().toString());
CodeViewerProvider connectedProvider =
(CodeViewerProvider) getInstanceField("connectedProvider", codeBrowserPlugin);
(CodeViewerProvider) getInstanceField("connectedProvider", codeBrowser);
assertNotNull(connectedProvider);
ListingPanel listingPanel =
(ListingPanel) getInstanceField("listingPanel", connectedProvider);
assertNotNull(listingPanel);
return connectedProvider;
waitForSwing();
}
private void createData(String addressString, DataType dataType) throws Exception {
@ -928,7 +850,7 @@ public class ApplyDataTypeToBrowserTest extends AbstractGhidraHeadedIntegrationT
finally {
program.endTransaction(transactionID, success);
}
waitForProgram();
waitForProgram(program);
}
private void createCode(String addressString, int len) throws Exception {
@ -945,7 +867,7 @@ public class ApplyDataTypeToBrowserTest extends AbstractGhidraHeadedIntegrationT
finally {
program.endTransaction(transactionID, success);
}
waitForProgram();
waitForProgram(program);
}
private Address addr(String addressString) {
@ -955,10 +877,4 @@ public class ApplyDataTypeToBrowserTest extends AbstractGhidraHeadedIntegrationT
private void waitForTree() {
waitForTree(tree);
}
private void waitForProgram() throws Exception {
program.flushEvents();
waitForTasks();
waitForSwing();
}
}

View file

@ -46,7 +46,8 @@ import generic.test.AbstractGTest;
import generic.util.WindowUtilities;
import generic.util.image.ImageUtils;
import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin;
import ghidra.app.plugin.core.datamgr.archive.*;
import ghidra.app.plugin.core.datamgr.archive.Archive;
import ghidra.app.plugin.core.datamgr.archive.DataTypeManagerHandler;
import ghidra.app.plugin.core.datamgr.tree.DataTypeArchiveGTree;
import ghidra.app.plugin.core.datamgr.tree.DataTypeNode;
import ghidra.app.plugin.core.datamgr.util.DataTypeChooserDialog;
@ -1175,7 +1176,7 @@ public class DataTypeSelectionDialogTest extends AbstractGhidraHeadedIntegration
JPanel editorPanel = new JPanel(new BorderLayout());
DataTypeSelectionEditor editor =
new DataTypeSelectionEditor(tool, -1, AllowedDataTypes.ALL);
new DataTypeSelectionEditor(tool, AllowedDataTypes.ALL);
editor.setPreferredDataTypeManager(program.getDataTypeManager());
editorPanel.add(panelUpdateField, BorderLayout.SOUTH);

View file

@ -45,14 +45,6 @@ public class CreateDataCmdTest extends AbstractGenericTest {
private Listing listing;
private ProgramBuilder builder;
/**
* Constructor for CreateDataCmdTest.
* @param arg0
*/
public CreateDataCmdTest() {
super();
}
@Before
public void setUp() throws Exception {
program = buildProgram();
@ -637,7 +629,8 @@ public class CreateDataCmdTest extends AbstractGenericTest {
cmd.applyTo(program);
// Add external reference from pointer
program.getReferenceManager().addExternalReference(addr, "OtherFile", "ExtLabel", null,
program.getReferenceManager()
.addExternalReference(addr, "OtherFile", "ExtLabel", null,
SourceType.USER_DEFINED, 0, RefType.DATA);
// Undefined* becomes Byte*
@ -724,7 +717,8 @@ public class CreateDataCmdTest extends AbstractGenericTest {
assertEquals(10, dt.getLength());
// Byte[] becomes Byte
CreateDataCmd cmd = new CreateDataCmd(addr, new ByteDataType(), false, ClearDataMode.CLEAR_SINGLE_DATA);
CreateDataCmd cmd =
new CreateDataCmd(addr, new ByteDataType(), false, ClearDataMode.CLEAR_SINGLE_DATA);
cmd.applyTo(program);
d = listing.getDataAt(addr);
@ -792,7 +786,8 @@ public class CreateDataCmdTest extends AbstractGenericTest {
assertEquals(10, dt.getLength());
// struct becomes Byte
CreateDataCmd cmd = new CreateDataCmd(addr, new ByteDataType(), false, ClearDataMode.CLEAR_SINGLE_DATA);
CreateDataCmd cmd =
new CreateDataCmd(addr, new ByteDataType(), false, ClearDataMode.CLEAR_SINGLE_DATA);
cmd.applyTo(program);
d = listing.getDataAt(addr);

View file

@ -557,8 +557,7 @@ class DetachedWindowNode extends WindowNode {
*/
public void setStatusText(String text) {
if (statusBar != null) {
boolean isActive = window == null ? false : window.isActive();
statusBar.setStatusText(text, isActive);
statusBar.setStatusText(text);
}
}

View file

@ -576,7 +576,7 @@ class RootNode extends WindowNode {
return;
}
statusBar.setStatusText(text, getMainWindow().isActive());
statusBar.setStatusText(text);
Iterator<DetachedWindowNode> iter = detachedWindows.iterator();
while (iter.hasNext()) {

View file

@ -24,6 +24,7 @@ import javax.swing.*;
import javax.swing.Timer;
import javax.swing.border.Border;
import org.apache.commons.lang3.StringUtils;
import org.jdesktop.animation.timing.Animator;
import docking.util.AnimationUtils;
@ -153,14 +154,40 @@ public class StatusBar extends JPanel {
statusAreaPanel.remove(c.getParent());
}
public void setStatusText(String text, boolean isActiveWindow) {
SystemUtilities.runIfSwingOrPostSwingLater(() -> doSetStatusText(text, isActiveWindow));
/**
* Returns the current text in this status bar
* @return the text
*/
public String getStatusText() {
return statusLabel.getText();
}
private void doSetStatusText(String text, boolean isActiveWindow) {
/**
* Deprecated. Call {@link #setStatusText(String)} instead.
*
* @param text the text
* @param isActiveWindow this parameter is ignored
* @deprecated Call {@link #setStatusText(String)} instead. Remove after 9.3
*/
@Deprecated
public void setStatusText(String text, boolean isActiveWindow) {
setStatusText(text);
}
/**
* Sets the status text
* @param text the text
*/
public void setStatusText(String text) {
// Run this later in case we are in the midst of a Java focus transition, such as when a
// dialog is closing. If we don't let the focus transition finish, then we will not
// correctly locate the active window.
Swing.runLater(() -> doSetStatusText(text));
}
private void doSetStatusText(String text) {
if (text == null) {
// not sure what do do here, do nothing for now so that the previous message
// stays around
// do nothing for now so that the previous message stays around
return;
}
@ -171,11 +198,12 @@ public class StatusBar extends JPanel {
statusLabel.setToolTipText(getToolTipText());
statusLabel.setForeground(Color.BLACK);
if (!isActiveWindow) {
if (StringUtils.isBlank(updatedText)) {
return;
}
if (updatedText.trim().isEmpty()) {
Window window = WindowUtilities.windowForComponent(statusLabel);
if (!window.isActive()) {
return;
}

View file

@ -496,6 +496,13 @@ public class AnimationUtils {
}
Rectangle startBounds = component.getBounds();
Container parent = component.getParent();
if (parent == null) {
// the given component is a Window; make it be the root
startBounds.x = 0;
startBounds.y = 0;
}
Point relativeStartCenter =
new Point((int) startBounds.getCenterX(), (int) startBounds.getCenterY());
return SwingUtilities.convertPoint(component.getParent(), relativeStartCenter,
@ -556,11 +563,20 @@ public class AnimationUtils {
int scaledWidth = (int) (defaultBounds.width * percentComplete);
int scaledHeight = (int) (defaultBounds.height * percentComplete);
// gains opacity as it gets closer to the end; capped at the given percentage
float opacity = (float) Math.min(.65, percentComplete);
Composite originalComposite = g2d.getComposite();
AlphaComposite alphaComposite = AlphaComposite.getInstance(
AlphaComposite.SrcOver.getRule(), opacity);
g2d.setComposite(alphaComposite);
//
// Calculate the position of the image. At 100% we want to be in the center of
// the display; at 0% we want to be at our default location
//
g2d.drawImage(image, (int) currentX, (int) currentY, scaledWidth, scaledHeight, null);
g2d.setComposite(originalComposite);
}
}

View file

@ -15,7 +15,7 @@
*/
package docking;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.*;
import javax.swing.JFrame;
import javax.swing.JLabel;
@ -38,15 +38,6 @@ public class StatusBarTest extends AbstractDockingTest {
private StatusBar statusBar;
private JFrame testFrame;
/**
* Constructor to run the test passed as a parameter.
*
* @param testName The name of the test to run
*/
public StatusBarTest() {
super();
}
@Before
public void setUp() throws Exception {
@ -113,59 +104,37 @@ public class StatusBarTest extends AbstractDockingTest {
final JLabel label2 = new GDLabel("Test Label 2");
// normal add/remove operations
runSwing(new Runnable() {
@Override
public void run() {
runSwing(() -> {
statusBar.addStatusItem(label1, true, true);
statusBar.addStatusItem(label2, true, true);
}
});
runSwing(new Runnable() {
@Override
public void run() {
runSwing(() -> {
statusBar.removeStatusItem(label1);
statusBar.removeStatusItem(label2);
}
});
// method call variations
runSwing(new Runnable() {
@Override
public void run() {
runSwing(() -> {
statusBar.addStatusItem(label1, false, true);
statusBar.addStatusItem(label2, true, false);
}
});
runSwing(new Runnable() {
@Override
public void run() {
runSwing(() -> {
statusBar.removeStatusItem(label1);
statusBar.removeStatusItem(label2);
}
});
// repeat adding
runSwing(new Runnable() {
@Override
public void run() {
runSwing(() -> {
statusBar.addStatusItem(label1, true, true);
statusBar.addStatusItem(label1, true, true);
}
});
// removing non-existent elements
runSwing(new Runnable() {
@Override
public void run() {
statusBar.removeStatusItem(label2);
}
});
runSwing(() -> statusBar.removeStatusItem(label2));
runSwing(new Runnable() {
@Override
public void run() {
runSwing(() -> {
try {
statusBar.removeStatusItem(new GLabel("Test Label 3"));
@ -174,17 +143,11 @@ public class StatusBarTest extends AbstractDockingTest {
catch (NullPointerException npe) {
// expected, caused by a null parent
}
}
});
}
private void setStatusText(final String text) {
runSwing(new Runnable() {
@Override
public void run() {
statusBar.setStatusText(text, true);
}
});
waitForPostedSwingRunnables();
runSwing(() -> statusBar.setStatusText(text));
waitForSwing();
}
}

View file

@ -26,9 +26,8 @@ import ghidra.util.exception.InvalidInputException;
public final class DataUtilities {
//private final static Set<Character> VALID_DATA_TYPE_NAME_SET = SystemUtilities.makeSet(FileSystem.DASH_CHAR, '_',' ', '.');
private DataUtilities() {
// utilities class
}
/**
@ -88,95 +87,58 @@ public final class DataUtilities {
/**
* Create data where existing data may already exist.
* @param program
* @param program the program
* @param addr data address (offcut data address only allowed if clearMode == ClearDataMode.CLEAR_ALL_CONFLICT_DATA)
* @param newDataType new data-type being applied
* @param newType new data-type being applied
* @param length data length (used only for Dynamic newDataType which has canSpecifyLength()==true)
* @param stackPointers see {@link #reconcileAppliedDataType(DataType, DataType, boolean)}
* @param clearMode see CreateDataMode
* @return new data created
* @throws CodeUnitInsertionException if data creation failed
*/
public static Data createData(Program program, Address addr, DataType newDataType, int length,
public static Data createData(Program program, Address addr, DataType newType, int length,
boolean stackPointers, ClearDataMode clearMode) throws CodeUnitInsertionException {
Listing listing = program.getListing();
ReferenceManager refMgr = program.getReferenceManager();
Data data = listing.getDataAt(addr);
DataType existingDT = null;
Data data = getData(addr, clearMode, listing);
int existingLength = addr.getAddressSpace().getAddressableUnitSize();
DataType existingType = data.getDataType();
Reference extRef = null;
int existingDataLen = addr.getAddressSpace().getAddressableUnitSize();
if (data == null) {
if (clearMode == ClearDataMode.CLEAR_ALL_CONFLICT_DATA ||
clearMode == ClearDataMode.CLEAR_ALL_UNDEFINED_CONFLICT_DATA) {
// allow offcut addr if CLEAR_ALL_CONFLICT_DATA
data = listing.getDataContaining(addr);
if (data != null && clearMode == ClearDataMode.CLEAR_ALL_UNDEFINED_CONFLICT_DATA &&
!Undefined.isUndefined(data.getDataType())) {
data = null; // force error
}
}
if (data == null) {
throw new CodeUnitInsertionException("Could not create Data at address " + addr);
}
}
else {
existingDataLen = data.getLength();
existingDT = data.getDataType();
if (!isParentData(data, addr)) {
if (data.isDefined() && newDataType.isEquivalent(existingDT)) {
existingLength = data.getLength();
if (data.isDefined() && newType.isEquivalent(existingType)) {
return data;
}
if (!stackPointers && clearMode == ClearDataMode.CLEAR_ALL_UNDEFINED_CONFLICT_DATA &&
!Undefined.isUndefined(existingDT)) {
!Undefined.isUndefined(existingType)) {
throw new CodeUnitInsertionException("Could not create Data at address " + addr);
}
// Check for external reference on pointer
if ((stackPointers || newDataType instanceof Pointer) &&
existingDT instanceof Pointer) {
// TODO: This can probably be eliminated
Reference[] refs = refMgr.getReferencesFrom(addr);
for (Reference ref : refs) {
if (ref.getOperandIndex() == 0 && ref.isExternalReference()) {
extRef = ref;
break;
}
}
}
// Check for external reference on pointer
extRef =
getExternalPointerReference(addr, newType, stackPointers, refMgr, existingType);
}
newDataType = newDataType.clone(program.getDataTypeManager());
newDataType = reconcileAppliedDataType(existingDT, newDataType, stackPointers);
newType = newType.clone(program.getDataTypeManager());
newType = reconcileAppliedDataType(existingType, newType, stackPointers);
DataType realType = newDataType;
if (newDataType instanceof TypeDef) {
realType = ((TypeDef) newDataType).getBaseDataType();
DataType realType = newType;
if (newType instanceof TypeDef) {
realType = ((TypeDef) newType).getBaseDataType();
}
// is the datatype already there?
if (!(realType instanceof Dynamic) && !(realType instanceof FactoryDataType) &&
newDataType.equals(existingDT)) {
if (isExistingNonDynamicType(realType, newType, existingType)) {
return data;
}
MemBuffer memBuf = new DumbMemBufferImpl(program.getMemory(), addr);
DataTypeInstance dti;
if (length > 0 && (realType instanceof Dynamic) &&
((Dynamic) realType).canSpecifyLength()) {
dti = DataTypeInstance.getDataTypeInstance(newDataType, memBuf, length);
}
else {
dti = DataTypeInstance.getDataTypeInstance(newDataType, memBuf);
}
if (dti == null) {
throw new CodeUnitInsertionException(
"Could not create DataType " + newDataType.getDisplayName());
}
if (stackPointers && existingDT instanceof Pointer && newDataType instanceof Pointer) {
DataTypeInstance dti = getDtInstance(program, addr, newType, length, realType);
if (stackPointers && existingType instanceof Pointer && newType instanceof Pointer) {
listing.clearCodeUnits(addr, addr, false);
}
@ -190,56 +152,175 @@ public final class DataUtilities {
listing.clearCodeUnits(addr, addr, false);
}
else {
checkEnoughSpace(program, addr, existingDataLen, dti, clearMode);
checkEnoughSpace(program, addr, existingLength, dti, clearMode);
}
newData = listing.createData(addr, dti.getDataType(), dti.getLength());
}
restoreReference(newType, refMgr, extRef);
return newData;
}
private static boolean isParentData(Data data, Address addr) {
return !data.getAddress().equals(addr);
}
private static Data getData(Address addr, ClearDataMode clearMode, Listing listing)
throws CodeUnitInsertionException {
Data data = listing.getDataAt(addr);
if (data != null) {
return data; // existing data; it us possible to create data
}
// null data; see if we are in a composite
if (clearMode == ClearDataMode.CLEAR_ALL_CONFLICT_DATA ||
clearMode == ClearDataMode.CLEAR_ALL_UNDEFINED_CONFLICT_DATA) {
// allow offcut addr if CLEAR_ALL_CONFLICT_DATA
data = listing.getDataContaining(addr);
if (data != null && clearMode == ClearDataMode.CLEAR_ALL_UNDEFINED_CONFLICT_DATA &&
!Undefined.isUndefined(data.getDataType())) {
data = null; // force error
}
}
// null data implies that we cannot create data at this address
if (data == null) {
throw new CodeUnitInsertionException("Could not create Data at address " + addr);
}
return data;
}
private static DataTypeInstance getDtInstance(Program program, Address addr, DataType newType,
int length, DataType realType) throws CodeUnitInsertionException {
MemBuffer memBuf = new DumbMemBufferImpl(program.getMemory(), addr);
DataTypeInstance dti;
if (length > 0 && (realType instanceof Dynamic) &&
((Dynamic) realType).canSpecifyLength()) {
dti = DataTypeInstance.getDataTypeInstance(newType, memBuf, length);
}
else {
dti = DataTypeInstance.getDataTypeInstance(newType, memBuf);
}
if (dti == null) {
throw new CodeUnitInsertionException(
"Could not create DataType " + newType.getDisplayName());
}
return dti;
}
private static boolean isExistingNonDynamicType(DataType realType, DataType newType,
DataType existingType) {
if (realType instanceof Dynamic || realType instanceof FactoryDataType) {
return false;
}
// not dynamic or factory--does it exist?
return newType.equals(existingType);
}
private static void restoreReference(DataType newType, ReferenceManager refMgr,
Reference ref) {
if (ref == null) {
return;
}
if (!(newType instanceof Pointer)) {
return;
}
// if this was a pointer and had an external reference, put it back!
if ((newDataType instanceof Pointer) && extRef != null) {
ExternalLocation extLoc = ((ExternalReference) extRef).getExternalLocation();
ExternalLocation extLoc = ((ExternalReference) ref).getExternalLocation();
Address fromAddress = ref.getFromAddress();
SourceType source = ref.getSource();
RefType type = ref.getReferenceType();
try {
refMgr.addExternalReference(extRef.getFromAddress(), 0, extLoc, extRef.getSource(),
extRef.getReferenceType());
refMgr.addExternalReference(fromAddress, 0, extLoc, source, type);
}
catch (InvalidInputException e) {
throw new AssertException(e);
}
}
return newData;
private static Reference getExternalPointerReference(Address addr, DataType newType,
boolean stackPointers,
ReferenceManager refMgr, DataType existingType) {
Reference extRef = null;
if ((stackPointers || newType instanceof Pointer) &&
existingType instanceof Pointer) {
Reference[] refs = refMgr.getReferencesFrom(addr);
for (Reference ref : refs) {
if (ref.getOperandIndex() == 0 && ref.isExternalReference()) {
extRef = ref;
break;
}
}
}
return extRef;
}
private static void validateCanCreateData(Address addr, ClearDataMode clearMode,
Listing listing, Data data) throws CodeUnitInsertionException {
if (data != null) {
return; // existing data; it us possible to create data
}
if (clearMode == ClearDataMode.CLEAR_ALL_CONFLICT_DATA ||
clearMode == ClearDataMode.CLEAR_ALL_UNDEFINED_CONFLICT_DATA) {
// allow offcut addr if CLEAR_ALL_CONFLICT_DATA
data = listing.getDataContaining(addr);
if (data != null && clearMode == ClearDataMode.CLEAR_ALL_UNDEFINED_CONFLICT_DATA &&
!Undefined.isUndefined(data.getDataType())) {
data = null; // force error
}
}
// null data implies that we cannot create data at this address
if (data == null) {
throw new CodeUnitInsertionException("Could not create Data at address " + addr);
}
}
private static void checkEnoughSpace(Program program, Address addr, int existingDataLen,
DataTypeInstance dti, ClearDataMode mode) throws CodeUnitInsertionException {
// NOTE: method not invoked when clearMode == ClearDataMode.CLEAR_SINGLE_DATA
Listing listing = program.getListing();
Address end = null;
Address newEnd = null;
try {
Address end = addr.addNoWrap(existingDataLen - 1);
Address newEnd = addr.addNoWrap(dti.getLength() - 1);
end = addr.addNoWrap(existingDataLen - 1);
newEnd = addr.addNoWrap(dti.getLength() - 1);
}
catch (AddressOverflowException e) {
throw new CodeUnitInsertionException(
"Not enough space to create DataType " + dti.getDataType().getDisplayName());
}
Instruction instr = listing.getInstructionAfter(end);
if (instr != null && instr.getMinAddress().compareTo(newEnd) <= 0) {
throw new CodeUnitInsertionException(
"Not enough space to create DataType " + dti.getDataType().getDisplayName());
}
Data definedData = listing.getDefinedDataAfter(end);
if (definedData != null && definedData.getMinAddress().compareTo(newEnd) <= 0) {
if (definedData == null || definedData.getMinAddress().compareTo(newEnd) > 0) {
listing.clearCodeUnits(addr, addr, false);
return;
}
if (mode == ClearDataMode.CLEAR_ALL_UNDEFINED_CONFLICT_DATA &&
Undefined.isUndefined(definedData.getDataType())) {
// ignore all defined data which is considered Undefined and may be cleared
end = definedData.getMaxAddress();
while (end.compareTo(newEnd) <= 0) {
definedData = listing.getDefinedDataAfter(end);
if (definedData == null ||
definedData.getMinAddress().compareTo(newEnd) > 0) {
break;
}
if (!Undefined.isUndefined(definedData.getDataType())) {
throw new CodeUnitInsertionException(
"Not enough space to create DataType " +
dti.getDataType().getDisplayName());
}
end = definedData.getMaxAddress();
}
checkForDefinedData(dti, listing, newEnd, definedData.getMaxAddress());
}
else if (mode != ClearDataMode.CLEAR_ALL_CONFLICT_DATA) {
throw new CodeUnitInsertionException("Not enough space to create DataType " +
@ -247,13 +328,23 @@ public final class DataUtilities {
}
listing.clearCodeUnits(addr, newEnd, false);
}
else {
listing.clearCodeUnits(addr, addr, false);
private static void checkForDefinedData(DataTypeInstance dti, Listing listing, Address address,
Address end) throws CodeUnitInsertionException {
// ignore all defined data which is considered Undefined and may be cleared
while (end.compareTo(address) <= 0) {
Data definedData = listing.getDefinedDataAfter(end);
if (definedData == null ||
definedData.getMinAddress().compareTo(address) > 0) {
return;
}
if (!Undefined.isUndefined(definedData.getDataType())) {
throw new CodeUnitInsertionException("Not enough space to create DataType " +
dti.getDataType().getDisplayName());
}
catch (AddressOverflowException e) {
throw new CodeUnitInsertionException(
"Not enough space to create DataType " + dti.getDataType().getDisplayName());
end = definedData.getMaxAddress();
}
}
@ -355,7 +446,10 @@ public final class DataUtilities {
* Get the data for the given address.
* <P>
* This will return a Data if and only if there is data that starts at the given address.
* @return the Data that starts at the given address or null if the address is code or offcut.
*
* @param program the program
* @param address the data address
* @return the Data that starts at the given address or null if the address is code or offcut
*/
public static Data getDataAtAddress(Program program, Address address) {
if (address == null) {
@ -417,9 +511,9 @@ public final class DataUtilities {
* Determine if the specified addr corresponds to an undefined data location
* where both undefined code units and defined data which has an Undefined
* data type is considered to be undefined.
* @param program
* @param addr
* @return
* @param program the program
* @param addr the data address
* @return true if the data is undefined
*/
public static boolean isUndefinedData(Program program, Address addr) {
Data data = program.getListing().getDataAt(addr);