mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 19:42:36 +02:00
GP-1572 - Set Equates - continuation of pull request to allow users to
apply equates from enums where multiple names are mapped to a single value. Closes #3618
This commit is contained in:
parent
1da1c9fef3
commit
6746fdf60a
13 changed files with 1172 additions and 1004 deletions
|
@ -32,7 +32,7 @@ import ghidra.program.util.ProgramLocation;
|
|||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
/**
|
||||
*Class to handle creating new equates for a selection or the whole program
|
||||
* Class to handle creating new equates for a selection or the whole program
|
||||
*/
|
||||
public class CreateEquateCmd extends BackgroundCommand {
|
||||
|
||||
|
@ -46,9 +46,10 @@ public class CreateEquateCmd extends BackgroundCommand {
|
|||
/**
|
||||
*
|
||||
* @param scalar user defined scalar to search for in program
|
||||
* @param iter the range of code units for which to maybe create equates
|
||||
* @param iter the range of code units for which to maybe create equates
|
||||
* @param equateName user defined name for the new equate to be set
|
||||
* @param overwriteExisting
|
||||
* @param overwriteExisting true to rename existing equates
|
||||
* @param context the action context
|
||||
*/
|
||||
public CreateEquateCmd(Scalar scalar, CodeUnitIterator iter, String equateName,
|
||||
boolean overwriteExisting, ListingActionContext context) {
|
||||
|
@ -64,9 +65,10 @@ public class CreateEquateCmd extends BackgroundCommand {
|
|||
/**
|
||||
*
|
||||
* @param scalar user defined scalar to search for in program
|
||||
* @param iter the range of code units for which to maybe create equates
|
||||
* @param iter the range of code units for which to maybe create equates
|
||||
* @param enoom the enum to use for formatting the equate name
|
||||
* @param overwriteExisting
|
||||
* @param overwriteExisting true to rename existing equates
|
||||
* @param context the action context
|
||||
*/
|
||||
public CreateEquateCmd(Scalar scalar, CodeUnitIterator iter, Enum enoom,
|
||||
boolean overwriteExisting, ListingActionContext context) {
|
||||
|
@ -138,7 +140,6 @@ public class CreateEquateCmd extends BackgroundCommand {
|
|||
private void createEquate(DomainObject domain, CodeUnit codeUnit, int opIndex,
|
||||
Scalar scalar) {
|
||||
|
||||
|
||||
EquateTable equateTable = codeUnit.getProgram().getEquateTable();
|
||||
Address address = codeUnit.getAddress();
|
||||
Equate curEquate = equateTable.getEquate(address, opIndex, targetScalarValue);
|
||||
|
@ -156,7 +157,7 @@ public class CreateEquateCmd extends BackgroundCommand {
|
|||
cmd.applyTo(domain);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private String generateFormattedEquateName() {
|
||||
Program program = context.getProgram();
|
||||
Enum enumWithId = (Enum) program.getDataTypeManager().addDataType(enoom, null);
|
||||
|
|
|
@ -68,29 +68,20 @@ public class EquatePlugin extends Plugin {
|
|||
private DockingAction renameAction;
|
||||
private DockingAction removeAction;
|
||||
private DockingAction applyEnumAction;
|
||||
private SetEquateDialog setEquateDialog;
|
||||
private ApplyEnumDialog applyEnumDialog;
|
||||
|
||||
public EquatePlugin(PluginTool tool) {
|
||||
super(tool);
|
||||
createActions();
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the GUI for the {@link SetEquateDialog}. Note that this function will close
|
||||
* any instance of the dialog that is currently open and construct a new one.
|
||||
*/
|
||||
private SetEquateDialog createEquateDialog(ListingActionContext context, Scalar scalar) {
|
||||
if (setEquateDialog != null) {
|
||||
setEquateDialog.close();
|
||||
}
|
||||
|
||||
InitializeDialogTask task = new InitializeDialogTask(context.getProgram(), scalar);
|
||||
TaskLauncher.launch(task);
|
||||
|
||||
setEquateDialog = task.getDialog();
|
||||
setEquateDialog.setHelpLocation(new HelpLocation(getName(), "Set_Equate"));
|
||||
return setEquateDialog;
|
||||
SetEquateDialog dialog = task.getDialog();
|
||||
dialog.setHelpLocation(new HelpLocation(getName(), "Set_Equate"));
|
||||
return dialog;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -99,22 +90,12 @@ public class EquatePlugin extends Plugin {
|
|||
*/
|
||||
private ApplyEnumDialog applyEnumDialog(ListingActionContext context) {
|
||||
DataTypeManager dtm = context.getProgram().getDataTypeManager();
|
||||
if (applyEnumDialog != null) {
|
||||
applyEnumDialog.close();
|
||||
}
|
||||
applyEnumDialog = new ApplyEnumDialog(tool, dtm);
|
||||
ApplyEnumDialog applyEnumDialog = new ApplyEnumDialog(tool, dtm);
|
||||
applyEnumDialog.setHelpLocation(new HelpLocation(getName(), "Apply_Enum"));
|
||||
tool.showDialog(applyEnumDialog);
|
||||
return applyEnumDialog;
|
||||
}
|
||||
|
||||
private void dispose(SetEquateDialog dialog) {
|
||||
if (setEquateDialog == dialog) {
|
||||
setEquateDialog.dispose();
|
||||
setEquateDialog = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a Set Equate operation is permitted for the specified action context.
|
||||
* The current context must satisfy the following constraints:
|
||||
|
@ -167,39 +148,27 @@ public class EquatePlugin extends Plugin {
|
|||
*/
|
||||
private void setEquate(ListingActionContext context) {
|
||||
|
||||
// Get the scalar item that was selected. If this returns null, then something
|
||||
// invalid was selected, so exit.
|
||||
Scalar curScalar = getScalar(context);
|
||||
if (curScalar == null) {
|
||||
Scalar scalar = getScalar(context);
|
||||
if (scalar == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Create the dialog that will allow the user to select options.
|
||||
createEquateDialog(context, curScalar);
|
||||
SetEquateDialog dialog = createEquateDialog(context, scalar);
|
||||
|
||||
// Set the state of the some buttons on the dialog. ie: if the user has selected
|
||||
// a range of addresses we should automatically set the "selection" radio button
|
||||
// to the selected state.
|
||||
setEquateDialog.setHasSelection(context);
|
||||
|
||||
// If the user has selected the cancel button, exit.
|
||||
if (setEquateDialog.showSetDialog() == SetEquateDialog.CANCELED) {
|
||||
// Set the state of the some buttons on the dialog. ie: if the user has selected a range
|
||||
// of addresses we should automatically set the "selection" radio button to the selected
|
||||
// state.
|
||||
dialog.setHasSelection(context);
|
||||
if (dialog.showSetDialog() == SetEquateDialog.CANCELED) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Define an iterator for the task. We're using a CodeUnitIterator to make sure we inspect
|
||||
// all Data and Instruction instances.
|
||||
CodeUnitIterator iter = null;
|
||||
|
||||
// Get the program listing. This is what allows us to get an iterator for the
|
||||
// addresses we're interested in.
|
||||
Listing listing = context.getProgram().getListing();
|
||||
|
||||
// Now we have to 'populate' the iterator with the proper addresses. Once we have the
|
||||
// iterator, we'll create a background task to process them.
|
||||
//
|
||||
SelectionType selectionType = setEquateDialog.getSelectionType();
|
||||
|
||||
SelectionType selectionType = dialog.getSelectionType();
|
||||
if (selectionType == SelectionType.CURRENT_ADDRESS) {
|
||||
AddressSet addrSet = new AddressSet(context.getAddress());
|
||||
iter = listing.getCodeUnits(addrSet, false);
|
||||
|
@ -213,21 +182,12 @@ public class EquatePlugin extends Plugin {
|
|||
iter = listing.getCodeUnits(context.getProgram().getMemory(), true);
|
||||
}
|
||||
|
||||
BackgroundCommand cmd;
|
||||
if (setEquateDialog.getEnumDataType() != null) {
|
||||
// Now set up a command to run in the background, and execute the task.
|
||||
cmd = new CreateEquateCmd(curScalar, iter, setEquateDialog.getEnumDataType(),
|
||||
setEquateDialog.getOverwriteExisting(), context);
|
||||
}
|
||||
else {
|
||||
// Now set up a command to run in the background, and execute the task.
|
||||
cmd = new CreateEquateCmd(curScalar, iter, setEquateDialog.getEquateName(),
|
||||
setEquateDialog.getOverwriteExisting(), context);
|
||||
}
|
||||
BackgroundCommand cmd =
|
||||
new CreateEquateCmd(scalar, iter, dialog.getEquateName(),
|
||||
dialog.getOverwriteExisting(), context);
|
||||
tool.executeBackgroundCommand(cmd, context.getProgram());
|
||||
|
||||
// Finally, blow away the dialog.
|
||||
dispose(setEquateDialog);
|
||||
dialog.dispose();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -236,40 +196,34 @@ public class EquatePlugin extends Plugin {
|
|||
* @param context the action context
|
||||
*/
|
||||
private void applyEnum(ListingActionContext context) {
|
||||
applyEnumDialog = applyEnumDialog(context);
|
||||
DataType dataType = applyEnumDialog.getUserChosenDataType();
|
||||
|
||||
ApplyEnumDialog dialog = applyEnumDialog(context);
|
||||
DataType dataType = dialog.getUserChosenDataType();
|
||||
if (dataType == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(dataType instanceof Enum)) {
|
||||
Msg.showError(this, null, "Input Error", "Data Type must be an enum");
|
||||
return;
|
||||
}
|
||||
|
||||
boolean shouldDoOnSubOps = applyEnumDialog.shouldApplyOnSubOps();
|
||||
|
||||
AddressSetView addresses = context.getSelection();
|
||||
if (addresses.isEmpty()) {
|
||||
addresses = new AddressSet(context.getAddress());
|
||||
}
|
||||
boolean shouldDoOnSubOps = dialog.shouldApplyOnSubOps();
|
||||
Program program = context.getProgram();
|
||||
CreateEnumEquateCommand cmd =
|
||||
new CreateEnumEquateCommand(program, addresses, (Enum) dataType, shouldDoOnSubOps);
|
||||
tool.executeBackgroundCommand(cmd, program);
|
||||
|
||||
dialog.dispose();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called in response to the user activating rename action from the context menu.
|
||||
*
|
||||
* @param context the action context
|
||||
*/
|
||||
private void renameEquate(ListingActionContext context) {
|
||||
|
||||
// Get the scalar item that was selected. If this returns null, then something
|
||||
// invalid was selected, so exit.
|
||||
Scalar curScalar = getScalar(context);
|
||||
if (curScalar == null) {
|
||||
Scalar scalar = getScalar(context);
|
||||
if (scalar == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -279,54 +233,48 @@ public class EquatePlugin extends Plugin {
|
|||
Listing listing = context.getProgram().getListing();
|
||||
|
||||
// Create the dialog that will allow the user to select options.
|
||||
createEquateDialog(context, curScalar);
|
||||
SetEquateDialog dialog = createEquateDialog(context, scalar);
|
||||
|
||||
// Set the state of the some buttons on the dialog. ie: if the user has selected
|
||||
// a range of addresses we should automatically set the "selection" radio button
|
||||
// to the selected state.
|
||||
setEquateDialog.setHasSelection(context);
|
||||
|
||||
// Check for user-cancel action.
|
||||
int result = setEquateDialog.showRenameDialog();
|
||||
// Set the state of the some buttons on the dialog. ie: if the user has selected a range
|
||||
// of addresses we should automatically set the "selection" radio button to the selected
|
||||
// state.
|
||||
dialog.setHasSelection(context);
|
||||
int result = dialog.showRenameDialog();
|
||||
if (result == SetEquateDialog.CANCELED) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Retrieve the name we want to change the equate(s) to. If the name is null,
|
||||
// it means it's not a name that's already in the table, so just remove the
|
||||
// equate.
|
||||
String equateName = setEquateDialog.getEquateName();
|
||||
// Retrieve the name we want to change the equate(s) to. If the name is null, it means
|
||||
// it's not a name that's already in the table, so just remove the equate.
|
||||
String equateName = dialog.getEquateName();
|
||||
|
||||
// Define an iterator for the task. We're using a CodeUnitIterator to make sure we inspect
|
||||
// all Data and Instruction instances.
|
||||
CodeUnitIterator iter = null;
|
||||
|
||||
SelectionType selectionType = setEquateDialog.getSelectionType();
|
||||
|
||||
SelectionType selectionType = dialog.getSelectionType();
|
||||
if (selectionType == SelectionType.CURRENT_ADDRESS) {
|
||||
AddressSet addrSet = new AddressSet(context.getAddress());
|
||||
iter = listing.getCodeUnits(addrSet, false);
|
||||
}
|
||||
|
||||
else if (selectionType == SelectionType.SELECTION) {
|
||||
iter = listing.getCodeUnits(context.getSelection(), true);
|
||||
}
|
||||
|
||||
else if (selectionType == SelectionType.ENTIRE_PROGRAM) {
|
||||
iter = listing.getCodeUnits(context.getProgram().getMemory(), true);
|
||||
}
|
||||
|
||||
// Determine if this is a remove or rename. If the user has left the "new equate name" field
|
||||
// blank in the dialog, then remove the equate entirely.
|
||||
// Determine if this is a remove or rename. If the user has left the "new equate name"
|
||||
// field blank in the dialog, then remove the equate entirely.
|
||||
Enum enoom = dialog.getEnumDataType();
|
||||
if (equateName == null) {
|
||||
removeEquateOverRange(context, equate, iter);
|
||||
}
|
||||
else {
|
||||
renameEquate(context, equate, equateName, iter);
|
||||
renameEquate(context, enoom, equate, equateName, iter);
|
||||
}
|
||||
|
||||
// Destroy the dialog.
|
||||
dispose(setEquateDialog);
|
||||
dialog.dispose();
|
||||
}
|
||||
|
||||
private Equate getEquate(ListingActionContext context) {
|
||||
|
@ -338,7 +286,8 @@ public class EquatePlugin extends Plugin {
|
|||
return equateTable.getEquate(context.getAddress(), getOperandIndex(context), s.getValue());
|
||||
}
|
||||
|
||||
private void renameEquate(ListingActionContext context, Equate oldEquate, String newEquateName,
|
||||
private void renameEquate(ListingActionContext context, Enum enoom, Equate oldEquate,
|
||||
String newEquateName,
|
||||
CodeUnitIterator iter) {
|
||||
|
||||
// First do a sanity check to make sure we're not trying to change to a duplicate
|
||||
|
@ -356,14 +305,15 @@ public class EquatePlugin extends Plugin {
|
|||
// Now loop over all the code units and search for matching scalars...
|
||||
while (iter.hasNext()) {
|
||||
CodeUnit cu = iter.next();
|
||||
renameEquateForCodeUnit(context, oldEquate, newEquateName, oldEquateName, bckCmd, cu);
|
||||
renameEquateForCodeUnit(context, enoom, oldEquate, newEquateName, oldEquateName, bckCmd,
|
||||
cu);
|
||||
}
|
||||
|
||||
// Finally, execute all the rename tasks.
|
||||
tool.executeBackgroundCommand(bckCmd, context.getProgram());
|
||||
}
|
||||
|
||||
private void renameEquateForCodeUnit(ListingActionContext context, Equate equate,
|
||||
private void renameEquateForCodeUnit(ListingActionContext context, Enum enoom, Equate equate,
|
||||
String newName, String oldName, CompoundBackgroundCommand bgCmd, CodeUnit cu) {
|
||||
|
||||
if (cu instanceof Instruction) {
|
||||
|
@ -373,7 +323,7 @@ public class EquatePlugin extends Plugin {
|
|||
List<Integer> opIndices = getInstructionMatches(program, inst, equate);
|
||||
Address addr = inst.getAddress();
|
||||
for (Integer opIndice : opIndices) {
|
||||
bgCmd.add(createRenameCmd(oldName, newName, addr, opIndice));
|
||||
bgCmd.add(createRenameCmd(enoom, oldName, newName, addr, opIndice));
|
||||
}
|
||||
}
|
||||
else if (cu instanceof Data) {
|
||||
|
@ -381,15 +331,15 @@ public class EquatePlugin extends Plugin {
|
|||
Data data = (Data) cu;
|
||||
if (isDataMatch(data, context, equate)) {
|
||||
Address addr = data.getAddress();
|
||||
bgCmd.add(createRenameCmd(oldName, newName, addr, getOperandIndex(context)));
|
||||
bgCmd.add(createRenameCmd(enoom, oldName, newName, addr, getOperandIndex(context)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private RenameEquateCmd createRenameCmd(String oldName, String newName, Address addr,
|
||||
private RenameEquateCmd createRenameCmd(Enum enoom, String oldName, String newName,
|
||||
Address addr,
|
||||
int opIndex) {
|
||||
|
||||
Enum enoom = getEnumDataType();
|
||||
if (enoom != null) {
|
||||
return new RenameEquateCmd(oldName, enoom, addr, opIndex);
|
||||
}
|
||||
|
@ -397,10 +347,6 @@ public class EquatePlugin extends Plugin {
|
|||
return new RenameEquateCmd(oldName, newName, addr, opIndex);
|
||||
}
|
||||
|
||||
public Enum getEnumDataType() {
|
||||
return setEquateDialog.getEnumDataType();
|
||||
}
|
||||
|
||||
private void removeEquateOverRange(ListingActionContext context, Equate equate,
|
||||
CodeUnitIterator iter) {
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ import java.awt.event.*;
|
|||
import java.util.*;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.table.TableColumnModel;
|
||||
|
@ -210,13 +211,18 @@ public class SetEquateDialog extends DialogComponentProvider {
|
|||
.stream()
|
||||
.filter(dt -> dt instanceof Enum)
|
||||
.map(Enum.class::cast)
|
||||
.flatMap(enoom -> Arrays.stream(enoom.getNames(scalar.getValue())).map(name -> new EquateRowObject(name, enoom)))
|
||||
.flatMap(this::enumToRowObjects)
|
||||
.forEach(entries::add);
|
||||
//@formatter:on
|
||||
|
||||
return entries;
|
||||
}
|
||||
|
||||
private Stream<EquateRowObject> enumToRowObjects(Enum enoom) {
|
||||
String[] names = enoom.getNames(scalar.getValue());
|
||||
return Arrays.stream(names).map(name -> new EquateRowObject(name, enoom));
|
||||
}
|
||||
|
||||
/*
|
||||
* Builds the main panel of the dialog and returns it.
|
||||
*/
|
||||
|
@ -467,7 +473,7 @@ public class SetEquateDialog extends DialogComponentProvider {
|
|||
/**
|
||||
* Returns true if the user has chosen to overwrite any existing equate rules.
|
||||
*
|
||||
* @return true if the user has chosen to overwrite any existing equate rules.
|
||||
* @return true if the user has chosen to overwrite any existing equate rules.
|
||||
*/
|
||||
public boolean getOverwriteExisting() {
|
||||
return overwriteExistingEquates.isSelected();
|
||||
|
@ -507,9 +513,6 @@ public class SetEquateDialog extends DialogComponentProvider {
|
|||
this.setStatusText(text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when user selects OK button
|
||||
*/
|
||||
@Override
|
||||
protected void okCallback() {
|
||||
if (isValid(this.getEquateName(), scalar)) {
|
||||
|
@ -529,7 +532,6 @@ public class SetEquateDialog extends DialogComponentProvider {
|
|||
|
||||
// look up the new equate string
|
||||
Equate newEquate = equateTable.getEquate(equateStr);
|
||||
|
||||
if (newEquate != null && getEnumDataType() == null) {
|
||||
// make sure any existing equate with that name has the same value.
|
||||
if (newEquate.getValue() != testScalar.getValue()) {
|
||||
|
@ -545,14 +547,12 @@ public class SetEquateDialog extends DialogComponentProvider {
|
|||
return (Enum) dataTypeManager.findDataTypeForID(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when user selects Cancel Button.
|
||||
*/
|
||||
@Override
|
||||
protected void cancelCallback() {
|
||||
close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
suggestedEquatesTable.dispose();
|
||||
filterPanel.dispose();
|
||||
|
@ -577,7 +577,7 @@ public class SetEquateDialog extends DialogComponentProvider {
|
|||
}
|
||||
|
||||
this.enoom = enoom;
|
||||
this.entryName = enoom.getName(value);
|
||||
this.entryName = name;
|
||||
this.dataTypeUUID = enoom.getUniversalID();
|
||||
this.path = getFullPath(enoom);
|
||||
String formattedEquateName = EquateManager.formatNameForEquate(dataTypeUUID, value);
|
||||
|
@ -673,6 +673,9 @@ public class SetEquateDialog extends DialogComponentProvider {
|
|||
if (enoom == null || !enoom.isEquivalent(other.getEnumDataType())) {
|
||||
return false;
|
||||
}
|
||||
if (!Objects.equals(entryName, other.entryName)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -100,25 +100,28 @@ public class EnumDataTypeHTMLRepresentation extends HTMLDataTypeRepresentation {
|
|||
List<ValidatableLine> list = new ArrayList<>(values.length);
|
||||
for (long value : values) {
|
||||
|
||||
String name = enumDataType.getName(value);
|
||||
if (trim) {
|
||||
name = StringUtilities.trimMiddle(name, ToolTipUtils.LINE_LENGTH);
|
||||
}
|
||||
String[] names = enumDataType.getNames(value);
|
||||
for (String name : names) {
|
||||
if (trim) {
|
||||
name = StringUtilities.trimMiddle(name, ToolTipUtils.LINE_LENGTH);
|
||||
}
|
||||
|
||||
String hexString = Long.toHexString(value);
|
||||
if (value < 0) {
|
||||
// Long will print leading FF for 8 bytes, regardless of enum size. Keep only
|
||||
// n bytes worth of text. For example, when n is 2, turn FFFFFFFFFFFFFF12 into FF12
|
||||
int length = hexString.length();
|
||||
hexString = hexString.substring(length - (n * 2));
|
||||
}
|
||||
String hexString = Long.toHexString(value);
|
||||
if (value < 0) {
|
||||
// Long will print leading FF for 8 bytes, regardless of enum size. Keep only
|
||||
// n bytes worth of text. For example, when n is 2, turn FFFFFFFFFFFFFF12 into
|
||||
// FF12
|
||||
int length = hexString.length();
|
||||
hexString = hexString.substring(length - (n * 2));
|
||||
}
|
||||
|
||||
String comment = enumDataType.getComment(name);
|
||||
if (trim && comment != null) {
|
||||
comment = StringUtilities.trim(comment, ToolTipUtils.LINE_LENGTH);
|
||||
}
|
||||
String comment = enumDataType.getComment(name);
|
||||
if (trim && comment != null) {
|
||||
comment = StringUtilities.trim(comment, ToolTipUtils.LINE_LENGTH);
|
||||
}
|
||||
|
||||
list.add(new TextLine(name + " = 0x" + hexString + " " + comment));
|
||||
list.add(new TextLine(name + " = 0x" + hexString + " " + comment));
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
|
|
|
@ -122,7 +122,7 @@ public abstract class AbstractGhidraHeadlessIntegrationTest extends AbstractDock
|
|||
}
|
||||
|
||||
// TODO add methods:
|
||||
// createDefaultToyProgram() with no params
|
||||
// createDefaultToyProgram() with no params
|
||||
// createDefaultX86Program() with no params
|
||||
// createDefaultX86ProgramBuilder() with no params
|
||||
// createClassicNotepadProgram()
|
||||
|
@ -198,10 +198,12 @@ public abstract class AbstractGhidraHeadlessIntegrationTest extends AbstractDock
|
|||
|
||||
/**
|
||||
* Provides a convenient method for modifying the current program, handling the transaction
|
||||
* logic.
|
||||
* logic.
|
||||
*
|
||||
* @param p the program
|
||||
* @param c the code to execute
|
||||
* @see #modifyProgram(Program, ExceptionalCallback)
|
||||
* @see #modifyProgram(Program, ExceptionalFunction)
|
||||
*/
|
||||
public static <E extends Exception> void tx(Program p, ExceptionalCallback<E> c) {
|
||||
int txId = p.startTransaction("Test - Function in Transaction");
|
||||
|
@ -227,6 +229,7 @@ public abstract class AbstractGhidraHeadlessIntegrationTest extends AbstractDock
|
|||
*
|
||||
* @param p the program
|
||||
* @param c the code to execute
|
||||
* @see #modifyProgram(Program, ExceptionalFunction)
|
||||
*/
|
||||
public static <E extends Exception> void modifyProgram(Program p, ExceptionalCallback<E> c) {
|
||||
tx(p, c);
|
||||
|
@ -239,6 +242,7 @@ public abstract class AbstractGhidraHeadlessIntegrationTest extends AbstractDock
|
|||
* @param program the program
|
||||
* @param f the function for modifying the program and creating the desired result
|
||||
* @return the result
|
||||
* @see #modifyProgram(Program, ExceptionalCallback)
|
||||
*/
|
||||
public <R, E extends Exception> R modifyProgram(Program program,
|
||||
ExceptionalFunction<Program, R, E> f) {
|
||||
|
@ -462,11 +466,11 @@ public abstract class AbstractGhidraHeadlessIntegrationTest extends AbstractDock
|
|||
}
|
||||
|
||||
/**
|
||||
* A convenience method that allows you to open the given program in a default tool,
|
||||
* navigating to the given address.
|
||||
* A convenience method that allows you to open the given program in a default tool,
|
||||
* navigating to the given address.
|
||||
*
|
||||
* <P>Note: this is a blocking operation. Your test will not proceed while this method is
|
||||
* sleeping.
|
||||
* sleeping.
|
||||
*
|
||||
* <P><B>Do not leave this call in your test when committing changes.</B>
|
||||
* @param p the program
|
||||
|
@ -507,7 +511,7 @@ public abstract class AbstractGhidraHeadlessIntegrationTest extends AbstractDock
|
|||
}
|
||||
|
||||
/**
|
||||
* Waits for a launched script to complete by using the given listener.
|
||||
* Waits for a launched script to complete by using the given listener.
|
||||
*
|
||||
* @param listener the listener used to track script progress
|
||||
* @param timeoutMS the max time to wait; failing if exceeded
|
||||
|
|
|
@ -1,455 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.app.plugin.core.equate;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import javax.swing.JTextField;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
|
||||
import docking.ActionContext;
|
||||
import docking.ComponentProvider;
|
||||
import docking.action.DockingActionIf;
|
||||
import ghidra.GhidraOptions;
|
||||
import ghidra.app.context.ListingActionContext;
|
||||
import ghidra.app.events.ProgramLocationPluginEvent;
|
||||
import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin;
|
||||
import ghidra.app.util.PluginConstants;
|
||||
import ghidra.app.util.bean.SetEquateDialog;
|
||||
import ghidra.app.util.datatype.ApplyEnumDialog;
|
||||
import ghidra.app.util.viewer.field.ListingTextField;
|
||||
import ghidra.app.util.viewer.field.OperandFieldFactory;
|
||||
import ghidra.framework.options.Options;
|
||||
import ghidra.program.database.ProgramBuilder;
|
||||
import ghidra.program.database.symbol.EquateManager;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.data.Enum;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.symbol.Equate;
|
||||
import ghidra.program.model.symbol.EquateTable;
|
||||
import ghidra.program.util.OperandFieldLocation;
|
||||
import ghidra.test.AbstractProgramBasedTest;
|
||||
import ghidra.util.UniversalID;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
import ghidra.util.exception.InvalidInputException;
|
||||
|
||||
/**
|
||||
* Tests the Equate Plugin functionality.
|
||||
*/
|
||||
public abstract class AbstractEquatePluginTest extends AbstractProgramBasedTest {
|
||||
|
||||
protected Listing listing;
|
||||
protected EquatePlugin equatePlugin;
|
||||
protected CodeBrowserPlugin cb;
|
||||
protected DockingActionIf setAction;
|
||||
protected DockingActionIf renameAction;
|
||||
protected DockingActionIf removeAction;
|
||||
protected DockingActionIf applyEnumAction;
|
||||
|
||||
protected final static String SHOW_BLOCK_NAME_OPTION = GhidraOptions.OPERAND_GROUP_TITLE +
|
||||
Options.DELIMITER + GhidraOptions.OPTION_SHOW_BLOCK_NAME;
|
||||
|
||||
/**
|
||||
* Sets up the plugins and actions for the tests.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
|
||||
initialize();
|
||||
|
||||
equatePlugin = getPlugin(tool, EquatePlugin.class);
|
||||
|
||||
cb = codeBrowser;
|
||||
|
||||
listing = program.getListing();
|
||||
|
||||
Options options = tool.getOptions(GhidraOptions.CATEGORY_BROWSER_DISPLAY);
|
||||
options.getBoolean(SHOW_BLOCK_NAME_OPTION, false);
|
||||
setAction = getAction(equatePlugin, "Set Equate");
|
||||
renameAction = getAction(equatePlugin, "Rename Equate");
|
||||
removeAction = getAction(equatePlugin, "Remove Equate");
|
||||
applyEnumAction = getAction(equatePlugin, "Apply Enum");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getProgramName() {
|
||||
return "notepad";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Program getProgram() throws Exception {
|
||||
return buildProgram();
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a program and sets equates.
|
||||
*
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
protected Program buildProgram() throws Exception {
|
||||
ProgramBuilder builder = new ProgramBuilder("notepad", ProgramBuilder._X86);
|
||||
builder.createMemory("test", "0x01001000", 0x100);
|
||||
builder.createMemory("test", "0x01002000", 0x100);
|
||||
builder.createMemory("test", "0x01003000", 0x4000);
|
||||
|
||||
// for selection containing a function stack address
|
||||
builder.setBytes("0x01004bbd", "c2 08 00"); // return of previous function
|
||||
builder.setBytes("0x01004bc0", "53 8b 5c 24 08 56 8b 35 b8 10 00 01 57 ff 35 78 80 00 01 " +
|
||||
"53 ff d6 8b 3d e0 10 00 01 53 ff d7 8d 5c 43 02 68 9c 13 00 01 53 ff d6 53 ff d7 " +
|
||||
"ff 35 7c 80 00 01 8d 5c 43 02 53 ff d6 53 ff d7 8d 5c 43 02 68 e0 17 00 01 53 ff " +
|
||||
"d6 53 ff d7 66 83 64 43 02 00 8d 44 43 02 5f 5e 5b c2 04 00");
|
||||
builder.disassemble(new AddressSet(builder.getProgram(), builder.addr("0x01004bc0"),
|
||||
builder.addr("0x01004c1a")), true);
|
||||
builder.createFunction("0x01004bc0");
|
||||
|
||||
//
|
||||
// Add bytes that result in instructions containing scalar values for X86
|
||||
//
|
||||
builder.setBytes("0x010018d6", "6a 02", true);
|
||||
builder.setBytes("0x010062d6", "83 c0 05", true);
|
||||
builder.setBytes("0x01002a83", "6a 01", true);
|
||||
builder.setBytes("0x01002a8e", "c2 10 00", true);
|
||||
|
||||
// not an equate - for testing action enablement
|
||||
builder.setBytes("0x01003359", "74 4c", true);
|
||||
builder.setBytes("0x01003a94", "6a fd", true);
|
||||
|
||||
builder.setBytes("0x010035be", "6a 02", true);
|
||||
builder.setBytes("0x0100364c", "6a 02", true);
|
||||
|
||||
builder.setBytes("0x01004ad6", "6a 02", true);
|
||||
builder.setBytes("0x01004bbd", "c2 08 00", true);
|
||||
builder.setBytes("0x01004e4a", "6a 5a", true);
|
||||
|
||||
builder.setBytes("0x01005128", "68 b7 00 00 00", true);
|
||||
builder.setBytes("0x0100519f", "6a 02", true);
|
||||
builder.setBytes("0x01005a01", "3d b7 00 00 00", true);
|
||||
builder.setBytes("0x01005e9d", "68 b7 00 00 00", true);
|
||||
builder.setBytes("0x010059ef", "83 f8 ff", true);
|
||||
builder.setBytes("0x01004c20", "6a 02", true);
|
||||
builder.setBytes("0x01003384", "ff ff", true);
|
||||
|
||||
builder.setBytes("0x010060f0", "6a 01", true);
|
||||
builder.createEquate("0x010060f0", "ANOTHER_ONE", 1, 0);
|
||||
|
||||
builder.setBytes("0x01006133", "68 b7 00 00 00", true);
|
||||
builder.setBytes("0x01006245", "68 b7 00 00 00", true);
|
||||
builder.setBytes("0x010063da", "f6 45 fc 02", true);
|
||||
builder.setBytes("0x0100649a", "a1 c0 85 00 01", true);
|
||||
builder.setBytes("0x010064c5", "83 c4 08", true);
|
||||
builder.setBytes("0x010064a3", "68 10 66 00 01", true);
|
||||
builder.setBytes("0x010064ae", "83 c4 04", true);
|
||||
builder.setBytes("0x01006500", "83 c4 08", true);
|
||||
builder.setBytes("0x010065a7", "c7 45 fc ff ff ff ff", true);
|
||||
builder.setBytes("0x010065b0", "c7 45 fc ff ff ff ff", true);
|
||||
builder.createEquate("0x010064c5", "EIGHT", 8, 1);
|
||||
builder.createEquate("0x01006500", "EIGHT", 8, 1);
|
||||
|
||||
builder.setBytes("0x01006455", "83 c4 04", true);
|
||||
builder.createEquate("0x01006455", "FOUR", 4, 1);
|
||||
builder.createEquate("0x010064ae", "FOUR", 4, 1);
|
||||
|
||||
builder.setBytes("0x01006140", "6a 01", true);
|
||||
builder.setBytes("0x01006147", "6a 01", true);
|
||||
builder.setBytes("0x0100621d", "6a 01", true);
|
||||
builder.setBytes("0x010063f4", "6a 01", true);
|
||||
builder.createEquate("0x01006140", "ONE", 1, 0);
|
||||
builder.createEquate("0x01006147", "ONE", 1, 0);
|
||||
builder.createEquate("0x0100621d", "ONE", 1, 1);
|
||||
builder.createEquate("0x010063f4", "ONE", 1, 1);
|
||||
|
||||
builder.setBytes("0x010061a2", "6a 30", true);
|
||||
builder.createEquate("0x010061a2", "THIRTY", 0x30, 0);
|
||||
|
||||
builder.setBytes("0x01006252", "6a 02", true);
|
||||
builder.setBytes("0x0100644d", "6a 02", true);
|
||||
builder.createEquate("0x01006252", "TWO", 2, 0);
|
||||
builder.createEquate("0x010063da", "TWO", 2, 1);
|
||||
builder.createEquate("0x0100644d", "TWO", 2, 0);
|
||||
|
||||
builder.setBytes("0x010060b2", "6a 02", true);
|
||||
builder.setBytes("0x01006254", "6a 02", true);
|
||||
builder.createEquate("0x010060b2", "TWO_alt", 2, 1);
|
||||
builder.createEquate("0x01006254", "TWO_alt", 2, 0);
|
||||
|
||||
return builder.getProgram();
|
||||
}
|
||||
|
||||
@Override
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
env.dispose();
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
// Private Methods
|
||||
//=================================================================================================
|
||||
|
||||
protected ListingActionContext getListingContext() {
|
||||
ActionContext context = cb.getProvider().getActionContext(null);
|
||||
return (ListingActionContext) context;
|
||||
}
|
||||
|
||||
protected ApplyEnumDialog performApplyEnum() {
|
||||
ComponentProvider provider = tool.getComponentProvider(PluginConstants.CODE_BROWSER);
|
||||
DockingActionIf action = getAction(equatePlugin, "Apply Enum");
|
||||
performAction(action, provider, false);
|
||||
ApplyEnumDialog d = waitForDialogComponent(ApplyEnumDialog.class);
|
||||
return d;
|
||||
}
|
||||
|
||||
protected void performAction(String name) {
|
||||
ComponentProvider provider = cb.getProvider();
|
||||
DockingActionIf action = getAction(equatePlugin, name);
|
||||
performAction(action, provider, true);
|
||||
waitForTasks();
|
||||
}
|
||||
|
||||
protected void assertConvertActionsInPopup(boolean inPopup) {
|
||||
Set<DockingActionIf> actions = getActionsByOwner(tool, "EquatePlugin");
|
||||
for (DockingActionIf action : actions) {
|
||||
String actionName = action.getName();
|
||||
if (actionName.startsWith("Convert")) {
|
||||
assertEquals("Unexpected popup menu item state: " + actionName, inPopup,
|
||||
action.isAddToPopup(getListingContext()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void assertNonFloatConvertActionsInPopup() {
|
||||
Set<DockingActionIf> actions = getActionsByOwner(tool, "EquatePlugin");
|
||||
for (DockingActionIf action : actions) {
|
||||
String actionName = action.getName();
|
||||
if (actionName.startsWith("Convert")) {
|
||||
boolean inPopup =
|
||||
!(actionName.indexOf("Double") > 0 || actionName.indexOf("Float") > 0);
|
||||
assertEquals("Unexpected popup menu item state: " + actionName, inPopup,
|
||||
action.isAddToPopup(getListingContext()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void assertConvertNonCharNonSignedActionsInPopup() {
|
||||
Set<DockingActionIf> actions = getActionsByOwner(tool, "EquatePlugin");
|
||||
for (DockingActionIf element : actions) {
|
||||
String name = element.getName();
|
||||
if (name.startsWith("Convert") &&
|
||||
(name.indexOf("Char") < 0 && name.indexOf("Signed") < 0)) {
|
||||
assertTrue(element.isAddToPopup(getListingContext()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void assertConvertNonSignedActionsInPopup() {
|
||||
Set<DockingActionIf> actions = getActionsByOwner(tool, "EquatePlugin");
|
||||
for (DockingActionIf action : actions) {
|
||||
String name = action.getName();
|
||||
if (name.startsWith("Convert") && name.indexOf("Signed") < 0) {
|
||||
assertTrue(action.isAddToPopup(getListingContext()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void createEquate(long address, int opIndex, String equateName, long equateValue)
|
||||
throws Exception {
|
||||
EquateTable equateTable = program.getEquateTable();
|
||||
|
||||
int transactionID = program.startTransaction("Test - Create Equate at " + address);
|
||||
Equate equate = equateTable.createEquate(equateName, equateValue);
|
||||
equate.addReference(addr(address), opIndex);
|
||||
program.endTransaction(transactionID, true);
|
||||
|
||||
flushProgramEvents();
|
||||
}
|
||||
|
||||
protected void assertEquatesAppliedFromEnum(UniversalID id, int... values) {
|
||||
EquateTable et = program.getEquateTable();
|
||||
for (int value : values) {
|
||||
String fullName = EquateManager.formatNameForEquate(id, value);
|
||||
assertNotNull("Equate not applied from Enum . No equate for " + fullName,
|
||||
et.getEquate(fullName));
|
||||
}
|
||||
}
|
||||
|
||||
protected void assertEquatesNotApplied(UniversalID id, int... values) {
|
||||
EquateTable et = program.getEquateTable();
|
||||
|
||||
for (int value : values) {
|
||||
String fullName = EquateManager.formatNameForEquate(id, value);
|
||||
assertNull("Equate should not have been applied " + fullName, et.getEquate(fullName));
|
||||
}
|
||||
}
|
||||
|
||||
protected void cancel(SetEquateDialog d) {
|
||||
pressButtonByText(d.getComponent(), "Cancel");
|
||||
}
|
||||
|
||||
protected SetEquateDialog showSetEquateDialog() {
|
||||
performAction(setAction, cb.getProvider(), false);
|
||||
SetEquateDialog d =
|
||||
waitForDialogComponent(tool.getToolFrame(), SetEquateDialog.class, 2000);
|
||||
assertNotNull(d);
|
||||
assertEquals("Set Equate", d.getTitle());
|
||||
return d;
|
||||
}
|
||||
|
||||
protected void createSameValueDifferentNameEquates()
|
||||
throws DuplicateNameException, InvalidInputException {
|
||||
EquateTable eqTable = program.getEquateTable();
|
||||
|
||||
int transactionID =
|
||||
program.startTransaction("Test - Create Equate - Same Value/Different Name");
|
||||
for (int i = 0; i < 5; i++) {
|
||||
eqTable.createEquate("MY_EQUATE_" + i, 5);
|
||||
}
|
||||
program.endTransaction(transactionID, true);
|
||||
|
||||
flushProgramEvents();
|
||||
}
|
||||
|
||||
protected void assertNoEquateAt(String addressString, String scalarText) {
|
||||
Address address = program.getAddressFactory().getAddress(addressString);
|
||||
cb.goToField(address, OperandFieldFactory.FIELD_NAME, 0, 0);
|
||||
ListingTextField f = (ListingTextField) cb.getCurrentField();
|
||||
assertEquals(scalarText, f.getText());
|
||||
}
|
||||
|
||||
protected void assertEquateAt(String equateText, AddressSet scalarAddresses) {
|
||||
for (AddressRange addressRange : scalarAddresses) {
|
||||
Address address = addressRange.getMinAddress();
|
||||
cb.goToField(address, OperandFieldFactory.FIELD_NAME, 0, 0);
|
||||
ListingTextField f = (ListingTextField) cb.getCurrentField();
|
||||
assertEquals("Equate \"" + equateText + "\" not applied @ " + address, equateText,
|
||||
f.getText());
|
||||
}
|
||||
}
|
||||
|
||||
protected Enum createEnum_myEnum() {
|
||||
|
||||
DataTypeManager dataTypeManager = program.getDataTypeManager();
|
||||
int id = dataTypeManager.startTransaction("EquatePluginTest enum");
|
||||
Enum enumm = new EnumDataType("myEnum", 1);
|
||||
enumm.add("zeroScalar", 0);
|
||||
enumm.add("oneScalar", 1);
|
||||
enumm.add("twoScalar", 2);
|
||||
enumm.add("threeScalar", 3);
|
||||
enumm.add("fourScalar", 4);
|
||||
enumm.add("fiveScalar", 5);
|
||||
|
||||
enumm = (Enum) dataTypeManager.addDataType(enumm, null);
|
||||
dataTypeManager.endTransaction(id, true);
|
||||
|
||||
return enumm;
|
||||
}
|
||||
|
||||
protected void setEquateString(String equateText, SetEquateDialog d) {
|
||||
JTextField tf = findComponent(d.getComponent(), JTextField.class);
|
||||
assertNotNull(tf);
|
||||
assertEquals("", tf.getText());
|
||||
setText(tf, equateText);
|
||||
}
|
||||
|
||||
protected SetEquateDialog getSetEquatesDialog() {
|
||||
SetEquateDialog d = showSetEquateDialog();
|
||||
return d;
|
||||
}
|
||||
|
||||
protected AddressSet selectScalars_0xb7() {
|
||||
AddressSet addrs = toAddressSet(0x1006245, 0x1006133, 0x1005e9d);
|
||||
makeSelection(tool, program, addrs);
|
||||
return addrs;
|
||||
}
|
||||
|
||||
protected AddressSet selectRange(Address start, Address end) {
|
||||
AddressSet addrs = toAddressSet(start, end);
|
||||
makeSelection(tool, program, addrs);
|
||||
return addrs;
|
||||
}
|
||||
|
||||
protected AddressSet selectSetAndInvalidAddress(AddressSet addAddrSet, Address addr) {
|
||||
|
||||
AddressSet addrs = new AddressSet();
|
||||
|
||||
addrs.add(addAddrSet);
|
||||
addrs.add(addr);
|
||||
|
||||
makeSelection(tool, program, addrs);
|
||||
return addrs;
|
||||
}
|
||||
|
||||
protected void fireOperandFieldLocationEvent(Address addr, int opIndex) {
|
||||
Instruction inst = listing.getInstructionAt(addr);
|
||||
if (inst == null) {
|
||||
fail("Must have a code unit to use this method");
|
||||
}
|
||||
|
||||
String str = CodeUnitFormat.DEFAULT.getOperandRepresentationString(inst, opIndex);
|
||||
OperandFieldLocation loc =
|
||||
new OperandFieldLocation(program, addr, null, null, str, opIndex, 0);
|
||||
tool.firePluginEvent(new ProgramLocationPluginEvent("test", loc, program));
|
||||
|
||||
waitForSwing();
|
||||
}
|
||||
|
||||
protected void putCursorOnOperand(long offset, int opIndex) {
|
||||
Address addr = addr(offset);
|
||||
fireOperandFieldLocationEvent(addr, opIndex);
|
||||
waitForBusyTool(tool);
|
||||
}
|
||||
|
||||
protected SetEquateDialog showRenameEquatesDialog() {
|
||||
performAction(renameAction, cb.getProvider(), false);
|
||||
SetEquateDialog d =
|
||||
waitForDialogComponent(tool.getToolFrame(), SetEquateDialog.class, 2000);
|
||||
assertNotNull(d);
|
||||
assertEquals("Rename Equate", d.getTitle());
|
||||
return d;
|
||||
}
|
||||
|
||||
protected void flushProgramEvents() {
|
||||
program.flushEvents();
|
||||
waitForBusyTool(tool);
|
||||
}
|
||||
|
||||
protected void createSignedData(Address addr) throws Exception {
|
||||
createData(addr, SignedWordDataType.dataType);
|
||||
}
|
||||
|
||||
protected void createUnsignedData(Address addr) throws Exception {
|
||||
createData(addr, WordDataType.dataType);
|
||||
}
|
||||
|
||||
protected void createData(Address addr, DataType dt) throws Exception {
|
||||
int id = program.startTransaction("Test - Create Data");
|
||||
|
||||
dt = dt.clone(program.getDataTypeManager());
|
||||
int length = dt.getLength();
|
||||
assertTrue("", length > 0);
|
||||
listing.clearCodeUnits(addr, addr.add(length - 1), true);
|
||||
program.getListing().createData(addr, dt);
|
||||
|
||||
program.endTransaction(id, true);
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,526 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.app.plugin.core.equate;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import javax.swing.JCheckBox;
|
||||
import javax.swing.JRadioButton;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import docking.ComponentProvider;
|
||||
import docking.action.DockingActionIf;
|
||||
import docking.widgets.DropDownSelectionTextField;
|
||||
import ghidra.GhidraOptions;
|
||||
import ghidra.app.events.ProgramLocationPluginEvent;
|
||||
import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin;
|
||||
import ghidra.app.util.PluginConstants;
|
||||
import ghidra.app.util.bean.SetEquateDialog;
|
||||
import ghidra.app.util.datatype.ApplyEnumDialog;
|
||||
import ghidra.framework.options.Options;
|
||||
import ghidra.program.database.ProgramBuilder;
|
||||
import ghidra.program.database.symbol.EquateManager;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSet;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.data.Enum;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.symbol.Equate;
|
||||
import ghidra.program.model.symbol.EquateTable;
|
||||
import ghidra.program.util.OperandFieldLocation;
|
||||
import ghidra.test.AbstractProgramBasedTest;
|
||||
import ghidra.util.UniversalID;
|
||||
|
||||
/**
|
||||
* Tests the Equate Plugin functionality.
|
||||
*/
|
||||
public class EquatePlugin2Test extends AbstractProgramBasedTest {
|
||||
|
||||
private final static String SHOW_BLOCK_NAME_OPTION = GhidraOptions.OPERAND_GROUP_TITLE +
|
||||
Options.DELIMITER + GhidraOptions.OPTION_SHOW_BLOCK_NAME;
|
||||
|
||||
private DockingActionIf setAction;
|
||||
private DockingActionIf renameAction;
|
||||
private EquatePlugin equatePlugin;
|
||||
private CodeBrowserPlugin cb;
|
||||
private Listing listing;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
|
||||
initialize();
|
||||
|
||||
equatePlugin = getPlugin(tool, EquatePlugin.class);
|
||||
|
||||
cb = codeBrowser;
|
||||
|
||||
listing = program.getListing();
|
||||
|
||||
Options options = tool.getOptions(GhidraOptions.CATEGORY_BROWSER_DISPLAY);
|
||||
options.getBoolean(SHOW_BLOCK_NAME_OPTION, false);
|
||||
setAction = getAction(equatePlugin, "Set Equate");
|
||||
renameAction = getAction(equatePlugin, "Rename Equate");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProgramName() {
|
||||
return "sample";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Program getProgram() throws Exception {
|
||||
|
||||
ProgramBuilder builder = new ProgramBuilder("sample", ProgramBuilder._X86);
|
||||
builder.createMemory("test", "0x01001000", 0x100);
|
||||
builder.createMemory("test", "0x01002000", 0x100);
|
||||
builder.createMemory("test", "0x01003000", 0x4000);
|
||||
|
||||
// for selection containing a function stack address
|
||||
builder.setBytes("0x01004bbd", "c2 08 00"); // return of previous function
|
||||
builder.setBytes("0x01004bc0", "53 8b 5c 24 08 56 8b 35 b8 10 00 01 57 ff 35 78 80 00 01 " +
|
||||
"53 ff d6 8b 3d e0 10 00 01 53 ff d7 8d 5c 43 02 68 9c 13 00 01 53 ff d6 53 ff d7 " +
|
||||
"ff 35 7c 80 00 01 8d 5c 43 02 53 ff d6 53 ff d7 8d 5c 43 02 68 e0 17 00 01 53 ff " +
|
||||
"d6 53 ff d7 66 83 64 43 02 00 8d 44 43 02 5f 5e 5b c2 04 00");
|
||||
builder.disassemble(new AddressSet(builder.getProgram(), builder.addr("0x01004bc0"),
|
||||
builder.addr("0x01004c1a")), true);
|
||||
builder.createFunction("0x01004bc0");
|
||||
|
||||
//
|
||||
// Add bytes that result in instructions containing scalar values for X86
|
||||
//
|
||||
builder.setBytes("0x010018d6", "6a 02", true);
|
||||
builder.setBytes("0x010062d6", "83 c0 05", true);
|
||||
builder.setBytes("0x01002a83", "6a 01", true);
|
||||
builder.setBytes("0x01002a8e", "c2 10 00", true);
|
||||
|
||||
// not an equate - for testing action enablement
|
||||
builder.setBytes("0x01003359", "74 4c", true);
|
||||
builder.setBytes("0x01003a94", "6a fd", true);
|
||||
|
||||
builder.setBytes("0x010035be", "6a 02", true);
|
||||
builder.setBytes("0x0100364c", "6a 02", true);
|
||||
|
||||
builder.setBytes("0x01004ad6", "6a 02", true);
|
||||
builder.setBytes("0x01004bbd", "c2 08 00", true);
|
||||
builder.setBytes("0x01004e4a", "6a 5a", true);
|
||||
|
||||
builder.setBytes("0x01005128", "68 b7 00 00 00", true);
|
||||
builder.setBytes("0x0100519f", "6a 02", true);
|
||||
builder.setBytes("0x01005a01", "3d b7 00 00 00", true);
|
||||
builder.setBytes("0x01005e9d", "68 b7 00 00 00", true);
|
||||
builder.setBytes("0x010059ef", "83 f8 ff", true);
|
||||
builder.setBytes("0x01004c20", "6a 02", true);
|
||||
builder.setBytes("0x01003384", "ff ff", true);
|
||||
|
||||
builder.setBytes("0x010060f0", "6a 01", true);
|
||||
builder.createEquate("0x010060f0", "ANOTHER_ONE", 1, 0);
|
||||
|
||||
builder.setBytes("0x01006133", "68 b7 00 00 00", true);
|
||||
builder.setBytes("0x01006245", "68 b7 00 00 00", true);
|
||||
builder.setBytes("0x010063da", "f6 45 fc 02", true);
|
||||
builder.setBytes("0x0100649a", "a1 c0 85 00 01", true);
|
||||
builder.setBytes("0x010064c5", "83 c4 08", true);
|
||||
builder.setBytes("0x010064a3", "68 10 66 00 01", true);
|
||||
builder.setBytes("0x010064ae", "83 c4 04", true);
|
||||
builder.setBytes("0x01006500", "83 c4 08", true);
|
||||
builder.setBytes("0x010065a7", "c7 45 fc ff ff ff ff", true);
|
||||
builder.setBytes("0x010065b0", "c7 45 fc ff ff ff ff", true);
|
||||
builder.createEquate("0x010064c5", "EIGHT", 8, 1);
|
||||
builder.createEquate("0x01006500", "EIGHT", 8, 1);
|
||||
|
||||
builder.setBytes("0x01006455", "83 c4 04", true);
|
||||
builder.createEquate("0x01006455", "FOUR", 4, 1);
|
||||
builder.createEquate("0x010064ae", "FOUR", 4, 1);
|
||||
|
||||
builder.setBytes("0x01006140", "6a 01", true);
|
||||
builder.setBytes("0x01006147", "6a 01", true);
|
||||
builder.setBytes("0x0100621d", "6a 01", true);
|
||||
builder.setBytes("0x010063f4", "6a 01", true);
|
||||
builder.createEquate("0x01006140", "ONE", 1, 0);
|
||||
builder.createEquate("0x01006147", "ONE", 1, 0);
|
||||
builder.createEquate("0x0100621d", "ONE", 1, 1);
|
||||
builder.createEquate("0x010063f4", "ONE", 1, 1);
|
||||
|
||||
builder.setBytes("0x010061a2", "6a 30", true);
|
||||
builder.createEquate("0x010061a2", "THIRTY", 0x30, 0);
|
||||
|
||||
builder.setBytes("0x01006252", "6a 02", true);
|
||||
builder.setBytes("0x0100644d", "6a 02", true);
|
||||
builder.createEquate("0x01006252", "TWO", 2, 0);
|
||||
builder.createEquate("0x010063da", "TWO", 2, 1);
|
||||
builder.createEquate("0x0100644d", "TWO", 2, 0);
|
||||
|
||||
builder.setBytes("0x010060b2", "6a 02", true);
|
||||
builder.setBytes("0x01006254", "6a 02", true);
|
||||
builder.createEquate("0x010060b2", "TWO_alt", 2, 1);
|
||||
builder.createEquate("0x01006254", "TWO_alt", 2, 0);
|
||||
|
||||
return builder.getProgram();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testApplyToOptions_SetEquate() {
|
||||
putCursorOnOperand(0x01002a8e, 0);
|
||||
|
||||
SetEquateDialog d = showSetEquateDialog();
|
||||
|
||||
JRadioButton applyToCurrentButton =
|
||||
(JRadioButton) findComponentByName(d.getComponent(), "applyToCurrent");
|
||||
JRadioButton applyToSelectionButton =
|
||||
(JRadioButton) findComponentByName(d.getComponent(), "applyToSelection");
|
||||
final JRadioButton applyToAllButton =
|
||||
(JRadioButton) findComponentByName(d.getComponent(), "applyToAll");
|
||||
JCheckBox overwriteExistingEquatesButton =
|
||||
(JCheckBox) findComponentByName(d.getComponent(), "Overwrite");
|
||||
|
||||
//dialog should come up with "current location" enabled and selected in all cases (even if a selection)
|
||||
assertNotNull(applyToCurrentButton);
|
||||
assertTrue(applyToCurrentButton.isEnabled());
|
||||
assertTrue(applyToCurrentButton.isSelected());
|
||||
|
||||
//no selection in this case so should be disabled and not selected
|
||||
assertNotNull(applyToSelectionButton);
|
||||
assertFalse(applyToSelectionButton.isEnabled());
|
||||
assertFalse(applyToSelectionButton.isSelected());
|
||||
|
||||
//entire program should be enabled but not selected
|
||||
assertNotNull(applyToAllButton);
|
||||
assertTrue(applyToAllButton.isEnabled());
|
||||
assertFalse(applyToAllButton.isSelected());
|
||||
|
||||
//overwrite existing should be visible but not be enabled or selected
|
||||
assertTrue(overwriteExistingEquatesButton.isVisible());
|
||||
assertFalse(overwriteExistingEquatesButton.isEnabled());
|
||||
assertFalse(overwriteExistingEquatesButton.isSelected());
|
||||
|
||||
//select applyToAll and verify that the other buttons respond accordingly
|
||||
applyToAllButton.setSelected(true);
|
||||
runSwing(
|
||||
() -> applyToAllButton.getActionListeners()[0].actionPerformed(null));
|
||||
program.flushEvents();
|
||||
waitForSwing();
|
||||
|
||||
assertTrue(applyToAllButton.isSelected());
|
||||
assertFalse(applyToCurrentButton.isSelected());
|
||||
assertFalse(applyToSelectionButton.isSelected());
|
||||
assertTrue(overwriteExistingEquatesButton.isEnabled());
|
||||
assertFalse(overwriteExistingEquatesButton.isSelected());
|
||||
|
||||
close(d);
|
||||
}
|
||||
|
||||
/*
|
||||
* Tests that the current selection button is the default option on the
|
||||
* Set Equate dialog if there is a range of addresses selected.
|
||||
*
|
||||
* @throws InterruptedException
|
||||
* @throws InvocationTargetException
|
||||
*/
|
||||
@Test
|
||||
public void testApplyToOptions_SetEquate_Selection() {
|
||||
|
||||
// put the cursor on a scalar
|
||||
putCursorOnOperand(0x1004bbd, 0);
|
||||
|
||||
// make a selection containing the scalar above.
|
||||
makeSelection(tool, program, addr("1004bbd"), addr("1004bc5"));
|
||||
|
||||
SetEquateDialog d = showSetEquateDialog();
|
||||
|
||||
JRadioButton applyToCurrentButton =
|
||||
(JRadioButton) findComponentByName(d.getComponent(), "applyToCurrent");
|
||||
final JRadioButton applyToSelectionButton =
|
||||
(JRadioButton) findComponentByName(d.getComponent(), "applyToSelection");
|
||||
final JRadioButton applyToAllButton =
|
||||
(JRadioButton) findComponentByName(d.getComponent(), "applyToAll");
|
||||
JCheckBox overwriteExistingEquatesButton =
|
||||
(JCheckBox) findComponentByName(d.getComponent(), "Overwrite");
|
||||
|
||||
//change as of 7.0 - dialog should come up with "current location" enabled.
|
||||
assertNotNull(applyToCurrentButton);
|
||||
assertTrue(applyToCurrentButton.isEnabled());
|
||||
assertFalse(applyToCurrentButton.isSelected());
|
||||
|
||||
//have selection in this case so should be enabled but not selected
|
||||
assertNotNull(applyToSelectionButton);
|
||||
assertTrue(applyToSelectionButton.isEnabled());
|
||||
assertTrue(applyToSelectionButton.isSelected());
|
||||
|
||||
//entire program should be enabled but not selected
|
||||
assertNotNull(applyToAllButton);
|
||||
assertTrue(applyToAllButton.isEnabled());
|
||||
assertFalse(applyToAllButton.isSelected());
|
||||
|
||||
//overwrite existing should be visible and enabled, but not selected
|
||||
assertTrue(overwriteExistingEquatesButton.isVisible());
|
||||
assertTrue(overwriteExistingEquatesButton.isEnabled());
|
||||
assertFalse(overwriteExistingEquatesButton.isSelected());
|
||||
|
||||
//select applyToSelection and verify that the other buttons respond accordingly
|
||||
applyToSelectionButton.setSelected(true);
|
||||
runSwing(
|
||||
() -> applyToSelectionButton.getActionListeners()[0].actionPerformed(null));
|
||||
program.flushEvents();
|
||||
waitForSwing();
|
||||
|
||||
assertFalse(applyToAllButton.isSelected());
|
||||
assertFalse(applyToCurrentButton.isSelected());
|
||||
assertTrue(applyToSelectionButton.isSelected());
|
||||
assertTrue(overwriteExistingEquatesButton.isEnabled());
|
||||
assertFalse(overwriteExistingEquatesButton.isSelected());
|
||||
|
||||
close(d);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testApplyToOptions_RenameEquate() {
|
||||
putCursorOnOperand(0x010064c5, 1);
|
||||
|
||||
performAction(renameAction, cb.getProvider(), false);
|
||||
SetEquateDialog d =
|
||||
waitForDialogComponent(SetEquateDialog.class);
|
||||
assertNotNull(d);
|
||||
|
||||
JRadioButton applyToCurrentButton =
|
||||
(JRadioButton) findComponentByName(d.getComponent(), "applyToCurrent");
|
||||
JRadioButton applyToSelectionButton =
|
||||
(JRadioButton) findComponentByName(d.getComponent(), "applyToSelection");
|
||||
JRadioButton applyToAllButton =
|
||||
(JRadioButton) findComponentByName(d.getComponent(), "applyToAll");
|
||||
JCheckBox overwriteExistingEquatesButton =
|
||||
(JCheckBox) findComponentByName(d.getComponent(), "Overwrite");
|
||||
|
||||
//no selection so should come up selected
|
||||
assertNotNull(applyToCurrentButton);
|
||||
assertTrue(applyToCurrentButton.isEnabled());
|
||||
assertTrue(applyToCurrentButton.isSelected());
|
||||
|
||||
//no selection in this case so should be disabled and not selected
|
||||
assertNotNull(applyToSelectionButton);
|
||||
assertFalse(applyToSelectionButton.isEnabled());
|
||||
assertFalse(applyToSelectionButton.isSelected());
|
||||
|
||||
//entire program should be enabled but not selected
|
||||
assertNotNull(applyToAllButton);
|
||||
assertTrue(applyToAllButton.isEnabled());
|
||||
assertFalse(applyToAllButton.isSelected());
|
||||
|
||||
//overwrite existing should not be visible, enabled, or selected
|
||||
assertFalse(overwriteExistingEquatesButton.isVisible());
|
||||
assertFalse(overwriteExistingEquatesButton.isEnabled());
|
||||
assertFalse(overwriteExistingEquatesButton.isSelected());
|
||||
|
||||
close(d);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testApplyToOptions_RenameEquate_Selection() {
|
||||
|
||||
putCursorOnOperand(0x010064c5, 1);
|
||||
|
||||
selectRange(addr("10064c5"), addr("10064ce"));
|
||||
|
||||
performAction(renameAction, cb.getProvider(), false);
|
||||
SetEquateDialog d =
|
||||
waitForDialogComponent(SetEquateDialog.class);
|
||||
assertNotNull(d);
|
||||
|
||||
JRadioButton applyToCurrentButton =
|
||||
(JRadioButton) findComponentByName(d.getComponent(), "applyToCurrent");
|
||||
JRadioButton applyToSelectionButton =
|
||||
(JRadioButton) findComponentByName(d.getComponent(), "applyToSelection");
|
||||
JRadioButton applyToAllButton =
|
||||
(JRadioButton) findComponentByName(d.getComponent(), "applyToAll");
|
||||
JCheckBox overwriteExistingEquatesButton =
|
||||
(JCheckBox) findComponentByName(d.getComponent(), "Overwrite");
|
||||
|
||||
//change as of 7.0 - dialog should come up with "current location" enabled.
|
||||
assertNotNull(applyToCurrentButton);
|
||||
assertTrue(applyToCurrentButton.isEnabled());
|
||||
assertFalse(applyToCurrentButton.isSelected());
|
||||
|
||||
//have selection in this case so should be enabled but not selected
|
||||
assertNotNull(applyToSelectionButton);
|
||||
assertTrue(applyToSelectionButton.isEnabled());
|
||||
assertTrue(applyToSelectionButton.isSelected());
|
||||
|
||||
//entire program should be enabled but not selected
|
||||
assertNotNull(applyToAllButton);
|
||||
assertTrue(applyToAllButton.isEnabled());
|
||||
assertFalse(applyToAllButton.isSelected());
|
||||
|
||||
//overwrite existing should not be visible, enabled, or selected
|
||||
assertFalse(overwriteExistingEquatesButton.isVisible());
|
||||
assertFalse(overwriteExistingEquatesButton.isEnabled());
|
||||
assertFalse(overwriteExistingEquatesButton.isSelected());
|
||||
|
||||
close(d);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testApplyEnumInSelection_DoOnSubOperands() throws Exception {
|
||||
Address addr1 = addr(0x01004bdd);
|
||||
Address addr2 = addr(0x01004c1f);
|
||||
selectRange(addr1, addr2);
|
||||
|
||||
EquateTable et = program.getEquateTable();
|
||||
UniversalID id = createEnum_myEnum().getUniversalID();
|
||||
|
||||
createEquate(0x01004c0d, 1, "bob", 0x0);
|
||||
assertNotNull(et.getEquate(addr(0x01004c0d), 1, 0x0));
|
||||
|
||||
ApplyEnumDialog d = performApplyEnum();
|
||||
|
||||
setToggleButtonSelected(d.getComponent(), "subOpCB", true);
|
||||
|
||||
DropDownSelectionTextField<DataType> textField = d.getEditor().getDropDownTextField();
|
||||
triggerText(textField, "myEnum");
|
||||
waitForSwing();
|
||||
triggerEnter(textField);
|
||||
waitForTasks();
|
||||
|
||||
assertFalse(et.getEquate(addr(0x01004c0d), 1, 0x0).getName().equals("bob"));
|
||||
assertEquatesAppliedFromEnum(id, 0, 2, 4);
|
||||
assertEquatesNotApplied(id, 3, 5);
|
||||
|
||||
// Special cases right below
|
||||
String errorMsg = "Equate not applied from Enum . No equate for ";
|
||||
Address twoSameScalarAddress = addr(0x01004bdf);
|
||||
assertNotNull(errorMsg, et.getEquate(twoSameScalarAddress, 1, 0x2));
|
||||
|
||||
Address twoDifferentScalarsAddress = addr(0x01004c0d);
|
||||
assertNotNull(errorMsg, et.getEquate(twoDifferentScalarsAddress, 0, 0x2));
|
||||
assertNotNull(errorMsg, et.getEquate(twoDifferentScalarsAddress, 1, 0x0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testApplyEnumInSelection_DontDoOnSubOperands() throws Exception {
|
||||
Address addr1 = addr(0x01004c0b);
|
||||
Address addr2 = addr(0x01004c17);
|
||||
selectRange(addr1, addr2);
|
||||
|
||||
UniversalID id = createEnum_myEnum().getUniversalID();
|
||||
|
||||
ApplyEnumDialog d = performApplyEnum();
|
||||
|
||||
setToggleButtonSelected(d.getComponent(), "subOpCB", false);
|
||||
|
||||
DropDownSelectionTextField<DataType> textField = d.getEditor().getDropDownTextField();
|
||||
triggerText(textField, "myEnum");
|
||||
waitForSwing();
|
||||
triggerEnter(textField);
|
||||
|
||||
assertEquatesAppliedFromEnum(id, 0);
|
||||
assertEquatesNotApplied(id, 2);
|
||||
}
|
||||
|
||||
private SetEquateDialog showSetEquateDialog() {
|
||||
performAction(setAction, cb.getProvider(), false);
|
||||
SetEquateDialog d = waitForDialogComponent(SetEquateDialog.class);
|
||||
assertEquals("Set Equate", d.getTitle());
|
||||
return d;
|
||||
}
|
||||
|
||||
private void fireOperandFieldLocationEvent(Address addr, int opIndex) {
|
||||
Instruction inst = listing.getInstructionAt(addr);
|
||||
if (inst == null) {
|
||||
fail("Must have a code unit to use this method");
|
||||
}
|
||||
|
||||
String str = CodeUnitFormat.DEFAULT.getOperandRepresentationString(inst, opIndex);
|
||||
OperandFieldLocation loc =
|
||||
new OperandFieldLocation(program, addr, null, null, str, opIndex, 0);
|
||||
tool.firePluginEvent(new ProgramLocationPluginEvent("test", loc, program));
|
||||
|
||||
waitForSwing();
|
||||
}
|
||||
|
||||
private void putCursorOnOperand(long offset, int opIndex) {
|
||||
Address addr = addr(offset);
|
||||
fireOperandFieldLocationEvent(addr, opIndex);
|
||||
waitForBusyTool(tool);
|
||||
}
|
||||
|
||||
private void assertEquatesAppliedFromEnum(UniversalID id, int... values) {
|
||||
EquateTable et = program.getEquateTable();
|
||||
for (int value : values) {
|
||||
String fullName = EquateManager.formatNameForEquate(id, value);
|
||||
assertNotNull("Equate not applied from Enum . No equate for " + fullName,
|
||||
et.getEquate(fullName));
|
||||
}
|
||||
}
|
||||
|
||||
private void assertEquatesNotApplied(UniversalID id, int... values) {
|
||||
EquateTable et = program.getEquateTable();
|
||||
|
||||
for (int value : values) {
|
||||
String fullName = EquateManager.formatNameForEquate(id, value);
|
||||
assertNull("Equate should not have been applied " + fullName, et.getEquate(fullName));
|
||||
}
|
||||
}
|
||||
|
||||
private void createEquate(long address, int opIndex, String equateName, long equateValue)
|
||||
throws Exception {
|
||||
EquateTable equateTable = program.getEquateTable();
|
||||
|
||||
int transactionID = program.startTransaction("Test - Create Equate at " + address);
|
||||
Equate equate = equateTable.createEquate(equateName, equateValue);
|
||||
equate.addReference(addr(address), opIndex);
|
||||
program.endTransaction(transactionID, true);
|
||||
|
||||
flushProgramEvents();
|
||||
}
|
||||
|
||||
private AddressSet selectRange(Address start, Address end) {
|
||||
AddressSet addrs = toAddressSet(start, end);
|
||||
makeSelection(tool, program, addrs);
|
||||
return addrs;
|
||||
}
|
||||
|
||||
private void flushProgramEvents() {
|
||||
program.flushEvents();
|
||||
waitForBusyTool(tool);
|
||||
}
|
||||
|
||||
private Enum createEnum_myEnum() {
|
||||
|
||||
DataTypeManager dataTypeManager = program.getDataTypeManager();
|
||||
int id = dataTypeManager.startTransaction("EquatePluginTest enum");
|
||||
Enum enumm = new EnumDataType("myEnum", 1);
|
||||
enumm.add("zeroScalar", 0);
|
||||
enumm.add("oneScalar", 1);
|
||||
enumm.add("twoScalar", 2);
|
||||
enumm.add("threeScalar", 3);
|
||||
enumm.add("fourScalar", 4);
|
||||
enumm.add("fiveScalar", 5);
|
||||
|
||||
enumm = (Enum) dataTypeManager.addDataType(enumm, null);
|
||||
dataTypeManager.endTransaction(id, true);
|
||||
|
||||
return enumm;
|
||||
}
|
||||
|
||||
private ApplyEnumDialog performApplyEnum() {
|
||||
ComponentProvider provider = tool.getComponentProvider(PluginConstants.CODE_BROWSER);
|
||||
DockingActionIf action = getAction(equatePlugin, "Apply Enum");
|
||||
performAction(action, provider, false);
|
||||
ApplyEnumDialog d = waitForDialogComponent(ApplyEnumDialog.class);
|
||||
return d;
|
||||
}
|
||||
|
||||
}
|
|
@ -81,7 +81,7 @@ public class EquateTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
}
|
||||
|
||||
private Program buildProgram() throws Exception {
|
||||
ToyProgramBuilder builder = new ToyProgramBuilder("notepad", true);
|
||||
ToyProgramBuilder builder = new ToyProgramBuilder("sample", true);
|
||||
builder.createMemory("test", "0x01006000", 0x1000);
|
||||
|
||||
builder.createEquate("0x010060f0", "ANOTHER_ONE", 1, 0);
|
||||
|
@ -116,7 +116,7 @@ public class EquateTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
|
||||
@Test
|
||||
public void testEquateTableView() throws Exception {
|
||||
// verify that the equate table shows the equates and the references
|
||||
// verify that the equate table shows the equates and the references
|
||||
assertNotNull(refsTable);
|
||||
assertNotNull(refsModel);
|
||||
assertEquals(1, refsModel.getRowCount());
|
||||
|
@ -137,7 +137,7 @@ public class EquateTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
|
||||
@Test
|
||||
public void testRefsNavigation() {
|
||||
// select a row in the refs table; the browser should go there
|
||||
// select a row in the refs table; the browser should go there
|
||||
|
||||
setRowSelection(equatesTable, 1, 1);
|
||||
|
||||
|
@ -271,7 +271,7 @@ public class EquateTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
assertTrue(pluginAction.isEnabled());
|
||||
performAction(pluginAction, false);
|
||||
|
||||
OptionDialog d = waitForDialogComponent(tool.getToolFrame(), OptionDialog.class, 2000);
|
||||
OptionDialog d = waitForDialogComponent(OptionDialog.class);
|
||||
assertNotNull(d);
|
||||
assertEquals("Delete Equate?", d.getTitle());
|
||||
|
||||
|
@ -307,7 +307,7 @@ public class EquateTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
assertTrue(pluginAction.isEnabled());
|
||||
performAction(pluginAction, false);
|
||||
|
||||
OptionDialog d = waitForDialogComponent(tool.getToolFrame(), OptionDialog.class, 2000);
|
||||
OptionDialog d = waitForDialogComponent(OptionDialog.class);
|
||||
assertNotNull(d);
|
||||
assertEquals("Delete Equate?", d.getTitle());
|
||||
|
||||
|
@ -328,7 +328,7 @@ public class EquateTablePluginTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
|
||||
//==================================================================================================
|
||||
// Private methods
|
||||
//==================================================================================================
|
||||
//==================================================================================================
|
||||
|
||||
private void setRowSelection(JTable table, int rowStart, int rowEnd) {
|
||||
waitForSwing();
|
||||
|
|
|
@ -169,7 +169,7 @@ class EnumDB extends DataTypeDB implements Enum {
|
|||
checkIsValid();
|
||||
initializeIfNeeded();
|
||||
List<String> list = valueMap.get(value);
|
||||
if (list == null) {
|
||||
if (list == null || list.isEmpty()) {
|
||||
return new String[0];
|
||||
}
|
||||
return list.toArray(new String[0]);
|
||||
|
|
|
@ -66,9 +66,6 @@ public class EquateDB extends DatabaseObject implements Equate {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.symbol.Equate#addReference(ghidra.program.model.address.Address, int)
|
||||
*/
|
||||
@Override
|
||||
public void addReference(Address refAddr, int opIndex) {
|
||||
checkDeleted();
|
||||
|
@ -95,9 +92,6 @@ public class EquateDB extends DatabaseObject implements Equate {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.symbol.Equate#addReference(long, ghidra.program.model.address.Address)
|
||||
*/
|
||||
@Override
|
||||
public void addReference(long dynamicHash, Address refAddr) {
|
||||
checkDeleted();
|
||||
|
@ -145,9 +139,6 @@ public class EquateDB extends DatabaseObject implements Equate {
|
|||
return opIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.symbol.Equate#getName()
|
||||
*/
|
||||
@Override
|
||||
public String getName() {
|
||||
checkIsValid();
|
||||
|
@ -178,9 +169,6 @@ public class EquateDB extends DatabaseObject implements Equate {
|
|||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.symbol.Equate#getReferenceCount()
|
||||
*/
|
||||
@Override
|
||||
public int getReferenceCount() {
|
||||
checkIsValid();
|
||||
|
@ -193,9 +181,6 @@ public class EquateDB extends DatabaseObject implements Equate {
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.symbol.Equate#getReferences()
|
||||
*/
|
||||
@Override
|
||||
public EquateReference[] getReferences() {
|
||||
checkIsValid();
|
||||
|
@ -208,9 +193,6 @@ public class EquateDB extends DatabaseObject implements Equate {
|
|||
return new EquateReference[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.symbol.Equate#getReferences(Address)
|
||||
*/
|
||||
@Override
|
||||
public List<EquateReference> getReferences(Address refAddr) {
|
||||
Lock lock = equateMgr.getLock();
|
||||
|
@ -229,27 +211,18 @@ public class EquateDB extends DatabaseObject implements Equate {
|
|||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.symbol.Equate#getValue()
|
||||
*/
|
||||
@Override
|
||||
public long getValue() {
|
||||
checkIsValid();
|
||||
return record.getLongValue(EquateDBAdapter.VALUE_COL);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.symbol.Equate#getDisplayValue()
|
||||
*/
|
||||
@Override
|
||||
public String getDisplayValue() {
|
||||
long val = getValue();
|
||||
return ((val < 0) ? "-" : "") + "0x" + Long.toHexString(Math.abs(val));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.symbol.Equate#removeReference(ghidra.program.model.address.Address, int)
|
||||
*/
|
||||
@Override
|
||||
public void removeReference(Address refAddr, int opIndex) {
|
||||
checkDeleted();
|
||||
|
@ -261,9 +234,6 @@ public class EquateDB extends DatabaseObject implements Equate {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.symbol.Equate#removeReference(long, ghidra.program.model.address.Address)
|
||||
*/
|
||||
@Override
|
||||
public void removeReference(long dynamicHash, Address refAddr) {
|
||||
checkDeleted();
|
||||
|
@ -275,9 +245,6 @@ public class EquateDB extends DatabaseObject implements Equate {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ghidra.program.model.symbol.Equate#renameEquate(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public void renameEquate(String newName) throws DuplicateNameException, InvalidInputException {
|
||||
Lock lock = equateMgr.getLock();
|
||||
|
@ -294,6 +261,7 @@ public class EquateDB extends DatabaseObject implements Equate {
|
|||
throw new DuplicateNameException("Equate named " + newName + " already exists");
|
||||
}
|
||||
catch (NotFoundException e) {
|
||||
// this is expected, since an existing name will be an unwanted duplicate
|
||||
}
|
||||
catch (IOException e) {
|
||||
equateMgr.dbError(e);
|
||||
|
@ -333,10 +301,6 @@ public class EquateDB extends DatabaseObject implements Equate {
|
|||
return getName().startsWith(EquateManager.DATATYPE_TAG);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @see java.lang.Object#equals(Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
|
||||
|
@ -350,26 +314,19 @@ public class EquateDB extends DatabaseObject implements Equate {
|
|||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
Equate eq = (Equate) obj;
|
||||
|
||||
Equate eq = (Equate) obj;
|
||||
if (getValue() != eq.getValue()) {
|
||||
return false;
|
||||
}
|
||||
return getName().equals(eq.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return getName().hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return getDisplayName();
|
||||
|
|
|
@ -37,6 +37,13 @@ public interface Enum extends DataType {
|
|||
*/
|
||||
public String getName(long value);
|
||||
|
||||
/**
|
||||
* Returns all names that map to the given value.
|
||||
* @param value value for the enum entries.
|
||||
* @return all names; null if there is not name for the given value.
|
||||
*/
|
||||
public String[] getNames(long value);
|
||||
|
||||
/**
|
||||
* Get the comment for the given name.
|
||||
* @param name name of the entry.
|
||||
|
|
|
@ -96,6 +96,15 @@ public class EnumDataType extends GenericDataType implements Enum {
|
|||
return list.get(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getNames(long value) {
|
||||
List<String> list = valueMap.get(value);
|
||||
if (list == null || list.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return list.toArray(new String[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getComment(String valueName) {
|
||||
String comment = commentMap.get(valueName);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue