Merge remote-tracking branch 'origin/GT-3227-dragonmacher-equate-manager-transactions'

This commit is contained in:
Ryan Kurtz 2019-10-18 08:47:44 -04:00
commit 792ad17cdb
6 changed files with 306 additions and 576 deletions

View file

@ -15,13 +15,20 @@
*/ */
package ghidra.app.plugin.core.equate; package ghidra.app.plugin.core.equate;
import java.util.*;
import ghidra.framework.cmd.BackgroundCommand; import ghidra.framework.cmd.BackgroundCommand;
import ghidra.framework.model.DomainObject; import ghidra.framework.model.DomainObject;
import ghidra.program.database.symbol.EquateManager;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSetView; import ghidra.program.model.address.AddressSetView;
import ghidra.program.model.data.Enum; import ghidra.program.model.data.Enum;
import ghidra.program.model.listing.Program; import ghidra.program.model.listing.*;
import ghidra.program.model.scalar.Scalar;
import ghidra.program.model.symbol.Equate;
import ghidra.program.model.symbol.EquateTable; import ghidra.program.model.symbol.EquateTable;
import ghidra.util.exception.CancelledException; import ghidra.util.Msg;
import ghidra.util.exception.*;
import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskMonitor;
public class CreateEnumEquateCommand extends BackgroundCommand { public class CreateEnumEquateCommand extends BackgroundCommand {
@ -30,6 +37,7 @@ public class CreateEnumEquateCommand extends BackgroundCommand {
private Enum enoom; private Enum enoom;
private Program program; private Program program;
private boolean shouldDoOnSubOps; private boolean shouldDoOnSubOps;
private EquateTable equateTable;
/** /**
* Constructor * Constructor
@ -37,33 +45,123 @@ public class CreateEnumEquateCommand extends BackgroundCommand {
* @param program The program to use * @param program The program to use
* @param addresses The addresses to apply an enum to * @param addresses The addresses to apply an enum to
* @param enoom The enum to apply equates with * @param enoom The enum to apply equates with
* @param shouldIncludeTypes True if the equate name should include the enum name. * @param shouldDoOnSubOps true if the enum should also be applied to the sub-operands.
* @param shouldDoOnSubOps True if the enum should also be applied to the sub-operands.
*/ */
public CreateEnumEquateCommand(Program program, AddressSetView addresses, Enum enoom, public CreateEnumEquateCommand(Program program, AddressSetView addresses, Enum enoom,
boolean shouldDoOnSubOps) { boolean shouldDoOnSubOps) {
this.program = program; this.program = Objects.requireNonNull(program);
this.addresses = addresses; this.addresses = Objects.requireNonNull(addresses);
this.enoom = enoom; this.enoom = Objects.requireNonNull(enoom);
this.shouldDoOnSubOps = shouldDoOnSubOps; this.shouldDoOnSubOps = shouldDoOnSubOps;
} }
@Override
public boolean applyTo(DomainObject obj, TaskMonitor monitor) {
EquateTable et = program.getEquateTable();
try {
et.applyEnum(addresses, enoom, monitor, shouldDoOnSubOps);
}
catch (CancelledException e) {
return false;
}
return true;
}
@Override @Override
public String getName() { public String getName() {
return "Create Enum Equate Command"; return "Create Enum Equate Command";
} }
@Override
public boolean applyTo(DomainObject obj, TaskMonitor monitor) {
equateTable = program.getEquateTable();
try {
applyEnum(monitor);
}
catch (CancelledException e) {
return false;
}
return true;
}
private void applyEnum(TaskMonitor monitor) throws CancelledException {
Listing listing = program.getListing();
InstructionIterator it = listing.getInstructions(addresses, true);
monitor.initialize(addresses.getNumAddresses());
while (it.hasNext()) {
monitor.checkCanceled();
Instruction instruction = it.next();
processsEquates(instruction);
monitor.incrementProgress(instruction.getLength());
}
}
private void processsEquates(Instruction instruction) {
for (int opIndex = 0; opIndex < instruction.getNumOperands(); opIndex++) {
if (!shouldDoOnSubOps) {
// Only apply equates to scalars that are not contained in sub operands.
Scalar scalar = instruction.getScalar(opIndex);
maybeCreateEquateOnScalar(instruction, opIndex, scalar);
}
else {
// Apply equates to scalars in the sub operands as well.
List<?> subOperands = instruction.getDefaultOperandRepresentationList(opIndex);
for (Object subOp : subOperands) {
maybeCreateEquateOnScalar(instruction, opIndex, subOp);
}
}
}
}
private void maybeCreateEquateOnScalar(Instruction instruction, int opIndex,
Object operandRepresentation) {
if (!(operandRepresentation instanceof Scalar)) {
return;
}
Scalar scalar = (Scalar) operandRepresentation;
int enoomLength = enoom.getLength();
boolean anyValuesMatch = Arrays.stream(enoom.getValues()).anyMatch(enumValue -> {
return scalar.equals(new Scalar(enoomLength * 8, enumValue, scalar.isSigned()));
});
if (!anyValuesMatch) {
return;
}
if (program.getDataTypeManager().findDataTypeForID(enoom.getUniversalID()) == null) {
enoom = (Enum) program.getDataTypeManager().addDataType(enoom, null);
}
Address addr = instruction.getAddress();
removeUnusedEquates(opIndex, scalar, addr);
long value = scalar.getValue();
String equateName = EquateManager.formatNameForEquate(enoom.getUniversalID(), value);
Equate equate = getOrCreateEquate(equateName, value);
equate.addReference(addr, opIndex);
}
private void removeUnusedEquates(int opIndex, Scalar scalar, Address addr) {
Equate existingEquate = equateTable.getEquate(addr, opIndex, scalar.getValue());
if (existingEquate != null) {
if (existingEquate.getReferenceCount() <= 1) {
equateTable.removeEquate(existingEquate.getName());
}
}
}
private Equate getOrCreateEquate(String name, long value) {
Equate equate = equateTable.getEquate(name);
if (equate != null) {
return equate;
}
try {
equate = equateTable.createEquate(name, value);
}
catch (DuplicateNameException | InvalidInputException e) {
// These should not happen:
// Duplicate will not happen since we checked for the existence first; Invalid
// can't happen since we built the name ourselves (we are assuming)
Msg.error(this, "Unexpected error creating equate", e); // just in case
}
return equate;
}
} }

View file

@ -30,7 +30,6 @@ import ghidra.app.plugin.PluginCategoryNames;
import ghidra.app.util.bean.SetEquateDialog; import ghidra.app.util.bean.SetEquateDialog;
import ghidra.app.util.bean.SetEquateDialog.SelectionType; import ghidra.app.util.bean.SetEquateDialog.SelectionType;
import ghidra.app.util.datatype.ApplyEnumDialog; import ghidra.app.util.datatype.ApplyEnumDialog;
import ghidra.app.util.datatype.DataTypeSelectionDialog;
import ghidra.framework.cmd.BackgroundCommand; import ghidra.framework.cmd.BackgroundCommand;
import ghidra.framework.cmd.CompoundBackgroundCommand; import ghidra.framework.cmd.CompoundBackgroundCommand;
import ghidra.framework.plugintool.*; import ghidra.framework.plugintool.*;
@ -74,23 +73,14 @@ public class EquatePlugin extends Plugin {
private SetEquateDialog setEquateDialog; private SetEquateDialog setEquateDialog;
private ApplyEnumDialog applyEnumDialog; private ApplyEnumDialog applyEnumDialog;
/**
* Constructor.
*
* @param tool
*/
public EquatePlugin(PluginTool tool) { public EquatePlugin(PluginTool tool) {
super(tool); super(tool);
createActions(); createActions();
} }
/** /*
* Returns the GUI for the {@link SetEquateDialog}. Note that this function will close * 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. * any instance of the dialog that is currently open and construct a new one.
*
* @param context
* @param scalar
* @return
*/ */
private SetEquateDialog createEquateDialog(ListingActionContext context, Scalar scalar) { private SetEquateDialog createEquateDialog(ListingActionContext context, Scalar scalar) {
if (setEquateDialog != null) { if (setEquateDialog != null) {
@ -105,11 +95,9 @@ public class EquatePlugin extends Plugin {
return setEquateDialog; return setEquateDialog;
} }
/** /*
* Returns the GUI for the {@link DataTypeSelectionDialog}. Note that this function will * Returns the GUI for the {@link DataTypeSelectionDialog}. Note that this function will
* close any instance of the dialog that is currently open and construct a new one. * close any instance of the dialog that is currently open and construct a new one.
* @param context
* @return
*/ */
private ApplyEnumDialog applyEnumDialog(ListingActionContext context) { private ApplyEnumDialog applyEnumDialog(ListingActionContext context) {
DataTypeManager dtm = context.getProgram().getDataTypeManager(); DataTypeManager dtm = context.getProgram().getDataTypeManager();
@ -122,11 +110,6 @@ public class EquatePlugin extends Plugin {
return applyEnumDialog; return applyEnumDialog;
} }
/**
* Destroys the {@link SetEquateDialog}.
*
* @param dialog
*/
private void dispose(SetEquateDialog dialog) { private void dispose(SetEquateDialog dialog) {
if (setEquateDialog == dialog) { if (setEquateDialog == dialog) {
setEquateDialog.dispose(); setEquateDialog.dispose();
@ -146,7 +129,7 @@ public class EquatePlugin extends Plugin {
* array or composite (CreateEquateCmd does not currently support such data cases)</li> * array or composite (CreateEquateCmd does not currently support such data cases)</li>
* </ul> * </ul>
* Currently markup of equates is not supported within composite or array data * Currently markup of equates is not supported within composite or array data
* @param context * @param context the action context
* @return true if current location satisfies the above constraints * @return true if current location satisfies the above constraints
*/ */
protected boolean isEquatePermitted(ListingActionContext context) { protected boolean isEquatePermitted(ListingActionContext context) {
@ -182,7 +165,7 @@ public class EquatePlugin extends Plugin {
* ultimately create the background tasks that will create the proper equate(s) for * ultimately create the background tasks that will create the proper equate(s) for
* the selected addresses. * the selected addresses.
* *
* @param context * @param context the action context
*/ */
private void setEquate(ListingActionContext context) { private void setEquate(ListingActionContext context) {
@ -252,7 +235,7 @@ public class EquatePlugin extends Plugin {
/** /**
* Called in response to the user selecting the Apply Enum action from the popup menu. This * Called in response to the user selecting the Apply Enum action from the popup menu. This
* action will apply enum values to scalars in a selection. * action will apply enum values to scalars in a selection.
* @param context * @param context the action context
*/ */
private void applyEnum(ListingActionContext context) { private void applyEnum(ListingActionContext context) {
applyEnumDialog = applyEnumDialog(context); applyEnumDialog = applyEnumDialog(context);
@ -281,7 +264,7 @@ public class EquatePlugin extends Plugin {
/** /**
* Called in response to the user activating rename action from the context menu. * Called in response to the user activating rename action from the context menu.
* *
* @param context * @param context the action context
*/ */
private void renameEquate(ListingActionContext context) { private void renameEquate(ListingActionContext context) {
@ -348,12 +331,6 @@ public class EquatePlugin extends Plugin {
dispose(setEquateDialog); dispose(setEquateDialog);
} }
/**
* Returns the equate for the given context listing.
*
* @param context
* @return
*/
private Equate getEquate(ListingActionContext context) { private Equate getEquate(ListingActionContext context) {
EquateTable equateTable = context.getProgram().getEquateTable(); EquateTable equateTable = context.getProgram().getEquateTable();
Scalar s = getScalar(context); Scalar s = getScalar(context);
@ -363,15 +340,6 @@ public class EquatePlugin extends Plugin {
return equateTable.getEquate(context.getAddress(), getOperandIndex(context), s.getValue()); return equateTable.getEquate(context.getAddress(), getOperandIndex(context), s.getValue());
} }
/**
* Renames all equates matching the given old equate name, within the address space identified
* by the iterator.
*
* @param context
* @param oldEquate
* @param newEquateName
* @param iter
*/
private void renameEquate(ListingActionContext context, Equate oldEquate, String newEquateName, private void renameEquate(ListingActionContext context, Equate oldEquate, String newEquateName,
CodeUnitIterator iter) { CodeUnitIterator iter) {
@ -476,14 +444,6 @@ public class EquatePlugin extends Plugin {
} }
} }
/**
* Returns the list of operands for the given {@link Instruction} that match the given
* {@link Equate}.
*
* @param instruction
* @param equate
* @return an array of matches, in the format: [operand][operand-obj]
*/
private List<Integer> getInstructionMatches(Program program, Instruction instruction, private List<Integer> getInstructionMatches(Program program, Instruction instruction,
Equate equate) { Equate equate) {
@ -521,15 +481,6 @@ public class EquatePlugin extends Plugin {
return matches; return matches;
} }
/**
* Returns true if the given {@link Data} object is a scalar value that has an equate
* that matches the one passed-in.
*
* @param data
* @param context
* @param equate
* @return
*/
private boolean isDataMatch(Data data, ListingActionContext context, Equate equate) { private boolean isDataMatch(Data data, ListingActionContext context, Equate equate) {
if (!data.isDefined()) { if (!data.isDefined()) {
@ -560,12 +511,10 @@ public class EquatePlugin extends Plugin {
return false; return false;
} }
/** /*
* Removes equates within the selected region, or a single equate if there's * Removes equates within the selected region, or a single equate if there's
* no selection. The user will be prompted for confirmation before * no selection. The user will be prompted for confirmation before
* removing multiple equates in a selection. * removing multiple equates in a selection.
*
* @param context
*/ */
private void removeSelectedEquates(ListingActionContext context) { private void removeSelectedEquates(ListingActionContext context) {
@ -606,7 +555,8 @@ public class EquatePlugin extends Plugin {
} }
/** /**
* Get the instruction at the location provided by the ProgramLocationProvider * Get the instruction at the location provided by the context
* @param context the action context
* @return code unit containing current location if found (component data unsupported) * @return code unit containing current location if found (component data unsupported)
*/ */
CodeUnit getCodeUnit(ListingActionContext context) { CodeUnit getCodeUnit(ListingActionContext context) {
@ -619,7 +569,7 @@ public class EquatePlugin extends Plugin {
/** /**
* Get the operand index at the location * Get the operand index at the location
* * @param context the action context
* @return 0-3 for a good operand location, -1 otherwise * @return 0-3 for a good operand location, -1 otherwise
*/ */
int getOperandIndex(ListingActionContext context) { int getOperandIndex(ListingActionContext context) {
@ -630,11 +580,6 @@ public class EquatePlugin extends Plugin {
return -1; return -1;
} }
/**
*
* @param context
* @return
*/
int getSubOperandIndex(ListingActionContext context) { int getSubOperandIndex(ListingActionContext context) {
ProgramLocation location = context.getLocation(); ProgramLocation location = context.getLocation();
if (location instanceof OperandFieldLocation) { if (location instanceof OperandFieldLocation) {
@ -649,10 +594,6 @@ public class EquatePlugin extends Plugin {
return scalar; return scalar;
} }
////////////////////////////////////////////////////////////////
// *** private methods ***
////////////////////////////////////////////////////////////////
private Scalar getScalar(CodeUnit cu, ListingActionContext context) { private Scalar getScalar(CodeUnit cu, ListingActionContext context) {
int opIndex = getOperandIndex(context); int opIndex = getOperandIndex(context);
int subOpIndex = getSubOperandIndex(context); int subOpIndex = getSubOperandIndex(context);
@ -664,7 +605,7 @@ public class EquatePlugin extends Plugin {
* Get scalar value associated with the specified code unit, * Get scalar value associated with the specified code unit,
* opIndex and subOpindex. NOTE: this method does not support * opIndex and subOpindex. NOTE: this method does not support
* composite or array data (null will always be returned). * composite or array data (null will always be returned).
* @param cu cpde unit * @param cu code unit
* @param opIndex operand index * @param opIndex operand index
* @param subOpIndex sub-operand index * @param subOpIndex sub-operand index
* @return scalar value or null * @return scalar value or null

View file

@ -38,16 +38,13 @@ import ghidra.program.model.data.*;
import ghidra.program.model.data.Enum; import ghidra.program.model.data.Enum;
import ghidra.test.AbstractGhidraHeadedIntegrationTest; import ghidra.test.AbstractGhidraHeadedIntegrationTest;
import ghidra.test.TestEnv; import ghidra.test.TestEnv;
import ghidra.util.InvalidNameException;
/** /**
* Tests for the make enum from a selection of enums action * Tests for the 'make enum from a selection' action
*/ */
public class CreateEnumFromSelectionTest extends AbstractGhidraHeadedIntegrationTest { public class CreateEnumFromSelectionTest extends AbstractGhidraHeadedIntegrationTest {
private static final String PROGRAM_FILENAME = "notepad"; private static final String PROGRAM_FILENAME = "notepad";
private static final int TASK_TIMEOUT = 2000;
//private Program program;
private PluginTool tool; private PluginTool tool;
private ProgramDB program; private ProgramDB program;
private TestEnv env; private TestEnv env;
@ -57,10 +54,6 @@ public class CreateEnumFromSelectionTest extends AbstractGhidraHeadedIntegration
private ArchiveRootNode archiveRootNode; private ArchiveRootNode archiveRootNode;
private ArchiveNode programNode; private ArchiveNode programNode;
public CreateEnumFromSelectionTest() {
super();
}
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
env = new TestEnv(); env = new TestEnv();
@ -93,16 +86,6 @@ public class CreateEnumFromSelectionTest extends AbstractGhidraHeadedIntegration
return builder.getProgram(); return builder.getProgram();
} }
// @Override
// protected void tearDown() throws Exception {
// executeOnSwingWithoutBlocking(new Runnable() {
// public void run() {
// ProgramManager pm = tool.getService(ProgramManager.class);
// pm.closeProgram();
//
// }
// });
// }
@After @After
public void tearDown() throws Exception { public void tearDown() throws Exception {
@ -116,8 +99,7 @@ public class CreateEnumFromSelectionTest extends AbstractGhidraHeadedIntegration
}); });
// this handles the save changes dialog and potential analysis dialogs // this handles the save changes dialog and potential analysis dialogs
closeAllWindowsAndFrames(); closeAllWindows();
env.release(program);
env.dispose(); env.dispose();
} }
@ -174,7 +156,7 @@ public class CreateEnumFromSelectionTest extends AbstractGhidraHeadedIntegration
} }
}); });
Window window = waitForWindow(tool.getToolFrame(), "Name new ENUM", TASK_TIMEOUT); Window window = waitForWindow("Name new ENUM");
assertNotNull(window); assertNotNull(window);
final JTextField tf = findComponent(window, JTextField.class); final JTextField tf = findComponent(window, JTextField.class);
@ -274,7 +256,7 @@ public class CreateEnumFromSelectionTest extends AbstractGhidraHeadedIntegration
} }
}); });
Window window = waitForWindow(tool.getToolFrame(), "Name new ENUM", TASK_TIMEOUT); Window window = waitForWindow("Name new ENUM");
assertNotNull(window); assertNotNull(window);
final JTextField tf = findComponent(window, JTextField.class); final JTextField tf = findComponent(window, JTextField.class);
@ -283,7 +265,7 @@ public class CreateEnumFromSelectionTest extends AbstractGhidraHeadedIntegration
tf.setText("myNewEnum"); tf.setText("myNewEnum");
pressButtonByText(window, "OK"); pressButtonByText(window, "OK");
Window window2 = waitForWindow(tool.getToolFrame(), "Duplicate ENUM Name", TASK_TIMEOUT); Window window2 = waitForWindow("Duplicate ENUM Name");
assertNotNull(window2); assertNotNull(window2);
final JTextField tf2 = findComponent(window2, JTextField.class); final JTextField tf2 = findComponent(window2, JTextField.class);
@ -334,27 +316,6 @@ public class CreateEnumFromSelectionTest extends AbstractGhidraHeadedIntegration
} }
private DataTypeNode createEnum(CategoryNode categoryNode, String newEnumName, int size) {
Category category = categoryNode.getCategory();
DataTypeManager dataTypeManager = category.getDataTypeManager();
int id = dataTypeManager.startTransaction("new category");
Enum newEnum = new EnumDataType(newEnumName, size);
category.addDataType(newEnum, null);
dataTypeManager.endTransaction(id, true);
waitForTree();
return getDataTypeNode(categoryNode, newEnumName);
}
private DataTypeNode getDataTypeNode(GTreeNode parent, String dataTypeName) {
List<GTreeNode> children = parent.getChildren();
for (GTreeNode node : children) {
if (node instanceof DataTypeNode && node.getName().equals(dataTypeName)) {
return (DataTypeNode) node;
}
}
return null;
}
private void expandNode(GTreeNode node) { private void expandNode(GTreeNode node) {
tree.expandPath(node); tree.expandPath(node);
waitForTree(); waitForTree();
@ -373,37 +334,4 @@ public class CreateEnumFromSelectionTest extends AbstractGhidraHeadedIntegration
private void waitForTree() { private void waitForTree() {
waitForTree(tree); waitForTree(tree);
} }
private void waitForProgram() throws Exception {
program.flushEvents();
waitForTasks();
waitForPostedSwingRunnables();
}
private CategoryNode createCategory(CategoryNode categoryNode, String newCategoryName) {
Category category = categoryNode.getCategory();
DataTypeManager dataTypeManager = category.getDataTypeManager();
int id = dataTypeManager.startTransaction("new category");
try {
category.createCategory(newCategoryName);
}
catch (InvalidNameException e) {
// shouldn't happen
}
dataTypeManager.endTransaction(id, true);
waitForTree();
CategoryNode node = getCategoryNode(categoryNode, newCategoryName);
return node;
}
private CategoryNode getCategoryNode(GTreeNode parent, String categoryName) {
List<GTreeNode> children = parent.getChildren();
for (GTreeNode node : children) {
if (node instanceof CategoryNode && node.getName().equals(categoryName)) {
return (CategoryNode) node;
}
}
return null;
}
} }

View file

@ -30,38 +30,21 @@ import ghidra.program.model.symbol.*;
import ghidra.test.AbstractGhidraHeadedIntegrationTest; import ghidra.test.AbstractGhidraHeadedIntegrationTest;
import ghidra.util.exception.DuplicateNameException; import ghidra.util.exception.DuplicateNameException;
import ghidra.util.exception.InvalidInputException; import ghidra.util.exception.InvalidInputException;
import ghidra.util.task.TaskMonitorAdapter; import ghidra.util.task.TaskMonitor;
/**
* Test the equate manager for the database implementation.
*
*
*/
public class EquateManagerTest extends AbstractGhidraHeadedIntegrationTest { public class EquateManagerTest extends AbstractGhidraHeadedIntegrationTest {
private ProgramDB program; private ProgramDB program;
private AddressSpace space; private AddressSpace space;
private EquateTable equateTable; private EquateTable equateTable;
private int transactionID; private int transactionID;
/**
* Constructor for EquateManagerTest.
* @param name
*/
public EquateManagerTest() {
super();
}
/*
* @see TestCase#setUp()
*/
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
program = createDefaultProgram("Test", ProgramBuilder._TOY, this); program = createDefaultProgram("Test", ProgramBuilder._TOY, this);
space = program.getAddressFactory().getDefaultAddressSpace(); space = program.getAddressFactory().getDefaultAddressSpace();
Memory memory = program.getMemory(); Memory memory = program.getMemory();
transactionID = program.startTransaction("Test"); transactionID = program.startTransaction("Test");
memory.createInitializedBlock("test", addr(0), 5000, (byte) 0, memory.createInitializedBlock("test", addr(0), 5000, (byte) 0, TaskMonitor.DUMMY, false);
TaskMonitorAdapter.DUMMY_MONITOR, false);
equateTable = program.getEquateTable(); equateTable = program.getEquateTable();
@ -91,6 +74,7 @@ public class EquateManagerTest extends AbstractGhidraHeadedIntegrationTest {
Assert.fail("Should have gotten duplicate name exception"); Assert.fail("Should have gotten duplicate name exception");
} }
catch (DuplicateNameException e) { catch (DuplicateNameException e) {
// expected
} }
} }
@ -101,12 +85,14 @@ public class EquateManagerTest extends AbstractGhidraHeadedIntegrationTest {
Assert.fail("Should have gotten invalid input exception"); Assert.fail("Should have gotten invalid input exception");
} }
catch (InvalidInputException e) { catch (InvalidInputException e) {
// expected
} }
try { try {
equateTable.createEquate(null, 100); equateTable.createEquate(null, 100);
Assert.fail("Should have gotten invalid input exception"); Assert.fail("Should have gotten invalid input exception");
} }
catch (InvalidInputException e) { catch (InvalidInputException e) {
// expected
} }
} }
@ -370,7 +356,7 @@ public class EquateManagerTest extends AbstractGhidraHeadedIntegrationTest {
} }
assertEquals(6, count); assertEquals(6, count);
equateTable.deleteAddressRange(addr(50), addr(500), TaskMonitorAdapter.DUMMY_MONITOR); equateTable.deleteAddressRange(addr(50), addr(500), TaskMonitor.DUMMY);
assertNull(equateTable.getEquate("Test1")); assertNull(equateTable.getEquate("Test1"));
assertNotNull(equateTable.getEquate("Test4")); assertNotNull(equateTable.getEquate("Test4"));
assertEquals(0, equateTable.getEquates(addr(100), 0).size()); assertEquals(0, equateTable.getEquates(addr(100), 0).size());
@ -419,6 +405,7 @@ public class EquateManagerTest extends AbstractGhidraHeadedIntegrationTest {
Assert.fail("Should have gotten DuplicateNameException"); Assert.fail("Should have gotten DuplicateNameException");
} }
catch (DuplicateNameException e) { catch (DuplicateNameException e) {
// expected
} }
eq = equateTable.createEquate("foo", 100); eq = equateTable.createEquate("foo", 100);
eq.renameEquate("foo");// nothing should happen eq.renameEquate("foo");// nothing should happen
@ -427,6 +414,7 @@ public class EquateManagerTest extends AbstractGhidraHeadedIntegrationTest {
Assert.fail("Should have gotten DuplicateNameException"); Assert.fail("Should have gotten DuplicateNameException");
} }
catch (DuplicateNameException e) { catch (DuplicateNameException e) {
// expected
} }
} }
@ -438,12 +426,14 @@ public class EquateManagerTest extends AbstractGhidraHeadedIntegrationTest {
Assert.fail("Empty string should be invalid!"); Assert.fail("Empty string should be invalid!");
} }
catch (InvalidInputException e) { catch (InvalidInputException e) {
// expected
} }
try { try {
eq.renameEquate(null); eq.renameEquate(null);
Assert.fail("Empty string should be invalid!"); Assert.fail("Empty string should be invalid!");
} }
catch (InvalidInputException e) { catch (InvalidInputException e) {
// expected
} }
} }

View file

@ -17,9 +17,6 @@ package ghidra.program.database.symbol;
import java.io.IOException; import java.io.IOException;
import java.util.*; import java.util.*;
import java.util.function.Consumer;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import db.*; import db.*;
import db.util.ErrorHandler; import db.util.ErrorHandler;
@ -27,22 +24,17 @@ import ghidra.program.database.*;
import ghidra.program.database.map.AddressKeyAddressIterator; import ghidra.program.database.map.AddressKeyAddressIterator;
import ghidra.program.database.map.AddressMap; import ghidra.program.database.map.AddressMap;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.program.model.data.DataTypeManager;
import ghidra.program.model.data.Enum;
import ghidra.program.model.listing.*;
import ghidra.program.model.scalar.Scalar;
import ghidra.program.model.symbol.Equate; import ghidra.program.model.symbol.Equate;
import ghidra.program.model.symbol.EquateTable; import ghidra.program.model.symbol.EquateTable;
import ghidra.program.util.ChangeManager; import ghidra.program.util.ChangeManager;
import ghidra.program.util.EquateInfo; import ghidra.program.util.EquateInfo;
import ghidra.util.*; import ghidra.util.Lock;
import ghidra.util.UniversalID;
import ghidra.util.exception.*; import ghidra.util.exception.*;
import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskMonitor;
/** /**
* Implementation for the Equate Table. * Implementation of the Equate Table
*
*
*/ */
public class EquateManager implements EquateTable, ErrorHandler, ManagerDB { public class EquateManager implements EquateTable, ErrorHandler, ManagerDB {
@ -60,14 +52,12 @@ public class EquateManager implements EquateTable, ErrorHandler, ManagerDB {
/** /**
* Constructor * Constructor
* @param handle database handle * @param handle database handle
* @param addrMap map that converts addresses to longs and longs to * @param addrMap map that converts addresses to longs and longs to addresses
* addresses
* @param openMode one of ProgramDB.CREATE, UPDATE, UPGRADE, or READ_ONLY * @param openMode one of ProgramDB.CREATE, UPDATE, UPGRADE, or READ_ONLY
* @param lock the program synchronization lock * @param lock the program synchronization lock
* @param monitor the progress monitor used when upgrading. * @param monitor the progress monitor used when upgrading.
* @throws VersionException if the database version doesn't match the current version. * @throws VersionException if the database version doesn't match the current version.
* @throws IOException if a database error occurs. * @throws IOException if a database error occurs.
* @throws CancelledException if the user cancels the upgrade.
*/ */
public EquateManager(DBHandle handle, AddressMap addrMap, int openMode, Lock lock, public EquateManager(DBHandle handle, AddressMap addrMap, int openMode, Lock lock,
TaskMonitor monitor) throws VersionException, IOException { TaskMonitor monitor) throws VersionException, IOException {
@ -103,149 +93,22 @@ public class EquateManager implements EquateTable, ErrorHandler, ManagerDB {
} }
} }
/**
* @see ghidra.program.database.ManagerDB#setProgram(ghidra.program.database.ProgramDB)
*/
@Override @Override
public void setProgram(ProgramDB program) { public void setProgram(ProgramDB program) {
this.program = program; this.program = program;
} }
/**
* @see ghidra.program.database.ManagerDB#programReady(int, int, ghidra.util.task.TaskMonitor)
*/
@Override @Override
public void programReady(int openMode, int currentRevision, TaskMonitor monitor) public void programReady(int openMode, int currentRevision, TaskMonitor monitor)
throws IOException, CancelledException { throws IOException, CancelledException {
// Nothing to do // Nothing to do
} }
/**
* @see db.util.ErrorHandler#dbError(java.io.IOException)
*/
@Override @Override
public void dbError(IOException e) { public void dbError(IOException e) {
program.dbError(e); program.dbError(e);
} }
@Override
public void applyEnum(AddressSetView addresses, Enum enoom, TaskMonitor monitor,
boolean shouldDoOnSubOps) throws CancelledException {
if (addresses == null) {
throw new IllegalArgumentException("Can't apply Enum over null addresses");
}
if (enoom == null) {
throw new IllegalArgumentException("Data Type is null");
}
Consumer<Instruction> applyEquates = instruction -> {
if (monitor.isCancelled()) {
return;
}
for (int opIndex = 0; opIndex < instruction.getNumOperands(); opIndex++) {
if (!shouldDoOnSubOps) {
// Only apply equates to scalars that are not contained in sub operands.
Scalar scalar = instruction.getScalar(opIndex);
maybeCreateEquateOnScalar(enoom, instruction, opIndex, scalar);
}
else {
// Apply equates to scalars in the sub operands as well.
List<?> subOperands = instruction.getDefaultOperandRepresentationList(opIndex);
for (Object subOp : subOperands) {
maybeCreateEquateOnScalar(enoom, instruction, opIndex, subOp);
}
}
}
};
Listing listing = program.getListing();
InstructionIterator it = listing.getInstructions(addresses, true);
Stream<Instruction> instructions = StreamSupport.stream(it.spliterator(), false);
DataTypeManager dtm = program.getDataTypeManager();
try {
lock.acquire();
int id = dtm.startTransaction("Apply Enum");
instructions.forEach(applyEquates);
dtm.endTransaction(id, true);
}
finally {
lock.release();
}
}
private void maybeCreateEquateOnScalar(Enum enoom, Instruction instruction, int opIndex,
Object operandRepresentation) {
if (!(operandRepresentation instanceof Scalar)) {
return;
}
Scalar scalar = (Scalar) operandRepresentation;
int enoomLength = enoom.getLength();
boolean anyValuesMatch = Arrays.stream(enoom.getValues()).anyMatch(enumValue -> {
return scalar.equals(new Scalar(enoomLength * 8, enumValue, scalar.isSigned()));
});
if (!anyValuesMatch) {
return;
}
if (program.getDataTypeManager().findDataTypeForID(enoom.getUniversalID()) == null) {
int transactionID = program.startTransaction("Set Equate Dialog");
try {
enoom = (Enum) program.getDataTypeManager().addDataType(enoom, null);
}
finally {
program.endTransaction(transactionID, true);
}
}
Address addr = instruction.getAddress();
removeUnusedEquates(opIndex, scalar, addr);
long value = scalar.getValue();
String equateName = EquateManager.formatNameForEquate(enoom.getUniversalID(), value);
Equate equate = getOrCreateEquate(equateName, value);
equate.addReference(addr, opIndex);
}
private void removeUnusedEquates(int opIndex, Scalar scalar, Address addr) {
Equate existingEquate = getEquate(addr, opIndex, scalar.getValue());
if (existingEquate != null) {
if (existingEquate.getReferenceCount() <= 1) {
removeEquate(existingEquate.getName());
}
}
}
private Equate getOrCreateEquate(String name, long value) {
Equate equate = getEquate(name);
if (equate != null) {
return equate;
}
try {
equate = createEquate(name, value);
}
catch (DuplicateNameException | InvalidInputException e) {
// These should not happen:
// Duplicate will not happen since we checked for the existence first; Invalid
// can't happen since we built the name ourselves (we are assuming)
Msg.error(this, "Unexpected error creating equate", e); // just in case
}
return equate;
}
/**
* @see ghidra.program.model.symbol.EquateTable#createEquate(java.lang.String, long)
*/
@Override @Override
public Equate createEquate(String name, long value) public Equate createEquate(String name, long value)
throws DuplicateNameException, InvalidInputException { throws DuplicateNameException, InvalidInputException {
@ -271,9 +134,6 @@ public class EquateManager implements EquateTable, ErrorHandler, ManagerDB {
return null; return null;
} }
/**
* @see ghidra.program.model.symbol.EquateTable#getEquate(ghidra.program.model.address.Address, int, long)
*/
@Override @Override
public Equate getEquate(Address reference, int opIndex, long scalarValue) { public Equate getEquate(Address reference, int opIndex, long scalarValue) {
lock.acquire(); lock.acquire();
@ -302,9 +162,6 @@ public class EquateManager implements EquateTable, ErrorHandler, ManagerDB {
return null; return null;
} }
/**
* @see ghidra.program.model.symbol.EquateTable#getEquates(ghidra.program.model.address.Address, int)
*/
@Override @Override
public List<Equate> getEquates(Address reference, int opIndex) { public List<Equate> getEquates(Address reference, int opIndex) {
List<Equate> ret = new LinkedList<>(); List<Equate> ret = new LinkedList<>();
@ -331,9 +188,6 @@ public class EquateManager implements EquateTable, ErrorHandler, ManagerDB {
return ret; return ret;
} }
/**
* @see ghidra.program.model.symbol.EquateTable#getEquates(ghidra.program.model.address.Address)
*/
@Override @Override
public List<Equate> getEquates(Address reference) { public List<Equate> getEquates(Address reference) {
List<Equate> ret = new LinkedList<>(); List<Equate> ret = new LinkedList<>();
@ -358,9 +212,6 @@ public class EquateManager implements EquateTable, ErrorHandler, ManagerDB {
return ret; return ret;
} }
/**
* @see ghidra.program.model.symbol.EquateTable#getEquate(java.lang.String)
*/
@Override @Override
public Equate getEquate(String name) { public Equate getEquate(String name) {
lock.acquire(); lock.acquire();
@ -369,6 +220,7 @@ public class EquateManager implements EquateTable, ErrorHandler, ManagerDB {
return getEquateDB(equateID); return getEquateDB(equateID);
} }
catch (NotFoundException e) { catch (NotFoundException e) {
// just return null below
} }
catch (IOException e) { catch (IOException e) {
program.dbError(e); program.dbError(e);
@ -379,9 +231,6 @@ public class EquateManager implements EquateTable, ErrorHandler, ManagerDB {
return null; return null;
} }
/**
* @see ghidra.program.model.symbol.EquateTable#getEquateAddresses()
*/
@Override @Override
public AddressIterator getEquateAddresses() { public AddressIterator getEquateAddresses() {
@ -395,9 +244,6 @@ public class EquateManager implements EquateTable, ErrorHandler, ManagerDB {
return new EmptyAddressIterator(); return new EmptyAddressIterator();
} }
/**
* @see ghidra.program.model.symbol.EquateTable#getEquateAddresses(ghidra.program.model.address.Address)
*/
@Override @Override
public AddressIterator getEquateAddresses(Address startAddr) { public AddressIterator getEquateAddresses(Address startAddr) {
try { try {
@ -421,9 +267,6 @@ public class EquateManager implements EquateTable, ErrorHandler, ManagerDB {
return new EmptyAddressIterator(); return new EmptyAddressIterator();
} }
/**
* @see ghidra.program.model.symbol.EquateTable#getEquateAddresses(ghidra.program.model.address.AddressSetView)
*/
@Override @Override
public AddressIterator getEquateAddresses(AddressSetView set) { public AddressIterator getEquateAddresses(AddressSetView set) {
try { try {
@ -436,9 +279,6 @@ public class EquateManager implements EquateTable, ErrorHandler, ManagerDB {
return new EmptyAddressIterator(); return new EmptyAddressIterator();
} }
/**
* @see ghidra.program.model.symbol.EquateTable#getEquates()
*/
@Override @Override
public Iterator<Equate> getEquates() { public Iterator<Equate> getEquates() {
try { try {
@ -451,9 +291,6 @@ public class EquateManager implements EquateTable, ErrorHandler, ManagerDB {
return new EquateIterator(null); return new EquateIterator(null);
} }
/**
* @see ghidra.program.model.symbol.EquateTable#getEquates(long)
*/
@Override @Override
public List<Equate> getEquates(long value) { public List<Equate> getEquates(long value) {
ArrayList<Equate> list = new ArrayList<>(); ArrayList<Equate> list = new ArrayList<>();
@ -473,9 +310,6 @@ public class EquateManager implements EquateTable, ErrorHandler, ManagerDB {
return list; return list;
} }
/**
* @see ghidra.program.database.ManagerDB#deleteAddressRange(ghidra.program.model.address.Address, ghidra.program.model.address.Address, ghidra.util.task.TaskMonitor)
*/
@Override @Override
public void deleteAddressRange(Address startAddr, Address endAddr, TaskMonitor monitor) public void deleteAddressRange(Address startAddr, Address endAddr, TaskMonitor monitor)
throws CancelledException { throws CancelledException {
@ -516,9 +350,6 @@ public class EquateManager implements EquateTable, ErrorHandler, ManagerDB {
} }
} }
/**
* @see ghidra.program.model.symbol.EquateTable#removeEquate(java.lang.String)
*/
@Override @Override
public boolean removeEquate(String name) { public boolean removeEquate(String name) {
if (name == null) { if (name == null) {
@ -562,30 +393,18 @@ public class EquateManager implements EquateTable, ErrorHandler, ManagerDB {
} }
} }
/**
* Return the address map.
*/
AddressMap getAddressMap() { AddressMap getAddressMap() {
return addrMap; return addrMap;
} }
/**
* Get the database adapter for equate table.
*/
EquateDBAdapter getEquateDatabaseAdapter() { EquateDBAdapter getEquateDatabaseAdapter() {
return equateAdapter; return equateAdapter;
} }
/**
* Get the database adapter for the equate references table.
*/
EquateRefDBAdapter getRefDatabaseAdapter() { EquateRefDBAdapter getRefDatabaseAdapter() {
return refAdapter; return refAdapter;
} }
/**
* Add a reference for an equate at the given operand position.
*/
void addReference(long equateID, Address address, int opIndex, long dynamicHash) void addReference(long equateID, Address address, int opIndex, long dynamicHash)
throws IOException { throws IOException {
lock.acquire(); lock.acquire();
@ -622,9 +441,6 @@ public class EquateManager implements EquateTable, ErrorHandler, ManagerDB {
} }
} }
/**
* Get the references for the given equate ID.
*/
EquateRefDB[] getReferences(long equateID) throws IOException { EquateRefDB[] getReferences(long equateID) throws IOException {
long[] keys = refAdapter.getRecordKeysForEquateID(equateID); long[] keys = refAdapter.getRecordKeysForEquateID(equateID);
EquateRefDB[] refs = new EquateRefDB[keys.length]; EquateRefDB[] refs = new EquateRefDB[keys.length];
@ -634,19 +450,10 @@ public class EquateManager implements EquateTable, ErrorHandler, ManagerDB {
return refs; return refs;
} }
/**
* Get the number of references for the given equate ID.
*/
int getReferenceCount(long equateID) throws IOException { int getReferenceCount(long equateID) throws IOException {
return getReferences(equateID).length; return getReferences(equateID).length;
} }
/**
* Remove the reference.
* @param equateDB equate
* @param refAddr ref address to remove
* @param opIndex operand index
*/
void removeReference(EquateDB equateDB, Address refAddr, short opIndex) throws IOException { void removeReference(EquateDB equateDB, Address refAddr, short opIndex) throws IOException {
long[] keys = refAdapter.getRecordKeysForEquateID(equateDB.getKey()); long[] keys = refAdapter.getRecordKeysForEquateID(equateDB.getKey());
@ -659,13 +466,6 @@ public class EquateManager implements EquateTable, ErrorHandler, ManagerDB {
} }
} }
/**
* Remove the reference.
* @param equateDB equate
* @param dynamicHash hash value
* @param refAddr ref address to remove
* @param opIndex operand index
*/
void removeReference(EquateDB equateDB, long dynamicHash, Address refAddr) throws IOException { void removeReference(EquateDB equateDB, long dynamicHash, Address refAddr) throws IOException {
long[] keys = refAdapter.getRecordKeysForEquateID(equateDB.getKey()); long[] keys = refAdapter.getRecordKeysForEquateID(equateDB.getKey());
@ -678,10 +478,6 @@ public class EquateManager implements EquateTable, ErrorHandler, ManagerDB {
} }
} }
/**
* Verify that the name is not null and not the empty string.
* @throws InvalidInputException if the name is null or is empty
*/
void validateName(String name) throws InvalidInputException { void validateName(String name) throws InvalidInputException {
if (name == null) { if (name == null) {
throw new InvalidInputException("Name is null"); throw new InvalidInputException("Name is null");
@ -693,7 +489,7 @@ public class EquateManager implements EquateTable, ErrorHandler, ManagerDB {
} }
/** /**
* Send notification that the equate name changed. * Send notification that the equate name changed
* @param oldName old name * @param oldName old name
* @param newName new name * @param newName new name
*/ */
@ -784,66 +580,10 @@ public class EquateManager implements EquateTable, ErrorHandler, ManagerDB {
null); null);
} }
//////////////////////////////////////////////////////////////////////
private class EquateIterator implements Iterator<Equate> {
private RecordIterator iter;
private EquateIterator(RecordIterator iter) {
this.iter = iter;
}
/**
* @see java.util.Iterator#hasNext()
*/
@Override
public boolean hasNext() {
if (iter != null) {
try {
return iter.hasNext();
}
catch (IOException e) {
program.dbError(e);
}
}
return false;
}
/**
* @see java.util.Iterator#next()
*/
@Override
public Equate next() {
if (iter != null) {
try {
Record record = iter.next();
if (record != null) {
return getEquateDB(record.getKey());
}
}
catch (IOException e) {
program.dbError(e);
}
}
return null;
}
/**
* @see java.util.Iterator#remove()
*/
@Override
public void remove() {
throw new UnsupportedOperationException("remove is not supported.");
}
}
Lock getLock() { Lock getLock() {
return lock; return lock;
} }
/**
* @see ghidra.program.database.ManagerDB#invalidateCache(boolean)
*/
@Override @Override
public void invalidateCache(boolean all) { public void invalidateCache(boolean all) {
lock.acquire(); lock.acquire();
@ -856,9 +596,6 @@ public class EquateManager implements EquateTable, ErrorHandler, ManagerDB {
} }
} }
/**
* @see ghidra.program.database.ManagerDB#moveAddressRange(ghidra.program.model.address.Address, ghidra.program.model.address.Address, long, ghidra.util.task.TaskMonitor)
*/
@Override @Override
public void moveAddressRange(Address fromAddr, Address toAddr, long length, TaskMonitor monitor) public void moveAddressRange(Address fromAddr, Address toAddr, long length, TaskMonitor monitor)
throws CancelledException { throws CancelledException {
@ -879,7 +616,7 @@ public class EquateManager implements EquateTable, ErrorHandler, ManagerDB {
* Formats a string to the equate format given the enum UUID and the value for the equate. The * Formats a string to the equate format given the enum UUID and the value for the equate. The
* formatted strings are used when setting equates from datatypes so that information can be * formatted strings are used when setting equates from datatypes so that information can be
* stored with an equate to point back to that datatype. * stored with an equate to point back to that datatype.
* @param dtID The enums data type UUID * @param dtID The enum's data type UUID
* @param equateValue The value intended for the equate * @param equateValue The value intended for the equate
* @return The formatted equate name * @return The formatted equate name
*/ */
@ -922,4 +659,51 @@ public class EquateManager implements EquateTable, ErrorHandler, ManagerDB {
} }
return -1; return -1;
} }
//==================================================================================================
// Inner Classes
//==================================================================================================
private class EquateIterator implements Iterator<Equate> {
private RecordIterator iter;
private EquateIterator(RecordIterator iter) {
this.iter = iter;
}
@Override
public boolean hasNext() {
if (iter != null) {
try {
return iter.hasNext();
}
catch (IOException e) {
program.dbError(e);
}
}
return false;
}
@Override
public Equate next() {
if (iter != null) {
try {
Record record = iter.next();
if (record != null) {
return getEquateDB(record.getKey());
}
}
catch (IOException e) {
program.dbError(e);
}
}
return null;
}
@Override
public void remove() {
throw new UnsupportedOperationException("remove is not supported.");
}
}
} }

View file

@ -21,9 +21,9 @@ import java.util.Iterator;
import java.util.List; import java.util.List;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.program.model.data.Enum;
import ghidra.util.exception.*; import ghidra.util.exception.*;
import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskMonitor;
/** /**
* EquateTable manages all equates for program. An equate defines a relationship * EquateTable manages all equates for program. An equate defines a relationship
* between a scalar value and a string whereby the scalar may be represented by * between a scalar value and a string whereby the scalar may be represented by
@ -32,25 +32,12 @@ import ghidra.util.task.TaskMonitor;
*/ */
public interface EquateTable { public interface EquateTable {
/**
* Creates equates and/or adds references for scalars
* in the given address set using the given data type.
* The data type given must be an enumeration data type.
* @param addrSet the address set to use.
* @param dataType the data type to use.
* @param monitor task monitor to cancel the remove operation
* @param shouldDoOnSubOps true if the enum should be applied inside sub-operands as well.
*
* @throws CancelledException if the operation is cancelled
* @throws IllegalArgumentException if the dataType is null or not an enum.
*/
public void applyEnum(AddressSetView addrSet, Enum dataType, TaskMonitor monitor,
boolean shouldDoOnSubOps) throws CancelledException;
/** /**
* Creates a new equate * Creates a new equate
* @param name the name to associate with the given value. * @param name the name to associate with the given value.
* @param value the value to associate with the given name. * @param value the value to associate with the given name.
* @return the equate
* @exception DuplicateNameException thrown if name is already in use * @exception DuplicateNameException thrown if name is already in use
* as an equate. * as an equate.
* @throws InvalidInputException if name contains blank characters, * @throws InvalidInputException if name contains blank characters,
@ -59,8 +46,6 @@ public interface EquateTable {
public Equate createEquate(String name, long value) public Equate createEquate(String name, long value)
throws DuplicateNameException, InvalidInputException; throws DuplicateNameException, InvalidInputException;
/** /**
* Removes the equate from the program. * Removes the equate from the program.
* @param name the name of the equate to remove. * @param name the name of the equate to remove.
@ -75,12 +60,13 @@ public interface EquateTable {
* @param monitor task monitor to cancel the remove operation * @param monitor task monitor to cancel the remove operation
* @throws CancelledException if the operation was cancelled. * @throws CancelledException if the operation was cancelled.
*/ */
public void deleteAddressRange(Address start, Address end, TaskMonitor monitor) throws CancelledException; public void deleteAddressRange(Address start, Address end, TaskMonitor monitor)
throws CancelledException;
/** /**
* Returns the equate with the given name, null if no such equate * Returns the equate with the given name, null if no such equate exists
* exists. * @param name the of the equate to be retrieved
* @param name the of the equate to be retrieved. * @return the equate
*/ */
public Equate getEquate(String name); public Equate getEquate(String name);
@ -114,17 +100,20 @@ public interface EquateTable {
/** /**
* Returns an address iterator over all the addresses where * Returns an address iterator over all the addresses where
* equates have been set. * equates have been set.
* @return the iterator
*/ */
public AddressIterator getEquateAddresses(); public AddressIterator getEquateAddresses();
/** /**
* Returns all equates defined for value. * Returns all equates defined for value.
* @param value the value to get all equates for. * @param value the value to get all equates for.
* @return the equates
*/ */
public List<Equate> getEquates(long value); public List<Equate> getEquates(long value);
/** /**
* Returns an iterator over all equates. * Returns an iterator over all equates.
* @return the iterator
*/ */
public Iterator<Equate> getEquates(); public Iterator<Equate> getEquates();