GP-5421 Ensure merge inserts structure components in the correct

sequence to account for zero-length overlapping components. Refactor how
dataTypeDeleted and dataTypeReplaced are handled.  Use blocking error
message popup during most Merge operations.
This commit is contained in:
ghidra1 2025-03-06 11:53:29 -05:00
parent dcc87e7fb7
commit fe944640b9
45 changed files with 2427 additions and 1795 deletions

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -226,27 +226,33 @@ public abstract class MergeManager implements DomainObjectMergeManager {
return merge(TaskMonitor.DUMMY); return merge(TaskMonitor.DUMMY);
} }
/**
* Display a blocking error popup. When used from a {@link MergeResolver} task it will
* prevent that task from exiting/progressing until the error popup is dismissed.
* @param title popup title
* @param msg error message
*/
public static void showBlockingError(String title, String msg) {
Swing.runNow(() -> Msg.showError(MergeManager.class, null, title, msg));
}
/**
* Display a blocking error popup. When used from a {@link MergeResolver} task it will
* prevent that task from exiting/progressing until the error popup is dismissed.
* @param title popup title
* @param msg error message
* @param e exception
*/
public static void showBlockingError(String title, String msg, Exception e) {
Swing.runNow(() -> Msg.showError(MergeManager.class, null, title, msg, e));
}
/** /**
* Enable the apply button according to the "enabled" parameter. * Enable the apply button according to the "enabled" parameter.
*/ */
@Override @Override
public void setApplyEnabled(final boolean enabled) { public void setApplyEnabled(final boolean enabled) {
Runnable r = () -> mergePlugin.setApplyEnabled(enabled); Swing.runNow(() -> mergePlugin.setApplyEnabled(enabled));
if (SwingUtilities.isEventDispatchThread()) {
r.run();
}
else {
try {
SwingUtilities.invokeAndWait(r);
}
catch (InterruptedException e) {
}
catch (InvocationTargetException e) {
Msg.showError(this, null, "Error in Merge Dialog",
"Error setting enablement for Apply button", e);
}
}
} }
/** /**
@ -440,13 +446,8 @@ public abstract class MergeManager implements DomainObjectMergeManager {
} }
catch (final Exception e) { catch (final Exception e) {
SwingUtilities.invokeLater(new Runnable() { MergeManager.showBlockingError("Error During Merge",
@Override "Error occurred in " + mergeResolvers[currentIndex].getName(), e);
public void run() {
Msg.showError(this, null, "Error During Merge",
"Error occurred in " + mergeResolvers[currentIndex].getName(), e);
}
});
mergeStatus = false; mergeStatus = false;
conflictsResolveCompleted(); conflictsResolveCompleted();
} }
@ -457,16 +458,6 @@ public abstract class MergeManager implements DomainObjectMergeManager {
} }
} }
/**
* Display error message dialog in a blocking fashion.
* @param originator message originator
* @param title dialog title
* @param msg dialog message
*/
public static void displayErrorAndWait(Object originator, String title, String msg) {
Swing.runNow(() -> Msg.showError(originator, null, title, msg));
}
/** /**
* Block until the user completes the current merge operation, or * Block until the user completes the current merge operation, or
* cancels the merge process. * cancels the merge process.

View file

@ -41,6 +41,7 @@ import ghidra.program.model.listing.ProgramChangeSet;
import ghidra.program.util.ProgramLocation; import ghidra.program.util.ProgramLocation;
import ghidra.program.util.ProgramSelection; import ghidra.program.util.ProgramSelection;
import ghidra.util.HelpLocation; import ghidra.util.HelpLocation;
import ghidra.util.SystemUtilities;
import help.Help; import help.Help;
import help.HelpService; import help.HelpService;
@ -54,25 +55,19 @@ public class ProgramMultiUserMergeManager extends MergeManager {
private GoToAddressLabelPlugin goToPlugin; private GoToAddressLabelPlugin goToPlugin;
private ListingMergePanel mergePanel; private ListingMergePanel mergePanel;
private boolean isShowingListingMergePanel = false; private boolean isShowingListingMergePanel = false;
private boolean showListingPanels = true;
MergeNavigatable navigatable; MergeNavigatable navigatable;
private final boolean showListingPanels;
public ProgramMultiUserMergeManager(Program resultProgram, Program myProgram, public ProgramMultiUserMergeManager(Program resultProgram, Program myProgram,
Program originalProgram, Program latestProgram, ProgramChangeSet latestChangeSet, Program originalProgram, Program latestProgram, ProgramChangeSet latestChangeSet,
ProgramChangeSet myChangeSet) { ProgramChangeSet myChangeSet) {
super(resultProgram, myProgram, originalProgram, latestProgram, latestChangeSet, super(resultProgram, myProgram, originalProgram, latestProgram, latestChangeSet,
myChangeSet); myChangeSet);
}
public ProgramMultiUserMergeManager(Program resultProgram, Program myProgram, // Disable multi-listing panel rendering when running in batch test mode for
Program originalProgram, Program latestProgram, ProgramChangeSet latestChangeSet, // improved performance.
ProgramChangeSet myChangeSet, boolean showListingPanels) { showListingPanels = !SystemUtilities.isInTestingBatchMode();
super(resultProgram, myProgram, originalProgram, latestProgram, latestChangeSet,
myChangeSet);
// True signals to show the Listing panels (the default); false signals to leave the
// panels empty.
this.showListingPanels = showListingPanels;
} }
@Override @Override

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -27,8 +27,7 @@ import org.apache.commons.lang3.StringUtils;
import docking.widgets.dialogs.ReadTextDialog; import docking.widgets.dialogs.ReadTextDialog;
import generic.stl.Pair; import generic.stl.Pair;
import ghidra.app.merge.MergeConstants; import ghidra.app.merge.*;
import ghidra.app.merge.ProgramMultiUserMergeManager;
import ghidra.app.merge.tool.ListingMergePanel; import ghidra.app.merge.tool.ListingMergePanel;
import ghidra.app.merge.util.ConflictUtility; import ghidra.app.merge.util.ConflictUtility;
import ghidra.framework.plugintool.PluginTool; import ghidra.framework.plugintool.PluginTool;
@ -267,9 +266,7 @@ abstract class AbstractFunctionMerger implements ListingMergeConstants {
switch (type) { switch (type) {
case FUNC_RETURN_ADDRESS_OFFSET: case FUNC_RETURN_ADDRESS_OFFSET:
return (latestStack.getReturnAddressOffset() == myStack return (latestStack.getReturnAddressOffset() == myStack
.getReturnAddressOffset()) .getReturnAddressOffset()) ? 0 : type;
? 0
: type;
// For now, we are not allowing you to set the parameter offset or local size outright. // For now, we are not allowing you to set the parameter offset or local size outright.
// case FUNC_PARAMETER_OFFSET: // case FUNC_PARAMETER_OFFSET:
// return (latestStack.getParameterOffset() == myStack.getParameterOffset()) ? 0 // return (latestStack.getParameterOffset() == myStack.getParameterOffset()) ? 0
@ -278,9 +275,7 @@ abstract class AbstractFunctionMerger implements ListingMergeConstants {
// return (latestStack.getLocalSize() == myStack.getLocalSize()) ? 0 : type; // return (latestStack.getLocalSize() == myStack.getLocalSize()) ? 0 : type;
case FUNC_STACK_PURGE_SIZE: case FUNC_STACK_PURGE_SIZE:
return (functions[LATEST].getStackPurgeSize() == functions[MY] return (functions[LATEST].getStackPurgeSize() == functions[MY]
.getStackPurgeSize()) .getStackPurgeSize()) ? 0 : type;
? 0
: type;
case FUNC_NAME: case FUNC_NAME:
return hasUnresolvedFunctionNameConflict(functions, monitor) ? type : 0; return hasUnresolvedFunctionNameConflict(functions, monitor) ? type : 0;
case FUNC_INLINE: case FUNC_INLINE:
@ -294,13 +289,10 @@ abstract class AbstractFunctionMerger implements ListingMergeConstants {
// : type; // : type;
case FUNC_CALLING_CONVENTION: case FUNC_CALLING_CONVENTION:
return (functions[LATEST].getCallingConventionName() return (functions[LATEST].getCallingConventionName()
.equals( .equals(functions[MY].getCallingConventionName())) ? 0 : type;
functions[MY].getCallingConventionName())) ? 0 : type;
case FUNC_SIGNATURE_SOURCE: case FUNC_SIGNATURE_SOURCE:
return (functions[LATEST].getSignatureSource() == functions[MY] return (functions[LATEST].getSignatureSource() == functions[MY]
.getSignatureSource()) .getSignatureSource()) ? 0 : type;
? 0
: type;
default: default:
throw new IllegalArgumentException("type = " + type); throw new IllegalArgumentException("type = " + type);
} }
@ -1372,10 +1364,8 @@ abstract class AbstractFunctionMerger implements ListingMergeConstants {
protected void mergeParamInfo(Address entryPt, List<ParamInfoConflict> paramInfoConflicts, protected void mergeParamInfo(Address entryPt, List<ParamInfoConflict> paramInfoConflicts,
int chosenConflictOption, TaskMonitor monitor) throws CancelledException { int chosenConflictOption, TaskMonitor monitor) throws CancelledException {
Iterator<ParamInfoConflict> iter = paramInfoConflicts.iterator(); for (ParamInfoConflict pc : paramInfoConflicts) {
while (iter.hasNext()) {
monitor.checkCancelled(); monitor.checkCancelled();
ParamInfoConflict pc = iter.next();
mergeParamInfo(entryPt, pc, chosenConflictOption, monitor); mergeParamInfo(entryPt, pc, chosenConflictOption, monitor);
} }
} }
@ -1404,10 +1394,8 @@ abstract class AbstractFunctionMerger implements ListingMergeConstants {
protected void mergeParamInfo(Function[] functions, List<ParamInfoConflict> paramInfoConflicts, protected void mergeParamInfo(Function[] functions, List<ParamInfoConflict> paramInfoConflicts,
int chosenConflictOption, TaskMonitor monitor) throws CancelledException { int chosenConflictOption, TaskMonitor monitor) throws CancelledException {
Iterator<ParamInfoConflict> iter = paramInfoConflicts.iterator(); for (ParamInfoConflict pc : paramInfoConflicts) {
while (iter.hasNext()) {
monitor.checkCancelled(); monitor.checkCancelled();
ParamInfoConflict pc = iter.next();
mergeParamInfo(functions, pc, chosenConflictOption, monitor); mergeParamInfo(functions, pc, chosenConflictOption, monitor);
} }
} }
@ -1435,10 +1423,8 @@ abstract class AbstractFunctionMerger implements ListingMergeConstants {
protected void mergeLocals(Address entryPt, List<LocalVariableConflict> localVarConflicts, protected void mergeLocals(Address entryPt, List<LocalVariableConflict> localVarConflicts,
int chosenConflictOption, TaskMonitor monitor) throws CancelledException { int chosenConflictOption, TaskMonitor monitor) throws CancelledException {
Iterator<LocalVariableConflict> iter = localVarConflicts.iterator(); for (LocalVariableConflict lvc : localVarConflicts) {
while (iter.hasNext()) {
monitor.checkCancelled(); monitor.checkCancelled();
LocalVariableConflict lvc = iter.next();
mergeLocal(entryPt, lvc, chosenConflictOption, monitor); mergeLocal(entryPt, lvc, chosenConflictOption, monitor);
} }
} }
@ -1629,7 +1615,7 @@ abstract class AbstractFunctionMerger implements ListingMergeConstants {
final Address entryPt, final TaskMonitor monitor) { final Address entryPt, final TaskMonitor monitor) {
if (conflictPanel == null) { if (conflictPanel == null) {
Msg.showError(this, null, "Error Displaying Conflict Panel", MergeManager.showBlockingError("Error Displaying Conflict Panel",
"The conflict panel could not be created."); "The conflict panel could not be created.");
return; return;
} }
@ -1666,8 +1652,7 @@ abstract class AbstractFunctionMerger implements ListingMergeConstants {
private void showConflictPanelException(final Address entryPt, Exception e) { private void showConflictPanelException(final Address entryPt, Exception e) {
String message = "Couldn't display conflict for function at " + entryPt.toString(true) + String message = "Couldn't display conflict for function at " + entryPt.toString(true) +
".\n " + e.getMessage(); ".\n " + e.getMessage();
Msg.showError(this, mergeManager.getMergeTool().getToolFrame(), "Function Merge Error", MergeManager.showBlockingError("Function Merge Error", message, e);
message, e);
// Should this just put a message on errorBuf instead? // Should this just put a message on errorBuf instead?
} }
@ -1990,16 +1975,13 @@ abstract class AbstractFunctionMerger implements ListingMergeConstants {
} }
} }
catch (DuplicateNameException e) { catch (DuplicateNameException e) {
Msg.showError(this, mergeManager.getMergeTool().getToolFrame(), MergeManager.showBlockingError("Error Setting Function Namespace", e.getMessage());
"Error Setting Function Namespace", e.getMessage());
} }
catch (InvalidInputException e) { catch (InvalidInputException e) {
Msg.showError(this, mergeManager.getMergeTool().getToolFrame(), MergeManager.showBlockingError("Error Setting Function Namespace", e.getMessage());
"Error Setting Function Namespace", e.getMessage());
} }
catch (CircularDependencyException e) { catch (CircularDependencyException e) {
Msg.showError(this, mergeManager.getMergeTool().getToolFrame(), MergeManager.showBlockingError("Error Setting Function Namespace", e.getMessage());
"Error Setting Function Namespace", e.getMessage());
} }
} }
} }
@ -2141,8 +2123,8 @@ abstract class AbstractFunctionMerger implements ListingMergeConstants {
final TaskMonitor monitor) { final TaskMonitor monitor) {
if (functions[RESULT] == null) { if (functions[RESULT] == null) {
Msg.showError(this, mergeManager.getMergeTool().getToolFrame(), MergeManager.showBlockingError("Error Creating Function Conflict Panel",
"Error Creating Function Conflict Panel", "RESULT function is null."); "RESULT function is null.");
return null; return null;
} }
Address myEntryPoint = functions[MY].getEntryPoint(); Address myEntryPoint = functions[MY].getEntryPoint();
@ -2157,8 +2139,7 @@ abstract class AbstractFunctionMerger implements ListingMergeConstants {
conflictCount = funcConflicts.get(myEntryPoint); conflictCount = funcConflicts.get(myEntryPoint);
} }
catch (NoValueException e) { catch (NoValueException e) {
Msg.showError(this, mergeManager.getMergeTool().getToolFrame(), MergeManager.showBlockingError("Error Creating Function Conflict Panel",
"Error Creating Function Conflict Panel",
"Couldn't get conflict information for MY function at " + "Couldn't get conflict information for MY function at " +
myEntryPoint.toString(true) + "."); myEntryPoint.toString(true) + ".");
return null; return null;
@ -2306,9 +2287,11 @@ abstract class AbstractFunctionMerger implements ListingMergeConstants {
getReturnInfo(programs[LATEST], getReturnInfo(programs[LATEST],
getReturnString(functions[LATEST], hasCustomerStorage), "Use ", " version"), getReturnString(functions[LATEST], hasCustomerStorage), "Use ", " version"),
LATEST_BUTTON_NAME, KEEP_LATEST, changeListener); LATEST_BUTTON_NAME, KEEP_LATEST, changeListener);
verticalConflictPanel.addRadioButtonRow(getReturnInfo(programs[MY], verticalConflictPanel
getReturnString(functions[MY], hasCustomerStorage), "Use ", " version"), .addRadioButtonRow(
CHECKED_OUT_BUTTON_NAME, KEEP_MY, changeListener); getReturnInfo(programs[MY],
getReturnString(functions[MY], hasCustomerStorage), "Use ", " version"),
CHECKED_OUT_BUTTON_NAME, KEEP_MY, changeListener);
verticalConflictPanel.addInfoRow(getReturnInfo(programs[ORIGINAL], verticalConflictPanel.addInfoRow(getReturnInfo(programs[ORIGINAL],
getReturnString(functions[ORIGINAL], hasCustomerStorage), "", " version")); getReturnString(functions[ORIGINAL], hasCustomerStorage), "", " version"));
@ -2351,7 +2334,7 @@ abstract class AbstractFunctionMerger implements ListingMergeConstants {
String msg = "Failed to resolve variable '" + String msg = "Failed to resolve variable '" +
((lvc.vars[ORIGINAL_VAR] != null) ? lvc.vars[ORIGINAL_VAR].getName() : "") + ((lvc.vars[ORIGINAL_VAR] != null) ? lvc.vars[ORIGINAL_VAR].getName() : "") +
"'."; "'.";
Msg.showError(this, null, "Resolve Variable Error", msg, e1); MergeManager.showBlockingError("Resolve Variable Error", msg, e1);
} }
showResolveInfo(getInfoTitle()); showResolveInfo(getInfoTitle());
} }

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -15,23 +15,23 @@
*/ */
package ghidra.app.merge.listing; package ghidra.app.merge.listing;
import ghidra.app.merge.tool.ListingMergePanel;
import ghidra.app.merge.util.ConflictUtility;
import ghidra.app.merge.util.MergeUtilities;
import ghidra.program.model.address.*;
import ghidra.program.model.listing.CodeUnit;
import ghidra.program.model.mem.MemoryAccessException;
import ghidra.program.util.*;
import ghidra.util.Msg;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener; import javax.swing.event.ChangeListener;
import ghidra.app.merge.MergeManager;
import ghidra.app.merge.tool.ListingMergePanel;
import ghidra.app.merge.util.ConflictUtility;
import ghidra.app.merge.util.MergeUtilities;
import ghidra.program.model.address.*;
import ghidra.program.model.listing.CommentType;
import ghidra.program.model.mem.MemoryAccessException;
import ghidra.program.util.*;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
/** /**
* Class for merging comment changes. This class can merge non-conflicting * Class for merging comment changes. This class can merge non-conflicting
* comment changes that were made to the checked out version. It can determine * comment changes that were made to the checked out version. It can determine
@ -87,6 +87,7 @@ class CommentMerger extends AbstractListingMerger {
/* (non-Javadoc) /* (non-Javadoc)
* @see ghidra.app.merge.listing.ListingMerger#getConflictType() * @see ghidra.app.merge.listing.ListingMerger#getConflictType()
*/ */
@Override
public String getConflictType() { public String getConflictType() {
return "Comment"; return "Comment";
} }
@ -107,6 +108,7 @@ class CommentMerger extends AbstractListingMerger {
/* (non-Javadoc) /* (non-Javadoc)
* @see ghidra.app.merge.listing.ListingMerger#autoMerge(ghidra.util.task.TaskMonitor) * @see ghidra.app.merge.listing.ListingMerger#autoMerge(ghidra.util.task.TaskMonitor)
*/ */
@Override
public void autoMerge(int progressMin, int progressMax, TaskMonitor monitor) public void autoMerge(int progressMin, int progressMax, TaskMonitor monitor)
throws ProgramConflictException, MemoryAccessException, CancelledException { throws ProgramConflictException, MemoryAccessException, CancelledException {
@ -133,9 +135,8 @@ class CommentMerger extends AbstractListingMerger {
private void autoMerge(int diffType, AddressSet conflictSet, TaskMonitor monitor) private void autoMerge(int diffType, AddressSet conflictSet, TaskMonitor monitor)
throws ProgramConflictException, CancelledException { throws ProgramConflictException, CancelledException {
AddressSetView latestDetailSet = AddressSetView latestDetailSet = listingMergeMgr.diffOriginalLatest
listingMergeMgr.diffOriginalLatest.getDifferences(new ProgramDiffFilter(diffType), .getDifferences(new ProgramDiffFilter(diffType), monitor);
monitor);
AddressSetView myDetailSet = AddressSetView myDetailSet =
listingMergeMgr.diffOriginalMy.getDifferences(new ProgramDiffFilter(diffType), monitor); listingMergeMgr.diffOriginalMy.getDifferences(new ProgramDiffFilter(diffType), monitor);
AddressSet autoSet = new AddressSet(); AddressSet autoSet = new AddressSet();
@ -175,6 +176,7 @@ class CommentMerger extends AbstractListingMerger {
/* (non-Javadoc) /* (non-Javadoc)
* @see ghidra.app.merge.listing.ListingMerger#hasConflict(ghidra.program.model.address.Address) * @see ghidra.app.merge.listing.ListingMerger#hasConflict(ghidra.program.model.address.Address)
*/ */
@Override
public boolean hasConflict(Address addr) { public boolean hasConflict(Address addr) {
return hasConflict(addr, ProgramMergeFilter.PLATE_COMMENTS) || return hasConflict(addr, ProgramMergeFilter.PLATE_COMMENTS) ||
hasConflict(addr, ProgramMergeFilter.PRE_COMMENTS) || hasConflict(addr, ProgramMergeFilter.PRE_COMMENTS) ||
@ -186,6 +188,7 @@ class CommentMerger extends AbstractListingMerger {
/* (non-Javadoc) /* (non-Javadoc)
* @see ghidra.app.merge.listing.ListingMerger#getConflictCount(ghidra.program.model.address.Address) * @see ghidra.app.merge.listing.ListingMerger#getConflictCount(ghidra.program.model.address.Address)
*/ */
@Override
public int getConflictCount(Address addr) { public int getConflictCount(Address addr) {
int count = 0; int count = 0;
if (hasConflict(addr, ProgramMergeFilter.PLATE_COMMENTS)) { if (hasConflict(addr, ProgramMergeFilter.PLATE_COMMENTS)) {
@ -216,7 +219,7 @@ class CommentMerger extends AbstractListingMerger {
else { else {
conflictPanel.clear(); conflictPanel.clear();
} }
int type = getCodeUnitCommentType(programMergeType); CommentType type = getCodeUnitCommentType(programMergeType);
int choice = getChoiceForCommentType(programMergeType); int choice = getChoiceForCommentType(programMergeType);
boolean useForAll = (choice != ASK_USER); boolean useForAll = (choice != ASK_USER);
conflictPanel.setUseForAll(useForAll); conflictPanel.setUseForAll(useForAll);
@ -234,9 +237,8 @@ class CommentMerger extends AbstractListingMerger {
String msg; String msg;
conflictPanel.setRowHeader(new String[] { "Option", "Comment" }); conflictPanel.setRowHeader(new String[] { "Option", "Comment" });
if (latestComment == null || myComment == null) { if (latestComment == null || myComment == null) {
String[] latestStrings = String[] latestStrings = new String[] {
new String[] { createButtonText(LATEST_TITLE, programMergeType, latestComment), createButtonText(LATEST_TITLE, programMergeType, latestComment), latestTrunc };
latestTrunc };
String[] myStrings = String[] myStrings =
new String[] { createButtonText(MY_TITLE, programMergeType, myComment), myTrunc }; new String[] { createButtonText(MY_TITLE, programMergeType, myComment), myTrunc };
conflictPanel.addRadioButtonRow(latestStrings, LATEST_BUTTON_NAME, KEEP_LATEST, conflictPanel.addRadioButtonRow(latestStrings, LATEST_BUTTON_NAME, KEEP_LATEST,
@ -246,20 +248,19 @@ class CommentMerger extends AbstractListingMerger {
msg = conflictTypeText + " comments differ. Select whether or not to keep the comment."; msg = conflictTypeText + " comments differ. Select whether or not to keep the comment.";
} }
else { else {
String[] latestStrings = String[] latestStrings = new String[] {
new String[] { createCheckBoxText(LATEST_TITLE, programMergeType, latestComment), createCheckBoxText(LATEST_TITLE, programMergeType, latestComment), latestTrunc };
latestTrunc };
String[] myStrings = String[] myStrings =
new String[] { createCheckBoxText(MY_TITLE, programMergeType, myComment), myTrunc }; new String[] { createCheckBoxText(MY_TITLE, programMergeType, myComment), myTrunc };
conflictPanel.addCheckBoxRow(latestStrings, LATEST_CHECK_BOX_NAME, KEEP_LATEST, conflictPanel.addCheckBoxRow(latestStrings, LATEST_CHECK_BOX_NAME, KEEP_LATEST,
changeListener); changeListener);
conflictPanel.addCheckBoxRow(myStrings, CHECKED_OUT_CHECK_BOX_NAME, KEEP_MY, conflictPanel.addCheckBoxRow(myStrings, CHECKED_OUT_CHECK_BOX_NAME, KEEP_MY,
changeListener); changeListener);
msg = msg = getTypeName(programMergeType) +
getTypeName(programMergeType) + " comments differ. Select either or both of the comments.";
" comments differ. Select either or both of the comments.";
} }
conflictPanel.addInfoRow(new String[] { "'" + ORIGINAL_TITLE + "' version", originalTrunc }); conflictPanel
.addInfoRow(new String[] { "'" + ORIGINAL_TITLE + "' version", originalTrunc });
conflictPanel.setHeader(msg); conflictPanel.setHeader(msg);
} }
@ -267,9 +268,10 @@ class CommentMerger extends AbstractListingMerger {
/* (non-Javadoc) /* (non-Javadoc)
* @see ghidra.app.merge.listing.ListingMerger#mergeConflicts(ghidra.app.merge.tool.ListingMergePanel, ghidra.program.model.address.Address, int, ghidra.util.task.TaskMonitor) * @see ghidra.app.merge.listing.ListingMerger#mergeConflicts(ghidra.app.merge.tool.ListingMergePanel, ghidra.program.model.address.Address, int, ghidra.util.task.TaskMonitor)
*/ */
@Override
public void mergeConflicts(ListingMergePanel listingPanel, Address addr, public void mergeConflicts(ListingMergePanel listingPanel, Address addr,
int chosenConflictOption, TaskMonitor monitor) throws CancelledException, int chosenConflictOption, TaskMonitor monitor)
MemoryAccessException { throws CancelledException, MemoryAccessException {
mergeConflicts(ProgramMergeFilter.PLATE_COMMENTS, listingPanel, addr, chosenConflictOption, mergeConflicts(ProgramMergeFilter.PLATE_COMMENTS, listingPanel, addr, chosenConflictOption,
monitor); monitor);
mergeConflicts(ProgramMergeFilter.PRE_COMMENTS, listingPanel, addr, chosenConflictOption, mergeConflicts(ProgramMergeFilter.PRE_COMMENTS, listingPanel, addr, chosenConflictOption,
@ -287,8 +289,8 @@ class CommentMerger extends AbstractListingMerger {
if (!hasConflict(addr, programMergeFilterCommentType)) { if (!hasConflict(addr, programMergeFilterCommentType)) {
return; return;
} }
monitor.setMessage("Resolving " + getTypeName(programMergeFilterCommentType) + monitor.setMessage(
" Comment conflicts."); "Resolving " + getTypeName(programMergeFilterCommentType) + " Comment conflicts.");
int choiceForCommentType = getChoiceForCommentType(programMergeFilterCommentType); int choiceForCommentType = getChoiceForCommentType(programMergeFilterCommentType);
if (choiceForCommentType != ASK_USER) { if (choiceForCommentType != ASK_USER) {
merge(addr, programMergeFilterCommentType, choiceForCommentType, monitor); merge(addr, programMergeFilterCommentType, choiceForCommentType, monitor);
@ -323,20 +325,20 @@ class CommentMerger extends AbstractListingMerger {
} }
} }
private int getCodeUnitCommentType(int programMergeCommentType) { private CommentType getCodeUnitCommentType(int programMergeCommentType) {
switch (programMergeCommentType) { switch (programMergeCommentType) {
case ProgramMergeFilter.PLATE_COMMENTS: case ProgramMergeFilter.PLATE_COMMENTS:
return CodeUnit.PLATE_COMMENT; return CommentType.PLATE;
case ProgramMergeFilter.PRE_COMMENTS: case ProgramMergeFilter.PRE_COMMENTS:
return CodeUnit.PRE_COMMENT; return CommentType.PRE;
case ProgramMergeFilter.EOL_COMMENTS: case ProgramMergeFilter.EOL_COMMENTS:
return CodeUnit.EOL_COMMENT; return CommentType.EOL;
case ProgramMergeFilter.REPEATABLE_COMMENTS: case ProgramMergeFilter.REPEATABLE_COMMENTS:
return CodeUnit.REPEATABLE_COMMENT; return CommentType.REPEATABLE;
case ProgramMergeFilter.POST_COMMENTS: case ProgramMergeFilter.POST_COMMENTS:
return CodeUnit.POST_COMMENT; return CommentType.POST;
default: default:
return -1; return null;
} }
} }
@ -392,7 +394,7 @@ class CommentMerger extends AbstractListingMerger {
postCommentChoice = choiceForCommentType; postCommentChoice = choiceForCommentType;
break; break;
default: default:
Msg.showError(this, listingMergePanel, "Unrecognized Comment Type", MergeManager.showBlockingError("Unrecognized Comment Type",
"Unrecognized indicator (" + programMergeCommentType + "Unrecognized indicator (" + programMergeCommentType +
") for comment type to merge."); ") for comment type to merge.");
} }
@ -405,6 +407,7 @@ class CommentMerger extends AbstractListingMerger {
this.currentMonitor = monitor; this.currentMonitor = monitor;
try { try {
final ChangeListener changeListener = new ChangeListener() { final ChangeListener changeListener = new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) { public void stateChanged(ChangeEvent e) {
conflictOption = conflictPanel.getSelectedOptions(); conflictOption = conflictPanel.getSelectedOptions();
if (conflictOption == ASK_USER) { if (conflictOption == ASK_USER) {
@ -432,6 +435,7 @@ class CommentMerger extends AbstractListingMerger {
} }
}; };
SwingUtilities.invokeAndWait(new Runnable() { SwingUtilities.invokeAndWait(new Runnable() {
@Override
public void run() { public void run() {
setupConflictsPanel(listingPanel, CommentMerger.this.currentAddress, setupConflictsPanel(listingPanel, CommentMerger.this.currentAddress,
CommentMerger.this.programMergeType, changeListener); CommentMerger.this.programMergeType, changeListener);
@ -439,6 +443,7 @@ class CommentMerger extends AbstractListingMerger {
} }
}); });
SwingUtilities.invokeLater(new Runnable() { SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() { public void run() {
Address addressToShow = CommentMerger.this.currentAddress; Address addressToShow = CommentMerger.this.currentAddress;
listingPanel.clearAllBackgrounds(); listingPanel.clearAllBackgrounds();
@ -506,6 +511,7 @@ class CommentMerger extends AbstractListingMerger {
/* (non-Javadoc) /* (non-Javadoc)
* @see ghidra.app.merge.listing.ListingMerger#getConflicts() * @see ghidra.app.merge.listing.ListingMerger#getConflicts()
*/ */
@Override
public AddressSetView getConflicts() { public AddressSetView getConflicts() {
AddressSet conflicts = new AddressSet(); AddressSet conflicts = new AddressSet();
conflicts.add(conflictPlate); conflicts.add(conflictPlate);

View file

@ -15,16 +15,15 @@
*/ */
package ghidra.app.merge.listing; package ghidra.app.merge.listing;
import java.lang.reflect.InvocationTargetException;
import java.util.*; import java.util.*;
import javax.swing.JPanel; import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener; import javax.swing.event.ChangeListener;
import generic.stl.Pair; import generic.stl.Pair;
import ghidra.app.merge.MergeConstants; import ghidra.app.merge.MergeConstants;
import ghidra.app.merge.MergeManager;
import ghidra.app.merge.tool.ListingMergePanel; import ghidra.app.merge.tool.ListingMergePanel;
import ghidra.app.merge.util.ConflictUtility; import ghidra.app.merge.util.ConflictUtility;
import ghidra.app.util.NamespaceUtils; import ghidra.app.util.NamespaceUtils;
@ -436,7 +435,7 @@ public class ExternalFunctionMerger extends AbstractFunctionMerger implements Li
thunkChoice = choiceForFunctionConflict; thunkChoice = choiceForFunctionConflict;
break; break;
default: default:
Msg.showError(this, listingMergePanel, "Unrecognized External Conflict Type", MergeManager.showBlockingError("Unrecognized External Conflict Type",
"Unrecognized indicator (" + externalConflictType + "Unrecognized indicator (" + externalConflictType +
") for external conflict type to merge."); ") for external conflict type to merge.");
} }
@ -1246,12 +1245,10 @@ public class ExternalFunctionMerger extends AbstractFunctionMerger implements Li
originalResolvedSymbols.put(originalID, resultID); originalResolvedSymbols.put(originalID, resultID);
} }
catch (DuplicateNameException e) { catch (DuplicateNameException e) {
Msg.showError(this, mergeManager.getMergeTool().getToolFrame(), MergeManager.showBlockingError("Error Merging External Location", e.getMessage());
"Error Merging External Location", e.getMessage());
} }
catch (InvalidInputException e) { catch (InvalidInputException e) {
Msg.showError(this, mergeManager.getMergeTool().getToolFrame(), MergeManager.showBlockingError("Error Merging External Location", e.getMessage());
"Error Merging External Location", e.getMessage());
} }
mergeManager.updateProgress((++changeNum / totalChanges) * 100); mergeManager.updateProgress((++changeNum / totalChanges) * 100);
@ -1392,8 +1389,7 @@ public class ExternalFunctionMerger extends AbstractFunctionMerger implements Li
ExternalLocation chosenExternalLocation; ExternalLocation chosenExternalLocation;
if ((chosenConflictOption & KEEP_ORIGINAL) != 0) { if ((chosenConflictOption & KEEP_ORIGINAL) != 0) {
// chosenExternalLocation = externalLocations[ORIGINAL]; // chosenExternalLocation = externalLocations[ORIGINAL];
Msg.showError(this, mergeManager.getMergeTool().getToolFrame(), MergeManager.showBlockingError("Error Merging External Location",
"Error Merging External Location",
"Can't currently merge external data type from ORIGINAL program." + "Can't currently merge external data type from ORIGINAL program." +
((externalLocations[ORIGINAL] != null) ((externalLocations[ORIGINAL] != null)
? (" ORIGINAL external was " + externalLocations[ORIGINAL].getLabel() + ? (" ORIGINAL external was " + externalLocations[ORIGINAL].getLabel() +
@ -1409,8 +1405,7 @@ public class ExternalFunctionMerger extends AbstractFunctionMerger implements Li
} }
else { else {
// chosenExternalLocation = null; // chosenExternalLocation = null;
Msg.showError(this, mergeManager.getMergeTool().getToolFrame(), MergeManager.showBlockingError("Error Merging External Location",
"Error Merging External Location",
"Can only merge external data type from LATEST or MY program." + "Can only merge external data type from LATEST or MY program." +
((externalLocations[RESULT] != null) ((externalLocations[RESULT] != null)
? (" RESULT external was " + externalLocations[RESULT].getLabel() + ".") ? (" RESULT external was " + externalLocations[RESULT].getLabel() + ".")
@ -3376,14 +3371,14 @@ public class ExternalFunctionMerger extends AbstractFunctionMerger implements Li
resultExternalLocation = addExternal(myExternalLocation, monitor); resultExternalLocation = addExternal(myExternalLocation, monitor);
} }
catch (DuplicateNameException e) { catch (DuplicateNameException e) {
Msg.showError(this, mergeManager.getMergeTool().getToolFrame(), MergeManager.showBlockingError("Error Merging External Location",
"Error Merging External Location", "Couldn't merge external '" + "Couldn't merge external '" + myExternalLocation.getLabel() + "'. " +
myExternalLocation.getLabel() + "'. " + e.getMessage()); e.getMessage());
} }
catch (InvalidInputException e) { catch (InvalidInputException e) {
Msg.showError(this, mergeManager.getMergeTool().getToolFrame(), MergeManager.showBlockingError("Error Merging External Location",
"Error Merging External Location", "Couldn't merge external '" + "Couldn't merge external '" + myExternalLocation.getLabel() + "'. " +
myExternalLocation.getLabel() + "'. " + e.getMessage()); e.getMessage());
} }
return resultExternalLocation; return resultExternalLocation;
} }
@ -3742,12 +3737,10 @@ public class ExternalFunctionMerger extends AbstractFunctionMerger implements Li
} }
} }
catch (DuplicateNameException e) { catch (DuplicateNameException e) {
Msg.showError(this, mergeManager.getMergeTool().getToolFrame(), MergeManager.showBlockingError("Error Merging External Location", e.getMessage());
"Error Merging External Location", e.getMessage());
} }
catch (InvalidInputException e) { catch (InvalidInputException e) {
Msg.showError(this, mergeManager.getMergeTool().getToolFrame(), MergeManager.showBlockingError("Error Merging External Location", e.getMessage());
"Error Merging External Location", e.getMessage());
} }
} }
@ -4087,17 +4080,8 @@ public class ExternalFunctionMerger extends AbstractFunctionMerger implements Li
this.currentMonitor = monitor; this.currentMonitor = monitor;
this.currentConflictPanel = (ConflictPanel) conflictPanel; this.currentConflictPanel = (ConflictPanel) conflictPanel;
try { Swing.runNow(() -> addConflictPanel.setBottomComponent(conflictPanel));
SwingUtilities.invokeAndWait(() -> addConflictPanel.setBottomComponent(conflictPanel));
}
catch (InterruptedException e) {
Msg.showError(this, null, "Error Displaying Conflict Panel", e);
return;
}
catch (InvocationTargetException e) {
Msg.showError(this, null, "Error Displaying Conflict Panel", e);
return;
}
if (mergeManager != null) { if (mergeManager != null) {
mergeManager.setApplyEnabled(false); mergeManager.setApplyEnabled(false);
addConflictPanel.setConflictInfo(conflictIndex, latestLocation, myLocation); addConflictPanel.setConflictInfo(conflictIndex, latestLocation, myLocation);
@ -4123,7 +4107,7 @@ public class ExternalFunctionMerger extends AbstractFunctionMerger implements Li
final TaskMonitor monitor) { final TaskMonitor monitor) {
if (conflictPanel == null) { if (conflictPanel == null) {
Msg.showError(this, null, "Error Displaying Conflict Panel", MergeManager.showBlockingError("Error Displaying Conflict Panel",
"The conflict panel could not be created."); "The conflict panel could not be created.");
return; return;
} }
@ -4131,23 +4115,8 @@ public class ExternalFunctionMerger extends AbstractFunctionMerger implements Li
this.currentMonitor = monitor; this.currentMonitor = monitor;
this.currentConflictPanel = conflictPanel; this.currentConflictPanel = conflictPanel;
try { Swing.runNow(() -> listingPanel.setBottomComponent(conflictPanel));
SwingUtilities.invokeAndWait(() -> listingPanel.setBottomComponent(conflictPanel));
SwingUtilities.invokeLater(() -> {
// Set background color of function entry point code unit
// listingPanel.clearAllBackgrounds();
// listingPanel.paintAllBackgrounds(new AddressSet(resultAddressFactory,
// entryPtAddr, entryPtAddr));
});
}
catch (InterruptedException e) {
Msg.showError(this, null, "Error Displaying Conflict Panel", e);
return;
}
catch (InvocationTargetException e) {
Msg.showError(this, null, "Error Displaying Conflict Panel", e);
return;
}
if (mergeManager != null) { if (mergeManager != null) {
mergeManager.setApplyEnabled(false); mergeManager.setApplyEnabled(false);

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -170,8 +170,8 @@ public class ExternalProgramMerger implements MergeResolver, ListingMergeConstan
String title = getConflictType() + " Merge Information"; String title = getConflictType() + " Merge Information";
String msg = infoBuf.toString(); String msg = infoBuf.toString();
ReadTextDialog dialog = new ReadTextDialog(title, msg); ReadTextDialog dialog = new ReadTextDialog(title, msg);
mergeManager.getMergeTool().showDialog(dialog, mergeManager.getMergeTool()
mergeManager.getMergeTool().getToolFrame()); .showDialog(dialog, mergeManager.getMergeTool().getToolFrame());
} }
}); });
} }
@ -195,11 +195,11 @@ public class ExternalProgramMerger implements MergeResolver, ListingMergeConstan
if (mergeManager != null) { if (mergeManager != null) {
latestResolvedSymbols = (LongLongHashtable) mergeManager latestResolvedSymbols = (LongLongHashtable) mergeManager
.getResolveInformation(MergeConstants.RESOLVED_LATEST_SYMBOLS); .getResolveInformation(MergeConstants.RESOLVED_LATEST_SYMBOLS);
myResolvedSymbols = (LongLongHashtable) mergeManager myResolvedSymbols = (LongLongHashtable) mergeManager
.getResolveInformation(MergeConstants.RESOLVED_MY_SYMBOLS); .getResolveInformation(MergeConstants.RESOLVED_MY_SYMBOLS);
originalResolvedSymbols = (LongLongHashtable) mergeManager originalResolvedSymbols = (LongLongHashtable) mergeManager
.getResolveInformation(MergeConstants.RESOLVED_ORIGINAL_SYMBOLS); .getResolveInformation(MergeConstants.RESOLVED_ORIGINAL_SYMBOLS);
// Populate the reverse maps. // Populate the reverse maps.
mapResultsToOriginalLibs(); mapResultsToOriginalLibs();
@ -913,7 +913,7 @@ public class ExternalProgramMerger implements MergeResolver, ListingMergeConstan
isExternalUserDefined(program2, libName2)); isExternalUserDefined(program2, libName2));
} }
catch (InvalidInputException e) { catch (InvalidInputException e) {
Msg.showError(this, null, "Error Setting External Program Name", MergeManager.showBlockingError("Error Setting External Program Name",
"Couldn't set path to '" + em2.getExternalLibraryPath(libName2) + "Couldn't set path to '" + em2.getExternalLibraryPath(libName2) +
"' for external program name '" + libName2 + "'"); "' for external program name '" + libName2 + "'");
} }
@ -922,7 +922,7 @@ public class ExternalProgramMerger implements MergeResolver, ListingMergeConstan
if (libName1 != null && em1.contains(libName1)) { if (libName1 != null && em1.contains(libName1)) {
boolean removed = em1.removeExternalLibrary(libName1); boolean removed = em1.removeExternalLibrary(libName1);
if (!removed) { if (!removed) {
Msg.showError(this, null, "Error Removing External Program Name", MergeManager.showBlockingError("Error Removing External Program Name",
"Couldn't remove external program name '" + libName1 + "'"); "Couldn't remove external program name '" + libName1 + "'");
} }
} }

View file

@ -26,6 +26,7 @@ import javax.swing.event.ChangeListener;
import generic.stl.Pair; import generic.stl.Pair;
import ghidra.app.merge.MergeConstants; import ghidra.app.merge.MergeConstants;
import ghidra.app.merge.MergeManager;
import ghidra.app.merge.tool.ListingMergePanel; import ghidra.app.merge.tool.ListingMergePanel;
import ghidra.app.merge.util.ConflictUtility; import ghidra.app.merge.util.ConflictUtility;
import ghidra.app.merge.util.MergeUtilities; import ghidra.app.merge.util.MergeUtilities;
@ -700,17 +701,8 @@ class FunctionMerger extends AbstractFunctionMerger implements ListingMerger {
f.setParentNamespace(ns); f.setParentNamespace(ns);
} }
} }
catch (DuplicateNameException e) { catch (DuplicateNameException | InvalidInputException | CircularDependencyException e) {
Msg.showError(this, mergeManager.getMergeTool().getToolFrame(), MergeManager.showBlockingError("Error Setting Function Namespace", e.getMessage());
"Error Setting Function Namespace", e.getMessage());
}
catch (InvalidInputException e) {
Msg.showError(this, mergeManager.getMergeTool().getToolFrame(),
"Error Setting Function Namespace", e.getMessage());
}
catch (CircularDependencyException e) {
Msg.showError(this, mergeManager.getMergeTool().getToolFrame(),
"Error Setting Function Namespace", e.getMessage());
} }
} }
} }
@ -762,17 +754,10 @@ class FunctionMerger extends AbstractFunctionMerger implements ListingMerger {
listingMergeManager.resolveNamespace(origP, origF.getParentNamespace()); listingMergeManager.resolveNamespace(origP, origF.getParentNamespace());
resultF.setParentNamespace(ns); resultF.setParentNamespace(ns);
} }
catch (DuplicateNameException e) { catch (DuplicateNameException | InvalidInputException
Msg.showError(this, mergeManager.getMergeTool().getToolFrame(), | CircularDependencyException e) {
"Error Setting Function Namespace", e.getMessage()); MergeManager.showBlockingError("Error Setting Function Namespace",
} e.getMessage());
catch (InvalidInputException e) {
Msg.showError(this, mergeManager.getMergeTool().getToolFrame(),
"Error Setting Function Namespace", e.getMessage());
}
catch (CircularDependencyException e) {
Msg.showError(this, mergeManager.getMergeTool().getToolFrame(),
"Error Setting Function Namespace", e.getMessage());
} }
} }
} }
@ -1453,8 +1438,7 @@ class FunctionMerger extends AbstractFunctionMerger implements ListingMerger {
private void showOverlapException(final Address entryPt, Exception e) { private void showOverlapException(final Address entryPt, Exception e) {
String message = "Couldn't display body address set conflict for function at " + String message = "Couldn't display body address set conflict for function at " +
entryPt.toString(true) + ".\n " + e.getMessage(); entryPt.toString(true) + ".\n " + e.getMessage();
Msg.showError(this, mergeManager.getMergeTool().getToolFrame(), "Function Merge Error", MergeManager.showBlockingError("Function Merge Error", message, e);
message, e);
// Should this just put a message on errorBuf instead? // Should this just put a message on errorBuf instead?
} }
@ -1738,7 +1722,7 @@ class FunctionMerger extends AbstractFunctionMerger implements ListingMerger {
thunkChoice = choiceForFunctionConflict; thunkChoice = choiceForFunctionConflict;
break; break;
default: default:
Msg.showError(this, listingMergePanel, "Unrecognized Function Conflict Type", MergeManager.showBlockingError("Unrecognized Function Conflict Type",
"Unrecognized indicator (" + functionConflictType + "Unrecognized indicator (" + functionConflictType +
") for function conflict type to merge."); ") for function conflict type to merge.");
} }

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -23,6 +23,7 @@ import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener; import javax.swing.event.ChangeListener;
import ghidra.app.merge.MergeManager;
import ghidra.app.merge.tool.ListingMergePanel; import ghidra.app.merge.tool.ListingMergePanel;
import ghidra.app.merge.util.ConflictUtility; import ghidra.app.merge.util.ConflictUtility;
import ghidra.program.database.function.FunctionManagerDB; import ghidra.program.database.function.FunctionManagerDB;
@ -82,7 +83,7 @@ public class FunctionTagListingMerger extends AbstractListingMerger {
// the same address, they will still require separate conflict // the same address, they will still require separate conflict
// panels. This keeps track of which one we're currently resolving. // panels. This keeps track of which one we're currently resolving.
private Long currentlyMergingTagID = null; private Long currentlyMergingTagID = null;
private int tagChoice = ASK_USER; private int tagChoice = ASK_USER;
/** /**
@ -249,14 +250,12 @@ public class FunctionTagListingMerger extends AbstractListingMerger {
// in these change sets. // in these change sets.
AddressSetView myChangedAddresses = AddressSetView myChangedAddresses =
listingMergeMgr.diffOriginalMy.getDifferences(new ProgramDiffFilter(diffType), monitor); listingMergeMgr.diffOriginalMy.getDifferences(new ProgramDiffFilter(diffType), monitor);
AddressSetView latestChangedAddresses = listingMergeMgr.diffOriginalLatest.getDifferences( AddressSetView latestChangedAddresses = listingMergeMgr.diffOriginalLatest
new ProgramDiffFilter(diffType), monitor); .getDifferences(new ProgramDiffFilter(diffType), monitor);
// Get a list of all deleted tags in My and Latest. // Get a list of all deleted tags in My and Latest.
Collection<? extends FunctionTag> myDeletedTags = Collection<? extends FunctionTag> myDeletedTags = getDeletedTags(myPgm, monitor);
getDeletedTags(myPgm, monitor); Collection<? extends FunctionTag> latestDeletedTags = getDeletedTags(latestPgm, monitor);
Collection<? extends FunctionTag> latestDeletedTags =
getDeletedTags(latestPgm, monitor);
// Loop over all changed addresses in My and see if any added tags are in the // Loop over all changed addresses in My and see if any added tags are in the
// Latest delete list. If so, conflict panel! // Latest delete list. If so, conflict panel!
@ -292,7 +291,7 @@ public class FunctionTagListingMerger extends AbstractListingMerger {
if (function == null) { if (function == null) {
continue; continue;
} }
// Get all the tags added to the function and compare against // Get all the tags added to the function and compare against
// the delete list. // the delete list.
Collection<FunctionTag> tags = getTagsAddedToFunction(programAddedTo, addr); Collection<FunctionTag> tags = getTagsAddedToFunction(programAddedTo, addr);
@ -419,9 +418,10 @@ public class FunctionTagListingMerger extends AbstractListingMerger {
FunctionTag myTag = getTag(tagID, myPgm); FunctionTag myTag = getTag(tagID, myPgm);
String my = myTag == null ? "<tag deleted>" : myTag.getName(); String my = myTag == null ? "<tag deleted>" : myTag.getName();
conflictPanel.setRowHeader(new String[] { "Option", "Function Tags" }); conflictPanel.setRowHeader(new String[] { "Option", "Function Tags" });
String text = "Function Tag conflict @ address :" + ConflictUtility.getAddressString(addr); String text =
"Function Tag conflict @ address :" + ConflictUtility.getAddressString(addr);
conflictPanel.setHeader(text); conflictPanel.setHeader(text);
conflictPanel.setRowHeader(getFunctionTagInfo(-1, null)); conflictPanel.setRowHeader(getFunctionTagInfo(-1, null));
@ -474,8 +474,8 @@ public class FunctionTagListingMerger extends AbstractListingMerger {
* @param monitor * @param monitor
* @throws CancelledException * @throws CancelledException
*/ */
private void mergeConflictingTag(Address addr, int chosenConflictOption, private void mergeConflictingTag(Address addr, int chosenConflictOption, TaskMonitor monitor)
TaskMonitor monitor) throws CancelledException { throws CancelledException {
int resolutionType = ProgramMergeFilter.MERGE; int resolutionType = ProgramMergeFilter.MERGE;
@ -595,8 +595,8 @@ public class FunctionTagListingMerger extends AbstractListingMerger {
SwingUtilities.invokeAndWait(new Runnable() { SwingUtilities.invokeAndWait(new Runnable() {
@Override @Override
public void run() { public void run() {
setupConflictsPanel(listingPanel, FunctionTagListingMerger.this.currentAddress, tagID, setupConflictsPanel(listingPanel, FunctionTagListingMerger.this.currentAddress,
changeListener); tagID, changeListener);
listingPanel.setBottomComponent(conflictPanel); listingPanel.setBottomComponent(conflictPanel);
} }
}); });
@ -613,7 +613,7 @@ public class FunctionTagListingMerger extends AbstractListingMerger {
}); });
} }
catch (InterruptedException | InvocationTargetException e) { catch (InterruptedException | InvocationTargetException e) {
Msg.showError(this, null, "Merge Error", "Error displaying merge panel", e); MergeManager.showBlockingError("Merge Error", "Error displaying merge panel", e);
return; return;
} }

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -23,6 +23,7 @@ import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener; import javax.swing.event.ChangeListener;
import ghidra.app.merge.MergeConstants; import ghidra.app.merge.MergeConstants;
import ghidra.app.merge.MergeManager;
import ghidra.app.merge.tool.ListingMergePanel; import ghidra.app.merge.tool.ListingMergePanel;
import ghidra.app.merge.util.ConflictUtility; import ghidra.app.merge.util.ConflictUtility;
import ghidra.app.merge.util.MergeUtilities; import ghidra.app.merge.util.MergeUtilities;
@ -182,19 +183,19 @@ class ReferenceMerger extends AbstractListingMerger {
totalChanges = 7; totalChanges = 7;
if (mergeManager != null) { if (mergeManager != null) {
latestResolvedSymbols = latestResolvedSymbols = (LongLongHashtable) mergeManager
(LongLongHashtable) mergeManager.getResolveInformation(MergeConstants.RESOLVED_LATEST_SYMBOLS); .getResolveInformation(MergeConstants.RESOLVED_LATEST_SYMBOLS);
myResolvedSymbols = myResolvedSymbols = (LongLongHashtable) mergeManager
(LongLongHashtable) mergeManager.getResolveInformation(MergeConstants.RESOLVED_MY_SYMBOLS); .getResolveInformation(MergeConstants.RESOLVED_MY_SYMBOLS);
origResolvedSymbols = origResolvedSymbols = (LongLongHashtable) mergeManager
(LongLongHashtable) mergeManager.getResolveInformation(MergeConstants.RESOLVED_ORIGINAL_SYMBOLS); .getResolveInformation(MergeConstants.RESOLVED_ORIGINAL_SYMBOLS);
pickedLatestCodeUnits = pickedLatestCodeUnits = (AddressSetView) mergeManager
(AddressSetView) mergeManager.getResolveInformation(MergeConstants.PICKED_LATEST_CODE_UNITS); .getResolveInformation(MergeConstants.PICKED_LATEST_CODE_UNITS);
pickedMyCodeUnits = pickedMyCodeUnits = (AddressSetView) mergeManager
(AddressSetView) mergeManager.getResolveInformation(MergeConstants.PICKED_MY_CODE_UNITS); .getResolveInformation(MergeConstants.PICKED_MY_CODE_UNITS);
pickedOriginalCodeUnits = pickedOriginalCodeUnits = (AddressSetView) mergeManager
(AddressSetView) mergeManager.getResolveInformation(MergeConstants.PICKED_ORIGINAL_CODE_UNITS); .getResolveInformation(MergeConstants.PICKED_ORIGINAL_CODE_UNITS);
} }
updateProgressMessage("Setting references where code units were merged..."); updateProgressMessage("Setting references where code units were merged...");
autoMergeWhereCodeUnitsMerged(monitor); autoMergeWhereCodeUnitsMerged(monitor);
@ -363,8 +364,7 @@ class ReferenceMerger extends AbstractListingMerger {
} }
private void processOriginalRefs(Reference[] originalRefs) { private void processOriginalRefs(Reference[] originalRefs) {
for (int origIndex = 0; origIndex < originalRefs.length; origIndex++) { for (Reference originalRef : originalRefs) {
Reference originalRef = originalRefs[origIndex];
Reference myRef = DiffUtility.getReference(originalPgm, originalRef, myPgm); Reference myRef = DiffUtility.getReference(originalPgm, originalRef, myPgm);
Reference latestRef = DiffUtility.getReference(originalPgm, originalRef, latestPgm); Reference latestRef = DiffUtility.getReference(originalPgm, originalRef, latestPgm);
if (myRef == null) { if (myRef == null) {
@ -406,8 +406,7 @@ class ReferenceMerger extends AbstractListingMerger {
private void processMyRefsAdded(Reference[] myRefs) { private void processMyRefsAdded(Reference[] myRefs) {
// Check Adds which could result in an AddConflict or a type conflict. // Check Adds which could result in an AddConflict or a type conflict.
for (int myIndex = 0; myIndex < myRefs.length; myIndex++) { for (Reference myRef : myRefs) {
Reference myRef = myRefs[myIndex];
Reference originalRef = DiffUtility.getReference(myPgm, myRef, originalPgm); Reference originalRef = DiffUtility.getReference(myPgm, myRef, originalPgm);
if (originalRef == null) { if (originalRef == null) {
Reference latestRef = DiffUtility.getReference(myPgm, myRef, latestPgm); Reference latestRef = DiffUtility.getReference(myPgm, myRef, latestPgm);
@ -432,7 +431,8 @@ class ReferenceMerger extends AbstractListingMerger {
* @param operandIndex * @param operandIndex
* @return * @return
*/ */
private Reference getFallThroughReference(Program program, Address fromAddress, int operandIndex) { private Reference getFallThroughReference(Program program, Address fromAddress,
int operandIndex) {
Reference[] otherRefs = Reference[] otherRefs =
program.getReferenceManager().getReferencesFrom(fromAddress, operandIndex); program.getReferenceManager().getReferencesFrom(fromAddress, operandIndex);
for (Reference reference : otherRefs) { for (Reference reference : otherRefs) {
@ -450,7 +450,8 @@ class ReferenceMerger extends AbstractListingMerger {
// If both refs changed from original then conflict. // If both refs changed from original then conflict.
Reference origForLatest = Reference origForLatest =
DiffUtility.getReference(latestPgm, latestPrimary, originalPgm); DiffUtility.getReference(latestPgm, latestPrimary, originalPgm);
if (origForLatest != null && diffOriginalLatest.equalRefs(origForLatest, latestPrimary)) { if (origForLatest != null &&
diffOriginalLatest.equalRefs(origForLatest, latestPrimary)) {
return; return;
} }
Reference origForMy = DiffUtility.getReference(myPgm, myPrimary, originalPgm); Reference origForMy = DiffUtility.getReference(myPgm, myPrimary, originalPgm);
@ -490,8 +491,8 @@ class ReferenceMerger extends AbstractListingMerger {
private boolean hasRefTypeConflict(Reference[] latestRefs, Reference[] myRefs, private boolean hasRefTypeConflict(Reference[] latestRefs, Reference[] myRefs,
Reference[] originalRefs) { Reference[] originalRefs) {
if (originalRefs.length > 0) { if (originalRefs.length > 0) {
return (compatibleRefs(originalRefs[0], latestRefs) && compatibleRefs(originalRefs[0], return (compatibleRefs(originalRefs[0], latestRefs) &&
myRefs)); compatibleRefs(originalRefs[0], myRefs));
} }
else if (latestRefs.length > 0) { else if (latestRefs.length > 0) {
return (compatibleRefs(latestRefs[0], myRefs)); return (compatibleRefs(latestRefs[0], myRefs));
@ -531,32 +532,32 @@ class ReferenceMerger extends AbstractListingMerger {
private boolean compatibleRefs(Reference ref1, Reference[] refs) { private boolean compatibleRefs(Reference ref1, Reference[] refs) {
Address toAddr = ref1.getToAddress(); Address toAddr = ref1.getToAddress();
if (toAddr.isMemoryAddress()) { if (toAddr.isMemoryAddress()) {
for (int i = 0; i < refs.length; i++) { for (Reference ref : refs) {
if (!refs[i].getToAddress().isMemoryAddress()) { if (!ref.getToAddress().isMemoryAddress()) {
return false; return false;
} }
} }
return true; return true;
} }
else if (toAddr.isExternalAddress()) { else if (toAddr.isExternalAddress()) {
for (int i = 0; i < refs.length; i++) { for (Reference ref : refs) {
if (!refs[i].getToAddress().isExternalAddress()) { if (!ref.getToAddress().isExternalAddress()) {
return false; return false;
} }
} }
return true; return true;
} }
if (toAddr.isRegisterAddress()) { if (toAddr.isRegisterAddress()) {
for (int i = 0; i < refs.length; i++) { for (Reference ref : refs) {
if (!refs[i].getToAddress().isRegisterAddress()) { if (!ref.getToAddress().isRegisterAddress()) {
return false; return false;
} }
} }
return true; return true;
} }
if (toAddr.isStackAddress()) { if (toAddr.isStackAddress()) {
for (int i = 0; i < refs.length; i++) { for (Reference ref : refs) {
if (!refs[i].getToAddress().isStackAddress()) { if (!ref.getToAddress().isStackAddress()) {
return false; return false;
} }
} }
@ -703,8 +704,8 @@ class ReferenceMerger extends AbstractListingMerger {
*/ */
@Override @Override
public void mergeConflicts(ListingMergePanel listingPanel, Address addr, public void mergeConflicts(ListingMergePanel listingPanel, Address addr,
int chosenConflictOption, TaskMonitor monitor) throws CancelledException, int chosenConflictOption, TaskMonitor monitor)
MemoryAccessException { throws CancelledException, MemoryAccessException {
if (!hasConflict(addr)) { if (!hasConflict(addr)) {
return; return;
} }
@ -768,8 +769,7 @@ class ReferenceMerger extends AbstractListingMerger {
currentOpIndex = opIndex; currentOpIndex = opIndex;
currentBackgroundSet = new AddressSet(addr, addr); currentBackgroundSet = new AddressSet(addr, addr);
currentConflictType = REMOVE_CONFLICT; currentConflictType = REMOVE_CONFLICT;
for (Iterator<Reference> iter = removeList.iterator(); iter.hasNext();) { for (Reference removeRef : removeList) {
Reference removeRef = iter.next();
currentReference = removeRef; currentReference = removeRef;
if (currentReference.getOperandIndex() == opIndex) { if (currentReference.getOperandIndex() == opIndex) {
// If we have a reference choice then a "Use For All" has already occurred. // If we have a reference choice then a "Use For All" has already occurred.
@ -800,8 +800,7 @@ class ReferenceMerger extends AbstractListingMerger {
currentOpIndex = opIndex; currentOpIndex = opIndex;
currentBackgroundSet = new AddressSet(addr, addr); currentBackgroundSet = new AddressSet(addr, addr);
currentConflictType = CHANGE_CONFLICT; currentConflictType = CHANGE_CONFLICT;
for (Iterator<Reference> iter = changeList.iterator(); iter.hasNext();) { for (Reference changeRef : changeList) {
Reference changeRef = iter.next();
currentReference = changeRef; currentReference = changeRef;
if (currentReference.getOperandIndex() == opIndex) { if (currentReference.getOperandIndex() == opIndex) {
// If we have a reference choice then a "Use For All" has already occurred. // If we have a reference choice then a "Use For All" has already occurred.
@ -832,8 +831,7 @@ class ReferenceMerger extends AbstractListingMerger {
currentOpIndex = opIndex; currentOpIndex = opIndex;
currentBackgroundSet = new AddressSet(addr, addr); currentBackgroundSet = new AddressSet(addr, addr);
currentConflictType = ADD_CONFLICT; currentConflictType = ADD_CONFLICT;
for (Iterator<Reference> iter = addList.iterator(); iter.hasNext();) { for (Reference changeRef : addList) {
Reference changeRef = iter.next();
currentReference = changeRef; currentReference = changeRef;
if (currentReference.getReferenceType().isFallthrough()) { if (currentReference.getReferenceType().isFallthrough()) {
continue; // Ignore fallthrough references. continue; // Ignore fallthrough references.
@ -957,7 +955,7 @@ class ReferenceMerger extends AbstractListingMerger {
listingPanel.setBottomComponent(conflictPanel); listingPanel.setBottomComponent(conflictPanel);
} }
catch (Exception e) { catch (Exception e) {
Msg.showError(this, listingPanel, "Error Merging References", MergeManager.showBlockingError("Error Merging References",
"Error Getting Conflict Panel", e); "Error Getting Conflict Panel", e);
} }
} }
@ -1060,20 +1058,19 @@ class ReferenceMerger extends AbstractListingMerger {
Reference[] myRefs = myRefMgr.getReferencesFrom(fromAddress, opIndex); Reference[] myRefs = myRefMgr.getReferencesFrom(fromAddress, opIndex);
panel.setTitle("Reference"); panel.setTitle("Reference");
String fromAddrStr = ConflictUtility.getAddressString(fromAddress); String fromAddrStr = ConflictUtility.getAddressString(fromAddress);
String text = String text = " Conflicting reference types, " + getRefGroup(latestRefs[0]) + " & " +
" Conflicting reference types, " + getRefGroup(latestRefs[0]) + " & " + getRefGroup(myRefs[0]) + ", at '" + fromAddrStr + "' " +
getRefGroup(myRefs[0]) + ", at '" + fromAddrStr + "' " + getOperandIndexString(opIndex) + ".";
getOperandIndexString(opIndex) + ".";
panel.setHeader(text); panel.setHeader(text);
panel.setRowHeader(getReferenceInfo(null, null, null, null)); panel.setRowHeader(getReferenceInfo(null, null, null, null));
String suffix = "' version"; String suffix = "' version";
panel.addRadioButtonRow( panel.addRadioButtonRow(
getReferenceInfo(latestPgm, ((latestRefs.length == 1) ? latestRefs[0] : null), getReferenceInfo(latestPgm, ((latestRefs.length == 1) ? latestRefs[0] : null),
((latestRefs.length == 1) ? "Use '" : "Use all in '"), suffix), LATEST_BUTTON_NAME, ((latestRefs.length == 1) ? "Use '" : "Use all in '"), suffix),
KEEP_LATEST, listener); LATEST_BUTTON_NAME, KEEP_LATEST, listener);
if (latestRefs.length > 1) { if (latestRefs.length > 1) {
for (int i = 0; i < latestRefs.length; i++) { for (Reference latestRef : latestRefs) {
panel.addInfoRow(getReferenceInfo(latestPgm, latestRefs[i], "'", suffix)); panel.addInfoRow(getReferenceInfo(latestPgm, latestRef, "'", suffix));
} }
} }
panel.addRadioButtonRow( panel.addRadioButtonRow(
@ -1081,12 +1078,12 @@ class ReferenceMerger extends AbstractListingMerger {
((myRefs.length == 1) ? "Use '" : "Use all in '"), suffix), ((myRefs.length == 1) ? "Use '" : "Use all in '"), suffix),
CHECKED_OUT_BUTTON_NAME, KEEP_MY, listener); CHECKED_OUT_BUTTON_NAME, KEEP_MY, listener);
if (myRefs.length > 1) { if (myRefs.length > 1) {
for (int i = 0; i < myRefs.length; i++) { for (Reference myRef : myRefs) {
panel.addInfoRow(getReferenceInfo(myPgm, myRefs[i], "'", suffix)); panel.addInfoRow(getReferenceInfo(myPgm, myRef, "'", suffix));
} }
} }
panel.addInfoRow(getReferenceInfo(originalPgm, ((originalRefs.length > 0) ? originalRefs[0] panel.addInfoRow(getReferenceInfo(originalPgm,
: null), "'", suffix)); ((originalRefs.length > 0) ? originalRefs[0] : null), "'", suffix));
for (int i = 1; i < originalRefs.length; i++) { for (int i = 1; i < originalRefs.length; i++) {
panel.addInfoRow(getReferenceInfo(originalPgm, originalRefs[i], "'", suffix)); panel.addInfoRow(getReferenceInfo(originalPgm, originalRefs[i], "'", suffix));
} }
@ -1109,13 +1106,11 @@ class ReferenceMerger extends AbstractListingMerger {
} }
panel.setTitle("Reference"); panel.setTitle("Reference");
String fromAddrStr = ConflictUtility.getAddressString(ref.getFromAddress()); String fromAddrStr = ConflictUtility.getAddressString(ref.getFromAddress());
String toAddrStr = String toAddrStr = ConflictUtility.colorString(ConflictUtility.ADDRESS_COLOR,
ConflictUtility.colorString(ConflictUtility.ADDRESS_COLOR, DiffUtility.getUserToAddressString(resultPgm, ref.getToAddress()));
DiffUtility.getUserToAddressString(resultPgm, ref.getToAddress())); String text = getRefGroup(ref) + " Reference from '" + fromAddrStr + "' " +
String text = getOperandIndexString(ref) + " to '" + toAddrStr +
getRefGroup(ref) + " Reference from '" + fromAddrStr + "' " + "' was removed in one version and changed in other.";
getOperandIndexString(ref) + " to '" + toAddrStr +
"' was removed in one version and changed in other.";
panel.setHeader(text); panel.setHeader(text);
panel.setRowHeader(getReferenceInfo(null, null, null, null)); panel.setRowHeader(getReferenceInfo(null, null, null, null));
String latestPrefix = (latestRef == null) ? "Remove as in '" : "Change as in '"; String latestPrefix = (latestRef == null) ? "Remove as in '" : "Change as in '";
@ -1130,15 +1125,15 @@ class ReferenceMerger extends AbstractListingMerger {
return panel; return panel;
} }
protected VerticalChoicesPanel getChangeConflictPanel(Reference myRef, ChangeListener listener) { protected VerticalChoicesPanel getChangeConflictPanel(Reference myRef,
ChangeListener listener) {
VerticalChoicesPanel panel = getVerticalConflictPanel(); VerticalChoicesPanel panel = getVerticalConflictPanel();
panel.setTitle("Reference"); panel.setTitle("Reference");
Address fromAddr = myRef.getFromAddress(); Address fromAddr = myRef.getFromAddress();
int opIndex = myRef.getOperandIndex(); int opIndex = myRef.getOperandIndex();
String fromAddrStr = ConflictUtility.getAddressString(myRef.getFromAddress()); String fromAddrStr = ConflictUtility.getAddressString(myRef.getFromAddress());
String toAddrStr = String toAddrStr = ConflictUtility.colorString(ConflictUtility.ADDRESS_COLOR,
ConflictUtility.colorString(ConflictUtility.ADDRESS_COLOR, DiffUtility.getUserToAddressString(resultPgm, myRef.getToAddress()));
DiffUtility.getUserToAddressString(resultPgm, myRef.getToAddress()));
Reference latestRef; Reference latestRef;
Reference originalRef; Reference originalRef;
if (myRef.isMemoryReference()) { if (myRef.isMemoryReference()) {
@ -1153,15 +1148,13 @@ class ReferenceMerger extends AbstractListingMerger {
} }
String text; String text;
if (myRef.isExternalReference()) { if (myRef.isExternalReference()) {
text = text = getRefGroup(myRef) + " Reference from '" + fromAddrStr + "' " +
getRefGroup(myRef) + " Reference from '" + fromAddrStr + "' " + getOperandIndexString(myRef) + " was changed in both versions.";
getOperandIndexString(myRef) + " was changed in both versions.";
} }
else { else {
text = text = getRefGroup(myRef) + " Reference from '" + fromAddrStr + "' " +
getRefGroup(myRef) + " Reference from '" + fromAddrStr + "' " + getOperandIndexString(myRef) + " to '" + toAddrStr +
getOperandIndexString(myRef) + " to '" + toAddrStr + "' was changed in both versions.";
"' was changed in both versions.";
} }
panel.setHeader(text); panel.setHeader(text);
panel.setRowHeader(getReferenceInfo(null, null, null, null)); panel.setRowHeader(getReferenceInfo(null, null, null, null));
@ -1195,9 +1188,8 @@ class ReferenceMerger extends AbstractListingMerger {
} }
panel.setTitle("Reference"); panel.setTitle("Reference");
String fromAddrStr = ConflictUtility.getAddressString(myRef.getFromAddress()); String fromAddrStr = ConflictUtility.getAddressString(myRef.getFromAddress());
String text = String text = getRefGroup(myRef) + " Reference from '" + fromAddrStr + "' " +
getRefGroup(myRef) + " Reference from '" + fromAddrStr + "' " + getOperandIndexString(myRef) + " was added in both versions.";
getOperandIndexString(myRef) + " was added in both versions.";
panel.setHeader(text); panel.setHeader(text);
panel.setRowHeader(getReferenceInfo(null, null, null, null)); panel.setRowHeader(getReferenceInfo(null, null, null, null));
String latestPrefix = "Use '"; String latestPrefix = "Use '";
@ -1219,9 +1211,8 @@ class ReferenceMerger extends AbstractListingMerger {
Reference myPrimary = myRefMgr.getPrimaryReferenceFrom(fromAddress, opIndex); Reference myPrimary = myRefMgr.getPrimaryReferenceFrom(fromAddress, opIndex);
panel.setTitle("Reference"); panel.setTitle("Reference");
String fromAddrStr = ConflictUtility.getAddressString(fromAddress); String fromAddrStr = ConflictUtility.getAddressString(fromAddress);
String text = String text = " Conflicting primary references at '" + fromAddrStr + "' " +
" Conflicting primary references at '" + fromAddrStr + "' " + getOperandIndexString(opIndex) + ".";
getOperandIndexString(opIndex) + ".";
panel.setHeader(text); panel.setHeader(text);
panel.setRowHeader(getReferenceInfo(null, null, null, null)); panel.setRowHeader(getReferenceInfo(null, null, null, null));
String prefix = "Set '"; String prefix = "Set '";
@ -1485,7 +1476,8 @@ class ReferenceMerger extends AbstractListingMerger {
return resultRef; return resultRef;
} }
private void resolvePrimaryConflict(Address fromAddress, int opIndex, int chosenConflictOption) { private void resolvePrimaryConflict(Address fromAddress, int opIndex,
int chosenConflictOption) {
if ((chosenConflictOption & KEEP_LATEST) != 0) { if ((chosenConflictOption & KEEP_LATEST) != 0) {
Reference latest = latestRefMgr.getPrimaryReferenceFrom(fromAddress, opIndex); Reference latest = latestRefMgr.getPrimaryReferenceFrom(fromAddress, opIndex);
Reference result = DiffUtility.getReference(latestPgm, latest, resultPgm); Reference result = DiffUtility.getReference(latestPgm, latest, resultPgm);
@ -1536,7 +1528,7 @@ class ReferenceMerger extends AbstractListingMerger {
referenceChoice = choiceForConflictType; referenceChoice = choiceForConflictType;
break; break;
default: default:
Msg.showError(this, listingMergePanel, "Unrecognized Reference Conflict Type", MergeManager.showBlockingError("Unrecognized Reference Conflict Type",
"Unrecognized indicator (" + programMergeConflictType + "Unrecognized indicator (" + programMergeConflictType +
") for reference conflict type to merge."); ") for reference conflict type to merge.");
} }
@ -1552,8 +1544,7 @@ class ReferenceMerger extends AbstractListingMerger {
} }
Symbol latestSymbol = latestPgm.getSymbolTable().getSymbol(latestSymbolID); Symbol latestSymbol = latestPgm.getSymbolTable().getSymbol(latestSymbolID);
if (latestSymbol != null) { if (latestSymbol != null) {
Symbol resultSymbol = Symbol resultSymbol = SimpleDiffUtility.getSymbol(latestSymbol, resultPgm);
SimpleDiffUtility.getSymbol(latestSymbol, resultPgm);
if (resultSymbol != null) { if (resultSymbol != null) {
return resultSymbol.getID(); return resultSymbol.getID();
} }

View file

@ -110,7 +110,7 @@ public class DeleteAction extends DockingAction {
"Are you sure you want to delete selected\n" + "Are you sure you want to delete selected\n" +
"data types and/or categories?\n\n" + "data types and/or categories?\n\n" +
"Note: Changes may trigger the removal of related\n" + "Note: Changes may trigger the removal of related\n" +
"data types, components and defined data.)"); "data types, components and defined data.");
//@formatter:on //@formatter:on
if (choice != OptionDialog.OPTION_ONE) { if (choice != OptionDialog.OPTION_ONE) {
return; return;

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -19,7 +19,6 @@ import static org.junit.Assert.*;
import java.awt.*; import java.awt.*;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator;
import java.util.List; import java.util.List;
import javax.swing.JButton; import javax.swing.JButton;
@ -101,6 +100,10 @@ public abstract class AbstractMergeTest extends AbstractGhidraHeadedIntegrationT
} }
private void tryToPressCancel() { private void tryToPressCancel() {
DockingWindowManager activeInstance = DockingWindowManager.getActiveInstance();
if (activeInstance == null) {
return;
}
Window window = DockingWindowManager.getActiveInstance().getActiveWindow(); Window window = DockingWindowManager.getActiveInstance().getActiveWindow();
JButton cancel = findButtonByText(window, "Cancel"); JButton cancel = findButtonByText(window, "Cancel");
if (cancel == null) { if (cancel == null) {
@ -191,12 +194,11 @@ public abstract class AbstractMergeTest extends AbstractGhidraHeadedIntegrationT
} }
ArrayList<String> list = tx.getOpenSubTransactions(); ArrayList<String> list = tx.getOpenSubTransactions();
StringBuffer tip = new StringBuffer(); StringBuffer tip = new StringBuffer();
Iterator<String> iter = list.iterator(); for (String element : list) {
while (iter.hasNext()) {
if (tip.length() != 0) { if (tip.length() != 0) {
tip.append('\n'); tip.append('\n');
} }
tip.append(iter.next()); tip.append(element);
} }
Msg.error(this, prefix + "Test Case " + testName.getMethodName() + Msg.error(this, prefix + "Test Case " + testName.getMethodName() +
" : ERROR: Transactions still exist! " + tip.toString()); " : ERROR: Transactions still exist! " + tip.toString());

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -321,4 +321,8 @@ public abstract class AbstractDataTypeMergeTest extends AbstractMergeTest {
chooseApply(); chooseApply();
} }
void dismissUnresolvedDataTypesPopup() {
pressButtonByName(waitForWindow("Unresolved Data Types and Components"), "OK");
}
} }

View file

@ -99,8 +99,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
public void modifyLatest(ProgramDB program) { public void modifyLatest(ProgramDB program) {
// change the name // change the name
Category c = program.getDataTypeManager() Category c = program.getDataTypeManager()
.getCategory( .getCategory(new CategoryPath("/Category1/Category2/Category5"));
new CategoryPath("/Category1/Category2/Category5"));
try { try {
c.createCategory("AnotherCategory"); c.createCategory("AnotherCategory");
} }
@ -261,8 +260,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
public void modifyLatest(ProgramDB program) { public void modifyLatest(ProgramDB program) {
// change the name // change the name
Category c = program.getDataTypeManager() Category c = program.getDataTypeManager()
.getCategory( .getCategory(new CategoryPath("/Category1/Category2/Category5"));
new CategoryPath("/Category1/Category2/Category5"));
try { try {
c.createCategory("AnotherCategory"); c.createCategory("AnotherCategory");
Structure dt = new StructureDataType("Test", 0); Structure dt = new StructureDataType("Test", 0);
@ -315,8 +313,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
public void modifyLatest(ProgramDB program) { public void modifyLatest(ProgramDB program) {
// change the name // change the name
Category c = program.getDataTypeManager() Category c = program.getDataTypeManager()
.getCategory( .getCategory(new CategoryPath("/Category1/Category2/Category5"));
new CategoryPath("/Category1/Category2/Category5"));
try { try {
c.createCategory("AnotherCategory"); c.createCategory("AnotherCategory");
StructureDataType dt = new StructureDataType("Test", 0); StructureDataType dt = new StructureDataType("Test", 0);
@ -541,18 +538,32 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
foo.insert(1, dt); foo.insert(1, dt);
} }
}); });
executeMerge(DataTypeMergeManager.OPTION_MY);
executeMerge();
dismissUnresolvedDataTypesPopup();
waitForCompletion();
// CoolUnion should not have been added back in // CoolUnion should not have been added back in
DataTypeManager dtm = resultProgram.getDataTypeManager(); DataTypeManager dtm = resultProgram.getDataTypeManager();
DataType dt = dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion"); DataType dt = dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion");
assertNull(dt); assertNull(dt);
Structure foo = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo"); Structure foo = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo");
DataTypeComponent[] dtcs = foo.getComponents(); assertNotNull(foo);
// components 1-97 should be default data types //@formatter:off
for (int i = 1; i < 97; i++) { assertEquals("/MISC/Foo\n" +
assertEquals(DataType.DEFAULT, dtcs[i].getDataType()); "pack(disabled)\n" +
} "Structure Foo {\n" +
" 0 byte 1 \"\"\n" +
" 1 -BAD- 96 \"Failed to apply 'CoolUnion'\"\n" +
" 97 byte 1 \"\"\n" +
" 98 word 2 \"\"\n" +
" 100 Bar 6 \"\"\n" +
"}\n" +
"Length: 106 Alignment: 1\n", foo.toString());
//@formatter:on
} }
@Test @Test
@ -951,9 +962,8 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest {
}); });
executeMerge(DataTypeMergeManager.OPTION_MY); executeMerge(DataTypeMergeManager.OPTION_MY);
DataTypeManager dtm = resultProgram.getDataTypeManager(); DataTypeManager dtm = resultProgram.getDataTypeManager();
Structure s = Structure s = (Structure) dtm
(Structure) dtm.getDataType(new CategoryPath("/Category1/Category2/Category3"), .getDataType(new CategoryPath("/Category1/Category2/Category3"), "IntStruct");
"IntStruct");
DataTypeComponent dtc = s.getComponent(2); DataTypeComponent dtc = s.getComponent(2);
assertEquals("My_Field_Three", dtc.getFieldName()); assertEquals("My_Field_Three", dtc.getFieldName());
assertEquals("my comments for Field 3", dtc.getComment()); assertEquals("my comments for Field 3", dtc.getComment());

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -99,10 +99,10 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
DataType cdt = dtm.getDataType(new CategoryPath("/Category1/Category2/Category4"), DataType cdt = dtm.getDataType(new CategoryPath("/Category1/Category2/Category4"),
"CharStruct"); "CharStruct");
Structure s = (Structure) dt; Structure s = (Structure) dt;
Array array = new ArrayDataType(cdt, 5, cdt.getLength()); Array array = new ArrayDataType(cdt, 0, cdt.getLength());
s.add(new ByteDataType()); s.add(new ByteDataType());
s.add(new WordDataType()); s.add(new WordDataType());
s.add(array); s.add(new PointerDataType(array, dtm));
} }
@Override @Override
@ -116,8 +116,8 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
DataType cdt = dtm.getDataType(new CategoryPath("/Category1/Category2/Category4"), DataType cdt = dtm.getDataType(new CategoryPath("/Category1/Category2/Category4"),
"CharStruct"); "CharStruct");
Structure s = (Structure) dt; Structure s = (Structure) dt;
Array array = new ArrayDataType(cdt, 3, cdt.getLength()); Array array = new ArrayDataType(cdt, 0, cdt.getLength());
s.add(array); s.add(new PointerDataType(array, dtm));
s.add(new ByteDataType()); s.add(new ByteDataType());
s.add(new WordDataType()); s.add(new WordDataType());
} }
@ -132,7 +132,8 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
Structure s = (Structure) dt; Structure s = (Structure) dt;
assertEquals(7, s.getNumComponents()); assertEquals(7, s.getNumComponents());
DataTypeComponent dtc = s.getComponent(4); DataTypeComponent dtc = s.getComponent(4);
assertTrue(dtc.getDataType() instanceof Array); System.out.println(dtc.getDataType());
//assertTrue(dtc.getDataType() instanceof Array);
} }
@Test @Test
@ -191,7 +192,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
// /Category1/Category2/Category3 // /Category1/Category2/Category3
DataType dt = dtm.getDataType(new CategoryPath("/Category1/Category2/Category3"), DataType dt = dtm.getDataType(new CategoryPath("/Category1/Category2/Category3"),
"IntStruct"); "IntStruct");
try { try {
dt.setName("OtherIntStruct"); dt.setName("OtherIntStruct");
} }
@ -366,7 +367,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
dt.setName("OtherIntStruct"); dt.setName("OtherIntStruct");
Structure s = (Structure) dt; Structure s = (Structure) dt;
s.add(new ByteDataType()); s.add(new ByteDataType());
s.add(new WordDataType());; s.add(new WordDataType());
} }
catch (DuplicateNameException e) { catch (DuplicateNameException e) {
Assert.fail("Got Duplicate name exception!"); Assert.fail("Got Duplicate name exception!");
@ -1018,10 +1019,9 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
Structure foo = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo"); Structure foo = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo");
Structure bar = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Bar"); Structure bar = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Bar");
Structure s1 = (Structure) dtm.getDataType(new CategoryPath("/Category1/Category2"), Structure s1 = (Structure) dtm.getDataType(new CategoryPath("/Category1/Category2"),
"Structure_1"); "Structure_1");
// create a TypeDef on Bar // create a TypeDef on Bar
TypeDef td = TypeDef td = new TypedefDataType(new CategoryPath("/MISC"), "MyBar_Typedef", bar);
new TypedefDataType(new CategoryPath("/MISC"), "MyBar_Typedef", bar);
// create a Pointer to typedef on Bar // create a Pointer to typedef on Bar
Pointer p = PointerDataType.getPointer(foo, 4);// Foo * Pointer p = PointerDataType.getPointer(foo, 4);// Foo *
p = PointerDataType.getPointer(td, 4);// MyBar_Typedef * p = PointerDataType.getPointer(td, 4);// MyBar_Typedef *
@ -1039,7 +1039,14 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
s1.add(bar); s1.add(bar);
} }
}); });
executeMerge(DataTypeMergeManager.OPTION_MY);// choose my Foo
executeMerge();
chooseOption(DataTypeMergeManager.OPTION_MY);
dismissUnresolvedDataTypesPopup();
waitForCompletion();
// Bar should not have been added back in // Bar should not have been added back in
DataTypeManager dtm = resultProgram.getDataTypeManager(); DataTypeManager dtm = resultProgram.getDataTypeManager();
@ -1047,32 +1054,50 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
assertNull(bar); assertNull(bar);
Structure s1 = Structure s1 =
(Structure) dtm.getDataType(new CategoryPath("/Category1/Category2"), "Structure_1"); (Structure) dtm.getDataType(new CategoryPath("/Category1/Category2"), "Structure_1");
DataTypeComponent[] dtcs = s1.getDefinedComponents(); assertNotNull(s1);
assertEquals(4, dtcs.length); //@formatter:off
assertEquals(20, s1.getLength()); assertEquals("/Category1/Category2/Structure_1\n" +
"pack(disabled)\n" +
dtcs = s1.getComponents(); "Structure Structure_1 {\n" +
for (int i = 6; i < 10; i++) { " 0 byte 1 \"\"\n" +
assertEquals(DataType.DEFAULT, dtcs[i].getDataType()); " 1 word 2 \"\"\n" +
} " 3 Foo 10 \"\"\n" +
" 13 byte 1 \"\"\n" +
" 14 -BAD- 6 \"Failed to apply 'Bar'\"\n" +
"}\n" +
"Length: 20 Alignment: 1\n", s1.toString());
//@formatter:on
TypeDef td = (TypeDef) dtm.getDataType(new CategoryPath("/MISC"), "MyBar_Typedef"); TypeDef td = (TypeDef) dtm.getDataType(new CategoryPath("/MISC"), "MyBar_Typedef");
assertNull(td); assertNull(td);
Structure foo = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo"); Structure foo = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo");
assertNotNull(foo);
// Foo should not have MyBar_Typedef * * * * * * * * // Foo should not have MyBar_Typedef * * * * * * * *
dtcs = foo.getDefinedComponents(); //@formatter:off
assertEquals(3, dtcs.length); assertEquals("/MISC/Foo\n" +
assertEquals(14, foo.getLength()); "pack(disabled)\n" +
dtcs = foo.getComponents(); "Structure Foo {\n" +
for (int i = 10; i < 13; i++) { " 0 byte 1 \"\"\n" +
assertEquals(DataType.DEFAULT, dtcs[i].getDataType()); " 1 byte 1 \"\"\n" +
} " 2 word 2 \"\"\n" +
" 4 -BAD- 6 \"Failed to apply 'Bar'\"\n" +
" 10 -BAD- 4 \"Failed to apply 'MyBar_Typedef * * * * * * * *'\"\n" +
"}\n" +
"Length: 14 Alignment: 1\n", foo.toString());
//@formatter:on
} }
@Test @Test
public void testAddedFuncSig() throws Exception { public void testAddedFuncSig() throws Exception {
ParameterDefinitionImpl p1 =
new ParameterDefinitionImpl("pw", WordDataType.dataType, "Comment1");
ParameterDefinitionImpl p2 =
new ParameterDefinitionImpl("pwp", new PointerDataType(WordDataType.dataType), null);
ParameterDefinitionImpl p3 =
new ParameterDefinitionImpl("pwa", new ArrayDataType(WordDataType.dataType, 1), null);
mtf.initialize("notepad2", new ProgramModifierListener() { mtf.initialize("notepad2", new ProgramModifierListener() {
@Override @Override
@ -1081,6 +1106,10 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
Structure bar = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Bar"); Structure bar = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Bar");
// remove Bar from the data type manager // remove Bar from the data type manager
dtm.remove(bar, TaskMonitor.DUMMY); dtm.remove(bar, TaskMonitor.DUMMY);
DataType word = dtm.getDataType(new CategoryPath("/"), "word");
// remove Bar and word from the data type manager
dtm.remove(bar, TaskMonitor.DUMMY);
dtm.remove(word, TaskMonitor.DUMMY);
} }
@Override @Override
@ -1101,6 +1130,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
new FunctionDefinitionDataType(func, false); new FunctionDefinitionDataType(func, false);
functionDef.setReturnType(bar); functionDef.setReturnType(bar);
functionDef.setCategoryPath(new CategoryPath("/MISC")); functionDef.setCategoryPath(new CategoryPath("/MISC"));
functionDef.setArguments(p1, p2, p3);
dtm.addDataType(functionDef, DataTypeConflictHandler.DEFAULT_HANDLER); dtm.addDataType(functionDef, DataTypeConflictHandler.DEFAULT_HANDLER);
} }
catch (Exception e) { catch (Exception e) {
@ -1109,13 +1139,29 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
} }
} }
}); });
executeMerge(-1); executeMerge();
dismissUnresolvedDataTypesPopup();
waitForCompletion();
DataTypeManager dtm = resultProgram.getDataTypeManager(); DataTypeManager dtm = resultProgram.getDataTypeManager();
assertNull(dtm.getDataType(new CategoryPath("/MISC"), "Bar")); assertNull(dtm.getDataType(new CategoryPath("/MISC"), "Bar"));
FunctionDefinition fd = FunctionDefinition fd =
(FunctionDefinition) dtm.getDataType(new CategoryPath("/MISC"), "entry"); (FunctionDefinition) dtm.getDataType(new CategoryPath("/MISC"), "entry");
assertNotNull(fd); assertNotNull(fd);
assertEquals(DataType.DEFAULT, fd.getReturnType()); assertEquals(DataType.DEFAULT, fd.getReturnType());
ParameterDefinition[] arguments = fd.getArguments();
assertEquals(3, arguments.length);
assertSameArgument(p1, arguments[0]);
assertSameArgument(p2, arguments[1]);
assertSameArgument(p3, arguments[2]);
}
private void assertSameArgument(ParameterDefinition p1, ParameterDefinition p2) {
assertTrue(p1.getDataType().isEquivalent(p2.getDataType()));
assertEquals(p1.getName(), p2.getName());
assertEquals(p1.getComment(), p2.getComment());
} }
@Test @Test
@ -1190,7 +1236,14 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
vars[1].setDataType(p); vars[1].setDataType(p);
} }
}); });
executeMerge(DataTypeMergeManager.OPTION_MY); executeMerge();
chooseOption(DataTypeMergeManager.OPTION_MY);
dismissUnresolvedDataTypesPopup();
waitForCompletion();
DataTypeManager dtm = resultProgram.getDataTypeManager(); DataTypeManager dtm = resultProgram.getDataTypeManager();
FunctionDefinition fd = FunctionDefinition fd =
(FunctionDefinition) dtm.getDataType(new CategoryPath("/MISC"), "MyFunctionDef"); (FunctionDefinition) dtm.getDataType(new CategoryPath("/MISC"), "MyFunctionDef");
@ -1201,8 +1254,10 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
assertEquals(dll, fd.getReturnType()); assertEquals(dll, fd.getReturnType());
ParameterDefinition[] vars = fd.getArguments(); ParameterDefinition[] vars = fd.getArguments();
assertEquals(DataType.DEFAULT, vars[0].getDataType()); assertEquals(DataType.DEFAULT, vars[0].getDataType());
assertEquals("this is a comment", vars[0].getComment()); assertEquals("Failed to apply 'Foo'; this is a comment", vars[0].getComment());
assertEquals(DataType.DEFAULT, vars[1].getDataType()); assertEquals(DataType.DEFAULT, vars[1].getDataType());
assertEquals("Failed to apply 'Foo *'", vars[1].getComment());
} }
@Test @Test
@ -1234,7 +1289,15 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
vars[1].setDataType(p); vars[1].setDataType(p);
} }
}); });
executeMerge(DataTypeMergeManager.OPTION_MY);
executeMerge();
chooseOption(DataTypeMergeManager.OPTION_MY);
dismissUnresolvedDataTypesPopup();
waitForCompletion();
DataTypeManager dtm = resultProgram.getDataTypeManager(); DataTypeManager dtm = resultProgram.getDataTypeManager();
FunctionDefinition fd = FunctionDefinition fd =
(FunctionDefinition) dtm.getDataType(new CategoryPath("/MISC"), "MyFunctionDef"); (FunctionDefinition) dtm.getDataType(new CategoryPath("/MISC"), "MyFunctionDef");
@ -1245,8 +1308,9 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
assertEquals(dll, fd.getReturnType()); assertEquals(dll, fd.getReturnType());
ParameterDefinition[] vars = fd.getArguments(); ParameterDefinition[] vars = fd.getArguments();
assertEquals(DataType.DEFAULT, vars[0].getDataType()); assertEquals(DataType.DEFAULT, vars[0].getDataType());
assertEquals("this is a comment", vars[0].getComment()); assertEquals("Failed to apply 'Foo'; this is a comment", vars[0].getComment());
assertEquals(DataType.DEFAULT, vars[1].getDataType()); assertEquals(DataType.DEFAULT, vars[1].getDataType());
assertEquals("Failed to apply 'Foo *'", vars[1].getComment());
assertFalse(fd.hasVarArgs()); assertFalse(fd.hasVarArgs());
assertFalse(fd.hasNoReturn()); assertFalse(fd.hasNoReturn());
} }
@ -1311,7 +1375,7 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
FunctionDefinition fd = (FunctionDefinition) dtm FunctionDefinition fd = (FunctionDefinition) dtm
.getDataType(new CategoryPath("/MISC"), "MyFunctionDef"); .getDataType(new CategoryPath("/MISC"), "MyFunctionDef");
fd.setReturnType(VoidDataType.dataType); fd.setReturnType(VoidDataType.dataType);
} }
@ -1366,9 +1430,8 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
FunctionDefinition fd = FunctionDefinition fd =
new FunctionDefinitionDataType(new CategoryPath("/MISC"), "printf"); new FunctionDefinitionDataType(new CategoryPath("/MISC"), "printf");
fd.setReturnType(new WordDataType()); fd.setReturnType(new WordDataType());
fd.setArguments( fd.setArguments(new ParameterDefinition[] { new ParameterDefinitionImpl("format",
new ParameterDefinition[] { new ParameterDefinitionImpl("format", new Pointer32DataType(new StringDataType()), null) });
new Pointer32DataType(new StringDataType()), null) });
fd.setVarArgs(false); fd.setVarArgs(false);
dtm.addDataType(fd, DataTypeConflictHandler.DEFAULT_HANDLER); dtm.addDataType(fd, DataTypeConflictHandler.DEFAULT_HANDLER);
} }
@ -1379,9 +1442,8 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
FunctionDefinition fd = FunctionDefinition fd =
new FunctionDefinitionDataType(new CategoryPath("/MISC"), "printf"); new FunctionDefinitionDataType(new CategoryPath("/MISC"), "printf");
fd.setReturnType(new WordDataType()); fd.setReturnType(new WordDataType());
fd.setArguments( fd.setArguments(new ParameterDefinition[] { new ParameterDefinitionImpl("format",
new ParameterDefinition[] { new ParameterDefinitionImpl("format", new Pointer32DataType(new StringDataType()), null) });
new Pointer32DataType(new StringDataType()), null) });
fd.setVarArgs(true); fd.setVarArgs(true);
dtm.addDataType(fd, DataTypeConflictHandler.DEFAULT_HANDLER); dtm.addDataType(fd, DataTypeConflictHandler.DEFAULT_HANDLER);
} }
@ -1424,9 +1486,8 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
new FunctionDefinitionDataType(new CategoryPath("/MISC"), "exit"); new FunctionDefinitionDataType(new CategoryPath("/MISC"), "exit");
fd.setReturnType(VoidDataType.dataType); fd.setReturnType(VoidDataType.dataType);
fd.setNoReturn(false); fd.setNoReturn(false);
fd.setArguments( fd.setArguments(new ParameterDefinition[] {
new ParameterDefinition[] { new ParameterDefinitionImpl("rc", new ParameterDefinitionImpl("rc", IntegerDataType.dataType, null) });
IntegerDataType.dataType, null) });
dtm.addDataType(fd, DataTypeConflictHandler.DEFAULT_HANDLER); dtm.addDataType(fd, DataTypeConflictHandler.DEFAULT_HANDLER);
} }
@ -1437,9 +1498,8 @@ public class DataTypeMerge2Test extends AbstractDataTypeMergeTest {
new FunctionDefinitionDataType(new CategoryPath("/MISC"), "exit"); new FunctionDefinitionDataType(new CategoryPath("/MISC"), "exit");
fd.setReturnType(VoidDataType.dataType); fd.setReturnType(VoidDataType.dataType);
fd.setNoReturn(true); fd.setNoReturn(true);
fd.setArguments( fd.setArguments(new ParameterDefinition[] {
new ParameterDefinition[] { new ParameterDefinitionImpl("rc", new ParameterDefinitionImpl("rc", IntegerDataType.dataType, null) });
IntegerDataType.dataType, null) });
dtm.addDataType(fd, DataTypeConflictHandler.DEFAULT_HANDLER); dtm.addDataType(fd, DataTypeConflictHandler.DEFAULT_HANDLER);
} }
}); });

View file

@ -70,22 +70,39 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
Category c = dtm.getCategory(new CategoryPath("/Category1/Category2")); Category c = dtm.getCategory(new CategoryPath("/Category1/Category2"));
Union union = (Union) c.getDataType("CoolUnion"); Union union = (Union) c.getDataType("CoolUnion");
assertNotNull(union);
//@formatter:off
assertEquals("/Category1/Category2/CoolUnion\n" +
"pack(disabled)\n" +
"Union CoolUnion {\n" +
" 0 qword 8 \"\"\n" +
" 0 word 2 \"\"\n" +
" 0 undefined * * * * * 4 \"\"\n" +
" 0 -BAD- 96 \"Type 'DLL_Table' was deleted\"\n" +
" 0 -BAD- 4 \"Type 'DLL_Table *' was deleted\"\n" +
"}\n" +
"Length: 96 Alignment: 1\n", union.toString());
//@formatter:on;
// DLL_Table should have a Word data type as the last component // DLL_Table should have a Word data type as the last component
Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table"); Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table");
DataTypeComponent dtc = s.getComponent(s.getNumComponents() - 1); assertNotNull(s);
assertTrue(dtc.getDataType().isEquivalent(new WordDataType())); //@formatter:off
assertEquals("/DLL_Table\n" +
// CoolUnion should not have DLL_Table components "pack(disabled)\n" +
DataTypeComponent[] dtcs = union.getComponents(); "Structure DLL_Table {\n" +
assertEquals(3, dtcs.length); " 0 string 13 COMDLG32 \"\"\n" +
DataType dt = dtcs[2].getDataType(); " 13 string 12 SHELL32 \"\"\n" +
assertTrue(dt instanceof Pointer); " 25 string 11 MSVCRT \"\"\n" +
" 36 string 13 ADVAPI32 \"\"\n" +
// DLL_Table should have Word added to it " 49 string 13 KERNEL32 \"\"\n" +
dtcs = s.getDefinedComponents(); " 62 string 10 GDI32 \"\"\n" +
assertEquals(9, dtcs.length); " 72 string 11 USER32 \"\"\n" +
assertTrue(dtcs[8].getDataType().isEquivalent(new WordDataType())); " 83 string 13 WINSPOOL32 \"\"\n" +
" 96 word 2 \"\"\n" +
"}\n" +
"Length: 98 Alignment: 1\n", s.toString());
//@formatter:on;
} }
@Test @Test
@ -97,7 +114,7 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
DataTypeManager dtm = program.getDataTypeManager(); DataTypeManager dtm = program.getDataTypeManager();
Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table"); Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table");
dtm.remove(s, TaskMonitor.DUMMY); dtm.remove(s, TaskMonitor.DUMMY);
// 2 components should get removed from CoolUnion // 2 components should be bad in CoolUnion
} }
@Override @Override
@ -127,23 +144,33 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
// MY CoolUnion // MY CoolUnion
chooseOption(DataTypeMergeManager.OPTION_MY); chooseOption(DataTypeMergeManager.OPTION_MY);
dismissUnresolvedDataTypesPopup();
waitForCompletion(); waitForCompletion();
DataTypeManager dtm = resultProgram.getDataTypeManager(); DataTypeManager dtm = resultProgram.getDataTypeManager();
Category c = dtm.getCategory(new CategoryPath("/Category1/Category2")); Category c = dtm.getCategory(new CategoryPath("/Category1/Category2"));
Union union = (Union) c.getDataType("CoolUnion"); Union union = (Union) c.getDataType("CoolUnion");
assertNotNull(union);
// DLL_Table should not exist // DLL_Table should not exist
assertNull(dtm.getDataType(CategoryPath.ROOT, "DLL_Table")); assertNull(dtm.getDataType(CategoryPath.ROOT, "DLL_Table"));
// CoolUnion should not have DLL_Table components but should have Float // CoolUnion should not have DLL_Table components but should have Float
DataTypeComponent[] dtcs = union.getComponents(); //@formatter:off
assertEquals(4, dtcs.length); assertEquals("/Category1/Category2/CoolUnion\n" +
DataType dt = dtcs[3].getDataType(); "pack(disabled)\n" +
assertTrue(dt.isEquivalent(new FloatDataType())); "Union CoolUnion {\n" +
assertEquals("my comments", dtcs[3].getComment()); " 0 qword 8 \"\"\n" +
assertEquals("Float_Field", dtcs[3].getFieldName()); " 0 word 2 \"\"\n" +
" 0 undefined * * * * * 4 \"\"\n" +
" 0 -BAD- 98 \"Failed to apply 'DLL_Table'\"\n" +
" 0 -BAD- 4 \"Failed to apply 'DLL_Table *'\"\n" +
" 0 float 4 Float_Field \"my comments\"\n" +
"}\n" +
"Length: 98 Alignment: 1\n", union.toString());
//@formatter:on
} }
@Test @Test
@ -231,7 +258,7 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
executeMerge(); executeMerge();
close(waitForWindow("Structure Update Failed")); // expected dependency error on Foo pressButtonByName(waitForWindow("Structure Update Failed"), "OK"); // expected dependency error on Foo
waitForCompletion(); waitForCompletion();
@ -257,7 +284,8 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
// original CoolUnion becomes CoolUnion.conflict. // original CoolUnion becomes CoolUnion.conflict.
assertEquals("float", fooComps[5].getDataType().getDisplayName()); assertEquals("float", fooComps[5].getDataType().getDisplayName());
assertTrue(fooComps[4].getDataType() instanceof BadDataType); assertTrue(fooComps[4].getDataType() instanceof BadDataType);
assertTrue(fooComps[4].getComment().startsWith("Couldn't add CoolUnion here.")); assertEquals("Failed to apply 'CoolUnion', Data type CoolUnion has Foo within it.",
fooComps[4].getComment());
} }
@Test @Test
@ -295,7 +323,7 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
chooseOption(DataTypeMergeManager.OPTION_MY);// MY Foo chooseOption(DataTypeMergeManager.OPTION_MY);// MY Foo
close(waitForWindow("Structure Update Failed")); // expected dependency error on Foo pressButtonByName(waitForWindow("Structure Update Failed"), "OK"); // expected dependency error on Foo
waitForCompletion(); waitForCompletion();
@ -305,23 +333,40 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
Union coolUnion = Union coolUnion =
(Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion"); (Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion");
DataTypeComponent[] coolUnionComps = coolUnion.getComponents(); assertNotNull(coolUnion);
assertEquals(6, coolUnionComps.length); //@formatter:off
assertEquals("/Category1/Category2/CoolUnion\n" +
Structure foo = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo"); "pack(disabled)\n" +
DataTypeComponent[] fooComps = foo.getComponents(); "Union CoolUnion {\n" +
assertEquals(6, fooComps.length); " 0 qword 8 \"\"\n" +
" 0 word 2 \"\"\n" +
" 0 undefined * * * * * 4 \"\"\n" +
" 0 DLL_Table 96 \"\"\n" +
" 0 DLL_Table *32 4 \"\"\n" +
" 0 Foo 110 \"\"\n" +
"}\n" +
"Length: 110 Alignment: 1\n", coolUnion.toString());
//@formatter:on
// Foo should not contain CoolUnion because CoolUnion already // Foo should not contain CoolUnion because CoolUnion already
// contains Foo (from Latest) // contains Foo (from Latest)
assertEquals("Foo", coolUnionComps[5].getDataType().getDisplayName());
// Foo.conflict should contain CoolUnion.conflict because CoolUnion already Structure foo = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo");
// contains Foo (from Latest), so Foo (From My) becomes Foo.conflict and its assertNotNull(foo);
// original CoolUnion becomes CoolUnion.conflict. //@formatter:off
assertEquals("float", fooComps[5].getDataType().getDisplayName()); assertEquals("/MISC/Foo\n" +
assertTrue(fooComps[4].getDataType() instanceof BadDataType); "pack(disabled)\n" +
assertTrue(fooComps[4].getComment().startsWith("Couldn't add CoolUnion here.")); "Structure Foo {\n" +
" 0 byte 1 \"\"\n" +
" 1 byte 1 \"\"\n" +
" 2 word 2 \"\"\n" +
" 4 Bar 6 \"\"\n" +
" 10 -BAD- 96 \"Failed to apply 'CoolUnion', Data type CoolUnion has Foo within it.\"\n" +
" 106 float 4 \"\"\n" +
"}\n" +
"Length: 110 Alignment: 1\n", foo.toString());
//@formatter:on
} }
@Test @Test
@ -409,7 +454,7 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
chooseOption(DataTypeMergeManager.OPTION_MY);// My Bar chooseOption(DataTypeMergeManager.OPTION_MY);// My Bar
close(waitForWindow("Structure Update Failed")); // expected dependency error on Bar pressButtonByName(waitForWindow("Structure Update Failed"), "OK"); // expected dependency error on Bar
waitForCompletion(); waitForCompletion();
@ -419,21 +464,33 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
Union coolUnion = Union coolUnion =
(Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion"); (Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion");
Structure bar = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Bar");
assertNotNull(coolUnion); assertNotNull(coolUnion);
//@formatter:off
assertEquals("/Category1/Category2/CoolUnion\n" +
"pack(disabled)\n" +
"Union CoolUnion {\n" +
" 0 qword 8 \"\"\n" +
" 0 word 2 \"\"\n" +
" 0 undefined * * * * * 4 \"\"\n" +
" 0 DLL_Table 96 \"\"\n" +
" 0 DLL_Table *32 4 \"\"\n" +
" 0 Bar 102 My_field_name \"My comments\"\n" +
"}\n" +
"Length: 102 Alignment: 1\n", coolUnion.toString());
//@formatter:on
Structure bar = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Bar");
assertNotNull(bar); assertNotNull(bar);
//@formatter:off
DataTypeComponent[] coolUnionComps = coolUnion.getComponents(); assertEquals("/MISC/Bar\n" +
assertEquals(6, coolUnionComps.length); "pack(disabled)\n" +
DataTypeComponent[] barComps = bar.getDefinedComponents(); "Structure Bar {\n" +
assertEquals(3, barComps.length); " 0 word 2 \"\"\n" +
" 2 Structure_1 *32 4 \"\"\n" +
assertEquals(bar, coolUnionComps[5].getDataType()); " 6 -BAD- 96 \"Failed to apply 'CoolUnion', Data type CoolUnion has Bar within it.\"\n" +
assertEquals("My_field_name", coolUnionComps[5].getFieldName()); "}\n" +
assertEquals("My comments", coolUnionComps[5].getComment()); "Length: 102 Alignment: 1\n", bar.toString());
//@formatter:on
assertTrue(barComps[2].getDataType() instanceof BadDataType);
assertTrue(barComps[2].getComment().startsWith("Couldn't add CoolUnion here."));
} }
@Test @Test
@ -587,18 +644,25 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
chooseOption(DataTypeMergeManager.OPTION_LATEST);// delele Structure_1 (choose Structure_1 from MY) chooseOption(DataTypeMergeManager.OPTION_LATEST);// delele Structure_1 (choose Structure_1 from MY)
dismissUnresolvedDataTypesPopup();
waitForCompletion(); waitForCompletion();
DataTypeManager dtm = resultProgram.getDataTypeManager(); DataTypeManager dtm = resultProgram.getDataTypeManager();
// Bar should contain undefined to replace Structure_1 // Bar should contain undefined to replace Structure_1
Structure bar = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Bar"); Structure bar = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Bar");
assertEquals(7, bar.getLength()); assertNotNull(bar);
DataTypeComponent[] dtcs = bar.getComponents(); //@formatter:off
assertEquals(6, dtcs.length); assertEquals("/MISC/Bar\n" +
for (int i = 1; i < 5; i++) { "pack(disabled)\n" +
assertEquals(DataType.DEFAULT, dtcs[i].getDataType()); "Structure Bar {\n" +
} " 0 word 2 \"\"\n" +
" 2 -BAD- 4 \"Failed to apply 'Structure_1 *'\"\n" +
" 6 byte 1 \"\"\n" +
"}\n" +
"Length: 7 Alignment: 1\n", bar.toString());
//@formatter:on;
// Structure_1 should have been deleted // Structure_1 should have been deleted
Structure s1 = Structure s1 =
@ -606,9 +670,20 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
assertNull(s1); assertNull(s1);
Structure foo = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo"); Structure foo = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo");
dtcs = foo.getDefinedComponents(); assertNotNull(foo);
assertEquals(5, dtcs.length); //@formatter:off
assertEquals(bar, dtcs[3].getDataType()); assertEquals("/MISC/Foo\n" +
"pack(disabled)\n" +
"Structure Foo {\n" +
" 0 byte 1 \"\"\n" +
" 1 byte 1 \"\"\n" +
" 2 word 2 \"\"\n" +
" 4 Bar 7 \"\"\n" +
" 11 float 4 \"\"\n" +
"}\n" +
"Length: 15 Alignment: 1\n", foo.toString());
//@formatter:on;
checkConflictCount(0); checkConflictCount(0);
} }
@ -644,14 +719,14 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
Structure fs = Structure fs =
(Structure) dtm.getDataType(new CategoryPath("/Category1/Category2/Category5"), (Structure) dtm.getDataType(new CategoryPath("/Category1/Category2/Category5"),
"FloatStruct"); "FloatStruct");
Structure s = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "ArrayStruct"); Structure a = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "ArrayStruct");
Structure ms = (Structure) dtm.getDataType(new CategoryPath("/Category1/Category2"), Structure ms = (Structure) dtm.getDataType(new CategoryPath("/Category1/Category2"),
"MyStruct"); "MyStruct");
s.add(new FloatDataType()); a.add(new FloatDataType());
Structure mys1 = new StructureDataType( Structure mys1 = new StructureDataType(
new CategoryPath("/Category1/Category2/Category5"), "my_s1", 0); new CategoryPath("/Category1/Category2/Category5"), "my_s1", 0);
mys1.add(s); mys1.add(a);
mys1 = (Structure) dtm.addDataType(mys1, DataTypeConflictHandler.DEFAULT_HANDLER); mys1 = (Structure) dtm.addDataType(mys1, DataTypeConflictHandler.DEFAULT_HANDLER);
// edit FloatStruct // edit FloatStruct
@ -673,12 +748,15 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
// conflict on FloatStruct (2) // conflict on FloatStruct (2)
chooseOption(DataTypeMergeManager.OPTION_LATEST);// delete FloatStruct chooseOption(DataTypeMergeManager.OPTION_LATEST);// delete FloatStruct
dismissUnresolvedDataTypesPopup();
waitForCompletion();
DataTypeManager dtm = resultProgram.getDataTypeManager(); DataTypeManager dtm = resultProgram.getDataTypeManager();
assertNull( assertNull(
dtm.getDataType(new CategoryPath("/Category1/Category2/Category5"), "FloatStruct")); dtm.getDataType(new CategoryPath("/Category1/Category2/Category5"), "FloatStruct"));
waitForCompletion();
Structure fs = (Structure) dtm Structure fs = (Structure) dtm
.getDataType(new CategoryPath("/Category1/Category2/Category5"), "FloatStruct"); .getDataType(new CategoryPath("/Category1/Category2/Category5"), "FloatStruct");
assertNull(fs); assertNull(fs);
@ -686,16 +764,33 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
// MyStruct should have a FloatDataType and a Word // MyStruct should have a FloatDataType and a Word
Structure ms = Structure ms =
(Structure) dtm.getDataType(new CategoryPath("/Category1/Category2"), "MyStruct"); (Structure) dtm.getDataType(new CategoryPath("/Category1/Category2"), "MyStruct");
DataTypeComponent[] dtcs = ms.getDefinedComponents(); assertNotNull(ms);
assertEquals(4, dtcs.length); //@formatter:off
assertEquals("/Category1/Category2/MyStruct\n" +
assertTrue(dtcs[2].getDataType().isEquivalent(new FloatDataType())); "pack(disabled)\n" +
assertTrue(dtcs[3].getDataType().isEquivalent(new WordDataType())); "Structure MyStruct {\n" +
" 0 -BAD- 120 \"Failed to apply 'FloatStruct[10]'\"\n" +
" 120 IntStruct[3] 45 \"\"\n" +
" 165 CharStruct * * * 4 \"\"\n" +
" 169 float 4 \"\"\n" +
" 173 word 2 \"\"\n" +
"}\n" +
"Length: 175 Alignment: 1\n", ms.toString());
//@formatter:on;
// ArrayStruct should have 3 components // ArrayStruct should have 3 components
Structure a = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "ArrayStruct"); Structure a = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "ArrayStruct");
dtcs = a.getDefinedComponents(); assertNotNull(a);
assertEquals(3, dtcs.length); //@formatter:off
assertEquals("/MISC/ArrayStruct\n" +
"pack(disabled)\n" +
"Structure ArrayStruct {\n" +
" 0 IntStruct * *[10] 40 \"\"\n" +
" 40 IntStruct[3] 45 \"\"\n" +
" 85 undefined * * * * * 4 \"\"\n" +
"}\n" +
"Length: 89 Alignment: 1\n", a.toString());
//@formatter:on;
} }
@Test @Test
@ -728,6 +823,8 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
try { try {
s1.insertBitFieldAt(3, 2, 6, td, 2, "bf1", "my bf1"); s1.insertBitFieldAt(3, 2, 6, td, 2, "bf1", "my bf1");
s1.insertBitFieldAt(3, 2, 4, td, 2, "bf2", "my bf2"); s1.insertBitFieldAt(3, 2, 4, td, 2, "bf2", "my bf2");
// foo grows but does alter size of existing component in s1
foo.add(new FloatDataType()); foo.add(new FloatDataType());
} }
catch (Exception e) { catch (Exception e) {
@ -739,45 +836,46 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
// bitfield silently transitions to int since typedef BF was removed // bitfield silently transitions to int since typedef BF was removed
executeMerge(true); executeMerge();
dismissUnresolvedDataTypesPopup();
waitForCompletion();
DataTypeManager dtm = resultProgram.getDataTypeManager(); DataTypeManager dtm = resultProgram.getDataTypeManager();
Structure s1 = Structure s1 =
(Structure) dtm.getDataType(new CategoryPath("/Category1/Category2"), "Structure_1"); (Structure) dtm.getDataType(new CategoryPath("/Category1/Category2"), "Structure_1");
assertNotNull(s1); assertNotNull(s1);
DataTypeComponent[] dtcs = s1.getComponents(); //@formatter:off
assertEquals(7, dtcs.length); assertEquals("/Category1/Category2/Structure_1\n" +
"pack(disabled)\n" +
assertEquals(4, dtcs[3].getOffset()); // base on original 2-byte length 1st byte remains undefined "Structure Structure_1 {\n" +
assertEquals("bf1", dtcs[3].getFieldName()); " 0 byte 1 \"\"\n" +
assertEquals("my bf1", dtcs[3].getComment()); " 1 word 2 \"\"\n" +
" 4 int:2(6) 1 bf1 \"Failed to apply 'BF'; my bf1\"\n" +
DataType dt = dtcs[3].getDataType(); " 4 int:2(4) 1 bf2 \"Failed to apply 'BF'; my bf2\"\n" +
assertTrue(dt instanceof BitFieldDataType); " 5 Foo 10 \"\"\n" +
BitFieldDataType bfDt = (BitFieldDataType) dt; " 15 byte 1 \"\"\n" +
assertTrue(bfDt.getBaseDataType() instanceof IntegerDataType); "}\n" +
assertEquals(2, bfDt.getDeclaredBitSize()); "Length: 16 Alignment: 1\n", s1.toString());
assertEquals(6, bfDt.getBitOffset()); //@formatter:on
assertEquals(4, dtcs[4].getOffset()); // base on original 2-byte length 1st byte remains undefined
assertEquals("bf2", dtcs[4].getFieldName());
assertEquals("my bf2", dtcs[4].getComment());
dt = dtcs[4].getDataType();
assertTrue(dt instanceof BitFieldDataType);
bfDt = (BitFieldDataType) dt;
assertTrue(bfDt.getBaseDataType() instanceof IntegerDataType);
assertEquals(2, bfDt.getDeclaredBitSize());
assertEquals(4, bfDt.getBitOffset());
Structure foo = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo"); Structure foo = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo");
// Structure_1 should contain MY Foo assertNotNull(foo);
assertEquals(foo, dtcs[5].getDataType()); //@formatter:off
assertEquals("/MISC/Foo\n" +
"pack(disabled)\n" +
"Structure Foo {\n" +
" 0 byte 1 \"\"\n" +
" 1 byte 1 \"\"\n" +
" 2 word 2 \"\"\n" +
" 4 Bar 6 \"\"\n" +
" 10 float 4 \"\"\n" +
"}\n" +
"Length: 14 Alignment: 1\n", foo.toString());
//@formatter:on
dtcs = foo.getComponents();
assertEquals(5, dtcs.length);
assertTrue(dtcs[4].getDataType().isEquivalent(new FloatDataType()));
checkConflictCount(0); checkConflictCount(0);
} }
@ -1215,6 +1313,8 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
chooseOption(DataTypeMergeManager.OPTION_MY);// MY CoolUnion chooseOption(DataTypeMergeManager.OPTION_MY);// MY CoolUnion
dismissUnresolvedDataTypesPopup();
waitForCompletion(); waitForCompletion();
DataTypeManager dtm = resultProgram.getDataTypeManager(); DataTypeManager dtm = resultProgram.getDataTypeManager();
@ -1228,16 +1328,31 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
Union union = Union union =
(Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), "AnotherUnion"); (Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), "AnotherUnion");
assertNotNull(union); assertNotNull(union);
//@formatter:off
DataTypeComponent[] dtcs = union.getComponents(); assertEquals("/Category1/Category2/AnotherUnion\n" +
assertEquals(1, dtcs.length); "pack(disabled)\n" +
assertTrue(dtcs[0].getDataType().isEquivalent(new ByteDataType())); "Union AnotherUnion {\n" +
" 0 -BAD- 98 \"Failed to apply 'DLL_Table'\"\n" +
" 0 byte 1 \"\"\n" +
"}\n" +
"Length: 98 Alignment: 1\n", union.toString());
//@formatter:on;
union = (Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion"); union = (Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion");
dtcs = union.getComponents(); assertNotNull(union);
assertEquals(4, dtcs.length); //@formatter:off
assertEquals("my comments", dtcs[3].getComment()); assertEquals("/Category1/Category2/CoolUnion\n" +
assertEquals("Float_Field", dtcs[3].getFieldName()); "pack(disabled)\n" +
"Union CoolUnion {\n" +
" 0 qword 8 \"\"\n" +
" 0 word 2 \"\"\n" +
" 0 undefined * * * * * 4 \"\"\n" +
" 0 -BAD- 98 \"Failed to apply 'DLL_Table'\"\n" +
" 0 -BAD- 4 \"Failed to apply 'DLL_Table *'\"\n" +
" 0 float 4 Float_Field \"my comments\"\n" +
"}\n" +
"Length: 98 Alignment: 1\n", union.toString());
//@formatter:on;
} }
@Test @Test
@ -1363,6 +1478,8 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
chooseOption(DataTypeMergeManager.OPTION_MY);// MY CoolUnion chooseOption(DataTypeMergeManager.OPTION_MY);// MY CoolUnion
dismissUnresolvedDataTypesPopup();
waitForCompletion(); waitForCompletion();
DataTypeManager dtm = resultProgram.getDataTypeManager(); DataTypeManager dtm = resultProgram.getDataTypeManager();
@ -1371,19 +1488,25 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
Union union = Union union =
(Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion"); (Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion");
assertNotNull(union); assertNotNull(union);
//@formatter:off
assertEquals("/Category1/Category2/CoolUnion\n" +
"pack(disabled)\n" +
"Union CoolUnion {\n" +
" 0 qword 8 \"\"\n" +
" 0 word 2 \"\"\n" +
" 0 undefined * * * * * 4 \"\"\n" +
" 0 -BAD- 98 \"Failed to apply 'DLL_Table'\"\n" +
" 0 -BAD- 4 \"Failed to apply 'DLL_Table *'\"\n" +
" 0 float 4 Float_Field \"my comments\"\n" +
" 0 MyEnum 1 \"\"\n" +
"}\n" +
"Length: 98 Alignment: 1\n", union.toString());
//@formatter:on;
// DLL_Table should be null // DLL_Table should be null
Structure dll = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table"); Structure dll = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table");
assertNull(dll); assertNull(dll);
DataTypeComponent[] dtcs = union.getComponents();
assertEquals(5, dtcs.length);
Enum enumm = (Enum) dtm.getDataType(new CategoryPath("/Category1"), "MyEnum");
assertNotNull(enumm);
assertEquals(enumm, dtcs[4].getDataType());
assertTrue(dtcs[3].getDataType().isEquivalent(new FloatDataType()));
} }
@Test @Test
@ -1515,24 +1638,49 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
DataTypeManager dtm = resultProgram.getDataTypeManager(); DataTypeManager dtm = resultProgram.getDataTypeManager();
Enum enumm = (Enum) dtm.getDataType(new CategoryPath("/Category1"), "MyEnum");
assertNotNull(enumm);
TypeDef td = (TypeDef) dtm.getDataType(new CategoryPath("/Category1"), "TD_MyEnum");
assertNotNull(td);
// CoolUnion should not be null // CoolUnion should not be null
Union union = Union union =
(Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion"); (Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion");
assertNotNull(union); assertNotNull(union);
//@formatter:off
assertEquals("/Category1/Category2/CoolUnion\n" +
"pack(disabled)\n" +
"Union CoolUnion {\n" +
" 0 qword 8 \"\"\n" +
" 0 word 2 \"\"\n" +
" 0 undefined * * * * * 4 \"\"\n" +
" 0 DLL_Table 96 \"\"\n" +
" 0 DLL_Table *32 4 \"\"\n" +
" 0 float 4 Float_Field \"my comments\"\n" +
" 0 TD_MyEnum 1 \"\"\n" +
"}\n" +
"Length: 96 Alignment: 1\n", union.toString());
//@formatter:on;
// DLL_Table should not be null // DLL_Table should not be null
Structure dll = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table"); Structure dll = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table");
assertNotNull(dll); assertNotNull(dll);
//@formatter:off
DataTypeComponent[] dtcs = union.getComponents(); assertEquals("/DLL_Table\n" +
assertEquals(7, dtcs.length); "pack(disabled)\n" +
"Structure DLL_Table {\n" +
Enum enumm = (Enum) dtm.getDataType(new CategoryPath("/Category1"), "MyEnum"); " 0 string 13 COMDLG32 \"\"\n" +
assertNotNull(enumm); " 13 string 12 SHELL32 \"\"\n" +
TypeDef td = (TypeDef) dtm.getDataType(new CategoryPath("/Category1"), "TD_MyEnum"); " 25 string 11 MSVCRT \"\"\n" +
assertNotNull(td); " 36 string 13 ADVAPI32 \"\"\n" +
assertEquals(td, dtcs[6].getDataType()); " 49 string 13 KERNEL32 \"\"\n" +
assertEquals(dll, dtcs[3].getDataType()); " 62 string 10 GDI32 \"\"\n" +
" 72 string 11 USER32 \"\"\n" +
" 83 string 13 WINSPOOL32 \"\"\n" +
"}\n" +
"Length: 96 Alignment: 1\n", dll.toString());
//@formatter:on;
checkConflictCount(0); checkConflictCount(0);
} }
@ -1778,6 +1926,8 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
chooseOption(DataTypeMergeManager.OPTION_MY);// MY bitfields w/ enum chooseOption(DataTypeMergeManager.OPTION_MY);// MY bitfields w/ enum
dismissUnresolvedDataTypesPopup();
waitForCompletion(); waitForCompletion();
DataTypeManager dtm = resultProgram.getDataTypeManager(); DataTypeManager dtm = resultProgram.getDataTypeManager();
@ -1790,8 +1940,8 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest {
"pack(disabled)\n" + "pack(disabled)\n" +
"Union CoolUnion {\n" + "Union CoolUnion {\n" +
" 0 qword 8 \"\"\n" + " 0 qword 8 \"\"\n" +
" 0 byte:4(4) 1 BF1 \"my bf1\"\n" + " 0 byte:4(4) 1 BF1 \"Failed to apply 'XYZ'; my bf1\"\n" +
" 0 byte:2(6) 1 BF2 \"my bf2\"\n" + " 0 byte:2(6) 1 BF2 \"Failed to apply 'XYZ'; my bf2\"\n" +
" 0 word 2 \"\"\n" + " 0 word 2 \"\"\n" +
" 0 undefined * * * * * 4 \"\"\n" + " 0 undefined * * * * * 4 \"\"\n" +
" 0 DLL_Table 96 \"\"\n" + " 0 DLL_Table 96 \"\"\n" +

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -19,6 +19,8 @@ import static org.junit.Assert.*;
import java.util.ArrayList; import java.util.ArrayList;
import javax.swing.JDialog;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
@ -380,17 +382,15 @@ public class DataTypeMerge4Test extends AbstractDataTypeMergeTest {
DataTypeManager dtm = resultProgram.getDataTypeManager(); DataTypeManager dtm = resultProgram.getDataTypeManager();
Structure s = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "ArrayStruct"); Structure s = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "ArrayStruct");
Structure intstruct = Structure intstruct = (Structure) dtm
(Structure) dtm.getDataType(new CategoryPath("/Category1/Category2/Category3"), .getDataType(new CategoryPath("/Category1/Category2/Category3"), "MyIntStruct");
"MyIntStruct");
DataTypeComponent[] idtcs = intstruct.getDefinedComponents(); DataTypeComponent[] idtcs = intstruct.getDefinedComponents();
assertEquals(7, idtcs.length); assertEquals(7, idtcs.length);
DataType dt = idtcs[6].getDataType(); DataType dt = idtcs[6].getDataType();
assertTrue(dt instanceof Pointer); assertTrue(dt instanceof Pointer);
Structure mystruct = Structure mystruct = (Structure) dtm
(Structure) dtm.getDataType(new CategoryPath("/Category1/Category2/Category3"), .getDataType(new CategoryPath("/Category1/Category2/Category3"), "my_struct");
"my_struct");
assertNotNull(mystruct); assertNotNull(mystruct);
assertEquals(mystruct, ((Pointer) dt).getDataType()); assertEquals(mystruct, ((Pointer) dt).getDataType());
@ -446,48 +446,56 @@ public class DataTypeMerge4Test extends AbstractDataTypeMergeTest {
} }
}); });
executeMerge(); executeMerge();
DataTypeManager dtm = resultProgram.getDataTypeManager();
Thread.sleep(250);
chooseOption(DataTypeMergeManager.OPTION_MY);// Choose my Foo chooseOption(DataTypeMergeManager.OPTION_MY);// Choose my Foo
waitForCompletion(); waitForCompletion();
DataTypeManager dtm = resultProgram.getDataTypeManager();
// Foo should exist // Foo should exist
Structure fs = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo"); Structure fs = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo");
assertNotNull(fs); assertNotNull(fs);
DataTypeComponent[] dtcs = fs.getDefinedComponents(); //@formatter:off
assertEquals(3, dtcs.length); assertEquals("/MISC/Foo\n" +
DataTypeComponent dtc = fs.getComponent(2); "pack(disabled)\n" +
DataType dt = dtc.getDataType(); "Structure Foo {\n" +
assertTrue(dt instanceof Pointer); " 0 qword 8 \"\"\n" +
" 8 Bar 6 \"\"\n" +
// Foo should have a pointer to Foo " 14 Foo *32 4 \"\"\n" +
assertEquals(fs, ((Pointer) dt).getDataType()); "}\n" +
"Length: 18 Alignment: 1\n", fs.toString());
//@formatter:on
// my_struct should have a Foo and Byte // my_struct should have a Foo and Byte
Structure ms = Structure ms = (Structure) dtm
(Structure) dtm.getDataType(new CategoryPath("/Category1/Category2/Category3"), .getDataType(new CategoryPath("/Category1/Category2/Category3"), "my_struct");
"my_struct");
assertNotNull(ms); assertNotNull(ms);
//@formatter:off
assertEquals(2, ms.getDefinedComponents().length); assertEquals("/Category1/Category2/Category3/my_struct\n" +
dtc = ms.getComponent(0); "pack(disabled)\n" +
assertEquals(fs, dtc.getDataType()); "Structure my_struct {\n" +
dtc = ms.getComponent(1); " 0 Foo 18 \"\"\n" +
assertTrue(new ByteDataType().isEquivalent(dtc.getDataType())); " 18 byte 1 \"\"\n" +
"}\n" +
"Length: 19 Alignment: 1\n", ms.toString());
//@formatter:on
// Structure1 should exist as modified by Latest. (My didn't change it.) // Structure1 should exist as modified by Latest. (My didn't change it.)
Structure s1 = Structure s1 =
(Structure) dtm.getDataType(new CategoryPath("/Category1/Category2"), "Structure_1"); (Structure) dtm.getDataType(new CategoryPath("/Category1/Category2"), "Structure_1");
assertNotNull(s1); assertNotNull(s1);
DataTypeComponent[] dtcs1 = s1.getDefinedComponents(); //@formatter:off
assertEquals(3, dtcs1.length); assertEquals("/Category1/Category2/Structure_1\n" +
DataType dt0 = dtcs1[0].getDataType(); "pack(disabled)\n" +
DataType dt1 = dtcs1[1].getDataType(); "Structure Structure_1 {\n" +
DataType dt2 = dtcs1[2].getDataType(); " 0 byte 1 \"\"\n" +
assertTrue(dt0 instanceof ByteDataType); " 1 word 2 \"\"\n" +
assertTrue(dt1 instanceof WordDataType); " 3 -BAD- 10 \"Type 'Foo' was deleted\"\n" +
assertTrue(dt2 instanceof ByteDataType); " 13 byte 1 \"\"\n" +
"}\n" +
"Length: 14 Alignment: 1\n", s1.toString());
//@formatter:on
// should be no .conflict data types // should be no .conflict data types
ArrayList<DataType> list = new ArrayList<DataType>(); ArrayList<DataType> list = new ArrayList<DataType>();
@ -527,56 +535,65 @@ public class DataTypeMerge4Test extends AbstractDataTypeMergeTest {
}); });
executeMerge(); executeMerge();
DataTypeManager dtm = resultProgram.getDataTypeManager();
chooseOption(DataTypeMergeManager.OPTION_LATEST);// Bar gets a Foo chooseOption(DataTypeMergeManager.OPTION_LATEST);// Bar gets a Foo
chooseOption(DataTypeMergeManager.OPTION_MY);// Foo keeps its Bar, which creates Foo.conflict. chooseOption(DataTypeMergeManager.OPTION_MY);// Foo keeps its Bar, which creates Foo.conflict.
close(waitForWindow("Structure Update Failed")); // expected dependency error on Bar (2 occurances of Bar use) pressButtonByName(waitForWindow("Structure Update Failed"), "OK"); // expected dependency error on Bar (2 occurances of Bar use)
waitForCompletion(); waitForCompletion();
DataTypeManager dtm = resultProgram.getDataTypeManager();
// should be two .conflict data types // should be two .conflict data types
checkConflictCount(0); checkConflictCount(0);
Structure foo = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo"); Structure foo = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo");
Structure bar = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Bar");
assertNotNull(foo); assertNotNull(foo);
//@formatter:off
assertEquals("/MISC/Foo\n" +
"pack(disabled)\n" +
"Structure Foo {\n" +
" 0 byte 1 \"\"\n" +
" 1 byte 1 \"\"\n" +
" 2 word 2 \"\"\n" +
" 4 -BAD- 6 \"Failed to apply 'Bar', Data type Bar has Foo within it.\"\n" +
" 10 qword 8 \"\"\n" +
" 18 -BAD- 6 \"Failed to apply 'Bar', Data type Bar has Foo within it.\"\n" +
" 24 Foo *32 4 \"\"\n" +
"}\n" +
"Length: 28 Alignment: 1\n", foo.toString());
//@formatter:on
Structure bar = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Bar");
assertNotNull(bar); assertNotNull(bar);
//@formatter:off
DataTypeComponent[] barComps = bar.getDefinedComponents(); assertEquals("/MISC/Bar\n" +
assertEquals(3, barComps.length); "pack(disabled)\n" +
"Structure Bar {\n" +
assertEquals(foo, barComps[2].getDataType()); " 0 word 2 \"\"\n" +
" 2 Structure_1 *32 4 \"\"\n" +
DataTypeComponent[] fooComps = foo.getComponents(); " 6 Foo 28 \"\"\n" +
assertEquals(7, fooComps.length); "}\n" +
assertEquals("byte", fooComps[0].getDataType().getDisplayName()); "Length: 34 Alignment: 1\n", bar.toString());
assertEquals("byte", fooComps[1].getDataType().getDisplayName()); //@formatter:on
assertEquals("word", fooComps[2].getDataType().getDisplayName());
assertTrue(fooComps[3].getDataType() instanceof BadDataType);
String comment3 = fooComps[3].getComment();
assertTrue(comment3.startsWith("Couldn't add Bar here."));
assertEquals("qword", fooComps[4].getDataType().getDisplayName());
assertTrue(fooComps[5].getDataType() instanceof BadDataType);
String comment5 = fooComps[5].getComment();
assertTrue(comment5.startsWith("Couldn't add Bar here."));
assertEquals("Foo *", fooComps[6].getDataType().getDisplayName());
DataTypeComponent[] dtcs = foo.getDefinedComponents();
// Update should fail for Foo
for (DataTypeComponent dtc : dtcs) {
if (dtc.getDataType() == bar) {
Assert.fail("Bar should not have been added to Foo!");
}
}
// Structure_1 should have a Foo component // Structure_1 should have a Foo component
Structure s1 = Structure s1 =
(Structure) dtm.getDataType(new CategoryPath("/Category1/Category2"), "Structure_1"); (Structure) dtm.getDataType(new CategoryPath("/Category1/Category2"), "Structure_1");
DataType dt = s1.getComponent(2).getDataType(); assertNotNull(s1);
assertEquals(foo, dt); //@formatter:off
assertEquals("/Category1/Category2/Structure_1\n" +
"pack(disabled)\n" +
"Structure Structure_1 {\n" +
" 0 byte 1 \"\"\n" +
" 1 word 2 \"\"\n" +
" 3 Foo 10 \"\"\n" +
" 13 byte 1 \"\"\n" +
"}\n" +
"Length: 14 Alignment: 1\n", s1.toString());
//@formatter:on
// FooTypedef should have Foo as its base type // FooTypedef should have Foo as its base type
TypeDef td = (TypeDef) dtm.getDataType(new CategoryPath("/MISC"), "FooTypedef"); TypeDef td = (TypeDef) dtm.getDataType(new CategoryPath("/MISC"), "FooTypedef");
@ -596,7 +613,7 @@ public class DataTypeMerge4Test extends AbstractDataTypeMergeTest {
Structure bs = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Bar"); Structure bs = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Bar");
Structure array = Structure array =
(Structure) dtm.getDataType(new CategoryPath("/MISC"), "ArrayStruct"); (Structure) dtm.getDataType(new CategoryPath("/MISC"), "ArrayStruct");
// delete Bar from Foo // delete Bar from Foo
fs.delete(3); fs.delete(3);
// add Foo to Bar // add Foo to Bar
@ -658,6 +675,8 @@ public class DataTypeMerge4Test extends AbstractDataTypeMergeTest {
chooseOption(DataTypeMergeManager.OPTION_MY); chooseOption(DataTypeMergeManager.OPTION_MY);
dismissUnresolvedDataTypesPopup();
waitForCompletion(); waitForCompletion();
// new data types from MY should go in as .conflicts // new data types from MY should go in as .conflicts
@ -716,7 +735,7 @@ public class DataTypeMerge4Test extends AbstractDataTypeMergeTest {
DataTypeManager dtm = program.getDataTypeManager(); DataTypeManager dtm = program.getDataTypeManager();
Structure fs = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo"); Structure fs = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo");
Structure bs = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Bar"); Structure bs = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Bar");
// Add s1, s2, s3 // Add s1, s2, s3
Structure s1 = new StructureDataType(new CategoryPath("/MISC"), "S1", 0); Structure s1 = new StructureDataType(new CategoryPath("/MISC"), "S1", 0);
s1.add(new ByteDataType()); s1.add(new ByteDataType());
@ -812,7 +831,7 @@ public class DataTypeMerge4Test extends AbstractDataTypeMergeTest {
DataTypeManager dtm = program.getDataTypeManager(); DataTypeManager dtm = program.getDataTypeManager();
Structure fs = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo"); Structure fs = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo");
Structure bs = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Bar"); Structure bs = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Bar");
// Add s1, s2, s3 // Add s1, s2, s3
Structure s1 = new StructureDataType(new CategoryPath("/MISC"), "S1", 0); Structure s1 = new StructureDataType(new CategoryPath("/MISC"), "S1", 0);
s1.add(new ByteDataType()); s1.add(new ByteDataType());
@ -846,6 +865,8 @@ public class DataTypeMerge4Test extends AbstractDataTypeMergeTest {
chooseOption(DataTypeMergeManager.OPTION_MY);// choose Foo from MY chooseOption(DataTypeMergeManager.OPTION_MY);// choose Foo from MY
dismissUnresolvedDataTypesPopup();
waitForCompletion(); waitForCompletion();
// new data types from MY should go in as .conflicts // new data types from MY should go in as .conflicts
@ -853,22 +874,66 @@ public class DataTypeMerge4Test extends AbstractDataTypeMergeTest {
Structure bs = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Bar"); Structure bs = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Bar");
assertNull(bs); assertNull(bs);
Structure fs = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo"); Structure fs = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo");
assertNotNull(fs);
//@formatter:off
assertEquals("/MISC/Foo\n" +
"pack(disabled)\n" +
"Structure Foo {\n" +
" 0 byte 1 \"\"\n" +
" 1 byte 1 \"\"\n" +
" 2 word 2 \"\"\n" +
" 4 -BAD- 6 \"Failed to apply 'Bar'\"\n" +
" 10 S1.conflict 5 \"\"\n" +
" 15 S2.conflict 12 \"\"\n" +
"}\n" +
"Length: 27 Alignment: 1\n", fs.toString());
//@formatter:on
// Foo should have undefined bytes where Bar was
DataTypeComponent[] dtcs = fs.getDefinedComponents();
assertEquals(5, dtcs.length);
Structure s1 = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "S1.conflict"); Structure s1 = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "S1.conflict");
assertEquals(s1, dtcs[3].getDataType()); assertNotNull(s1);
Structure s2 = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "S2.conflict"); //@formatter:off
assertEquals(s2, dtcs[4].getDataType()); assertEquals("/MISC/S1.conflict\n" +
"pack(disabled)\n" +
"Structure S1.conflict {\n" +
" 0 byte 1 \"\"\n" +
" 1 byte *32 4 \"\"\n" +
"}\n" +
"Length: 5 Alignment: 1\n", s1.toString());
//@formatter:on
Structure s2 = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "S2.conflict");
assertNotNull(s2);
//@formatter:off
assertEquals("/MISC/S2.conflict\n" +
"pack(disabled)\n" +
"Structure S2.conflict {\n" +
" 0 Foo *32 4 \"\"\n" +
" 4 qword 8 \"\"\n" +
"}\n" +
"Length: 12 Alignment: 1\n", s2.toString());
//@formatter:on
// Structure_1 should contain Foo from MY
Structure struct_1 = Structure struct_1 =
(Structure) dtm.getDataType(new CategoryPath("/Category1/Category2"), "Structure_1"); (Structure) dtm.getDataType(new CategoryPath("/Category1/Category2"), "Structure_1");
dtcs = struct_1.getDefinedComponents(); assertNotNull(struct_1);
//@formatter:off
assertEquals("/Category1/Category2/Structure_1\n" +
"pack(disabled)\n" +
"Structure Structure_1 {\n" +
" 0 byte 1 \"\"\n" +
" 1 word 2 \"\"\n" +
" 3 Foo 10 \"\"\n" +
" 13 byte 1 \"\"\n" +
"}\n" +
"Length: 14 Alignment: 1\n", struct_1.toString());
//@formatter:on
// Structure_1 should contain Foo from MY although its component will not reflect
// change in Foo size.
assertTrue(struct_1.getDefinedComponents()[2].getDataType() == fs);
assertEquals(fs, dtcs[2].getDataType());
} }
@Test @Test
@ -1124,7 +1189,7 @@ public class DataTypeMerge4Test extends AbstractDataTypeMergeTest {
DataTypeManager dtm = program.getDataTypeManager(); DataTypeManager dtm = program.getDataTypeManager();
Structure foo = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo"); Structure foo = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo");
Structure bar = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Bar"); Structure bar = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Bar");
// edit Bar to create conflict because Latest deleted it // edit Bar to create conflict because Latest deleted it
Pointer p = PointerDataType.getPointer(foo, 4);// Foo * Pointer p = PointerDataType.getPointer(foo, 4);// Foo *
p = PointerDataType.getPointer(p, 4);// Foo * * p = PointerDataType.getPointer(p, 4);// Foo * *
@ -1156,6 +1221,14 @@ public class DataTypeMerge4Test extends AbstractDataTypeMergeTest {
p = PointerDataType.getPointer(p, 4);// MyArray_Typedef * * * * * * * * p = PointerDataType.getPointer(p, 4);// MyArray_Typedef * * * * * * * *
// add pointer to Foo // add pointer to Foo
foo.add(p); foo.add(p);
foo.add(new ArrayDataType(p, 0, 0, dtm));
array = new ArrayDataType(bar, 0, 0, dtm);
foo.add(array);
foo.add(new PointerDataType(array, dtm));
} }
}); });
executeMerge(); executeMerge();
@ -1202,7 +1275,7 @@ public class DataTypeMerge4Test extends AbstractDataTypeMergeTest {
ArrayList<DataType> list = new ArrayList<DataType>(); ArrayList<DataType> list = new ArrayList<DataType>();
dtm.findDataTypes("MyArray_Typedef*", list, false, null); dtm.findDataTypes("MyArray_Typedef*", list, false, null);
assertEquals(9, list.size()); assertEquals(10, list.size());
assertNotNull(dtm.getDataType(new CategoryPath("/MISC"), "Bar[6][7][8][9][10][11]")); assertNotNull(dtm.getDataType(new CategoryPath("/MISC"), "Bar[6][7][8][9][10][11]"));
@ -1264,6 +1337,13 @@ public class DataTypeMerge4Test extends AbstractDataTypeMergeTest {
p = PointerDataType.getPointer(p, 4);// MyArray_Typedef * * * * * * * * p = PointerDataType.getPointer(p, 4);// MyArray_Typedef * * * * * * * *
// add pointer to Foo // add pointer to Foo
foo.add(p); foo.add(p);
foo.add(new ArrayDataType(p, 0, 0, dtm));
array = new ArrayDataType(bar, 0, 0, dtm);
foo.add(array);
foo.add(new PointerDataType(array, dtm));
} }
}); });
executeMerge(); executeMerge();
@ -1282,6 +1362,14 @@ public class DataTypeMerge4Test extends AbstractDataTypeMergeTest {
Structure bar = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Bar"); Structure bar = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Bar");
assertNotNull(bar); assertNotNull(bar);
assertEquals("/MISC/Foo\n" + "pack(disabled)\n" + "Structure Foo {\n" +
" 0 byte 1 \"\"\n" + " 1 byte 1 \"\"\n" +
" 2 word 2 \"\"\n" + " 4 Bar 6 \"\"\n" +
" 14 MyArray_Typedef *32 *32 *32 *32 *32 *32 *32 *32 4 \"\"\n" +
" 18 MyArray_Typedef *32 *32 *32 *32 *32 *32 *32 *32[0] 0 \"\"\n" +
" 18 Bar[0] 0 \"\"\n" + " 18 Bar[0] * 4 \"\"\n" + "}\n" +
"Length: 22 Alignment: 1\n" + "", foo.toString());
// Bar should NOT have Foo * * * * * * // Bar should NOT have Foo * * * * * *
DataTypeComponent[] dtcs = bar.getDefinedComponents(); DataTypeComponent[] dtcs = bar.getDefinedComponents();
assertEquals(2, dtcs.length); assertEquals(2, dtcs.length);
@ -1289,7 +1377,7 @@ public class DataTypeMerge4Test extends AbstractDataTypeMergeTest {
//Foo should have MyArray_Typedef * * * * * * * * //Foo should have MyArray_Typedef * * * * * * * *
dtcs = foo.getDefinedComponents(); dtcs = foo.getDefinedComponents();
assertEquals(5, dtcs.length); assertEquals(8, dtcs.length);
DataType dt = dtcs[4].getDataType(); DataType dt = dtcs[4].getDataType();
TypeDef td = (TypeDef) dtm.getDataType(new CategoryPath("/MISC"), "MyArray_Typedef"); TypeDef td = (TypeDef) dtm.getDataType(new CategoryPath("/MISC"), "MyArray_Typedef");
assertNotNull(td); assertNotNull(td);
@ -1352,6 +1440,7 @@ public class DataTypeMerge4Test extends AbstractDataTypeMergeTest {
p = PointerDataType.getPointer(p, 4);// MyArray_Typedef * * * * * * * * p = PointerDataType.getPointer(p, 4);// MyArray_Typedef * * * * * * * *
// add pointer to Bar // add pointer to Bar
bar.add(p); bar.add(p);
} }
}); });
executeMerge(); executeMerge();
@ -1384,6 +1473,103 @@ public class DataTypeMerge4Test extends AbstractDataTypeMergeTest {
checkConflictCount(0); checkConflictCount(0);
} }
@Test
public void testDeletedBaseTypeDef4() throws Exception {
mtf.initialize("notepad2", new ProgramModifierListener() {
@Override
public void modifyLatest(ProgramDB program) {
DataTypeManager dtm = program.getDataTypeManager();
Structure bar = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Bar");
// remove Bar from the data type manager
dtm.remove(bar, TaskMonitor.DUMMY);
}
@Override
public void modifyPrivate(ProgramDB program) {
DataTypeManager dtm = program.getDataTypeManager();
Structure foo = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo");
Structure bar = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Bar");
// edit Bar to create conflict because Latest deleted it
Pointer p = PointerDataType.getPointer(foo, 4);// Foo *
p = PointerDataType.getPointer(p, 4);// Foo * *
p = PointerDataType.getPointer(p, 4);// Foo * * *
p = PointerDataType.getPointer(p, 4);// Foo * * * *
p = PointerDataType.getPointer(p, 4);// Foo * * * * *
p = PointerDataType.getPointer(p, 4);// Foo * * * * * *
bar.add(p);
// create a multi-dimension array on Bar
Array array = new ArrayDataType(bar, 11, bar.getLength());
array = new ArrayDataType(array, 10, array.getLength());
array = new ArrayDataType(array, 9, array.getLength());
array = new ArrayDataType(array, 8, array.getLength());
array = new ArrayDataType(array, 7, array.getLength());
array = new ArrayDataType(array, 6, array.getLength());
// create a TypeDef on the array
TypeDef td =
new TypedefDataType(new CategoryPath("/MISC"), "MyArray_Typedef", array);
// create a Pointer to typedef on MyArray_Typedef
p = PointerDataType.getPointer(td, 4);// MyArray_Typedef *
p = PointerDataType.getPointer(p, 4);// MyArray_Typedef * *
p = PointerDataType.getPointer(p, 4);// MyArray_Typedef * * *
p = PointerDataType.getPointer(p, 4);// MyArray_Typedef * * * *
p = PointerDataType.getPointer(p, 4);// MyArray_Typedef * * * * *
p = PointerDataType.getPointer(p, 4);// MyArray_Typedef * * * * * *
p = PointerDataType.getPointer(p, 4);// MyArray_Typedef * * * * * * *
p = PointerDataType.getPointer(p, 4);// MyArray_Typedef * * * * * * * *
// add pointer to Foo
foo.add(p);
foo.add(new ArrayDataType(p, 0, 0, dtm));
array = new ArrayDataType(bar, 0, 0, dtm);
foo.add(array);
foo.add(new PointerDataType(array, dtm));
}
});
executeMerge();
DataTypeManager dtm = resultProgram.getDataTypeManager();
// Conflict on Bar
chooseOption(DataTypeMergeManager.OPTION_LATEST);// choose Bar deleted
// Conflict on Foo
chooseOption(DataTypeMergeManager.OPTION_MY);// choose My Foo - Bar removal will cause problems
dismissUnresolvedDataTypesPopup();
waitForCompletion();
Structure bar = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Bar");
assertNull(bar);
Structure foo = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo");
assertNotNull(foo);
//@formatter:off
assertEquals("/MISC/Foo\n" +
"pack(disabled)\n" +
"Structure Foo {\n" +
" 0 byte 1 \"\"\n" +
" 1 byte 1 \"\"\n" +
" 2 word 2 \"\"\n" +
" 4 -BAD- 10 \"Failed to apply 'Bar'\"\n" +
" 14 -BAD- 4 \"Failed to apply 'MyArray_Typedef * * * * * * * *'\"\n" +
" 18 -BAD- 0 \"Failed to apply 'MyArray_Typedef * * * * * * * *[0]'\"\n" +
" 18 -BAD- 0 \"Failed to apply 'Bar[0]'\"\n" +
" 18 -BAD- 4 \"Failed to apply 'Bar[0] *'\"\n" +
"}\n" +
"Length: 22 Alignment: 1\n", foo.toString());
//@formatter:on
// should be no .conflict data types
checkConflictCount(0);
}
@Test @Test
public void testDeletedBasePointerDT() throws Exception { public void testDeletedBasePointerDT() throws Exception {
@ -1401,7 +1587,7 @@ public class DataTypeMerge4Test extends AbstractDataTypeMergeTest {
DataTypeManager dtm = program.getDataTypeManager(); DataTypeManager dtm = program.getDataTypeManager();
Structure foo = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo"); Structure foo = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo");
Structure bar = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Bar"); Structure bar = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Bar");
// edit Bar to create conflict because Latest deleted it // edit Bar to create conflict because Latest deleted it
Pointer p = PointerDataType.getPointer(foo, 4);// Foo * Pointer p = PointerDataType.getPointer(foo, 4);// Foo *
p = PointerDataType.getPointer(p, 4);// Foo * * p = PointerDataType.getPointer(p, 4);// Foo * *
@ -1412,8 +1598,7 @@ public class DataTypeMerge4Test extends AbstractDataTypeMergeTest {
bar.add(p); bar.add(p);
// create a TypeDef on Bar // create a TypeDef on Bar
TypeDef td = TypeDef td = new TypedefDataType(new CategoryPath("/MISC"), "MyBar_Typedef", bar);
new TypedefDataType(new CategoryPath("/MISC"), "MyBar_Typedef", bar);
// create a Pointer to typedef on Bar // create a Pointer to typedef on Bar
p = PointerDataType.getPointer(td, 4);// MyBar_Typedef * p = PointerDataType.getPointer(td, 4);// MyBar_Typedef *
p = PointerDataType.getPointer(p, 4);// MyBar_Typedef * * p = PointerDataType.getPointer(p, 4);// MyBar_Typedef * *
@ -1483,7 +1668,7 @@ public class DataTypeMerge4Test extends AbstractDataTypeMergeTest {
public void modifyLatest(ProgramDB program) { public void modifyLatest(ProgramDB program) {
DataTypeManager dtm = program.getDataTypeManager(); DataTypeManager dtm = program.getDataTypeManager();
Structure bar = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Bar"); Structure bar = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Bar");
// remove Bar from the data type manager // remove Bar from the data type manager
dtm.remove(bar, TaskMonitor.DUMMY); dtm.remove(bar, TaskMonitor.DUMMY);
} }
@ -1504,8 +1689,7 @@ public class DataTypeMerge4Test extends AbstractDataTypeMergeTest {
bar.add(p); bar.add(p);
// create a TypeDef on Bar // create a TypeDef on Bar
TypeDef td = TypeDef td = new TypedefDataType(new CategoryPath("/MISC"), "MyBar_Typedef", bar);
new TypedefDataType(new CategoryPath("/MISC"), "MyBar_Typedef", bar);
// create a Pointer to typedef on Bar // create a Pointer to typedef on Bar
p = PointerDataType.getPointer(td, 4);// MyBar_Typedef * p = PointerDataType.getPointer(td, 4);// MyBar_Typedef *
p = PointerDataType.getPointer(p, 4);// MyBar_Typedef * * p = PointerDataType.getPointer(p, 4);// MyBar_Typedef * *
@ -1528,9 +1712,25 @@ public class DataTypeMerge4Test extends AbstractDataTypeMergeTest {
// Conflict on Foo // Conflict on Foo
chooseOption(DataTypeMergeManager.OPTION_MY);// choose Foo MY chooseOption(DataTypeMergeManager.OPTION_MY);// choose Foo MY
dismissUnresolvedDataTypesPopup();
waitForCompletion(); waitForCompletion();
Structure foo = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo"); Structure foo = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo");
assertNotNull(foo);
//@formatter:off
assertEquals("/MISC/Foo\n" +
"pack(disabled)\n" +
"Structure Foo {\n" +
" 0 byte 1 \"\"\n" +
" 1 byte 1 \"\"\n" +
" 2 word 2 \"\"\n" +
" 4 -BAD- 10 \"Failed to apply 'Bar'\"\n" +
" 14 -BAD- 4 \"Failed to apply 'MyBar_Typedef * * * * * * * *'\"\n" +
"}\n" +
"Length: 18 Alignment: 1\n", foo.toString());
//@formatter:on
Structure bar = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Bar"); Structure bar = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Bar");
assertNull(bar); assertNull(bar);
@ -1538,14 +1738,6 @@ public class DataTypeMerge4Test extends AbstractDataTypeMergeTest {
TypeDef td = (TypeDef) dtm.getDataType(new CategoryPath("/MISC"), "MyBar_Typedef"); TypeDef td = (TypeDef) dtm.getDataType(new CategoryPath("/MISC"), "MyBar_Typedef");
assertNull(td); assertNull(td);
DataTypeComponent[] dtcs = foo.getDefinedComponents();
assertEquals(3, dtcs.length);
dtcs = foo.getComponents();
// pointer gets converted to default
for (int i = 4; i < dtcs.length; i++) {
assertEquals(DataType.DEFAULT, dtcs[i].getDataType());
}
ArrayList<DataType> list = new ArrayList<DataType>(); ArrayList<DataType> list = new ArrayList<DataType>();
dtm.findDataTypes("MyBar_Typedef*", list, false, null); dtm.findDataTypes("MyBar_Typedef*", list, false, null);
assertEquals(0, list.size()); assertEquals(0, list.size());
@ -1583,8 +1775,7 @@ public class DataTypeMerge4Test extends AbstractDataTypeMergeTest {
bar.add(p); bar.add(p);
// create a TypeDef on Bar // create a TypeDef on Bar
TypeDef td = TypeDef td = new TypedefDataType(new CategoryPath("/MISC"), "MyBar_Typedef", bar);
new TypedefDataType(new CategoryPath("/MISC"), "MyBar_Typedef", bar);
// create a Pointer to typedef on Bar // create a Pointer to typedef on Bar
p = PointerDataType.getPointer(td, 4);// MyBar_Typedef * p = PointerDataType.getPointer(td, 4);// MyBar_Typedef *
p = PointerDataType.getPointer(p, 4);// MyBar_Typedef * * p = PointerDataType.getPointer(p, 4);// MyBar_Typedef * *
@ -1656,30 +1847,29 @@ public class DataTypeMerge4Test extends AbstractDataTypeMergeTest {
Structure foo = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo"); Structure foo = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo");
Structure bar = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Bar"); Structure bar = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Bar");
// edit Bar to create conflict because Latest deleted it // edit Bar to create conflict because Latest deleted it
Pointer p = PointerDataType.getPointer(foo, 4);// Foo * Pointer p = PointerDataType.getPointer(foo, 4);// Foo *
p = PointerDataType.getPointer(p, 4);// Foo * * p = PointerDataType.getPointer(p, 4);// Foo * *
p = PointerDataType.getPointer(p, 4);// Foo * * * p = PointerDataType.getPointer(p, 4);// Foo * * *
p = PointerDataType.getPointer(p, 4);// Foo * * * * p = PointerDataType.getPointer(p, 4);// Foo * * * *
p = PointerDataType.getPointer(p, 4);// Foo * * * * * p = PointerDataType.getPointer(p, 4);// Foo * * * * *
p = PointerDataType.getPointer(p, 4);// Foo * * * * * * p = PointerDataType.getPointer(p, 4);// Foo * * * * * *
bar.add(p);// This causes Bar to increase by 4 bytes bar.add(p);// This causes Bar to increase by 4 bytes
// and Foo contains Bar at the end so it also increases by 4. // and Foo contains Bar at the end so it also increases by 4.
// create a TypeDef on Bar // create a TypeDef on Bar
TypeDef td = TypeDef td = new TypedefDataType(new CategoryPath("/MISC"), "MyBar_Typedef", bar);
new TypedefDataType(new CategoryPath("/MISC"), "MyBar_Typedef", bar); // create a Pointer to typedef on Bar
// create a Pointer to typedef on Bar p = PointerDataType.getPointer(td, 4);// MyBar_Typedef *
p = PointerDataType.getPointer(td, 4);// MyBar_Typedef * p = PointerDataType.getPointer(p, 4);// MyBar_Typedef * *
p = PointerDataType.getPointer(p, 4);// MyBar_Typedef * * p = PointerDataType.getPointer(p, 4);// MyBar_Typedef * * *
p = PointerDataType.getPointer(p, 4);// MyBar_Typedef * * * p = PointerDataType.getPointer(p, 4);// MyBar_Typedef * * * *
p = PointerDataType.getPointer(p, 4);// MyBar_Typedef * * * * p = PointerDataType.getPointer(p, 4);// MyBar_Typedef * * * * *
p = PointerDataType.getPointer(p, 4);// MyBar_Typedef * * * * * p = PointerDataType.getPointer(p, 4);// MyBar_Typedef * * * * * *
p = PointerDataType.getPointer(p, 4);// MyBar_Typedef * * * * * * p = PointerDataType.getPointer(p, 4);// MyBar_Typedef * * * * * * *
p = PointerDataType.getPointer(p, 4);// MyBar_Typedef * * * * * * * p = PointerDataType.getPointer(p, 4);// MyBar_Typedef * * * * * * * *
p = PointerDataType.getPointer(p, 4);// MyBar_Typedef * * * * * * * * // add pointer to Foo
// add pointer to Foo foo.add(p);
foo.add(p);
} }
}); });
executeMerge(); executeMerge();
@ -1691,6 +1881,8 @@ public class DataTypeMerge4Test extends AbstractDataTypeMergeTest {
// Conflict on Foo // Conflict on Foo
chooseOption(DataTypeMergeManager.OPTION_MY);// choose Foo MY chooseOption(DataTypeMergeManager.OPTION_MY);// choose Foo MY
dismissUnresolvedDataTypesPopup();
waitForCompletion(); waitForCompletion();
// Bar should have been removed // Bar should have been removed
@ -1698,20 +1890,23 @@ public class DataTypeMerge4Test extends AbstractDataTypeMergeTest {
assertNull(bar); assertNull(bar);
Structure foo = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo"); Structure foo = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo");
DataTypeComponent[] dtcs = foo.getDefinedComponents(); assertNotNull(foo);
assertEquals(3, dtcs.length); //@formatter:off
assertEquals("Structure Foo was the wrong size.", 18, foo.getLength()); assertEquals("/MISC/Foo\n" +
"pack(disabled)\n" +
"Structure Foo {\n" +
" 0 byte 1 \"\"\n" +
" 1 byte 1 \"\"\n" +
" 2 word 2 \"\"\n" +
" 4 -BAD- 10 \"Failed to apply 'Bar'\"\n" +
" 14 -BAD- 4 \"Failed to apply 'MyBar_Typedef * * * * * * * *'\"\n" +
"}\n" +
"Length: 18 Alignment: 1\n", foo.toString());
//@formatter:on
// MyBar_Typedef should not exist since the option to delete Bar was chosen // MyBar_Typedef should not exist since the option to delete Bar was chosen
assertNull(dtm.getDataType(new CategoryPath("/MISC"), "MyBar_Typedef")); assertNull(dtm.getDataType(new CategoryPath("/MISC"), "MyBar_Typedef"));
dtcs = foo.getComponents();
// pointer gets converted to default
for (int i = 4; i < dtcs.length; i++) {
assertEquals(DataType.DEFAULT, dtcs[i].getDataType());
}
} }
@Test @Test
@ -1733,7 +1928,7 @@ public class DataTypeMerge4Test extends AbstractDataTypeMergeTest {
DataTypeManager dtm = program.getDataTypeManager(); DataTypeManager dtm = program.getDataTypeManager();
DataType dt = dtm.getDataType(new CategoryPath("/Category1/Category2/Category3"), DataType dt = dtm.getDataType(new CategoryPath("/Category1/Category2/Category3"),
"IntStruct"); "IntStruct");
try { try {
dt.setName("MyIntStruct"); dt.setName("MyIntStruct");
dt.setCategoryPath(new CategoryPath("/MyCategory/Ints")); dt.setCategoryPath(new CategoryPath("/MyCategory/Ints"));

View file

@ -342,8 +342,7 @@ public class DataTypeMerge5Test extends AbstractDataTypeMergeTest {
dtm.remove(dt, TaskMonitor.DUMMY); dtm.remove(dt, TaskMonitor.DUMMY);
// edit FavoriteColors // edit FavoriteColors
Enum enumm = Enum enumm = (Enum) dtm.getDataType(new CategoryPath("/MISC"), "FavoriteColors");
(Enum) dtm.getDataType(new CategoryPath("/MISC"), "FavoriteColors");
enumm.remove("Red"); enumm.remove("Red");
enumm.remove("Black"); enumm.remove("Black");
enumm.add("Crimson", 6); enumm.add("Crimson", 6);
@ -466,8 +465,7 @@ public class DataTypeMerge5Test extends AbstractDataTypeMergeTest {
dtm.remove(dt, TaskMonitor.DUMMY); dtm.remove(dt, TaskMonitor.DUMMY);
// delete FavoriteColors // delete FavoriteColors
Enum enumm = Enum enumm = (Enum) dtm.getDataType(new CategoryPath("/MISC"), "FavoriteColors");
(Enum) dtm.getDataType(new CategoryPath("/MISC"), "FavoriteColors");
dtm.remove(enumm, TaskMonitor.DUMMY); dtm.remove(enumm, TaskMonitor.DUMMY);
} }
@ -587,8 +585,7 @@ public class DataTypeMerge5Test extends AbstractDataTypeMergeTest {
dtm.remove(dt, TaskMonitor.DUMMY); dtm.remove(dt, TaskMonitor.DUMMY);
// delete FavoriteColors // delete FavoriteColors
Enum enumm = Enum enumm = (Enum) dtm.getDataType(new CategoryPath("/MISC"), "FavoriteColors");
(Enum) dtm.getDataType(new CategoryPath("/MISC"), "FavoriteColors");
dtm.remove(enumm, TaskMonitor.DUMMY); dtm.remove(enumm, TaskMonitor.DUMMY);
} }
@ -655,24 +652,47 @@ public class DataTypeMerge5Test extends AbstractDataTypeMergeTest {
Union union = Union union =
(Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion"); (Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion");
assertNotNull(union); assertNotNull(union);
//@formatter:off
assertEquals("/Category1/Category2/CoolUnion\n" +
"pack(disabled)\n" +
"Union CoolUnion {\n" +
" 0 qword 8 \"\"\n" +
" 0 word 2 \"\"\n" +
" 0 undefined * * * * * 4 \"\"\n" +
" 0 DLL_Table 96 \"\"\n" +
" 0 DLL_Table *32 4 \"\"\n" +
" 0 float 4 Float_Field \"my comments\"\n" +
" 0 -BAD- 4 typedef_field_name_TD_MyEnumPointer \"Type 'TD_MyEnumPointer' was deleted; a typedef\"\n" +
"}\n" +
"Length: 96 Alignment: 1\n", union.toString());
//@formatter:on
// DLL_Table should not be null // DLL_Table should not be null
Structure dll = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table"); Structure dll = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table");
assertNotNull(dll); assertNotNull(dll);
//@formatter:off
assertEquals("/DLL_Table\n" +
"pack(disabled)\n" +
"Structure DLL_Table {\n" +
" 0 string 13 COMDLG32 \"\"\n" +
" 13 string 12 SHELL32 \"\"\n" +
" 25 string 11 MSVCRT \"\"\n" +
" 36 string 13 ADVAPI32 \"\"\n" +
" 49 string 13 KERNEL32 \"\"\n" +
" 62 string 10 GDI32 \"\"\n" +
" 72 string 11 USER32 \"\"\n" +
" 83 string 13 WINSPOOL32 \"\"\n" +
"}\n" +
"Length: 96 Alignment: 1\n", dll.toString());
//@formatter:on
// Typedef should not have been created because we chose to // Typedef should not have been created because we chose to
// delete FavoriteColors (deleted in LATEST) // delete FavoriteColors (deleted in LATEST)
Enum enumm = (Enum) dtm.getDataType(new CategoryPath("/MISC"), "FavoriteColors"); Enum enumm = (Enum) dtm.getDataType(new CategoryPath("/MISC"), "FavoriteColors");
assertNull(enumm); assertNull(enumm);
DataTypeComponent[] dtcs = union.getComponents();
assertEquals(6, dtcs.length);
assertEquals("Float_Field", dtcs[5].getFieldName());
assertEquals("my comments", dtcs[5].getComment());
TypeDef td = (TypeDef) dtm.getDataType(new CategoryPath("/Category1"), "TD_MyEnumPointer"); TypeDef td = (TypeDef) dtm.getDataType(new CategoryPath("/Category1"), "TD_MyEnumPointer");
assertNull(td); assertNull(td);
assertEquals(dll, dtcs[3].getDataType());
ArrayList<DataType> list = new ArrayList<DataType>(); ArrayList<DataType> list = new ArrayList<DataType>();
dtm.findDataTypes("FavoriteColors*", list, false, null); dtm.findDataTypes("FavoriteColors*", list, false, null);
@ -696,8 +716,7 @@ public class DataTypeMerge5Test extends AbstractDataTypeMergeTest {
dtm.remove(dt, TaskMonitor.DUMMY); dtm.remove(dt, TaskMonitor.DUMMY);
// edit FavoriteColors // edit FavoriteColors
Enum enumm = Enum enumm = (Enum) dtm.getDataType(new CategoryPath("/MISC"), "FavoriteColors");
(Enum) dtm.getDataType(new CategoryPath("/MISC"), "FavoriteColors");
enumm.remove("Red"); enumm.remove("Red");
enumm.remove("Black"); enumm.remove("Black");
enumm.add("Crimson", 6); enumm.add("Crimson", 6);
@ -821,8 +840,7 @@ public class DataTypeMerge5Test extends AbstractDataTypeMergeTest {
dtm.remove(dt, TaskMonitor.DUMMY); dtm.remove(dt, TaskMonitor.DUMMY);
// edit FavoriteColors // edit FavoriteColors
Enum enumm = Enum enumm = (Enum) dtm.getDataType(new CategoryPath("/MISC"), "FavoriteColors");
(Enum) dtm.getDataType(new CategoryPath("/MISC"), "FavoriteColors");
enumm.remove("Red"); enumm.remove("Red");
enumm.remove("Black"); enumm.remove("Black");
enumm.add("Crimson", 6); enumm.add("Crimson", 6);
@ -956,8 +974,7 @@ public class DataTypeMerge5Test extends AbstractDataTypeMergeTest {
dtm.remove(dt, TaskMonitor.DUMMY); dtm.remove(dt, TaskMonitor.DUMMY);
// edit FavoriteColors // edit FavoriteColors
Enum enumm = Enum enumm = (Enum) dtm.getDataType(new CategoryPath("/MISC"), "FavoriteColors");
(Enum) dtm.getDataType(new CategoryPath("/MISC"), "FavoriteColors");
enumm.remove("Red"); enumm.remove("Red");
enumm.remove("Black"); enumm.remove("Black");
enumm.add("Crimson", 6); enumm.add("Crimson", 6);
@ -1224,8 +1241,7 @@ public class DataTypeMerge5Test extends AbstractDataTypeMergeTest {
// must specify datatype manager when constructing to allow for settings to be made // must specify datatype manager when constructing to allow for settings to be made
Pointer p = dtm.getPointer(CharDataType.dataType); Pointer p = dtm.getPointer(CharDataType.dataType);
TypeDef td = TypeDef td = new TypedefDataType(new CategoryPath("/MISC"), "PtrTypeDef", p, dtm);
new TypedefDataType(new CategoryPath("/MISC"), "PtrTypeDef", p, dtm);
// NOTE: these are not viable settings but are intended to exercise all of them // NOTE: these are not viable settings but are intended to exercise all of them
Settings settings = td.getDefaultSettings(); Settings settings = td.getDefaultSettings();
@ -1246,8 +1262,7 @@ public class DataTypeMerge5Test extends AbstractDataTypeMergeTest {
TypeDef td = (TypeDef) dtm.getDataType(new CategoryPath("/MISC"), "PtrTypeDef"); TypeDef td = (TypeDef) dtm.getDataType(new CategoryPath("/MISC"), "PtrTypeDef");
Settings settings = td.getDefaultSettings(); Settings settings = td.getDefaultSettings();
PointerTypeSettingsDefinition.DEF.setType(settings, PointerTypeSettingsDefinition.DEF.setType(settings, PointerType.RELATIVE);
PointerType.RELATIVE);
AddressSpaceSettingsDefinition.DEF.clear(settings); AddressSpaceSettingsDefinition.DEF.clear(settings);
OffsetMaskSettingsDefinition.DEF.clear(settings); OffsetMaskSettingsDefinition.DEF.clear(settings);
OffsetShiftSettingsDefinition.DEF.setValue(settings, 3); OffsetShiftSettingsDefinition.DEF.setValue(settings, 3);
@ -1328,8 +1343,7 @@ public class DataTypeMerge5Test extends AbstractDataTypeMergeTest {
td.setName("Bob_Ptr_Td"); td.setName("Bob_Ptr_Td");
Settings settings = td.getDefaultSettings(); Settings settings = td.getDefaultSettings();
PointerTypeSettingsDefinition.DEF.setType(settings, PointerTypeSettingsDefinition.DEF.setType(settings, PointerType.RELATIVE);
PointerType.RELATIVE);
Structure st = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo"); Structure st = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo");
st.setName("Bob"); st.setName("Bob");
@ -1375,9 +1389,8 @@ public class DataTypeMerge5Test extends AbstractDataTypeMergeTest {
assertEquals("Bill", dt.getName()); assertEquals("Bill", dt.getName());
Settings settings = td.getDefaultSettings(); Settings settings = td.getDefaultSettings();
assertEquals( assertEquals("Expected pointer-typedef type: relative", PointerType.RELATIVE,
"Expected pointer-typedef type: relative", PointerTypeSettingsDefinition.DEF.getType(settings));
PointerType.RELATIVE, PointerTypeSettingsDefinition.DEF.getType(settings));
assertFalse( assertFalse(
"Unexpected setting: " + "Unexpected setting: " +
ComponentOffsetSettingsDefinition.DEF.getAttributeSpecification(settings), ComponentOffsetSettingsDefinition.DEF.getAttributeSpecification(settings),
@ -1416,8 +1429,7 @@ public class DataTypeMerge5Test extends AbstractDataTypeMergeTest {
td.setName("Bob_Ptr_Td"); td.setName("Bob_Ptr_Td");
Settings settings = td.getDefaultSettings(); Settings settings = td.getDefaultSettings();
PointerTypeSettingsDefinition.DEF.setType(settings, PointerTypeSettingsDefinition.DEF.setType(settings, PointerType.RELATIVE);
PointerType.RELATIVE);
} }
catch (InvalidNameException | DuplicateNameException e) { catch (InvalidNameException | DuplicateNameException e) {
failWithException("unexpected", e); failWithException("unexpected", e);
@ -1447,9 +1459,8 @@ public class DataTypeMerge5Test extends AbstractDataTypeMergeTest {
assertEquals("Bill", dt.getName()); assertEquals("Bill", dt.getName());
Settings settings = td.getDefaultSettings(); Settings settings = td.getDefaultSettings();
assertEquals( assertEquals("Expected pointer-typedef type: relative", PointerType.RELATIVE,
"Expected pointer-typedef type: relative", PointerTypeSettingsDefinition.DEF.getType(settings));
PointerType.RELATIVE, PointerTypeSettingsDefinition.DEF.getType(settings));
assertFalse( assertFalse(
"Unexpected setting: " + "Unexpected setting: " +
ComponentOffsetSettingsDefinition.DEF.getAttributeSpecification(settings), ComponentOffsetSettingsDefinition.DEF.getAttributeSpecification(settings),
@ -1474,8 +1485,7 @@ public class DataTypeMerge5Test extends AbstractDataTypeMergeTest {
dtm.remove(dt, TaskMonitor.DUMMY); dtm.remove(dt, TaskMonitor.DUMMY);
// edit FavoriteColors // edit FavoriteColors
Enum enumm = Enum enumm = (Enum) dtm.getDataType(new CategoryPath("/MISC"), "FavoriteColors");
(Enum) dtm.getDataType(new CategoryPath("/MISC"), "FavoriteColors");
enumm.remove("Red"); enumm.remove("Red");
enumm.remove("Black"); enumm.remove("Black");
enumm.add("Crimson", 6); enumm.add("Crimson", 6);

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -36,8 +36,9 @@ public class DataTypeMerge6Test extends AbstractDataTypeMergeTest {
public void modifyOriginal(ProgramDB program) throws Exception { public void modifyOriginal(ProgramDB program) throws Exception {
DataTypeManager dtm = program.getDataTypeManager(); DataTypeManager dtm = program.getDataTypeManager();
Structure s = (Structure) dtm.getDataType( Structure s =
new CategoryPath("/Category1/Category2/Category3"), "IntStruct"); (Structure) dtm.getDataType(new CategoryPath("/Category1/Category2/Category3"),
"IntStruct");
assertEquals(15, s.getLength()); assertEquals(15, s.getLength());
assertEquals(1, s.getAlignment()); assertEquals(1, s.getAlignment());
s.setToDefaultPacking(); s.setToDefaultPacking();
@ -55,8 +56,9 @@ public class DataTypeMerge6Test extends AbstractDataTypeMergeTest {
public void modifyLatest(ProgramDB program) throws Exception { public void modifyLatest(ProgramDB program) throws Exception {
DataTypeManager dtm = program.getDataTypeManager(); DataTypeManager dtm = program.getDataTypeManager();
Structure s = (Structure) dtm.getDataType( Structure s =
new CategoryPath("/Category1/Category2/Category3"), "IntStruct"); (Structure) dtm.getDataType(new CategoryPath("/Category1/Category2/Category3"),
"IntStruct");
s.setToMachineAligned(); s.setToMachineAligned();
// Offsets change to 0,2,4,8. // Offsets change to 0,2,4,8.
@ -72,8 +74,9 @@ public class DataTypeMerge6Test extends AbstractDataTypeMergeTest {
public void modifyPrivate(ProgramDB program) throws Exception { public void modifyPrivate(ProgramDB program) throws Exception {
DataTypeManager dtm = program.getDataTypeManager(); DataTypeManager dtm = program.getDataTypeManager();
Structure s = (Structure) dtm.getDataType( Structure s =
new CategoryPath("/Category1/Category2/Category3"), "IntStruct"); (Structure) dtm.getDataType(new CategoryPath("/Category1/Category2/Category3"),
"IntStruct");
s.setExplicitMinimumAlignment(4); s.setExplicitMinimumAlignment(4);
// Offsets change to 0,2,4,8. // Offsets change to 0,2,4,8.
@ -168,8 +171,9 @@ public class DataTypeMerge6Test extends AbstractDataTypeMergeTest {
public void modifyOriginal(ProgramDB program) throws Exception { public void modifyOriginal(ProgramDB program) throws Exception {
DataTypeManager dtm = program.getDataTypeManager(); DataTypeManager dtm = program.getDataTypeManager();
Structure s = (Structure) dtm.getDataType( Structure s =
new CategoryPath("/Category1/Category2/Category3"), "IntStruct"); (Structure) dtm.getDataType(new CategoryPath("/Category1/Category2/Category3"),
"IntStruct");
assertEquals(15, s.getLength()); assertEquals(15, s.getLength());
assertEquals(1, s.getAlignment()); assertEquals(1, s.getAlignment());
s.setToDefaultPacking(); s.setToDefaultPacking();
@ -187,8 +191,9 @@ public class DataTypeMerge6Test extends AbstractDataTypeMergeTest {
public void modifyLatest(ProgramDB program) throws Exception { public void modifyLatest(ProgramDB program) throws Exception {
DataTypeManager dtm = program.getDataTypeManager(); DataTypeManager dtm = program.getDataTypeManager();
Structure s = (Structure) dtm.getDataType( Structure s =
new CategoryPath("/Category1/Category2/Category3"), "IntStruct"); (Structure) dtm.getDataType(new CategoryPath("/Category1/Category2/Category3"),
"IntStruct");
s.pack(1); s.pack(1);
// Offsets change to 0,2,4,8. // Offsets change to 0,2,4,8.
@ -204,8 +209,9 @@ public class DataTypeMerge6Test extends AbstractDataTypeMergeTest {
public void modifyPrivate(ProgramDB program) throws Exception { public void modifyPrivate(ProgramDB program) throws Exception {
DataTypeManager dtm = program.getDataTypeManager(); DataTypeManager dtm = program.getDataTypeManager();
Structure s = (Structure) dtm.getDataType( Structure s =
new CategoryPath("/Category1/Category2/Category3"), "IntStruct"); (Structure) dtm.getDataType(new CategoryPath("/Category1/Category2/Category3"),
"IntStruct");
s.pack(2); s.pack(2);
// Offsets change to 0,2,4,8. // Offsets change to 0,2,4,8.
@ -230,9 +236,8 @@ public class DataTypeMerge6Test extends AbstractDataTypeMergeTest {
waitForCompletion(); waitForCompletion();
DataTypeManager dtm = resultProgram.getDataTypeManager(); DataTypeManager dtm = resultProgram.getDataTypeManager();
Structure s = Structure s = (Structure) dtm
(Structure) dtm.getDataType(new CategoryPath("/Category1/Category2/Category3"), .getDataType(new CategoryPath("/Category1/Category2/Category3"), "IntStruct");
"IntStruct");
assertTrue(s.hasExplicitPackingValue()); assertTrue(s.hasExplicitPackingValue());
assertEquals(1, s.getExplicitPackingValue()); assertEquals(1, s.getExplicitPackingValue());
assertTrue(s.isDefaultAligned()); assertTrue(s.isDefaultAligned());
@ -256,9 +261,8 @@ public class DataTypeMerge6Test extends AbstractDataTypeMergeTest {
waitForCompletion(); waitForCompletion();
DataTypeManager dtm = resultProgram.getDataTypeManager(); DataTypeManager dtm = resultProgram.getDataTypeManager();
Structure s = Structure s = (Structure) dtm
(Structure) dtm.getDataType(new CategoryPath("/Category1/Category2/Category3"), .getDataType(new CategoryPath("/Category1/Category2/Category3"), "IntStruct");
"IntStruct");
assertTrue(s.hasExplicitPackingValue()); assertTrue(s.hasExplicitPackingValue());
assertEquals(2, s.getExplicitPackingValue()); assertEquals(2, s.getExplicitPackingValue());
assertTrue(s.isDefaultAligned()); assertTrue(s.isDefaultAligned());
@ -303,8 +307,9 @@ public class DataTypeMerge6Test extends AbstractDataTypeMergeTest {
public void modifyOriginal(ProgramDB program) throws Exception { public void modifyOriginal(ProgramDB program) throws Exception {
DataTypeManager dtm = program.getDataTypeManager(); DataTypeManager dtm = program.getDataTypeManager();
Structure s = (Structure) dtm.getDataType( Structure s =
new CategoryPath("/Category1/Category2/Category3"), "IntStruct"); (Structure) dtm.getDataType(new CategoryPath("/Category1/Category2/Category3"),
"IntStruct");
assertEquals(15, s.getLength()); assertEquals(15, s.getLength());
assertEquals(1, s.getAlignment()); assertEquals(1, s.getAlignment());
s.setToDefaultPacking(); s.setToDefaultPacking();
@ -322,8 +327,9 @@ public class DataTypeMerge6Test extends AbstractDataTypeMergeTest {
public void modifyLatest(ProgramDB program) throws Exception { public void modifyLatest(ProgramDB program) throws Exception {
DataTypeManager dtm = program.getDataTypeManager(); DataTypeManager dtm = program.getDataTypeManager();
Structure s = (Structure) dtm.getDataType( Structure s =
new CategoryPath("/Category1/Category2/Category3"), "IntStruct"); (Structure) dtm.getDataType(new CategoryPath("/Category1/Category2/Category3"),
"IntStruct");
s.setToMachineAligned(); s.setToMachineAligned();
// Offsets change to 0,2,4,8. // Offsets change to 0,2,4,8.
@ -339,8 +345,9 @@ public class DataTypeMerge6Test extends AbstractDataTypeMergeTest {
public void modifyPrivate(ProgramDB program) throws Exception { public void modifyPrivate(ProgramDB program) throws Exception {
DataTypeManager dtm = program.getDataTypeManager(); DataTypeManager dtm = program.getDataTypeManager();
Structure s = (Structure) dtm.getDataType( Structure s =
new CategoryPath("/Category1/Category2/Category3"), "IntStruct"); (Structure) dtm.getDataType(new CategoryPath("/Category1/Category2/Category3"),
"IntStruct");
s.pack(1); s.pack(1);
assertEquals(0, s.getComponent(0).getOffset()); assertEquals(0, s.getComponent(0).getOffset());
@ -364,9 +371,8 @@ public class DataTypeMerge6Test extends AbstractDataTypeMergeTest {
waitForCompletion(); waitForCompletion();
DataTypeManager dtm = resultProgram.getDataTypeManager(); DataTypeManager dtm = resultProgram.getDataTypeManager();
Structure s = Structure s = (Structure) dtm
(Structure) dtm.getDataType(new CategoryPath("/Category1/Category2/Category3"), .getDataType(new CategoryPath("/Category1/Category2/Category3"), "IntStruct");
"IntStruct");
assertTrue(s.hasDefaultPacking()); assertTrue(s.hasDefaultPacking());
assertTrue(s.isMachineAligned()); assertTrue(s.isMachineAligned());
@ -389,9 +395,8 @@ public class DataTypeMerge6Test extends AbstractDataTypeMergeTest {
waitForCompletion(); waitForCompletion();
DataTypeManager dtm = resultProgram.getDataTypeManager(); DataTypeManager dtm = resultProgram.getDataTypeManager();
Structure s = Structure s = (Structure) dtm
(Structure) dtm.getDataType(new CategoryPath("/Category1/Category2/Category3"), .getDataType(new CategoryPath("/Category1/Category2/Category3"), "IntStruct");
"IntStruct");
assertTrue(s.hasExplicitPackingValue()); assertTrue(s.hasExplicitPackingValue());
assertEquals(1, s.getExplicitPackingValue()); assertEquals(1, s.getExplicitPackingValue());
assertTrue(s.isDefaultAligned()); assertTrue(s.isDefaultAligned());
@ -412,8 +417,9 @@ public class DataTypeMerge6Test extends AbstractDataTypeMergeTest {
public void modifyLatest(ProgramDB program) throws Exception { public void modifyLatest(ProgramDB program) throws Exception {
DataTypeManager dtm = program.getDataTypeManager(); DataTypeManager dtm = program.getDataTypeManager();
Structure s = (Structure) dtm.getDataType( Structure s =
new CategoryPath("/Category1/Category2/Category3"), "IntStruct"); (Structure) dtm.getDataType(new CategoryPath("/Category1/Category2/Category3"),
"IntStruct");
assertEquals(15, s.getLength()); assertEquals(15, s.getLength());
assertEquals(1, s.getAlignment()); assertEquals(1, s.getAlignment());
s.add(new IntegerDataType()); s.add(new IntegerDataType());
@ -433,8 +439,9 @@ public class DataTypeMerge6Test extends AbstractDataTypeMergeTest {
public void modifyPrivate(ProgramDB program) throws Exception { public void modifyPrivate(ProgramDB program) throws Exception {
DataTypeManager dtm = program.getDataTypeManager(); DataTypeManager dtm = program.getDataTypeManager();
Structure s = (Structure) dtm.getDataType( Structure s =
new CategoryPath("/Category1/Category2/Category3"), "IntStruct"); (Structure) dtm.getDataType(new CategoryPath("/Category1/Category2/Category3"),
"IntStruct");
assertEquals(15, s.getLength()); assertEquals(15, s.getLength());
assertEquals(1, s.getAlignment()); assertEquals(1, s.getAlignment());
s.setToDefaultPacking(); s.setToDefaultPacking();
@ -461,9 +468,8 @@ public class DataTypeMerge6Test extends AbstractDataTypeMergeTest {
waitForCompletion(); waitForCompletion();
DataTypeManager dtm = resultProgram.getDataTypeManager(); DataTypeManager dtm = resultProgram.getDataTypeManager();
Structure s = Structure s = (Structure) dtm
(Structure) dtm.getDataType(new CategoryPath("/Category1/Category2/Category3"), .getDataType(new CategoryPath("/Category1/Category2/Category3"), "IntStruct");
"IntStruct");
assertFalse(s.isPackingEnabled()); assertFalse(s.isPackingEnabled());
assertTrue(s.isDefaultAligned()); assertTrue(s.isDefaultAligned());
@ -487,9 +493,8 @@ public class DataTypeMerge6Test extends AbstractDataTypeMergeTest {
waitForCompletion(); waitForCompletion();
DataTypeManager dtm = resultProgram.getDataTypeManager(); DataTypeManager dtm = resultProgram.getDataTypeManager();
Structure s = Structure s = (Structure) dtm
(Structure) dtm.getDataType(new CategoryPath("/Category1/Category2/Category3"), .getDataType(new CategoryPath("/Category1/Category2/Category3"), "IntStruct");
"IntStruct");
assertTrue(s.hasDefaultPacking()); assertTrue(s.hasDefaultPacking());
assertTrue(s.isDefaultAligned()); assertTrue(s.isDefaultAligned());
@ -509,8 +514,9 @@ public class DataTypeMerge6Test extends AbstractDataTypeMergeTest {
public void modifyOriginal(ProgramDB program) throws Exception { public void modifyOriginal(ProgramDB program) throws Exception {
DataTypeManager dtm = program.getDataTypeManager(); DataTypeManager dtm = program.getDataTypeManager();
Structure s = (Structure) dtm.getDataType( Structure s =
new CategoryPath("/Category1/Category2/Category3"), "IntStruct"); (Structure) dtm.getDataType(new CategoryPath("/Category1/Category2/Category3"),
"IntStruct");
assertEquals(15, s.getLength()); assertEquals(15, s.getLength());
assertEquals(1, s.getAlignment()); assertEquals(1, s.getAlignment());
s.setToDefaultPacking(); s.setToDefaultPacking();
@ -528,8 +534,9 @@ public class DataTypeMerge6Test extends AbstractDataTypeMergeTest {
public void modifyLatest(ProgramDB program) throws Exception { public void modifyLatest(ProgramDB program) throws Exception {
DataTypeManager dtm = program.getDataTypeManager(); DataTypeManager dtm = program.getDataTypeManager();
Structure s = (Structure) dtm.getDataType( Structure s =
new CategoryPath("/Category1/Category2/Category3"), "IntStruct"); (Structure) dtm.getDataType(new CategoryPath("/Category1/Category2/Category3"),
"IntStruct");
assertEquals(16, s.getLength()); assertEquals(16, s.getLength());
assertEquals(4, s.getAlignment()); assertEquals(4, s.getAlignment());
s.getComponent(1).setFieldName("MyComponentOne"); s.getComponent(1).setFieldName("MyComponentOne");
@ -550,8 +557,9 @@ public class DataTypeMerge6Test extends AbstractDataTypeMergeTest {
public void modifyPrivate(ProgramDB program) throws Exception { public void modifyPrivate(ProgramDB program) throws Exception {
DataTypeManager dtm = program.getDataTypeManager(); DataTypeManager dtm = program.getDataTypeManager();
Structure s = (Structure) dtm.getDataType( Structure s =
new CategoryPath("/Category1/Category2/Category3"), "IntStruct"); (Structure) dtm.getDataType(new CategoryPath("/Category1/Category2/Category3"),
"IntStruct");
assertEquals(16, s.getLength()); assertEquals(16, s.getLength());
assertEquals(4, s.getAlignment()); assertEquals(4, s.getAlignment());
s.pack(1); s.pack(1);
@ -577,9 +585,8 @@ public class DataTypeMerge6Test extends AbstractDataTypeMergeTest {
waitForCompletion(); waitForCompletion();
DataTypeManager dtm = resultProgram.getDataTypeManager(); DataTypeManager dtm = resultProgram.getDataTypeManager();
Structure s = Structure s = (Structure) dtm
(Structure) dtm.getDataType(new CategoryPath("/Category1/Category2/Category3"), .getDataType(new CategoryPath("/Category1/Category2/Category3"), "IntStruct");
"IntStruct");
assertTrue(s.hasDefaultPacking()); assertTrue(s.hasDefaultPacking());
assertTrue(s.isDefaultAligned()); assertTrue(s.isDefaultAligned());
@ -602,9 +609,8 @@ public class DataTypeMerge6Test extends AbstractDataTypeMergeTest {
waitForCompletion(); waitForCompletion();
DataTypeManager dtm = resultProgram.getDataTypeManager(); DataTypeManager dtm = resultProgram.getDataTypeManager();
Structure s = Structure s = (Structure) dtm
(Structure) dtm.getDataType(new CategoryPath("/Category1/Category2/Category3"), .getDataType(new CategoryPath("/Category1/Category2/Category3"), "IntStruct");
"IntStruct");
assertTrue(s.hasExplicitPackingValue()); assertTrue(s.hasExplicitPackingValue());
assertEquals(1, s.getExplicitPackingValue()); assertEquals(1, s.getExplicitPackingValue());
assertTrue(s.isDefaultAligned()); assertTrue(s.isDefaultAligned());
@ -625,8 +631,9 @@ public class DataTypeMerge6Test extends AbstractDataTypeMergeTest {
public void modifyOriginal(ProgramDB program) throws Exception { public void modifyOriginal(ProgramDB program) throws Exception {
DataTypeManager dtm = program.getDataTypeManager(); DataTypeManager dtm = program.getDataTypeManager();
Structure s = (Structure) dtm.getDataType( Structure s =
new CategoryPath("/Category1/Category2/Category3"), "IntStruct"); (Structure) dtm.getDataType(new CategoryPath("/Category1/Category2/Category3"),
"IntStruct");
assertEquals(15, s.getLength()); assertEquals(15, s.getLength());
assertEquals(1, s.getAlignment()); assertEquals(1, s.getAlignment());
s.setToDefaultPacking(); s.setToDefaultPacking();
@ -644,13 +651,15 @@ public class DataTypeMerge6Test extends AbstractDataTypeMergeTest {
public void modifyLatest(ProgramDB program) throws Exception { public void modifyLatest(ProgramDB program) throws Exception {
DataTypeManager dtm = program.getDataTypeManager(); DataTypeManager dtm = program.getDataTypeManager();
Structure s = (Structure) dtm.getDataType( Structure s =
new CategoryPath("/Category1/Category2/Category3"), "IntStruct"); (Structure) dtm.getDataType(new CategoryPath("/Category1/Category2/Category3"),
"IntStruct");
dtm.remove(s, TaskMonitor.DUMMY); dtm.remove(s, TaskMonitor.DUMMY);
// Offsets change to 0,2,4,8. // Offsets change to 0,2,4,8.
Structure intStruct = (Structure) dtm.getDataType( Structure intStruct =
new CategoryPath("/Category1/Category2/Category3"), "IntStruct"); (Structure) dtm.getDataType(new CategoryPath("/Category1/Category2/Category3"),
"IntStruct");
assertNull(intStruct); assertNull(intStruct);
} }
@ -658,8 +667,9 @@ public class DataTypeMerge6Test extends AbstractDataTypeMergeTest {
public void modifyPrivate(ProgramDB program) throws Exception { public void modifyPrivate(ProgramDB program) throws Exception {
DataTypeManager dtm = program.getDataTypeManager(); DataTypeManager dtm = program.getDataTypeManager();
Structure s = (Structure) dtm.getDataType( Structure s =
new CategoryPath("/Category1/Category2/Category3"), "IntStruct"); (Structure) dtm.getDataType(new CategoryPath("/Category1/Category2/Category3"),
"IntStruct");
s.pack(1); s.pack(1);
assertEquals(0, s.getComponent(0).getOffset()); assertEquals(0, s.getComponent(0).getOffset());
@ -683,9 +693,8 @@ public class DataTypeMerge6Test extends AbstractDataTypeMergeTest {
waitForCompletion(); waitForCompletion();
DataTypeManager dtm = resultProgram.getDataTypeManager(); DataTypeManager dtm = resultProgram.getDataTypeManager();
Structure intStruct = Structure intStruct = (Structure) dtm
(Structure) dtm.getDataType(new CategoryPath("/Category1/Category2/Category3"), .getDataType(new CategoryPath("/Category1/Category2/Category3"), "IntStruct");
"IntStruct");
assertNull(intStruct); assertNull(intStruct);
} }
@ -700,9 +709,8 @@ public class DataTypeMerge6Test extends AbstractDataTypeMergeTest {
waitForCompletion(); waitForCompletion();
DataTypeManager dtm = resultProgram.getDataTypeManager(); DataTypeManager dtm = resultProgram.getDataTypeManager();
Structure s = Structure s = (Structure) dtm
(Structure) dtm.getDataType(new CategoryPath("/Category1/Category2/Category3"), .getDataType(new CategoryPath("/Category1/Category2/Category3"), "IntStruct");
"IntStruct");
assertTrue(s.hasExplicitPackingValue()); assertTrue(s.hasExplicitPackingValue());
assertEquals(1, s.getExplicitPackingValue()); assertEquals(1, s.getExplicitPackingValue());
assertTrue(s.isDefaultAligned()); assertTrue(s.isDefaultAligned());
@ -723,26 +731,28 @@ public class DataTypeMerge6Test extends AbstractDataTypeMergeTest {
public void modifyOriginal(ProgramDB program) throws Exception { public void modifyOriginal(ProgramDB program) throws Exception {
DataTypeManager dtm = program.getDataTypeManager(); DataTypeManager dtm = program.getDataTypeManager();
Structure s = (Structure) dtm.getDataType( Structure s =
new CategoryPath("/Category1/Category2/Category3"), "IntStruct"); (Structure) dtm.getDataType(new CategoryPath("/Category1/Category2/Category3"),
"IntStruct");
s.setPackingEnabled(true); s.setPackingEnabled(true);
Union union = (Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), Union union =
"CoolUnion"); (Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion");
union.setPackingEnabled(true); union.setPackingEnabled(true);
} }
@Override @Override
public void modifyLatest(ProgramDB program) throws Exception { public void modifyLatest(ProgramDB program) throws Exception {
DataTypeManager dtm = program.getDataTypeManager(); DataTypeManager dtm = program.getDataTypeManager();
Structure structure = (Structure) dtm.getDataType( Structure structure =
new CategoryPath("/Category1/Category2/Category3"), "IntStruct"); (Structure) dtm.getDataType(new CategoryPath("/Category1/Category2/Category3"),
"IntStruct");
assertEquals(16, structure.getLength()); assertEquals(16, structure.getLength());
assertEquals(4, structure.getAlignment()); assertEquals(4, structure.getAlignment());
Union union = (Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), Union union =
"CoolUnion"); (Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion");
assertEquals(96, union.getLength()); assertEquals(96, union.getLength());
assertEquals(4, union.getAlignment()); assertEquals(4, union.getAlignment());
@ -753,13 +763,14 @@ public class DataTypeMerge6Test extends AbstractDataTypeMergeTest {
public void modifyPrivate(ProgramDB program) throws Exception { public void modifyPrivate(ProgramDB program) throws Exception {
DataTypeManager dtm = program.getDataTypeManager(); DataTypeManager dtm = program.getDataTypeManager();
Structure structure = (Structure) dtm.getDataType( Structure structure =
new CategoryPath("/Category1/Category2/Category3"), "IntStruct"); (Structure) dtm.getDataType(new CategoryPath("/Category1/Category2/Category3"),
"IntStruct");
assertEquals(16, structure.getLength()); assertEquals(16, structure.getLength());
assertEquals(4, structure.getAlignment()); assertEquals(4, structure.getAlignment());
Union union = (Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), Union union =
"CoolUnion"); (Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion");
assertEquals(96, union.getLength()); assertEquals(96, union.getLength());
assertEquals(4, union.getAlignment()); assertEquals(4, union.getAlignment());
@ -774,44 +785,43 @@ public class DataTypeMerge6Test extends AbstractDataTypeMergeTest {
setupStructureInUnionAndViceVersa(); setupStructureInUnionAndViceVersa();
executeMerge(); executeMerge();
close(waitForWindow("Union Update Failed")); // expected dependency error on CoolUnion pressButtonByName(waitForWindow("Union Update Failed"), "OK"); // expected dependency error on CoolUnion
waitForCompletion(); waitForCompletion();
DataTypeManager dtm = resultProgram.getDataTypeManager(); DataTypeManager dtm = resultProgram.getDataTypeManager();
Structure intStruct = Structure intStruct = (Structure) dtm
(Structure) dtm.getDataType(new CategoryPath("/Category1/Category2/Category3"), .getDataType(new CategoryPath("/Category1/Category2/Category3"), "IntStruct");
"IntStruct"); assertNotNull(intStruct);
assertTrue(intStruct.hasDefaultPacking()); //@formatter:off
assertTrue(intStruct.isDefaultAligned()); assertEquals("/Category1/Category2/Category3/IntStruct\n" +
"pack()\n" +
assertEquals(5, intStruct.getNumComponents()); "Structure IntStruct {\n" +
assertEquals(0, intStruct.getComponent(0).getOffset()); " 0 byte 1 field0 \"\"\n" +
assertEquals(2, intStruct.getComponent(1).getOffset()); " 2 word 2 \"\"\n" +
assertEquals(4, intStruct.getComponent(2).getOffset()); " 4 dword 4 \"\"\n" +
assertEquals(8, intStruct.getComponent(3).getOffset()); " 8 qword 8 \"\"\n" +
assertEquals(16, intStruct.getComponent(4).getOffset()); " 16 CoolUnion 112 \"\"\n" +
assertEquals("CoolUnion", intStruct.getComponent(4).getDataType().getDisplayName()); "}\n" +
assertEquals(112, intStruct.getLength()); "Length: 128 Alignment: 4\n", intStruct.toString());
assertEquals(4, intStruct.getAlignment()); //@formatter:on
Union coolUnion = Union coolUnion =
(Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion"); (Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion");
assertTrue(coolUnion.hasDefaultPacking()); assertNotNull(coolUnion);
assertTrue(coolUnion.isDefaultAligned()); //@formatter:off
assertEquals("/Category1/Category2/CoolUnion\n" +
assertEquals(6, coolUnion.getNumComponents()); "pack()\n" +
assertEquals("qword", coolUnion.getComponent(0).getDataType().getDisplayName()); "Union CoolUnion {\n" +
assertEquals("word", coolUnion.getComponent(1).getDataType().getDisplayName()); " 0 qword 8 \"\"\n" +
assertEquals("undefined * * * * *", " 0 word 2 \"\"\n" +
coolUnion.getComponent(2).getDataType().getDisplayName()); " 0 undefined * * * * * 4 \"\"\n" +
assertEquals("DLL_Table", coolUnion.getComponent(3).getDataType().getDisplayName()); " 0 DLL_Table 96 \"\"\n" +
assertEquals("DLL_Table *", coolUnion.getComponent(4).getDataType().getDisplayName()); " 0 DLL_Table *32 4 \"\"\n" +
assertTrue(coolUnion.getComponent(5).getDataType() instanceof BadDataType); " 0 -BAD- 112 \"Failed to apply 'IntStruct', Data type IntStruct has CoolUnion within it.\"\n" +
String comment5 = coolUnion.getComponent(5).getComment(); "}\n" +
assertTrue(comment5.startsWith("Couldn't add IntStruct here.")); "Length: 112 Alignment: 4\n", coolUnion.toString());
assertEquals(96, coolUnion.getLength()); //@formatter:on
assertEquals(4, coolUnion.getAlignment());
} }
@ -825,8 +835,8 @@ public class DataTypeMerge6Test extends AbstractDataTypeMergeTest {
public void modifyOriginal(ProgramDB program) throws Exception { public void modifyOriginal(ProgramDB program) throws Exception {
DataTypeManager dtm = program.getDataTypeManager(); DataTypeManager dtm = program.getDataTypeManager();
Union union = (Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), Union union =
"CoolUnion"); (Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion");
assertEquals(96, union.getLength()); assertEquals(96, union.getLength());
assertEquals(1, union.getAlignment()); assertEquals(1, union.getAlignment());
union.setPackingEnabled(true); union.setPackingEnabled(true);
@ -844,8 +854,8 @@ public class DataTypeMerge6Test extends AbstractDataTypeMergeTest {
public void modifyLatest(ProgramDB program) throws Exception { public void modifyLatest(ProgramDB program) throws Exception {
DataTypeManager dtm = program.getDataTypeManager(); DataTypeManager dtm = program.getDataTypeManager();
Union union = (Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), Union union =
"CoolUnion"); (Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion");
union.setToMachineAligned(); union.setToMachineAligned();
assertEquals(8, union.getComponent(0).getLength()); assertEquals(8, union.getComponent(0).getLength());
@ -861,8 +871,8 @@ public class DataTypeMerge6Test extends AbstractDataTypeMergeTest {
public void modifyPrivate(ProgramDB program) throws Exception { public void modifyPrivate(ProgramDB program) throws Exception {
DataTypeManager dtm = program.getDataTypeManager(); DataTypeManager dtm = program.getDataTypeManager();
Union union = (Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), Union union =
"CoolUnion"); (Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion");
union.setExplicitMinimumAlignment(4); union.setExplicitMinimumAlignment(4);
assertEquals(8, union.getComponent(0).getLength()); assertEquals(8, union.getComponent(0).getLength());
@ -960,8 +970,8 @@ public class DataTypeMerge6Test extends AbstractDataTypeMergeTest {
public void modifyOriginal(ProgramDB program) throws Exception { public void modifyOriginal(ProgramDB program) throws Exception {
DataTypeManager dtm = program.getDataTypeManager(); DataTypeManager dtm = program.getDataTypeManager();
Union union = (Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), Union union =
"CoolUnion"); (Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion");
assertEquals(96, union.getLength()); assertEquals(96, union.getLength());
assertEquals(1, union.getAlignment()); assertEquals(1, union.getAlignment());
union.setPackingEnabled(true); union.setPackingEnabled(true);
@ -979,8 +989,8 @@ public class DataTypeMerge6Test extends AbstractDataTypeMergeTest {
public void modifyLatest(ProgramDB program) throws Exception { public void modifyLatest(ProgramDB program) throws Exception {
DataTypeManager dtm = program.getDataTypeManager(); DataTypeManager dtm = program.getDataTypeManager();
Union union = (Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), Union union =
"CoolUnion"); (Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion");
union.pack(1); union.pack(1);
assertEquals(8, union.getComponent(0).getLength()); assertEquals(8, union.getComponent(0).getLength());
@ -996,8 +1006,8 @@ public class DataTypeMerge6Test extends AbstractDataTypeMergeTest {
public void modifyPrivate(ProgramDB program) throws Exception { public void modifyPrivate(ProgramDB program) throws Exception {
DataTypeManager dtm = program.getDataTypeManager(); DataTypeManager dtm = program.getDataTypeManager();
Union union = (Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), Union union =
"CoolUnion"); (Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion");
union.pack(2); union.pack(2);
assertEquals(8, union.getComponent(0).getLength()); assertEquals(8, union.getComponent(0).getLength());
@ -1116,8 +1126,8 @@ public class DataTypeMerge6Test extends AbstractDataTypeMergeTest {
assertEquals(4, s.getComponent(1).getOffset()); assertEquals(4, s.getComponent(1).getOffset());
assertEquals(4, s.getComponent(0).getLength()); assertEquals(4, s.getComponent(0).getLength());
assertEquals(4, s.getComponent(1).getLength()); assertEquals(4, s.getComponent(1).getLength());
assertTrue(new PointerDataType(new FloatDataType()).isEquivalent( assertTrue(new PointerDataType(new FloatDataType())
s.getComponent(0).getDataType())); .isEquivalent(s.getComponent(0).getDataType()));
assertTrue(new FloatDataType().isEquivalent(s.getComponent(1).getDataType())); assertTrue(new FloatDataType().isEquivalent(s.getComponent(1).getDataType()));
} }
@ -1154,8 +1164,8 @@ public class DataTypeMerge6Test extends AbstractDataTypeMergeTest {
assertEquals(4, s1.getComponent(1).getOffset()); assertEquals(4, s1.getComponent(1).getOffset());
assertEquals(4, s1.getComponent(0).getLength()); assertEquals(4, s1.getComponent(0).getLength());
assertEquals(4, s1.getComponent(1).getLength()); assertEquals(4, s1.getComponent(1).getLength());
assertTrue(new PointerDataType(new FloatDataType()).isEquivalent( assertTrue(new PointerDataType(new FloatDataType())
s1.getComponent(0).getDataType())); .isEquivalent(s1.getComponent(0).getDataType()));
assertTrue(new FloatDataType().isEquivalent(s1.getComponent(1).getDataType())); assertTrue(new FloatDataType().isEquivalent(s1.getComponent(1).getDataType()));
Structure s2 = Structure s2 =

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -95,7 +95,7 @@ public class DataTypeMergeFixupTest extends AbstractDataTypeMergeTest {
} }
@Test @Test
public void testRemoveInnerAddOuterChangeInnerPickLatest() throws Exception { public void testRemoveInnerAddOuterChangeInnerPickLatest() throws Exception {
final CategoryPath rootPath = new CategoryPath("/"); final CategoryPath rootPath = new CategoryPath("/");
@ -105,25 +105,29 @@ public class DataTypeMergeFixupTest extends AbstractDataTypeMergeTest {
chooseOption(DataTypeMergeManager.OPTION_LATEST); chooseOption(DataTypeMergeManager.OPTION_LATEST);
dismissUnresolvedDataTypesPopup();
waitForCompletion(); waitForCompletion();
DataTypeManager dtm = resultProgram.getDataTypeManager(); DataTypeManager dtm = resultProgram.getDataTypeManager();
StructureInternal inner = (StructureInternal) dtm.getDataType(rootPath, "inner"); StructureInternal inner = (StructureInternal) dtm.getDataType(rootPath, "inner");
assertNull(inner); assertNull(inner);
StructureInternal outer = (StructureInternal) dtm.getDataType(rootPath, "outer"); StructureInternal outer = (StructureInternal) dtm.getDataType(rootPath, "outer");
assertNotNull(outer); assertNotNull(outer);
assertEquals(true, outer.isPackingEnabled()); //@formatter:off
assertEquals(true, outer.isDefaultAligned()); assertEquals("/outer\n" +
assertEquals(CompositeInternal.DEFAULT_ALIGNMENT, outer.getStoredMinimumAlignment()); "pack()\n" +
assertEquals(CompositeInternal.DEFAULT_PACKING, outer.getStoredPackingValue()); "Structure outer {\n" +
assertEquals(1, outer.getNumComponents()); " 0 byte 1 \"\"\n" +
assertTrue(new ByteDataType().isEquivalent(outer.getComponent(0).getDataType())); " 1 -BAD- 4 \"Failed to apply 'inner'\"\n" +
assertEquals(1, outer.getLength()); "}\n" +
assertEquals(1, outer.getAlignment()); "Length: 5 Alignment: 1\n", outer.toString());
//@formatter:on
} }
@Test @Test
public void testRemoveInnerAddOuterChangeInnerPickMy() throws Exception { public void testRemoveInnerAddOuterChangeInnerPickMy() throws Exception {
final CategoryPath rootPath = new CategoryPath("/"); final CategoryPath rootPath = new CategoryPath("/");
@ -163,7 +167,7 @@ public class DataTypeMergeFixupTest extends AbstractDataTypeMergeTest {
} }
@Test @Test
public void testRemoveInnerVsAddOuterContainingInner() throws Exception { public void testRemoveInnerVsAddOuterContainingInner() throws Exception {
final CategoryPath rootPath = new CategoryPath("/"); final CategoryPath rootPath = new CategoryPath("/");
@ -227,25 +231,29 @@ public class DataTypeMergeFixupTest extends AbstractDataTypeMergeTest {
executeMerge(); executeMerge();
dismissUnresolvedDataTypesPopup();
waitForCompletion(); waitForCompletion();
DataTypeManager dtm = resultProgram.getDataTypeManager(); DataTypeManager dtm = resultProgram.getDataTypeManager();
StructureInternal inner = (StructureInternal) dtm.getDataType(rootPath, "inner"); StructureInternal inner = (StructureInternal) dtm.getDataType(rootPath, "inner");
assertNull(inner); assertNull(inner);
StructureInternal outer = (StructureInternal) dtm.getDataType(rootPath, "outer"); StructureInternal outer = (StructureInternal) dtm.getDataType(rootPath, "outer");
assertNotNull(outer); assertNotNull(outer);
assertEquals(true, outer.isPackingEnabled()); //@formatter:off
assertEquals(true, outer.isDefaultAligned()); assertEquals("/outer\n" +
assertEquals(CompositeInternal.DEFAULT_ALIGNMENT, outer.getStoredMinimumAlignment()); "pack()\n" +
assertEquals(CompositeInternal.DEFAULT_PACKING, outer.getStoredPackingValue()); "Structure outer {\n" +
assertEquals(1, outer.getNumComponents()); " 0 byte 1 \"\"\n" +
assertTrue(new ByteDataType().isEquivalent(outer.getComponent(0).getDataType())); " 1 -BAD- 4 \"Failed to apply 'inner'\"\n" +
assertEquals(1, outer.getLength()); "}\n" +
assertEquals(1, outer.getAlignment()); "Length: 5 Alignment: 1\n", outer.toString());
//@formatter:on
} }
@Test @Test
public void testRemoveInnerVsAddOuterWithOtherAfterInner() throws Exception { public void testRemoveInnerVsAddOuterWithOtherAfterInner() throws Exception {
final CategoryPath rootPath = new CategoryPath("/"); final CategoryPath rootPath = new CategoryPath("/");
@ -293,7 +301,7 @@ public class DataTypeMergeFixupTest extends AbstractDataTypeMergeTest {
public void modifyLatest(ProgramDB program) throws Exception { public void modifyLatest(ProgramDB program) throws Exception {
DataTypeManager dtm = program.getDataTypeManager(); DataTypeManager dtm = program.getDataTypeManager();
Structure inner = (Structure) dtm.getDataType(rootPath, "inner"); Structure inner = (Structure) dtm.getDataType(rootPath, "inner");
// Remove inner struct // Remove inner struct
dtm.remove(inner, TaskMonitor.DUMMY); dtm.remove(inner, TaskMonitor.DUMMY);
} }
@ -323,6 +331,8 @@ public class DataTypeMergeFixupTest extends AbstractDataTypeMergeTest {
executeMerge(); executeMerge();
dismissUnresolvedDataTypesPopup();
waitForCompletion(); waitForCompletion();
DataTypeManager dtm = resultProgram.getDataTypeManager(); DataTypeManager dtm = resultProgram.getDataTypeManager();
@ -332,31 +342,30 @@ public class DataTypeMergeFixupTest extends AbstractDataTypeMergeTest {
StructureInternal other = (StructureInternal) dtm.getDataType(rootPath, "other"); StructureInternal other = (StructureInternal) dtm.getDataType(rootPath, "other");
assertNotNull(other); assertNotNull(other);
assertEquals(true, other.isPackingEnabled()); //@formatter:off
assertEquals(true, other.isDefaultAligned()); assertEquals("/other\n" +
assertEquals(CompositeInternal.DEFAULT_ALIGNMENT, other.getStoredMinimumAlignment()); "pack()\n" +
assertEquals(CompositeInternal.DEFAULT_PACKING, other.getStoredPackingValue()); "Structure other {\n" +
assertEquals(2, other.getNumComponents()); " 0 byte 1 \"\"\n" +
assertTrue(new ByteDataType().isEquivalent(other.getComponent(0).getDataType())); " 4 void * 4 \"\"\n" +
assertTrue(new PointerDataType(new VoidDataType()).isEquivalent( "}\n" +
other.getComponent(1).getDataType())); "Length: 8 Alignment: 4\n", other.toString());
assertEquals(8, other.getLength()); //@formatter:on
assertEquals(4, other.getAlignment());
StructureInternal outer = (StructureInternal) dtm.getDataType(rootPath, "outer"); StructureInternal outer = (StructureInternal) dtm.getDataType(rootPath, "outer");
assertNotNull(outer); assertNotNull(outer);
assertEquals(true, outer.isPackingEnabled()); //@formatter:off
assertEquals(true, outer.isDefaultAligned()); assertEquals("/outer\n" +
assertEquals(CompositeInternal.DEFAULT_ALIGNMENT, outer.getStoredMinimumAlignment()); "pack()\n" +
assertEquals(CompositeInternal.DEFAULT_PACKING, outer.getStoredPackingValue()); "Structure outer {\n" +
assertEquals(4, outer.getNumComponents()); " 0 byte 1 \"\"\n" +
assertTrue(new ByteDataType().isEquivalent(outer.getComponent(0).getDataType())); " 1 -BAD- 4 \"Failed to apply 'inner'\"\n" +
assertTrue(new FloatDataType().isEquivalent(outer.getComponent(1).getDataType())); " 8 float 4 \"\"\n" +
assertEquals(other, outer.getComponent(2).getDataType()); " 12 other 8 \"\"\n" +
assertTrue(new ByteDataType().isEquivalent(outer.getComponent(3).getDataType())); " 20 byte 1 \"\"\n" +
assertEquals(4, outer.getComponent(1).getLength()); "}\n" +
assertEquals(20, outer.getLength()); "Length: 24 Alignment: 4\n", outer.toString());
assertEquals(4, outer.getAlignment()); //@formatter:on
} }
} }

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -15,7 +15,7 @@
*/ */
package ghidra.app.merge.listing; package ghidra.app.merge.listing;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.*;
import org.junit.Test; import org.junit.Test;
@ -44,15 +44,8 @@ public class BookmarkMergerNoteTest extends AbstractListingMergeManagerTest {
@Override @Override
protected ProgramMultiUserMergeManager createMergeManager(ProgramChangeSet resultChangeSet, protected ProgramMultiUserMergeManager createMergeManager(ProgramChangeSet resultChangeSet,
ProgramChangeSet myChangeSet) { ProgramChangeSet myChangeSet) {
return new ProgramMultiUserMergeManager(resultProgram, myProgram, originalProgram,
// NOTE: this makes the tests faster. If you need visual debugging, then make this true latestProgram, resultChangeSet, myChangeSet);
boolean showListingPanels = false;
ProgramMultiUserMergeManager mergeManger =
new ProgramMultiUserMergeManager(resultProgram, myProgram, originalProgram,
latestProgram, resultChangeSet, myChangeSet, showListingPanels);
return mergeManger;
} }
@Test @Test

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -74,15 +74,8 @@ public class ExternalMergerAddTest extends AbstractExternalMergerTest {
@Override @Override
protected ProgramMultiUserMergeManager createMergeManager(ProgramChangeSet resultChangeSet, protected ProgramMultiUserMergeManager createMergeManager(ProgramChangeSet resultChangeSet,
ProgramChangeSet myChangeSet) { ProgramChangeSet myChangeSet) {
return new ProgramMultiUserMergeManager(resultProgram, myProgram, originalProgram,
// NOTE: this makes the tests faster. If you need visual debugging, then make this true latestProgram, resultChangeSet, myChangeSet);
boolean showListingPanels = false;
ProgramMultiUserMergeManager mergeManger =
new ProgramMultiUserMergeManager(resultProgram, myProgram, originalProgram,
latestProgram, resultChangeSet, myChangeSet, showListingPanels);
return mergeManger;
} }
@Test @Test
@ -2103,8 +2096,9 @@ public class ExternalMergerAddTest extends AbstractExternalMergerTest {
Namespace externalLibrary = Namespace externalLibrary =
(Namespace) resultProgram.getSymbolTable().getLibrarySymbol(libname).getObject(); (Namespace) resultProgram.getSymbolTable().getLibrarySymbol(libname).getObject();
Namespace myNamespace = (Namespace) getUniqueSymbol(resultProgram, parentNamespace, Namespace myNamespace =
externalLibrary).getObject(); (Namespace) getUniqueSymbol(resultProgram, parentNamespace, externalLibrary)
.getObject();
Symbol blue = getUniqueSymbol(resultProgram, namespace1, myNamespace); Symbol blue = getUniqueSymbol(resultProgram, namespace1, myNamespace);
Symbol blueConflict = Symbol blueConflict =
getUniqueSymbol(resultProgram, namespace1 + "_conflict1", myNamespace); getUniqueSymbol(resultProgram, namespace1 + "_conflict1", myNamespace);
@ -2167,8 +2161,9 @@ public class ExternalMergerAddTest extends AbstractExternalMergerTest {
Namespace externalLibrary = Namespace externalLibrary =
(Namespace) resultProgram.getSymbolTable().getLibrarySymbol(libname).getObject(); (Namespace) resultProgram.getSymbolTable().getLibrarySymbol(libname).getObject();
assertNotNull(externalLibrary); assertNotNull(externalLibrary);
Namespace myNamespace = (Namespace) getUniqueSymbol(resultProgram, parentNamespace, Namespace myNamespace =
externalLibrary).getObject(); (Namespace) getUniqueSymbol(resultProgram, parentNamespace, externalLibrary)
.getObject();
assertNotNull(myNamespace); assertNotNull(myNamespace);
Symbol apples = getUniqueSymbol(resultProgram, label, myNamespace); Symbol apples = getUniqueSymbol(resultProgram, label, myNamespace);
Symbol applesConflict = getUniqueSymbol(resultProgram, label + "_conflict1", myNamespace); Symbol applesConflict = getUniqueSymbol(resultProgram, label + "_conflict1", myNamespace);
@ -2221,8 +2216,9 @@ public class ExternalMergerAddTest extends AbstractExternalMergerTest {
Namespace externalLibrary = Namespace externalLibrary =
(Namespace) resultProgram.getSymbolTable().getLibrarySymbol(libname).getObject(); (Namespace) resultProgram.getSymbolTable().getLibrarySymbol(libname).getObject();
assertNotNull(externalLibrary); assertNotNull(externalLibrary);
Namespace myNamespace = (Namespace) getUniqueSymbol(resultProgram, parentNamespace, Namespace myNamespace =
externalLibrary).getObject(); (Namespace) getUniqueSymbol(resultProgram, parentNamespace, externalLibrary)
.getObject();
assertNotNull(myNamespace); assertNotNull(myNamespace);
Symbol apples = getUniqueSymbol(resultProgram, label1, myNamespace); Symbol apples = getUniqueSymbol(resultProgram, label1, myNamespace);
Symbol oranges = getUniqueSymbol(resultProgram, label2, myNamespace); Symbol oranges = getUniqueSymbol(resultProgram, label2, myNamespace);
@ -2296,8 +2292,9 @@ public class ExternalMergerAddTest extends AbstractExternalMergerTest {
Namespace externalLibrary = Namespace externalLibrary =
(Namespace) resultProgram.getSymbolTable().getLibrarySymbol(libname).getObject(); (Namespace) resultProgram.getSymbolTable().getLibrarySymbol(libname).getObject();
assertNotNull(externalLibrary); assertNotNull(externalLibrary);
Namespace myNamespace = (Namespace) getUniqueSymbol(resultProgram, parentNamespace, Namespace myNamespace =
externalLibrary).getObject(); (Namespace) getUniqueSymbol(resultProgram, parentNamespace, externalLibrary)
.getObject();
assertNotNull(myNamespace); assertNotNull(myNamespace);
Symbol apples = getUniqueSymbol(resultProgram, label, myNamespace); Symbol apples = getUniqueSymbol(resultProgram, label, myNamespace);
Symbol applesConflict = getUniqueSymbol(resultProgram, label + "_conflict1", myNamespace); Symbol applesConflict = getUniqueSymbol(resultProgram, label + "_conflict1", myNamespace);
@ -2361,8 +2358,9 @@ public class ExternalMergerAddTest extends AbstractExternalMergerTest {
Namespace externalLibrary = Namespace externalLibrary =
(Namespace) resultProgram.getSymbolTable().getLibrarySymbol(libname).getObject(); (Namespace) resultProgram.getSymbolTable().getLibrarySymbol(libname).getObject();
assertNotNull(externalLibrary); assertNotNull(externalLibrary);
Namespace myNamespace = (Namespace) getUniqueSymbol(resultProgram, parentNamespace, Namespace myNamespace =
externalLibrary).getObject(); (Namespace) getUniqueSymbol(resultProgram, parentNamespace, externalLibrary)
.getObject();
assertNotNull(myNamespace); assertNotNull(myNamespace);
Symbol apples = getUniqueSymbol(resultProgram, label, myNamespace); Symbol apples = getUniqueSymbol(resultProgram, label, myNamespace);
Symbol applesConflict = getUniqueSymbol(resultProgram, label + "_conflict1", myNamespace); Symbol applesConflict = getUniqueSymbol(resultProgram, label + "_conflict1", myNamespace);
@ -2501,8 +2499,9 @@ public class ExternalMergerAddTest extends AbstractExternalMergerTest {
Namespace externalLibrary = Namespace externalLibrary =
(Namespace) resultProgram.getSymbolTable().getLibrarySymbol(libname).getObject(); (Namespace) resultProgram.getSymbolTable().getLibrarySymbol(libname).getObject();
assertNotNull(externalLibrary); assertNotNull(externalLibrary);
Namespace myNamespace = (Namespace) getUniqueSymbol(resultProgram, parentNamespace, Namespace myNamespace =
externalLibrary).getObject(); (Namespace) getUniqueSymbol(resultProgram, parentNamespace, externalLibrary)
.getObject();
assertNotNull(myNamespace); assertNotNull(myNamespace);
Symbol apples = getUniqueSymbol(resultProgram, label, myNamespace); Symbol apples = getUniqueSymbol(resultProgram, label, myNamespace);
Symbol applesConflict = getUniqueSymbol(resultProgram, label + "_conflict1", myNamespace); Symbol applesConflict = getUniqueSymbol(resultProgram, label + "_conflict1", myNamespace);
@ -2585,8 +2584,9 @@ public class ExternalMergerAddTest extends AbstractExternalMergerTest {
Namespace externalLibrary = Namespace externalLibrary =
(Namespace) resultProgram.getSymbolTable().getLibrarySymbol(libname).getObject(); (Namespace) resultProgram.getSymbolTable().getLibrarySymbol(libname).getObject();
assertNotNull(externalLibrary); assertNotNull(externalLibrary);
Namespace myNamespace = (Namespace) getUniqueSymbol(resultProgram, parentNamespace, Namespace myNamespace =
externalLibrary).getObject(); (Namespace) getUniqueSymbol(resultProgram, parentNamespace, externalLibrary)
.getObject();
assertNotNull(myNamespace); assertNotNull(myNamespace);
Symbol apples = getUniqueSymbol(resultProgram, label, myNamespace); Symbol apples = getUniqueSymbol(resultProgram, label, myNamespace);
Symbol applesConflict = getUniqueSymbol(resultProgram, label + "_conflict1", myNamespace); Symbol applesConflict = getUniqueSymbol(resultProgram, label + "_conflict1", myNamespace);
@ -2780,8 +2780,9 @@ public class ExternalMergerAddTest extends AbstractExternalMergerTest {
Namespace externalLibrary = Namespace externalLibrary =
(Namespace) resultProgram.getSymbolTable().getLibrarySymbol(libname).getObject(); (Namespace) resultProgram.getSymbolTable().getLibrarySymbol(libname).getObject();
assertNotNull(externalLibrary); assertNotNull(externalLibrary);
Namespace myNamespace = (Namespace) getUniqueSymbol(resultProgram, parentNamespace, Namespace myNamespace =
externalLibrary).getObject(); (Namespace) getUniqueSymbol(resultProgram, parentNamespace, externalLibrary)
.getObject();
assertNotNull(myNamespace); assertNotNull(myNamespace);
Symbol apples = getUniqueSymbol(resultProgram, label, myNamespace); Symbol apples = getUniqueSymbol(resultProgram, label, myNamespace);
Symbol applesConflict = getUniqueSymbol(resultProgram, label + "_conflict1", myNamespace); Symbol applesConflict = getUniqueSymbol(resultProgram, label + "_conflict1", myNamespace);
@ -2863,8 +2864,9 @@ public class ExternalMergerAddTest extends AbstractExternalMergerTest {
Namespace externalLibrary = Namespace externalLibrary =
(Namespace) resultProgram.getSymbolTable().getLibrarySymbol(libname).getObject(); (Namespace) resultProgram.getSymbolTable().getLibrarySymbol(libname).getObject();
assertNotNull(externalLibrary); assertNotNull(externalLibrary);
Namespace myNamespace = (Namespace) getUniqueSymbol(resultProgram, parentNamespace, Namespace myNamespace =
externalLibrary).getObject(); (Namespace) getUniqueSymbol(resultProgram, parentNamespace, externalLibrary)
.getObject();
assertNotNull(myNamespace); assertNotNull(myNamespace);
Symbol apples = getUniqueSymbol(resultProgram, label, myNamespace); Symbol apples = getUniqueSymbol(resultProgram, label, myNamespace);
Symbol applesConflict = getUniqueSymbol(resultProgram, label + "_conflict1", myNamespace); Symbol applesConflict = getUniqueSymbol(resultProgram, label + "_conflict1", myNamespace);
@ -2948,8 +2950,9 @@ public class ExternalMergerAddTest extends AbstractExternalMergerTest {
Namespace externalLibrary = Namespace externalLibrary =
(Namespace) resultProgram.getSymbolTable().getLibrarySymbol(libname).getObject(); (Namespace) resultProgram.getSymbolTable().getLibrarySymbol(libname).getObject();
assertNotNull(externalLibrary); assertNotNull(externalLibrary);
Namespace myNamespace = (Namespace) getUniqueSymbol(resultProgram, parentNamespace, Namespace myNamespace =
externalLibrary).getObject(); (Namespace) getUniqueSymbol(resultProgram, parentNamespace, externalLibrary)
.getObject();
List<Symbol> symbols = symbolTable.getSymbols(label, myNamespace); List<Symbol> symbols = symbolTable.getSymbols(label, myNamespace);
assertEquals(2, symbols.size()); assertEquals(2, symbols.size());

View file

@ -84,9 +84,9 @@ public class StructureEditorNotifiedTest extends AbstractStructureEditorTest {
init(complexStructure, tempCat); init(complexStructure, tempCat);
int num = model.getNumComponents(); int num = model.getNumComponents();
int len = model.getLength(); int len = model.getLength();
DataType dataType10 = model.viewComposite.getComponent(10).getDataType(); DataType dataType10 = getDataType(10);
assertEquals("complexStructure *", dataType10.getDisplayName()); assertEquals("complexStructure *", dataType10.getDisplayName());
assertEquals(4, dataType10.getLength()); assertEquals(4, getLength(10));
programDTM.remove(complexStructure, TaskMonitor.DUMMY); programDTM.remove(complexStructure, TaskMonitor.DUMMY);
programDTM.getCategory(pgmRootCat.getCategoryPath()) programDTM.getCategory(pgmRootCat.getCategoryPath())
@ -97,12 +97,12 @@ public class StructureEditorNotifiedTest extends AbstractStructureEditorTest {
waitForSwing(); waitForSwing();
// complexStructure* gets removed and becomes 4 undefined bytes in this editor. // complexStructure* gets removed and becomes BadDataType in this editor.
assertEquals(num + 3, model.getNumComponents()); assertEquals(num, model.getNumComponents());
assertEquals(len, model.getLength()); assertEquals(len, model.getLength());
dataType10 = model.viewComposite.getComponent(10).getDataType(); assertTrue(BadDataType.dataType.isEquivalent(getDataType(10)));
assertEquals("undefined", dataType10.getDisplayName()); assertEquals("Type 'complexStructure *' was deleted", getComment(10));
assertEquals(1, dataType10.getLength()); assertEquals(4, getLength(10));
} }
@Test @Test
@ -498,25 +498,31 @@ public class StructureEditorNotifiedTest extends AbstractStructureEditorTest {
DataType dt10 = getDataType(complexStructure, 10); DataType dt10 = getDataType(complexStructure, 10);
init(complexStructure, pgmTestCat); init(complexStructure, pgmTestCat);
DataType undef = DataType.DEFAULT;
assertEquals(1, getLength(9)); // length start-off wierd - not sure why
assertEquals(23, model.getNumComponents()); assertEquals(23, model.getNumComponents());
assertEquals(0x145, model.getLength());
runSwing( runSwing(
() -> complexStructure.getDataTypeManager().remove(simpleUnion, TaskMonitor.DUMMY)); () -> complexStructure.getDataTypeManager().remove(simpleUnion, TaskMonitor.DUMMY));
waitForSwing(); waitForSwing();
assertEquals(30, model.getNumComponents()); assertEquals(23, model.getNumComponents());
assertTrue(dt3.isEquivalent(getDataType(3))); assertTrue(dt3.isEquivalent(getDataType(3)));
assertTrue(undef.isEquivalent(getDataType(4)));
assertTrue(undef.isEquivalent(getDataType(11)));
assertTrue(dt5.isEquivalent(getDataType(12)));
assertTrue(dt8.isEquivalent(getDataType(15)));
assertTrue(undef.isEquivalent(getDataType(16)));
assertTrue(dt10.isEquivalent(getDataType(17)));
assertEquals(4, getOffset(3)); assertEquals(4, getOffset(3));
assertEquals(16, getOffset(12)); assertEquals(0x8, getLength(4));
assertEquals(24, getOffset(15)); assertTrue(BadDataType.dataType.isEquivalent(getDataType(4)));
assertEquals(33, getOffset(17)); assertEquals("Type 'simpleUnion' was deleted", getComment(4));
assertTrue(dt5.isEquivalent(getDataType(5)));
assertTrue(dt8.isEquivalent(getDataType(8)));
assertEquals(0x20, getOffset(9));
assertEquals(1, getLength(9)); // length start-off wierd
assertTrue(BadDataType.dataType.isEquivalent(getDataType(9)));
assertEquals("Type 'simpleUnion *' was deleted", getComment(9));
assertEquals(0x21, getOffset(10));
assertEquals(0x4, getLength(10));
assertTrue(dt10.isEquivalent(getDataType(10)));
assertEquals(0x145, model.getLength());
} }
@Test @Test
@ -525,12 +531,17 @@ public class StructureEditorNotifiedTest extends AbstractStructureEditorTest {
runSwingWithException(() -> model.add(simpleStructure)); runSwingWithException(() -> model.add(simpleStructure));
waitForSwing(); waitForSwing();
assertEquals(1, model.getNumComponents());
assertTrue(simpleStructure.isEquivalent(getDataType(0))); assertTrue(simpleStructure.isEquivalent(getDataType(0)));
runSwing( runSwing(
() -> simpleStructure.getDataTypeManager().remove(simpleStructure, TaskMonitor.DUMMY)); () -> simpleStructure.getDataTypeManager().remove(simpleStructure, TaskMonitor.DUMMY));
waitForSwing(); waitForSwing();
assertEquals(29, model.getNumComponents());// becomes undefined bytes
assertEquals(1, model.getNumComponents());// component becomes BadDataType
assertTrue(BadDataType.dataType.isEquivalent(getDataType(0)));
assertEquals("Type 'simpleStructure' was deleted", getComment(0));
} }
@Test @Test

View file

@ -299,14 +299,26 @@ public class StructureEditorProviderTest extends AbstractStructureEditorTest {
dialog = getWindow("Close Structure Editor?"); dialog = getWindow("Close Structure Editor?");
assertNull(dialog); assertNull(dialog);
// Verify the editor provider remains visible with myStructure use converted to BadDataType.
assertEquals(1, model.viewComposite.getNumComponents());
assertEquals(1, model.viewComposite.getNumDefinedComponents());
DataTypeComponent dtc = model.viewComposite.getComponent(0);
assertTrue(BadDataType.dataType.isEquivalent(dtc.getDataType()));
assertEquals(2, dtc.getLength());
runSwing(() -> {
model.deleteComponent(0);
});
waitForSwing();
assertTrue( assertTrue(
isProviderShown(tool.getToolFrame(), "Structure Editor", "emptyStructure (Test)")); isProviderShown(tool.getToolFrame(), "Structure Editor", "emptyStructure (Test)"));
// Verify the editor provider remains visible with myStructure use cleared. // Verify the editor provider remains visible with BadDataType use cleared.
assertFalse(emptyStructure.isEquivalent(model.viewComposite)); assertTrue(emptyStructure.isEquivalent(model.viewComposite));
assertFalse(dtCopy.isEquivalent(model.viewComposite)); assertFalse(dtCopy.isEquivalent(model.viewComposite));
assertEquals(dtCopy.getLength(), model.viewComposite.getLength()); assertTrue(model.viewComposite.isZeroLength());
assertEquals(2, model.viewComposite.getNumComponents()); assertEquals(0, model.viewComposite.getNumComponents());
assertEquals(0, model.viewComposite.getNumDefinedComponents()); assertEquals(0, model.viewComposite.getNumDefinedComponents());
} }

View file

@ -109,6 +109,8 @@ public class UnionEditorNotifiedTest extends AbstractUnionEditorTest {
init(complexUnion, tempCat, false); init(complexUnion, tempCat, false);
int num = model.getNumComponents(); int num = model.getNumComponents();
int len = model.getLength();
// Clone the data types we want to hold onto for comparison later, since reload can close the viewDTM. // Clone the data types we want to hold onto for comparison later, since reload can close the viewDTM.
DataType dt18 = getDataType(18).clone(programDTM); DataType dt18 = getDataType(18).clone(programDTM);
DataType dt20 = getDataType(20).clone(programDTM); DataType dt20 = getDataType(20).clone(programDTM);
@ -128,9 +130,13 @@ public class UnionEditorNotifiedTest extends AbstractUnionEditorTest {
dialog = null; dialog = null;
// refUnion* gets removed // refUnion* gets removed
assertEquals(num - 1, model.getNumComponents()); assertEquals(num, model.getNumComponents());
assertEquals(len, model.getLength());
assertTrue(dt18.isEquivalent(getDataType(18))); assertTrue(dt18.isEquivalent(getDataType(18)));
assertTrue(dt20.isEquivalent(getDataType(19))); assertEquals(4, getLength(19));
assertTrue(BadDataType.dataType.isEquivalent(getDataType(19)));
assertEquals("Type 'refUnion *' was deleted", getComment(19));
assertTrue(dt20.isEquivalent(getDataType(20)));
} }
@Test @Test
@ -303,10 +309,38 @@ public class UnionEditorNotifiedTest extends AbstractUnionEditorTest {
init(complexUnion, pgmTestCat, false); init(complexUnion, pgmTestCat, false);
assertEquals(21, model.getNumComponents()); assertEquals(21, model.getNumComponents());
assertEquals(4, getLength(5));
assertEquals(0x57, getLength(12));
assertEquals(0x38, getLength(13));
assertEquals(0x1d, getLength(15));
assertEquals(0x18, getLength(17));
assertEquals(0x1d, getLength(20));
assertEquals(21, model.getNumComponents());
assertEquals(0x57, model.getLength());
SwingUtilities.invokeLater( SwingUtilities.invokeLater(
() -> complexUnion.getDataTypeManager().remove(simpleStructure, TaskMonitor.DUMMY)); () -> complexUnion.getDataTypeManager().remove(simpleStructure, TaskMonitor.DUMMY));
waitForSwing(); waitForSwing();
assertEquals(15, model.getNumComponents());
assertEquals(21, model.getNumComponents());
assertEquals(4, getLength(5));
assertEquals(0x57, getLength(12));
assertTrue(BadDataType.dataType.isEquivalent(getDataType(12)));
assertEquals("Type 'simpleStructure[3]' was deleted", getComment(12));
assertEquals(0x38, getLength(13));
assertTrue(BadDataType.dataType.isEquivalent(getDataType(13)));
assertEquals("Type 'simpleStructure *[7]' was deleted", getComment(13));
assertEquals(0x1d, getLength(15));
assertTrue(BadDataType.dataType.isEquivalent(getDataType(15)));
assertEquals("Type 'simpleStructureTypedef' was deleted", getComment(15));
assertEquals(0x18, getLength(17));
assertTrue(BadDataType.dataType.isEquivalent(getDataType(17)));
assertEquals("Type 'simpleStructureTypedef * *[2][3]' was deleted", getComment(17));
assertEquals(0x1d, getLength(20));
assertTrue(BadDataType.dataType.isEquivalent(getDataType(20)));
assertEquals("Type 'simpleStructure' was deleted", getComment(20));
assertEquals(21, model.getNumComponents());
assertEquals(0x57, model.getLength());
} }
@Test @Test
@ -322,12 +356,20 @@ public class UnionEditorNotifiedTest extends AbstractUnionEditorTest {
} }
}); });
waitForSwing(); waitForSwing();
assertEquals(1, model.getNumComponents());
assertTrue(simpleUnion.isEquivalent(getDataType(0))); assertTrue(simpleUnion.isEquivalent(getDataType(0)));
assertEquals(8, getLength(0));
assertEquals(8, model.getLength());
SwingUtilities.invokeLater( SwingUtilities.invokeLater(
() -> simpleUnion.getDataTypeManager().remove(simpleUnion, TaskMonitor.DUMMY)); () -> simpleUnion.getDataTypeManager().remove(simpleUnion, TaskMonitor.DUMMY));
waitForSwing(); waitForSwing();
assertEquals(0, model.getNumComponents());
assertEquals(1, model.getNumComponents());
assertTrue(BadDataType.dataType.isEquivalent(getDataType(0)));
assertEquals("Type 'simpleUnion' was deleted", getComment(0));
assertEquals(8, getLength(0));
assertEquals(8, model.getLength());
} }
@Test @Test
@ -335,6 +377,7 @@ public class UnionEditorNotifiedTest extends AbstractUnionEditorTest {
init(complexUnion, pgmTestCat, false); init(complexUnion, pgmTestCat, false);
int num = model.getNumComponents(); int num = model.getNumComponents();
int len = model.getLength();
// Clone the data types we want to hold onto for comparison later, since reload can close the viewDTM. // Clone the data types we want to hold onto for comparison later, since reload can close the viewDTM.
DataType dt18 = getDataType(18).clone(programDTM); DataType dt18 = getDataType(18).clone(programDTM);
@ -347,19 +390,38 @@ public class UnionEditorNotifiedTest extends AbstractUnionEditorTest {
SwingUtilities.invokeLater(() -> dtm.remove(refUnion, TaskMonitor.DUMMY)); // remove refUnion SwingUtilities.invokeLater(() -> dtm.remove(refUnion, TaskMonitor.DUMMY)); // remove refUnion
waitForSwing(); waitForSwing();
// refUnion* gets removed (1 component) // refUnion* gets removed
num -= 1; assertEquals(len, model.getLength());
assertEquals(num, model.getNumComponents()); assertEquals(num, model.getNumComponents());
assertEquals(1, getLength(8)); // weird length
assertTrue(dt18.isEquivalent(getDataType(18))); assertTrue(dt18.isEquivalent(getDataType(18)));
assertTrue(dt20.isEquivalent(getDataType(19))); assertEquals(4, getLength(19));
assertTrue(BadDataType.dataType.isEquivalent(getDataType(19)));
assertEquals("Type 'refUnion *' was deleted", getComment(19));
assertTrue(dt20.isEquivalent(getDataType(20)));
SwingUtilities.invokeLater( SwingUtilities.invokeLater(
() -> simpleUnion.getDataTypeManager().remove(simpleUnion, TaskMonitor.DUMMY)); () -> simpleUnion.getDataTypeManager().remove(simpleUnion, TaskMonitor.DUMMY));
waitForSwing(); waitForSwing();
// All components (3 total) which were dependent upon simpleUnion are removed assertEquals(len, model.getLength());
num -= 3;
assertEquals(num, model.getNumComponents()); assertEquals(num, model.getNumComponents());
assertEquals(8, getLength(3));
assertTrue(BadDataType.dataType.isEquivalent(getDataType(3)));
assertEquals("Type 'simpleUnion' was deleted", getComment(3));
assertEquals(1, getLength(8)); // length was weird to start with
assertTrue(BadDataType.dataType.isEquivalent(getDataType(8)));
assertEquals("Type 'simpleUnion *' was deleted", getComment(8));
assertEquals(8, getLength(16));
assertTrue(BadDataType.dataType.isEquivalent(getDataType(16)));
assertEquals("Type 'simpleUnionTypedef' was deleted", getComment(16));
assertEquals(4, getLength(19));
assertTrue(BadDataType.dataType.isEquivalent(getDataType(19)));
assertEquals("Type 'refUnion *' was deleted", getComment(19));
} }
@Test @Test

View file

@ -573,9 +573,30 @@ public class CategoryTest extends AbstractGhidraHeadedIntegrationTest {
DataType cdt = root.getDataType("InnerStruct"); DataType cdt = root.getDataType("InnerStruct");
assertNotNull(cdt); assertNotNull(cdt);
//@formatter:off
assertEquals("/SubCat-A/Sub-cat/MyStruct\n" + "pack(disabled)\n" +
"Structure MyStruct {\n" +
" 0 byte 1 \"\"\n" +
" 1 word 2 \"\"\n" +
" 3 byte 1 \"\"\n" +
" 4 InnerStruct 31 \"\"\n" +
"}\n" +
"Length: 135 Alignment: 1\n", newDt.toString());
//@formatter:on
root.remove(cdt, monitor); root.remove(cdt, monitor);
assertEquals(comps.length - 1, newDt.getDefinedComponents().length); //@formatter:off
assertEquals("/SubCat-A/Sub-cat/MyStruct\n" +
"pack(disabled)\n" +
"Structure MyStruct {\n" +
" 0 byte 1 \"\"\n" +
" 1 word 2 \"\"\n" +
" 3 byte 1 \"\"\n" +
" 4 -BAD- 31 \"Type 'InnerStruct' was deleted\"\n" +
"}\n" +
"Length: 135 Alignment: 1\n", newDt.toString());
//@formatter:on
} }
@Test @Test

View file

@ -23,6 +23,7 @@ import org.apache.commons.compress.utils.Sets;
import org.junit.*; import org.junit.*;
import generic.test.AbstractGenericTest; import generic.test.AbstractGenericTest;
import ghidra.util.task.TaskMonitorAdapter;
public class StructureDataTypeTest extends AbstractGenericTest { public class StructureDataTypeTest extends AbstractGenericTest {
@ -1043,40 +1044,40 @@ public class StructureDataTypeTest extends AbstractGenericTest {
assertEquals(10, comps[3].getOffset()); assertEquals(10, comps[3].getOffset());
assertEquals(7, comps[3].getOrdinal()); assertEquals(7, comps[3].getOrdinal());
} }
@Test @Test
public void testSetLength() { public void testSetLength() {
assertEquals(8, struct.getLength()); assertEquals(8, struct.getLength());
assertEquals(4, struct.getNumComponents()); assertEquals(4, struct.getNumComponents());
assertEquals(4, struct.getNumDefinedComponents()); assertEquals(4, struct.getNumDefinedComponents());
struct.setLength(20); struct.setLength(20);
assertEquals(20, struct.getLength()); assertEquals(20, struct.getLength());
assertEquals(16, struct.getNumComponents()); assertEquals(16, struct.getNumComponents());
assertEquals(4, struct.getNumDefinedComponents()); assertEquals(4, struct.getNumDefinedComponents());
// new length is offcut within 3rd component at offset 0x3 which should get cleared // new length is offcut within 3rd component at offset 0x3 which should get cleared
struct.setLength(4); struct.setLength(4);
assertEquals(4, struct.getLength()); assertEquals(4, struct.getLength());
assertEquals(3, struct.getNumComponents()); assertEquals(3, struct.getNumComponents());
assertEquals(2, struct.getNumDefinedComponents()); assertEquals(2, struct.getNumDefinedComponents());
// Maximum length supported by GUI editor is ~Integer.MAX_VALUE/10 // Maximum length supported by GUI editor is ~Integer.MAX_VALUE/10
int len = Integer.MAX_VALUE / 10; int len = Integer.MAX_VALUE / 10;
struct.setLength(len); struct.setLength(len);
assertEquals(len, struct.getLength()); assertEquals(len, struct.getLength());
assertEquals(len - 1, struct.getNumComponents()); assertEquals(len - 1, struct.getNumComponents());
assertEquals(2, struct.getNumDefinedComponents()); assertEquals(2, struct.getNumDefinedComponents());
len /= 2; len /= 2;
struct.replaceAtOffset(len-2, WordDataType.dataType, -1, "x", null); // will be preserved below struct.replaceAtOffset(len - 2, WordDataType.dataType, -1, "x", null); // will be preserved below
struct.replaceAtOffset(len+2, WordDataType.dataType, -1, "y", null); // will be cleared below struct.replaceAtOffset(len + 2, WordDataType.dataType, -1, "y", null); // will be cleared below
struct.setLength(len); struct.setLength(len);
assertEquals(len, struct.getLength()); assertEquals(len, struct.getLength());
assertEquals(len - 2, struct.getNumComponents()); assertEquals(len - 2, struct.getNumComponents());
assertEquals(3, struct.getNumDefinedComponents()); assertEquals(3, struct.getNumDefinedComponents());
} }
@Test @Test
@ -1393,15 +1394,34 @@ public class StructureDataTypeTest extends AbstractGenericTest {
struct.add(s); struct.add(s);
DataTypeComponent[] dtc = struct.getComponents(); //@formatter:off
assertEquals(5, dtc.length); CompositeTestUtils.assertExpectedComposite(this, "/TestStruct\n" +
"pack(disabled)\n" +
"Structure TestStruct {\n" +
" 0 byte 1 field1 \"Comment1\"\n" +
" 1 word 2 \"Comment2\"\n" +
" 3 dword 4 field3 \"\"\n" +
" 7 byte 1 field4 \"Comment4\"\n" +
" 8 test1 5 \"\"\n" +
"}\n" +
"Length: 13 Alignment: 1", struct);
//@formatter:on
struct.dataTypeDeleted(s); struct.dataTypeDeleted(s);
dtc = struct.getComponents(); //@formatter:off
assertEquals(9, dtc.length); CompositeTestUtils.assertExpectedComposite(this, "/TestStruct\n" +
"pack(disabled)\n" +
"Structure TestStruct {\n" +
" 0 byte 1 field1 \"Comment1\"\n" +
" 1 word 2 \"Comment2\"\n" +
" 3 dword 4 field3 \"\"\n" +
" 7 byte 1 field4 \"Comment4\"\n" +
" 8 -BAD- 5 \"\"\n" +
"}\n" +
"Length: 13 Alignment: 1", struct);
//@formatter:on
assertEquals(9, struct.getNumComponents());
} }
@Test @Test

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -56,7 +56,8 @@ class BitFieldDBDataType extends BitFieldDataType {
* bit size may be reduced based upon the specified base datatype size. * bit size may be reduced based upon the specified base datatype size.
* @param bitOffset right shift factor within storage unit when viewed as a big-endian dd * @param bitOffset right shift factor within storage unit when viewed as a big-endian dd
* scalar value. Based upon minimal storage bitOffset should be in the range 0 to 7. * scalar value. Based upon minimal storage bitOffset should be in the range 0 to 7.
* @throws InvalidDataTypeException * @throws InvalidDataTypeException if invalid base datatype has been specified or an
* invalid bitSize or bitOffset has been specified
*/ */
BitFieldDBDataType(DataType baseDataType, int bitSize, int bitOffset) BitFieldDBDataType(DataType baseDataType, int bitSize, int bitOffset)
throws InvalidDataTypeException { throws InvalidDataTypeException {
@ -66,6 +67,7 @@ class BitFieldDBDataType extends BitFieldDataType {
private static enum BaseDatatypeKind { private static enum BaseDatatypeKind {
NONE(0), TYPEDEF(1), ENUM(2), INTEGER(3); NONE(0), TYPEDEF(1), ENUM(2), INTEGER(3);
final int id; final int id;
BaseDatatypeKind(int id) { BaseDatatypeKind(int id) {

View file

@ -156,25 +156,23 @@ abstract class CompositeDB extends DataTypeDB implements CompositeInternal {
* @param oldDt affected datatype which has been removed or replaced * @param oldDt affected datatype which has been removed or replaced
* @param newDt replacement datatype * @param newDt replacement datatype
* @return true if bitfield component was modified * @return true if bitfield component was modified
* @throws InvalidDataTypeException if bitfield was based upon oldDt but new
* datatype is invalid for a bitfield
*/ */
protected boolean updateBitFieldDataType(DataTypeComponentDB bitfieldComponent, DataType oldDt, protected boolean updateBitFieldDataType(DataTypeComponentDB bitfieldComponent, DataType oldDt,
DataType newDt) throws InvalidDataTypeException { DataType newDt) {
if (!bitfieldComponent.isBitFieldComponent()) { if (!bitfieldComponent.isBitFieldComponent()) {
throw new AssertException("expected bitfield component"); throw new AssertException("expected bitfield component");
} }
BitFieldDBDataType bitfieldDt = (BitFieldDBDataType) bitfieldComponent.getDataType(); BitFieldDBDataType bitfieldDt = (BitFieldDBDataType) bitfieldComponent.getDataType();
if (bitfieldDt.getBaseDataType() != oldDt) { if (bitfieldDt.getBaseDataType() != oldDt || !BitFieldDataType.isValidBaseDataType(newDt)) {
return false; return false;
} }
if (newDt != null) { if (newDt != null) {
BitFieldDataType.checkBaseDataType(newDt);
int maxBitSize = 8 * newDt.getLength(); int maxBitSize = 8 * newDt.getLength();
if (bitfieldDt.getBitSize() > maxBitSize) { if (bitfieldDt.getBitSize() > maxBitSize) {
throw new InvalidDataTypeException("Replacement datatype too small for bitfield"); // Replacement datatype too small for bitfield
return false;
} }
} }
@ -186,7 +184,7 @@ abstract class CompositeDB extends DataTypeDB implements CompositeInternal {
newDt.addParent(this); newDt.addParent(this);
} }
catch (InvalidDataTypeException e) { catch (InvalidDataTypeException e) {
throw new AssertException("unexpected"); throw new AssertException(e); // unexpected
} }
return true; return true;

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -19,6 +19,8 @@ import java.io.IOException;
import java.net.URL; import java.net.URL;
import java.util.Collection; import java.util.Collection;
import org.apache.commons.lang3.StringUtils;
import db.DBRecord; import db.DBRecord;
import ghidra.docking.settings.*; import ghidra.docking.settings.*;
import ghidra.program.database.DBObjectCache; import ghidra.program.database.DBObjectCache;
@ -614,4 +616,12 @@ abstract class DataTypeDB extends DatabaseObject implements DataType {
return existingDataType.isEquivalent(otherDataType); return existingDataType.isEquivalent(otherDataType);
} }
static String prependComment(String additionalComment, String oldComment) {
String comment = additionalComment;
if (!StringUtils.isBlank(oldComment)) {
comment += "; " + oldComment;
}
return comment;
}
} }

View file

@ -156,6 +156,13 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
private LinkedList<Pair<DataType, DataType>> typesToReplace = new LinkedList<>(); private LinkedList<Pair<DataType, DataType>> typesToReplace = new LinkedList<>();
private List<DataType> favoritesList = new ArrayList<>(); private List<DataType> favoritesList = new ArrayList<>();
/**
* Set of {@link AbstractIntegerDataType} IDs whose removal has been blocked
* to allow persistence of defined bitfields.
* See {@link #blockDataTypeRemoval(AbstractIntegerDataType)}
*/
private Set<Long> blockedRemovalsByID;
// TODO: idsToDataTypeMap may have issue since there could be a one to many mapping // TODO: idsToDataTypeMap may have issue since there could be a one to many mapping
// (e.g., type with same UniversalID could be in multiple categories unless specifically // (e.g., type with same UniversalID could be in multiple categories unless specifically
// prevented during resolve) // prevented during resolve)
@ -2299,6 +2306,26 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
} }
} }
/**
* Register a {@link AbstractIntegerDataType}, during an invocation of
* {@link StructureDB#dataTypeDeleted(DataType)} or {@link UnionDB#dataTypeDeleted(DataType)},
* to block final removal of the specified datatype since it is required for persistence of a
* defined bitfield. It is required that this be done within the same thread where this manager
* has initiated the removal and callbacks.
* @param dt integer datatype which should be retained and not deleted
*/
void blockDataTypeRemoval(AbstractIntegerDataType dt) {
long id = getID(dt);
if (id == NULL_DATATYPE_ID) {
throw new IllegalArgumentException(
"Datatype instance is not associated with this manager");
}
if (blockedRemovalsByID == null) {
blockedRemovalsByID = new HashSet<>();
}
blockedRemovalsByID.add(id);
}
/** /**
* Remove the given datatype from this manager (assumes the lock has already been acquired). * Remove the given datatype from this manager (assumes the lock has already been acquired).
* *
@ -2335,8 +2362,15 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
// perform actual database updates (e.g., record removal, change notifications, etc.) // perform actual database updates (e.g., record removal, change notifications, etc.)
for (long id : deletedIds) { for (long id : deletedIds) {
if (blockedRemovalsByID != null && blockedRemovalsByID.contains(id)) {
DataType dt = getDataType(id);
Msg.warn(this, "The datatype '" + dt.getDisplayName() +
"' has been retained for use by defined bitfields");
continue;
}
deleteDataType(id); deleteDataType(id);
} }
blockedRemovalsByID = null;
} }
/** /**
@ -2367,14 +2401,11 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
public boolean remove(DataType dataType, TaskMonitor monitor) { public boolean remove(DataType dataType, TaskMonitor monitor) {
lock.acquire(); lock.acquire();
try { try {
if (contains(dataType)) { return removeInternal(dataType);
return removeInternal(dataType);
}
} }
finally { finally {
lock.release(); lock.release();
} }
return false;
} }
@Override @Override

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -321,7 +321,7 @@ class FunctionDefinitionDB extends DataTypeDB implements FunctionDefinition {
} }
@Override @Override
public void setArguments(ParameterDefinition[] args) { public void setArguments(ParameterDefinition... args) {
lock.acquire(); lock.acquire();
try { try {
checkDeleted(); checkDeleted();
@ -413,15 +413,26 @@ class FunctionDefinitionDB extends DataTypeDB implements FunctionDefinition {
lock.acquire(); lock.acquire();
try { try {
checkDeleted(); checkDeleted();
boolean changed = false;
int n = parameters.size(); int n = parameters.size();
for (int i = 0; i < n; i++) { for (int i = 0; i < n; i++) {
ParameterDefinitionDB param = parameters.get(i); ParameterDefinitionDB param = parameters.get(i);
if (param.getDataType() == dt) { if (param.getDataType() == dt) {
param.setDataType(DataType.DEFAULT); param.doSetDataType(DataType.DEFAULT, false);
param.doSetComment(
prependComment("Type '" + dt.getDisplayName() + "' was deleted",
param.getComment()),
false);
changed = true;
} }
} }
if (dt == getReturnType()) { if (dt == getReturnType()) {
setReturnType(DataType.DEFAULT); // NOTE: Not sure how to reflect in a comment
doSetReturnType(DataType.DEFAULT, false, false);
changed = true;
}
if (changed) {
dataMgr.dataTypeChanged(this, true);
} }
} }
finally { finally {

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -133,10 +133,16 @@ final class ParameterDefinitionDB implements ParameterDefinition {
@Override @Override
public void setComment(String comment) { public void setComment(String comment) {
doSetComment(comment, true);
}
void doSetComment(String comment, boolean notify) {
record.setString(FunctionParameterAdapter.PARAMETER_COMMENT_COL, comment); record.setString(FunctionParameterAdapter.PARAMETER_COMMENT_COL, comment);
try { try {
adapter.updateRecord(record); adapter.updateRecord(record);
dataMgr.dataTypeChanged(parent, false); if (notify) {
dataMgr.dataTypeChanged(parent, false);
}
} }
catch (IOException e) { catch (IOException e) {
dataMgr.dbError(e); dataMgr.dbError(e);

View file

@ -251,7 +251,7 @@ class StructureDB extends CompositeDB implements StructureInternal {
// identify index of first defined-component to be removed // identify index of first defined-component to be removed
int index = Collections.binarySearch(components, Integer.valueOf(len), int index = Collections.binarySearch(components, Integer.valueOf(len),
OffsetComparator.INSTANCE); OffsetComparator.INSTANCE);
if (index < 0) { if (index < 0) {
index = -index - 1; index = -index - 1;
} }
@ -280,7 +280,7 @@ class StructureDB extends CompositeDB implements StructureInternal {
lock.release(); lock.release();
} }
} }
@Override @Override
public void growStructure(int amount) { public void growStructure(int amount) {
if (amount < 0) { if (amount < 0) {
@ -1836,20 +1836,30 @@ class StructureDB extends CompositeDB implements StructureInternal {
int n = components.size(); int n = components.size();
for (int i = n - 1; i >= 0; i--) { for (int i = n - 1; i >= 0; i--) {
DataTypeComponentDB dtc = components.get(i); DataTypeComponentDB dtc = components.get(i);
boolean removeBitFieldComponent = false;
if (dtc.isBitFieldComponent()) { if (dtc.isBitFieldComponent()) {
// Do not allow bitfield to be destroyed
// If base type is removed - revert to primitive type
BitFieldDataType bitfieldDt = (BitFieldDataType) dtc.getDataType(); BitFieldDataType bitfieldDt = (BitFieldDataType) dtc.getDataType();
removeBitFieldComponent = bitfieldDt.getBaseDataType() == dt; if (bitfieldDt.getBaseDataType() == dt) {
AbstractIntegerDataType primitiveDt = bitfieldDt.getPrimitiveBaseDataType();
dataMgr.blockDataTypeRemoval(primitiveDt);
if (primitiveDt != dt && updateBitFieldDataType(dtc, dt, primitiveDt)) {
dtc.setComment(
prependComment("Type '" + dt.getDisplayName() + "' was deleted",
dtc.getComment()));
changed = true;
}
}
} }
if (removeBitFieldComponent || dtc.getDataType() == dt) { else if (dtc.getDataType() == dt) {
doDelete(i); setComponentDataType(dtc, BadDataType.dataType, i);
// for non-packed offsets of remaining components will not change dtc.setComment(prependComment("Type '" + dt.getDisplayName() + "' was deleted",
shiftOffsets(i, dtc.getLength() - 1, 0); // ordinals only dtc.getComment()));
--numComponents; // may be revised by repack
changed = true; changed = true;
} }
} }
if (changed && !repack(false, true)) { // repack not needed for non-packed structure - nothing should move
if (changed && (!isPackingEnabled() || !repack(false, true))) {
dataMgr.dataTypeChanged(this, false); dataMgr.dataTypeChanged(this, false);
} }
} }
@ -2344,7 +2354,7 @@ class StructureDB extends CompositeDB implements StructureInternal {
checkDeleted(); checkDeleted();
DataType replacementDt = newDt; DataType replacementDt = newDt;
try { try {
validateDataType(replacementDt); replacementDt = validateDataType(replacementDt); // blocks DEFAULT use for packed
replacementDt = resolve(replacementDt); replacementDt = resolve(replacementDt);
checkAncestry(replacementDt); checkAncestry(replacementDt);
} }
@ -2355,39 +2365,12 @@ class StructureDB extends CompositeDB implements StructureInternal {
boolean changed = false; boolean changed = false;
for (int i = components.size() - 1; i >= 0; i--) { for (int i = components.size() - 1; i >= 0; i--) {
DataTypeComponentDB comp = components.get(i); DataTypeComponentDB comp = components.get(i);
boolean remove = false;
if (comp.isBitFieldComponent()) { if (comp.isBitFieldComponent()) {
try { changed |= updateBitFieldDataType(comp, oldDt, replacementDt);
changed |= updateBitFieldDataType(comp, oldDt, replacementDt);
}
catch (InvalidDataTypeException e) {
Msg.error(this,
"Invalid bitfield replacement type " + newDt.getName() +
", removing bitfield " + comp.getDataType().getName() + ": " +
getPathName());
remove = true;
}
} }
else if (comp.getDataType() == oldDt) { else if (comp.getDataType() == oldDt) {
if (replacementDt == DEFAULT && isPackingEnabled()) { setComponentDataType(comp, replacementDt, i);
Msg.error(this,
"Invalid replacement type " + newDt.getName() +
", removing component " + comp.getDataType().getName() + ": " +
getPathName());
remove = true;
}
else {
setComponentDataType(comp, replacementDt, i);
changed = true;
}
}
if (remove) {
// error case - remove component
doDelete(i);
shiftOffsets(i, comp.getLength() - 1, 0); // ordinals only
changed = true; changed = true;
} }
} }

View file

@ -25,7 +25,6 @@ import ghidra.program.database.DBObjectCache;
import ghidra.program.model.data.*; import ghidra.program.model.data.*;
import ghidra.program.model.data.DataTypeConflictHandler.ConflictResult; import ghidra.program.model.data.DataTypeConflictHandler.ConflictResult;
import ghidra.program.model.mem.MemBuffer; import ghidra.program.model.mem.MemBuffer;
import ghidra.util.Msg;
/** /**
* Database implementation for the Union data type. * Database implementation for the Union data type.
@ -715,20 +714,32 @@ class UnionDB extends CompositeDB implements UnionInternal {
boolean changed = false; boolean changed = false;
for (int i = components.size() - 1; i >= 0; i--) { // reverse order for (int i = components.size() - 1; i >= 0; i--) { // reverse order
DataTypeComponentDB dtc = components.get(i); DataTypeComponentDB dtc = components.get(i);
boolean removeBitFieldComponent = false;
if (dtc.isBitFieldComponent()) { if (dtc.isBitFieldComponent()) {
// Do not allow bitfield to be destroyed
// If base type is removed - revert to primitive type
BitFieldDataType bitfieldDt = (BitFieldDataType) dtc.getDataType(); BitFieldDataType bitfieldDt = (BitFieldDataType) dtc.getDataType();
removeBitFieldComponent = bitfieldDt.getBaseDataType() == dt; if (bitfieldDt.getBaseDataType() == dt) {
AbstractIntegerDataType primitiveDt = bitfieldDt.getPrimitiveBaseDataType();
dataMgr.blockDataTypeRemoval(primitiveDt);
if (primitiveDt != dt && updateBitFieldDataType(dtc, dt, primitiveDt)) {
dtc.setComment(
prependComment("Type '" + dt.getDisplayName() + "' was deleted",
dtc.getComment()));
changed = true;
}
}
} }
if (removeBitFieldComponent || dtc.getDataType() == dt) { else if (dtc.getDataType() == dt) {
dt.removeParent(this); dt.removeParent(this);
components.remove(i); dtc.setDataType(BadDataType.dataType); // updates record
removeComponentRecord(dtc.getKey()); dataMgr.getSettingsAdapter().removeAllSettingsRecords(dtc.getKey());
shiftOrdinals(i, -1); dtc.setComment(prependComment("Type '" + dt.getDisplayName() + "' was deleted",
dtc.getComment()));
changed = true; changed = true;
} }
} }
if (changed && !repack(false, true)) { if (changed && (!isPackingEnabled() || !repack(false, true))) {
dataMgr.dataTypeChanged(this, false); dataMgr.dataTypeChanged(this, false);
} }
} }
@ -821,58 +832,26 @@ class UnionDB extends CompositeDB implements UnionInternal {
checkDeleted(); checkDeleted();
DataType replacementDt = newDt; DataType replacementDt = newDt;
try { try {
validateDataType(replacementDt); replacementDt = validateDataType(replacementDt); // blocks DEFAULT use
if (!(replacementDt instanceof DataTypeDB) || replacementDt = replacementDt.clone(dataMgr);
(replacementDt.getDataTypeManager() != getDataTypeManager())) {
replacementDt = resolve(replacementDt);
}
checkAncestry(replacementDt); checkAncestry(replacementDt);
} }
catch (Exception e) { catch (Exception e) {
// TODO: should we flag bad replacement
replacementDt = Undefined1DataType.dataType; replacementDt = Undefined1DataType.dataType;
} }
boolean changed = false; boolean changed = false;
for (int i = components.size() - 1; i >= 0; i--) { for (int i = components.size() - 1; i >= 0; i--) {
DataTypeComponentDB dtc = components.get(i); DataTypeComponentDB dtc = components.get(i);
boolean remove = false;
if (dtc.isBitFieldComponent()) { if (dtc.isBitFieldComponent()) {
try { changed |= updateBitFieldDataType(dtc, oldDt, replacementDt);
changed |= updateBitFieldDataType(dtc, oldDt, replacementDt);
}
catch (InvalidDataTypeException e) {
Msg.error(this,
"Invalid bitfield replacement type " + newDt.getName() +
", removing bitfield " + dtc.getDataType().getName() + ": " +
getPathName());
remove = true;
}
} }
else if (dtc.getDataType() == oldDt) { else if (dtc.getDataType() == oldDt) {
if (replacementDt == DEFAULT) { int len = getPreferredComponentLength(newDt, dtc.getLength());
Msg.error(this, dtc.setLength(len, false);
"Invalid replacement type " + newDt.getName() +
", removing component " + dtc.getDataType().getName() + ": " +
getPathName());
remove = true;
}
else {
int len = getPreferredComponentLength(newDt, dtc.getLength());
dtc.setLength(len, false);
oldDt.removeParent(this);
dtc.setDataType(replacementDt); // updates record
dataMgr.getSettingsAdapter().removeAllSettingsRecords(dtc.getKey());
replacementDt.addParent(this);
changed = true;
}
}
if (remove) {
oldDt.removeParent(this); oldDt.removeParent(this);
components.remove(i); dtc.setDataType(replacementDt); // updates record
removeComponentRecord(dtc.getKey()); dataMgr.getSettingsAdapter().removeAllSettingsRecords(dtc.getKey());
shiftOrdinals(i, -1); replacementDt.addParent(this);
changed = true; changed = true;
} }
} }

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -61,7 +61,8 @@ public class BitFieldDataType extends AbstractDataType {
* bit size may be reduced based upon the specified base datatype size. * bit size may be reduced based upon the specified base datatype size.
* @param bitOffset right shift factor within storage unit when viewed as a big-endian dd * @param bitOffset right shift factor within storage unit when viewed as a big-endian dd
* scalar value. Based upon minimal storage bitOffset should be in the range 0 to 7. * scalar value. Based upon minimal storage bitOffset should be in the range 0 to 7.
* @throws InvalidDataTypeException * @throws InvalidDataTypeException if invalid base datatype has been specified or an
* invalid bitSize or bitOffset has been specified
*/ */
protected BitFieldDataType(DataType baseDataType, int bitSize, int bitOffset) protected BitFieldDataType(DataType baseDataType, int bitSize, int bitOffset)
throws InvalidDataTypeException { throws InvalidDataTypeException {
@ -92,7 +93,7 @@ public class BitFieldDataType extends AbstractDataType {
protected BitFieldDataType(DataType baseDataType, int bitSize) throws InvalidDataTypeException { protected BitFieldDataType(DataType baseDataType, int bitSize) throws InvalidDataTypeException {
this(baseDataType, bitSize, 0); this(baseDataType, bitSize, 0);
} }
@Override @Override
public boolean isZeroLength() { public boolean isZeroLength() {
return bitSize == 0; return bitSize == 0;
@ -234,8 +235,8 @@ public class BitFieldDataType extends AbstractDataType {
public AbstractIntegerDataType getPrimitiveBaseDataType() { public AbstractIntegerDataType getPrimitiveBaseDataType() {
// assumes proper enforcement during construction // assumes proper enforcement during construction
DataType dt = baseDataType; DataType dt = baseDataType;
if (baseDataType instanceof TypeDef) { while (dt instanceof TypeDef typeDef) {
dt = ((TypeDef) baseDataType).getBaseDataType(); dt = typeDef.getBaseDataType();
} }
if (dt instanceof Enum) { if (dt instanceof Enum) {
// TODO: uncertain if we should use signed or unsigned, although size // TODO: uncertain if we should use signed or unsigned, although size
@ -417,8 +418,8 @@ public class BitFieldDataType extends AbstractDataType {
return ((Enum) dt).getRepresentation(big, settings, effectiveBitSize); return ((Enum) dt).getRepresentation(big, settings, effectiveBitSize);
} }
AbstractIntegerDataType intDT = (AbstractIntegerDataType) dt; AbstractIntegerDataType intDT = (AbstractIntegerDataType) dt;
if (intDT.getFormatSettingsDefinition().getFormat( if (intDT.getFormatSettingsDefinition()
settings) == FormatSettingsDefinition.CHAR) { .getFormat(settings) == FormatSettingsDefinition.CHAR) {
if (big.signum() < 0) { if (big.signum() < 0) {
big = big.add(BigInteger.valueOf(2).pow(effectiveBitSize)); big = big.add(BigInteger.valueOf(2).pow(effectiveBitSize));
} }

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -233,24 +233,23 @@ public abstract class CompositeDataTypeImpl extends GenericDataType implements C
* @param oldDt affected datatype which has been removed or replaced * @param oldDt affected datatype which has been removed or replaced
* @param newDt replacement datatype * @param newDt replacement datatype
* @return true if bitfield component was modified * @return true if bitfield component was modified
* @throws InvalidDataTypeException if new datatype is not
*/ */
protected boolean updateBitFieldDataType(DataTypeComponentImpl bitfieldComponent, protected boolean updateBitFieldDataType(DataTypeComponentImpl bitfieldComponent,
DataType oldDt, DataType newDt) throws InvalidDataTypeException { DataType oldDt, DataType newDt) {
if (!bitfieldComponent.isBitFieldComponent()) { if (!bitfieldComponent.isBitFieldComponent()) {
throw new AssertException("expected bitfield component"); throw new AssertException("expected bitfield component");
} }
BitFieldDataType bitfieldDt = (BitFieldDataType) bitfieldComponent.getDataType(); BitFieldDataType bitfieldDt = (BitFieldDataType) bitfieldComponent.getDataType();
if (bitfieldDt.getBaseDataType() != oldDt) { if (bitfieldDt.getBaseDataType() != oldDt || !BitFieldDataType.isValidBaseDataType(newDt)) {
return false; return false;
} }
if (newDt != null) { if (newDt != null) {
BitFieldDataType.checkBaseDataType(newDt);
int maxBitSize = 8 * newDt.getLength(); int maxBitSize = 8 * newDt.getLength();
if (bitfieldDt.getBitSize() > maxBitSize) { if (bitfieldDt.getBitSize() > maxBitSize) {
throw new InvalidDataTypeException("Replacement datatype too small for bitfield"); // Replacement datatype too small for bitfield
return false;
} }
} }
@ -262,7 +261,7 @@ public abstract class CompositeDataTypeImpl extends GenericDataType implements C
newDt.addParent(this); newDt.addParent(this);
} }
catch (InvalidDataTypeException e) { catch (InvalidDataTypeException e) {
throw new AssertException("unexpected"); throw new AssertException(e); // unexpected
} }
return true; return true;

View file

@ -332,6 +332,9 @@ public class DataTypeComponentImpl implements InternalDataTypeComponent, Seriali
if (DataTypeComponent.usesZeroLengthComponent(dataType)) { if (DataTypeComponent.usesZeroLengthComponent(dataType)) {
return 0; return 0;
} }
if ((dataType instanceof Dynamic dynamic) && dynamic.canSpecifyLength()) {
return length;
}
int dtLength = dataType.getLength(); int dtLength = dataType.getLength();
if (length <= 0) { if (length <= 0) {
length = dtLength; length = dtLength;

View file

@ -308,7 +308,14 @@ public interface DataTypeManager {
public void removeInvalidatedListener(InvalidatedListener listener); public void removeInvalidatedListener(InvalidatedListener listener);
/** /**
* Remove the given datatype from this manager * Remove the given datatype from this manager.
* <br>
* NOTE: Any use of the specified datatype within a {@link FunctionDefinition} will be
* converted to the {@link DataType#DEFAULT default 'undefined' datatype}. Any use within
* a {@link Structure} or {@link Union} will be converted to the {@link BadDataType} as
* a placeholder to retain the component's field name and length (the comment will be prefixed
* with a message indicating the remval of the old datatype.
*
* @param dataType the dataType to be removed * @param dataType the dataType to be removed
* @param monitor the task monitor * @param monitor the task monitor
* @return true if the data type existed and was removed * @return true if the data type existed and was removed

View file

@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -29,7 +29,7 @@ public interface FunctionDefinition extends DataType, FunctionSignature {
* Set the arguments to this function. * Set the arguments to this function.
* @param args array of parameter definitions to be used as arguments to this function * @param args array of parameter definitions to be used as arguments to this function
*/ */
public void setArguments(ParameterDefinition[] args); public void setArguments(ParameterDefinition... args);
/** /**
* Set the return data type for this function * Set the return data type for this function

View file

@ -141,7 +141,7 @@ public class FunctionDefinitionDataType extends GenericDataType implements Funct
} }
@Override @Override
public void setArguments(ParameterDefinition[] args) { public void setArguments(ParameterDefinition... args) {
params = new ParameterDefinition[args.length]; params = new ParameterDefinition[args.length];
for (int i = 0; i < args.length; i++) { for (int i = 0; i < args.length; i++) {
DataType dt = args[i].getDataType(); DataType dt = args[i].getDataType();

View file

@ -20,7 +20,6 @@ import java.util.*;
import ghidra.docking.settings.Settings; import ghidra.docking.settings.Settings;
import ghidra.program.model.data.AlignedStructurePacker.StructurePackResult; import ghidra.program.model.data.AlignedStructurePacker.StructurePackResult;
import ghidra.program.model.mem.MemBuffer; import ghidra.program.model.mem.MemBuffer;
import ghidra.util.Msg;
import ghidra.util.UniversalID; import ghidra.util.UniversalID;
import ghidra.util.exception.AssertException; import ghidra.util.exception.AssertException;
@ -654,7 +653,7 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur
repack(false); repack(false);
notifySizeChanged(); notifySizeChanged();
} }
@Override @Override
public void growStructure(int amount) { public void growStructure(int amount) {
if (amount < 0) { if (amount < 0) {
@ -1296,80 +1295,50 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur
int n = components.size(); int n = components.size();
for (int i = n - 1; i >= 0; i--) { for (int i = n - 1; i >= 0; i--) {
DataTypeComponentImpl dtc = components.get(i); DataTypeComponentImpl dtc = components.get(i);
boolean removeBitFieldComponent = false;
if (dtc.isBitFieldComponent()) { if (dtc.isBitFieldComponent()) {
// Do not allow bitfield to be destroyed
// If base type is removed - revert to primitive type
BitFieldDataType bitfieldDt = (BitFieldDataType) dtc.getDataType(); BitFieldDataType bitfieldDt = (BitFieldDataType) dtc.getDataType();
removeBitFieldComponent = bitfieldDt.getBaseDataType() == dt; if (bitfieldDt.getBaseDataType() == dt &&
updateBitFieldDataType(dtc, dt, bitfieldDt.getPrimitiveBaseDataType())) {
changed = true;
}
} }
if (removeBitFieldComponent || dtc.getDataType() == dt) { else if (dtc.getDataType() == dt) {
dt.removeParent(this); setComponentDataType(dtc, BadDataType.dataType, i);
// FIXME: Consider replacing with undefined type instead of removing (don't remove bitfield)
components.remove(i);
shiftOffsets(i, dtc.getLength() - 1, 0);
--numComponents; // may be revised by repack
changed = true; changed = true;
} }
} }
if (changed) { // Should be no impact for non-packed
if (changed && !isPackingEnabled()) {
repack(true); repack(true);
} }
} }
@Override @Override
public void dataTypeReplaced(DataType oldDt, DataType replacementDt) public void dataTypeReplaced(DataType oldDt, DataType newDt) throws IllegalArgumentException {
throws IllegalArgumentException { DataType replacementDt = newDt;
DataType newDt = replacementDt;
try { try {
validateDataType(replacementDt); replacementDt = validateDataType(replacementDt); // blocks DEFAULT use for packed
replacementDt = replacementDt.clone(dataMgr); replacementDt = replacementDt.clone(dataMgr);
checkAncestry(replacementDt); checkAncestry(replacementDt);
} }
catch (Exception e) { catch (Exception e) {
// TODO: should we use Undefined1 instead to avoid cases where // Handle bad replacement with use of undefined component
// DEFAULT datatype can not be used (bitfield, aligned structure, etc.) replacementDt = isPackingEnabled() ? Undefined1DataType.dataType : DataType.DEFAULT;
// TODO: failing silently is rather hidden
replacementDt = DataType.DEFAULT;
} }
boolean changed = false; boolean changed = false;
for (int i = components.size() - 1; i >= 0; i--) { for (int i = components.size() - 1; i >= 0; i--) {
DataTypeComponentImpl comp = components.get(i); DataTypeComponentImpl comp = components.get(i);
boolean remove = false;
if (comp.isBitFieldComponent()) { if (comp.isBitFieldComponent()) {
try { changed |= updateBitFieldDataType(comp, oldDt, replacementDt);
changed |= updateBitFieldDataType(comp, oldDt, replacementDt);
}
catch (InvalidDataTypeException e) {
Msg.error(this,
"Invalid bitfield replacement type " + newDt.getName() +
", removing bitfield " + comp.getDataType().getName() + ": " +
getPathName());
remove = true;
}
} }
else if (comp.getDataType() == oldDt) { else if (comp.getDataType() == oldDt) {
if (replacementDt == DEFAULT && isPackingEnabled()) { setComponentDataType(comp, replacementDt, i);
Msg.error(this,
"Invalid replacement type " + newDt.getName() + ", removing component " +
comp.getDataType().getName() + ": " + getPathName());
remove = true;
}
else {
setComponentDataType(comp, replacementDt, i);
changed = true;
}
}
if (remove) {
// error case - remove component
oldDt.removeParent(this);
components.remove(i);
shiftOffsets(i, comp.getLength() - 1, 0); // ordinals only
changed = true; changed = true;
} }
} }
if (changed) { if (changed) {
repack(false); repack(false);
notifySizeChanged(); // also handles alignment change notifySizeChanged(); // also handles alignment change

View file

@ -19,7 +19,6 @@ import java.util.*;
import ghidra.docking.settings.Settings; import ghidra.docking.settings.Settings;
import ghidra.program.model.mem.MemBuffer; import ghidra.program.model.mem.MemBuffer;
import ghidra.util.Msg;
import ghidra.util.UniversalID; import ghidra.util.UniversalID;
/** /**
@ -505,57 +504,26 @@ public class UnionDataType extends CompositeDataTypeImpl implements UnionInterna
public void dataTypeReplaced(DataType oldDt, DataType newDt) throws IllegalArgumentException { public void dataTypeReplaced(DataType oldDt, DataType newDt) throws IllegalArgumentException {
DataType replacementDt = newDt; DataType replacementDt = newDt;
try { try {
validateDataType(replacementDt); replacementDt = validateDataType(replacementDt); // blocks DEFAULT use
if (replacementDt.getDataTypeManager() != dataMgr) { replacementDt = replacementDt.clone(dataMgr);
replacementDt = replacementDt.clone(dataMgr);
}
checkAncestry(replacementDt); checkAncestry(replacementDt);
} }
catch (Exception e) { catch (Exception e) {
// TODO: should we use Undefined instead since we do not support replacementDt = Undefined1DataType.dataType;
// DEFAULT in Unions
replacementDt = DataType.DEFAULT;
} }
boolean changed = false; boolean changed = false;
for (int i = components.size() - 1; i >= 0; i--) { for (int i = components.size() - 1; i >= 0; i--) {
DataTypeComponentImpl dtc = components.get(i); DataTypeComponentImpl dtc = components.get(i);
boolean remove = false;
if (dtc.isBitFieldComponent()) { if (dtc.isBitFieldComponent()) {
try { changed |= updateBitFieldDataType(dtc, oldDt, replacementDt);
changed |= updateBitFieldDataType(dtc, oldDt, replacementDt);
}
catch (InvalidDataTypeException e) {
Msg.error(this,
"Invalid bitfield replacement type " + newDt.getName() +
", removing bitfield " + dtc.getDataType().getName() + ": " +
getPathName());
remove = true;
}
} }
else if (dtc.getDataType() == oldDt) { else if (dtc.getDataType() == oldDt) {
if (replacementDt == DEFAULT) { int len = getPreferredComponentLength(newDt, dtc.getLength());
Msg.error(this,
"Invalid replacement type " + newDt.getName() + ", removing component " +
dtc.getDataType().getName() + ": " + getPathName());
remove = true;
}
else {
int len = getPreferredComponentLength(newDt, dtc.getLength());
oldDt.removeParent(this);
dtc.setLength(len);
dtc.setDataType(replacementDt);
dtc.invalidateSettings();
replacementDt.addParent(this);
changed = true;
}
}
if (remove) {
// error case - remove component
oldDt.removeParent(this); oldDt.removeParent(this);
components.remove(i); dtc.setLength(len);
shiftOrdinals(i, -1); dtc.setDataType(replacementDt);
dtc.invalidateSettings();
replacementDt.addParent(this);
changed = true; changed = true;
} }
} }
@ -570,19 +538,22 @@ public class UnionDataType extends CompositeDataTypeImpl implements UnionInterna
boolean changed = false; boolean changed = false;
for (int i = components.size() - 1; i >= 0; i--) { // reverse order for (int i = components.size() - 1; i >= 0; i--) { // reverse order
DataTypeComponentImpl dtc = components.get(i); DataTypeComponentImpl dtc = components.get(i);
boolean removeBitFieldComponent = false;
if (dtc.isBitFieldComponent()) { if (dtc.isBitFieldComponent()) {
// Do not allow bitfield to be destroyed
// If base type is removed - revert to primitive type
BitFieldDataType bitfieldDt = (BitFieldDataType) dtc.getDataType(); BitFieldDataType bitfieldDt = (BitFieldDataType) dtc.getDataType();
removeBitFieldComponent = bitfieldDt.getBaseDataType() == dt; if (bitfieldDt.getBaseDataType() == dt &&
updateBitFieldDataType(dtc, dt, bitfieldDt.getPrimitiveBaseDataType())) {
changed = true;
}
} }
if (removeBitFieldComponent || dtc.getDataType() == dt) { else if (dtc.getDataType() == dt) {
dt.removeParent(this); dt.removeParent(this);
components.remove(i); dtc.setDataType(BadDataType.dataType); // updates record
shiftOrdinals(i, -1);
changed = true; changed = true;
} }
} }
if (changed && !repack(true) && isPackingEnabled()) { if (changed && isPackingEnabled() && !repack(true)) {
// NOTE: Must assume alignment change since we are unable to determine // NOTE: Must assume alignment change since we are unable to determine
// without stored alignment // without stored alignment
notifyAlignmentChanged(); notifyAlignmentChanged();

View file

@ -1153,13 +1153,34 @@ public class StructureDBTest extends AbstractGenericTest {
assertEquals(8, struct.getLength()); assertEquals(8, struct.getLength());
struct.add(new ArrayDataType(IntegerDataType.dataType, 0, -1), "flex", "FlexComment"); struct.add(new ArrayDataType(IntegerDataType.dataType, 0, -1), "flex", "FlexComment");
assertEquals(5, struct.getNumComponents());
assertEquals(8, struct.getLength()); //@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/Test\n" +
"pack(disabled)\n" +
"Structure Test {\n" +
" 0 byte 1 field1 \"Comment1\"\n" +
" 1 word 2 \"Comment2\"\n" +
" 3 dword 4 field3 \"\"\n" +
" 7 byte 1 field4 \"Comment4\"\n" +
" 8 int[0] 0 flex \"FlexComment\"\n" +
"}\n" +
"Length: 8 Alignment: 1", struct);
//@formatter:on
dataMgr.remove(dataMgr.resolve(IntegerDataType.dataType, null), TaskMonitor.DUMMY); dataMgr.remove(dataMgr.resolve(IntegerDataType.dataType, null), TaskMonitor.DUMMY);
assertEquals(4, struct.getNumComponents()); //@formatter:off
assertEquals(8, struct.getLength()); CompositeTestUtils.assertExpectedComposite(this, "/Test\n" +
"pack(disabled)\n" +
"Structure Test {\n" +
" 0 byte 1 field1 \"Comment1\"\n" +
" 1 word 2 \"Comment2\"\n" +
" 3 dword 4 field3 \"\"\n" +
" 7 byte 1 field4 \"Comment4\"\n" +
" 8 -BAD- 0 flex \"Type 'int[0]' was deleted; FlexComment\"\n" +
"}\n" +
"Length: 8 Alignment: 1", struct);
//@formatter:on
} }
@Test @Test
@ -1197,9 +1218,9 @@ public class StructureDBTest extends AbstractGenericTest {
" 1 word 2 \"Comment2\"\n" + " 1 word 2 \"Comment2\"\n" +
" 3 dword 4 field3 \"\"\n" + " 3 dword 4 field3 \"\"\n" +
" 7 byte 1 field4 \"Comment4\"\n" + " 7 byte 1 field4 \"Comment4\"\n" +
// " 8 undefined 1 \"\"\n" + " 8 int:4(0) 1 MyBit1 \"Type 'Foo' was deleted; bitComment\"\n" +
// " 9 undefined 1 \"\"\n" + " 9 int:3(0) 1 MyBit2 \"Type 'Foo' was deleted; bitComment\"\n" +
// " 10 undefined 1 \"\"\n" + " 10 int:2(0) 1 MyBit3 \"Type 'Foo' was deleted; bitComment\"\n" +
"}\n" + "}\n" +
"Length: 11 Alignment: 1", struct); "Length: 11 Alignment: 1", struct);
//@formatter:on //@formatter:on
@ -1807,14 +1828,33 @@ public class StructureDBTest extends AbstractGenericTest {
DataType dt = struct.getDataTypeManager().getDataType(struct.getCategoryPath(), "test1"); DataType dt = struct.getDataTypeManager().getDataType(struct.getCategoryPath(), "test1");
assertNotNull(dt); assertNotNull(dt);
DataTypeComponent[] dtc = struct.getComponents(); //@formatter:off
assertEquals(5, dtc.length); CompositeTestUtils.assertExpectedComposite(this, "/Test\n" +
"pack(disabled)\n" +
"Structure Test {\n" +
" 0 byte 1 field1 \"Comment1\"\n" +
" 1 word 2 \"Comment2\"\n" +
" 3 dword 4 field3 \"\"\n" +
" 7 byte 1 field4 \"Comment4\"\n" +
" 8 test1 5 \"\"\n" +
"}\n" +
"Length: 13 Alignment: 1", struct);
//@formatter:on
dt.getDataTypeManager().remove(dt, new TaskMonitorAdapter()); dt.getDataTypeManager().remove(dt, new TaskMonitorAdapter());
dtc = struct.getComponents();
assertEquals(9, dtc.length);
assertEquals(9, struct.getNumComponents()); //@formatter:off
CompositeTestUtils.assertExpectedComposite(this, "/Test\n" +
"pack(disabled)\n" +
"Structure Test {\n" +
" 0 byte 1 field1 \"Comment1\"\n" +
" 1 word 2 \"Comment2\"\n" +
" 3 dword 4 field3 \"\"\n" +
" 7 byte 1 field4 \"Comment4\"\n" +
" 8 -BAD- 5 \"Type 'test1' was deleted\"\n" +
"}\n" +
"Length: 13 Alignment: 1", struct);
//@formatter:on
} }
@Test @Test

View file

@ -280,6 +280,8 @@ public class UnionDBTest extends AbstractGenericTest {
"Union TestUnion {\n" + "Union TestUnion {\n" +
" 0 byte 1 field1 \"Comment1\"\n" + " 0 byte 1 field1 \"Comment1\"\n" +
" 0 word 2 \"Comment2\"\n" + " 0 word 2 \"Comment2\"\n" +
" 0 int:4(0) 1 bf1 \"Type 'Foo' was deleted; bf1Comment\"\n" +
" 0 int:4(0) 1 bf2 \"Type 'Foo' was deleted; bf2Comment\"\n" +
" 0 dword 4 field3 \"\"\n" + " 0 dword 4 field3 \"\"\n" +
" 0 byte 1 field4 \"Comment4\"\n" + " 0 byte 1 field4 \"Comment4\"\n" +
"}\n" + "}\n" +