Refactor HighSymbol mutability

This commit is contained in:
caheckman 2024-04-16 00:13:34 +00:00
parent 616bf82426
commit e279c5b56a
6 changed files with 69 additions and 144 deletions

View file

@ -30,7 +30,8 @@ import ghidra.program.model.data.*;
import ghidra.program.model.lang.*;
import ghidra.program.model.lang.ConstantPool.Record;
import ghidra.program.model.listing.*;
import ghidra.program.model.mem.*;
import ghidra.program.model.mem.MemoryAccessException;
import ghidra.program.model.mem.MemoryBufferImpl;
import ghidra.program.model.pcode.*;
import ghidra.program.model.symbol.*;
import ghidra.util.Msg;
@ -840,9 +841,8 @@ public class DecompileCallback {
else {
highSymbol = new HighCodeSymbol(0,
SymbolUtilities.getDynamicName(program, data.getAddress()), data, dtmanage);
SymbolEntry entry = highSymbol.getFirstWholeMap();
if (data.getDataType() == DataType.DEFAULT && !entry.isReadOnly() &&
!entry.isVolatile()) {
if (data.getDataType() == DataType.DEFAULT &&
highSymbol.getMutability() == MutabilitySettingsDefinition.NORMAL) {
return false;
}
}
@ -875,53 +875,6 @@ public class DecompileCallback {
encodeResult(encoder, labelSymbol, namespc);
}
/**
* Check address is read only. This only checks whether the block containing
* the address is read-only. It does not, and should not, check if there is
* a data object that has been set to constant
*
* @param addr - address to check
*
* @return true if the block is read_only, and there are no write
* references.
*/
private boolean isReadOnlyNoData(Address addr) {
boolean readonly = false;
MemoryBlock block = program.getMemory().getBlock(addr);
if (block != null) {
readonly = !block.isWrite();
// if the block says read-only, check the refs to the variable
// if the block says read-only, check the refs to the variable
if (readonly) {
ReferenceIterator refIter = program.getReferenceManager().getReferencesTo(addr);
int count = 0;
// boolean foundRead = false;
while (refIter.hasNext() && count < 100) {
Reference ref = refIter.next();
if (ref.getReferenceType().isWrite()) {
readonly = false;
break;
}
if (ref.getReferenceType().isRead()) {
// foundRead = true;
}
count++;
}
// TODO: Don't do override if no read reference found
//
// if we only have indirect refs to it, don't assume readonly!
//if (!foundRead && readonly && count > 1) {
// readonly = false;
//}
// they must be reading it multiple times for some reason
// if (readonly && count > 1) {
// readonly = false;
// }
}
}
return readonly;
}
/**
* This function deals with the vagaries of the getMappedSymbols
* interface when the queried address is in the body of a function.
@ -967,16 +920,15 @@ public class DecompileCallback {
if (range.contains(addr)) {
Address first = range.getMinAddress();
Address last = range.getMaxAddress();
boolean readonly = true; // Treat function body as readonly
encodeHole(encoder, first.getAddressSpace(), first.getUnsignedOffset(),
last.getUnsignedOffset(), readonly, false);
last.getUnsignedOffset(), MutabilitySettingsDefinition.CONSTANT);
return;
}
}
// There is probably some sort of error, just return a block
// containing the single queried address
encodeHole(encoder, addr.getAddressSpace(), addr.getUnsignedOffset(),
addr.getUnsignedOffset(), true, false);
addr.getUnsignedOffset(), MutabilitySettingsDefinition.CONSTANT);
}
private int getExtraPopOverride(Function func, Address addr) {
@ -1013,10 +965,14 @@ public class DecompileCallback {
}
private void encodeHole(Encoder encoder, AddressSpace spc, long first, long last,
boolean readonly, boolean isVolatile) throws IOException {
int mutability) throws IOException {
encoder.openElement(ELEM_HOLE);
encoder.writeBool(ATTRIB_READONLY, readonly);
encoder.writeBool(ATTRIB_VOLATILE, isVolatile);
if (mutability == MutabilitySettingsDefinition.CONSTANT) {
encoder.writeBool(ATTRIB_READONLY, true);
}
else if (mutability == MutabilitySettingsDefinition.VOLATILE) {
encoder.writeBool(ATTRIB_VOLATILE, true);
}
encoder.writeSpace(ATTRIB_SPACE, spc);
encoder.writeUnsignedInteger(ATTRIB_FIRST, first);
encoder.writeUnsignedInteger(ATTRIB_LAST, last);
@ -1038,10 +994,9 @@ public class DecompileCallback {
* @throws IOException for errors in the underlying stream
*/
private void encodeHole(Encoder encoder, Address addr) throws IOException {
boolean readonly = isReadOnlyNoData(addr);
boolean isvolatile = isVolatileNoData(addr);
int mutability = MappedEntry.getMutabilityOfAddress(addr, program);
encodeHole(encoder, addr.getAddressSpace(), addr.getUnsignedOffset(),
addr.getUnsignedOffset(), readonly, isvolatile);
addr.getUnsignedOffset(), mutability);
}
private void encodeExternalRef(Encoder encoder, Address addr, ExternalReference ref)
@ -1135,20 +1090,6 @@ public class DecompileCallback {
return null;
}
/**
* Check whether the address is volatile. Do not check the data object.
*
* @param addr is address to check for volatility
* @return true if the address is volatile
*/
private boolean isVolatileNoData(Address addr) {
if (program.getLanguage().isVolatile(addr)) {
return true;
}
MemoryBlock block = program.getMemory().getBlock(addr);
return (block != null && block.isVolatile());
}
private Function getFunctionContaining(Address addr) {
if (cachedFunction != null && cachedFunction.getBody().contains(addr)) {
return cachedFunction;

View file

@ -22,6 +22,7 @@ import java.io.IOException;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSpace;
import ghidra.program.model.data.MutabilitySettingsDefinition;
import ghidra.program.model.listing.Program;
import ghidra.program.model.listing.VariableStorage;
import ghidra.util.exception.AssertException;
@ -115,13 +116,8 @@ public class DynamicEntry extends SymbolEntry {
}
@Override
public boolean isReadOnly() {
return false;
}
@Override
public boolean isVolatile() {
return false;
public int getMutability() {
return MutabilitySettingsDefinition.NORMAL;
}
}

View file

@ -22,6 +22,7 @@ import java.io.IOException;
import ghidra.program.model.address.Address;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.MutabilitySettingsDefinition;
import ghidra.program.model.lang.DynamicVariableStorage;
import ghidra.program.model.listing.*;
import ghidra.program.model.symbol.Namespace;
@ -314,10 +315,14 @@ public class HighSymbol {
}
/**
* @return true if the symbol's value is considered read-only (by the decompiler)
* Return one of
* - MutabilitySettingsDefinition.NORMAL
* - MutabilitySettingsDefinition.VOLATILE
* - MutabilitySettingsDefinition.CONSTANT
* @return the mutability setting
*/
public boolean isReadOnly() {
return entryList[0].isReadOnly();
public int getMutability() {
return entryList[0].getMutability();
}
/**
@ -384,9 +389,11 @@ public class HighSymbol {
encoder.writeString(ATTRIB_NAME, name);
encoder.writeBool(ATTRIB_TYPELOCK, typelock);
encoder.writeBool(ATTRIB_NAMELOCK, namelock);
encoder.writeBool(ATTRIB_READONLY, isReadOnly());
boolean isVolatile = entryList[0].isVolatile();
if (isVolatile) {
int mutability = getMutability();
if (mutability == MutabilitySettingsDefinition.CONSTANT) {
encoder.writeBool(ATTRIB_READONLY, true);
}
else if (mutability == MutabilitySettingsDefinition.VOLATILE) {
encoder.writeBool(ATTRIB_VOLATILE, true);
}
if (isIsolated()) {

View file

@ -15,6 +15,7 @@
*/
package ghidra.program.model.pcode;
import ghidra.program.model.data.MutabilitySettingsDefinition;
import ghidra.program.model.listing.Data;
import ghidra.program.model.listing.VariableStorage;
@ -57,21 +58,16 @@ public class MappedDataEntry extends MappedEntry {
}
@Override
public boolean isReadOnly() {
if (data.isWritable()) {
return false;
public int getMutability() {
if (data.isVolatile()) {
return MutabilitySettingsDefinition.VOLATILE;
}
if (data.isConstant()) {
return true;
return MutabilitySettingsDefinition.CONSTANT;
}
return super.isReadOnly();
if (data.isWritable()) {
return MutabilitySettingsDefinition.NORMAL;
}
@Override
public boolean isVolatile() {
if (data.isVolatile()) {
return true;
}
return super.isVolatile();
return super.getMutability();
}
}

View file

@ -19,6 +19,7 @@ import java.io.IOException;
import ghidra.program.model.address.Address;
import ghidra.program.model.data.AbstractFloatDataType;
import ghidra.program.model.data.MutabilitySettingsDefinition;
import ghidra.program.model.listing.Program;
import ghidra.program.model.listing.VariableStorage;
import ghidra.program.model.mem.MemoryBlock;
@ -87,59 +88,44 @@ public class MappedEntry extends SymbolEntry {
}
@Override
public boolean isReadOnly() {
public int getMutability() {
Address addr = storage.getMinAddress();
if (addr == null) {
return false;
return getMutabilityOfAddress(addr, symbol.getProgram());
}
/**
* Get the underlying mutability setting of an Address based on the Program
* configuration and the MemoryBlock. Ignore any overrides of Data at the address.
* @param addr is the Address
* @param program is the Program containing the Address
* @return the mutability
*/
public static int getMutabilityOfAddress(Address addr, Program program) {
if (addr == null) {
return MutabilitySettingsDefinition.NORMAL;
}
if (program.getLanguage().isVolatile(addr)) {
return MutabilitySettingsDefinition.VOLATILE;
}
boolean readonly = false;
Program program = symbol.getProgram();
MemoryBlock block = program.getMemory().getBlock(addr);
if (block != null) {
readonly = !block.isWrite();
if (block.isVolatile()) {
return MutabilitySettingsDefinition.VOLATILE;
}
// if the block says read-only, check the refs to the variable
// if the block says read-only, check the refs to the variable
if (readonly) {
if (!block.isWrite()) {
ReferenceIterator refIter = program.getReferenceManager().getReferencesTo(addr);
int count = 0;
// boolean foundRead = false;
while (refIter.hasNext() && count < 100) {
Reference ref = refIter.next();
if (ref.getReferenceType().isWrite()) {
readonly = false;
break;
}
if (ref.getReferenceType().isRead()) {
// foundRead = true;
return MutabilitySettingsDefinition.NORMAL;
}
count++;
}
// TODO: Don't do override if no read reference found
//
// if we only have indirect refs to it, don't assume readonly!
//if (!foundRead && readonly && count > 1) {
// readonly = false;
//}
// they must be reading it multiple times for some reason
// if (readonly && count > 1) {
// readonly = false;
// }
return MutabilitySettingsDefinition.CONSTANT;
}
}
return readonly;
}
@Override
public boolean isVolatile() {
Address addr = storage.getMinAddress();
if (addr == null) {
return false;
}
Program program = symbol.getProgram();
if (program.getLanguage().isVolatile(addr)) {
return true;
}
MemoryBlock block = program.getMemory().getBlock(addr);
return (block != null && block.isVolatile());
return MutabilitySettingsDefinition.NORMAL;
}
}

View file

@ -67,14 +67,13 @@ public abstract class SymbolEntry {
public abstract int getSize();
/**
* @return true if the mapped storage is read-only
* Return one of
* - MutabilitySettingsDefinition.NORMAL
* - MutabilitySettingsDefinition.VOLATILE
* - MutabilitySettingsDefinition.CONSTANT
* @return the mutability setting
*/
public abstract boolean isReadOnly();
/**
* @return true if the mapped storage is volatile
*/
public abstract boolean isVolatile();
public abstract int getMutability();
/**
* The storage used to hold this Symbol may be used for other purposes at different points in