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

@ -17,9 +17,6 @@ package ghidra.program.database.symbol;
import java.io.IOException;
import java.util.*;
import java.util.function.Consumer;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import db.*;
import db.util.ErrorHandler;
@ -27,22 +24,17 @@ import ghidra.program.database.*;
import ghidra.program.database.map.AddressKeyAddressIterator;
import ghidra.program.database.map.AddressMap;
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.EquateTable;
import ghidra.program.util.ChangeManager;
import ghidra.program.util.EquateInfo;
import ghidra.util.*;
import ghidra.util.Lock;
import ghidra.util.UniversalID;
import ghidra.util.exception.*;
import ghidra.util.task.TaskMonitor;
/**
* Implementation for the Equate Table.
*
*
* Implementation of the Equate Table
*/
public class EquateManager implements EquateTable, ErrorHandler, ManagerDB {
@ -60,14 +52,12 @@ public class EquateManager implements EquateTable, ErrorHandler, ManagerDB {
/**
* Constructor
* @param handle database handle
* @param addrMap map that converts addresses to longs and longs to
* addresses
* @param addrMap map that converts addresses to longs and longs to addresses
* @param openMode one of ProgramDB.CREATE, UPDATE, UPGRADE, or READ_ONLY
* @param lock the program synchronization lock
* @param monitor the progress monitor used when upgrading.
* @throws VersionException if the database version doesn't match the current version.
* @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,
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
public void setProgram(ProgramDB program) {
this.program = program;
}
/**
* @see ghidra.program.database.ManagerDB#programReady(int, int, ghidra.util.task.TaskMonitor)
*/
@Override
public void programReady(int openMode, int currentRevision, TaskMonitor monitor)
throws IOException, CancelledException {
// Nothing to do
}
/**
* @see db.util.ErrorHandler#dbError(java.io.IOException)
*/
@Override
public void dbError(IOException 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
public Equate createEquate(String name, long value)
throws DuplicateNameException, InvalidInputException {
@ -271,9 +134,6 @@ public class EquateManager implements EquateTable, ErrorHandler, ManagerDB {
return null;
}
/**
* @see ghidra.program.model.symbol.EquateTable#getEquate(ghidra.program.model.address.Address, int, long)
*/
@Override
public Equate getEquate(Address reference, int opIndex, long scalarValue) {
lock.acquire();
@ -302,9 +162,6 @@ public class EquateManager implements EquateTable, ErrorHandler, ManagerDB {
return null;
}
/**
* @see ghidra.program.model.symbol.EquateTable#getEquates(ghidra.program.model.address.Address, int)
*/
@Override
public List<Equate> getEquates(Address reference, int opIndex) {
List<Equate> ret = new LinkedList<>();
@ -331,9 +188,6 @@ public class EquateManager implements EquateTable, ErrorHandler, ManagerDB {
return ret;
}
/**
* @see ghidra.program.model.symbol.EquateTable#getEquates(ghidra.program.model.address.Address)
*/
@Override
public List<Equate> getEquates(Address reference) {
List<Equate> ret = new LinkedList<>();
@ -358,9 +212,6 @@ public class EquateManager implements EquateTable, ErrorHandler, ManagerDB {
return ret;
}
/**
* @see ghidra.program.model.symbol.EquateTable#getEquate(java.lang.String)
*/
@Override
public Equate getEquate(String name) {
lock.acquire();
@ -369,6 +220,7 @@ public class EquateManager implements EquateTable, ErrorHandler, ManagerDB {
return getEquateDB(equateID);
}
catch (NotFoundException e) {
// just return null below
}
catch (IOException e) {
program.dbError(e);
@ -379,9 +231,6 @@ public class EquateManager implements EquateTable, ErrorHandler, ManagerDB {
return null;
}
/**
* @see ghidra.program.model.symbol.EquateTable#getEquateAddresses()
*/
@Override
public AddressIterator getEquateAddresses() {
@ -395,9 +244,6 @@ public class EquateManager implements EquateTable, ErrorHandler, ManagerDB {
return new EmptyAddressIterator();
}
/**
* @see ghidra.program.model.symbol.EquateTable#getEquateAddresses(ghidra.program.model.address.Address)
*/
@Override
public AddressIterator getEquateAddresses(Address startAddr) {
try {
@ -421,9 +267,6 @@ public class EquateManager implements EquateTable, ErrorHandler, ManagerDB {
return new EmptyAddressIterator();
}
/**
* @see ghidra.program.model.symbol.EquateTable#getEquateAddresses(ghidra.program.model.address.AddressSetView)
*/
@Override
public AddressIterator getEquateAddresses(AddressSetView set) {
try {
@ -436,9 +279,6 @@ public class EquateManager implements EquateTable, ErrorHandler, ManagerDB {
return new EmptyAddressIterator();
}
/**
* @see ghidra.program.model.symbol.EquateTable#getEquates()
*/
@Override
public Iterator<Equate> getEquates() {
try {
@ -451,9 +291,6 @@ public class EquateManager implements EquateTable, ErrorHandler, ManagerDB {
return new EquateIterator(null);
}
/**
* @see ghidra.program.model.symbol.EquateTable#getEquates(long)
*/
@Override
public List<Equate> getEquates(long value) {
ArrayList<Equate> list = new ArrayList<>();
@ -473,9 +310,6 @@ public class EquateManager implements EquateTable, ErrorHandler, ManagerDB {
return list;
}
/**
* @see ghidra.program.database.ManagerDB#deleteAddressRange(ghidra.program.model.address.Address, ghidra.program.model.address.Address, ghidra.util.task.TaskMonitor)
*/
@Override
public void deleteAddressRange(Address startAddr, Address endAddr, TaskMonitor monitor)
throws CancelledException {
@ -516,9 +350,6 @@ public class EquateManager implements EquateTable, ErrorHandler, ManagerDB {
}
}
/**
* @see ghidra.program.model.symbol.EquateTable#removeEquate(java.lang.String)
*/
@Override
public boolean removeEquate(String name) {
if (name == null) {
@ -562,30 +393,18 @@ public class EquateManager implements EquateTable, ErrorHandler, ManagerDB {
}
}
/**
* Return the address map.
*/
AddressMap getAddressMap() {
return addrMap;
}
/**
* Get the database adapter for equate table.
*/
EquateDBAdapter getEquateDatabaseAdapter() {
return equateAdapter;
}
/**
* Get the database adapter for the equate references table.
*/
EquateRefDBAdapter getRefDatabaseAdapter() {
return refAdapter;
}
/**
* Add a reference for an equate at the given operand position.
*/
void addReference(long equateID, Address address, int opIndex, long dynamicHash)
throws IOException {
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 {
long[] keys = refAdapter.getRecordKeysForEquateID(equateID);
EquateRefDB[] refs = new EquateRefDB[keys.length];
@ -634,19 +450,10 @@ public class EquateManager implements EquateTable, ErrorHandler, ManagerDB {
return refs;
}
/**
* Get the number of references for the given equate ID.
*/
int getReferenceCount(long equateID) throws IOException {
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 {
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 {
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 {
if (name == 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 newName new name
*/
@ -784,66 +580,10 @@ public class EquateManager implements EquateTable, ErrorHandler, ManagerDB {
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() {
return lock;
}
/**
* @see ghidra.program.database.ManagerDB#invalidateCache(boolean)
*/
@Override
public void invalidateCache(boolean all) {
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
public void moveAddressRange(Address fromAddr, Address toAddr, long length, TaskMonitor monitor)
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
* formatted strings are used when setting equates from datatypes so that information can be
* 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
* @return The formatted equate name
*/
@ -922,4 +659,51 @@ public class EquateManager implements EquateTable, ErrorHandler, ManagerDB {
}
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 ghidra.program.model.address.*;
import ghidra.program.model.data.Enum;
import ghidra.util.exception.*;
import ghidra.util.task.TaskMonitor;
/**
* 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
@ -32,40 +32,25 @@ import ghidra.util.task.TaskMonitor;
*/
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.
* Creates a new equate
* @param name the name to associate with the given value.
* @param value the value to associate with the given name.
* @return the equate
* @exception DuplicateNameException thrown if name is already in use
* as an equate.
* @throws InvalidInputException if name contains blank characters,
* is zero length, or is null
*/
public void applyEnum(AddressSetView addrSet, Enum dataType, TaskMonitor monitor,
boolean shouldDoOnSubOps) throws CancelledException;
public Equate createEquate(String name, long value)
throws DuplicateNameException, InvalidInputException;
/**
* Creates a new equate
* @param name the name to associate with the given value.
* @param value the value to associate with the given name.
* @exception DuplicateNameException thrown if name is already in use
* as an equate.
* @throws InvalidInputException if name contains blank characters,
* is zero length, or is null
*/
public Equate createEquate(String name,long value)
throws DuplicateNameException, InvalidInputException;
/**
* Removes the equate from the program.
* @param name the name of the equate to remove.
* @return true if the equate existed, false otherwise.
*/
/**
* Removes the equate from the program.
* @param name the name of the equate to remove.
* @return true if the equate existed, false otherwise.
*/
public boolean removeEquate(String name);
/**
@ -75,24 +60,25 @@ public interface EquateTable {
* @param monitor task monitor to cancel the remove operation
* @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
* exists.
* @param name the of the equate to be retrieved.
*/
public Equate getEquate(String name);
/**
* Returns the equate with the given name, null if no such equate exists
* @param name the of the equate to be retrieved
* @return the equate
*/
public Equate getEquate(String name);
/**
* Returns the first equate found that is associated with the given
* value at the given reference address and operand position;
* @param reference address where the equate is used.
* @param opndPosition the operand index of the operand where the equate is used.
* @param value the value where the equate is used.
/**
* Returns the first equate found that is associated with the given
* value at the given reference address and operand position;
* @param reference address where the equate is used.
* @param opndPosition the operand index of the operand where the equate is used.
* @param value the value where the equate is used.
* @return the equate or null if there is no such equate.
*/
public Equate getEquate(Address reference, int opndPosition, long value);
*/
public Equate getEquate(Address reference, int opndPosition, long value);
/**
* Returns the equates (one for each scalar) at the given reference address
@ -102,7 +88,7 @@ public interface EquateTable {
* @return the list of equates or empty list if there is no such equate.
*/
public List<Equate> getEquates(Address reference, int opndPosition);
/**
* Returns the equates (one for each scalar and opIndex) at the given reference address.
* For an instruction a given operand can have multiple scalars.
@ -111,39 +97,42 @@ public interface EquateTable {
*/
public List<Equate> getEquates(Address reference);
/**
* Returns an address iterator over all the addresses where
* equates have been set.
*/
public AddressIterator getEquateAddresses();
/**
* Returns all equates defined for value.
* @param value the value to get all equates for.
*/
public List<Equate> getEquates(long value);
/**
* Returns an iterator over all equates.
*/
/**
* Returns an address iterator over all the addresses where
* equates have been set.
* @return the iterator
*/
public AddressIterator getEquateAddresses();
/**
* Returns all equates defined for value.
* @param value the value to get all equates for.
* @return the equates
*/
public List<Equate> getEquates(long value);
/**
* Returns an iterator over all equates.
* @return the iterator
*/
public Iterator<Equate> getEquates();
/**
* Return an address iterator over each address with an
* equate reference starting at the start address.
*
* @param start start address
* @return an AddressIterator over addresses with defined equate references
*/
public AddressIterator getEquateAddresses(Address start);
/**
* Return an address iterator over each address with an
* equate reference starting at the start address.
*
* @param start start address
* @return an AddressIterator over addresses with defined equate references
*/
public AddressIterator getEquateAddresses(Address start);
/**
* Return an address iterator over each address with an
* equate reference that is in the specified address set.
*
* @param asv the address set
* @return AddressIterator over addresses with defined equate references
*/
public AddressIterator getEquateAddresses(AddressSetView asv);
/**
* Return an address iterator over each address with an
* equate reference that is in the specified address set.
*
* @param asv the address set
* @return AddressIterator over addresses with defined equate references
*/
public AddressIterator getEquateAddresses(AddressSetView asv);
}