mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 10:49:34 +02:00
GP-1403 Allow unrestricted clearing of settings. Improve Pointer-Typedef
error condition feedback in listing. Various tweaks to settings-based pointer calculations.
This commit is contained in:
parent
362bd6b5cb
commit
abce9bbf85
16 changed files with 215 additions and 71 deletions
|
@ -15,12 +15,12 @@
|
|||
*/
|
||||
package ghidra.pcode.emulate;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import ghidra.pcode.memstate.MemoryState;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.mem.*;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
/**
|
||||
* <code>MemoryStateBuffer</code> provides a MemBuffer for instruction parsing use
|
||||
* which wraps an emulator MemoryState. This implementation wraps all specified
|
||||
|
@ -111,8 +111,7 @@ public class EmulateMemoryStateBuffer implements MemBuffer {
|
|||
|
||||
@Override
|
||||
public Memory getMemory() {
|
||||
// Make sure Sleigh language provider does not call this method
|
||||
throw new UnsupportedOperationException();
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -120,7 +120,7 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
|||
private SettingsCache<Long> settingsCache = new SettingsCache<>(200);
|
||||
private List<DataType> sortedDataTypes;
|
||||
private Map<Long, Set<String>> enumValueMap;
|
||||
private Map<String, Set<String>> suggestedSettingsValuesMap = new HashMap<>();
|
||||
private Map<String, Set<String>> previouslyUsedSettingsValuesMap = new HashMap<>();
|
||||
|
||||
private List<InvalidatedListener> invalidatedListeners = new ArrayList<>();
|
||||
protected DataTypeManagerChangeListenerHandler defaultListener =
|
||||
|
@ -679,7 +679,7 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
|||
SettingDB setting = new SettingDB(rec, settingsAdapter.getSettingName(rec));
|
||||
settingsCache.put(dataTypeId, name, setting);
|
||||
if (strValue != null) {
|
||||
Set<String> suggestions = suggestedSettingsValuesMap.get(name);
|
||||
Set<String> suggestions = previouslyUsedSettingsValuesMap.get(name);
|
||||
if (suggestions != null) {
|
||||
// only cache suggestion if suggestions previously requested
|
||||
suggestions.add(strValue);
|
||||
|
@ -702,7 +702,6 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
|||
Set<String> set = new TreeSet<>();
|
||||
try {
|
||||
settingsAdapter.addAllValues(settingsDefinition.getStorageKey(), set);
|
||||
settingsDefinition.addPreferredValues(this, set);
|
||||
}
|
||||
catch (IOException e) {
|
||||
errHandler.dbError(e);
|
||||
|
@ -716,11 +715,17 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
|||
* @return suggested values or empty array if none
|
||||
*/
|
||||
String[] getSuggestedValues(StringSettingsDefinition settingsDefinition) {
|
||||
if (!settingsDefinition.supportsSuggestedValues()) {
|
||||
return Settings.EMPTY_STRING_ARRAY;
|
||||
}
|
||||
lock.acquire();
|
||||
try {
|
||||
Set<String> set = suggestedSettingsValuesMap
|
||||
Set<String> previouslyUsedSet = previouslyUsedSettingsValuesMap
|
||||
.computeIfAbsent(settingsDefinition.getStorageKey(),
|
||||
n -> generateSuggestions(settingsDefinition));
|
||||
// Last-minute additions are not cached since suggested values may change
|
||||
Set<String> set = new TreeSet<>(previouslyUsedSet); // copy before updating
|
||||
settingsDefinition.addPreferredValues(this, set);
|
||||
if (set.isEmpty()) {
|
||||
return Settings.EMPTY_STRING_ARRAY;
|
||||
}
|
||||
|
@ -3240,7 +3245,6 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
|
|||
fireInvalidated();
|
||||
updateFavorites();
|
||||
idsToDataTypeMap.clear();
|
||||
suggestedSettingsValuesMap.clear();
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
|
|
|
@ -109,6 +109,25 @@ class DataTypeSettingsDB implements Settings {
|
|||
* @return true if change permitted
|
||||
*/
|
||||
private boolean checkSetting(String type, String name) {
|
||||
if (!checkImmutableSetting(type, name)) {
|
||||
return false;
|
||||
}
|
||||
if (name != null && allowedSettingPredicate != null &&
|
||||
!allowedSettingPredicate.apply(name)) {
|
||||
Msg.warn(this, "Ignored disallowed setting '" + name + "'");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for immutable settings and log error of modification not permitted.
|
||||
* Does not check for other setting restrictions.
|
||||
* @param type setting type or null
|
||||
* @param name setting name or null
|
||||
* @return true if change permitted
|
||||
*/
|
||||
private boolean checkImmutableSetting(String type, String name) {
|
||||
if (locked) {
|
||||
String typeStr = "";
|
||||
if (type != null) {
|
||||
|
@ -123,11 +142,6 @@ class DataTypeSettingsDB implements Settings {
|
|||
nameStr);
|
||||
return false;
|
||||
}
|
||||
if (name != null && allowedSettingPredicate != null &&
|
||||
!allowedSettingPredicate.apply(name)) {
|
||||
Msg.warn(this, "Ignored disallowed setting '" + name + "'");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -205,14 +219,14 @@ class DataTypeSettingsDB implements Settings {
|
|||
|
||||
@Override
|
||||
public void clearSetting(String name) {
|
||||
if (checkSetting(null, name) && dataMgr.clearSetting(dataTypeID, name)) {
|
||||
if (checkImmutableSetting(null, name) && dataMgr.clearSetting(dataTypeID, name)) {
|
||||
settingsChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearAllSettings() {
|
||||
if (checkSetting(null, null) && dataMgr.clearAllSettings(dataTypeID)) {
|
||||
if (checkImmutableSetting(null, null) && dataMgr.clearAllSettings(dataTypeID)) {
|
||||
settingsChanged();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -415,6 +415,9 @@ class TypedefDB extends DataTypeDB implements TypeDef {
|
|||
|
||||
@Override
|
||||
public String getDefaultLabelPrefix() {
|
||||
if (isAutoNamed()) {
|
||||
return getDataType().getDefaultLabelPrefix();
|
||||
}
|
||||
return getName();
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ import java.util.Collection;
|
|||
import ghidra.docking.settings.Settings;
|
||||
import ghidra.docking.settings.SettingsDefinition;
|
||||
import ghidra.program.model.mem.MemBuffer;
|
||||
import ghidra.program.model.scalar.Scalar;
|
||||
import ghidra.util.InvalidNameException;
|
||||
import ghidra.util.UniversalID;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
@ -281,10 +282,11 @@ public interface DataType {
|
|||
public URL getDocs();
|
||||
|
||||
/**
|
||||
* Get the data in the form of the appropriate Object for this DataType.
|
||||
* Get the interpretted data value in the form of the appropriate Object for this DataType.
|
||||
* This method must return a value consistent with {@link #getValueClass(Settings)}.
|
||||
* <p>
|
||||
* For instance if the datatype is an AddressDT, return an Address object. a Byte, return a
|
||||
* Scalar* (maybe this should be a Byte) a Float, return a Float
|
||||
* For instance, if this datatype is a {@link Pointer} an Address object or null should be returned.
|
||||
* A Byte, returns a {@link Scalar} object.
|
||||
*
|
||||
* @param buf the data buffer.
|
||||
* @param settings the settings to use.
|
||||
|
@ -328,7 +330,8 @@ public interface DataType {
|
|||
throws DataTypeEncodeException;
|
||||
|
||||
/**
|
||||
* Get the Class of the value to be returned by this datatype.
|
||||
* Get the Class of the value Object to be returned by this datatype
|
||||
* (see {@link #getValue(MemBuffer, Settings, int)}).
|
||||
*
|
||||
* @param settings the relevant settings to use or null for default.
|
||||
* @return Class of the value to be returned by this datatype or null if it can vary or is
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
package ghidra.program.model.data;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import ghidra.docking.settings.Settings;
|
||||
import ghidra.program.database.data.DataTypeUtilities;
|
||||
|
@ -24,6 +25,7 @@ import ghidra.program.model.listing.*;
|
|||
import ghidra.program.model.mem.*;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.util.DataConverter;
|
||||
import ghidra.util.StringUtilities;
|
||||
|
||||
/**
|
||||
* Basic implementation for a pointer dataType
|
||||
|
@ -37,6 +39,7 @@ public class PointerDataType extends BuiltIn implements Pointer {
|
|||
public static final String POINTER_NAME = "pointer";
|
||||
public static final String POINTER_LABEL_PREFIX = "PTR";
|
||||
public static final String POINTER_LOOP_LABEL_PREFIX = "PTR_LOOP";
|
||||
public static final String NOT_A_POINTER = "NaP";
|
||||
|
||||
// NOTE: order dictates auto-name attribute ordering (order should not be changed)
|
||||
private static TypeDefSettingsDefinition[] POINTER_TYPEDEF_SETTINGS_DEFS =
|
||||
|
@ -345,14 +348,16 @@ public class PointerDataType extends BuiltIn implements Pointer {
|
|||
|
||||
/**
|
||||
* Generate an address value based upon bytes stored at the specified buf
|
||||
* location. The following settings, if specified, may influence the generated address:
|
||||
* location. Interpretation of settings may depend on access to a {@link Memory}
|
||||
* object associated with the specified {@link MemBuffer} buf.
|
||||
* <BR>
|
||||
* The following pointer-typedef settings are supported:
|
||||
* <ul>
|
||||
* <li>{@link AddressSpaceSettingsDefinition}</li>
|
||||
* <li>{@link OffsetMaskSettingsDefinition}</li>
|
||||
* <li>{@link OffsetShiftSettingsDefinition}</li>
|
||||
* <li>{@link PointerTypeSettingsDefinition}</li>
|
||||
* </ul>
|
||||
* The default address space will be the same as the buffer's associated memory address.
|
||||
* Interpretation of settings may depend on access to a {@link Memory} object associated
|
||||
* with the specified {@link MemBuffer} buf.
|
||||
*
|
||||
* @param buf memory buffer positioned to stored pointer
|
||||
* @param size pointer size in bytes
|
||||
|
@ -360,31 +365,40 @@ public class PointerDataType extends BuiltIn implements Pointer {
|
|||
* @return address value or null if unusable buf or data
|
||||
*/
|
||||
public static Address getAddressValue(MemBuffer buf, int size, Settings settings) {
|
||||
return getAddressValue(buf, size, settings, msg -> {
|
||||
/* ignore */});
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate an address value based upon bytes stored at the specified buf
|
||||
* location. Interpretation of settings may depend on access to a {@link Memory}
|
||||
* object associated with the specified {@link MemBuffer} buf.
|
||||
* <BR>
|
||||
* The following pointer-typedef settings are supported:
|
||||
* <ul>
|
||||
* <li>{@link AddressSpaceSettingsDefinition}</li>
|
||||
* <li>{@link OffsetMaskSettingsDefinition}</li>
|
||||
* <li>{@link OffsetShiftSettingsDefinition}</li>
|
||||
* <li>{@link PointerTypeSettingsDefinition}</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param buf memory buffer positioned to stored pointer
|
||||
* @param size pointer size in bytes
|
||||
* @param settings settings which may influence address generation
|
||||
* @param errorHandler if null returned an error may be conveyed to this errorHandler
|
||||
* @return address value or null if unusable buf or data
|
||||
*/
|
||||
public static Address getAddressValue(MemBuffer buf, int size, Settings settings,
|
||||
Consumer<String> errorHandler) {
|
||||
|
||||
String spaceName = AddressSpaceSettingsDefinition.DEF.getValue(settings);
|
||||
AddressSpace targetSpace = null;
|
||||
|
||||
Memory mem = buf.getMemory();
|
||||
if (mem != null) {
|
||||
Program program = mem.getProgram();
|
||||
String spaceName = AddressSpaceSettingsDefinition.DEF.getValue(settings);
|
||||
if (spaceName != null) {
|
||||
// this space may be ignored if pointer type specified
|
||||
targetSpace = program.getAddressFactory().getAddressSpace(spaceName);
|
||||
}
|
||||
}
|
||||
if (targetSpace == null) {
|
||||
// default to address space associated with mem buffer
|
||||
targetSpace = buf.getAddress().getAddressSpace();
|
||||
}
|
||||
|
||||
if (targetSpace instanceof SegmentedAddressSpace) {
|
||||
// ignore other settings with SegmentedAddressSpace use
|
||||
return getAddressValue(buf, size, targetSpace);
|
||||
}
|
||||
|
||||
Long offset = getStoredOffset(buf, size);
|
||||
if (offset == null) {
|
||||
// Insufficient bytes
|
||||
errorHandler.accept("Insufficient data");
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -397,7 +411,7 @@ public class PointerDataType extends BuiltIn implements Pointer {
|
|||
|
||||
int shift = (int) OffsetShiftSettingsDefinition.DEF.getValue(settings);
|
||||
if (shift < 0) {
|
||||
addrOffset >>= -shift;
|
||||
addrOffset >>>= -shift; // avoid sign-extension
|
||||
}
|
||||
else {
|
||||
addrOffset <<= shift;
|
||||
|
@ -405,42 +419,103 @@ public class PointerDataType extends BuiltIn implements Pointer {
|
|||
|
||||
try {
|
||||
PointerType choice = PointerTypeSettingsDefinition.DEF.getType(settings);
|
||||
if (choice != PointerType.DEFAULT && spaceName != null) {
|
||||
errorHandler.accept("Address Space and Pointer Type settings conflict");
|
||||
return null;
|
||||
}
|
||||
// Address space setting ignored if Pointer Type has been specified
|
||||
if (choice == PointerType.IMAGE_BASE_RELATIVE && mem != null) {
|
||||
if (choice == PointerType.IMAGE_BASE_RELATIVE) {
|
||||
if (addrOffset == 0) {
|
||||
// Done for consistency with old ImageBaseOffsetDataType.
|
||||
// A 0 relative offset is considerd invalid (NaP)
|
||||
return null;
|
||||
return null; // NaP without error
|
||||
}
|
||||
if (mem == null) {
|
||||
errorHandler.accept("Memory not specified");
|
||||
}
|
||||
// must ignore AddressSpaceSettingsDefinition
|
||||
Address imageBase = mem.getProgram().getImageBase();
|
||||
targetSpace = imageBase.getAddressSpace();
|
||||
return imageBase.add(addrOffset * targetSpace.getAddressableUnitSize());
|
||||
return imageBase.addWrap(addrOffset * targetSpace.getAddressableUnitSize());
|
||||
}
|
||||
else if (choice == PointerType.RELATIVE) {
|
||||
// must ignore AddressSpaceSettingsDefinition
|
||||
Address base = buf.getAddress();
|
||||
targetSpace = base.getAddressSpace();
|
||||
return base.add(addrOffset * targetSpace.getAddressableUnitSize());
|
||||
return base.addWrap(addrOffset * targetSpace.getAddressableUnitSize());
|
||||
}
|
||||
if (choice == PointerType.FILE_OFFSET) {
|
||||
if (mem != null) {
|
||||
else if (choice == PointerType.FILE_OFFSET) {
|
||||
if (mem == null) {
|
||||
errorHandler.accept("Memory not specified");
|
||||
}
|
||||
else if (mem.getAllFileBytes().size() == 0) {
|
||||
errorHandler.accept("No File bytes used");
|
||||
}
|
||||
else {
|
||||
List<Address> addressList = mem.locateAddressesForFileOffset(addrOffset);
|
||||
if (addressList.size() == 1) {
|
||||
return addressList.get(0);
|
||||
}
|
||||
if (addressList.size() > 1) {
|
||||
errorHandler.accept(
|
||||
"Non-unique File offset mapping: 0x" + Long.toHexString(addrOffset));
|
||||
}
|
||||
else {
|
||||
errorHandler.accept(
|
||||
"File offset mapping not found: 0x" + Long.toHexString(addrOffset));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
else if (choice != PointerType.DEFAULT) {
|
||||
errorHandler.accept("Unsupported pointer type: " + choice.toString());
|
||||
return null;
|
||||
}
|
||||
|
||||
if (spaceName != null) {
|
||||
if (mem == null) {
|
||||
errorHandler.accept("Memory not specified");
|
||||
return null;
|
||||
}
|
||||
Program program = mem.getProgram();
|
||||
targetSpace = program.getAddressFactory().getAddressSpace(spaceName);
|
||||
if (targetSpace == null) {
|
||||
errorHandler.accept(
|
||||
"Address space not defined: " + spaceName + ":" + formatOffset(addrOffset));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if (targetSpace == null) {
|
||||
targetSpace = buf.getAddress().getAddressSpace();
|
||||
}
|
||||
|
||||
if (targetSpace instanceof SegmentedAddressSpace) {
|
||||
if (size != 2 && size != 4) {
|
||||
errorHandler.accept("Unsupported segmented address size: " + size);
|
||||
return null;
|
||||
}
|
||||
if (mask != 0 || shift != 0) {
|
||||
errorHandler.accept("Unsupported mask/shift setting for segmented address");
|
||||
return null;
|
||||
}
|
||||
return getSegmentedAddressValue(buf, size, addrOffset);
|
||||
}
|
||||
|
||||
return targetSpace.getAddress(addrOffset, true);
|
||||
}
|
||||
catch (AddressOutOfBoundsException e) {
|
||||
// offset too large
|
||||
catch (IllegalArgumentException | AddressOutOfBoundsException e) {
|
||||
errorHandler.accept(e.toString());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String formatOffset(long offset) {
|
||||
String offsetStr = Long.toHexString(offset);
|
||||
int len = offsetStr.length();
|
||||
len = len - (len % 4) + 4; // multiple of 4-digits
|
||||
return StringUtilities.pad(offsetStr, '0', len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get signed offset value based upon bytes stored at the specified buf
|
||||
* location
|
||||
|
@ -554,7 +629,7 @@ public class PointerDataType extends BuiltIn implements Pointer {
|
|||
|
||||
Address addr = (Address) getValue(buf, settings, len);
|
||||
if (addr == null) { // could not create address, so return "Not a pointer (NaP)"
|
||||
return "NaP";
|
||||
return NOT_A_POINTER;
|
||||
}
|
||||
return addr.toString();
|
||||
}
|
||||
|
|
|
@ -122,6 +122,9 @@ public class TypedefDataType extends GenericDataType implements TypeDef {
|
|||
|
||||
@Override
|
||||
public String getDefaultLabelPrefix() {
|
||||
if (isAutoNamed()) {
|
||||
return getDataType().getDefaultLabelPrefix();
|
||||
}
|
||||
return getName();
|
||||
}
|
||||
|
||||
|
|
|
@ -294,7 +294,7 @@ public class DataStub implements Data {
|
|||
|
||||
@Override
|
||||
public Memory getMemory() {
|
||||
throw new UnsupportedOperationException();
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -290,7 +290,7 @@ public class InstructionStub implements Instruction {
|
|||
|
||||
@Override
|
||||
public Memory getMemory() {
|
||||
throw new UnsupportedOperationException();
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -67,7 +67,7 @@ public class ByteMemBufferImpl implements MemBuffer {
|
|||
|
||||
@Override
|
||||
public Memory getMemory() {
|
||||
throw new UnsupportedOperationException("Can't get memory from ByteMemBuffer");
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -114,7 +114,7 @@ public interface MemBuffer {
|
|||
/**
|
||||
* Get the Memory object actually used by the MemBuffer.
|
||||
*
|
||||
* @return the Memory used by this MemBuffer.
|
||||
* @return the Memory used by this MemBuffer or null if not available.
|
||||
*/
|
||||
public Memory getMemory();
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue