GP-1403 Improved support for auto-named typedefs. Updated create

typedef action from pointer to use auto-naming.  Replaced old
ImageBaseOffsetDataType 32/64-bit BuiltIn types with new pointer-typedef
based implementations. Improved settings modification
restrictions.  Resolved various bugs.
This commit is contained in:
ghidra1 2022-02-15 10:16:08 -05:00
parent ec5b6aada7
commit 8f0589a6d8
103 changed files with 2226 additions and 1156 deletions

View file

@ -18,6 +18,7 @@ package ghidra.app.util;
import java.util.*;
import ghidra.docking.settings.Settings;
import ghidra.docking.settings.SettingsDefinition;
import ghidra.program.database.ProgramDB;
import ghidra.program.database.data.ProgramDataTypeManager;
import ghidra.program.model.address.Address;
@ -228,7 +229,12 @@ public class PseudoData extends PseudoCodeUnit implements Data {
@Override
public Long getLong(String name) {
return null;
return getDefaultSettings().getLong(name);
}
@Override
public boolean isChangeAllowed(SettingsDefinition settingsDefinition) {
return false;
}
@Override
@ -238,15 +244,12 @@ public class PseudoData extends PseudoCodeUnit implements Data {
@Override
public String getString(String name) {
return null;
return getDefaultSettings().getString(name);
}
@Override
public Object getValue(String name) {
if (baseDataType != null) {
return baseDataType.getValue(this, this, length);
}
return null;
return getDefaultSettings().getValue(name);
}
@Override
@ -369,41 +372,6 @@ public class PseudoData extends PseudoCodeUnit implements Data {
return null;
}
// /**
// * @see ghidra.program.model.listing.Data#getComponents()
// */
// public Data[] getComponents() {
// if (length < dataType.getLength()) {
// return null;
// }
// Data[] retData = EMPTY_COMPONENTS;
// if (baseDataType instanceof Composite) {
// Composite composite = (Composite)baseDataType;
// int n = composite.getNumComponents();
// retData = new Data[n];
// for(int i=0;i<n;i++) {
// retData[i] = getComponent(i);
// }
// }
// else if (baseDataType instanceof Array) {
// Array array = (Array)baseDataType;
// int n = array.getNumElements();
// retData = new Data[n];
// for(int i=0;i<n;i++) {
// retData[i] = getComponent(i);
// }
// }
// else if (baseDataType instanceof DynamicDataType) {
// DynamicDataType ddt = (DynamicDataType)baseDataType;
// int n = ddt.getNumComponents(this);
// retData = new Data[n];
// for(int i=0;i<n;i++) {
// retData[i] = getComponent(i);
// }
// }
// return retData;
// }
@Override
public DataType getDataType() {
return dataType;
@ -542,7 +510,7 @@ public class PseudoData extends PseudoCodeUnit implements Data {
if (dataMgr == null) {
return true;
}
return dataMgr.isEmptySetting(address);
return dataMgr.isEmptySetting(this);
}
@Override

View file

@ -38,7 +38,6 @@ class PseudoDataComponent extends PseudoData {
private int indexInParent;
private int offset;
private int[] path;
private Settings defaultSettings;
PseudoDataComponent(Program program, Address address, PseudoData parent,
DataTypeComponent component, MemBuffer memBuffer)
@ -170,60 +169,6 @@ class PseudoDataComponent extends PseudoData {
return super.equals(obj);
}
@Override
public Long getLong(String name) {
if (dataMgr == null) {
return null;
}
Long value = dataMgr.getLongSettingsValue(address, name);
if (value != null) {
return value;
}
if (component == null) {
return null;
}
if (defaultSettings == null) {
defaultSettings = component.getDefaultSettings();
}
return defaultSettings.getLong(name);
}
@Override
public String getString(String name) {
if (dataMgr == null) {
return null;
}
String value = dataMgr.getStringSettingsValue(address, name);
if (value != null) {
return value;
}
if (component == null) {
return null;
}
if (defaultSettings == null) {
defaultSettings = component.getDefaultSettings();
}
return defaultSettings.getString(name);
}
@Override
public Object getValue(String name) {
if (dataMgr == null) {
return null;
}
Object value = dataMgr.getSettings(address, name);
if (value != null) {
return value;
}
if (component == null) {
return null;
}
if (defaultSettings == null) {
defaultSettings = component.getDefaultSettings();
}
return defaultSettings.getValue(name);
}
@Override
public synchronized String getComment(int commentType) {
String cmt = super.getComment(commentType);
@ -238,7 +183,7 @@ class PseudoDataComponent extends PseudoData {
if (component != null) {
return component.getDefaultSettings();
}
return dataType.getDefaultSettings();
return super.getDefaultSettings();
}
}

View file

@ -283,12 +283,4 @@ class DataComponent extends DataDB {
return super.getDefaultSettings();
}
@Override
protected Address getDataSettingsAddress() {
if (parent.getBaseDataType() instanceof Array) {
return parent.getDataSettingsAddress();
}
return address;
}
}

View file

@ -373,17 +373,22 @@ class DataDB extends CodeUnitDB implements Data {
return hasMutability(MutabilitySettingsDefinition.VOLATILE);
}
@Override
public boolean isChangeAllowed(SettingsDefinition settingsDefinition) {
refreshIfNeeded();
return dataMgr.isChangeAllowed(this, settingsDefinition);
}
@Override
public void clearSetting(String name) {
refreshIfNeeded();
Address cuAddr = getDataSettingsAddress();
dataMgr.clearSetting(cuAddr, name);
dataMgr.clearSetting(this, name);
}
@Override
public Long getLong(String name) {
refreshIfNeeded();
Long value = dataMgr.getLongSettingsValue(getDataSettingsAddress(), name);
Long value = dataMgr.getLongSettingsValue(this, name);
if (value == null) {
value = getDefaultSettings().getLong(name);
}
@ -393,13 +398,13 @@ class DataDB extends CodeUnitDB implements Data {
@Override
public String[] getNames() {
refreshIfNeeded();
return dataMgr.getInstanceSettingsNames(getDataSettingsAddress());
return dataMgr.getInstanceSettingsNames(this);
}
@Override
public String getString(String name) {
refreshIfNeeded();
String value = dataMgr.getStringSettingsValue(getDataSettingsAddress(), name);
String value = dataMgr.getStringSettingsValue(this, name);
if (value == null) {
value = getDefaultSettings().getString(name);
}
@ -409,7 +414,7 @@ class DataDB extends CodeUnitDB implements Data {
@Override
public Object getValue(String name) {
refreshIfNeeded();
Object value = dataMgr.getSettings(getDataSettingsAddress(), name);
Object value = dataMgr.getSettings(this, name);
if (value == null) {
value = getDefaultSettings().getValue(name);
}
@ -419,22 +424,19 @@ class DataDB extends CodeUnitDB implements Data {
@Override
public void setLong(String name, long value) {
refreshIfNeeded();
Address cuAddr = getDataSettingsAddress();
dataMgr.setLongSettingsValue(cuAddr, name, value);
dataMgr.setLongSettingsValue(this, name, value);
}
@Override
public void setString(String name, String value) {
refreshIfNeeded();
Address cuAddr = getDataSettingsAddress();
dataMgr.setStringSettingsValue(cuAddr, name, value);
dataMgr.setStringSettingsValue(this, name, value);
}
@Override
public void setValue(String name, Object value) {
refreshIfNeeded();
Address cuAddr = getDataSettingsAddress();
dataMgr.setSettings(cuAddr, name, value);
dataMgr.setSettings(this, name, value);
}
@Override
@ -758,14 +760,13 @@ class DataDB extends CodeUnitDB implements Data {
@Override
public void clearAllSettings() {
refreshIfNeeded();
Address cuAddr = getDataSettingsAddress();
dataMgr.clearAllSettings(cuAddr);
dataMgr.clearAllSettings(this);
}
@Override
public boolean isEmpty() {
refreshIfNeeded();
return dataMgr.isEmptySetting(getDataSettingsAddress());
return dataMgr.isEmptySetting(this);
}
@Override
@ -789,7 +790,4 @@ class DataDB extends CodeUnitDB implements Data {
return dataType.getDefaultSettings();
}
protected Address getDataSettingsAddress() {
return address;
}
}

View file

@ -18,8 +18,7 @@ package ghidra.program.database.data;
import java.io.IOException;
import db.DBRecord;
import ghidra.docking.settings.Settings;
import ghidra.docking.settings.SettingsImpl;
import ghidra.docking.settings.*;
import ghidra.program.model.data.*;
import ghidra.util.SystemUtilities;
import ghidra.util.exception.DuplicateNameException;
@ -433,6 +432,19 @@ class DataTypeComponentDB implements InternalDataTypeComponent {
dataMgr.dataTypeChanged(getParent(), false);
}
@Override
public boolean isChangeAllowed(SettingsDefinition settingsDefinition) {
if (settingsDefinition instanceof TypeDefSettingsDefinition) {
return false;
}
for (SettingsDefinition def : getDataType().getSettingsDefinitions()) {
if (def.equals(settingsDefinition)) {
return true;
}
}
return false;
}
@Override
public Long getLong(String name) {
SettingDB settingDB = dataMgr.getSetting(record.getKey(), name);

View file

@ -26,6 +26,8 @@ import db.*;
import db.util.ErrorHandler;
import generic.jar.ResourceFile;
import ghidra.app.plugin.core.datamgr.archive.BuiltInSourceArchive;
import ghidra.docking.settings.Settings;
import ghidra.docking.settings.SettingsDefinition;
import ghidra.framework.store.db.PackedDBHandle;
import ghidra.framework.store.db.PackedDatabase;
import ghidra.graph.*;
@ -63,8 +65,9 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
*
* Due to the frequent use of read-only mode for certain archives, read-only
* mode must always be allowed when opening older versions.
* - version 1 - legacy prior to overall DTM versioning (not stored)
* 12-Jan-2022 - version 2 - introduced DataTypeManager data map table and overall DTM version
* - version 1 - Legacy prior to overall DTM versioning (not stored)
* 12-Jan-2022 - version 2 - Introduced DataTypeManager data map table and overall DTM version.
* Also added typedef flags and auto-naming support.
*/
static final int DB_VERSION = 2;
@ -869,7 +872,7 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
return name;
}
public String getUniqueName(CategoryPath path1, CategoryPath path2, String baseName) {
String getUniqueName(CategoryPath path1, CategoryPath path2, String baseName) {
int pos = baseName.lastIndexOf('_');
int oneUpNumber = 0;
String name = baseName;
@ -893,6 +896,9 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
@Override
public Category getCategory(CategoryPath path) {
if (path == null) {
return null;
}
if (path.equals(CategoryPath.ROOT)) {
return root;
}
@ -2166,7 +2172,7 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
@Override
public DataType getDataType(CategoryPath path, String name) {
if (path.equals(DataType.DEFAULT.getCategoryPath()) &&
if (CategoryPath.ROOT.equals(path) &&
name.equals(DataType.DEFAULT.getName())) {
return DataType.DEFAULT;
}
@ -2279,16 +2285,13 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
private DataType getBuiltInDataType(long dataTypeID, DBRecord record) {
lock.acquire();
try {
Long key = dataTypeID;
DataType dt = builtInMap.get(key);
DataType dt = builtInMap.get(dataTypeID);
if (dt != null) {
return dt;
}
if (record == null) {
record = builtinAdapter.getRecord(dataTypeID);
if (record == null) {
return null;
}
@ -2301,7 +2304,6 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
String name = record.getString(BuiltinDBAdapter.BUILT_IN_NAME_COL);
try { // TODO: !! Can we look for alternate constructor which takes DTM argument
Class<?> c;
try {
c = Class.forName(classPath);
}
@ -2322,18 +2324,41 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
BuiltInDataType bdt = (BuiltInDataType) c.getDeclaredConstructor().newInstance();
bdt.setName(name);
bdt.setCategoryPath(catPath);
bdt = (BuiltInDataType) bdt.clone(this);
if (allowsDefaultBuiltInSettings() && bdt.getSettingsDefinitions().length != 0) {
bdt.setDefaultSettings(new DataTypeSettingsDB(this, bdt, dataTypeID));
final BuiltInDataType builtInDt = (BuiltInDataType) bdt.clone(this);
// check for prior instantiation with different id
Long id = builtIn2IdMap.get(builtInDt);
if (id != null) {
DataType datatype = builtInMap.get(id);
if (datatype != null) {
builtInMap.put(dataTypeID, datatype);
return datatype;
}
}
dt = bdt;
if (allowsDefaultBuiltInSettings() &&
builtInDt.getSettingsDefinitions().length != 0) {
DataTypeSettingsDB settings =
new DataTypeSettingsDB(this, builtInDt, dataTypeID);
if (builtInDt instanceof TypeDef) {
// Copy default immutable builtin typedef settings
Settings typedefSettings = builtInDt.getDefaultSettings();
for (String n : typedefSettings.getNames()) {
settings.setValue(n, typedefSettings.getValue(n));
}
}
settings.setAllowedSettingPredicate(n -> isBuiltInSettingAllowed(builtInDt, n));
builtInDt.setDefaultSettings(settings);
}
dt = builtInDt;
}
catch (Exception e) {
Msg.error(this, e);
dt = new MissingBuiltInDataType(catPath, name, classPath, this);
}
builtInMap.put(key, dt);
builtIn2IdMap.put(dt, key);
builtInMap.put(dataTypeID, dt);
builtIn2IdMap.put(dt, dataTypeID);
return dt;
}
catch (IOException e) {
@ -2345,6 +2370,18 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
return null;
}
private boolean isBuiltInSettingAllowed(BuiltInDataType bdt, String settingName) {
SettingsDefinition def = null;
for (SettingsDefinition sd : bdt.getSettingsDefinitions()) {
if (sd.getStorageKey().equals(settingName)) {
def = sd;
break;
}
}
// restrict to non-TypeDefSettingsDefinitions which are defined for the datatype
return def != null && !(def instanceof TypeDefSettingsDefinition);
}
private Enum getEnumDataType(long dataTypeID, DBRecord record) {
lock.acquire();
try {
@ -2526,6 +2563,10 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
int len = ptr.hasLanguageDependantLength() ? -1 : ptr.getLength();
newDataType = createPointer(ptr.getDataType(), cat, (byte) len, handler);
}
else if (dt instanceof BuiltInDataType) {
BuiltInDataType builtInDataType = (BuiltInDataType) dt;
newDataType = createBuiltIn(builtInDataType, cat);
}
else if (dt instanceof StructureInternal) {
StructureInternal structure = (StructureInternal) dt;
newDataType = createStructure(structure, name, cat, sourceArchiveIdValue,
@ -2550,10 +2591,6 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
newDataType = createFunctionDefinition(funDef, name, cat, sourceArchiveIdValue,
id.getValue());
}
else if (dt instanceof BuiltInDataType) {
BuiltInDataType builtInDataType = (BuiltInDataType) dt;
newDataType = createBuiltIn(builtInDataType, cat);
}
else if (dt instanceof MissingBuiltInDataType) {
MissingBuiltInDataType missingBuiltInDataType = (MissingBuiltInDataType) dt;
newDataType = createMissingBuiltIn(missingBuiltInDataType, cat);
@ -2621,7 +2658,13 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
throw new IllegalArgumentException("Data type must have a valid name");
}
DataType dataType = resolve(typedef.getDataType(), getDependencyConflictHandler());
DBRecord record = typedefAdapter.createRecord(getID(dataType), name, cat.getID(),
boolean isAutoNamed = typedef.isAutoNamed();
short flags = 0;
if (isAutoNamed) {
flags = (short) TypedefDBAdapter.TYPEDEF_FLAG_AUTONAME;
cat = getCategory(dataType.getCategoryPath()); // force category
}
DBRecord record = typedefAdapter.createRecord(getID(dataType), name, flags, cat.getID(),
sourceArchiveIdValue, universalIdValue, typedef.getLastChangeTime());
TypedefDB typedefDB = new TypedefDB(this, dtCache, typedefAdapter, record);
@ -2631,6 +2674,8 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
TypedefDataType.copyTypeDefSettings(typedef, typedefDB, false);
settings.setLock(wasLocked);
typedefDB.updateAutoName(false);
dataType.addParent(typedefDB);
return typedefDB;
}
@ -3047,8 +3092,9 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
* @param oldCatId the old category's record id
*/
void dataTypeCategoryPathChanged(DataTypeDB dt, CategoryPath oldPath, long oldCatId) {
if (!(dt instanceof Array) && !(dt instanceof Pointer)) {
try {
try {
if (!(dt instanceof Array) && !(dt instanceof Pointer)) {
for (Field arrayId : arrayAdapter.getRecordIdsInCategory(oldCatId)) {
long id = arrayId.getLongValue();
DBRecord rec = arrayAdapter.getRecord(id);
@ -3062,10 +3108,18 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
ptr.updatePath(dt);
}
}
catch (IOException e) {
dbError(e);
// only affects those with auto-naming which must follow category change
for (Field ptrId : typedefAdapter.getRecordIdsInCategory(oldCatId)) {
long id = ptrId.getLongValue();
DBRecord rec = typedefAdapter.getRecord(id);
TypedefDB td = (TypedefDB) getDataType(id, rec);
td.updatePath(dt);
}
}
catch (IOException e) {
dbError(e);
}
dataTypeMoved(dt, new DataTypePath(oldPath, dt.getName()), dt.getDataTypePath());
}
@ -3341,7 +3395,12 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
return creatingDataType != 0;
}
@Override
/**
* Notification when data type is changed.
* @param dt data type that is changed
* @param isAutoChange true if change was an automatic change in response to
* another datatype's change (e.g., size, alignment).
*/
public void dataTypeChanged(DataType dt, boolean isAutoChange) {
if (dt instanceof Enum) {
enumValueMap = null;
@ -3353,6 +3412,22 @@ abstract public class DataTypeManagerDB implements DataTypeManager {
defaultListener.dataTypeChanged(this, dt.getDataTypePath());
}
/**
* Notification when data type settings have changed.
* @param dt data type that is changed
*/
public void dataTypeSettingsChanged(DataType dt) {
if (dt instanceof TypedefDB) {
TypedefDB td = (TypedefDB) dt;
td.updateAutoName(true);
if (creatingDataType == 0) {
td.setLastChangeTime(System.currentTimeMillis());
setDirtyFlag(dt);
}
}
defaultListener.dataTypeChanged(this, dt.getDataTypePath());
}
protected void dataTypeAdded(DataType newDt, DataType originalDataType) {
CategoryDB category = (CategoryDB) getCategory(newDt.getCategoryPath());
category.dataTypeAdded(newDt);

View file

@ -17,8 +17,7 @@ package ghidra.program.database.data;
import com.google.common.base.Predicate;
import ghidra.docking.settings.Settings;
import ghidra.docking.settings.SettingsImpl;
import ghidra.docking.settings.*;
import ghidra.program.model.data.*;
import ghidra.util.Msg;
@ -78,6 +77,18 @@ class DataTypeSettingsDB implements Settings {
return wasLocked;
}
@Override
public boolean isChangeAllowed(SettingsDefinition settingsDefinition) {
if (locked) {
return false;
}
if (allowedSettingPredicate != null &&
!allowedSettingPredicate.apply(settingsDefinition.getStorageKey())) {
return false;
}
return true;
}
/**
* Set predicate for settings modification
* @param allowedSettingPredicate callback for checking an allowed setting modification
@ -107,7 +118,8 @@ class DataTypeSettingsDB implements Settings {
nameStr);
return false;
}
if (allowedSettingPredicate != null && !allowedSettingPredicate.apply(name)) {
if (name != null && allowedSettingPredicate != null &&
!allowedSettingPredicate.apply(name)) {
Msg.warn(this, "Ignored disallowed setting '" + name + "'");
return false;
}
@ -118,7 +130,7 @@ class DataTypeSettingsDB implements Settings {
// NOTE: Merge currently only supports TypeDefDB default settings changes which correspond
// to TypeDefSettingsDefinition established by the base datatype
// and does not consider DataTypeComponent default settings changes or other setting types.
dataMgr.dataTypeChanged(dataType, false);
dataMgr.dataTypeSettingsChanged(dataType);
}
@Override

View file

@ -52,8 +52,8 @@ public class PointerTypedefInspector {
* its default settings.
* @param pointerTypeDef Pointer TypeDef
* @param addrFactory target address factory
* @return referenced address space or null if not applicable
* or the space setting is not defined within the addrFactory.
* @return referenced address space or null if not specified or address space
* lookup fails.
*/
public static AddressSpace getPointerAddressSpace(TypeDef pointerTypeDef,
AddressFactory addrFactory) {

View file

@ -20,11 +20,14 @@ import java.util.List;
import db.*;
import db.util.ErrorHandler;
import ghidra.docking.settings.SettingsDefinition;
import ghidra.program.database.map.AddressMap;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.KeyRange;
import ghidra.program.model.data.ProgramBasedDataTypeManager;
import ghidra.program.model.data.*;
import ghidra.program.model.listing.Data;
import ghidra.util.Lock;
import ghidra.util.Msg;
import ghidra.util.exception.CancelledException;
import ghidra.util.exception.VersionException;
import ghidra.util.task.TaskMonitor;
@ -91,22 +94,36 @@ public abstract class ProgramBasedDataTypeManagerDB extends DataTypeManagerDB
abstract protected void dataSettingChanged(Address address);
@Override
public boolean setLongSettingsValue(Address dataAddr, String name, long value) {
return updateInstanceSettings(dataAddr, name, null, value);
public boolean isChangeAllowed(Data data,
SettingsDefinition settingsDefinition) {
if (settingsDefinition instanceof TypeDefSettingsDefinition) {
return false;
}
for (SettingsDefinition def : data.getDataType().getSettingsDefinitions()) {
if (def.equals(settingsDefinition)) {
return true;
}
}
return false;
}
@Override
public boolean setStringSettingsValue(Address dataAddr, String name, String value) {
return updateInstanceSettings(dataAddr, name, value, -1);
public boolean setLongSettingsValue(Data data, String name, long value) {
return updateInstanceSettings(data, name, null, value);
}
@Override
public boolean setSettings(Address dataAddr, String name, Object value) {
public boolean setStringSettingsValue(Data data, String name, String value) {
return updateInstanceSettings(data, name, value, -1);
}
@Override
public boolean setSettings(Data data, String name, Object value) {
if (value instanceof String) {
return updateInstanceSettings(dataAddr, name, (String) value, -1);
return updateInstanceSettings(data, name, (String) value, -1);
}
else if (isAllowedNumberType(value)) {
return updateInstanceSettings(dataAddr, name, null, ((Number) value).longValue());
return updateInstanceSettings(data, name, null, ((Number) value).longValue());
}
throw new IllegalArgumentException(
"Unsupportd Settings Value: " + (value == null ? "null" : value.getClass().getName()));
@ -129,8 +146,8 @@ public abstract class ProgramBasedDataTypeManagerDB extends DataTypeManagerDB
}
@Override
public Long getLongSettingsValue(Address dataAddr, String name) {
SettingDB settings = getSettingDB(dataAddr, name);
public Long getLongSettingsValue(Data data, String name) {
SettingDB settings = getSettingDB(data, name);
if (settings != null) {
return settings.getLongValue();
}
@ -138,8 +155,8 @@ public abstract class ProgramBasedDataTypeManagerDB extends DataTypeManagerDB
}
@Override
public String getStringSettingsValue(Address dataAddr, String name) {
SettingDB settings = getSettingDB(dataAddr, name);
public String getStringSettingsValue(Data data, String name) {
SettingDB settings = getSettingDB(data, name);
if (settings != null) {
return settings.getStringValue();
}
@ -147,21 +164,22 @@ public abstract class ProgramBasedDataTypeManagerDB extends DataTypeManagerDB
}
@Override
public Object getSettings(Address dataAddr, String name) {
Object obj = getStringSettingsValue(dataAddr, name);
public Object getSettings(Data data, String name) {
Object obj = getStringSettingsValue(data, name);
if (obj != null) {
return obj;
}
return getLongSettingsValue(dataAddr, name);
return getLongSettingsValue(data, name);
}
@Override
public boolean clearSetting(Address dataAddr, String name) {
public boolean clearSetting(Data data, String name) {
if (instanceSettingsAdapter == null) {
throw new UnsupportedOperationException();
}
lock.acquire();
try {
Address dataAddr = getDataSettingsAddress(data);
instanceSettingsCache.remove(dataAddr, name);
long addr = addrMap.getKey(dataAddr, false);
if (instanceSettingsAdapter.removeSettingsRecord(addr, name)) {
@ -180,7 +198,7 @@ public abstract class ProgramBasedDataTypeManagerDB extends DataTypeManagerDB
}
@Override
public void clearAllSettings(Address dataAddr) {
public void clearAllSettings(Data data) {
if (instanceSettingsAdapter == null) {
throw new UnsupportedOperationException();
}
@ -188,6 +206,7 @@ public abstract class ProgramBasedDataTypeManagerDB extends DataTypeManagerDB
try {
instanceSettingsCache.clear();
boolean changed = false;
Address dataAddr = getDataSettingsAddress(data);
Field[] keys = instanceSettingsAdapter.getSettingsKeys(addrMap.getKey(dataAddr, false));
for (Field key : keys) {
instanceSettingsAdapter.removeSettingsRecord(key.getLongValue());
@ -267,12 +286,13 @@ public abstract class ProgramBasedDataTypeManagerDB extends DataTypeManagerDB
}
@Override
public String[] getInstanceSettingsNames(Address dataAddr) {
public String[] getInstanceSettingsNames(Data data) {
if (instanceSettingsAdapter == null) {
throw new UnsupportedOperationException();
}
lock.acquire();
try {
Address dataAddr = getDataSettingsAddress(data);
return instanceSettingsAdapter.getSettingsNames(addrMap.getKey(dataAddr, false));
}
catch (IOException e) {
@ -285,11 +305,12 @@ public abstract class ProgramBasedDataTypeManagerDB extends DataTypeManagerDB
}
@Override
public boolean isEmptySetting(Address dataAddr) {
public boolean isEmptySetting(Data data) {
if (instanceSettingsAdapter == null) {
throw new UnsupportedOperationException();
}
try {
Address dataAddr = getDataSettingsAddress(data);
return instanceSettingsAdapter
.getSettingsKeys(addrMap.getKey(dataAddr, false)).length == 0;
}
@ -299,7 +320,7 @@ public abstract class ProgramBasedDataTypeManagerDB extends DataTypeManagerDB
return true;
}
private boolean updateInstanceSettings(Address dataAddr, String name, String strValue,
private boolean updateInstanceSettings(Data data, String name, String strValue,
long longValue) {
boolean wasChanged = false;
@ -309,6 +330,10 @@ public abstract class ProgramBasedDataTypeManagerDB extends DataTypeManagerDB
if (instanceSettingsAdapter == null) {
throw new UnsupportedOperationException();
}
if (!checkSetting(data, name)) {
return false;
}
Address dataAddr = getDataSettingsAddress(data);
long addrKey = addrMap.getKey(dataAddr, true);
DBRecord rec =
instanceSettingsAdapter.updateSettingsRecord(addrKey, name, strValue, longValue);
@ -330,12 +355,31 @@ public abstract class ProgramBasedDataTypeManagerDB extends DataTypeManagerDB
return wasChanged;
}
private SettingDB getSettingDB(Address dataAddr, String name) {
private boolean checkSetting(Data data, String name) {
SettingsDefinition settingsDefinition = null;
for (SettingsDefinition def : data.getDataType().getSettingsDefinitions()) {
if (def.getStorageKey().equals(name)) {
settingsDefinition = def;
break;
}
}
if (settingsDefinition == null) {
Msg.warn(this, "Ignored unrecognized setting '" + name + "'");
return false;
}
if (settingsDefinition instanceof TypeDefSettingsDefinition) {
Msg.warn(this, "Ignored disallowed instance setting '" + name + "'");
}
return true;
}
private SettingDB getSettingDB(Data data, String name) {
lock.acquire();
try {
if (instanceSettingsAdapter == null) {
throw new UnsupportedOperationException();
}
Address dataAddr = getDataSettingsAddress(data);
SettingDB settings = instanceSettingsCache.get(dataAddr, name);
if (settings != null) {
return settings;
@ -380,4 +424,15 @@ public abstract class ProgramBasedDataTypeManagerDB extends DataTypeManagerDB
lock.release();
}
}
private static Address getDataSettingsAddress(Data data) {
Data parent = data.getParent();
if (parent != null) {
DataType dataType = parent.getDataType();
if (dataType instanceof Array) {
return getDataSettingsAddress(parent);
}
}
return data.getAddress();
}
}

View file

@ -55,8 +55,8 @@ class SettingsDBAdapterV1 extends SettingsDBAdapter {
private Table settingsTable;
private Table settingsNameTable;
private HashMap<Short, String> nameIndexMap = new HashMap<>();
private HashMap<String, Short> nameStringMap = new HashMap<>();
private HashMap<Short, String> nameIndexMap;
private HashMap<String, Short> nameStringMap;
SettingsDBAdapterV1(String tableName, DBHandle handle, boolean create)
throws VersionException, IOException {

View file

@ -24,6 +24,7 @@ import ghidra.program.database.DBObjectCache;
import ghidra.program.model.data.*;
import ghidra.program.model.mem.MemBuffer;
import ghidra.util.UniversalID;
import ghidra.util.exception.DuplicateNameException;
/**
* Database implementation for a Typedef data type.
@ -49,6 +50,73 @@ class TypedefDB extends DataTypeDB implements TypeDef {
this.defaultSettings = null; // ensure lazy initialization
}
private void setFlags(int flags) {
record.setShortValue(TypedefDBAdapter.TYPEDEF_FLAGS_COL, (short) flags);
}
private int getFlags() {
return record.getShortValue(TypedefDBAdapter.TYPEDEF_FLAGS_COL);
}
@Override
public void enableAutoNaming() {
if (isAutoNamed()) {
return;
}
lock.acquire();
try {
checkDeleted();
String oldName = getName();
setFlags(getFlags() | TypedefDBAdapter.TYPEDEF_FLAG_AUTONAME);
adapter.updateRecord(record, true);
// auto-named typedef follows category of associated datatype
CategoryPath oldPath = getCategoryPath();
CategoryPath currentPath = getDataType().getCategoryPath();
String newName = generateTypedefName(currentPath);
record.setString(TypedefDBAdapter.TYPEDEF_NAME_COL, newName);
adapter.updateRecord(record, true);
refreshName();
if (!currentPath.equals(oldPath)) {
// update category for typedef
try {
super.setCategoryPath(currentPath);
}
catch (DuplicateNameException e) {
// should not happen
}
}
notifyNameChanged(oldName);
}
catch (IOException e) {
dataMgr.dbError(e);
}
finally {
lock.release();
}
}
@Override
public boolean isAutoNamed() {
int flags = getFlags();
if (isInvalid()) {
lock.acquire();
try {
checkIsValid();
flags = getFlags();
}
finally {
lock.release();
}
}
return (flags & TypedefDBAdapter.TYPEDEF_FLAG_AUTONAME) != 0;
}
@Override
protected long doGetCategoryID() {
return record.getLongValue(TypedefDBAdapter.TYPEDEF_CAT_COL);
@ -67,6 +135,7 @@ class TypedefDB extends DataTypeDB implements TypeDef {
@Override
protected void doSetNameRecord(String name) throws IOException {
record.setString(TypedefDBAdapter.TYPEDEF_NAME_COL, name);
setFlags(getFlags() & ~TypedefDBAdapter.TYPEDEF_FLAG_AUTONAME); // clear auto-name flag if name is set
adapter.updateRecord(record, true);
}
@ -165,19 +234,13 @@ class TypedefDB extends DataTypeDB implements TypeDef {
}
@Override
public DataType clone(DataTypeManager dtm) {
TypedefDataType typeDef =
new TypedefDataType(getCategoryPath(), getName(), getDataType(), getUniversalID(),
getSourceArchive(), getLastChangeTime(), getLastChangeTimeInSourceArchive(), dtm);
TypedefDataType.copyTypeDefSettings(this, typeDef, false);
return typeDef;
public TypeDef clone(DataTypeManager dtm) {
return TypedefDataType.clone(this, dtm);
}
@Override
public DataType copy(DataTypeManager dtm) {
TypedefDataType typeDef = new TypedefDataType(getCategoryPath(), getName(), getDataType(), dtm);
TypedefDataType.copyTypeDefSettings(this, typeDef, false);
return typeDef;
public TypedefDataType copy(DataTypeManager dtm) {
return TypedefDataType.copy(this, dtm);
}
@Override
@ -190,7 +253,12 @@ class TypedefDB extends DataTypeDB implements TypeDef {
}
TypeDef td = (TypeDef) obj;
validate(lock);
if (!DataTypeUtilities.equalsIgnoreConflict(getName(), td.getName())) {
boolean autoNamed = isAutoNamed();
if (autoNamed != td.isAutoNamed()) {
return false;
}
if (!autoNamed && !DataTypeUtilities.equalsIgnoreConflict(getName(), td.getName())) {
return false;
}
if (!hasSameTypeDefSettings(td)) {
@ -199,6 +267,13 @@ class TypedefDB extends DataTypeDB implements TypeDef {
return DataTypeUtilities.isSameOrEquivalentDataType(getDataType(), td.getDataType());
}
public void setCategoryPath(CategoryPath path) throws DuplicateNameException {
if (isAutoNamed()) {
return; // ignore category change if auto-naming enabled
}
super.setCategoryPath(path);
}
@Override
protected void doSetCategoryPathRecord(long categoryID) throws IOException {
record.setLongValue(TypedefDBAdapter.TYPEDEF_CAT_COL, categoryID);
@ -251,7 +326,9 @@ class TypedefDB extends DataTypeDB implements TypeDef {
@Override
public void dataTypeNameChanged(DataType dt, String oldName) {
// ignore
if (getDataType() == dt) {
updateAutoName(true);
}
}
@Override
@ -330,6 +407,9 @@ class TypedefDB extends DataTypeDB implements TypeDef {
@Override
public String toString() {
if (isAutoNamed()) {
return getName();
}
return "typedef " + this.getName() + " " + getDataType().getName();
}
@ -440,10 +520,92 @@ class TypedefDB extends DataTypeDB implements TypeDef {
TypeDef td = (TypeDef) dataType;
dataTypeReplaced(getDataType(), td.getDataType());
TypedefDataType.copyTypeDefSettings(td, this, true);
// NOTE: as with the name, auto-name setting is left unchanged
}
finally {
lock.release();
}
}
@Override
protected void updatePath(DataTypeDB dt) {
if (isAutoNamed() && dt == getDataType()) {
// auto-named typedef follows category of associated datatype
CategoryPath oldPath = getCategoryPath();
CategoryPath currentPath = dt.getCategoryPath();
if (!currentPath.equals(oldPath)) {
try {
boolean nameChanged = false;
String oldName = getName();
String newName = generateTypedefName(currentPath);
if (!newName.equals(oldName)) {
nameChanged = true;
record.setString(TypedefDBAdapter.TYPEDEF_NAME_COL, newName);
refreshName();
}
super.setCategoryPath(currentPath);
if (nameChanged) {
notifyNameChanged(oldName);
}
}
catch (DuplicateNameException e) {
// should not happen
}
}
}
}
private String generateTypedefName(CategoryPath path) {
String newName = TypedefDataType.generateTypedefName(this);
DataType dt = dataMgr.getDataType(path, newName);
if (dt == null || dt == this) {
return newName;
}
String baseName = newName + DataType.CONFLICT_SUFFIX;
newName = baseName;
int count = 0;
while (true) {
dt = dataMgr.getDataType(path, newName);
if (dt == null || dt == this) {
break;
}
count++;
newName = baseName + count;
}
return newName;
}
boolean updateAutoName(boolean notify) {
lock.acquire();
try {
checkIsValid();
if (!isAutoNamed()) {
return false;
}
String oldName = getName();
String newName = generateTypedefName(getCategoryPath());
if (oldName.equals(newName)) {
return false;
}
record.setString(TypedefDBAdapter.TYPEDEF_NAME_COL, newName);
adapter.updateRecord(record, false);
refreshName();
if (notify) {
notifyNameChanged(oldName);
}
}
catch (IOException e) {
dataMgr.dbError(e);
}
finally {
lock.release();
}
return true;
}
}

View file

@ -28,19 +28,23 @@ import ghidra.util.task.TaskMonitor;
abstract class TypedefDBAdapter {
static final String TYPEDEF_TABLE_NAME = "Typedefs";
static final Schema SCHEMA = TypedefDBAdapterV1.V1_SCHEMA;
static final Schema SCHEMA = TypedefDBAdapterV2.V2_SCHEMA;
static final int TYPEDEF_DT_ID_COL = TypedefDBAdapterV1.V1_TYPEDEF_DT_ID_COL;
static final int TYPEDEF_NAME_COL = TypedefDBAdapterV1.V1_TYPEDEF_NAME_COL;
static final int TYPEDEF_CAT_COL = TypedefDBAdapterV1.V1_TYPEDEF_CAT_COL;
static final int TYPEDEF_DT_ID_COL = TypedefDBAdapterV2.V2_TYPEDEF_DT_ID_COL;
static final int TYPEDEF_FLAGS_COL = TypedefDBAdapterV2.V2_TYPEDEF_FLAGS_COL;
static final int TYPEDEF_NAME_COL = TypedefDBAdapterV2.V2_TYPEDEF_NAME_COL;
static final int TYPEDEF_CAT_COL = TypedefDBAdapterV2.V2_TYPEDEF_CAT_COL;
static final int TYPEDEF_SOURCE_ARCHIVE_ID_COL =
TypedefDBAdapterV1.V1_TYPEDEF_SOURCE_ARCHIVE_ID_COL;
TypedefDBAdapterV2.V2_TYPEDEF_SOURCE_ARCHIVE_ID_COL;
static final int TYPEDEF_UNIVERSAL_DT_ID_COL =
TypedefDBAdapterV1.V1_TYPEDEF_UNIVERSAL_DT_ID_COL;
TypedefDBAdapterV2.V2_TYPEDEF_UNIVERSAL_DT_ID_COL;
static final int TYPEDEF_SOURCE_SYNC_TIME_COL =
TypedefDBAdapterV1.V1_TYPEDEF_SOURCE_SYNC_TIME_COL;
TypedefDBAdapterV2.V2_TYPEDEF_SOURCE_SYNC_TIME_COL;
static final int TYPEDEF_LAST_CHANGE_TIME_COL =
TypedefDBAdapterV1.V1_TYPEDEF_LAST_CHANGE_TIME_COL;
TypedefDBAdapterV2.V2_TYPEDEF_LAST_CHANGE_TIME_COL;
// Typedef flags bits
static final int TYPEDEF_FLAG_AUTONAME = 0x1;
/**
* Gets an adapter for working with the Typedef data type database table. The adapter is based
@ -55,7 +59,7 @@ abstract class TypedefDBAdapter {
static TypedefDBAdapter getAdapter(DBHandle handle, int openMode, TaskMonitor monitor)
throws VersionException, IOException {
try {
return new TypedefDBAdapterV1(handle, openMode == DBConstants.CREATE);
return new TypedefDBAdapterV2(handle, openMode == DBConstants.CREATE);
}
catch (VersionException e) {
if (!e.isUpgradable() || openMode == DBConstants.UPDATE) {
@ -76,6 +80,12 @@ abstract class TypedefDBAdapter {
* @throws VersionException if a read only adapter can't be obtained for the database handle's version.
*/
static TypedefDBAdapter findReadOnlyAdapter(DBHandle handle) throws VersionException {
try {
return new TypedefDBAdapterV1(handle);
}
catch (VersionException e) {
// ignore
}
return new TypedefDBAdapterV0(handle);
}
@ -95,14 +105,14 @@ abstract class TypedefDBAdapter {
long id = tmpHandle.startTransaction();
TypedefDBAdapter tmpAdapter = null;
try {
tmpAdapter = new TypedefDBAdapterV1(tmpHandle, true);
tmpAdapter = new TypedefDBAdapterV2(tmpHandle, true);
RecordIterator it = oldAdapter.getRecords();
while (it.hasNext()) {
DBRecord rec = it.next();
tmpAdapter.updateRecord(rec, false);
}
oldAdapter.deleteTable(handle);
TypedefDBAdapter newAdapter = new TypedefDBAdapterV1(handle, true);
TypedefDBAdapter newAdapter = new TypedefDBAdapterV2(handle, true);
it = tmpAdapter.getRecords();
while (it.hasNext()) {
DBRecord rec = it.next();
@ -120,6 +130,7 @@ abstract class TypedefDBAdapter {
* Creates a database record for a type definition data type.
* @param dataTypeID the ID of the data type that is referred to by this type definition.
* @param name the unique name for this data type
* @param flags typedef flags (e.g., auto-name flag bit).
* @param categoryID the ID for the category that contains this data type.
* @param sourceArchiveID the ID for the source archive where this data type originated.
* @param sourceDataTypeID the ID of the associated data type in the source archive.
@ -127,7 +138,7 @@ abstract class TypedefDBAdapter {
* @return the database record for this data type.
* @throws IOException if the database can't be accessed.
*/
abstract DBRecord createRecord(long dataTypeID, String name, long categoryID,
abstract DBRecord createRecord(long dataTypeID, String name, short flags, long categoryID,
long sourceArchiveID, long sourceDataTypeID, long lastChangeTime) throws IOException;
/**

View file

@ -68,10 +68,9 @@ class TypedefDBAdapterV0 extends TypedefDBAdapter implements RecordTranslator {
}
@Override
public DBRecord createRecord(long dataTypeID, String name, long categoryID, long sourceArchiveID,
long sourceDataTypeID, long lastChangeTime) throws IOException {
throw new UnsupportedOperationException("Not allowed to update prior version #" + VERSION +
" of " + TYPEDEF_TABLE_NAME + " table.");
public DBRecord createRecord(long dataTypeID, String name, short flags, long categoryID,
long sourceArchiveID, long sourceDataTypeID, long lastChangeTime) throws IOException {
throw new UnsupportedOperationException();
}
@Override
@ -91,7 +90,7 @@ class TypedefDBAdapterV0 extends TypedefDBAdapter implements RecordTranslator {
@Override
public boolean removeRecord(long dataID) throws IOException {
return table.deleteRecord(dataID);
throw new UnsupportedOperationException();
}
@Override
@ -111,6 +110,7 @@ class TypedefDBAdapterV0 extends TypedefDBAdapter implements RecordTranslator {
}
DBRecord rec = TypedefDBAdapter.SCHEMA.createRecord(oldRec.getKey());
rec.setLongValue(TYPEDEF_DT_ID_COL, oldRec.getLongValue(V0_TYPEDEF_DT_ID_COL));
// default TYPEDEF_FLAGS_COL to 0
rec.setString(TYPEDEF_NAME_COL, oldRec.getString(V0_TYPEDEF_NAME_COL));
rec.setLongValue(TYPEDEF_CAT_COL, oldRec.getLongValue(V0_TYPEDEF_CAT_COL));
rec.setLongValue(TYPEDEF_SOURCE_ARCHIVE_ID_COL, DataTypeManager.LOCAL_ARCHIVE_KEY);

View file

@ -16,7 +16,6 @@
package ghidra.program.database.data;
import java.io.IOException;
import java.util.Date;
import db.*;
import ghidra.util.UniversalID;
@ -25,7 +24,7 @@ import ghidra.util.exception.VersionException;
/**
* Version 1 implementation for accessing the Typedef database table.
*/
class TypedefDBAdapterV1 extends TypedefDBAdapter {
class TypedefDBAdapterV1 extends TypedefDBAdapter implements RecordTranslator {
static final int VERSION = 1;
static final int V1_TYPEDEF_DT_ID_COL = 0;
static final int V1_TYPEDEF_NAME_COL = 1;
@ -34,41 +33,35 @@ class TypedefDBAdapterV1 extends TypedefDBAdapter {
static final int V1_TYPEDEF_UNIVERSAL_DT_ID_COL = 4;
static final int V1_TYPEDEF_SOURCE_SYNC_TIME_COL = 5;
static final int V1_TYPEDEF_LAST_CHANGE_TIME_COL = 6;
static final Schema V1_SCHEMA = new Schema(VERSION, "Typedef ID",
new Field[] { LongField.INSTANCE, StringField.INSTANCE, LongField.INSTANCE,
LongField.INSTANCE, LongField.INSTANCE, LongField.INSTANCE, LongField.INSTANCE },
new String[] { "Data Type ID", "Name", "Category ID", "Source Archive ID",
"Universal Data Type ID", "Source Sync Time", "Last Change Time" });
// DO NOT REMOVE WHAT'S BELOW - this documents the schema used in version 0.
// static final Schema V1_SCHEMA = new Schema(VERSION, "Typedef ID",
// new Field[] { LongField.INSTANCE, StringField.INSTANCE, LongField.INSTANCE,
// LongField.INSTANCE, LongField.INSTANCE, LongField.INSTANCE, LongField.INSTANCE },
// new String[] { "Data Type ID", "Name", "Category ID", "Source Archive ID",
// "Universal Data Type ID", "Source Sync Time", "Last Change Time" });
private Table table;
/**
* Gets a version 1 adapter for the Typedef database table.
* @param handle handle to the database containing the table.
* @param create true if this constructor should create the table.
* @throws VersionException if the the table's version does not match the expected version
* for this adapter.
*/
public TypedefDBAdapterV1(DBHandle handle, boolean create)
throws VersionException, IOException {
public TypedefDBAdapterV1(DBHandle handle) throws VersionException {
if (create) {
table = handle.createTable(TYPEDEF_TABLE_NAME, V1_SCHEMA,
new int[] { V1_TYPEDEF_CAT_COL, V1_TYPEDEF_UNIVERSAL_DT_ID_COL });
table = handle.getTable(TYPEDEF_TABLE_NAME);
if (table == null) {
throw new VersionException("Missing Table: " + TYPEDEF_TABLE_NAME);
}
else {
table = handle.getTable(TYPEDEF_TABLE_NAME);
if (table == null) {
throw new VersionException("Missing Table: " + TYPEDEF_TABLE_NAME);
}
int version = table.getSchema().getVersion();
if (version != VERSION) {
String msg = "Expected version " + VERSION + " for table " + TYPEDEF_TABLE_NAME +
" but got " + table.getSchema().getVersion();
if (version < VERSION) {
throw new VersionException(msg, VersionException.OLDER_VERSION, true);
}
throw new VersionException(msg, VersionException.NEWER_VERSION, false);
int version = table.getSchema().getVersion();
if (version != VERSION) {
String msg = "Expected version " + VERSION + " for table " + TYPEDEF_TABLE_NAME +
" but got " + table.getSchema().getVersion();
if (version < VERSION) {
throw new VersionException(msg, VersionException.OLDER_VERSION, true);
}
throw new VersionException(msg, VersionException.NEWER_VERSION, false);
}
}
@ -78,49 +71,29 @@ class TypedefDBAdapterV1 extends TypedefDBAdapter {
}
@Override
public DBRecord createRecord(long dataTypeID, String name, long categoryID, long sourceArchiveID,
long sourceDataTypeID, long lastChangeTime) throws IOException {
long tableKey = table.getKey();
// if (tableKey <= DataManager.VOID_DATATYPE_ID) {
// tableKey = DataManager.VOID_DATATYPE_ID +1;
// }
long key = DataTypeManagerDB.createKey(DataTypeManagerDB.TYPEDEF, tableKey);
DBRecord record = V1_SCHEMA.createRecord(key);
record.setLongValue(V1_TYPEDEF_DT_ID_COL, dataTypeID);
record.setString(V1_TYPEDEF_NAME_COL, name);
record.setLongValue(V1_TYPEDEF_CAT_COL, categoryID);
record.setLongValue(V1_TYPEDEF_SOURCE_ARCHIVE_ID_COL, sourceArchiveID);
record.setLongValue(V1_TYPEDEF_UNIVERSAL_DT_ID_COL, sourceDataTypeID);
record.setLongValue(V1_TYPEDEF_SOURCE_SYNC_TIME_COL, lastChangeTime);
record.setLongValue(V1_TYPEDEF_LAST_CHANGE_TIME_COL, lastChangeTime);
table.putRecord(record);
return record;
public DBRecord createRecord(long dataTypeID, String name, short flags, long categoryID,
long sourceArchiveID, long sourceDataTypeID, long lastChangeTime) throws IOException {
throw new UnsupportedOperationException();
}
@Override
public DBRecord getRecord(long typedefID) throws IOException {
return table.getRecord(typedefID);
return translateRecord(table.getRecord(typedefID));
}
@Override
public RecordIterator getRecords() throws IOException {
return table.iterator();
RecordIterator getRecords() throws IOException {
return new TranslatedRecordIterator(table.iterator(), this);
}
@Override
public void updateRecord(DBRecord record, boolean setLastChangeTime) throws IOException {
if (setLastChangeTime) {
record.setLongValue(TypedefDBAdapter.TYPEDEF_LAST_CHANGE_TIME_COL,
(new Date()).getTime());
}
table.putRecord(record);
throw new UnsupportedOperationException();
}
@Override
public boolean removeRecord(long dataID) throws IOException {
return table.deleteRecord(dataID);
throw new UnsupportedOperationException();
}
@Override
@ -137,14 +110,33 @@ class TypedefDBAdapterV1 extends TypedefDBAdapter {
DBRecord getRecordWithIDs(UniversalID sourceID, UniversalID datatypeID) throws IOException {
Field[] keys =
table.findRecords(new LongField(datatypeID.getValue()), V1_TYPEDEF_UNIVERSAL_DT_ID_COL);
for (int i = 0; i < keys.length; i++) {
DBRecord record = table.getRecord(keys[i]);
if (record.getLongValue(V1_TYPEDEF_SOURCE_ARCHIVE_ID_COL) == sourceID.getValue()) {
return record;
return translateRecord(record);
}
}
return null;
}
@Override
public DBRecord translateRecord(DBRecord oldRec) {
if (oldRec == null) {
return null;
}
DBRecord rec = TypedefDBAdapter.SCHEMA.createRecord(oldRec.getKey());
rec.setLongValue(TYPEDEF_DT_ID_COL, oldRec.getLongValue(V1_TYPEDEF_DT_ID_COL));
// default TYPEDEF_FLAGS_COL to 0
rec.setString(TYPEDEF_NAME_COL, oldRec.getString(V1_TYPEDEF_NAME_COL));
rec.setLongValue(TYPEDEF_CAT_COL, oldRec.getLongValue(V1_TYPEDEF_CAT_COL));
rec.setLongValue(TYPEDEF_SOURCE_ARCHIVE_ID_COL,
oldRec.getLongValue(V1_TYPEDEF_SOURCE_ARCHIVE_ID_COL));
rec.setLongValue(TYPEDEF_UNIVERSAL_DT_ID_COL,
oldRec.getLongValue(V1_TYPEDEF_UNIVERSAL_DT_ID_COL));
rec.setLongValue(TYPEDEF_SOURCE_SYNC_TIME_COL,
oldRec.getLongValue(V1_TYPEDEF_SOURCE_SYNC_TIME_COL));
rec.setLongValue(TYPEDEF_LAST_CHANGE_TIME_COL,
oldRec.getLongValue(V1_TYPEDEF_LAST_CHANGE_TIME_COL));
return rec;
}
}

View file

@ -0,0 +1,154 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.program.database.data;
import java.io.IOException;
import java.util.Date;
import db.*;
import ghidra.util.UniversalID;
import ghidra.util.exception.VersionException;
/**
* Version 2 implementation for accessing the Typedef database table.
*/
class TypedefDBAdapterV2 extends TypedefDBAdapter {
static final int VERSION = 2;
static final int V2_TYPEDEF_DT_ID_COL = 0;
static final int V2_TYPEDEF_FLAGS_COL = 1;
static final int V2_TYPEDEF_NAME_COL = 2;
static final int V2_TYPEDEF_CAT_COL = 3;
static final int V2_TYPEDEF_SOURCE_ARCHIVE_ID_COL = 4;
static final int V2_TYPEDEF_UNIVERSAL_DT_ID_COL = 5;
static final int V2_TYPEDEF_SOURCE_SYNC_TIME_COL = 6;
static final int V2_TYPEDEF_LAST_CHANGE_TIME_COL = 7;
static final Schema V2_SCHEMA = new Schema(VERSION, "Typedef ID",
new Field[] { LongField.INSTANCE, ShortField.INSTANCE, StringField.INSTANCE,
LongField.INSTANCE, LongField.INSTANCE, LongField.INSTANCE, LongField.INSTANCE,
LongField.INSTANCE },
new String[] { "Data Type ID", "Flags", "Name", "Category ID", "Source Archive ID",
"Universal Data Type ID", "Source Sync Time", "Last Change Time" });
private Table table;
/**
* Gets a version 1 adapter for the Typedef database table.
* @param handle handle to the database containing the table.
* @param create true if this constructor should create the table.
* @throws VersionException if the the table's version does not match the expected version
* for this adapter.
* @throws IOException if IO error occurs
*/
public TypedefDBAdapterV2(DBHandle handle, boolean create)
throws VersionException, IOException {
if (create) {
table = handle.createTable(TYPEDEF_TABLE_NAME, V2_SCHEMA,
new int[] { V2_TYPEDEF_CAT_COL, V2_TYPEDEF_UNIVERSAL_DT_ID_COL });
}
else {
table = handle.getTable(TYPEDEF_TABLE_NAME);
if (table == null) {
throw new VersionException("Missing Table: " + TYPEDEF_TABLE_NAME);
}
int version = table.getSchema().getVersion();
if (version != VERSION) {
String msg = "Expected version " + VERSION + " for table " + TYPEDEF_TABLE_NAME +
" but got " + table.getSchema().getVersion();
if (version < VERSION) {
throw new VersionException(msg, VersionException.OLDER_VERSION, true);
}
throw new VersionException(msg, VersionException.NEWER_VERSION, false);
}
}
}
@Override
void deleteTable(DBHandle handle) throws IOException {
handle.deleteTable(TYPEDEF_TABLE_NAME);
}
@Override
public DBRecord createRecord(long dataTypeID, String name, short flags, long categoryID,
long sourceArchiveID, long sourceDataTypeID, long lastChangeTime) throws IOException {
long tableKey = table.getKey();
// if (tableKey <= DataManager.VOID_DATATYPE_ID) {
// tableKey = DataManager.VOID_DATATYPE_ID +1;
// }
long key = DataTypeManagerDB.createKey(DataTypeManagerDB.TYPEDEF, tableKey);
DBRecord record = V2_SCHEMA.createRecord(key);
record.setLongValue(V2_TYPEDEF_DT_ID_COL, dataTypeID);
record.setShortValue(V2_TYPEDEF_FLAGS_COL, flags);
record.setString(V2_TYPEDEF_NAME_COL, name);
record.setLongValue(V2_TYPEDEF_CAT_COL, categoryID);
record.setLongValue(V2_TYPEDEF_SOURCE_ARCHIVE_ID_COL, sourceArchiveID);
record.setLongValue(V2_TYPEDEF_UNIVERSAL_DT_ID_COL, sourceDataTypeID);
record.setLongValue(V2_TYPEDEF_SOURCE_SYNC_TIME_COL, lastChangeTime);
record.setLongValue(V2_TYPEDEF_LAST_CHANGE_TIME_COL, lastChangeTime);
table.putRecord(record);
return record;
}
@Override
public DBRecord getRecord(long typedefID) throws IOException {
return table.getRecord(typedefID);
}
@Override
public RecordIterator getRecords() throws IOException {
return table.iterator();
}
@Override
public void updateRecord(DBRecord record, boolean setLastChangeTime) throws IOException {
if (setLastChangeTime) {
record.setLongValue(TypedefDBAdapter.TYPEDEF_LAST_CHANGE_TIME_COL,
(new Date()).getTime());
}
table.putRecord(record);
}
@Override
public boolean removeRecord(long dataID) throws IOException {
return table.deleteRecord(dataID);
}
@Override
public Field[] getRecordIdsInCategory(long categoryID) throws IOException {
return table.findRecords(new LongField(categoryID), V2_TYPEDEF_CAT_COL);
}
@Override
Field[] getRecordIdsForSourceArchive(long archiveID) throws IOException {
return table.findRecords(new LongField(archiveID), V2_TYPEDEF_SOURCE_ARCHIVE_ID_COL);
}
@Override
DBRecord getRecordWithIDs(UniversalID sourceID, UniversalID datatypeID) throws IOException {
Field[] keys =
table.findRecords(new LongField(datatypeID.getValue()), V2_TYPEDEF_UNIVERSAL_DT_ID_COL);
for (int i = 0; i < keys.length; i++) {
DBRecord record = table.getRecord(keys[i]);
if (record.getLongValue(V2_TYPEDEF_SOURCE_ARCHIVE_ID_COL) == sourceID.getValue()) {
return record;
}
}
return null;
}
}

View file

@ -89,7 +89,8 @@ public abstract class AbstractDataType implements DataType {
@Override
public DataTypePath getDataTypePath() {
return new DataTypePath(categoryPath, name);
// use methods instead of fields since they mey be overriden
return new DataTypePath(getCategoryPath(), getName());
}
@Override

View file

@ -1,125 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.program.model.data;
import ghidra.docking.settings.Settings;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressOutOfBoundsException;
import ghidra.program.model.mem.MemBuffer;
import ghidra.program.model.scalar.Scalar;
abstract class AbstractImageBaseOffsetDataType extends BuiltIn {
AbstractImageBaseOffsetDataType(CategoryPath path, String name, DataTypeManager dtm) {
super(path, name, dtm);
}
abstract DataType getScalarDataType();
static String generateName(DataType dt) {
return "ImageBaseOffset" + dt.getLength() * 8;
}
static String generateMnemonic(DataType dt) {
return "ibo" + dt.getLength() * 8;
}
static String generateDescription(DataType dt) {
return (dt.getLength() * 8) + "-bit Image Base Offset";
}
@Override
public String getDescription() {
DataType dt = getScalarDataType();
return generateDescription(dt);
}
@Override
public String getMnemonic(Settings settings) {
DataType dt = getScalarDataType();
return generateMnemonic(dt);
}
@Override
public int getLength() {
return getScalarDataType().getLength();
}
@Override
public String getRepresentation(MemBuffer buf, Settings settings, int length) {
Address addr = (Address) getValue(buf, settings, length);
if (addr == null) { // could not create address, so return "Not a pointer (NaP)"
return "NaP";
}
return addr.toString();
}
@Override
public Object getValue(MemBuffer buf, Settings settings, int length) {
DataType dt = getScalarDataType();
Address imageBase = buf.getMemory().getProgram().getImageBase();
Scalar value = (Scalar) dt.getValue(buf, settings, length);
if (value != null && value.getUnsignedValue() != 0) {
try {
return imageBase.add(value.getUnsignedValue());
}
catch (AddressOutOfBoundsException e) {
// ignore
}
}
return null;
}
@Override
public boolean isEncodable() {
return getScalarDataType().isEncodable();
}
@Override
public byte[] encodeValue(Object value, MemBuffer buf, Settings settings, int length)
throws DataTypeEncodeException {
if (!(value instanceof Address)) {
throw new DataTypeEncodeException("Requires Address", value, this);
}
Address addressValue = (Address) value;
Address imageBase = buf.getMemory().getProgram().getImageBase();
long offset;
try {
offset = addressValue.subtract(imageBase);
}
catch (IllegalArgumentException e) {
throw new DataTypeEncodeException(value, this, e);
}
Scalar scalarOffset = new Scalar(imageBase.getSize(), offset, false);
DataType dt = getScalarDataType();
return dt.encodeValue(scalarOffset, buf, settings, length);
}
@Override
public byte[] encodeRepresentation(String repr, MemBuffer buf, Settings settings, int length)
throws DataTypeEncodeException {
Address address = buf.getMemory().getProgram().getAddressFactory().getAddress(repr);
if (address == null) {
throw new DataTypeEncodeException("Cannot parse address", repr, this);
}
return encodeValue(address, buf, settings, length);
}
@Override
public Class<?> getValueClass(Settings settings) {
return Address.class;
}
}

View file

@ -25,14 +25,10 @@ import ghidra.util.UniversalID;
import ghidra.util.UniversalIdGenerator;
/**
* <code>AbstractPointerTypedefDataType</code> provides an abstract implementation for
* a Pointer-Typedef BuiltIn datatype.
* <br>
* If a generated name is used the name will be locked-in once this datatype is resolved
* and will not automatcally update if any subsequent changes are made to
* {@link TypeDefSettingsDefinition} settings or the name of the referenced datatype.
* <code>AbstractPointerTypedefDataType</code> provides an abstract {@link BuiltIn} datatype
* implementation for a pointer-typedef datatype.
*/
public abstract class AbstractPointerTypedefDataType extends BuiltIn implements TypeDef {
public abstract class AbstractPointerTypedefBuiltIn extends BuiltIn implements TypeDef {
private String typedefName;
private TypedefDataType modelTypedef;
@ -47,12 +43,13 @@ public abstract class AbstractPointerTypedefDataType extends BuiltIn implements
* @param pointerSize pointer size in bytes or -1 for default pointer size
* @param dtm data-type manager whose data organization should be used
*/
public AbstractPointerTypedefDataType(String name, DataType referencedDataType,
protected AbstractPointerTypedefBuiltIn(String name, DataType referencedDataType,
int pointerSize, DataTypeManager dtm) {
super(getCategoryPath(referencedDataType), getTempNameIfNeeded(name), dtm);
setTypedefName(name);
modelTypedef =
new TypedefDataType("TEMP", new PointerDataType(referencedDataType, pointerSize, dtm));
setDefaultSettings(modelTypedef.getDefaultSettings());
}
/**
@ -63,13 +60,20 @@ public abstract class AbstractPointerTypedefDataType extends BuiltIn implements
* @param pointerDataType associated pointer datatype (required)
* @param dtm data-type manager whose data organization should be used
*/
public AbstractPointerTypedefDataType(String name, Pointer pointerDataType,
protected AbstractPointerTypedefBuiltIn(String name, Pointer pointerDataType,
DataTypeManager dtm) {
super(pointerDataType.getCategoryPath(), getTempNameIfNeeded(name), dtm);
setTypedefName(name);
modelTypedef = new TypedefDataType("TEMP", pointerDataType.clone(dtm));
setDefaultSettings(modelTypedef.getDefaultSettings());
}
@Override
public void enableAutoNaming() {
typedefName = null;
}
@Override
public boolean isAutoNamed() {
return typedefName == null;
}
@ -102,7 +106,7 @@ public abstract class AbstractPointerTypedefDataType extends BuiltIn implements
}
void setTypedefName(String name) {
if (name != null) {
if (name != null && !DataUtilities.isValidDataTypeName(name)) {
throw new IllegalArgumentException("Invalid DataType name: " + name);
}
this.typedefName = name;
@ -158,17 +162,7 @@ public abstract class AbstractPointerTypedefDataType extends BuiltIn implements
@Override
public SettingsDefinition[] getBuiltInSettingsDefinitions() {
return getTypeDefSettingsDefinitions();
}
@Override
public TypeDefSettingsDefinition[] getTypeDefSettingsDefinitions() {
return modelTypedef.getTypeDefSettingsDefinitions();
}
@Override
public Settings getDefaultSettings() {
return modelTypedef.getDefaultSettings();
return modelTypedef.getSettingsDefinitions();
}
@Override
@ -183,6 +177,11 @@ public abstract class AbstractPointerTypedefDataType extends BuiltIn implements
getDataType().getName();
}
@Override
public Class<?> getValueClass(Settings settings) {
return modelTypedef.getValueClass(settings);
}
@Override
public Object getValue(MemBuffer buf, Settings settings, int length) {
return modelTypedef.getValue(buf, settings, length);

View file

@ -128,6 +128,11 @@ public class CharsetSettingsDefinition implements EnumSettingsDefinition {
return CHARSET_NAME;
}
@Override
public String getStorageKey() {
return CHARSET_SETTING_NAME;
}
@Override
public String getDescription() {
return "Character set";

View file

@ -114,7 +114,7 @@ public class ComponentOffsetSettingsDefinition
public String getAttributeSpecification(Settings settings) {
if (hasValue(settings)) {
long offset = getValue(settings);
return "offset(" + Long.toString(offset) + ")";
return "offset(0x" + Long.toHexString(offset) + ")";
}
return null;
}

View file

@ -51,6 +51,9 @@ public interface DataType {
public final static String CONFLICT_SUFFIX = ".conflict";
public final static String TYPEDEF_ATTRIBUTE_PREFIX = "__((";
public final static String TYPEDEF_ATTRIBUTE_SUFFIX = "))";
static final long NO_SOURCE_SYNC_TIME = 0L;
static final long NO_LAST_CHANGE_TIME = 0L;

View file

@ -246,14 +246,6 @@ public interface DataTypeManager {
*/
public Category getCategory(CategoryPath path);
/**
* Notification when data type is changed.
* @param dataType data type that is changed
* @param isAutoChange true if change was an automatic change in response to
* another datatype's change (e.g., size, alignment).
*/
public void dataTypeChanged(DataType dataType, boolean isAutoChange);
/**
* Add a listener that is notified when the dataTypeManger changes.
* @param l the listener

View file

@ -88,6 +88,11 @@ public class DataTypeMnemonicSettingsDefinition implements EnumSettingsDefinitio
return "Mnemonic-style";
}
@Override
public String getStorageKey() {
return MNEMONIC;
}
@Override
public String getDescription() {
return "Selects the data-type mnemonic style";

View file

@ -108,6 +108,11 @@ public class EndianSettingsDefinition implements EnumSettingsDefinition {
return "Endian";
}
@Override
public String getStorageKey() {
return ENDIAN_SETTING_NAME;
}
@Override
public String getDescription() {
return "Selects the endianess of the data";

View file

@ -15,27 +15,43 @@
*/
package ghidra.program.model.data;
import ghidra.docking.settings.Settings;
import ghidra.util.classfinder.ClassTranslator;
/**
* <code>IBO32DataType</code> provides a Pointer-Typedef BuiltIn for
* a 32-bit Image Base Offset Relative Pointer.
* a 32-bit Image Base Offset Relative Pointer. This {@link TypeDef} implementation
* specifies the {@link PointerType#IMAGE_BASE_RELATIVE} attribute/setting
* associated with a 32-bit {@link Pointer}.
* <br>
* This class replaces the use of the old <code>ImageBaseOffset32DataType</code>
* which did not implement the Pointer interface. This is an alternative
* {@link BuiltIn} implementation to using the more general {@link PointerTypedef}
* datatype with an unspecified referenced datatype. {@link PointerTypedef} should
* be used for other cases
* (see {@link #createIBO32PointerTypedef(DataType)}).
*/
public class IBO32DataType extends AbstractPointerTypedefDataType {
public class IBO32DataType extends AbstractPointerTypedefBuiltIn {
static final String NAME = "ibo32";
public static final IBO32DataType dataType = new IBO32DataType();
// TODO: remove old ImageBaseOffset32DataType implementation and uncomment
// static {
// ClassTranslator.put("ghidra.program.model.data.ImageBaseOffset32",
// IBO32DataType.class.getName());
// ClassTranslator.put("ghidra.program.model.data.ImageBaseOffset32DataType",
// IBO32DataType.class.getName());
// }
static final String NAME = "ImageBaseOffset32";
private static TypeDefSettingsDefinition[] IBO_TYPEDEF_SETTINGS_DEFS =
{ PointerTypeSettingsDefinition.DEF };
static {
ClassTranslator.put("ghidra.program.model.data.ImageBaseOffset32",
IBO32DataType.class.getName());
ClassTranslator.put("ghidra.program.model.data.ImageBaseOffset32DataType",
IBO32DataType.class.getName());
}
/**
* Constructs a 32-bit Image Base Offset relative pointer-typedef.
*/
public IBO32DataType() {
this(DataType.DEFAULT, null);
this(null);
}
/**
@ -43,25 +59,9 @@ public class IBO32DataType extends AbstractPointerTypedefDataType {
* @param dtm data-type manager whose data organization should be used
*/
public IBO32DataType(DataTypeManager dtm) {
this(DataType.DEFAULT, dtm);
}
/**
* Constructs a 32-bit Image Base Offset relative pointer-typedef.
* @param referencedDataType data type this pointer-typedef points to
*/
public IBO32DataType(DataType referencedDataType) {
this(referencedDataType, null);
}
/**
* Constructs a 32-bit Image Base Offset relative pointer-typedef.
* @param referencedDataType data type this pointer-typedef points to
* @param dtm data-type manager whose data organization should be used
*/
public IBO32DataType(DataType referencedDataType, DataTypeManager dtm) {
super(null, referencedDataType, 4, dtm);
PointerTypeSettingsDefinition.DEF.setType(getDefaultSettings(), PointerType.IBO);
super(NAME, null, 4, dtm);
PointerTypeSettingsDefinition.DEF.setType(getDefaultSettings(),
PointerType.IMAGE_BASE_RELATIVE);
}
@Override
@ -74,18 +74,30 @@ public class IBO32DataType extends AbstractPointerTypedefDataType {
if (dataMgr == dtm) {
return this;
}
IBO32DataType td = new IBO32DataType(getReferencedDataType(), dtm);
TypedefDataType.copyTypeDefSettings(this, td, false);
return td;
return new IBO32DataType(dtm);
}
@Override
public String getName() {
DataType dt = getReferencedDataType();
if (dt == null || Undefined.isUndefined(dt) || (dt instanceof VoidDataType)) {
return NAME; // use simple ibo name
}
return super.getName(); // use generated named
public String getMnemonic(Settings settings) {
return "ibo32";
}
@Override
public TypeDefSettingsDefinition[] getBuiltInSettingsDefinitions() {
return IBO_TYPEDEF_SETTINGS_DEFS;
}
/**
* Create a IBO32 {@link PointerTypedef} with auto-naming. If needed, a name and category
* may be assigned to the returned instance. Unlike using an immutable {@link IBO32DataType} instance
* the returned instance is mutable.
* @param referencedDataType referenced datatype or null
* @return new IBO32 pointer-typedef
*/
public static PointerTypedef createIBO32PointerTypedef(DataType referencedDataType) {
return new PointerTypedef(null, referencedDataType, 4,
referencedDataType != null ? referencedDataType.getDataTypeManager() : null,
PointerType.IMAGE_BASE_RELATIVE);
}
}

View file

@ -15,27 +15,43 @@
*/
package ghidra.program.model.data;
import ghidra.docking.settings.Settings;
import ghidra.util.classfinder.ClassTranslator;
/**
* <code>IBO64DataType</code> provides a Pointer-Typedef BuiltIn for
* a 64-bit Image Base Offset Relative Pointer.
* a 64-bit Image Base Offset Relative Pointer. This {@link TypeDef} implementation
* specifies the {@link PointerType#IMAGE_BASE_RELATIVE} attribute/setting
* associated with a 64-bit {@link Pointer}.
* <br>
* This class replaces the use of the old <code>ImageBaseOffset64DataType</code>
* which did not implement the Pointer interface. This is an alternative
* {@link BuiltIn} implementation to using the more general {@link PointerTypedef}
* datatype with an unspecified referenced datatype. {@link PointerTypedef} should
* be used for other cases
* (see {@link #createIBO64PointerTypedef(DataType)}).
*/
public class IBO64DataType extends AbstractPointerTypedefDataType {
public class IBO64DataType extends AbstractPointerTypedefBuiltIn {
static final String NAME = "ibo64";
public static final IBO64DataType dataType = new IBO64DataType();
// TODO: remove old ImageBaseOffset64DataType implementation and uncomment
// static {
// ClassTranslator.put("ghidra.program.model.data.ImageBaseOffset64",
// IBO64DataType.class.getName());
// ClassTranslator.put("ghidra.program.model.data.ImageBaseOffset64DataType",
// IBO64DataType.class.getName());
// }
static final String NAME = "ImageBaseOffset64";
private static TypeDefSettingsDefinition[] IBO_TYPEDEF_SETTINGS_DEFS =
{ PointerTypeSettingsDefinition.DEF };
static {
ClassTranslator.put("ghidra.program.model.data.ImageBaseOffset64",
IBO64DataType.class.getName());
ClassTranslator.put("ghidra.program.model.data.ImageBaseOffset64DataType",
IBO64DataType.class.getName());
}
/**
* Constructs a 64-bit Image Base Offset relative pointer-typedef.
*/
public IBO64DataType() {
this(DataType.DEFAULT, null);
this(null);
}
/**
@ -43,25 +59,8 @@ public class IBO64DataType extends AbstractPointerTypedefDataType {
* @param dtm data-type manager whose data organization should be used
*/
public IBO64DataType(DataTypeManager dtm) {
this(DataType.DEFAULT, dtm);
}
/**
* Constructs a 64-bit Image Base Offset relative pointer-typedef.
* @param referencedDataType data type this pointer-typedef points to
*/
public IBO64DataType(DataType referencedDataType) {
this(referencedDataType, null);
}
/**
* Constructs a 64-bit Image Base Offset relative pointer-typedef.
* @param referencedDataType data type this pointer-typedef points to
* @param dtm data-type manager whose data organization should be used
*/
public IBO64DataType(DataType referencedDataType, DataTypeManager dtm) {
super(null, referencedDataType, 8, dtm);
PointerTypeSettingsDefinition.DEF.setType(getDefaultSettings(), PointerType.IBO);
super(NAME, null, 8, dtm);
PointerTypeSettingsDefinition.DEF.setType(getDefaultSettings(), PointerType.IMAGE_BASE_RELATIVE);
}
@Override
@ -74,18 +73,30 @@ public class IBO64DataType extends AbstractPointerTypedefDataType {
if (dataMgr == dtm) {
return this;
}
IBO64DataType td = new IBO64DataType(getReferencedDataType(), dtm);
TypedefDataType.copyTypeDefSettings(this, td, false);
return td;
return new IBO64DataType(dtm);
}
@Override
public String getName() {
DataType dt = getReferencedDataType();
if (dt == null || Undefined.isUndefined(dt) || (dt instanceof VoidDataType)) {
return NAME; // use simple ibo name
}
return super.getName(); // use generated named
public String getMnemonic(Settings settings) {
return "ibo64";
}
@Override
public TypeDefSettingsDefinition[] getBuiltInSettingsDefinitions() {
return IBO_TYPEDEF_SETTINGS_DEFS;
}
/**
* Create a IBO64 {@link PointerTypedef} with auto-naming. If needed, a name and category
* may be assigned to the returned instance. Unlike using an immutable {@link IBO32DataType} instance
* the returned instance is mutable.
* @param referencedDataType referenced datatype or null
* @return new IBO64 pointer-typedef
*/
public static PointerTypedef createIBO64PointerTypedef(DataType referencedDataType) {
return new PointerTypedef(null, referencedDataType, 8,
referencedDataType != null ? referencedDataType.getDataTypeManager() : null,
PointerType.IMAGE_BASE_RELATIVE);
}
}

View file

@ -1,48 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.program.model.data;
import ghidra.util.classfinder.*;
public class ImageBaseOffset32DataType extends AbstractImageBaseOffsetDataType {
static {
ClassTranslator.put("ghidra.program.model.data.ImageBaseOffset32",
ImageBaseOffset32DataType.class.getName());
}
private static DataType datatype = DWordDataType.dataType;
public ImageBaseOffset32DataType() {
this(null);
}
public ImageBaseOffset32DataType(DataTypeManager dtm) {
super(null, generateName(datatype), dtm);
}
@Override
DataType getScalarDataType() {
return datatype;
}
public DataType clone(DataTypeManager dtm) {
if (dtm == getDataTypeManager()) {
return this;
}
return new ImageBaseOffset32DataType(dtm);
}
}

View file

@ -1,48 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.program.model.data;
import ghidra.util.classfinder.*;
public class ImageBaseOffset64DataType extends AbstractImageBaseOffsetDataType {
static {
ClassTranslator.put("ghidra.program.model.data.ImageBaseOffset64",
ImageBaseOffset64DataType.class.getName());
}
private static DataType datatype = QWordDataType.dataType;
public ImageBaseOffset64DataType() {
this(null);
}
public ImageBaseOffset64DataType(DataTypeManager dtm) {
super(null, generateName(datatype), dtm);
}
@Override
DataType getScalarDataType() {
return datatype;
}
public DataType clone(DataTypeManager dtm) {
if (dtm == getDataTypeManager()) {
return this;
}
return new ImageBaseOffset64DataType(dtm);
}
}

View file

@ -87,6 +87,11 @@ public class MutabilitySettingsDefinition implements EnumSettingsDefinition {
return "Mutability";
}
@Override
public String getStorageKey() {
return MUTABILITY;
}
@Override
public String getDescription() {
return "Selects the data mutability";

View file

@ -23,8 +23,9 @@ import ghidra.docking.settings.Settings;
*/
public class PaddingSettingsDefinition implements EnumSettingsDefinition {
private static final int PADDED_VALUE = 1;
private static final int UNPADDED_VALUE = 0;
public static final int PADDED_VALUE = 1;
public static final int UNPADDED_VALUE = 0;
private static final String[] choices = { "unpadded", "padded" };
private static final String PADDED = "padded";
@ -86,6 +87,11 @@ public class PaddingSettingsDefinition implements EnumSettingsDefinition {
return "Padding";
}
@Override
public String getStorageKey() {
return PADDED;
}
@Override
public String getDescription() {
return "Selects if the data is padded or not";

View file

@ -403,7 +403,7 @@ public class PointerDataType extends BuiltIn implements Pointer {
try {
PointerType choice = PointerTypeSettingsDefinition.DEF.getType(settings);
if (choice == PointerType.IBO && mem != null) {
if (choice == PointerType.IMAGE_BASE_RELATIVE && mem != null) {
// must ignore AddressSpaceSettingsDefinition
Address imageBase = mem.getProgram().getImageBase();
targetSpace = imageBase.getAddressSpace();

View file

@ -33,7 +33,7 @@ public enum PointerType {
/**
* Pointer offset relative to program image base.
*/
IBO(1),
IMAGE_BASE_RELATIVE(1),
/**
* Pointer offset relative to pointer storage address.
* NOTE: This type has limited usefulness since it can only be applied to

View file

@ -31,6 +31,7 @@ public class PointerTypeSettingsDefinition
"Specifies the pointer type which affects interpretation of offset";
private static final String DISPLAY_NAME = "Pointer Type";
// Choices correspond to the enumerated PointerType values
private static final String[] choices =
{ "default", "image-base-relative", "relative", "file-offset" };

View file

@ -17,7 +17,15 @@ package ghidra.program.model.data;
import java.util.Objects;
import org.apache.commons.lang3.StringUtils;
import ghidra.docking.settings.Settings;
import ghidra.docking.settings.SettingsDefinition;
import ghidra.program.database.data.DataTypeUtilities;
import ghidra.program.model.address.AddressSpace;
import ghidra.program.model.mem.MemBuffer;
import ghidra.util.UniversalID;
import ghidra.util.UniversalIdGenerator;
/**
* <code>PointerTypedef</code> provides a Pointer-Typedef template datatype
@ -30,59 +38,151 @@ import ghidra.program.model.address.AddressSpace;
* since it does not implement a default constructor so it may not be treated
* like other {@link BuiltIn} datatypes which are managed by the
* <{@link BuiltInDataTypeManager}.
* <br>
* NOTE: As a {@link BuiltIn} datatype the use of {@link #setName(String)} and
* {@link #setNameAndCategory(CategoryPath, String)} is disabled. The datatype
* instance must be instantiated with the correct typedef name.
*/
public class PointerTypedef extends AbstractPointerTypedefDataType {
public class PointerTypedef extends GenericDataType implements TypeDef {
private boolean isAutoNamed;
private TypedefDataType modelTypedef;
private UniversalID universalId = UniversalIdGenerator.nextID();
/**
* Constructs a pointer-typedef which dereferences into a specific address space.
* @param typeDefName name of this pointer-typedef or null to force name generation.
* @param referencedDataType data type this pointer-typedef points to
* @param pointerSize pointer size in bytes or -1 for default pointer size based upon datatype manager
* @param typeDefName name of this pointer-typedef or null to use auto-named typedef.
* @param referencedDataType data type this pointer-typedef points to or null
* @param pointerSize pointer size in bytes or -1 for default pointer size based upon specified
* address space and datatype manager
* @param dtm data-type manager whose data organization should be used (highly recommended, may be null)
* @param space address space to be used when dereferencing pointer offset
*/
public PointerTypedef(String typeDefName, DataType referencedDataType, int pointerSize,
DataTypeManager dtm, AddressSpace space) {
super(typeDefName, referencedDataType, pointerSize, dtm);
Objects.requireNonNull(space, "Address space must be specified");
this(typeDefName, referencedDataType, getPreferredPointerSize(pointerSize, dtm, space),
dtm);
AddressSpaceSettingsDefinition.DEF.setValue(getDefaultSettings(), space.getName());
}
/**
* Constructs a pointer-typedef of a specific type
* @param typeDefName name of this pointer-typedef or null to force name generation.
* @param referencedDataType data type this pointer-typedef points to
* @param typeDefName name of this pointer-typedef or null to use auto-named typedef.
* @param referencedDataType data type this pointer-typedef points to or null
* @param pointerSize pointer size in bytes or -1 for default pointer size based upon datatype manager
* @param dtm data-type manager whose data organization should be used (highly recommended, may be null)
* @param type pointer type (IBO, RELATIVE, FILE_OFFSET)
*/
public PointerTypedef(String typeDefName, DataType referencedDataType, int pointerSize,
DataTypeManager dtm, PointerType type) {
super(typeDefName, referencedDataType, pointerSize, dtm);
this(typeDefName, referencedDataType, pointerSize, dtm);
Objects.requireNonNull(type, "Pointer type required");
PointerTypeSettingsDefinition.DEF.setType(getDefaultSettings(), type);
}
/**
* Constructs a pointer-typedef without any settings
* @param typeDefName name of this pointer-typedef or null to force name generation.
* @param referencedDataType data type this pointer-typedef points to
* Constructs a offset-pointer-typedef
* @param typeDefName name of this pointer-typedef or null to use auto-named typedef.
* @param referencedDataType data type this pointer-typedef points to or null
* @param pointerSize pointer size in bytes or -1 for default pointer size based upon datatype manager
* @param dtm data-type manager whose data organization should be used (highly recommended, may be null)
* @param componentOffset signed component offset setting value (see {@link ComponentOffsetSettingsDefinition}
*/
/* package */ PointerTypedef(String typeDefName, DataType referencedDataType, int pointerSize,
DataTypeManager dtm) {
super(typeDefName, referencedDataType, pointerSize, dtm);
public PointerTypedef(String typeDefName, DataType referencedDataType, int pointerSize,
DataTypeManager dtm, long componentOffset) {
this(typeDefName, referencedDataType, pointerSize, dtm);
ComponentOffsetSettingsDefinition.DEF.setValue(getDefaultSettings(), componentOffset);
}
/**
* Constructs a pointer-typedef without any settings
* @param typeDefName name of this pointer-typedef or null to force name generation.
* @param typeDefName name of this pointer-typedef or null to use auto-named typedef.
* @param referencedDataType data type this pointer-typedef points to or null
* @param pointerSize pointer size in bytes or -1 for default pointer size based upon datatype manager
* @param dtm data-type manager whose data organization should be used (highly recommended, may be null)
*/
public PointerTypedef(String typeDefName, DataType referencedDataType, int pointerSize,
DataTypeManager dtm) {
super(getCategoryPath(referencedDataType), getTempNameIfNeeded(typeDefName), dtm);
isAutoNamed = StringUtils.isBlank(typeDefName);
modelTypedef =
new TypedefDataType("TEMP", new PointerDataType(referencedDataType, pointerSize, dtm));
}
/**
* Constructs a pointer-typedef without any settings
* @param typeDefName name of this pointer-typedef or null to use auto-named typedef.
* @param pointerDataType associated pointer datatype
* @param dtm data-type manager whose data organization should be used (highly recommended, may be null)
*/
/* package */ PointerTypedef(String typeDefName, Pointer pointerDataType, DataTypeManager dtm) {
super(typeDefName, pointerDataType, dtm);
public PointerTypedef(String typeDefName, Pointer pointerDataType, DataTypeManager dtm) {
super(pointerDataType.getCategoryPath(), getTempNameIfNeeded(typeDefName), dtm);
isAutoNamed = StringUtils.isBlank(typeDefName);
modelTypedef = new TypedefDataType("TEMP", pointerDataType.clone(dtm));
}
private static CategoryPath getCategoryPath(DataType referencedDataType) {
return referencedDataType != null ? referencedDataType.getCategoryPath()
: CategoryPath.ROOT;
}
private static String getTempNameIfNeeded(String baseName) {
return StringUtils.isBlank(baseName) ? "TEMP" : baseName;
}
private static int getPreferredPointerSize(int pointerSize, DataTypeManager dtm,
AddressSpace space) {
Objects.requireNonNull(space, "Address space must be specified");
if (pointerSize > 0) {
return pointerSize;
}
pointerSize = space.getSize() / 8;
if (dtm.getDataOrganization().getPointerSize() == pointerSize) {
pointerSize = -1;
}
return pointerSize;
}
@Override
public void enableAutoNaming() {
isAutoNamed = true;
}
@Override
public boolean isAutoNamed() {
return isAutoNamed;
}
/**
* Get the referenced datatype used to construct this datatype
* (datatype which pointer references).
* @return referenced datatype
*/
protected DataType getReferencedDataType() {
Pointer ptrType = (Pointer) getDataType();
return ptrType.getDataType();
}
public UniversalID getUniversalID() {
return universalId;
}
@Override
public boolean isEquivalent(DataType obj) {
if (obj == this) {
return true;
}
if (obj == null || !(obj instanceof TypeDef)) {
return false;
}
TypeDef td = (TypeDef) obj;
if (!DataTypeUtilities.equalsIgnoreConflict(getName(), td.getName())) {
return false;
}
if (!hasSameTypeDefSettings(td)) {
return false;
}
return DataTypeUtilities.isSameOrEquivalentDataType(getDataType(), td.getDataType());
}
@Override
@ -91,12 +191,92 @@ public class PointerTypedef extends AbstractPointerTypedefDataType {
}
@Override
public DataType clone(DataTypeManager dtm) {
public String getName() {
if (isAutoNamed) {
// Do not cache name since we do not have listeners to detect
// settings change which may impact name generation.
return TypedefDataType.generateTypedefName(this);
}
return super.getName(); // use name provided at instantiation
}
@Override
public boolean hasLanguageDependantLength() {
return modelTypedef.hasLanguageDependantLength();
}
@Override
public int getLength() {
return modelTypedef.getLength();
}
@Override
public DataType getDataType() {
return modelTypedef.getDataType();
}
@Override
public DataType getBaseDataType() {
return modelTypedef.getBaseDataType();
}
@Override
public SettingsDefinition[] getSettingsDefinitions() {
return modelTypedef.getSettingsDefinitions();
}
@Override
public TypeDefSettingsDefinition[] getTypeDefSettingsDefinitions() {
return modelTypedef.getTypeDefSettingsDefinitions();
}
@Override
public Settings getDefaultSettings() {
return modelTypedef.getDefaultSettings();
}
@Override
public boolean dependsOn(DataType dt) {
DataType myDt = getDataType();
return (myDt == dt || myDt.dependsOn(dt));
}
@Override
public String toString() {
if (isAutoNamed) {
return getClass().getSimpleName() + ": " + getName();
}
return getClass().getSimpleName() + ": typedef " + getName() + " " +
getDataType().getName();
}
@Override
public Class<?> getValueClass(Settings settings) {
return modelTypedef.getValueClass(settings);
}
@Override
public Object getValue(MemBuffer buf, Settings settings, int length) {
return modelTypedef.getValue(buf, settings, length);
}
@Override
public String getRepresentation(MemBuffer buf, Settings settings, int length) {
return modelTypedef.getRepresentation(buf, settings, length);
}
@Override
public PointerTypedef clone(DataTypeManager dtm) {
if (dataMgr == dtm) {
return this;
}
return copy(dtm);
}
@Override
public PointerTypedef copy(DataTypeManager dtm) {
Pointer ptrType = (Pointer) getDataType();
String n = hasGeneratedNamed() ? null : getName();
String n = isAutoNamed ? null : getName();
PointerTypedef td = new PointerTypedef(n, ptrType, getDataTypeManager());
TypedefDataType.copyTypeDefSettings(this, td, false);
return td;

View file

@ -20,6 +20,7 @@ import java.util.Objects;
import ghidra.program.database.data.PointerTypedefInspector;
import ghidra.program.model.address.AddressSpace;
import ghidra.program.model.symbol.OffsetReference;
import ghidra.util.InvalidNameException;
/**
* <code>PointerTypedefBuilder</code> provides a builder for creating {@link Pointer} - {@link TypeDef}s.
@ -62,9 +63,10 @@ public class PointerTypedefBuilder {
* upon the associated pointer type and the specified settings.
* @param name typedef name
* @return this builder
* @throws InvalidNameException if name contains unsupported characters
*/
public PointerTypedefBuilder name(String name) {
typedef.setTypedefName(name);
public PointerTypedefBuilder name(String name) throws InvalidNameException {
typedef.setName(name);
return this;
}

View file

@ -15,7 +15,9 @@
*/
package ghidra.program.model.data;
import ghidra.docking.settings.SettingsDefinition;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Data;
import ghidra.program.model.listing.Program;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
@ -33,78 +35,102 @@ public interface ProgramBasedDataTypeManager extends DomainFileBasedDataTypeMana
Program getProgram();
/**
* Set the long value for instance settings.
* Determine if a settings change is permitted for the specified settingsDefinition.
* @param data data code unit
* @param settingsDefinition settings definition
* @return true if change permitted else false
*/
public boolean isChangeAllowed(Data data, SettingsDefinition settingsDefinition);
/**
* Set the long value for data instance settings.
*
* @param dataAddr min address of data
* @param data data code unit
* @param name settings name
* @param value value of setting
* @return true if the settings actually changed
*/
public boolean setLongSettingsValue(Address dataAddr, String name, long value);
public boolean setLongSettingsValue(Data data, String name, long value);
/**
* Set the string value for instance settings.
* Set the string value for data instance settings.
*
* @param dataAddr min address of data
* @param data data code unit
* @param name settings name
* @param value value of setting
* @return true if the settings actually changed
*/
public boolean setStringSettingsValue(Address dataAddr, String name, String value);
public boolean setStringSettingsValue(Data data, String name, String value);
/**
* Set the Object settings.
* Set the Object value for data instance settings.
*
* @param dataAddr min address of data
* @param data data code unit
* @param name the name of the settings
* @param value the value for the settings, must be either a String, byte[]
* or Long
* @return true if the settings were updated
*/
public boolean setSettings(Address dataAddr, String name, Object value);
public boolean setSettings(Data data, String name, Object value);
/**
* Get the long value for an instance setting.
* Get the long value for data instance settings.
*
* @param dataAddr min address of data
* @param data data code unit
* @param name settings name
* @return null if the named setting was not found
*/
public Long getLongSettingsValue(Address dataAddr, String name);
public Long getLongSettingsValue(Data data, String name);
/**
* Get the String value for an instance setting.
* Get the String value for data instance settings.
*
* @param dataAddr min address of data
* @param data data code unit
* @param name settings name
* @return null if the named setting was not found
*/
public String getStringSettingsValue(Address dataAddr, String name);
public String getStringSettingsValue(Data data, String name);
/**
* Gets the value of a settings as an object (either String, byte[], or Long).
* Gets the value for data instance settings in Object form.
*
* @param dataAddr the address of the data for this settings
* @param data data code unit
* @param name the name of settings.
* @return the settings object
*/
public Object getSettings(Address dataAddr, String name);
public Object getSettings(Data data, String name);
/**
* Clear the setting
* Clear the specified setting for the given data
*
* @param dataAddr min address of data
* @param data data code unit
* @param name settings name
* @return true if the settings were cleared
*/
public boolean clearSetting(Address dataAddr, String name);
public boolean clearSetting(Data data, String name);
/**
* Clear all settings at the given address.
* Clear all settings for the given data.
*
* @param dataAddr the address for this settings.
* @param data data code unit
*/
public void clearAllSettings(Address dataAddr);
public void clearAllSettings(Data data);
/**
* Returns all the instance Settings names used for the specified data
*
* @param data data code unit
* @return the names
*/
public String[] getInstanceSettingsNames(Data data);
/**
* Returns true if no settings are set for the given data
*
* @param data data code unit
* @return true if not settings
*/
public boolean isEmptySetting(Data data);
/**
* Move the settings in the range to the new start address
@ -118,22 +144,6 @@ public interface ProgramBasedDataTypeManager extends DomainFileBasedDataTypeMana
public void moveAddressRange(Address fromAddr, Address toAddr, long length, TaskMonitor monitor)
throws CancelledException;
/**
* Returns all the instance Settings names used at the given address
*
* @param dataAddr the address
* @return the names
*/
public String[] getInstanceSettingsNames(Address dataAddr);
/**
* Returns true if no settings are set for the given address
*
* @param dataAddr the address to test
* @return true if not settings
*/
public boolean isEmptySetting(Address dataAddr);
/**
* Removes all settings in the range
*

View file

@ -82,6 +82,11 @@ public class TerminatedSettingsDefinition implements EnumSettingsDefinition {
return "Termination";
}
@Override
public String getStorageKey() {
return TERMINATED;
}
@Override
public String getDescription() {
return "Selects if the string is terminated or unterminated";

View file

@ -23,15 +23,33 @@ import ghidra.docking.settings.SettingsDefinition;
*/
public interface TypeDef extends DataType {
/**
* Determine if this datatype use auto-naming (e.g., see {@link PointerTypedef}).
* If true, any change to associated {@link TypeDefSettingsDefinition} settings
* or naming of the pointer-referenced datatype will cause a automatic renaming
* of this datatype.
* @return true if auto-named, else false.
*/
public boolean isAutoNamed();
/**
* Enable auto-naming for this typedef. This will force naming to reflect the name of
* associated datatype plus an attribute list which corresponds to any
* {@link TypeDefSettingsDefinition} settings which may be set.
*/
public void enableAutoNaming();
/**
* Returns the dataType that this typedef is based on. This could be
* another typedef
* @return the datatype which this typedef is based on (may be another {@link TypeDef}).
*/
public DataType getDataType();
/**
* Returns the non-typedef dataType that this typedef is based on, following
* chains of typedefs as necessary.
* @return the datatype which this typedef is based on (will not be another {@link TypeDef}).
*/
public DataType getBaseDataType();
@ -78,4 +96,5 @@ public interface TypeDef extends DataType {
}
return true;
}
}

View file

@ -33,13 +33,6 @@ import ghidra.docking.settings.SettingsDefinition;
*/
public interface TypeDefSettingsDefinition extends SettingsDefinition {
/**
* Get the storage key which should be used when storing a key/value
* map entry which corresponds to this settings definition.
* @return settings storage key
*/
String getStorageKey();
/**
* Get the {@link TypeDef} attribute specification for this setting and its
* current value.

View file

@ -18,6 +18,7 @@ package ghidra.program.model.data;
import ghidra.docking.settings.*;
import ghidra.program.database.data.DataTypeUtilities;
import ghidra.program.model.mem.MemBuffer;
import ghidra.util.InvalidNameException;
import ghidra.util.UniversalID;
/**
@ -30,6 +31,7 @@ public class TypedefDataType extends GenericDataType implements TypeDef {
private DataType dataType;
private SettingsDefinition[] settingsDef;
private boolean isAutoNamed = false;
private boolean deleted = false;
/**
@ -104,6 +106,20 @@ public class TypedefDataType extends GenericDataType implements TypeDef {
}
}
@Override
public void enableAutoNaming() {
if (isAutoNamed) {
return;
}
isAutoNamed = true;
notifyNameChanged(name);
}
@Override
public boolean isAutoNamed() {
return isAutoNamed;
}
@Override
public String getDefaultLabelPrefix() {
return getName();
@ -124,7 +140,10 @@ public class TypedefDataType extends GenericDataType implements TypeDef {
}
if (obj instanceof TypeDef) {
TypeDef td = (TypeDef) obj;
if (!DataTypeUtilities.equalsIgnoreConflict(name, td.getName())) {
if (isAutoNamed != td.isAutoNamed()) {
return false;
}
if (!isAutoNamed && !DataTypeUtilities.equalsIgnoreConflict(getName(), td.getName())) {
return false;
}
if (!hasSameTypeDefSettings(td)) {
@ -175,23 +194,66 @@ public class TypedefDataType extends GenericDataType implements TypeDef {
return dataType.getValueClass(settings);
}
public static TypeDef clone(TypeDef typedef, DataTypeManager dtm) {
if (typedef.getDataTypeManager() == dtm) {
return typedef;
}
TypedefDataType newTypedef =
new TypedefDataType(typedef.getCategoryPath(), typedef.getName(), typedef.getDataType(),
typedef.getUniversalID(),
typedef.getSourceArchive(), typedef.getLastChangeTime(),
typedef.getLastChangeTimeInSourceArchive(), dtm);
copyTypeDefSettings(typedef, newTypedef, false);
newTypedef.isAutoNamed = typedef.isAutoNamed();
return newTypedef;
}
public static TypedefDataType copy(TypeDef typedef, DataTypeManager dtm) {
TypedefDataType newTypedef = new TypedefDataType(typedef.getCategoryPath(),
typedef.getName(), typedef.getDataType(), dtm);
copyTypeDefSettings(typedef, newTypedef, false);
newTypedef.isAutoNamed = typedef.isAutoNamed();
return newTypedef;
}
@Override
public TypedefDataType clone(DataTypeManager dtm) {
if (getDataTypeManager() == dtm) {
return this;
}
TypedefDataType typeDef =
new TypedefDataType(categoryPath, name, dataType, getUniversalID(),
getSourceArchive(), getLastChangeTime(), getLastChangeTimeInSourceArchive(), dtm);
copyTypeDefSettings(this, typeDef, false);
return typeDef;
return (TypedefDataType) clone(this, dtm);
}
@Override
public TypedefDataType copy(DataTypeManager dtm) {
TypedefDataType typeDef = new TypedefDataType(categoryPath, name, dataType, dtm);
copyTypeDefSettings(this, typeDef, false);
return typeDef;
return copy(this, dtm);
}
@Override
public String getName() {
if (isAutoNamed()) {
return generateTypedefName(this);
}
return super.getName();
}
@Override
public void setName(String name) throws InvalidNameException {
super.setName(name);
isAutoNamed = false;
}
@Override
public void setCategoryPath(CategoryPath path) {
if (isAutoNamed()) {
return; // ignore category change if auto-naming enabled
}
super.setCategoryPath(path);
}
@Override
public CategoryPath getCategoryPath() {
if (isAutoNamed()) {
return getDataType().getCategoryPath();
}
return super.getCategoryPath();
}
@Override
@ -316,6 +378,9 @@ public class TypedefDataType extends GenericDataType implements TypeDef {
@Override
public String toString() {
if (isAutoNamed()) {
return getName();
}
return "typedef " + getName() + " " + dataType.getName();
}
@ -351,9 +416,9 @@ public class TypedefDataType extends GenericDataType implements TypeDef {
public static String generateTypedefName(TypeDef modelType) {
// Examples:
// string *32 __attribute__((relative))
// char *32 __attribute__((image-base-relative))
// char *16 __attribute__((space(data)))
// string *32 __((relative))
// char *32 __((image-base-relative))
// char *16 __((space(data)))
Settings settings = modelType.getDefaultSettings();
StringBuilder attributesBuf = new StringBuilder();
@ -367,9 +432,11 @@ public class TypedefDataType extends GenericDataType implements TypeDef {
}
}
StringBuilder buf = new StringBuilder(modelType.getDataType().getName());
buf.append(" __attribute__((");
buf.append(' ');
buf.append(DataType.TYPEDEF_ATTRIBUTE_PREFIX);
buf.append(attributesBuf);
buf.append("))");
buf.append(DataType.TYPEDEF_ATTRIBUTE_SUFFIX);
return buf.toString();
}
}

View file

@ -20,6 +20,7 @@ import java.util.Iterator;
import java.util.List;
import ghidra.docking.settings.Settings;
import ghidra.docking.settings.SettingsDefinition;
import ghidra.program.model.address.Address;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.DataTypeDisplayOptions;
@ -322,6 +323,11 @@ public class DataStub implements Data {
throw new UnsupportedOperationException();
}
@Override
public boolean isChangeAllowed(SettingsDefinition settingsDefinition) {
throw new UnsupportedOperationException();
}
@Override
public Long getLong(String name) {
throw new UnsupportedOperationException();

View file

@ -17,8 +17,7 @@ package ghidra.program.model.data;
import java.nio.charset.Charset;
import ghidra.docking.settings.Settings;
import ghidra.docking.settings.SettingsImpl;
import ghidra.docking.settings.*;
import ghidra.program.model.data.RenderUnicodeSettingsDefinition.RENDER_ENUM;
import ghidra.program.model.data.TranslationSettingsDefinition.TRANSLATION_ENUM;
@ -36,6 +35,11 @@ public class SettingsBuilder implements Settings {
// nada
}
@Override
public boolean isChangeAllowed(SettingsDefinition settingsDefinition) {
return settings.isChangeAllowed(settingsDefinition);
}
/**
* Sets the {@link CharsetSettingsDefinition}.
*

View file

@ -141,11 +141,6 @@ public class TestDoubleDataTypeManager implements DataTypeManager {
throw new UnsupportedOperationException();
}
@Override
public void dataTypeChanged(DataType dataType, boolean isAutoChange) {
throw new UnsupportedOperationException();
}
@Override
public void addDataTypeManagerListener(DataTypeManagerChangeListener l) {
throw new UnsupportedOperationException();

View file

@ -155,12 +155,6 @@ public class TestDummyDataTypeManager implements DataTypeManager {
return null;
}
@Override
public void dataTypeChanged(DataType dataType, boolean isAutoChange) {
// stub
}
@Override
public void addDataTypeManagerListener(DataTypeManagerChangeListener l) {
// stub